Commit 482ba7a6 authored by Thierry Reding's avatar Thierry Reding Committed by Greg Kroah-Hartman

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 <jckuo@nvidia.com>.
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
Link: https://lore.kernel.org/r/20191206140653.2085561-5-thierry.reding@gmail.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ec12ac10
...@@ -830,10 +830,10 @@ static int tegra_xusb_request_firmware(struct tegra_xusb *tegra) ...@@ -830,10 +830,10 @@ static int tegra_xusb_request_firmware(struct tegra_xusb *tegra)
static int tegra_xusb_load_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; 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 tegra_xusb_fw_header *header;
struct xhci_cap_regs __iomem *cap;
struct xhci_op_regs __iomem *op;
struct device *dev = tegra->dev; struct device *dev = tegra->dev;
struct xhci_op_regs __iomem *op;
unsigned long timeout; unsigned long timeout;
time64_t timestamp; time64_t timestamp;
struct tm time; struct tm time;
...@@ -842,6 +842,7 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) ...@@ -842,6 +842,7 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
int err; int err;
header = (struct tegra_xusb_fw_header *)tegra->fw.virt; 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) { if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) {
dev_info(dev, "Firmware already loaded, Falcon state %#x\n", dev_info(dev, "Firmware already loaded, Falcon state %#x\n",
...@@ -911,21 +912,23 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra) ...@@ -911,21 +912,23 @@ static int tegra_xusb_load_firmware(struct tegra_xusb *tegra)
csb_writel(tegra, le32_to_cpu(header->boot_codetag), csb_writel(tegra, le32_to_cpu(header->boot_codetag),
XUSB_FALC_BOOTVEC); XUSB_FALC_BOOTVEC);
/* Boot Falcon CPU and wait for it to enter the STOPPED (idle) state. */ /* Boot Falcon CPU and wait for USBSTS_CNR to get cleared. */
timeout = jiffies + msecs_to_jiffies(5);
csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL); csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL);
while (time_before(jiffies, timeout)) { timeout = jiffies + msecs_to_jiffies(200);
if (csb_readl(tegra, XUSB_FALC_CPUCTL) == CPUCTL_STATE_STOPPED)
do {
value = readl(&op->status);
if ((value & STS_CNR) == 0)
break; 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) { value = readl(&op->status);
dev_err(dev, "Falcon failed to start, state: %#x\n", if (value & STS_CNR) {
csb_readl(tegra, XUSB_FALC_CPUCTL)); value = csb_readl(tegra, XUSB_FALC_CPUCTL);
dev_err(dev, "XHCI controller not read: %#010x\n", value);
return -EIO; return -EIO;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment