From 6dc27579bc9f0dc1361b72043c7eea4d991ece39 Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Wed, 8 Jul 2015 13:36:29 -0700 Subject: [PATCH] x86: Extend PCI driver module with support for metadata and configuration writes This patch adds the 'meta' field to the generic driver structure to point to optional driver-defined metadata. It also modifies the associated initialization routine to populate it and updates the 16X50 UART driver to use the new initialization routine signature. This patch also adds a function to perform PCI configuration register writes, definitions for the PCI Command configuration register address and some of the bits in that register, and a function to set additional bits in that register. Finally, it adds macros to help with performing MMIO to and from PCI devices. --- cpu/x86/drivers/legacy_pc/pci.c | 36 +++++++++++++++++++++++++- cpu/x86/drivers/legacy_pc/pci.h | 21 +++++++++++++-- cpu/x86/drivers/legacy_pc/uart-16x50.c | 2 +- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/cpu/x86/drivers/legacy_pc/pci.c b/cpu/x86/drivers/legacy_pc/pci.c index a56be38fa..922a3db4b 100644 --- a/cpu/x86/drivers/legacy_pc/pci.c +++ b/cpu/x86/drivers/legacy_pc/pci.c @@ -63,6 +63,36 @@ pci_config_read(pci_config_addr_t addr) return inl(PCI_CONFIG_DATA_PORT); } /*---------------------------------------------------------------------------*/ +/** + * \brief Write to the PCI configuration data port. + * \param addr Address of PCI configuration register. + * \param data Value to write. + */ +void +pci_config_write(pci_config_addr_t addr, uint32_t data) +{ + set_addr(addr); + + outl(PCI_CONFIG_DATA_PORT, data); +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Enable PCI command bits of the specified PCI configuration + * register. + * \param addr Address of PCI configuration register. + * \param flags Flags used to enable PCI command bits. + */ +void +pci_command_enable(pci_config_addr_t addr, uint32_t flags) +{ + uint32_t data; + + addr.reg_off = 0x04; /* PCI COMMAND_REGISTER */ + + data = pci_config_read(addr); + pci_config_write(addr, data | flags); +} +/*---------------------------------------------------------------------------*/ /** * \brief Set current PIRQ to interrupt queue agent. PCI based interrupts * PIRQ[A:H] are then available for consumption by either the 8259 @@ -201,12 +231,16 @@ pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy) * firmware. * \param c_this Structure that will be initialized to represent the driver. * \param pci_addr PCI base address of device. + * \param meta Base address of optional driver-defined metadata. */ void -pci_init_bar0(pci_driver_t *c_this, pci_config_addr_t pci_addr) +pci_init_bar0(pci_driver_t *c_this, + pci_config_addr_t pci_addr, + uintptr_t meta) { pci_addr.reg_off = PCI_CONFIG_REG_BAR0; /* The BAR0 value is masked to clear non-address bits. */ c_this->mmio = pci_config_read(pci_addr) & ~0xFFF; + c_this->meta = meta; } /*---------------------------------------------------------------------------*/ diff --git a/cpu/x86/drivers/legacy_pc/pci.h b/cpu/x86/drivers/legacy_pc/pci.h index 0b7f21ce6..180d0a074 100644 --- a/cpu/x86/drivers/legacy_pc/pci.h +++ b/cpu/x86/drivers/legacy_pc/pci.h @@ -32,6 +32,7 @@ #define CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ #include +#include "helpers.h" /** PCI configuration register identifier for Base Address Register 0 (BAR0) */ #define PCI_CONFIG_REG_BAR0 0x10 @@ -67,6 +68,11 @@ typedef enum { PIRQH, } PIRQ; +/** PCI command register bit to enable bus mastering */ +#define PCI_CMD_2_BUS_MST_EN BIT(2) +/** PCI command register bit to enable memory space */ +#define PCI_CMD_1_MEM_SPACE_EN BIT(1) + /** * PCI configuration address * @@ -88,16 +94,27 @@ typedef union pci_config_addr { } pci_config_addr_t; uint32_t pci_config_read(pci_config_addr_t addr); +void pci_config_write(pci_config_addr_t addr, uint32_t data); +void pci_command_enable(pci_config_addr_t addr, uint32_t flags); /** - * PCI device driver instance with a single MMIO range. + * PCI device driver instance with an optional single MMIO range and optional + * metadata. */ typedef struct pci_driver { uintptr_t mmio; /**< MMIO range base address */ + uintptr_t meta; /**< Driver-defined metadata base address */ } pci_driver_t; -void pci_init_bar0(pci_driver_t *c_this, pci_config_addr_t pci_addr); +void pci_init_bar0(pci_driver_t *c_this, + pci_config_addr_t pci_addr, + uintptr_t meta); int pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq); void pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy); +#define PCI_MMIO_READL(c_this, dest, reg_addr) \ + dest = *((volatile uint32_t *)((c_this).mmio + (reg_addr))) +#define PCI_MMIO_WRITEL(c_this, reg_addr, src) \ + *((volatile uint32_t *)((c_this).mmio + (reg_addr))) = (src) + #endif /* CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ */ diff --git a/cpu/x86/drivers/legacy_pc/uart-16x50.c b/cpu/x86/drivers/legacy_pc/uart-16x50.c index 090544ddc..1b9bab10b 100644 --- a/cpu/x86/drivers/legacy_pc/uart-16x50.c +++ b/cpu/x86/drivers/legacy_pc/uart-16x50.c @@ -79,7 +79,7 @@ uart_16x50_init(uart_16x50_driver_t *c_this, /* This assumes that the UART had an MMIO range assigned to it by the * firmware during boot. */ - pci_init_bar0(c_this, pci_addr); + pci_init_bar0(c_this, pci_addr, 0); uart_16x50_regs_t *regs = (uart_16x50_regs_t *)c_this->mmio;