From 482ba7a6b42fa87dc8fa7d8c6140a916d0506549 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 6 Dec 2019 15:06:47 +0100 Subject: [PATCH] usb: host: xhci-tegra: Use CNR as firmware ready indicator The Falcon CPU state is a suboptimal indicator for firmware readiness, since the Falcon can be in a running state if the firmware is handling port state changes or running other tasks. Instead, the driver should check the STS_CNR bit to determine whether or not the firmware has been successfully loaded and is ready for XHCI operation. Based on work by JC Kuo . Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20191206140653.2085561-5-thierry.reding@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index e80fce712fd5..eda5e1d50828 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -830,10 +830,10 @@ static int tegra_xusb_request_firmware(struct tegra_xusb *tegra) static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) { unsigned int code_tag_blocks, code_size_blocks, code_blocks; + struct xhci_cap_regs __iomem *cap = tegra->regs; struct tegra_xusb_fw_header *header; - struct xhci_cap_regs __iomem *cap; - struct xhci_op_regs __iomem *op; struct device *dev = tegra->dev; + struct xhci_op_regs __iomem *op; unsigned long timeout; time64_t timestamp; struct tm time; @@ -842,6 +842,7 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) int err; header = (struct tegra_xusb_fw_header *)tegra->fw.virt; + op = tegra->regs + HC_LENGTH(readl(&cap->hc_capbase)); if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) { dev_info(dev, "Firmware already loaded, Falcon state %#x\n", @@ -911,21 +912,23 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) csb_writel(tegra, le32_to_cpu(header->boot_codetag), XUSB_FALC_BOOTVEC); - /* Boot Falcon CPU and wait for it to enter the STOPPED (idle) state. */ - timeout = jiffies + msecs_to_jiffies(5); - + /* Boot Falcon CPU and wait for USBSTS_CNR to get cleared. */ csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL); - while (time_before(jiffies, timeout)) { - if (csb_readl(tegra, XUSB_FALC_CPUCTL) == CPUCTL_STATE_STOPPED) + timeout = jiffies + msecs_to_jiffies(200); + + do { + value = readl(&op->status); + if ((value & STS_CNR) == 0) break; - usleep_range(100, 200); - } + usleep_range(1000, 2000); + } while (time_is_after_jiffies(timeout)); - if (csb_readl(tegra, XUSB_FALC_CPUCTL) != CPUCTL_STATE_STOPPED) { - dev_err(dev, "Falcon failed to start, state: %#x\n", - csb_readl(tegra, XUSB_FALC_CPUCTL)); + value = readl(&op->status); + if (value & STS_CNR) { + value = csb_readl(tegra, XUSB_FALC_CPUCTL); + dev_err(dev, "XHCI controller not read: %#010x\n", value); return -EIO; }