OxPCIe uart: Split PCI bridge control

None of the PCI bridge management here is specific to the PCI UART
device/function. Also the Kconfig variable defaults are not globally
valid, fill samsung/lumpy with working values.

Change-Id: Id22631412379af1d6bf62c996357d36d7ec47ca3
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/5237
Tested-by: build bot (Jenkins)
Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
This commit is contained in:
Kyösti Mälkki 2014-02-14 12:45:09 +02:00 committed by Patrick Georgi
parent afa7b13b93
commit 4c686f2106
9 changed files with 183 additions and 135 deletions

View File

@ -28,6 +28,11 @@
#include <arch/hlt.h> #include <arch/hlt.h>
#include <arch/io.h> #include <arch/io.h>
#if CONFIG_EARLY_PCI_BRIDGE
/* FIXME: ROMCC chokes on PCI headers. */
#include <device/pci.h>
#endif
#ifndef __PRE_RAM__ #ifndef __PRE_RAM__
#include <string.h> #include <string.h>
#include <types.h> #include <types.h>
@ -40,6 +45,9 @@ void console_init(void)
if(get_option(&console_loglevel, "debug_level") != CB_SUCCESS) if(get_option(&console_loglevel, "debug_level") != CB_SUCCESS)
console_loglevel=CONFIG_DEFAULT_CONSOLE_LOGLEVEL; console_loglevel=CONFIG_DEFAULT_CONSOLE_LOGLEVEL;
#if CONFIG_EARLY_PCI_BRIDGE
pci_early_bridge_init();
#endif
for(driver = console_drivers; driver < econsole_drivers; driver++) { for(driver = console_drivers; driver < econsole_drivers; driver++) {
if (!driver->init) if (!driver->init)
continue; continue;
@ -101,8 +109,8 @@ void console_init(void)
#if defined(__BOOT_BLOCK__) && CONFIG_BOOTBLOCK_CONSOLE || \ #if defined(__BOOT_BLOCK__) && CONFIG_BOOTBLOCK_CONSOLE || \
!defined(__BOOT_BLOCK__) && CONFIG_EARLY_CONSOLE !defined(__BOOT_BLOCK__) && CONFIG_EARLY_CONSOLE
#if CONFIG_DRIVERS_OXFORD_OXPCIE #if CONFIG_EARLY_PCI_BRIDGE
oxford_init(); pci_early_bridge_init();
#endif #endif
#if CONFIG_CONSOLE_SERIAL #if CONFIG_CONSOLE_SERIAL
uart_init(); uart_init();

View File

@ -237,6 +237,35 @@ config PCIEXP_ASPM
config PCI_BUS_SEGN_BITS config PCI_BUS_SEGN_BITS
int int
default 0 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 endmenu
menu "VGA BIOS" menu "VGA BIOS"

View File

@ -11,6 +11,7 @@ ramstage-$(CONFIG_CARDBUS_PLUGIN_SUPPORT) += cardbus_device.c
ramstage-$(CONFIG_AZALIA_PLUGIN_SUPPORT) += azalia_device.c ramstage-$(CONFIG_AZALIA_PLUGIN_SUPPORT) += azalia_device.c
ramstage-$(CONFIG_ARCH_X86) += pnp_device.c ramstage-$(CONFIG_ARCH_X86) += pnp_device.c
ramstage-$(CONFIG_PCI) += pci_ops.c ramstage-$(CONFIG_PCI) += pci_ops.c
ramstage-$(CONFIG_PCI) += pci_early.c
ramstage-y += smbus_ops.c ramstage-y += smbus_ops.c
romstage-y += device_romstage.c romstage-y += device_romstage.c

View File

@ -1,6 +1,8 @@
/* /*
* This file is part of the coreboot project. * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License. * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/ */
#define __SIMPLE_DEVICE__
#include <arch/io.h> #include <arch/io.h>
#include <device/pci.h> #include <device/pci.h>
#include <device/pci_def.h> #include <device/pci_def.h>
#include <delay.h>
#ifdef __PRE_RAM__
unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last) unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last)
{ {
@ -66,3 +73,100 @@ unsigned pci_find_capability(device_t dev, unsigned cap)
{ {
return pci_find_next_capability(dev, cap, 0); 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;
/* 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_SECONDARY_BUS, 0x00);
pci_write_config8(p2p_bridge, PCI_SUBORDINATE_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; timeout--) {
u32 id = pci_read_config32(PCI_DEV(secondary, dev, 0), PCI_VENDOR_ID);
if (id != 0 && id != 0xffffffff && id != 0xffff0001)
break;
udelay(10);
}
if (timeout != 0)
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 */

View File

@ -1,68 +1,10 @@
config DRIVERS_OXFORD_OXPCIE config DRIVERS_OXFORD_OXPCIE
bool "Oxford OXPCIe952" bool "Oxford OXPCIe952"
default n default n
depends on PCI
select DRIVERS_UART_8250MEM select DRIVERS_UART_8250MEM
select EARLY_PCI_BRIDGE
help help
Support for Oxford OXPCIe952 serial port PCIe cards. Support for Oxford OXPCIe952 serial port PCIe cards.
Currently only devices with the vendor ID 0x1415 and device ID Currently only devices with the vendor ID 0x1415 and device ID
0xc158 will work. 0xc158 or 0xc11b 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.

View File

@ -23,101 +23,53 @@
#include <stddef.h> #include <stddef.h>
#include <arch/io.h> #include <arch/io.h>
#include <arch/early_variables.h> #include <arch/early_variables.h>
#include <delay.h>
#include <boot/coreboot_tables.h> #include <boot/coreboot_tables.h>
#include <console/uart.h> #include <console/uart.h>
#include <device/pci.h> #include <device/pci.h>
#include <device/pci_def.h> #include <device/pci_def.h>
static unsigned int oxpcie_present CAR_GLOBAL; static unsigned int oxpcie_present CAR_GLOBAL;
static ROMSTAGE_CONST u32 uart0_base = CONFIG_OXFORD_OXPCIE_BASE_ADDRESS + 0x1000; static ROMSTAGE_CONST u32 uart0_base = CONFIG_EARLY_PCI_MMIO_BASE + 0x1000;
static ROMSTAGE_CONST u32 uart1_base = CONFIG_OXFORD_OXPCIE_BASE_ADDRESS + 0x2000; static ROMSTAGE_CONST u32 uart1_base = CONFIG_EARLY_PCI_MMIO_BASE + 0x2000;
#define PCIE_BRIDGE \ int pci_early_device_probe(u8 bus, u8 dev, u32 mmio_base)
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)
{ {
u16 reg16; pci_devfn_t device = PCI_DEV(bus, dev, 0);
/* First we reset the secondary bus */ u32 id = pci_read_config32(device, PCI_VENDOR_ID);
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 */
/* 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 */
switch (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 /* On this device function 0 is the parallel port, and
* function 3 is the serial port. So let's go look for * function 3 is the serial port. So let's go look for
* the UART. * 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) if (id != 0xc11b1415)
return; return -1;
device = OXPCIE_DEVICE_3;
break; break;
case 0xc11b1415: /* e.g. Startech PEX1S1PMINI function 3 */
case 0xc1581415: /* e.g. Startech MPEX2S952 */ case 0xc1581415: /* e.g. Startech MPEX2S952 */
device = OXPCIE_DEVICE;
break; break;
default: default:
/* No UART here. */ /* 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 */ /* Setup base address on device */
pci_write_config32(device, PCI_BASE_ADDRESS_0, pci_write_config32(device, PCI_BASE_ADDRESS_0, mmio_base);
CONFIG_OXFORD_OXPCIE_BASE_ADDRESS);
/* Enable memory on device */ /* Enable memory on device */
reg16 = pci_read_config16(device, PCI_COMMAND); u16 reg16 = pci_read_config16(device, PCI_COMMAND);
reg16 |= PCI_COMMAND_MEMORY; reg16 |= PCI_COMMAND_MEMORY;
pci_write_config16(device, PCI_COMMAND, reg16); pci_write_config16(device, PCI_COMMAND, reg16);
car_set_var(oxpcie_present, 1); car_set_var(oxpcie_present, 1);
return 0;
} }
static int oxpcie_uart_active(void) static int oxpcie_uart_active(void)
@ -157,8 +109,3 @@ unsigned int uart_platform_refclk(void)
{ {
return 62500000; return 62500000;
} }
void oxford_init(void)
{
oxpcie_init_bridge();
}

View File

@ -54,7 +54,6 @@ static inline void *uart_platform_baseptr(int idx)
} }
#endif #endif
void oxford_init(void);
void oxford_remap(unsigned int new_base); void oxford_remap(unsigned int new_base);
#endif /* CONSOLE_UART_H */ #endif /* CONSOLE_UART_H */

View File

@ -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_next_capability(device_t dev, unsigned cap, unsigned last);
unsigned pci_find_capability(device_t dev, unsigned cap); 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 */ #endif /* CONFIG_PCI */

View File

@ -46,4 +46,20 @@ config MAINBOARD_POWER_ON_AFTER_POWER_FAIL
bool bool
default n default n
if EARLY_PCI_BRIDGE
config EARLY_PCI_BRIDGE_DEVICE
hex
default 0x1c
config EARLY_PCI_BRIDGE_FUNCTION
hex
default 0x0
config EARLY_PCI_MMIO_BASE
hex
default 0xe0400000
endif
endif # BOARD_SAMSUNG_LUMPY endif # BOARD_SAMSUNG_LUMPY