[coreboot-gerrit] Change in ...coreboot[master]: [WIP]sb/intel/i82801gx: Autodisable functions based on devicetree
Arthur Heymans (Code Review)
gerrit at coreboot.org
Sat Dec 15 23:48:50 CET 2018
Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/30244
Change subject: [WIP]sb/intel/i82801gx: Autodisable functions based on devicetree
......................................................................
[WIP]sb/intel/i82801gx: Autodisable functions based on devicetree
This mostly reimplements what sandybridge does albeit a bit simpler
TODO:
- remove romstage FD
- What about INTLAN?
TESTED with coalescing (root port 0 disabled in devicetree)
Change-Id: I83576599538a02d295fe00b35826f98d8c97d1cf
Signed-off-by: Arthur Heymans <arthur at aheymans.xyz>
---
M src/southbridge/intel/i82801gx/i82801gx.c
M src/southbridge/intel/i82801gx/i82801gx.h
2 files changed, 205 insertions(+), 7 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/44/30244/1
diff --git a/src/southbridge/intel/i82801gx/i82801gx.c b/src/southbridge/intel/i82801gx/i82801gx.c
index eb0583f..2541fc6 100644
--- a/src/southbridge/intel/i82801gx/i82801gx.c
+++ b/src/southbridge/intel/i82801gx/i82801gx.c
@@ -20,18 +20,204 @@
#include "i82801gx.h"
#include "sata.h"
+static void ich_hide_devfn(unsigned int devfn)
+{
+ switch (devfn) {
+ case PCI_DEVFN(27, 0): /* HD Audio Controller */
+ RCBA32_OR(FD, FD_HDAUD);
+ break;
+ case PCI_DEVFN(28, 0): /* PCI Express Root Port 1 */
+ case PCI_DEVFN(28, 1): /* PCI Express Root Port 2 */
+ case PCI_DEVFN(28, 2): /* PCI Express Root Port 3 */
+ case PCI_DEVFN(28, 3): /* PCI Express Root Port 4 */
+ case PCI_DEVFN(28, 4): /* PCI Express Root Port 5 */
+ case PCI_DEVFN(28, 5): /* PCI Express Root Port 6 */
+ RCBA32_OR(FD, ICH_DISABLE_PCIE(PCI_FUNC(devfn)));
+ break;
+ case PCI_DEVFN(29, 0): /* UHCI #1 */
+ case PCI_DEVFN(29, 1): /* UHCI #2 */
+ case PCI_DEVFN(29, 2): /* UHCI #3 */
+ case PCI_DEVFN(29, 3): /* UHCI #4 */
+ RCBA32_OR(FD, ICH_DISABLE_UHCI(PCI_FUNC(devfn)));
+ break;
+ case PCI_DEVFN(29, 7): /* EHCI #1 */
+ RCBA32_OR(FD, FD_EHCI);
+ break;
+ case PCI_DEVFN(30, 2): /* AC Audio */
+ RCBA32_OR(FD, FD_ACMOD);
+ break;
+ case PCI_DEVFN(30, 3): /* AC Modem */
+ RCBA32_OR(FD, FD_ACMOD);
+ break;
+ case PCI_DEVFN(31, 0): /* LPC */
+ RCBA32_OR(FD, FD_LPCB);
+ break;
+ case PCI_DEVFN(31, 1): /* PATA #1 */
+ RCBA32_OR(FD, FD_PATA);
+ break;
+ case PCI_DEVFN(31, 2): /* SATA #1 */
+ RCBA32_OR(FD, FD_PATA);
+ break;
+ case PCI_DEVFN(31, 3): /* SMBUS */
+ RCBA32_OR(FD, FD_SMBUS);
+ break;
+ }
+}
+
+/* RPFN is a write-once register so keep a copy until it is written */
+static u32 new_rpfn;
+
+/* Update devicetree with new Root Port function number assignment */
+static void ich_pcie_devicetree_update(
+ struct southbridge_intel_i82801gx_config *config)
+{
+ struct device *dev;
+
+ /* Update the function numbers in the static devicetree */
+ for (dev = all_devices; dev; dev = dev->next) {
+ u8 new_devfn;
+
+ /* Only care about ICH PCIe root ports */
+ if (PCI_SLOT(dev->path.pci.devfn) != ICH_PCIE_DEV_SLOT)
+ continue;
+
+ /* Determine the new devfn for this port */
+ new_devfn = PCI_DEVFN(ICH_PCIE_DEV_SLOT,
+ RPFN_FNGET(new_rpfn,
+ PCI_FUNC(dev->path.pci.devfn)));
+
+ if (dev->path.pci.devfn != new_devfn) {
+ printk(BIOS_DEBUG,
+ "ICH: PCIe map %02x.%1x -> %02x.%1x\n",
+ PCI_SLOT(dev->path.pci.devfn),
+ PCI_FUNC(dev->path.pci.devfn),
+ PCI_SLOT(new_devfn), PCI_FUNC(new_devfn));
+
+ dev->path.pci.devfn = new_devfn;
+ }
+ }
+}
+
+/* Swap function numbers assigned to two PCIe Root Ports */
+static void ich_pcie_function_swap(u8 old_fn, u8 new_fn)
+{
+ u32 old_rpfn = new_rpfn;
+
+ printk(BIOS_DEBUG, "ICH: Remap PCIe function %d to %d\n",
+ old_fn, new_fn);
+
+ new_rpfn &= ~(RPFN_FNMASK(old_fn) | RPFN_FNMASK(new_fn));
+
+ /* Old function set to new function and disabled */
+ new_rpfn |= RPFN_FNSET(old_fn, RPFN_FNGET(old_rpfn, new_fn));
+ new_rpfn |= RPFN_FNSET(new_fn, RPFN_FNGET(old_rpfn, old_fn));
+}
+
+/* Special handling for PCIe Root Port devices */
+static void ich_pcie_enable(struct device *dev)
+{
+ struct southbridge_intel_i82801gx_config *config = dev->chip_info;
+ u32 reg32;
+ static int pcie_port_coalesce = 0;
+ static int port_coalescence_done = 0;
+
+ if (!config)
+ return;
+
+ /*
+ * Save a copy of the Root Port Function Number map when
+ * starting to walk the list of PCIe Root Ports so it can
+ * be updated locally and written out when the last port
+ * has been processed.
+ */
+ if (PCI_FUNC(dev->path.pci.devfn) == 0) {
+ new_rpfn = RCBA32(RPFN);
+
+ /*
+ * Enable Root Port coalescing if the first port is disabled
+ * or the other devices will not be enumerated by the OS.
+ */
+ if (!dev->enabled)
+ pcie_port_coalesce = 1;
+
+ if (pcie_port_coalesce)
+ printk(BIOS_INFO,
+ "ICH: PCIe Root Port coalescing is enabled\n");
+ }
+
+ if (!dev->enabled) {
+ printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
+
+ /* Ensure memory, io, and bus master are all disabled */
+ reg32 = pci_read_config32(dev, PCI_COMMAND);
+ reg32 &= ~(PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+ pci_write_config32(dev, PCI_COMMAND, reg32);
+
+ /* Hide this device if possible */
+ ich_hide_devfn(dev->path.pci.devfn);
+ } else {
+ /*
+ * Check if there is a lower disabled port to swap with this
+ * port in order to maintain linear order starting at zero.
+ */
+ if (pcie_port_coalesce && !port_coalescence_done) {
+ /* Swap places with this function */
+ ich_pcie_function_swap(PCI_FUNC(dev->path.pci.devfn),
+ 0);
+ port_coalescence_done = 1;
+ }
+
+ /* Enable SERR */
+ reg32 = pci_read_config32(dev, PCI_COMMAND);
+ reg32 |= PCI_COMMAND_SERR;
+ pci_write_config32(dev, PCI_COMMAND, reg32);
+ }
+
+ /*
+ * When processing the last PCIe root port we can now
+ * update the Root Port Function Number and Hide register.
+ */
+ if (PCI_FUNC(dev->path.pci.devfn) == 5) {
+ printk(BIOS_SPEW, "ICH: RPFN 0x%08x -> 0x%08x\n",
+ RCBA32(RPFN), new_rpfn);
+ RCBA32(RPFN) = new_rpfn;
+
+ /* Update static devictree with new function numbers */
+ if (pcie_port_coalesce)
+ ich_pcie_devicetree_update(config);
+ }
+}
+
void i82801gx_enable(struct device *dev)
{
u32 reg32;
- /* Enable SERR */
- reg32 = pci_read_config32(dev, PCI_COMMAND);
- reg32 |= PCI_COMMAND_SERR;
- pci_write_config32(dev, PCI_COMMAND, reg32);
+ /* ICH PCIe Root Ports get special handling */
+ if (PCI_SLOT(dev->path.pci.devfn) == ICH_PCIE_DEV_SLOT)
+ return ich_pcie_enable(dev);
- if (dev->path.pci.devfn == PCI_DEVFN(31, 2)) {
- printk(BIOS_DEBUG, "Set SATA mode early\n");
- sata_enable(dev);
+ if (!dev->enabled) {
+ printk(BIOS_DEBUG, "%s: Disabling device\n", dev_path(dev));
+
+ /* Ensure memory, io, and bus master are all disabled */
+ reg32 = pci_read_config32(dev, PCI_COMMAND);
+ reg32 &= ~(PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
+ pci_write_config32(dev, PCI_COMMAND, reg32);
+
+ /* Hide this device if possible */
+ ich_hide_devfn(dev->path.pci.devfn);
+ } else {
+ /* Enable SERR */
+ reg32 = pci_read_config32(dev, PCI_COMMAND);
+ reg32 |= PCI_COMMAND_SERR;
+ pci_write_config32(dev, PCI_COMMAND, reg32);
+
+ if (dev->path.pci.devfn == PCI_DEVFN(31, 2)) {
+ printk(BIOS_DEBUG, "Set SATA mode early\n");
+ sata_enable(dev);
+ }
}
}
diff --git a/src/southbridge/intel/i82801gx/i82801gx.h b/src/southbridge/intel/i82801gx/i82801gx.h
index 40c2bb7..c1235ed 100644
--- a/src/southbridge/intel/i82801gx/i82801gx.h
+++ b/src/southbridge/intel/i82801gx/i82801gx.h
@@ -72,6 +72,8 @@
#define SEE (1 << 1)
#define PERE (1 << 0)
+#define ICH_PCIE_DEV_SLOT 28
+
/* PCI Configuration Space (D31:F0): LPC */
#define SERIRQ_CNTL 0x64
@@ -231,6 +233,13 @@
#define RPC 0x0224 /* 32bit */
#define RPFN 0x0238 /* 32bit */
+/* Get the function number assigned to a Root Port */
+#define RPFN_FNGET(reg, port) (((reg) >> ((port) * 4)) & 7)
+/* Set the function number for a Root Port */
+#define RPFN_FNSET(port, func) (((func) & 7) << ((port) * 4))
+/* Root Port function number mask */
+#define RPFN_FNMASK(port) (7 << ((port) * 4))
+
#define TRSR 0x1e00 /* 8bit */
#define TRCR 0x1e10 /* 64bit */
#define TWDR 0x1e18 /* 64bit */
@@ -273,6 +282,7 @@
#define FD_PCIE3 (1 << 18)
#define FD_PCIE2 (1 << 17)
#define FD_PCIE1 (1 << 16)
+#define ICH_DISABLE_PCIE(x) (1 << (16 + x))
#define FD_EHCI (1 << 15)
#define FD_LPCB (1 << 14)
@@ -283,6 +293,8 @@
#define FD_UHCI34 ((1 << 10) | FD_UHCI4)
#define FD_UHCI234 ((1 << 9) | FD_UHCI3)
#define FD_UHCI1234 ((1 << 8) | FD_UHCI2)
+#define ICH_DISABLE_UHCI(x) (1 << (8 + x))
+
#define FD_INTLAN (1 << 7)
#define FD_ACMOD (1 << 6)
--
To view, visit https://review.coreboot.org/c/coreboot/+/30244
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I83576599538a02d295fe00b35826f98d8c97d1cf
Gerrit-Change-Number: 30244
Gerrit-PatchSet: 1
Gerrit-Owner: Arthur Heymans <arthur at aheymans.xyz>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20181215/61a5deef/attachment-0001.html>
More information about the coreboot-gerrit
mailing list