summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
Diffstat (limited to 'src/device')
-rw-r--r--src/device/Kconfig29
-rw-r--r--src/device/Makefile.inc1
-rw-r--r--src/device/pci_early.c104
3 files changed, 134 insertions, 0 deletions
diff --git a/src/device/Kconfig b/src/device/Kconfig
index eaa0c042f7..932b4de540 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 ce412b7840..bd41b12d76 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 c15a4d0f77..e31287e8bf 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,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 */