diff options
author | Chris Johns <chrisj@rtems.org> | 2016-04-20 14:49:32 +1000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2016-05-11 11:45:01 +1000 |
commit | 03ad2a5a92feab28917e1b2b8a5f127b4e54c296 (patch) | |
tree | 1e292cdb013e299838bf63af472744068463ff15 | |
parent | i386/pc386: Add support for the gdb stub to use available console drivers. (diff) | |
download | rtems-03ad2a5a92feab28917e1b2b8a5f127b4e54c296.tar.bz2 |
i386/pc386: Add IO and memory support to PCI UART devices.
Use the BAR to determine IO and memory mapped support for PCI UART
boards.
Diffstat (limited to '')
-rw-r--r-- | c/src/lib/libbsp/i386/pc386/console/uart_bus_pci.c | 150 |
1 files changed, 113 insertions, 37 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/console/uart_bus_pci.c b/c/src/lib/libbsp/i386/pc386/console/uart_bus_pci.c index 60d35e8322..7b4824895f 100644 --- a/c/src/lib/libbsp/i386/pc386/console/uart_bus_pci.c +++ b/c/src/lib/libbsp/i386/pc386/console/uart_bus_pci.c @@ -36,6 +36,7 @@ #ifdef __rtems__ #include <stddef.h> #include <stdint.h> +#include <i386_io.h> #else #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -54,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_bus.h> + #endif #define DEFAULT_RCLK 1843200 @@ -225,11 +227,11 @@ DRIVER_MODULE(uart, pci, uart_pci_driver, uart_devclass, NULL, NULL); #ifdef __rtems__ #include <bsp.h> -// #include <termios.h> +#include <bsp/bspimpl.h> + #include <stdio.h> #include <stdlib.h> -// #include <rtems/termiostypes.h> #include <libchip/serial.h> #include <libchip/ns16550.h> #include <rtems/bspIo.h> @@ -242,36 +244,58 @@ DRIVER_MODULE(uart, pci, uart_pci_driver, uart_devclass, NULL, NULL); * Information saved from PCI scan */ typedef struct { - bool found; - uint32_t base; - uint8_t irq; - uint8_t bus; - uint8_t slot; - int ports; - uint32_t clock; + bool found; + const char* desc; + uint32_t base; + uint8_t irq; + uint8_t bus; + uint8_t slot; + int ports; + uint32_t clock; } port_instance_conf_t; /* - * Register Access Routines + * Memory Mapped Register Access Routines */ -static uint8_t pci_ns16550_get_register(uint32_t addr, uint8_t i) + +#define UART_PCI_IO (0) + +static uint8_t pci_ns16550_mem_get_register(uint32_t addr, uint8_t i) { uint8_t val = 0; volatile uint32_t *reg = (volatile uint32_t *)(addr + (i*4)); - val = *reg; - /* printk( "RD(%p -> 0x%02x) ", reg, val ); */ + if (UART_PCI_IO) + printk( "RD(%p -> 0x%02x) ", reg, val ); return val; } -static void pci_ns16550_set_register(uint32_t addr, uint8_t i, uint8_t val) +static void pci_ns16550_mem_set_register(uint32_t addr, uint8_t i, uint8_t val) { volatile uint32_t *reg = (volatile uint32_t *)(addr + (i*4)); - - /* printk( "WR(%p <- 0x%02x) ", reg, val ); */ + if (UART_PCI_IO) + printk( "WR(%p <- 0x%02x) ", reg, val ); *reg = val; } +/* + * IO Register Access Routines + */ +static uint8_t pci_ns16550_io_get_register(uint32_t addr, uint8_t i) +{ + uint8_t val = rtems_inb(addr + i); + if (UART_PCI_IO) + printk( "RD(%p -> 0x%02x) ", addr + i, val ); + return val; +} + +static void pci_ns16550_io_set_register(uint32_t addr, uint8_t i, uint8_t val) +{ + if (UART_PCI_IO) + printk( "WR(%p <- 0x%02x) ", addr + i, val ); + rtems_outb(addr + i, val); +} + void pci_uart_probe(void) { port_instance_conf_t conf[MAX_BOARDS]; @@ -316,27 +340,28 @@ void pci_uart_probe(void) if ( status == PCIB_ERR_SUCCESS ) { uint8_t irq; uint32_t base; + bool io; - boards++; - conf[instance].found = true; - conf[instance].clock = pci_ns8250_ids[i].rclk; - conf[instance].ports = 1; - total_ports += conf[instance].ports; - - pci_read_config_byte( bus, dev, fun, PCI_INTERRUPT_LINE, &irq ); pci_read_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0, &base ); - conf[instance].irq = irq; - conf[instance].base = base; - - printk( - "Found %s #%d at 0x%08x IRQ %d with %d clock\n", - pci_ns8250_ids[i].desc, - instance, - conf[instance].base, - conf[instance].irq, - conf[instance].clock - ); + /* + * Reject memory mapped 64-bit boards. We need 2 BAR registers and the + * driver's base field is only 32-bits any way. + */ + io = (base & 1) == 1; + if (io || (!io && (((base >> 1) & 3) != 2))) { + boards++; + conf[instance].found = true; + conf[instance].desc = pci_ns8250_ids[i].desc; + conf[instance].clock = pci_ns8250_ids[i].rclk; + conf[instance].ports = 1; + total_ports += conf[instance].ports; + + pci_read_config_byte( bus, dev, fun, PCI_INTERRUPT_LINE, &irq ); + + conf[instance].irq = irq; + conf[instance].base = base; + } } } } @@ -352,6 +377,10 @@ void pci_uart_probe(void) port_p = ports; device_instance = 1; for (b = 0; b < MAX_BOARDS; b++) { + uint32_t base = 0; + bool io; + const char* locatable = ""; + const char* prefectable = locatable; char name[32]; if ( conf[b].found == false ) continue; @@ -369,21 +398,68 @@ void pci_uart_probe(void) port_p->pDeviceFns = &ns16550_fns_polled; } + /* + * PCI BAR (http://wiki.osdev.org/PCI#Base_Address_Registers): + * + * Bit 0: 0 = memory, 1 = IO + * + * Memory: + * Bit 2-1 : 0 = any 32bit address, + * 1 = < 1M + * 2 = any 64bit address + * Bit 3 : 0 = no, 1 = yes + * Bit 31-4 : base address (16-byte aligned) + * + * IO: + * Bit 1 : reserved + * Bit 31-2 : base address (4-byte aligned) + */ + + io = (conf[b].base & 1) == 1; + + if (io) { + base = conf[b].base & 0xfffffffc; + } else { + int loc = (conf[b].base >> 1) & 3; + if (loc == 0) { + base = conf[b].base & 0xfffffff0; + locatable = ",A32"; + } else if (loc == 1) { + base = conf[b].base & 0x0000fff0; + locatable = ",A16"; + } + prefectable = (conf[b].base & (1 << 3)) == 0 ? ",no-prefech" : ",prefetch"; + } + port_p->deviceProbe = NULL; port_p->pDeviceFlow = NULL; port_p->ulMargin = 16; port_p->ulHysteresis = 8; port_p->pDeviceParams = (void *) 9600; - port_p->ulCtrlPort1 = conf[b].base; + port_p->ulCtrlPort1 = base; port_p->ulCtrlPort2 = 0; /* NA */ port_p->ulDataPort = 0; /* NA */ - port_p->getRegister = pci_ns16550_get_register; - port_p->setRegister = pci_ns16550_set_register; + if (io) { + port_p->getRegister = pci_ns16550_io_get_register; + port_p->setRegister = pci_ns16550_io_set_register; + } else { + port_p->getRegister = pci_ns16550_mem_get_register; + port_p->setRegister = pci_ns16550_mem_set_register; + } port_p->getData = NULL; /* NA */ port_p->setData = NULL; /* NA */ port_p->ulClock = conf[b].clock; port_p->ulIntVector = conf[b].irq; + + printk( + "%s:%d:%s,%s:0x%x%s%s,irq:%d,clk:%d\n", /* */ + name, b, conf[b].desc, + io ? "io" : "mem", base, locatable, prefectable, + conf[b].irq, conf[b].clock + ); + + port_p++; } /* end boards */ |