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@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;