summaryrefslogtreecommitdiff
path: root/resources/coreboot/haswell/patches/0005-sb-intel-lynxpoint-Add-native-USB-init.patch
diff options
context:
space:
mode:
Diffstat (limited to 'resources/coreboot/haswell/patches/0005-sb-intel-lynxpoint-Add-native-USB-init.patch')
-rw-r--r--resources/coreboot/haswell/patches/0005-sb-intel-lynxpoint-Add-native-USB-init.patch783
1 files changed, 0 insertions, 783 deletions
diff --git a/resources/coreboot/haswell/patches/0005-sb-intel-lynxpoint-Add-native-USB-init.patch b/resources/coreboot/haswell/patches/0005-sb-intel-lynxpoint-Add-native-USB-init.patch
deleted file mode 100644
index d9c2570b..00000000
--- a/resources/coreboot/haswell/patches/0005-sb-intel-lynxpoint-Add-native-USB-init.patch
+++ /dev/null
@@ -1,783 +0,0 @@
-From 9bfb8614dbf1d9800ef8251cb3d839bcdbe5577f Mon Sep 17 00:00:00 2001
-From: Angel Pons <th3fanbus@gmail.com>
-Date: Fri, 6 May 2022 23:17:39 +0200
-Subject: [PATCH 05/26] sb/intel/lynxpoint: Add native USB init
-
-Implement native USB initialisation for Lynx Point. This is only needed
-when MRC.bin is not used.
-
-TO DO: Figure out how to deal with the FIXME's and TODO's lying around.
-
-Change-Id: Ie0fbeeca7b1ca1557173772d733fd2fa27703373
-Signed-off-by: Angel Pons <th3fanbus@gmail.com>
----
- .../haswell/native_raminit/raminit_native.c | 3 +
- src/southbridge/intel/lynxpoint/Makefile.inc | 2 +-
- src/southbridge/intel/lynxpoint/early_usb.c | 11 -
- .../intel/lynxpoint/early_usb_native.c | 584 ++++++++++++++++++
- src/southbridge/intel/lynxpoint/pch.h | 49 ++
- 5 files changed, 637 insertions(+), 12 deletions(-)
- create mode 100644 src/southbridge/intel/lynxpoint/early_usb_native.c
-
-diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-index 6a002548c1..ef61d4ee09 100644
---- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-+++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
-@@ -5,6 +5,7 @@
- #include <northbridge/intel/haswell/haswell.h>
- #include <northbridge/intel/haswell/raminit.h>
- #include <southbridge/intel/lynxpoint/me.h>
-+#include <southbridge/intel/lynxpoint/pch.h>
- #include <types.h>
-
- static bool early_init_native(int s3resume)
-@@ -15,6 +16,8 @@ static bool early_init_native(int s3resume)
- /** TODO: CPU replacement check must be skipped in warm boots and S3 resumes **/
- const bool cpu_replaced = !s3resume && intel_early_me_cpu_replacement_check();
-
-+ early_usb_init();
-+
- if (!CONFIG(INTEL_LYNXPOINT_LP))
- dmi_early_init();
-
-diff --git a/src/southbridge/intel/lynxpoint/Makefile.inc b/src/southbridge/intel/lynxpoint/Makefile.inc
-index b8503ac8bc..0e1f2fe4eb 100644
---- a/src/southbridge/intel/lynxpoint/Makefile.inc
-+++ b/src/southbridge/intel/lynxpoint/Makefile.inc
-@@ -37,7 +37,7 @@ bootblock-y += early_pch.c
- romstage-y += early_usb.c early_me.c me_status.c early_pch.c
- romstage-y += pmutil.c
-
--romstage-$(CONFIG_USE_NATIVE_RAMINIT) += early_pch_native.c
-+romstage-$(CONFIG_USE_NATIVE_RAMINIT) += early_pch_native.c early_usb_native.c iobp.c
-
- ifeq ($(CONFIG_INTEL_LYNXPOINT_LP),y)
- romstage-y += lp_gpio.c
-diff --git a/src/southbridge/intel/lynxpoint/early_usb.c b/src/southbridge/intel/lynxpoint/early_usb.c
-index a753681ce0..52e8ac17f8 100644
---- a/src/southbridge/intel/lynxpoint/early_usb.c
-+++ b/src/southbridge/intel/lynxpoint/early_usb.c
-@@ -4,17 +4,6 @@
- #include <device/pci_def.h>
- #include "pch.h"
-
--/* HCD_INDEX == 2 selects 0:1a.0 (PCH_EHCI2), any other index
-- * selects 0:1d.0 (PCH_EHCI1) for usbdebug use.
-- */
--#if CONFIG_USBDEBUG_HCD_INDEX != 2
--#define PCH_EHCI1_TEMP_BAR0 CONFIG_EHCI_BAR
--#define PCH_EHCI2_TEMP_BAR0 (PCH_EHCI1_TEMP_BAR0 + 0x400)
--#else
--#define PCH_EHCI2_TEMP_BAR0 CONFIG_EHCI_BAR
--#define PCH_EHCI1_TEMP_BAR0 (PCH_EHCI2_TEMP_BAR0 + 0x400)
--#endif
--
- /*
- * Setup USB controller MMIO BAR to prevent the
- * reference code from resetting the controller.
-diff --git a/src/southbridge/intel/lynxpoint/early_usb_native.c b/src/southbridge/intel/lynxpoint/early_usb_native.c
-new file mode 100644
-index 0000000000..cb6f6ee8e6
---- /dev/null
-+++ b/src/southbridge/intel/lynxpoint/early_usb_native.c
-@@ -0,0 +1,584 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+
-+#include <console/console.h>
-+#include <delay.h>
-+#include <device/mmio.h>
-+#include <device/pci_def.h>
-+#include <device/pci_ops.h>
-+#include <northbridge/intel/haswell/haswell.h>
-+#include <northbridge/intel/haswell/raminit.h>
-+#include <southbridge/intel/lynxpoint/iobp.h>
-+#include <southbridge/intel/lynxpoint/pch.h>
-+#include <timer.h>
-+#include <types.h>
-+
-+static unsigned int is_usbr_enabled(void)
-+{
-+ return !!(pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) & BIT(5));
-+}
-+
-+static char *const xhci_bar = (char *)PCH_XHCI_TEMP_BAR0;
-+
-+static void ehci_hcs_init(const pci_devfn_t dev, const uintptr_t ehci_bar)
-+{
-+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, ehci_bar);
-+
-+ /** FIXME: Determine whether Bus Master is required (or clean it up afterwards) **/
-+ pci_or_config16(dev, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
-+
-+ char *const mem_bar = (char *)ehci_bar;
-+
-+ /**
-+ * Shared EHCI/XHCI ports w/a.
-+ * This step is required when some of the ports are routed to EHCI
-+ * and other ports are routed XHCI at the same time.
-+ *
-+ * FIXME: Under which conditions should this be done?
-+ */
-+ pci_and_config16(dev, 0x78, ~0x03);
-+
-+ /* Skip reset if usbdebug is enabled */
-+ if (!CONFIG(USBDEBUG_IN_PRE_RAM))
-+ setbits32(mem_bar + EHCI_USB_CMD, EHCI_USB_CMD_HCRESET);
-+
-+ /* 2: Configure number of controllers and ports */
-+ pci_or_config16(dev, EHCI_ACCESS_CNTL, ACCESS_CNTL_ENABLE);
-+ clrsetbits32(mem_bar + EHCI_HCS_PARAMS, 0xf << 12, 0);
-+ clrsetbits32(mem_bar + EHCI_HCS_PARAMS, 0xf << 0, 2 + is_usbr_enabled());
-+ pci_and_config16(dev, EHCI_ACCESS_CNTL, ~ACCESS_CNTL_ENABLE);
-+
-+ pci_or_config16(dev, 0x78, BIT(2));
-+ pci_or_config16(dev, 0x7c, BIT(14) | BIT(7));
-+ pci_update_config32(dev, 0x8c, ~(0xf << 8), (4 << 8));
-+ pci_update_config32(dev, 0x8c, ~BIT(26), BIT(17));
-+}
-+
-+static inline unsigned int physical_port_count(void)
-+{
-+ return MAX_USB2_PORTS;
-+}
-+
-+static unsigned int hs_port_count(void)
-+{
-+ /** TODO: Apparently, WPT-LP has 10 USB2 ports **/
-+ if (CONFIG(INTEL_LYNXPOINT_LP))
-+ return 8;
-+
-+ switch ((pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) >> 1) & 3) {
-+ case 3:
-+ return 8;
-+ case 2:
-+ return 10;
-+ case 1:
-+ return 12;
-+ case 0:
-+ default:
-+ return 14;
-+ }
-+}
-+
-+static unsigned int ss_port_count(void)
-+{
-+ if (CONFIG(INTEL_LYNXPOINT_LP))
-+ return 4;
-+
-+ switch ((pci_read_config32(PCH_XHCI_DEV, XHCI_USB3FUS) >> 3) & 3) {
-+ case 3:
-+ return 0;
-+ case 2:
-+ return 2;
-+ case 1:
-+ return 4;
-+ case 0:
-+ default:
-+ return 6;
-+ }
-+}
-+
-+static void common_ehci_hcs_init(void)
-+{
-+ const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
-+
-+ ehci_hcs_init(PCH_EHCI1_DEV, PCH_EHCI1_TEMP_BAR0);
-+ if (!is_lp)
-+ ehci_hcs_init(PCH_EHCI2_DEV, PCH_EHCI2_TEMP_BAR0);
-+
-+ pch_iobp_update(0xe5007f04, 0, 0x00004481);
-+
-+ for (unsigned int port = 0; port < physical_port_count(); port++)
-+ pch_iobp_update(0xe500400f + port * 0x100, ~(1 << 0), 0 << 0);
-+
-+ pch_iobp_update(0xe5007f14, ~(3 << 19), (3 << 19));
-+
-+ if (is_lp)
-+ pch_iobp_update(0xe5007f02, ~(3 << 22), (0 << 22));
-+}
-+
-+static void xhci_open_memory_space(void)
-+{
-+ /** FIXME: Determine whether Bus Master is required (or clean it up afterwards) **/
-+ pci_write_config32(PCH_XHCI_DEV, PCI_BASE_ADDRESS_0, (uintptr_t)xhci_bar);
-+ pci_or_config16(PCH_XHCI_DEV, PCI_COMMAND, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
-+}
-+
-+static void xhci_close_memory_space(void)
-+{
-+ pci_and_config16(PCH_XHCI_DEV, PCI_COMMAND, ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY));
-+ pci_write_config32(PCH_XHCI_DEV, PCI_BASE_ADDRESS_0, 0);
-+}
-+
-+static void common_xhci_hc_init(void)
-+{
-+ const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
-+
-+ if (!is_lp) {
-+ const unsigned int max_ports = 15 + ss_port_count();
-+ clrsetbits32(xhci_bar + XHCI_HCS_PARAMS_1, 0xf << 28, max_ports << 28);
-+ }
-+
-+ clrsetbits32(xhci_bar + XHCI_HCS_PARAMS_3, 0xffff << 16 | 0xff, 0x200 << 16 | 0x0a);
-+ clrsetbits32(xhci_bar + XHCI_HCC_PARAMS, BIT(5), BIT(10) | BIT(9));
-+
-+ if (!is_lp)
-+ clrsetbits32(xhci_bar + 0x8008, BIT(19), 0);
-+
-+ if (is_lp)
-+ clrsetbits32(xhci_bar + 0x8058, BIT(8), BIT(16));
-+ else
-+ clrsetbits32(xhci_bar + 0x8058, BIT(8), BIT(16) | BIT(20));
-+
-+ clrsetbits32(xhci_bar + 0x8060, 0, BIT(25) | BIT(18));
-+ clrsetbits32(xhci_bar + 0x8090, 0, BIT(14) | BIT(8));
-+ clrsetbits32(xhci_bar + 0x8094, 0, BIT(23) | BIT(21) | BIT(14));
-+ clrsetbits32(xhci_bar + 0x80e0, BIT(16), BIT(6));
-+ clrsetbits32(xhci_bar + 0x80ec, (7 << 12) | (7 << 9), (0 << 12) | (6 << 9));
-+ clrsetbits32(xhci_bar + 0x80f0, BIT(20), 0);
-+
-+ if (is_lp)
-+ clrsetbits32(xhci_bar + 0x80fc, 0, BIT(25));
-+
-+ if (is_lp)
-+ clrsetbits32(xhci_bar + 0x8110, BIT(8) | BIT(2), BIT(20) | BIT(11));
-+ else
-+ clrsetbits32(xhci_bar + 0x8110, BIT(2), BIT(20) | BIT(11));
-+
-+ if (is_lp)
-+ write32(xhci_bar + 0x8140, 0xff00f03c);
-+ else
-+ write32(xhci_bar + 0x8140, 0xff03c132);
-+
-+ if (is_lp)
-+ clrsetbits32(xhci_bar + 0x8154, BIT(21), BIT(13));
-+ else
-+ clrsetbits32(xhci_bar + 0x8154, BIT(21) | BIT(13), 0);
-+
-+ clrsetbits32(xhci_bar + 0x8154, BIT(3), 0);
-+
-+ if (is_lp) {
-+ clrsetbits32(xhci_bar + 0x8164, 0, BIT(1) | BIT(0));
-+ write32(xhci_bar + 0x8174, 0x01400c0a);
-+ write32(xhci_bar + 0x817c, 0x033200a3);
-+ write32(xhci_bar + 0x8180, 0x00cb0028);
-+ write32(xhci_bar + 0x8184, 0x0064001e);
-+ }
-+
-+ /*
-+ * Note: Register at offset 0x44 is 32-bit, but bit 31 is write-once.
-+ * We use these weird partial accesses here to avoid locking bit 31.
-+ */
-+ pci_or_config16(PCH_XHCI_DEV, 0x44, BIT(15) | BIT(14) | BIT(10) | BIT(0));
-+ pci_or_config8(PCH_XHCI_DEV, 0x44 + 2, 0x0f);
-+
-+ /* LPT-LP >= B0 */
-+ if (is_lp)
-+ clrsetbits32(xhci_bar + 0x8188, 0, BIT(26) | BIT(24));
-+
-+ /* LPT-H >= C0 */
-+ if (!is_lp)
-+ clrsetbits32(xhci_bar + 0x8188, 0, BIT(24));
-+}
-+
-+static inline bool is_mem_sr(void)
-+{
-+ return pci_read_config16(PCH_LPC_DEV, GEN_PMCON_2) & GEN_PMCON_2_MEM_SR;
-+}
-+
-+static bool should_restore_xhci_smart_auto(void)
-+{
-+ if (!is_mem_sr())
-+ return false;
-+
-+ return pci_read_config32(PCH_LPC_DEV, PMIR) & PMIR_XHCI_SMART_AUTO;
-+}
-+
-+enum usb_port_route {
-+ ROUTE_TO_EHCI,
-+ ROUTE_TO_XHCI,
-+};
-+
-+/* Returns whether port reset was successful */
-+static bool reset_usb2_ports(const unsigned int ehci_ports)
-+{
-+ for (unsigned int port = 0; port < ehci_ports; port++) {
-+ /* Initiate port reset for all USB2 ports */
-+ clrsetbits32(
-+ xhci_bar + XHCI_USB2_PORTSC(port),
-+ XHCI_USB2_PORTSC_PED,
-+ XHCI_USB2_PORTSC_PR);
-+ }
-+ /* Poll for port reset bit to be cleared or time out at 100ms */
-+ struct stopwatch timer;
-+ stopwatch_init_msecs_expire(&timer, 100);
-+ uint32_t reg32;
-+ do {
-+ reg32 = 0;
-+ for (unsigned int port = 0; port < ehci_ports; port++)
-+ reg32 |= read32(xhci_bar + XHCI_USB2_PORTSC(port));
-+
-+ reg32 &= XHCI_USB2_PORTSC_PR;
-+ if (!reg32) {
-+ const long elapsed_time = stopwatch_duration_usecs(&timer);
-+ printk(BIOS_DEBUG, "%s: took %lu usecs\n", __func__, elapsed_time);
-+ return true;
-+ }
-+ /* Reference code has a 10 ms delay here, but a smaller delay works too */
-+ udelay(100);
-+ } while (!stopwatch_expired(&timer));
-+ printk(BIOS_ERR, "%s: timed out\n", __func__);
-+ return !reg32;
-+}
-+
-+/* Returns whether warm reset was successful */
-+static bool warm_reset_usb3_ports(const unsigned int xhci_ports)
-+{
-+ for (unsigned int port = 0; port < xhci_ports; port++) {
-+ /* Initiate warm reset for all USB3 ports */
-+ clrsetbits32(
-+ xhci_bar + XHCI_USB3_PORTSC(port),
-+ XHCI_USB3_PORTSC_PED,
-+ XHCI_USB3_PORTSC_WPR);
-+ }
-+ /* Poll for port reset bit to be cleared or time out at 100ms */
-+ struct stopwatch timer;
-+ stopwatch_init_msecs_expire(&timer, 100);
-+ uint32_t reg32;
-+ do {
-+ reg32 = 0;
-+ for (unsigned int port = 0; port < xhci_ports; port++)
-+ reg32 |= read32(xhci_bar + XHCI_USB3_PORTSC(port));
-+
-+ reg32 &= XHCI_USB3_PORTSC_PR;
-+ if (!reg32) {
-+ const long elapsed_time = stopwatch_duration_usecs(&timer);
-+ printk(BIOS_DEBUG, "%s: took %lu usecs\n", __func__, elapsed_time);
-+ return true;
-+ }
-+ /* Reference code has a 10 ms delay here, but a smaller delay works too */
-+ udelay(100);
-+ } while (!stopwatch_expired(&timer));
-+ printk(BIOS_ERR, "%s: timed out\n", __func__);
-+ return !reg32;
-+}
-+
-+static void perform_xhci_ehci_switching_flow(const enum usb_port_route usb_route)
-+{
-+ const pci_devfn_t dev = PCH_XHCI_DEV;
-+
-+ const unsigned int ehci_ports = hs_port_count() + is_usbr_enabled();
-+ const unsigned int xhci_ports = ss_port_count();
-+
-+ const uint32_t ehci_mask = BIT(ehci_ports) - 1;
-+ const uint32_t xhci_mask = BIT(xhci_ports) - 1;
-+
-+ /** TODO: Handle USBr port? How, though? **/
-+ pci_update_config32(dev, XHCI_USB2PRM, ~XHCI_USB2PR_HCSEL, ehci_mask);
-+ pci_update_config32(dev, XHCI_USB3PRM, ~XHCI_USB3PR_SSEN, xhci_mask);
-+
-+ /*
-+ * Workaround for USB2PR / USB3PR value not surviving warm reset.
-+ * Restore USB Port Routing registers if OS HC Switch driver has been executed.
-+ */
-+ if (should_restore_xhci_smart_auto()) {
-+ /** FIXME: Derive values from mainboard code instead? **/
-+ pci_update_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL, ehci_mask);
-+ pci_update_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN, xhci_mask);
-+ }
-+
-+ /* Later stages shouldn't need the value of this bit */
-+ pci_and_config32(PCH_LPC_DEV, PMIR, ~PMIR_XHCI_SMART_AUTO);
-+
-+ /**
-+ * FIXME: Things here depend on the chosen routing mode.
-+ * For now, implement both functions.
-+ */
-+
-+ /* Route to EHCI if xHCI disabled or auto mode */
-+ if (usb_route == ROUTE_TO_EHCI) {
-+ if (!reset_usb2_ports(ehci_ports))
-+ printk(BIOS_ERR, "USB2 port reset timed out\n");
-+
-+ pci_and_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL);
-+
-+ for (unsigned int port = 0; port < ehci_ports; port++) {
-+ clrsetbits32(
-+ xhci_bar + XHCI_USB2_PORTSC(port),
-+ XHCI_USB2_PORTSC_PED,
-+ XHCI_USB2_PORTSC_CHST);
-+ }
-+
-+ if (!warm_reset_usb3_ports(xhci_ports))
-+ printk(BIOS_ERR, "USB3 warm reset timed out\n");
-+
-+ /* FIXME: BWG says this should be inside the warm reset function */
-+ pci_and_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN);
-+
-+ for (unsigned int port = 0; port < ehci_ports; port++) {
-+ clrsetbits32(
-+ xhci_bar + XHCI_USB3_PORTSC(port),
-+ XHCI_USB3_PORTSC_PED,
-+ XHCI_USB3_PORTSC_CHST);
-+ }
-+
-+ setbits32(xhci_bar + XHCI_USBCMD, BIT(0));
-+ clrbits32(xhci_bar + XHCI_USBCMD, BIT(0));
-+ }
-+
-+ /* Route to xHCI if xHCI enabled */
-+ if (usb_route == ROUTE_TO_XHCI) {
-+ if (is_mem_sr()) {
-+ if (!warm_reset_usb3_ports(xhci_ports))
-+ printk(BIOS_ERR, "USB3 warm reset timed out\n");
-+ }
-+
-+ const uint32_t xhci_port_mask = pci_read_config32(dev, XHCI_USB3PRM) & 0x3f;
-+ pci_update_config32(dev, XHCI_USB3PR, ~XHCI_USB3PR_SSEN, xhci_port_mask);
-+
-+ const uint32_t ehci_port_mask = pci_read_config32(dev, XHCI_USB2PRM) & 0x7fff;
-+ pci_update_config32(dev, XHCI_USB2PR, ~XHCI_USB2PR_HCSEL, ehci_port_mask);
-+ }
-+}
-+
-+/* Do not shift in this macro, as it can cause undefined behaviour for bad port/oc values */
-+#define PORT_TO_OC_SHIFT(port, oc) ((oc) * 8 + (port))
-+
-+/* Avoid shifting into undefined behaviour */
-+static inline bool shift_ok(const int shift)
-+{
-+ return shift >= 0 && shift < 32;
-+}
-+
-+static void usb_overcurrent_mapping(void)
-+{
-+ const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
-+
-+ uint32_t ehci_1_ocmap = 0;
-+ uint32_t ehci_2_ocmap = 0;
-+ uint32_t xhci_1_ocmap = 0;
-+ uint32_t xhci_2_ocmap = 0;
-+
-+ /*
-+ * EHCI
-+ */
-+ for (unsigned int idx = 0; idx < physical_port_count(); idx++) {
-+ const struct usb2_port_config *const port = &mainboard_usb2_ports[idx];
-+ printk(BIOS_DEBUG, "USB2 port %u => ", idx);
-+ if (!port->enable) {
-+ printk(BIOS_DEBUG, "disabled\n");
-+ continue;
-+ }
-+ const unsigned short oc_pin = port->oc_pin;
-+ if (oc_pin == USB_OC_PIN_SKIP) {
-+ printk(BIOS_DEBUG, "not mapped to OC pin\n");
-+ continue;
-+ }
-+ /* Ports 0 .. 7 => OC 0 .. 3 */
-+ if (idx < 8 && oc_pin <= 3) {
-+ const int shift = PORT_TO_OC_SHIFT(idx, oc_pin);
-+ if (shift_ok(shift)) {
-+ printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
-+ ehci_1_ocmap |= 1 << shift;
-+ continue;
-+ }
-+ }
-+ /* Ports 8 .. 13 => OC 4 .. 7 (LPT-H only) */
-+ if (!is_lp && idx >= 8 && oc_pin >= 4) {
-+ const int shift = PORT_TO_OC_SHIFT(idx, oc_pin - 4);
-+ if (shift_ok(shift)) {
-+ printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
-+ ehci_2_ocmap |= 1 << shift;
-+ continue;
-+ }
-+ }
-+ printk(BIOS_ERR, "Invalid OC pin %u for USB2 port %u\n", oc_pin, idx);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ pci_write_config32(PCH_EHCI1_DEV, EHCI_OCMAP, ehci_1_ocmap);
-+ if (!is_lp)
-+ pci_write_config32(PCH_EHCI2_DEV, EHCI_OCMAP, ehci_2_ocmap);
-+
-+ /*
-+ * xHCI
-+ */
-+ for (unsigned int idx = 0; idx < ss_port_count(); idx++) {
-+ const struct usb3_port_config *const port = &mainboard_usb3_ports[idx];
-+ printk(BIOS_DEBUG, "USB3 port %u => ", idx);
-+ if (!port->enable) {
-+ printk(BIOS_DEBUG, "disabled\n");
-+ continue;
-+ }
-+ const unsigned short oc_pin = port->oc_pin;
-+ if (oc_pin == USB_OC_PIN_SKIP) {
-+ printk(BIOS_DEBUG, "not mapped to OC pin\n");
-+ continue;
-+ }
-+ /* Ports 0 .. 5 => OC 0 .. 3 */
-+ if (oc_pin <= 3) {
-+ const int shift = PORT_TO_OC_SHIFT(idx, oc_pin);
-+ if (shift_ok(shift)) {
-+ printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
-+ xhci_1_ocmap |= 1 << shift;
-+ continue;
-+ }
-+ }
-+ /* Ports 0 .. 5 => OC 4 .. 7 (LPT-H only) */
-+ if (!is_lp && oc_pin >= 4) {
-+ const int shift = PORT_TO_OC_SHIFT(idx, oc_pin - 4);
-+ if (shift_ok(shift)) {
-+ printk(BIOS_DEBUG, "mapped to OC pin %u\n", oc_pin);
-+ xhci_2_ocmap |= 1 << shift;
-+ continue;
-+ }
-+ }
-+ printk(BIOS_ERR, "Invalid OC pin %u for USB3 port %u\n", oc_pin, idx);
-+ }
-+ printk(BIOS_DEBUG, "\n");
-+ pci_write_config32(PCH_XHCI_DEV, XHCI_U2OCM1, ehci_1_ocmap);
-+ pci_write_config32(PCH_XHCI_DEV, XHCI_U3OCM1, xhci_1_ocmap);
-+ if (!is_lp) {
-+ pci_write_config32(PCH_XHCI_DEV, XHCI_U2OCM2, ehci_2_ocmap);
-+ pci_write_config32(PCH_XHCI_DEV, XHCI_U3OCM2, xhci_2_ocmap);
-+ }
-+}
-+
-+static uint8_t get_ehci_tune_param_1(const struct usb2_port_config *const port)
-+{
-+ const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
-+
-+ const enum pch_platform_type plat_type = get_pch_platform_type();
-+ const enum usb2_port_location location = port->location;
-+ const uint16_t length = port->length;
-+ if (!is_lp) {
-+ if (plat_type == PCH_TYPE_DESKTOP) {
-+ if (location == USB_PORT_BACK_PANEL)
-+ return 4; /* Back Panel */
-+ else
-+ return 3; /* Front Panel */
-+
-+ } else if (plat_type == PCH_TYPE_MOBILE) {
-+ if (location == USB_PORT_INTERNAL)
-+ return 5; /* Internal Topology */
-+ else if (location == USB_PORT_DOCK)
-+ return 4; /* Dock */
-+ else if (length < 0x70)
-+ return 5; /* Back Panel, less than 7" */
-+ else
-+ return 6; /* Back Panel, 7" or more */
-+ }
-+ } else {
-+ if (location == USB_PORT_BACK_PANEL || location == USB_PORT_MINI_PCIE) {
-+ if (length < 0x70)
-+ return 5; /* Back Panel, less than 7" */
-+ else
-+ return 6; /* Back Panel, 7" or more */
-+ } else if (location == USB_PORT_DOCK) {
-+ return 4; /* Dock */
-+ } else {
-+ return 5; /* Internal Topology */
-+ }
-+ }
-+ printk(BIOS_ERR, "%s: Unhandled case\n", __func__);
-+ return 0;
-+}
-+
-+static uint8_t get_ehci_tune_param_2(const struct usb2_port_config *const port)
-+{
-+ const bool is_lp = CONFIG(INTEL_LYNXPOINT_LP);
-+
-+ const enum pch_platform_type plat_type = get_pch_platform_type();
-+ const enum usb2_port_location location = port->location;
-+ const uint16_t length = port->length;
-+ if (!is_lp) {
-+ if (plat_type == PCH_TYPE_DESKTOP) {
-+ if (location == USB_PORT_BACK_PANEL) {
-+ if (length < 0x80)
-+ return 2; /* Back Panel, less than 8" */
-+ else if (length < 0x130)
-+ return 3; /* Back Panel, 8"-13" */
-+ else
-+ return 4; /* Back Panel, 13" or more */
-+ } else {
-+ return 2; /* Front Panel */
-+ }
-+
-+ } else if (plat_type == PCH_TYPE_MOBILE) {
-+ if (location == USB_PORT_INTERNAL) {
-+ return 2; /* Internal Topology */
-+ } else if (location == USB_PORT_DOCK) {
-+ if (length < 0x50)
-+ return 1; /* Dock, less than 5" */
-+ else
-+ return 2; /* Dock, 5" or more */
-+ } else {
-+ if (length < 0x100)
-+ return 2; /* Back Panel, less than 10" */
-+ else
-+ return 3; /* Back Panel, 10" or more */
-+ }
-+ }
-+ } else {
-+ if (location == USB_PORT_BACK_PANEL || location == USB_PORT_MINI_PCIE) {
-+ if (length < 0x100)
-+ return 2; /* Back Panel, less than 10" */
-+ else
-+ return 3; /* Back Panel, 10" or more */
-+ } else if (location == USB_PORT_DOCK) {
-+ if (length < 0x50)
-+ return 1; /* Dock, less than 5" */
-+ else
-+ return 2; /* Dock, 5" or more */
-+ } else {
-+ return 2; /* Internal Topology */
-+ }
-+ }
-+ printk(BIOS_ERR, "%s: Unhandled case\n", __func__);
-+ return 0;
-+}
-+
-+static void program_ehci_port_length(void)
-+{
-+ for (unsigned int port = 0; port < physical_port_count(); port++) {
-+ if (!mainboard_usb2_ports[port].enable)
-+ continue;
-+ const uint32_t addr = 0xe5004000 + (port + 1) * 0x100;
-+ const uint8_t param_1 = get_ehci_tune_param_1(&mainboard_usb2_ports[port]);
-+ const uint8_t param_2 = get_ehci_tune_param_2(&mainboard_usb2_ports[port]);
-+ pch_iobp_update(addr, ~0x7f00, param_2 << 11 | param_1 << 8);
-+ }
-+}
-+
-+void early_usb_init(void)
-+{
-+ /** TODO: Make this configurable? How do the modes affect usbdebug? **/
-+ const enum usb_port_route usb_route = ROUTE_TO_XHCI;
-+ ///(pd->boot_mode == 2 && pd->usb_xhci_on_resume) ? ROUTE_TO_XHCI : ROUTE_TO_EHCI;
-+
-+ common_ehci_hcs_init();
-+ xhci_open_memory_space();
-+ common_xhci_hc_init();
-+ perform_xhci_ehci_switching_flow(usb_route);
-+ usb_overcurrent_mapping();
-+ program_ehci_port_length();
-+ /** FIXME: USB per port control is missing, is it needed? **/
-+ xhci_close_memory_space();
-+ /** TODO: Close EHCI memory space? **/
-+}
-diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h
-index b5e0c2a830..ad983d86cf 100644
---- a/src/southbridge/intel/lynxpoint/pch.h
-+++ b/src/southbridge/intel/lynxpoint/pch.h
-@@ -115,6 +115,7 @@ enum pch_platform_type {
-
- void pch_dmi_setup_physical_layer(void);
- void pch_dmi_tc_vc_mapping(u32 vc0, u32 vc1, u32 vcp, u32 vcm);
-+void early_usb_init(void);
-
- void usb_ehci_sleep_prepare(pci_devfn_t dev, u8 slp_typ);
- void usb_ehci_disable(pci_devfn_t dev);
-@@ -202,6 +203,8 @@ void mainboard_config_rcba(void);
- #define GEN_PMCON_1 0xa0
- #define SMI_LOCK (1 << 4)
- #define GEN_PMCON_2 0xa2
-+#define GEN_PMCON_2_DISB (1 << 7)
-+#define GEN_PMCON_2_MEM_SR (1 << 5)
- #define SYSTEM_RESET_STS (1 << 4)
- #define THERMTRIP_STS (1 << 3)
- #define SYSPWR_FLR (1 << 1)
-@@ -215,6 +218,7 @@ void mainboard_config_rcba(void);
- #define PMIR 0xac
- #define PMIR_CF9LOCK (1 << 31)
- #define PMIR_CF9GR (1 << 20)
-+#define PMIR_XHCI_SMART_AUTO (1 << 16) /* c.f. LPT BWG or WPT-LP BIOS spec */
-
- /* GEN_PMCON_3 bits */
- #define RTC_BATTERY_DEAD (1 << 2)
-@@ -282,6 +286,20 @@ void mainboard_config_rcba(void);
- #define SATA_DTLE_DATA_SHIFT 24
- #define SATA_DTLE_EDGE_SHIFT 16
-
-+/*
-+ * HCD_INDEX == 2 selects 0:1a.0 (PCH_EHCI2), any other index
-+ * selects 0:1d.0 (PCH_EHCI1) for usbdebug use.
-+ */
-+#if CONFIG_USBDEBUG_HCD_INDEX != 2
-+#define PCH_EHCI1_TEMP_BAR0 CONFIG_EHCI_BAR
-+#define PCH_EHCI2_TEMP_BAR0 (PCH_EHCI1_TEMP_BAR0 + 0x400)
-+#else
-+#define PCH_EHCI2_TEMP_BAR0 CONFIG_EHCI_BAR
-+#define PCH_EHCI1_TEMP_BAR0 (PCH_EHCI2_TEMP_BAR0 + 0x400)
-+#endif
-+
-+#define PCH_XHCI_TEMP_BAR0 0xe8100000
-+
- /* EHCI PCI Registers */
- #define EHCI_PWR_CTL_STS 0x54
- #define PWR_CTL_SET_MASK 0x3
-@@ -289,10 +307,15 @@ void mainboard_config_rcba(void);
- #define PWR_CTL_SET_D3 0x3
- #define PWR_CTL_ENABLE_PME (1 << 8)
- #define PWR_CTL_STATUS_PME (1 << 15)
-+#define EHCI_OCMAP 0x74
-+#define EHCI_ACCESS_CNTL 0x80
-+#define ACCESS_CNTL_ENABLE (1 << 0)
-
- /* EHCI Memory Registers */
-+#define EHCI_HCS_PARAMS 0x04
- #define EHCI_USB_CMD 0x20
- #define EHCI_USB_CMD_RUN (1 << 0)
-+#define EHCI_USB_CMD_HCRESET (1 << 1)
- #define EHCI_USB_CMD_PSE (1 << 4)
- #define EHCI_USB_CMD_ASE (1 << 5)
- #define EHCI_PORTSC(port) (0x64 + (port) * 4)
-@@ -301,6 +324,10 @@ void mainboard_config_rcba(void);
-
- /* XHCI PCI Registers */
- #define XHCI_PWR_CTL_STS 0x74
-+#define XHCI_U2OCM1 0xc0
-+#define XHCI_U2OCM2 0xc4
-+#define XHCI_U3OCM1 0xc8
-+#define XHCI_U3OCM2 0xcc
- #define XHCI_USB2PR 0xd0
- #define XHCI_USB2PRM 0xd4
- #define XHCI_USB2PR_HCSEL 0x7fff
-@@ -313,6 +340,27 @@ void mainboard_config_rcba(void);
- #define XHCI_USB3PDO 0xe8
-
- /* XHCI Memory Registers */
-+#define XHCI_HCS_PARAMS_1 0x04
-+#define XHCI_HCS_PARAMS_2 0x08
-+#define XHCI_HCS_PARAMS_3 0x0c
-+#define XHCI_HCC_PARAMS 0x10
-+#define XHCI_USBCMD 0x80
-+#define XHCI_USB2_PORTSC(port) (0x480 + ((port) * 0x10))
-+#define XHCI_USB2_PORTSC_WPR (1 << 31) /* Warm Port Reset */
-+#define XHCI_USB2_PORTSC_CEC (1 << 23) /* Port Config Error Change */
-+#define XHCI_USB2_PORTSC_PLC (1 << 22) /* Port Link State Change */
-+#define XHCI_USB2_PORTSC_PRC (1 << 21) /* Port Reset Change */
-+#define XHCI_USB2_PORTSC_OCC (1 << 20) /* Over-current Change */
-+#define XHCI_USB2_PORTSC_WRC (1 << 19) /* Warm Port Reset Change */
-+#define XHCI_USB2_PORTSC_PEC (1 << 18) /* Port Enabled Disabled Change */
-+#define XHCI_USB2_PORTSC_CSC (1 << 17) /* Connect Status Change */
-+#define XHCI_USB2_PORTSC_CHST (0x7f << 17)
-+#define XHCI_USB2_PORTSC_LWS (1 << 16) /* Port Link State Write Strobe */
-+#define XHCI_USB2_PORTSC_PP (1 << 9)
-+#define XHCI_USB2_PORTSC_PR (1 << 4) /* Port Reset */
-+#define XHCI_USB2_PORTSC_PED (1 << 1) /* Port Enable/Disabled */
-+#define XHCI_USB2_PORTSC_CCS (1 << 0) /* Current Connect Status */
-+
- #define XHCI_USB3_PORTSC(port) ((pch_is_lp() ? 0x510 : 0x570) + ((port) * 0x10))
- #define XHCI_USB3_PORTSC_CHST (0x7f << 17)
- #define XHCI_USB3_PORTSC_WCE (1 << 25) /* Wake on Connect */
-@@ -320,6 +368,7 @@ void mainboard_config_rcba(void);
- #define XHCI_USB3_PORTSC_WOE (1 << 27) /* Wake on Overcurrent */
- #define XHCI_USB3_PORTSC_WRC (1 << 19) /* Warm Reset Complete */
- #define XHCI_USB3_PORTSC_LWS (1 << 16) /* Link Write Strobe */
-+#define XHCI_USB3_PORTSC_PR (1 << 4) /* Port Reset */
- #define XHCI_USB3_PORTSC_PED (1 << 1) /* Port Enabled/Disabled */
- #define XHCI_USB3_PORTSC_WPR (1 << 31) /* Warm Port Reset */
- #define XHCI_USB3_PORTSC_PLS (0xf << 5) /* Port Link State */
---
-2.39.2
-