This provides basic debug output on the Quark system, assuming that
*something* (i.e. coreboot or UEFI) has set it up in advance for us.
Signed-off-by: David Woodhouse <David.Woodhouse(a)intel.com>
---
I looked briefly at making this part of the CONFIG_DEBUG_SERIAL code,
and making that generic enough to handle I/O access *or* MMIO access
depending on what's present... but in fact that's probably overkill.
This isn't really limited to Quark; it would work with any 16550 device
wired up as MMIO32. But we can expand it as required, I think. No point
in starting off with the same functionality as the 5000-odd lines of the
Linux kernel's 8250_pci.c.
What do I need to do if called in 32-bit segmented mode? I'm guessing
that's not going to work right now...
src/Kconfig | 5 +++++
src/fw/csm.c | 2 ++
src/output.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 71 insertions(+)
diff --git a/src/Kconfig b/src/Kconfig
index a42ab2d..bdc2602 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -472,6 +472,11 @@ menu "Debugging"
Set to zero to disable debugging.
+ config DEBUG_QUARK_UART
+ depends on DEBUG_LEVEL != 0
+ bool "Debug to Quark UART #1"
+ default n
+
config DEBUG_SERIAL
depends on DEBUG_LEVEL != 0
bool "Serial port debugging"
diff --git a/src/fw/csm.c b/src/fw/csm.c
index dfb0d12..afd7ffe 100644
--- a/src/fw/csm.c
+++ b/src/fw/csm.c
@@ -280,6 +280,8 @@ handle_csm(struct bregs *regs)
if (!CONFIG_CSM)
return;
+ debug_serial_preinit();
+
dprintf(3, "handle_csm regs %p AX=%04x\n", regs, regs->ax);
pic_irqmask_write(PICMask);
diff --git a/src/output.c b/src/output.c
index b47625f..a90d350 100644
--- a/src/output.c
+++ b/src/output.c
@@ -17,6 +17,8 @@
#include "stacks.h" // call16_int
#include "string.h" // memset
#include "util.h" // ScreenAndDebug
+#include "hw/pci_regs.h" // PCI_VENDOR_ID, PCI_BASE_ADDRESS_0
+#include "hw/pci.h" // pci_config_readl
struct putcinfo {
void (*func)(struct putcinfo *info, char c);
@@ -31,9 +33,59 @@ struct putcinfo {
u16 DebugOutputPort VARFSEG = 0x402;
+static volatile u32 *quark_uart_addr = 0;
+
+extern void _cfunc32flat_quark_uart_preinit(void);
+extern void _cfunc32flat_quark_uart_putc(void);
+extern void _cfunc32flat_quark_uart_flush(void);
+
+void quark_uart_preinit(void)
+{
+ // debug port is bus 0, device 0x14, function 5.
+ u16 uart_bdf = pci_to_bdf(0, 0x14, 5);
+
+ // If it isn't a Quark UART...
+ if (pci_config_readl(uart_bdf, PCI_VENDOR_ID) != 0x09368086)
+ return;
+
+ u32 bar0 = pci_config_readl(uart_bdf, PCI_BASE_ADDRESS_0);
+ if (!(bar0 & 0xf))
+ quark_uart_addr = (void *)bar0;
+}
+
+void quark_uart_putc(char c)
+{
+ if (!quark_uart_addr)
+ return;
+
+ int timeout = DEBUG_TIMEOUT;
+ while ((quark_uart_addr[SEROFF_LSR] & 0x20) != 0x20)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+ quark_uart_addr[SEROFF_DATA] = c;
+}
+
+void quark_uart_flush(void)
+{
+ if (!quark_uart_addr)
+ return;
+ int timeout = DEBUG_TIMEOUT;
+ while ((quark_uart_addr[SEROFF_LSR] & 0x60) != 0x60)
+ if (!timeout--)
+ // Ran out of time.
+ return;
+}
+
void
debug_serial_preinit(void)
{
+ if (CONFIG_DEBUG_QUARK_UART) {
+ if (MODE16)
+ call32(_cfunc32flat_quark_uart_preinit, 0, 0);
+ else
+ quark_uart_preinit();
+ }
if (!CONFIG_DEBUG_SERIAL)
return;
// setup for serial logging: 8N1
@@ -54,6 +106,12 @@ debug_serial_preinit(void)
static void
debug_serial(char c)
{
+ if (CONFIG_DEBUG_QUARK_UART) {
+ if (MODE16)
+ call32(_cfunc32flat_quark_uart_putc, c, 0);
+ else
+ quark_uart_putc(c);
+ }
if (!CONFIG_DEBUG_SERIAL)
return;
int timeout = DEBUG_TIMEOUT;
@@ -68,6 +126,12 @@ debug_serial(char c)
static void
debug_serial_flush(void)
{
+ if (CONFIG_DEBUG_QUARK_UART) {
+ if (MODE16)
+ call32(_cfunc32flat_quark_uart_flush, 0, 0);
+ else
+ quark_uart_flush();
+ }
if (!CONFIG_DEBUG_SERIAL)
return;
int timeout = DEBUG_TIMEOUT;
--
1.8.3.1
--
dwmw2