From d355247333a828a146ce7cf9b92a63da74119c1d Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Thu, 1 May 2014 13:37:19 -0700 Subject: [PATCH] broadwell: Clean up XHCI and EHCI ramstage drivers The EHCI controller is disabled in refcode binary in the typical case, it is only left enabled when using USBDEBUG. So the code to disable the controller can be removed. The XHCI controller clock gating setup is done in the ramstage refcode binary so that code can be removed now. The SMM code for preparing the controller prior to S3/S5 is reworked but still made available to be called by the SMI handler. BUG=chrome-os-partner:28234 TEST=None Change-Id: I19d1df99d2ee5dbc9c93ca01b2d246432928d77f Signed-off-by: Duncan Laurie Reviewed-on: https://chromium-review.googlesource.com/199181 Reviewed-by: Aaron Durbin --- src/soc/intel/broadwell/ehci.c | 145 +------------------ src/soc/intel/broadwell/xhci.c | 251 ++++----------------------------- 2 files changed, 26 insertions(+), 370 deletions(-) diff --git a/src/soc/intel/broadwell/ehci.c b/src/soc/intel/broadwell/ehci.c index 7ec82d7f3a..e27c8e59c9 100644 --- a/src/soc/intel/broadwell/ehci.c +++ b/src/soc/intel/broadwell/ehci.c @@ -23,150 +23,9 @@ #include #include #include -#include "pch.h" #include #include - -#ifdef __SMM__ - -void usb_ehci_disable(device_t dev) -{ - u16 reg16; - u32 reg32; - - /* Set 0xDC[0]=1 */ - pci_or_config32(dev, 0xdc, (1 << 0)); - - /* Set D3Hot state and disable PME */ - reg16 = pci_read_config16(dev, EHCI_PWR_CTL_STS); - reg16 &= ~(PWR_CTL_ENABLE_PME | PWR_CTL_SET_MASK); - reg16 |= PWR_CTL_SET_D3; - pci_write_config16(dev, EHCI_PWR_CTL_STS, reg16); - - /* Clear memory and bus master */ - pci_write_config32(dev, PCI_BASE_ADDRESS_0, 0); - reg32 = pci_read_config32(dev, PCI_COMMAND); - reg32 &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - pci_write_config32(dev, PCI_COMMAND, reg32); - - /* Disable device */ - switch (dev) { - case PCH_EHCI1_DEV: - RCBA32_OR(FD, PCH_DISABLE_EHCI1); - break; - case PCH_EHCI2_DEV: - RCBA32_OR(FD, PCH_DISABLE_EHCI2); - break; - } -} - -/* Handler for EHCI controller on entry to S3/S4/S5 */ -void usb_ehci_sleep_prepare(device_t dev, u8 slp_typ) -{ - u32 reg32; - u32 bar0_base; - u16 pwr_state; - u16 pci_cmd; - - /* Check if the controller is disabled or not present */ - bar0_base = pci_read_config32(dev, PCI_BASE_ADDRESS_0); - if (bar0_base == 0 || bar0_base == 0xffffffff) - return; - pci_cmd = pci_read_config32(dev, PCI_COMMAND); - - switch (slp_typ) { - case SLP_TYP_S4: - case SLP_TYP_S5: - /* Check if controller is in D3 power state */ - pwr_state = pci_read_config16(dev, EHCI_PWR_CTL_STS); - if ((pwr_state & PWR_CTL_SET_MASK) == PWR_CTL_SET_D3) { - /* Put in D0 */ - u32 new_state = pwr_state & ~PWR_CTL_SET_MASK; - new_state |= PWR_CTL_SET_D0; - pci_write_config16(dev, EHCI_PWR_CTL_STS, new_state); - - /* Make sure memory bar is set */ - pci_write_config32(dev, PCI_BASE_ADDRESS_0, bar0_base); - - /* Make sure memory space is enabled */ - pci_write_config16(dev, PCI_COMMAND, pci_cmd | - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); - } - - /* - * If Run/Stop (bit0) is clear in USB2.0_CMD: - * - Clear Async Schedule Enable (bit5) and - * - Clear Periodic Schedule Enable (bit4) and - * - Set Run/Stop (bit0) - */ - reg32 = read32(bar0_base + EHCI_USB_CMD); - if (reg32 & EHCI_USB_CMD_RUN) { - reg32 &= ~(EHCI_USB_CMD_PSE | EHCI_USB_CMD_ASE); - reg32 |= EHCI_USB_CMD_RUN; - write32(bar0_base + EHCI_USB_CMD, reg32); - } - - /* Check for Port Enabled in PORTSC(0) (RMH) */ - reg32 = read32(bar0_base + EHCI_PORTSC(0)); - if (reg32 & EHCI_PORTSC_ENABLED) { - /* Set suspend bit in PORTSC if not already set */ - if (!(reg32 & EHCI_PORTSC_SUSPEND)) { - reg32 |= EHCI_PORTSC_SUSPEND; - write32(bar0_base + EHCI_PORTSC(0), reg32); - } - - /* Delay 25ms !! */ - udelay(25 * 1000); - - /* Clear Run/Stop bit */ - reg32 = read32(bar0_base + EHCI_USB_CMD); - reg32 &= EHCI_USB_CMD_RUN; - write32(bar0_base + EHCI_USB_CMD, reg32); - } - - /* Restore state to D3 if that is what it was at the start */ - if ((pwr_state & PWR_CTL_SET_MASK) == PWR_CTL_SET_D3) { - /* Restore pci command reg */ - pci_write_config16(dev, PCI_COMMAND, pci_cmd); - - /* Enable D3 */ - pci_write_config16(dev, EHCI_PWR_CTL_STS, pwr_state); - } - } -} - -#else /* !__SMM__ */ - -static void usb_ehci_clock_gating(struct device *dev) -{ - u32 reg32; - - /* IOBP 0xE5004001[7:6] = 11b */ - pch_iobp_update(0xe5004001, ~0, (1 << 7)|(1 << 6)); - - /* Dx:F0:DCh[5,2,1] = 111b - * Dx:F0:DCh[0] = 1b when EHCI controller is disabled */ - reg32 = pci_read_config32(dev, 0xdc); - reg32 |= (1 << 5) | (1 << 2) | (1 << 1); - pci_write_config32(dev, 0xdc, reg32); - - /* Dx:F0:78h[1:0] = 11b */ - reg32 = pci_read_config32(dev, 0x78); - reg32 |= (1 << 1) | (1 << 0); - pci_write_config32(dev, 0x78, reg32); -} - -static void usb_ehci_init(struct device *dev) -{ - printk(BIOS_DEBUG, "EHCI: Setting up controller.. "); - - usb_ehci_clock_gating(dev); - - /* Disable Wake on Disconnect in RMH */ - RCBA32_OR(0x35b0, 0x00000022); - - printk(BIOS_DEBUG, "done.\n"); -} +#include static void usb_ehci_set_subsystem(device_t dev, unsigned vendor, unsigned device) { @@ -233,5 +92,3 @@ static const struct pci_driver pch_usb_ehci __pci_driver = { .vendor = PCI_VENDOR_ID_INTEL, .devices = pci_device_ids, }; - -#endif /* !__SMM__ */ diff --git a/src/soc/intel/broadwell/xhci.c b/src/soc/intel/broadwell/xhci.c index 3e74f2acde..89e1139f14 100644 --- a/src/soc/intel/broadwell/xhci.c +++ b/src/soc/intel/broadwell/xhci.c @@ -23,11 +23,10 @@ #include #include #include -#include "pch.h" - -typedef struct southbridge_intel_lynxpoint_config config_t; #include +#include +#ifdef __SMM__ static u32 usb_xhci_mem_base(device_t dev) { u32 mem_base = pci_read_config32(dev, PCI_BASE_ADDRESS_0); @@ -41,23 +40,8 @@ static u32 usb_xhci_mem_base(device_t dev) static int usb_xhci_port_count_usb3(device_t dev) { - if (pch_is_lp()) { - /* LynxPoint-LP has 4 SS ports */ - return 4; - } else { - /* LynxPoint-H can have 0, 2, 4, or 6 SS ports */ - u32 mem_base = usb_xhci_mem_base(dev); - u32 fus = read32(mem_base + XHCI_USB3FUS); - fus >>= XHCI_USB3FUS_SS_SHIFT; - fus &= XHCI_USB3FUS_SS_MASK; - switch (fus) { - case 3: return 0; - case 2: return 2; - case 1: return 4; - case 0: default: return 6; - } - } - return 0; + /* PCH-LP has 4 SS ports */ + return 4; } static void usb_xhci_reset_status_usb3(u32 mem_base, int port) @@ -157,8 +141,6 @@ static void usb_xhci_reset_usb3(device_t dev, int all) usb_xhci_reset_status_usb3(mem_base, port); } -#ifdef __SMM__ - /* Handler for XHCI controller on entry to S3/S4/S5 */ void usb_xhci_sleep_prepare(device_t dev, u8 slp_typ) { @@ -169,219 +151,36 @@ void usb_xhci_sleep_prepare(device_t dev, u8 slp_typ) if (!mem_base || slp_typ < 3) return; - if (pch_is_lp()) { - /* Set D0 state */ - reg16 = pci_read_config16(dev, XHCI_PWR_CTL_STS); - reg16 &= ~PWR_CTL_SET_MASK; - reg16 |= PWR_CTL_SET_D0; - pci_write_config16(dev, XHCI_PWR_CTL_STS, reg16); - - /* Clear PCI 0xB0[14:13] */ - reg32 = pci_read_config32(dev, 0xb0); - reg32 &= ~((1 << 14) | (1 << 13)); - pci_write_config32(dev, 0xb0, reg32); - - /* Clear MMIO 0x816c[14,2] */ - reg32 = read32(mem_base + 0x816c); - reg32 &= ~((1 << 14) | (1 << 2)); - write32(mem_base + 0x816c, reg32); - - /* Reset disconnected USB3 ports */ - usb_xhci_reset_usb3(dev, 0); - - /* Set MMIO 0x80e0[15] */ - reg32 = read32(mem_base + 0x80e0); - reg32 |= (1 << 15); - write32(mem_base + 0x80e0, reg32); - } - - /* Set D3Hot state and enable PME */ - pci_or_config16(dev, XHCI_PWR_CTL_STS, PWR_CTL_SET_D3); - pci_or_config16(dev, XHCI_PWR_CTL_STS, PWR_CTL_STATUS_PME); - 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) -{ - u32 reg32; - u16 reg16; - - /* IOBP 0xE5004001[7:6] = 11b */ - pch_iobp_update(0xe5004001, ~0, (1 << 7)|(1 << 6)); - - reg32 = pci_read_config32(dev, 0x40); - reg32 &= ~(1 << 23); /* unsupported request */ - - if (pch_is_lp()) { - /* D20:F0:40h[18,17,8] = 111b */ - reg32 |= (1 << 18) | (1 << 17) | (1 << 8); - /* D20:F0:40h[21,20,19] = 110b to enable XHCI Idle L1 */ - reg32 &= ~(1 << 19); - reg32 |= (1 << 21) | (1 << 20); - } else { - /* D20:F0:40h[21,20,18,17,8] = 11111b */ - reg32 |= (1 << 21)|(1 << 20)|(1 << 18)|(1 << 17)|(1 << 8); - } - - /* Avoid writing upper byte as it is write-once */ - pci_write_config16(dev, 0x40, (u16)(reg32 & 0xffff)); - pci_write_config8(dev, 0x40 + 2, (u8)((reg32 >> 16) & 0xff)); - - /* D20:F0:44h[9,7,3] = 111b */ - reg16 = pci_read_config16(dev, 0x44); - reg16 |= (1 << 9) | (1 << 7) | (1 << 3); - pci_write_config16(dev, 0x44, reg16); - - reg32 = pci_read_config32(dev, 0xa0); - if (pch_is_lp()) { - /* D20:F0:A0h[18] = 1 */ - reg32 |= (1 << 18); - } else { - /* D20:F0:A0h[6] = 1 */ - reg32 |= (1 << 6); - } - pci_write_config32(dev, 0xa0, reg32); - - /* D20:F0:A4h[13] = 0 */ - reg32 = pci_read_config32(dev, 0xa4); - reg32 &= ~(1 << 13); - pci_write_config32(dev, 0xa4, reg32); -} - -static void usb_xhci_init(device_t dev) -{ - u32 reg32; - u16 reg16; - u32 mem_base = usb_xhci_mem_base(dev); - config_t *config = dev->chip_info; - - /* D20:F0:74h[1:0] = 00b (set D0 state) */ reg16 = pci_read_config16(dev, XHCI_PWR_CTL_STS); - reg16 &= ~PWR_CTL_SET_MASK; - reg16 |= PWR_CTL_SET_D0; + reg16 &= ~XHCI_PWR_CTL_SET_MASK; + reg16 |= XHCI_PWR_CTL_SET_D0; pci_write_config16(dev, XHCI_PWR_CTL_STS, reg16); - /* Enable clock gating first */ - usb_xhci_clock_gating(dev); + /* Clear PCI 0xB0[14:13] */ + reg32 = pci_read_config32(dev, 0xb0); + reg32 &= ~((1 << 14) | (1 << 13)); + pci_write_config32(dev, 0xb0, reg32); - reg32 = read32(mem_base + 0x8144); - if (pch_is_lp()) { - /* XHCIBAR + 8144h[8,7,6] = 111b */ - reg32 |= (1 << 8) | (1 << 7) | (1 << 6); - } else { - /* XHCIBAR + 8144h[8,7,6] = 100b */ - reg32 &= ~((1 << 7) | (1 << 6)); - reg32 |= (1 << 8); - } - write32(mem_base + 0x8144, reg32); + /* Clear MMIO 0x816c[14,2] */ + reg32 = read32(mem_base + 0x816c); + reg32 &= ~((1 << 14) | (1 << 2)); + write32(mem_base + 0x816c, reg32); - if (pch_is_lp()) { - /* XHCIBAR + 816Ch[19:0] = 000e0038h */ - reg32 = read32(mem_base + 0x816c); - reg32 &= ~0x000fffff; - reg32 |= 0x000e0038; - write32(mem_base + 0x816c, reg32); + /* Reset disconnected USB3 ports */ + usb_xhci_reset_usb3(dev, 0); - /* D20:F0:B0h[17,14,13] = 100b */ - reg32 = pci_read_config32(dev, 0xb0); - reg32 &= ~((1 << 14) | (1 << 13)); - reg32 |= (1 << 17); - pci_write_config32(dev, 0xb0, reg32); - } + /* Set MMIO 0x80e0[15] */ + reg32 = read32(mem_base + 0x80e0); + reg32 |= (1 << 15); + write32(mem_base + 0x80e0, reg32); - reg32 = pci_read_config32(dev, 0x50); - if (pch_is_lp()) { - /* D20:F0:50h[28:0] = 0FCE2E5Fh */ - reg32 &= ~0x1fffffff; - reg32 |= 0x0fce2e5f; - } else { - /* D20:F0:50h[26:0] = 07886E9Fh */ - reg32 &= ~0x07ffffff; - reg32 |= 0x07886e9f; - } - pci_write_config32(dev, 0x50, reg32); - - /* D20:F0:44h[31] = 1 (Access Control Bit) */ - reg32 = pci_read_config32(dev, 0x44); - reg32 |= (1 << 31); - pci_write_config32(dev, 0x44, reg32); - - /* D20:F0:40h[31,23] = 10b (OC Configuration Done) */ - reg32 = pci_read_config32(dev, 0x40); - reg32 &= ~(1 << 23); /* unsupported request */ - reg32 |= (1 << 31); - pci_write_config32(dev, 0x40, reg32); - -#if CONFIG_HAVE_ACPI_RESUME - if (acpi_slp_type == 3) { - /* Reset ports that are disabled or - * polling before returning to the OS. */ - usb_xhci_reset_usb3(dev, 0); - } else -#endif - /* Route all ports to XHCI */ - if (config->xhci_default) - outb(0xca, 0xb2); + /* Set D3Hot state and enable PME */ + pci_or_config16(dev, XHCI_PWR_CTL_STS, XHCI_PWR_CTL_SET_D3); + pci_or_config16(dev, XHCI_PWR_CTL_STS, XHCI_PWR_CTL_STATUS_PME); + pci_or_config16(dev, XHCI_PWR_CTL_STS, XHCI_PWR_CTL_ENABLE_PME); } - -static void usb_xhci_set_subsystem(device_t dev, unsigned vendor, - unsigned device) -{ - if (!vendor || !device) { - pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, - pci_read_config32(dev, PCI_VENDOR_ID)); - } else { - pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID, - ((device & 0xffff) << 16) | (vendor & 0xffff)); - } -} - -static struct pci_operations lops_pci = { - .set_subsystem = &usb_xhci_set_subsystem, -}; +#else /* !__SMM__ */ static struct device_operations usb_xhci_ops = { .read_resources = &pci_dev_read_resources,