DO NOT COMMIT Get serial console working

Change-Id: I7bf649118677929d38798691eff960bb94048fee
diff --git a/kernel/kernel/debug.c b/kernel/kernel/debug.c
index 8b01839..cf8214f 100644
--- a/kernel/kernel/debug.c
+++ b/kernel/kernel/debug.c
@@ -45,7 +45,9 @@
 STATIC_COMMAND_END(kernel);
 
 #if LK_DEBUGLEVEL > 1
+extern void uart_reinit(void);
 static int cmd_thread(int argc, const cmd_args* argv, uint32_t flags) {
+    uart_reinit();
     if (argc < 2) {
         printf("not enough arguments\n");
     usage:
diff --git a/kernel/platform/pc/debug.cpp b/kernel/platform/pc/debug.cpp
index 414dc6e..dc6b250 100644
--- a/kernel/platform/pc/debug.cpp
+++ b/kernel/platform/pc/debug.cpp
@@ -95,6 +95,38 @@
     }
 }
 
+#include <dev/pcie_bus_driver.h>
+
+extern "C" void uart_reinit(void) {
+    auto cfg = PcieBusDriver::GetDriver()->GetConfig(0, 0x19, 0);
+    uint64_t bar0 = cfg->Read(PciConfig::kBAR(0)) | ((uint64_t)cfg->Read(PciConfig::kBAR(1)) >> 32);
+    bar0 &= ~7;
+    uart_mem_addr = (uint64_t)paddr_to_kvaddr(bar0);
+
+    if (uart_irq) {
+        mask_interrupt(uart_irq);
+        uart_irq = 0;
+        platform_debug_start_uart_timer();
+    }
+
+    /* configure the uart */
+    int divisor = 115200 / uart_baud_rate;
+
+    /* get basic config done so that tx functions */
+    uart_write(1, 0); // mask all irqs
+    uart_write(3, 0x80); // set up to load divisor latch
+    uart_write(0, static_cast<uint8_t>(divisor)); // lsb
+    uart_write(1, static_cast<uint8_t>(divisor >> 8)); // msb
+    uart_write(3, 3); // 8N1
+    uart_write(2, 0xc7); // enable FIFO, clear, 14-byte threshold
+
+    uart_write(1, 0x1); // enable receive data available interrupt
+
+    // modem control register: Axiliary Output 2 is another IRQ enable bit
+    const uint8_t mcr = uart_read(4);
+    uart_write(4, mcr | 0x8);
+}
+
 void platform_init_debug_early(void)
 {
     switch (bootloader.uart.type) {
diff --git a/system/dev/serial/intel-serialio/intel-serialio-include/intel-serialio/serialio.h b/system/dev/serial/intel-serialio/intel-serialio-include/intel-serialio/serialio.h
index a20d02b..36dca1f 100644
--- a/system/dev/serial/intel-serialio/intel-serialio-include/intel-serialio/serialio.h
+++ b/system/dev/serial/intel-serialio/intel-serialio-include/intel-serialio/serialio.h
@@ -23,6 +23,7 @@
 #define INTEL_SUNRISE_POINT_SERIALIO_I2C1_DID (0x9d61)
 #define INTEL_SUNRISE_POINT_SERIALIO_I2C2_DID (0x9d62)
 #define INTEL_SUNRISE_POINT_SERIALIO_I2C3_DID (0x9d63)
+#define INTEL_SUNRISE_POINT_SERIALIO_UART0_DID (0x9d66)
 
 #define TRACE 0
 
diff --git a/system/dev/serial/intel-serialio/serialio.c b/system/dev/serial/intel-serialio/serialio.c
index d7321ed..2bb9641 100644
--- a/system/dev/serial/intel-serialio/serialio.c
+++ b/system/dev/serial/intel-serialio/serialio.c
@@ -55,9 +55,8 @@
         res = intel_serialio_bind_spi(dev);
         break;
     case INTEL_WILDCAT_POINT_SERIALIO_UART0_DID:
-        res = intel_serialio_bind_uart(dev);
-        break;
     case INTEL_WILDCAT_POINT_SERIALIO_UART1_DID:
+    case INTEL_SUNRISE_POINT_SERIALIO_UART0_DID:
         res = intel_serialio_bind_uart(dev);
         break;
     default:
@@ -75,7 +74,7 @@
 };
 
 // clang-format off
-ZIRCON_DRIVER_BEGIN(intel_serialio, intel_serialio_driver_ops, "zircon", "0.1", 14)
+ZIRCON_DRIVER_BEGIN(intel_serialio, intel_serialio_driver_ops, "zircon", "0.1", 15)
     BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PCI),
     BI_ABORT_IF(NE, BIND_PCI_VID, INTEL_VID),
     BI_MATCH_IF(EQ, BIND_PCI_DID, INTEL_WILDCAT_POINT_SERIALIO_DMA_DID),
@@ -90,4 +89,5 @@
     BI_MATCH_IF(EQ, BIND_PCI_DID, INTEL_SUNRISE_POINT_SERIALIO_I2C1_DID),
     BI_MATCH_IF(EQ, BIND_PCI_DID, INTEL_SUNRISE_POINT_SERIALIO_I2C2_DID),
     BI_MATCH_IF(EQ, BIND_PCI_DID, INTEL_SUNRISE_POINT_SERIALIO_I2C3_DID),
+    BI_MATCH_IF(EQ, BIND_PCI_DID, INTEL_SUNRISE_POINT_SERIALIO_UART0_DID),
 ZIRCON_DRIVER_END(intel_serialio)
diff --git a/system/dev/serial/intel-serialio/uart/uart.c b/system/dev/serial/intel-serialio/uart/uart.c
index 7c05b14..e17e537 100644
--- a/system/dev/serial/intel-serialio/uart/uart.c
+++ b/system/dev/serial/intel-serialio/uart/uart.c
@@ -3,13 +3,116 @@
 // found in the LICENSE file.
 
 #include <ddk/device.h>
+#include <ddk/debug.h>
 #include <ddk/driver.h>
+#include <ddk/protocol/pci.h>
 
 #include <zircon/types.h>
 
 #include <intel-serialio/serialio.h>
 
+#define UART_RESETS_MASK 0x3u
+#define UART_RESETS_IN_RESET 0x0u
+#define UART_RESETS_RELEASE_RESET 0x3u
+
+#define UART_CLOCKS_CLK_UPDATE (1u << 31)
+#define UART_CLOCKS_N_VAL(val) ((val) << 16)
+#define UART_CLOCKS_M_VAL(val) ((val) << 1)
+#define UART_CLOCKS_CLK_EN 1u
+
+void intel_serialio_uart_release(void* ctx) {
+}
+
+static zx_protocol_device_t intel_serialio_uart_device_proto = {
+    .version = DEVICE_OPS_VERSION,
+    .release = intel_serialio_uart_release,
+};
+
 zx_status_t intel_serialio_bind_uart(zx_device_t* dev) {
+    pci_protocol_t pci;
+    if (device_get_protocol(dev, ZX_PROTOCOL_PCI, &pci)) {
+        return ZX_ERR_NOT_SUPPORTED;
+    }
+
+    zx_handle_t config_handle = ZX_HANDLE_INVALID;
+    zx_handle_t regs_handle = ZX_HANDLE_INVALID;
+
+    const pci_config_t* pci_config;
+    size_t config_size;
+    zx_status_t status = pci_map_resource(&pci, PCI_RESOURCE_CONFIG,
+                                          ZX_CACHE_POLICY_UNCACHED_DEVICE,
+                                          (void**)&pci_config, &config_size,
+                                          &config_handle);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "uart: failed to map pci config: %d\n", status);
+        goto fail;
+    }
+
+    void* regs;
+    size_t regs_size;
+    status = pci_map_resource(&pci, PCI_RESOURCE_BAR_0, ZX_CACHE_POLICY_UNCACHED_DEVICE,
+                              (void**)&regs, &regs_size, &regs_handle);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "uart: failed to map pci bar 0: %d\n", status);
+        goto fail;
+    }
+
+    status = pci_enable_bus_master(&pci, true);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "uart: failed to enable bus master: %d\n", status);
+        goto fail;
+    }
+
+    if (pci_config->vendor_id == INTEL_VID &&
+        pci_config->device_id == INTEL_SUNRISE_POINT_SERIALIO_UART0_DID) {
+        volatile struct real_reg_map {
+            uint8_t pad[0x200];
+            uint32_t clocks;
+            uint32_t resets;
+        } *real_regs = regs;
+
+        // Check if UART is being held in reset.  If so, let's set it up.
+        if ((real_regs->resets & UART_RESETS_MASK) == UART_RESETS_IN_RESET) {
+            zxlogf(INFO, "uart: resetting\n");
+            // Take controller out of reset
+            real_regs->resets = UART_RESETS_RELEASE_RESET;
+
+            // Configure the clock
+            real_regs->clocks = UART_CLOCKS_CLK_UPDATE |
+                    UART_CLOCKS_M_VAL(0x30) | UART_CLOCKS_N_VAL(0xc35);
+            real_regs->clocks = UART_CLOCKS_CLK_EN |
+                    UART_CLOCKS_M_VAL(0x30) | UART_CLOCKS_N_VAL(0xc35);
+            zxlogf(INFO, "uart: read back: %08x\n", real_regs->clocks);
+
+            zx_device_t* zxdev;
+            // Add a placeholder device
+            device_add_args_t args = {
+                .version = DEVICE_ADD_ARGS_VERSION,
+                .name = "uart",
+                .ctx = NULL,
+                .ops = &intel_serialio_uart_device_proto,
+            };
+
+            status = device_add(dev, &args, &zxdev);
+            if (status < 0) {
+                goto fail;
+            }
+
+            return ZX_OK;
+
+        }
+        zxlogf(INFO, "uart: was not in reset\n");
+    }
+
     // Not implemented yet.
-    return ZX_ERR_NOT_SUPPORTED;
+    status = ZX_ERR_NOT_SUPPORTED;
+
+fail:
+    if (config_handle != ZX_HANDLE_INVALID) {
+        zx_handle_close(config_handle);
+    }
+    if (regs_handle != ZX_HANDLE_INVALID) {
+        zx_handle_close(regs_handle);
+    }
+    return status;
 }