[coreboot-gerrit] Patch set updated for coreboot: 631312a baytrail: add support for disabling south cluster pci devices

Aaron Durbin (adurbin@google.com) gerrit at coreboot.org
Thu Feb 27 05:46:11 CET 2014


Aaron Durbin (adurbin at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4911

-gerrit

commit 631312a2ea9256d793aa005a025eb7bf40bf1e27
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Tue Oct 29 16:37:10 2013 -0500

    baytrail: add support for disabling south cluster pci devices
    
    When the southcluster pci devices are listed in the devicetree add
    the ability to perform the proper disabling sequence for turning
    off devices. This only turns off the pci device interface as well
    as put the device into D3Hot. It is not yet known how to put the TXE
    device into D3Hot so it's currently not possible to disable that
    device.
    
    Also, expose the southcluster_enable_dev() function so that other
    devices can call this if they require doing specific things before
    disabling the device. The southcluster_enable_dev() is only called
    on devices found in the devicetree and if they currently have no
    ops associated with them.
    
    BUG=chrome-os-partner:22871
    BRANCH=None
    TEST=Built and booted through depthcharge. Interrogated
         output to ensure devices were being properly disabled.
    
    Change-Id: I537ddcb9379907af2fe012948542b6150a8bf7c5
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
    Reviewed-on: https://chromium-review.googlesource.com/174644
    Reviewed-by: Duncan Laurie <dlaurie at chromium.org>
---
 src/soc/intel/baytrail/baytrail/pci_devs.h |   4 +
 src/soc/intel/baytrail/baytrail/pmc.h      |  33 ++++
 src/soc/intel/baytrail/baytrail/ramstage.h |   1 +
 src/soc/intel/baytrail/chip.c              |   8 +-
 src/soc/intel/baytrail/southcluster.c      | 268 ++++++++++++++++++++++++++++-
 5 files changed, 311 insertions(+), 3 deletions(-)

diff --git a/src/soc/intel/baytrail/baytrail/pci_devs.h b/src/soc/intel/baytrail/baytrail/pci_devs.h
index 8b0335e..f20102a 100644
--- a/src/soc/intel/baytrail/baytrail/pci_devs.h
+++ b/src/soc/intel/baytrail/baytrail/pci_devs.h
@@ -102,12 +102,16 @@
 
 /* PCIe Ports */
 #define PCIE_DEV 28
+# define PCIE_PORT1_DEV PCIE_DEV
 # define PCIE_PORT1_FUNC 0
 # define PCIE_PORT1_DEVID 0x0f48
+# define PCIE_PORT2_DEV PCIE_DEV
 # define PCIE_PORT2_FUNC 1
 # define PCIE_PORT2_DEVID 0x0f4a
+# define PCIE_PORT3_DEV PCIE_DEV
 # define PCIE_PORT3_FUNC 2
 # define PCIE_PORT3_DEVID 0x0f4c
+# define PCIE_PORT4_DEV PCIE_DEV
 # define PCIE_PORT4_FUNC 3
 # define PCIE_PORT4_DEVID 0x0f4e
 
diff --git a/src/soc/intel/baytrail/baytrail/pmc.h b/src/soc/intel/baytrail/baytrail/pmc.h
index e0e5cff..51f8887 100644
--- a/src/soc/intel/baytrail/baytrail/pmc.h
+++ b/src/soc/intel/baytrail/baytrail/pmc.h
@@ -33,6 +33,39 @@
 #	define IGNORE_HPET	(1 << 21)
 #	define CF9GR		(1 << 20)
 #	define CWORWRE		(1 << 18)
+#define FUNC_DIS	0x34
+#	define SIO_DMA2_DIS	(1 <<  0)
+#	define PWM1_DIS		(1 <<  1)
+#	define PWM2_DIS		(1 <<  2)
+#	define HSUART1_DIS	(1 <<  3)
+#	define HSUART2_DIS	(1 <<  4)
+#	define SPI_DIS		(1 <<  5)
+#	define SDIO_DIS		(1 <<  9)
+#	define SD_DIS		(1 << 10)
+#	define MMC_DIS		(1 << 11)
+#	define HDA_DIS		(1 << 12)
+#	define LPE_DIS		(1 << 13)
+#	define OTG_DIS		(1 << 14)
+#	define XHCI_DIS		(1 << 15)
+#	define SATA_DIS		(1 << 17)
+#	define EHCI_DIS		(1 << 18)
+#	define TXE_DIS		(1 << 19)
+#	define PCIE_PORT1_DIS	(1 << 20)
+#	define PCIE_PORT2_DIS	(1 << 21)
+#	define PCIE_PORT3_DIS	(1 << 22)
+#	define PCIE_PORT4_DIS	(1 << 23)
+#	define SIO_DMA1_DIS	(1 << 24)
+#	define I2C1_DIS		(1 << 25)
+#	define I2C2_DIS		(1 << 26)
+#	define I2C3_DIS		(1 << 27)
+#	define I2C4_DIS		(1 << 28)
+#	define I2C5_DIS		(1 << 29)
+#	define I2C6_DIS		(1 << 30)
+#	define I2C7_DIS		(1 << 31)
+#define FUNC_DIS2	0x38
+#	define USH_SS_PHY_DIS	(1 << 2)
+#	define OTG_SS_PHY_DIS	(1 << 1)
+#	define SMBUS_DIS	(1 << 0)
 
 /* IO Mapped registers behind ACPI_BASE_ADDRESS */
 #define PM1_STS			0x00
diff --git a/src/soc/intel/baytrail/baytrail/ramstage.h b/src/soc/intel/baytrail/baytrail/ramstage.h
index eaa8f6b..4fa6ddd 100644
--- a/src/soc/intel/baytrail/baytrail/ramstage.h
+++ b/src/soc/intel/baytrail/baytrail/ramstage.h
@@ -27,6 +27,7 @@
 void baytrail_init_pre_device(void);
 void baytrail_init_cpus(device_t dev);
 void set_max_freq(void);
+void southcluster_enable_dev(device_t dev);
 #if CONFIG_HAVE_REFCODE_BLOB
 void baytrail_run_reference_code(void);
 #else
diff --git a/src/soc/intel/baytrail/chip.c b/src/soc/intel/baytrail/chip.c
index 0f686fa..eedae39 100644
--- a/src/soc/intel/baytrail/chip.c
+++ b/src/soc/intel/baytrail/chip.c
@@ -53,13 +53,17 @@ static struct device_operations cpu_bus_ops = {
 
 static void enable_dev(device_t dev)
 {
-	printk(BIOS_DEBUG, "enable_dev(%s, %d)\n",
-	       dev_name(dev), dev->path.type);
 	/* Set the operations if it is a special bus type */
 	if (dev->path.type == DEVICE_PATH_DOMAIN) {
 		dev->ops = &pci_domain_ops;
 	} else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
 		dev->ops = &cpu_bus_ops;
+	} else if (dev->path.type == DEVICE_PATH_PCI) {
+		/* Handle south cluster enablement. */
+		if (PCI_SLOT(dev->path.pci.devfn) > GFX_DEV &&
+		    (dev->ops == NULL || dev->ops->enable == NULL)) {
+			southcluster_enable_dev(dev);
+		}
 	}
 }
 
diff --git a/src/soc/intel/baytrail/southcluster.c b/src/soc/intel/baytrail/southcluster.c
index 32b8799..b58f0e0 100644
--- a/src/soc/intel/baytrail/southcluster.c
+++ b/src/soc/intel/baytrail/southcluster.c
@@ -20,6 +20,7 @@
 
 #include <stdint.h>
 #include <arch/io.h>
+#include <console/console.h>
 #include <device/device.h>
 #include <device/pci.h>
 #include <device/pci_ids.h>
@@ -29,6 +30,7 @@
 #include <baytrail/lpc.h>
 #include <baytrail/nvs.h>
 #include <baytrail/pci_devs.h>
+#include <baytrail/pmc.h>
 #include <baytrail/ramstage.h>
 
 static inline void
@@ -113,12 +115,276 @@ static void sc_read_resources(device_t dev)
 	sc_add_io_resources(dev);
 }
 
+/*
+ * Common code for the south cluster devices.
+ */
+
+/* Set bit in function disble register to hide this device. */
+static void sc_disable_devfn(device_t dev)
+{
+	const unsigned long func_dis = PMC_BASE_ADDRESS + FUNC_DIS;
+	const unsigned long func_dis2 = PMC_BASE_ADDRESS + FUNC_DIS2;
+	uint32_t mask = 0;
+	uint32_t mask2 = 0;
+
+	switch (dev->path.pci.devfn) {
+	case PCI_DEVFN(SDIO_DEV, SDIO_FUNC):
+		mask |= SDIO_DIS;
+		break;
+	case PCI_DEVFN(SD_DEV, SD_FUNC):
+		mask |= SD_DIS;
+		break;
+	case PCI_DEVFN(SATA_DEV, SATA_FUNC):
+		mask |= SATA_DIS;
+		break;
+	case PCI_DEVFN(XHCI_DEV, XHCI_FUNC):
+		mask |= XHCI_DIS;
+		/* Disable super speed PHY when XHCI is not available. */
+		mask2 |= USH_SS_PHY_DIS;
+		break;
+	case PCI_DEVFN(LPE_DEV, LPE_FUNC):
+		mask |= LPE_DIS;
+		break;
+	case PCI_DEVFN(MMC_DEV, MMC_FUNC):
+		mask |= MMC_DIS;
+		break;
+	case PCI_DEVFN(SIO_DMA1_DEV, SIO_DMA1_FUNC):
+		mask |= SIO_DMA1_DIS;
+		break;
+	case PCI_DEVFN(I2C1_DEV, I2C1_FUNC):
+		mask |= I2C1_DIS;
+		break;
+	case PCI_DEVFN(I2C2_DEV, I2C2_FUNC):
+		mask |= I2C1_DIS;
+		break;
+	case PCI_DEVFN(I2C3_DEV, I2C3_FUNC):
+		mask |= I2C3_DIS;
+		break;
+	case PCI_DEVFN(I2C4_DEV, I2C4_FUNC):
+		mask |= I2C4_DIS;
+		break;
+	case PCI_DEVFN(I2C5_DEV, I2C5_FUNC):
+		mask |= I2C5_DIS;
+		break;
+	case PCI_DEVFN(I2C6_DEV, I2C6_FUNC):
+		mask |= I2C6_DIS;
+		break;
+	case PCI_DEVFN(I2C7_DEV, I2C7_FUNC):
+		mask |= I2C7_DIS;
+		break;
+	case PCI_DEVFN(TXE_DEV, TXE_FUNC):
+		mask |= TXE_DIS;
+		break;
+	case PCI_DEVFN(HDA_DEV, HDA_FUNC):
+		mask |= HDA_DIS;
+		break;
+	case PCI_DEVFN(PCIE_PORT1_DEV, PCIE_PORT1_FUNC):
+		mask |= PCIE_PORT1_DIS;
+		break;
+	case PCI_DEVFN(PCIE_PORT2_DEV, PCIE_PORT2_FUNC):
+		mask |= PCIE_PORT2_DIS;
+		break;
+	case PCI_DEVFN(PCIE_PORT3_DEV, PCIE_PORT3_FUNC):
+		mask |= PCIE_PORT3_DIS;
+		break;
+	case PCI_DEVFN(PCIE_PORT4_DEV, PCIE_PORT4_FUNC):
+		mask |= PCIE_PORT4_DIS;
+		break;
+	case PCI_DEVFN(EHCI_DEV, EHCI_FUNC):
+		mask |= EHCI_DIS;
+		break;
+	case PCI_DEVFN(SIO_DMA2_DEV, SIO_DMA2_FUNC):
+		mask |= SIO_DMA2_DIS;
+		break;
+	case PCI_DEVFN(PWM1_DEV, PWM1_FUNC):
+		mask |= PWM1_DIS;
+		break;
+	case PCI_DEVFN(PWM2_DEV, PWM2_FUNC):
+		mask |= PWM2_DIS;
+		break;
+	case PCI_DEVFN(HSUART1_DEV, HSUART1_FUNC):
+		mask |= HSUART1_DIS;
+		break;
+	case PCI_DEVFN(HSUART2_DEV, HSUART2_FUNC):
+		mask |= HSUART2_DIS;
+		break;
+	case PCI_DEVFN(SPI_DEV, SPI_FUNC):
+		mask |= SPI_DIS;
+		break;
+	case PCI_DEVFN(SMBUS_DEV, SMBUS_FUNC):
+		mask2 |= SMBUS_DIS;
+		break;
+	}
+
+	if (mask != 0) {
+		write32(func_dis, read32(func_dis) | mask);
+		/* Ensure posted write hits. */
+		read32(func_dis);
+	}
+
+	if (mask2 != 0) {
+		write32(func_dis2, read32(func_dis2) | mask2);
+		/* Ensure posted write hits. */
+		read32(func_dis2);
+	}
+}
+
+static inline void set_d3hot_bits(device_t dev, int offset)
+{
+	uint32_t reg8;
+	printk(BIOS_DEBUG, "Power management CAP offset 0x%x.\n", offset);
+	reg8 = pci_read_config8(dev, offset + 4);
+	reg8 |= 0x3;
+	pci_write_config8(dev, offset + 4, reg8);
+}
+
+static int place_device_in_d3hot(device_t dev)
+{
+	unsigned offset;
+
+	offset = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+	if (offset != 0) {
+		set_d3hot_bits(dev, offset);
+		return 0;
+	}
+
+	/* For some reason some of the devices don't have the capability
+	 * pointer set correctly. Work around this by hard coding the offset. */
+	switch (dev->path.pci.devfn) {
+	case PCI_DEVFN(SDIO_DEV, SDIO_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(SD_DEV, SD_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(MMC_DEV, MMC_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(LPE_DEV, LPE_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(SIO_DMA1_DEV, SIO_DMA1_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(I2C1_DEV, I2C1_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(I2C2_DEV, I2C2_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(I2C3_DEV, I2C3_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(I2C4_DEV, I2C4_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(I2C5_DEV, I2C5_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(I2C6_DEV, I2C6_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(I2C7_DEV, I2C7_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(SIO_DMA2_DEV, SIO_DMA2_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(PWM1_DEV, PWM1_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(PWM2_DEV, PWM2_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(HSUART1_DEV, HSUART1_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(HSUART2_DEV, HSUART2_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(SPI_DEV, SPI_FUNC):
+		offset = 0x80;
+		break;
+	case PCI_DEVFN(SATA_DEV, SATA_FUNC):
+		offset = 0x70;
+		break;
+	case PCI_DEVFN(XHCI_DEV, XHCI_FUNC):
+		offset = 0x70;
+		break;
+	case PCI_DEVFN(EHCI_DEV, EHCI_FUNC):
+		offset = 0x70;
+		break;
+	case PCI_DEVFN(HDA_DEV, HDA_FUNC):
+		offset = 0x50;
+		break;
+	case PCI_DEVFN(SMBUS_DEV, SMBUS_FUNC):
+		offset = 0x50;
+		break;
+	case PCI_DEVFN(TXE_DEV, TXE_FUNC):
+		break;
+	case PCI_DEVFN(PCIE_PORT1_DEV, PCIE_PORT1_FUNC):
+		offset = 0xa0;
+		break;
+	case PCI_DEVFN(PCIE_PORT2_DEV, PCIE_PORT2_FUNC):
+		offset = 0xa0;
+		break;
+	case PCI_DEVFN(PCIE_PORT3_DEV, PCIE_PORT3_FUNC):
+		offset = 0xa0;
+		break;
+	case PCI_DEVFN(PCIE_PORT4_DEV, PCIE_PORT4_FUNC):
+		offset = 0xa0;
+		break;
+	}
+
+	if (offset != 0) {
+		set_d3hot_bits(dev, offset);
+		return 0;
+	}
+
+	return -1;
+}
+
+/* Common PCI device function disable. */
+void southcluster_enable_dev(device_t dev)
+{
+	uint32_t reg32;
+
+	if (!dev->enabled) {
+		int slot = PCI_SLOT(dev->path.pci.devfn);
+		int func = PCI_FUNC(dev->path.pci.devfn);
+		printk(BIOS_DEBUG, "%s: Disabling device: %02x.%01x\n",
+		       dev_path(dev), slot, func);
+
+		/* 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);
+
+		/* Place device in D3Hot */
+		if (place_device_in_d3hot(dev) < 0) {
+			printk(BIOS_WARNING,
+			       "Could not place %02x.%01x into D3Hot. "
+			       "Keeping device visible.\n", slot, func);
+			return;
+		}
+		/* Disable this device if possible */
+		sc_disable_devfn(dev);
+	} else {
+		/* Enable SERR */
+		reg32 = pci_read_config32(dev, PCI_COMMAND);
+		reg32 |= PCI_COMMAND_SERR;
+		pci_write_config32(dev, PCI_COMMAND, reg32);
+	}
+}
+
 static struct device_operations device_ops = {
 	.read_resources		= sc_read_resources,
 	.set_resources		= pci_dev_set_resources,
 	.enable_resources	= NULL,
 	.init			= NULL,
-	.enable			= NULL,
+	.enable			= southcluster_enable_dev,
 	.scan_bus		= NULL,
 	.ops_pci		= &soc_pci_ops,
 };



More information about the coreboot-gerrit mailing list