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**)®s, ®s_size, ®s_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;
}