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:
parent
afa7b13b93
commit
4c686f2106
|
@ -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>
|
||||
|
@ -40,6 +45,9 @@ void console_init(void)
|
|||
if(get_option(&console_loglevel, "debug_level") != CB_SUCCESS)
|
||||
console_loglevel=CONFIG_DEFAULT_CONSOLE_LOGLEVEL;
|
||||
|
||||
#if CONFIG_EARLY_PCI_BRIDGE
|
||||
pci_early_bridge_init();
|
||||
#endif
|
||||
for(driver = console_drivers; driver < econsole_drivers; driver++) {
|
||||
if (!driver->init)
|
||||
continue;
|
||||
|
@ -101,8 +109,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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,100 @@ 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;
|
||||
|
||||
/* 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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
pci_devfn_t device = PCI_DEV(bus, dev, 0);
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ static inline void *uart_platform_baseptr(int idx)
|
|||
}
|
||||
#endif
|
||||
|
||||
void oxford_init(void);
|
||||
void oxford_remap(unsigned int new_base);
|
||||
|
||||
#endif /* CONSOLE_UART_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 */
|
||||
|
||||
|
|
|
@ -46,4 +46,20 @@ config MAINBOARD_POWER_ON_AFTER_POWER_FAIL
|
|||
bool
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue