[coreboot-gerrit] Patch set updated for coreboot: 607580b lynxpoint: Route all USB ports to XHCI in finalize step

Patrick Georgi (patrick@georgi-clan.de) gerrit at coreboot.org
Fri Dec 20 23:31:42 CET 2013


Patrick Georgi (patrick at georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4407

-gerrit

commit 607580be9fdd60b96661155d451213321ab9a1f2
Author: Duncan Laurie <dlaurie at chromium.org>
Date:   Tue Jul 30 16:05:55 2013 -0700

    lynxpoint: Route all USB ports to XHCI in finalize step
    
    This commit adds a new Kconfig option for the LynxPoint
    southbridge that will have coreboot route all of the USB
    ports to the XHCI controller in the finalize step (i.e.
    after the bootloader) and disable the EHCI controller(s).
    
    Additionally when doing this the XHCI USB3 ports need
    to be put into an expected state on resume in order to make
    the kernel state machine happy.
    
    Part of this could also be done in depthcharge but there
    are also some resume-time steps required so it makes sense
    to keep it all together in coreboot.
    
    This can theoretically save ~100mW at runtime.
    
    Verify that the EHCI controller is not found in Linux and
    that booting from USB still works.
    
    Change-Id: I3ddfecc0ab12a4302e6034ea8d13ccd8ea2a655d
    Signed-off-by: Duncan Laurie <dlaurie at chromium.org>
    Reviewed-on: https://gerrit.chromium.org/gerrit/63802
    Reviewed-by: Aaron Durbin <adurbin at chromium.org>
---
 src/include/cpu/x86/smm.h                    |  1 +
 src/southbridge/intel/lynxpoint/Kconfig      |  7 +++
 src/southbridge/intel/lynxpoint/pch.h        |  1 +
 src/southbridge/intel/lynxpoint/smihandler.c |  7 +++
 src/southbridge/intel/lynxpoint/usb_xhci.c   | 90 ++++++++++++++++++++++++++++
 5 files changed, 106 insertions(+)

diff --git a/src/include/cpu/x86/smm.h b/src/include/cpu/x86/smm.h
index 607c0f0..feb50ec 100644
--- a/src/include/cpu/x86/smm.h
+++ b/src/include/cpu/x86/smm.h
@@ -372,6 +372,7 @@ typedef struct {
 #define APM_CNT_ACPI_ENABLE	0xe1
 #define APM_CNT_MBI_UPDATE	0xeb
 #define APM_CNT_GNVS_UPDATE	0xea
+#define APM_CNT_FINALIZE	0xcb
 #define APM_STS		0xb3
 
 /* SMI handler function prototypes */
diff --git a/src/southbridge/intel/lynxpoint/Kconfig b/src/southbridge/intel/lynxpoint/Kconfig
index 28ebdb6..5ff00db 100644
--- a/src/southbridge/intel/lynxpoint/Kconfig
+++ b/src/southbridge/intel/lynxpoint/Kconfig
@@ -76,4 +76,11 @@ config ME_MBP_CLEAR_LATE
 	  finalize step.  This can speed up boot time if the ME takes
 	  a long time to indicate this status.
 
+config FINALIZE_USB_ROUTE_XHCI
+	bool "Route all ports to XHCI controller in finalize step"
+	default y
+	help
+	  If you set this option to y, the USB ports will be routed
+	  to the XHCI controller during the finalize SMM callback.
+
 endif
diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h
index e77fdb6..32980ec 100644
--- a/src/southbridge/intel/lynxpoint/pch.h
+++ b/src/southbridge/intel/lynxpoint/pch.h
@@ -92,6 +92,7 @@ void intel_pch_finalize_smm(void);
 void usb_ehci_sleep_prepare(device_t dev, u8 slp_typ);
 void usb_ehci_disable(device_t dev);
 void usb_xhci_sleep_prepare(device_t dev, u8 slp_typ);
+void usb_xhci_route_all(void);
 #endif
 
 
diff --git a/src/southbridge/intel/lynxpoint/smihandler.c b/src/southbridge/intel/lynxpoint/smihandler.c
index e920cfe..d1e9bbc 100644
--- a/src/southbridge/intel/lynxpoint/smihandler.c
+++ b/src/southbridge/intel/lynxpoint/smihandler.c
@@ -135,8 +135,10 @@ static void southbridge_smi_sleep(void)
 	mainboard_smi_sleep(slp_typ-2);
 
 	/* USB sleep preparations */
+#if !CONFIG_FINALIZE_USB_ROUTE_XHCI
 	usb_ehci_sleep_prepare(PCH_EHCI1_DEV, slp_typ);
 	usb_ehci_sleep_prepare(PCH_EHCI2_DEV, slp_typ);
+#endif
 	usb_xhci_sleep_prepare(PCH_XHCI_DEV, slp_typ);
 
 #if CONFIG_ELOG_GSMI
@@ -314,6 +316,11 @@ static void southbridge_smi_apmc(void)
 			printk(BIOS_DEBUG, "SMI#: Setting GNVS to %p\n", gnvs);
 		}
 		break;
+	case APM_CNT_FINALIZE:
+#if CONFIG_FINALIZE_USB_ROUTE_XHCI
+		usb_xhci_route_all();
+#endif
+		break;
 #if CONFIG_ELOG_GSMI
 	case ELOG_GSMI_APM_CNT:
 		southbridge_smi_gsmi();
diff --git a/src/southbridge/intel/lynxpoint/usb_xhci.c b/src/southbridge/intel/lynxpoint/usb_xhci.c
index 5adf88c..dbf0f40 100644
--- a/src/southbridge/intel/lynxpoint/usb_xhci.c
+++ b/src/southbridge/intel/lynxpoint/usb_xhci.c
@@ -189,6 +189,47 @@ void usb_xhci_sleep_prepare(device_t dev, u8 slp_typ)
 	pci_or_config16(dev, XHCI_PWR_CTL_STS, PWR_CTL_ENABLE_PME);
 }
 
+/* Route all ports to XHCI controller */
+void usb_xhci_route_all(void)
+{
+	u32 port_mask, route;
+	u16 reg16;
+
+	/* Skip if EHCI is already disabled */
+	if (RCBA32(FD) & PCH_DISABLE_EHCI1)
+		return;
+
+	/* Set D0 state */
+	reg16 = pci_read_config16(PCH_XHCI_DEV, XHCI_PWR_CTL_STS);
+	reg16 &= ~PWR_CTL_SET_MASK;
+	reg16 |= PWR_CTL_SET_D0;
+	pci_write_config16(PCH_XHCI_DEV, XHCI_PWR_CTL_STS, reg16);
+
+	/* Set USB3 superspeed enable */
+	port_mask = pci_read_config32(PCH_XHCI_DEV, XHCI_USB3PRM);
+	route = pci_read_config32(PCH_XHCI_DEV, XHCI_USB3PR);
+	route &= ~XHCI_USB3PR_SSEN;
+	route |= XHCI_USB3PR_SSEN & port_mask;
+	pci_write_config32(PCH_XHCI_DEV, XHCI_USB3PR, route);
+
+	/* Route USB2 ports to XHCI controller */
+	port_mask = pci_read_config32(PCH_XHCI_DEV, XHCI_USB2PRM);
+	route = pci_read_config32(PCH_XHCI_DEV, XHCI_USB2PR);
+	route &= ~XHCI_USB2PR_HCSEL;
+	route |= XHCI_USB2PR_HCSEL & port_mask;
+	pci_write_config32(PCH_XHCI_DEV, XHCI_USB2PR, route);
+
+	/* Disable EHCI controller */
+	usb_ehci_disable(PCH_EHCI1_DEV);
+
+	/* LynxPoint-H has a second EHCI controller */
+	if (!pch_is_lp())
+		usb_ehci_disable(PCH_EHCI2_DEV);
+
+	/* Reset and clear port change status */
+	usb_xhci_reset_usb3(PCH_XHCI_DEV, 1);
+}
+
 #else /* !__SMM__ */
 
 static void usb_xhci_clock_gating(device_t dev)
@@ -237,6 +278,49 @@ static void usb_xhci_clock_gating(device_t dev)
 	pci_write_config32(dev, 0xa4, reg32);
 }
 
+/* Re-enable ports that are disabled */
+static void usb_xhci_enable_ports_usb3(device_t dev)
+{
+#if CONFIG_FINALIZE_USB_ROUTE_XHCI
+	int port;
+	u32 portsc, status, disabled;
+	u32 mem_base = usb_xhci_mem_base(dev);
+	int port_count = usb_xhci_port_count_usb3(dev);
+
+	if (!mem_base || !port_count)
+		return;
+
+	/* Get port disable override map */
+	disabled = pci_read_config32(dev, XHCI_USB3PDO);
+
+	for (port = 0; port < port_count; port++) {
+		/* Skip overridden ports */
+		if (disabled & (1 << port))
+			continue;
+		portsc = mem_base + XHCI_USB3_PORTSC(port);
+		status = read32(portsc) & XHCI_USB3_PORTSC_PLS;
+
+		switch (status) {
+		case XHCI_PLSR_RXDETECT:
+			/* Clear change status */
+			printk(BIOS_DEBUG, "usb_xhci reset port %d\n", port);
+			usb_xhci_reset_status_usb3(mem_base, port);
+			break;
+		case XHCI_PLSR_DISABLED:
+		default:
+			/* Transition to enabled */
+			printk(BIOS_DEBUG, "usb_xhci enable port %d\n", port);
+			usb_xhci_reset_port_usb3(mem_base, port);
+			status = read32(portsc);
+			status &= ~XHCI_USB3_PORTSC_PLS;
+			status |= XHCI_PLSW_ENABLE | XHCI_USB3_PORTSC_LWS;
+			write32(portsc, status);
+			break;
+		}
+	}
+#endif
+}
+
 static void usb_xhci_init(device_t dev)
 {
 	struct resource *bar0 = find_resource(dev, PCI_BASE_ADDRESS_0);
@@ -305,6 +389,12 @@ static void usb_xhci_init(device_t dev)
 	reg32 &= ~(1 << 23); /* unsupported request */
 	reg32 |= (1 << 31);
 	pci_write_config32(dev, 0x40, reg32);
+
+#if CONFIG_HAVE_ACPI_RESUME
+	/* Enable ports that are disabled before returning to OS */
+	if (acpi_slp_type == 3)
+		usb_xhci_enable_ports_usb3(dev);
+#endif
 }
 
 static void usb_xhci_set_subsystem(device_t dev, unsigned vendor,



More information about the coreboot-gerrit mailing list