Kyösti Mälkki (kyosti.malkki@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5237
-gerrit
commit 6c81841f2a7c7dfcdb471df11a198aabf3d4c53b Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Fri Feb 14 12:45:09 2014 +0200
OxPCIe uart: Split PCI bridge control
None of the bridge management here is specific to the PCI UART device/function. Also the Kconfig variable defaults are not globally valid but originate from lumpy and/or stumpy devices.
Change-Id: Id22631412379af1d6bf62c996357d36d7ec47ca3 Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- src/console/console.c | 9 ++- src/device/Kconfig | 29 ++++++++ src/device/Makefile.inc | 1 + src/device/pci_early.c | 115 +++++++++++++++++++++++++++++++ src/drivers/oxford/oxpcie/Kconfig | 64 +---------------- src/drivers/oxford/oxpcie/oxpcie_early.c | 89 +++++------------------- src/include/console/uart.h | 1 - src/include/device/pci.h | 2 + src/southbridge/intel/bd82x6x/Kconfig | 16 +++++ 9 files changed, 191 insertions(+), 135 deletions(-)
diff --git a/src/console/console.c b/src/console/console.c index 9e9e4e2..c46d996 100644 --- a/src/console/console.c +++ b/src/console/console.c @@ -28,6 +28,11 @@ #include <arch/hlt.h> #include <arch/io.h>
+#if CONFIG_EARLY_PCI_BRIDGE +/* FIXME: ROMCC chokes on PCI headers. */ +#include <device/pci.h> +#endif + #ifndef __PRE_RAM__ #include <string.h> #include <types.h> @@ -101,8 +106,8 @@ void console_init(void) #if defined(__BOOT_BLOCK__) && CONFIG_BOOTBLOCK_CONSOLE || \ !defined(__BOOT_BLOCK__) && CONFIG_EARLY_CONSOLE
-#if CONFIG_DRIVERS_OXFORD_OXPCIE - oxford_init(); +#if CONFIG_EARLY_PCI_BRIDGE + pci_early_bridge_init(); #endif #if CONFIG_CONSOLE_SERIAL uart_init(); diff --git a/src/device/Kconfig b/src/device/Kconfig index eaa0c04..932b4de 100644 --- a/src/device/Kconfig +++ b/src/device/Kconfig @@ -237,6 +237,35 @@ config PCIEXP_ASPM config PCI_BUS_SEGN_BITS int default 0 + +config EARLY_PCI_BRIDGE + bool "Early PCI bridge" + depends on PCI + default n + help + While coreboot is executing code from ROM, the coreboot resource + allocator has not been running yet. Hence PCI devices living behind + a bridge are not yet visible to the system. + + This option enables static configuration for a single pre-defined + PCI bridge function on bus 0. + +if EARLY_PCI_BRIDGE + +config EARLY_PCI_BRIDGE_DEVICE + hex "bridge device" + default 0x0 + +config EARLY_PCI_BRIDGE_FUNCTION + hex "bridge function" + default 0x0 + +config EARLY_PCI_MMIO_BASE + hex "MMIO window base" + default 0x0 + +endif # EARLY_PCI_BRIDGE + endmenu
menu "VGA BIOS" diff --git a/src/device/Makefile.inc b/src/device/Makefile.inc index ce412b7..bd41b12 100644 --- a/src/device/Makefile.inc +++ b/src/device/Makefile.inc @@ -11,6 +11,7 @@ ramstage-$(CONFIG_CARDBUS_PLUGIN_SUPPORT) += cardbus_device.c ramstage-$(CONFIG_AZALIA_PLUGIN_SUPPORT) += azalia_device.c ramstage-$(CONFIG_ARCH_X86) += pnp_device.c ramstage-$(CONFIG_PCI) += pci_ops.c +ramstage-$(CONFIG_PCI) += pci_early.c ramstage-y += smbus_ops.c
romstage-y += device_romstage.c diff --git a/src/device/pci_early.c b/src/device/pci_early.c index c15a4d0..627e5ac 100644 --- a/src/device/pci_early.c +++ b/src/device/pci_early.c @@ -1,6 +1,8 @@ /* * This file is part of the coreboot project. * + * Copyright (C) 2011 Google Inc + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. @@ -15,9 +17,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA */
+#define __SIMPLE_DEVICE__ + #include <arch/io.h> #include <device/pci.h> #include <device/pci_def.h> +#include <delay.h> + +#ifdef __PRE_RAM__
unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) { @@ -66,3 +73,111 @@ unsigned pci_find_capability(device_t dev, unsigned cap) { return pci_find_next_capability(dev, cap, 0); } +#endif + + +#if CONFIG_EARLY_PCI_BRIDGE + +static void pci_bridge_reset_secondary(device_t p2p_bridge) +{ + u16 reg16; + /* Disable all access through bridge. */ + reg16 = pci_read_config16(p2p_bridge, PCI_COMMAND); + reg16 &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO); + pci_write_config16(p2p_bridge, PCI_COMMAND, reg16); + + /* First we reset the secondary bus. */ + reg16 = pci_read_config16(p2p_bridge, PCI_BRIDGE_CONTROL); + reg16 |= (1 << 6); /* SRESET */ + pci_write_config16(p2p_bridge, PCI_BRIDGE_CONTROL, reg16); + + /* Assume we don't have to wait here forever */ + + /* Read back and clear reset bit. */ + reg16 = pci_read_config16(p2p_bridge, PCI_BRIDGE_CONTROL); + reg16 &= ~(1 << 6); /* SRESET */ + pci_write_config16(p2p_bridge, PCI_BRIDGE_CONTROL, reg16); +} + +static void pci_bridge_set_secondary(device_t p2p_bridge, u8 secondary) +{ + /* Disable config transaction forwarding. */ + pci_write_config8(p2p_bridge, PCI_SUBORDINATE_BUS, 0x00); + pci_write_config8(p2p_bridge, PCI_SECONDARY_BUS, 0x00); + /* Enable config transaction forwarding. */ + pci_write_config8(p2p_bridge, PCI_SECONDARY_BUS, secondary); + pci_write_config8(p2p_bridge, PCI_SUBORDINATE_BUS, secondary); +} + +static void pci_bridge_set_mmio(device_t p2p_bridge, u32 base, u32 size) +{ + u16 reg16; + + /* Disable MMIO window behind the bridge. */ + reg16 = pci_read_config16(p2p_bridge, PCI_COMMAND); + reg16 &= ~PCI_COMMAND_MEMORY; + pci_write_config16(p2p_bridge, PCI_COMMAND, reg16); + pci_write_config32(p2p_bridge, PCI_MEMORY_BASE, 0x10); + + if (!size) + return; + + /* Enable MMIO window behind the bridge. */ + pci_write_config32(p2p_bridge, PCI_MEMORY_BASE, + ((base + size - 1) & 0xfff00000) | ((base >> 16) & 0xfff0)); + + reg16 = pci_read_config16(p2p_bridge, PCI_COMMAND); + reg16 |= PCI_COMMAND_MEMORY; + pci_write_config16(p2p_bridge, PCI_COMMAND, reg16); +} + +void pci_early_bridge_init(void) +{ + int timeout, ret = -1; + + /* No PCI-to-PCI bridges are enabled yet, so the one we try to + * configure must have its primary on bus 0. + */ + pci_devfn_t p2p_bridge = PCI_DEV(0, CONFIG_EARLY_PCI_BRIDGE_DEVICE, + CONFIG_EARLY_PCI_BRIDGE_FUNCTION); + + /* Secondary bus number is mostly irrelevant as we disable + * configuration transactions right after the probe. + */ + u8 secondary = 15; + u8 dev = 0; + u32 mmio_base = CONFIG_EARLY_PCI_MMIO_BASE; + + /* Enable configuration and MMIO over bridge. */ + pci_bridge_reset_secondary(p2p_bridge); + pci_bridge_set_secondary(p2p_bridge, secondary); + pci_bridge_set_mmio(p2p_bridge, mmio_base, 0x4000); + + for (timeout = 20000; timeout && (dev < 32) && ret; timeout--) { + u32 id = pci_read_config32(PCI_DEV(secondary, dev, 0), PCI_VENDOR_ID); + + /* Retry request. */ + if (id == 0xffff0001) { + udelay(10); + continue; + } + + /* Empty slot. */ + if (id == 0xffffffff || id == 0) { + dev++; + continue; + } + ret = pci_early_device_probe(secondary, dev, mmio_base); + } + + /* Disable MMIO window if we found no suitable device. */ + if (ret) + pci_bridge_set_mmio(p2p_bridge, 0, 0); + + /* Resource allocator will reconfigure bridges and secondary bus + * number may change. Thus early device cannot reliably use config + * transactions from here on, so we may as well disable them. + */ + pci_bridge_set_secondary(p2p_bridge, 0); +} +#endif /* CONFIG_EARLY_PCI_BRIDGE */ diff --git a/src/drivers/oxford/oxpcie/Kconfig b/src/drivers/oxford/oxpcie/Kconfig index 5ad42aa..c2ea7b6 100644 --- a/src/drivers/oxford/oxpcie/Kconfig +++ b/src/drivers/oxford/oxpcie/Kconfig @@ -1,68 +1,10 @@ config DRIVERS_OXFORD_OXPCIE bool "Oxford OXPCIe952" default n + depends on PCI select DRIVERS_UART_8250MEM + select EARLY_PCI_BRIDGE help Support for Oxford OXPCIe952 serial port PCIe cards. Currently only devices with the vendor ID 0x1415 and device ID - 0xc158 will work. - NOTE: Right now you have to set the base address of your OXPCIe952 - card to exactly the value that the device allocator would set them - later on, or serial console functionality will stop as soon as the - resource allocator assigns a new base address to the device. - -config OXFORD_OXPCIE_BRIDGE_BUS - hex "OXPCIe's PCIe bridge bus number" - default 0x0 - depends on DRIVERS_OXFORD_OXPCIE - help - While coreboot is executing code from ROM, the coreboot resource - allocator has not been running yet. Hence PCI devices living behind - a bridge are not yet visible to the system. In order to use an - OXPCIe952 based PCIe card, coreboot has to set up the PCIe bridge - that controls the OXPCIe952 controller first. - -config OXFORD_OXPCIE_BRIDGE_DEVICE - hex "OXPCIe's PCIe bridge device number" - default 0x1c - depends on DRIVERS_OXFORD_OXPCIE - help - While coreboot is executing code from ROM, the coreboot resource - allocator has not been running yet. Hence PCI devices living behind - a bridge are not yet visible to the system. In order to use an - OXPCIe952 based PCIe card, coreboot has to set up the PCIe bridge - that controls the OXPCIe952 controller first. - -config OXFORD_OXPCIE_BRIDGE_FUNCTION - hex "OXPCIe's PCIe bridge function number" - default 0x2 - depends on DRIVERS_OXFORD_OXPCIE - help - While coreboot is executing code from ROM, the coreboot resource - allocator has not been running yet. Hence PCI devices living behind - a bridge are not yet visible to the system. In order to use an - OXPCIe952 based PCIe card, coreboot has to set up the PCIe bridge - that controls the OXPCIe952 controller first. - -config OXFORD_OXPCIE_BRIDGE_SUBORDINATE - hex "OXPCIe's PCIe bridge subordinate bus" - default 0x3 - depends on DRIVERS_OXFORD_OXPCIE - help - While coreboot is executing code from ROM, the coreboot resource - allocator has not been running yet. Hence PCI devices living behind - a bridge are not yet visible to the system. In order to use an - OXPCIe952 based PCIe card, coreboot has to set up the PCIe bridge - that controls the OXPCIe952 controller first. - -config OXFORD_OXPCIE_BASE_ADDRESS - hex "Base address for rom stage console" - default 0xe0400000 - depends on DRIVERS_OXFORD_OXPCIE - help - While coreboot is executing code from ROM, the coreboot resource - allocator has not been running yet. Hence PCI devices living behind - a bridge are not yet visible to the system. In order to use an - OXPCIe952 based PCIe card, coreboot has to set up a temporary address - for the OXPCIe952 controller. - + 0xc158 or 0xc11b will work. diff --git a/src/drivers/oxford/oxpcie/oxpcie_early.c b/src/drivers/oxford/oxpcie/oxpcie_early.c index 7de9da6..b81fa89 100644 --- a/src/drivers/oxford/oxpcie/oxpcie_early.c +++ b/src/drivers/oxford/oxpcie/oxpcie_early.c @@ -23,101 +23,53 @@ #include <stddef.h> #include <arch/io.h> #include <arch/early_variables.h> -#include <delay.h> #include <boot/coreboot_tables.h> #include <console/uart.h> #include <device/pci.h> #include <device/pci_def.h>
static unsigned int oxpcie_present CAR_GLOBAL; -static ROMSTAGE_CONST u32 uart0_base = CONFIG_OXFORD_OXPCIE_BASE_ADDRESS + 0x1000; -static ROMSTAGE_CONST u32 uart1_base = CONFIG_OXFORD_OXPCIE_BASE_ADDRESS + 0x2000; +static ROMSTAGE_CONST u32 uart0_base = CONFIG_EARLY_PCI_MMIO_BASE + 0x1000; +static ROMSTAGE_CONST u32 uart1_base = CONFIG_EARLY_PCI_MMIO_BASE + 0x2000;
-#define PCIE_BRIDGE \ - PCI_DEV(CONFIG_OXFORD_OXPCIE_BRIDGE_BUS, \ - CONFIG_OXFORD_OXPCIE_BRIDGE_DEVICE, \ - CONFIG_OXFORD_OXPCIE_BRIDGE_FUNCTION) - -#define OXPCIE_DEVICE \ - PCI_DEV(CONFIG_OXFORD_OXPCIE_BRIDGE_SUBORDINATE, 0, 0) - -#define OXPCIE_DEVICE_3 \ - PCI_DEV(CONFIG_OXFORD_OXPCIE_BRIDGE_SUBORDINATE, 0, 3) - -static void oxpcie_init_bridge(void) +int pci_early_device_probe(u8 bus, u8 dev, u32 mmio_base) { - u16 reg16; - - /* First we reset the secondary bus */ - reg16 = pci_read_config16(PCIE_BRIDGE, PCI_BRIDGE_CONTROL); - reg16 |= (1 << 6); /* SRESET */ - pci_write_config16(PCIE_BRIDGE, PCI_BRIDGE_CONTROL, reg16); - - /* Assume we don't have to wait here forever */ + pci_devfn_t device = PCI_DEV(bus, dev, 0);
- /* Read back and clear reset bit. */ - reg16 = pci_read_config16(PCIE_BRIDGE, PCI_BRIDGE_CONTROL); - reg16 &= ~(1 << 6); /* SRESET */ - pci_write_config16(PCIE_BRIDGE, PCI_BRIDGE_CONTROL, reg16); - - /* Set up subordinate bus number */ - pci_write_config8(PCIE_BRIDGE, PCI_SECONDARY_BUS, 0x00); - pci_write_config8(PCIE_BRIDGE, PCI_SUBORDINATE_BUS, 0x00); - pci_write_config8(PCIE_BRIDGE, PCI_SECONDARY_BUS, - CONFIG_OXFORD_OXPCIE_BRIDGE_SUBORDINATE); - pci_write_config8(PCIE_BRIDGE, PCI_SUBORDINATE_BUS, - CONFIG_OXFORD_OXPCIE_BRIDGE_SUBORDINATE); - - /* Memory window for the OXPCIe952 card */ - // XXX is the calculation of base and limit correct? - pci_write_config32(PCIE_BRIDGE, PCI_MEMORY_BASE, - ((CONFIG_OXFORD_OXPCIE_BASE_ADDRESS & 0xffff0000) | - ((CONFIG_OXFORD_OXPCIE_BASE_ADDRESS >> 16) & 0xff00))); - - /* Enable memory access through bridge */ - reg16 = pci_read_config16(PCIE_BRIDGE, PCI_COMMAND); - reg16 |= PCI_COMMAND_MEMORY; - pci_write_config16(PCIE_BRIDGE, PCI_COMMAND, reg16); - - u32 timeout = 20000; // Timeout in 10s of microseconds. - u32 id = 0; - for (;;) { - id = pci_read_config32(OXPCIE_DEVICE, PCI_VENDOR_ID); - if (!timeout-- || (id != 0 && id != 0xffffffff)) - break; - udelay(10); - } - - u32 device = OXPCIE_DEVICE; /* unknown default */ + u32 id = pci_read_config32(device, PCI_VENDOR_ID); switch (id) { - case 0xc1181415: /* e.g. Startech PEX1S1PMINI */ + case 0xc1181415: /* e.g. Startech PEX1S1PMINI function 0 */ /* On this device function 0 is the parallel port, and * function 3 is the serial port. So let's go look for * the UART. */ - id = pci_read_config32(OXPCIE_DEVICE_3, PCI_VENDOR_ID); + device = PCI_DEV(bus, dev, 3); + id = pci_read_config32(device, PCI_VENDOR_ID); if (id != 0xc11b1415) - return; - device = OXPCIE_DEVICE_3; + return -1; break; + case 0xc11b1415: /* e.g. Startech PEX1S1PMINI function 3 */ case 0xc1581415: /* e.g. Startech MPEX2S952 */ - device = OXPCIE_DEVICE; break; default: /* No UART here. */ - return; + return -1; }
+ /* Sanity-check, we assume fixed location. */ + if (mmio_base != CONFIG_EARLY_PCI_MMIO_BASE) + return -1; + /* Setup base address on device */ - pci_write_config32(device, PCI_BASE_ADDRESS_0, - CONFIG_OXFORD_OXPCIE_BASE_ADDRESS); + pci_write_config32(device, PCI_BASE_ADDRESS_0, mmio_base);
/* Enable memory on device */ - reg16 = pci_read_config16(device, PCI_COMMAND); + u16 reg16 = pci_read_config16(device, PCI_COMMAND); reg16 |= PCI_COMMAND_MEMORY; pci_write_config16(device, PCI_COMMAND, reg16);
car_set_var(oxpcie_present, 1); + return 0; }
static int oxpcie_uart_active(void) @@ -157,8 +109,3 @@ unsigned int uart_platform_refclk(void) { return 62500000; } - -void oxford_init(void) -{ - oxpcie_init_bridge(); -} diff --git a/src/include/console/uart.h b/src/include/console/uart.h index 4516b71..7d92a21 100644 --- a/src/include/console/uart.h +++ b/src/include/console/uart.h @@ -47,7 +47,6 @@ int uart_can_rx_byte(void);
unsigned int uart_platform_base(int idx);
-void oxford_init(void); void oxford_remap(unsigned int new_base);
#endif /* CONSOLE_UART_H */ diff --git a/src/include/device/pci.h b/src/include/device/pci.h index 29d988f..f729c27 100644 --- a/src/include/device/pci.h +++ b/src/include/device/pci.h @@ -102,6 +102,8 @@ static inline const struct pci_operations *ops_pci(device_t dev)
unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last); unsigned pci_find_capability(device_t dev, unsigned cap); +void pci_early_bridge_init(void); +int pci_early_device_probe(u8 bus, u8 dev, u32 mmio_base);
#endif /* CONFIG_PCI */
diff --git a/src/southbridge/intel/bd82x6x/Kconfig b/src/southbridge/intel/bd82x6x/Kconfig index 9cfa5d5..14281e6 100644 --- a/src/southbridge/intel/bd82x6x/Kconfig +++ b/src/southbridge/intel/bd82x6x/Kconfig @@ -41,6 +41,22 @@ config EHCI_BAR hex default 0xfef00000
+if EARLY_PCI_BRIDGE + +config EARLY_PCI_BRIDGE_DEVICE + hex + default 0x1c + +config EARLY_PCI_BRIDGE_FUNCTION + hex + default 0x2 + +config EARLY_PCI_MMIO_BASE + hex + default 0xe0400000 + +endif + config DRAM_RESET_GATE_GPIO int default 60