// SPDX-License-Identifier: GPL-2.0 /* * This file contains code to reset and initialize USB host controllers. * Some of it includes work-arounds for PCI hardware and BIOS quirks. * It may need to run early during booting -- before USB would normally * initialize -- to ensure that Linux doesn't use any legacy modes. * * Copyright (c) 1999 Martin Mares <mj@ucw.cz> * (and others)
*/
/* * The hardware normally enables the A-link power management feature, which * lets the system lower the power consumption in idle states. * * This USB quirk prevents the link going into that lower power state * during isochronous transfers. * * Without this quirk, isochronous stream on OHCI/EHCI/xHCI controllers of * some AMD platforms may stutter or have breaks occasionally.
*/ staticvoid usb_amd_quirk_pll(int disable)
{
u32 addr, addr_low, addr_high, val;
u32 bit = disable ? 0 : 1; unsignedlong flags;
spin_lock_irqsave(&amd_lock, flags);
if (disable) {
amd_chipset.isoc_reqs++; if (amd_chipset.isoc_reqs > 1) {
spin_unlock_irqrestore(&amd_lock, flags); return;
}
} else {
amd_chipset.isoc_reqs--; if (amd_chipset.isoc_reqs > 0) {
spin_unlock_irqrestore(&amd_lock, flags); return;
}
}
/* * Check if port is disabled in BIOS on AMD Promontory host. * BIOS Disabled ports may wake on connect/disconnect and need * driver workaround to keep them disabled. * Returns true if port is marked disabled.
*/ bool usb_amd_pt_check_port(struct device *device, int port)
{ unsignedchar value, port_shift; struct pci_dev *pdev;
u16 reg;
#ifdefined(CONFIG_HAS_IOPORT) && IS_ENABLED(CONFIG_USB_UHCI_HCD) /* * Make sure the controller is completely inactive, unable to * generate interrupts or do DMA.
*/ void uhci_reset_hc(struct pci_dev *pdev, unsignedlong base)
{ /* Turn off PIRQ enable and SMI enable. (This also turns off the * BIOS's USB Legacy Support.) Turn off all the R/WC bits too.
*/
pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC);
/* Reset the HC - this will force us to get a * new notification of any already connected * ports due to the virtual disconnect that it * implies.
*/
outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD);
mb();
udelay(5); if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET)
dev_warn(&pdev->dev, "HCRESET not completed yet!\n");
/* Just to be safe, disable interrupt requests and * make sure the controller is stopped.
*/
outw(0, base + UHCI_USBINTR);
outw(0, base + UHCI_USBCMD);
}
EXPORT_SYMBOL_GPL(uhci_reset_hc);
/* * Initialize a controller that was newly discovered or has just been * resumed. In either case we can't be sure of its previous state. * * Returns: 1 if the controller was reset, 0 otherwise.
*/ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsignedlong base)
{
u16 legsup; unsignedint cmd, intr;
/* * When restarting a suspended controller, we expect all the * settings to be the same as we left them: * * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; * Controller is stopped and configured with EGSM set; * No interrupts enabled except possibly Resume Detect. * * If any of these conditions are violated we do a complete reset.
*/
pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup); if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) {
dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n",
__func__, legsup); goto reset_needed;
}
base = pci_ioremap_bar(pdev, 0); if (base == NULL) return;
/* * ULi M5237 OHCI controller locks the whole system when accessing * the OHCI_FMINTERVAL offset.
*/ if (pdev->vendor == PCI_VENDOR_ID_AL && pdev->device == 0x5237)
no_fminterval = true;
control = readl(base + OHCI_CONTROL);
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ #ifdef __hppa__ #define OHCI_CTRL_MASK (OHCI_CTRL_RWC | OHCI_CTRL_IR) #else #define OHCI_CTRL_MASK OHCI_CTRL_RWC
if (control & OHCI_CTRL_IR) { int wait_time = 500; /* arbitrary; 5 seconds */
writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
writel(OHCI_OCR, base + OHCI_CMDSTATUS); while (wait_time > 0 &&
readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
wait_time -= 10;
msleep(10);
} if (wait_time <= 0)
dev_warn(&pdev->dev, "OHCI: BIOS handoff failed (BIOS bug?) %08x\n",
readl(base + OHCI_CONTROL));
} #endif
/* disable interrupts */
writel((u32) ~0, base + OHCI_INTRDISABLE);
/* Go into the USB_RESET state, preserving RWC (and possibly IR) */
writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
readl(base + OHCI_CONTROL);
/* software reset of the controller, preserving HcFmInterval */ if (!no_fminterval)
fminterval = readl(base + OHCI_FMINTERVAL);
writel(OHCI_HCR, base + OHCI_CMDSTATUS);
/* reset requires max 10 us delay */ for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) break;
udelay(1);
}
if (!no_fminterval)
writel(fminterval, base + OHCI_FMINTERVAL);
/* Now the controller is safely in SUSPEND and nothing can wake it up */
iounmap(base);
}
/* * The Pegatron Lucid tablet sporadically waits for 98 seconds trying * the handoff on its unused controller. Skip it. * * The HASEE E200 hangs when the semaphore is set (bugzilla #77021).
*/ if (pdev->vendor == 0x8086 && (pdev->device == 0x283a ||
pdev->device == 0x27cc)) { if (dmi_check_system(ehci_dmi_nohandoff_table))
try_handoff = 0;
}
#if 0 /* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on, * but that seems dubious in general (the BIOS left it off intentionally) * and is known to prevent some systems from booting. so we won't do this * unless maybe we can determine when we're on a system that needs SMI forced.
*/ /* BIOS workaround (?): be sure the pre-Linux code * receives the SMI
*/
pci_read_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, &val);
pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS,
val | EHCI_USBLEGCTLSTS_SOOE); #endif
/* some systems get upset if this semaphore is * set for any other reason than forcing a BIOS * handoff..
*/
pci_write_config_byte(pdev, offset + 3, 1);
}
/* if boot firmware now owns EHCI, spin till it hands it over. */ if (try_handoff) { int msec = 1000; while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
tried_handoff = 1;
msleep(10);
msec -= 10;
pci_read_config_dword(pdev, offset, &cap);
}
}
if (cap & EHCI_USBLEGSUP_BIOS) { /* well, possibly buggy BIOS... try to shut it down, * and hope nothing goes too wrong
*/ if (try_handoff)
dev_warn(&pdev->dev, "EHCI: BIOS handoff failed (BIOS bug?) %08x\n",
cap);
pci_write_config_byte(pdev, offset + 2, 0);
}
/* just in case, always disable EHCI SMIs */
pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, 0);
/* If the BIOS ever owned the controller then we can't expect * any power sessions to remain intact.
*/ if (tried_handoff)
writel(0, op_reg_base + EHCI_CONFIGFLAG);
}
base = pci_ioremap_bar(pdev, 0); if (base == NULL) return;
cap_length = readb(base);
op_reg_base = base + cap_length;
/* EHCI 0.96 and later may have "extended capabilities" * spec section 5.1 explains the bios handoff, e.g. for * booting from USB disk or using a usb keyboard
*/
hcc_params = readl(base + EHCI_HCC_PARAMS);
/* LS7A EHCI controller doesn't have extended capabilities, the * EECP (EHCI Extended Capabilities Pointer) field of HCCPARAMS * register should be 0x0 but it reads as 0xa0. So clear it to * avoid error messages on boot.
*/ if (pdev->vendor == PCI_VENDOR_ID_LOONGSON && pdev->device == 0x7a14)
hcc_params &= ~(0xffL << 8);
switch (cap & 0xff) { case 1:
ehci_bios_handoff(pdev, op_reg_base, cap, offset); break; case 0: /* Illegal reserved cap, set cap=0 so we exit */
cap = 0;
fallthrough; default:
dev_warn(&pdev->dev, "EHCI: unrecognized capability %02x\n",
cap & 0xff);
}
offset = (cap >> 8) & 0xff;
} if (!count)
dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n");
/* * halt EHCI & disable its interrupts in any case
*/
val = readl(op_reg_base + EHCI_USBSTS); if ((val & EHCI_USBSTS_HALTED) == 0) {
val = readl(op_reg_base + EHCI_USBCMD);
val &= ~EHCI_USBCMD_RUN;
writel(val, op_reg_base + EHCI_USBCMD);
/* * handshake - spin reading a register until handshake completes * @ptr: address of hc register to be read * @mask: bits to look at in result of read * @done: value of those bits when handshake succeeds * @wait_usec: timeout in microseconds * @delay_usec: delay in microseconds to wait between polling * * Polls a register every delay_usec microseconds. * Returns 0 when the mask bits have the value done. * Returns -ETIMEDOUT if this condition is not true after * wait_usec microseconds have passed.
*/ staticint handshake(void __iomem *ptr, u32 mask, u32 done, int wait_usec, int delay_usec)
{
u32 result;
/* * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that * share some number of ports. These ports can be switched between either * controller. Not all of the ports under the EHCI host controller may be * switchable. * * The ports should be switched over to xHCI before PCI probes for any device * start. This avoids active devices under EHCI being disconnected during the * port switchover, which could cause loss of data on USB storage devices, or * failed boot when the root file system is on a USB mass storage device and is * enumerated under EHCI first. * * We write into the xHC's PCI configuration space in some Intel-specific * registers to switch the ports over. The USB 3.0 terminations and the USB * 2.0 data wires are switched separately. We want to enable the SuperSpeed * terminations before switching the USB 2.0 wires over, so that USB 3.0 * devices connect at SuperSpeed, rather than at USB 2.0 speeds.
*/ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
{
u32 ports_available; bool ehci_found = false; struct pci_dev *companion = NULL;
/* Sony VAIO t-series with subsystem device ID 90a8 is not capable of * switching ports from EHCI to xHCI
*/ if (xhci_pdev->subsystem_vendor == PCI_VENDOR_ID_SONY &&
xhci_pdev->subsystem_device == 0x90a8) return;
/* make sure an intel EHCI controller exists */
for_each_pci_dev(companion) { if (companion->class == PCI_CLASS_SERIAL_USB_EHCI &&
companion->vendor == PCI_VENDOR_ID_INTEL) {
ehci_found = true; break;
}
}
if (!ehci_found) return;
/* Don't switchover the ports if the user hasn't compiled the xHCI * driver. Otherwise they will see "dead" USB ports that don't power * the devices.
*/ if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
dev_warn(&xhci_pdev->dev, "CONFIG_USB_XHCI_HCD is turned off, defaulting to EHCI.\n");
dev_warn(&xhci_pdev->dev, "USB 3.0 devices will work at USB 2.0 speeds.\n");
usb_disable_xhci_ports(xhci_pdev); return;
}
/* Read USB3PRM, the USB 3.0 Port Routing Mask Register * Indicate the ports that can be changed from OS.
*/
pci_read_config_dword(xhci_pdev, USB_INTEL_USB3PRM,
&ports_available);
dev_dbg(&xhci_pdev->dev, "Configurable ports to enable SuperSpeed: 0x%x\n",
ports_available);
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable * Register, to turn on SuperSpeed terminations for the * switchable ports.
*/
pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
ports_available);
pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
&ports_available);
dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled under xHCI: 0x%x\n",
ports_available);
/* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register * Indicate the USB 2.0 ports to be controlled by the xHCI host.
*/
dev_dbg(&xhci_pdev->dev, "Configurable USB 2.0 ports to hand over to xCHI: 0x%x\n",
ports_available);
/* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to * switch the USB 2.0 power and data lines over to the xHCI * host.
*/
pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
ports_available);
pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
&ports_available);
dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over to xHCI: 0x%x\n",
ports_available);
}
EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
/* * PCI Quirks for xHCI. * * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS. * It signals to the BIOS that the OS wants control of the host controller, * and then waits 1 second for the BIOS to hand over control. * If we timeout, assume the BIOS is broken and take control anyway.
*/ staticvoid quirk_usb_handoff_xhci(struct pci_dev *pdev)
{ void __iomem *base; int ext_cap_offset; void __iomem *op_reg_base;
u32 val; int timeout; int len = pci_resource_len(pdev, 0);
if (!mmio_resource_enabled(pdev, 0)) return;
base = ioremap(pci_resource_start(pdev, 0), len); if (base == NULL) return;
/* * Find the Legacy Support Capability register - * this is optional for xHCI host controllers.
*/
ext_cap_offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_LEGACY);
if (!ext_cap_offset) goto hc_init;
if ((ext_cap_offset + sizeof(val)) > len) { /* We're reading garbage from the controller */
dev_warn(&pdev->dev, "xHCI controller failing to respond"); goto iounmap;
}
val = readl(base + ext_cap_offset);
/* Auto handoff never worked for these devices. Force it and continue */ if ((pdev->vendor == PCI_VENDOR_ID_TI && pdev->device == 0x8241) ||
(pdev->vendor == PCI_VENDOR_ID_RENESAS
&& pdev->device == 0x0014)) {
val = (val | XHCI_HC_OS_OWNED) & ~XHCI_HC_BIOS_OWNED;
writel(val, base + ext_cap_offset);
}
/* If the BIOS owns the HC, signal that the OS wants it, and wait */ if (val & XHCI_HC_BIOS_OWNED) {
writel(val | XHCI_HC_OS_OWNED, base + ext_cap_offset);
/* Wait for 1 second with 10 microsecond polling interval */
timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
0, 1000000, 10);
/* Assume a buggy BIOS and take HC ownership anyway */ if (timeout) {
dev_warn(&pdev->dev, "xHCI BIOS handoff failed (BIOS bug ?) %08x\n",
val);
writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
}
}
val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); /* Mask off (turn off) any enabled SMIs */
val &= XHCI_LEGACY_DISABLE_SMI; /* Mask all SMI events bits, RW1C */
val |= XHCI_LEGACY_SMI_EVENTS; /* Disable any BIOS SMIs and clear all SMI events*/
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
hc_init: if (pdev->vendor == PCI_VENDOR_ID_INTEL)
usb_enable_intel_xhci_ports(pdev);
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
/* Wait for the host controller to be ready before writing any * operational or runtime registers. Wait 5 seconds and no more.
*/
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
5000000, 10); /* Assume a buggy HC and start HC initialization anyway */ if (timeout) {
val = readl(op_reg_base + XHCI_STS_OFFSET);
dev_warn(&pdev->dev, "xHCI HW not ready after 5 sec (HC bug?) status = 0x%x\n",
val);
}
/* Send the halt and disable interrupts command */
val = readl(op_reg_base + XHCI_CMD_OFFSET);
val &= ~(XHCI_CMD_RUN | XHCI_IRQS);
writel(val, op_reg_base + XHCI_CMD_OFFSET);
/* Wait for the HC to halt - poll every 125 usec (one microframe). */
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1,
XHCI_MAX_HALT_USEC, 125); if (timeout) {
val = readl(op_reg_base + XHCI_STS_OFFSET);
dev_warn(&pdev->dev, "xHCI HW did not halt within %d usec status = 0x%x\n",
XHCI_MAX_HALT_USEC, val);
}
/* Skip Netlogic mips SoC's internal PCI USB controller. * This device does not need/support EHCI/OHCI handoff
*/ if (pdev->vendor == 0x184e) /* vendor Netlogic */ return;
/* * Bypass the Raspberry Pi 4 controller xHCI controller, things are * taken care of by the board's co-processor.
*/ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) {
parent = of_get_parent(pdev->bus->dev.of_node);
is_rpi = of_device_is_compatible(parent, "brcm,bcm2711-pcie");
of_node_put(parent); if (is_rpi) return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.