add support for OXPCIe 952 card and clean up debug abstraction layer

Signed-off-by: Stefan Reinauer <reinauer@google.com>

diff --git a/src/Kconfig b/src/Kconfig
index fca73e4..38eb5d8 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -343,6 +343,13 @@ menu "Debugging"
         help
             Send debugging information to serial port.
 
+    config DEBUG_SERIAL_OXFORD
+        depends on DEBUG_LEVEL != 0
+        bool "OXPCIe 952 serial port debugging"
+        default n
+        help
+            Send debugging information to serial port.
+
     config SCREEN_AND_DEBUG
         depends on DEBUG_LEVEL != 0
         bool "Show screen writes on debug ports"
diff --git a/src/boot.c b/src/boot.c
index 1cd4126..df11b8e 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -629,7 +629,7 @@ do_boot(u16 seq_nr)
 void VISIBLE32FLAT
 handle_18(void)
 {
-    debug_serial_setup();
+    debug_setup();
     debug_enter(NULL, DEBUG_HDL_18);
     u16 ebda_seg = get_ebda_seg();
     u16 seq = GET_EBDA2(ebda_seg, boot_sequence) + 1;
@@ -641,7 +641,7 @@ handle_18(void)
 void VISIBLE32FLAT
 handle_19(void)
 {
-    debug_serial_setup();
+    debug_setup();
     debug_enter(NULL, DEBUG_HDL_19);
     SET_EBDA(boot_sequence, 0);
     do_boot(0);
diff --git a/src/optionroms.c b/src/optionroms.c
index a94b46c..42cea88 100644
--- a/src/optionroms.c
+++ b/src/optionroms.c
@@ -99,7 +99,7 @@ __callrom(struct rom_header *rom, u16 offset, u16 bdf)
     call16big(&br);
     finish_preempt();
 
-    debug_serial_setup();
+    debug_setup();
 }
 
 // Execute a given option rom at the standard entry vector.
diff --git a/src/output.c b/src/output.c
index 4c9f95b..f27bdb9 100644
--- a/src/output.c
+++ b/src/output.c
@@ -11,6 +11,7 @@
 #include "bregs.h" // struct bregs
 #include "config.h" // CONFIG_*
 #include "biosvar.h" // GET_GLOBAL
+#include "pci.h" // pci_find_device
 
 struct putcinfo {
     void (*func)(struct putcinfo *info, char c);
@@ -24,7 +25,10 @@ struct putcinfo {
 #define DEBUG_PORT PORT_SERIAL1
 #define DEBUG_TIMEOUT 100000
 
-void
+#define OXPCIE_COM1 (oxpcie_bar + 0x1000)
+u32 oxpcie_bar VAR16VISIBLE;
+
+static void
 debug_serial_setup(void)
 {
     if (!CONFIG_DEBUG_SERIAL)
@@ -70,29 +74,114 @@ debug_serial_flush(void)
             return;
 }
 
+static void
+debug_serial_oxford_setup(void)
+{
+    if (!CONFIG_DEBUG_SERIAL_OXFORD)
+        return;
+
+    int oxpcie_bdf;
+    oxpcie_bar = 0;
+    oxpcie_bdf = pci_find_device(0x1415, 0xc158);
+    if (oxpcie_bdf != -1)
+        oxpcie_bar = pci_config_readl(oxpcie_bdf, 0x10);
+    if (!oxpcie_bar)
+        return;
+    // setup for serial logging: 8N1
+    u8 oldparam, newparam = 0x03;
+    oldparam = readb((void *)OXPCIE_COM1+SEROFF_LCR);
+    writeb((void *)OXPCIE_COM1+SEROFF_LCR, newparam);
+    // Disable irqs
+    u8 oldier, newier = 0;
+    oldier = readb((void *)OXPCIE_COM1+SEROFF_IER);
+    writeb((void *)OXPCIE_COM1+SEROFF_IER, newier);
+
+    if (oldparam != newparam || oldier != newier)
+        dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
+                , oldparam, oldier, newparam, newier);
+}
+
+// Write a character to the serial port.
+static void
+debug_serial_oxford(char c)
+{
+    if (!CONFIG_DEBUG_SERIAL_OXFORD)
+        return;
+    if (!oxpcie_bar)
+        return;
+
+    int timeout = DEBUG_TIMEOUT;
+    while ((readb((void *)OXPCIE_COM1+SEROFF_LSR) & 0x60) != 0x60)
+        if (!timeout--)
+            // Ran out of time.
+            return;
+    writeb((void *)OXPCIE_COM1+SEROFF_DATA, c);
+}
+
+// Make sure all serial port writes have been completely sent.
+static void
+debug_serial_oxford_flush(void)
+{
+    if (!CONFIG_DEBUG_SERIAL_OXFORD)
+        return;
+    if (!oxpcie_bar)
+        return;
+    int timeout = DEBUG_TIMEOUT;
+
+    while ((readb((void *)OXPCIE_COM1+SEROFF_LSR) & 0x40) != 0x40)
+        if (!timeout--)
+            // Ran out of time.
+            return;
+}
+
+void
+debug_setup(void)
+{
+    if (! CONFIG_DEBUG_LEVEL)
+        return;
+    if (CONFIG_DEBUG_SERIAL)
+        debug_serial_setup();
+    if (CONFIG_DEBUG_SERIAL_OXFORD)
+        debug_serial_oxford_setup();
+}
+
 // Write a character to debug port(s).
 static void
-putc_debug(struct putcinfo *action, char c)
+debug_putc(struct putcinfo *action, char c)
 {
     if (! CONFIG_DEBUG_LEVEL)
         return;
+    if (c == '\n')
+        debug_putc(action, '\r');
     if (! CONFIG_COREBOOT)
         // Send character to debug port.
         outb(c, PORT_BIOS_DEBUG);
-    if (c == '\n')
-        debug_serial('\r');
-    debug_serial(c);
+    if (CONFIG_DEBUG_SERIAL)
+        debug_serial(c);
+    if (CONFIG_DEBUG_SERIAL_OXFORD)
+        debug_serial_oxford(c);
+}
+
+static void
+debug_flush(void)
+{
+    if (! CONFIG_DEBUG_LEVEL)
+        return;
+    if (CONFIG_DEBUG_SERIAL)
+        debug_serial_flush();
+    if (CONFIG_DEBUG_SERIAL_OXFORD)
+        debug_serial_oxford_flush();
 }
 
-// In segmented mode just need a dummy variable (putc_debug is always
+// In segmented mode just need a dummy variable (debug_putc is always
 // used anyway), and in 32bit flat mode need a pointer to the 32bit
-// instance of putc_debug().
+// instance of debug_putc().
 #if MODE16
 static struct putcinfo debuginfo VAR16;
 #elif MODESEGMENT
 static struct putcinfo debuginfo VAR32SEG;
 #else
-static struct putcinfo debuginfo = { putc_debug };
+static struct putcinfo debuginfo = { debug_putc };
 #endif
 
 
@@ -117,7 +206,7 @@ static void
 putc_screen(struct putcinfo *action, char c)
 {
     if (CONFIG_SCREEN_AND_DEBUG)
-        putc_debug(&debuginfo, c);
+        debug_putc(&debuginfo, c);
     if (c == '\n')
         screenc('\r');
     screenc(c);
@@ -136,7 +225,7 @@ putc(struct putcinfo *action, char c)
 {
     if (MODESEGMENT) {
         // Only debugging output supported in segmented mode.
-        putc_debug(action, c);
+        debug_putc(action, c);
         return;
     }
 
@@ -325,7 +414,7 @@ panic(const char *fmt, ...)
         va_start(args, fmt);
         bvprintf(&debuginfo, fmt, args);
         va_end(args);
-        debug_serial_flush();
+        debug_flush();
     }
 
     // XXX - use PANIC PORT.
@@ -342,10 +431,10 @@ __dprintf(const char *fmt, ...)
         struct thread_info *cur = getCurThread();
         if (cur != &MainThread) {
             // Show "thread id" for this debug message.
-            putc_debug(&debuginfo, '|');
+            debug_putc(&debuginfo, '|');
             puthex(&debuginfo, (u32)cur, 8, 0);
-            putc_debug(&debuginfo, '|');
-            putc_debug(&debuginfo, ' ');
+            debug_putc(&debuginfo, '|');
+            debug_putc(&debuginfo, ' ');
         }
     }
 
@@ -353,7 +442,7 @@ __dprintf(const char *fmt, ...)
     va_start(args, fmt);
     bvprintf(&debuginfo, fmt, args);
     va_end(args);
-    debug_serial_flush();
+    debug_flush();
 }
 
 void
@@ -365,7 +454,7 @@ printf(const char *fmt, ...)
     bvprintf(&screeninfo, fmt, args);
     va_end(args);
     if (CONFIG_SCREEN_AND_DEBUG)
-        debug_serial_flush();
+        debug_flush();
 }
 
 
@@ -456,7 +545,7 @@ hexdump(const void *d, int len)
         d+=4;
     }
     putc(&debuginfo, '\n');
-    debug_serial_flush();
+    debug_flush();
 }
 
 static void
@@ -480,7 +569,7 @@ __debug_isr(const char *fname)
 {
     puts_cs(&debuginfo, fname);
     putc(&debuginfo, '\n');
-    debug_serial_flush();
+    debug_flush();
 }
 
 // Function called on handler startup.
diff --git a/src/post.c b/src/post.c
index 7d2b5f2..f39d862 100644
--- a/src/post.c
+++ b/src/post.c
@@ -373,7 +373,7 @@ _start(void)
 {
     init_dma();
 
-    debug_serial_setup();
+    debug_setup();
     dprintf(1, "Start bios (version %s)\n", VERSION);
 
     if (HaveRunPost)
diff --git a/src/resume.c b/src/resume.c
index 20e2e3d..dacb889 100644
--- a/src/resume.c
+++ b/src/resume.c
@@ -30,7 +30,7 @@ handle_resume(u8 status)
 {
     init_dma();
 
-    debug_serial_setup();
+    debug_setup();
     dprintf(1, "In resume (status=%d)\n", status);
 
     switch (status) {
diff --git a/src/util.h b/src/util.h
index 2160b37..5a0eb96 100644
--- a/src/util.h
+++ b/src/util.h
@@ -231,7 +231,7 @@ int wait_preempt(void);
 void check_preempt(void);
 
 // output.c
-void debug_serial_setup(void);
+void debug_setup(void);
 void panic(const char *fmt, ...)
     __attribute__ ((format (printf, 1, 2))) __noreturn;
 void printf(const char *fmt, ...)
