From patchwork Wed Aug 14 12:16:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sherry Sun X-Patchwork-Id: 1147014 X-Patchwork-Delegate: marek.vasut@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nxp.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 467pwl0KzQz9sPL for ; Wed, 14 Aug 2019 22:36:22 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 93ADAC21E57; Wed, 14 Aug 2019 12:35:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 5EE27C21D4A; Wed, 14 Aug 2019 12:35:36 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 1AC63C21E53; Wed, 14 Aug 2019 12:35:29 +0000 (UTC) Received: from inva020.nxp.com (inva020.nxp.com [92.121.34.13]) by lists.denx.de (Postfix) with ESMTPS id AA16BC21E39 for ; Wed, 14 Aug 2019 12:35:28 +0000 (UTC) Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 7AD3E1A0005; Wed, 14 Aug 2019 14:35:28 +0200 (CEST) Received: from invc005.ap-rdc01.nxp.com (invc005.ap-rdc01.nxp.com [165.114.16.14]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 639791A0171; Wed, 14 Aug 2019 14:35:24 +0200 (CEST) Received: from localhost.localdomain (shlinux2.ap.freescale.net [10.192.224.44]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id 5864E402EC; Wed, 14 Aug 2019 20:35:19 +0800 (SGT) From: sherry sun To: marex@denx.de, lukma@denx.de, bmeng.cn@gmail.com Date: Wed, 14 Aug 2019 08:16:34 -0400 Message-Id: <1565784996-402-3-git-send-email-sherry.sun@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1565784996-402-1-git-send-email-sherry.sun@nxp.com> References: <1565784996-402-1-git-send-email-sherry.sun@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Cc: marcel.ziswiler@toradex.com, u-boot@lists.denx.de, uboot-imx@nxp.com Subject: [U-Boot] [PATCH v2 2/4] USB: host: Add the USB3 host driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Sherry Sun Add the USB3 host driver for NXP imx8 platform, and the cadence IP is in it. The USB3 host driver support DM mode, it will probe USB3 host node in dts. Signed-off-by: Sherry Sun --- drivers/usb/host/Kconfig | 9 ++ drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-imx8.c | 201 +++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 drivers/usb/host/xhci-imx8.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ac68aa2d27..cc1dfe463b 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -95,6 +95,15 @@ config USB_XHCI_FSL depends on !SPL_NO_USB help Enables support for the on-chip xHCI controller on NXP Layerscape SoCs. + +config USB_XHCI_IMX8 + bool "XHCI support for imx8" + depends on ARCH_IMX8 + default y + help + Enables support for the on-chip xHCI controller on imx8qm and + imx8qxp SoCs. + endif # USB_XHCI_HCD config USB_EHCI_HCD diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 6aa574f6f7..e5a0a4ea5a 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar.o obj-$(CONFIG_USB_XHCI_STI) += dwc3-sti-glue.o +obj-$(CONFIG_USB_XHCI_IMX8) += xhci-imx8.o # designware obj-$(CONFIG_USB_DWC2) += dwc2.o diff --git a/drivers/usb/host/xhci-imx8.c b/drivers/usb/host/xhci-imx8.c new file mode 100644 index 0000000000..3a7086742d --- /dev/null +++ b/drivers/usb/host/xhci-imx8.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + * + * NXP i.MX8 USB HOST xHCI Controller (Cadence IP) + * + * Author: Peter Chen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xhci.h" + +/* Declare global data pointer */ +DECLARE_GLOBAL_DATA_PTR; + +/* Host registers */ +#define HCIVERSION_CAPLENGTH 0x10000 +#define USBSTS 0x10084 + +/* None-core registers */ +#define USB3_CORE_CTRL1 0x00 +#define USB3_CORE_STATUS 0x0c +#define USB3_SSPHY_STATUS 0x4c + +struct xhci_imx8_data { + void __iomem *usb3_ctrl_base; + void __iomem *usb3_core_base; + struct clk_bulk clks; + struct phy phy; +}; + +static struct xhci_imx8_data imx8_data; + +static void imx8_xhci_init(void) +{ + u32 tmp_data; + int timeout_us = 100000; + + tmp_data = readl(imx8_data.usb3_ctrl_base + USB3_SSPHY_STATUS); + writel(tmp_data, imx8_data.usb3_ctrl_base + USB3_SSPHY_STATUS); + tmp_data = readl(imx8_data.usb3_ctrl_base + USB3_SSPHY_STATUS); + while ((tmp_data & 0xf0000000) != 0xf0000000 && timeout_us-- > 0) { + udelay(10); + tmp_data = readl(imx8_data.usb3_ctrl_base + USB3_SSPHY_STATUS); + } + + if (timeout_us <= 0) + printf("clkvld is incorrect = 0x%x\n", tmp_data); + + tmp_data = readl(imx8_data.usb3_ctrl_base + USB3_CORE_CTRL1); + tmp_data = (tmp_data & 0xfffffff8) | 0x202; + writel(tmp_data, imx8_data.usb3_ctrl_base + USB3_CORE_CTRL1); + clrbits_le32(imx8_data.usb3_ctrl_base + USB3_CORE_CTRL1, 1 << 26); + generic_phy_init(&imx8_data.phy); + + /* clear all sw_rst */ + clrbits_le32(imx8_data.usb3_ctrl_base + USB3_CORE_CTRL1, 0xFC << 24); + + debug("wait xhci_power_on_ready\n"); + tmp_data = readl(imx8_data.usb3_ctrl_base + USB3_CORE_STATUS); + timeout_us = 100000; + while (!(tmp_data & 0x1000) && timeout_us-- > 0) { + tmp_data = readl(imx8_data.usb3_ctrl_base + USB3_CORE_STATUS); + udelay(1); + } + + if (timeout_us <= 0) + printf("wait xhci_power_on_ready timeout\n"); + debug("xhci_power_on_ready\n"); + + tmp_data = readl(imx8_data.usb3_core_base + USBSTS); + debug("waiting CNR 0x%x\n", tmp_data); + timeout_us = 100000; + while (tmp_data & 0x800 && timeout_us-- > 0) { + tmp_data = readl(imx8_data.usb3_core_base + USBSTS); + udelay(1); + } + + if (timeout_us <= 0) + printf("wait CNR timeout\n"); + debug("check CNR has finished\n"); +} + +static void imx8_xhci_reset(void) +{ + /* Set CORE ctrl to default value, that all rst are hold */ + writel(0xfc000001, imx8_data.usb3_ctrl_base + USB3_CORE_CTRL1); +} + +static int xhci_imx8_clk_init(struct udevice *dev) +{ + int ret; + + ret = clk_get_bulk(dev, &imx8_data.clks); + if (ret) + return ret; + + ret = clk_enable_bulk(&imx8_data.clks); + if (ret) + return ret; + + return 0; +} + +static int xhci_imx8_get_reg_addr(struct udevice *dev) +{ + imx8_data.usb3_ctrl_base = + (void __iomem *)devfdt_get_addr_index(dev, 0); + imx8_data.usb3_core_base = + (void __iomem *)devfdt_get_addr_index(dev, 4); + + return 0; +} + +static int xhci_imx8_probe(struct udevice *dev) +{ + struct xhci_hccr *hccr; + struct xhci_hcor *hcor; + struct udevice usbotg_dev; + struct power_domain pd; + int usbotg_off; + int ret = 0; + int len; + + usbotg_off = fdtdec_lookup_phandle(gd->fdt_blob, + dev_of_offset(dev), + "cdns3,usb"); + if (usbotg_off < 0) + return -EINVAL; + usbotg_dev.node = offset_to_ofnode(usbotg_off); + usbotg_dev.parent = dev->parent; + xhci_imx8_get_reg_addr(&usbotg_dev); + +#if CONFIG_IS_ENABLED(POWER_DOMAIN) + if (!power_domain_get(&usbotg_dev, &pd)) { + if (power_domain_on(&pd)) + return -EINVAL; + } +#endif + + ret = generic_phy_get_by_index(&usbotg_dev, 0, &imx8_data.phy); + if (ret && ret != -ENOENT) { + printf("Failed to get USB PHY for %s\n", dev->name); + return ret; + } +#if CONFIG_IS_ENABLED(CLK) + xhci_imx8_clk_init(&usbotg_dev); +#endif + + imx8_xhci_init(); + + hccr = (struct xhci_hccr *)(imx8_data.usb3_core_base + + HCIVERSION_CAPLENGTH); + len = HC_LENGTH(xhci_readl(&hccr->cr_capbase)); + hcor = (struct xhci_hcor *)((uintptr_t)hccr + len); + printf("XHCI-imx8 init hccr 0x%p and hcor 0x%p hc_length %d\n", + (uint32_t *)hccr, (uint32_t *)hcor, len); + + return xhci_register(dev, hccr, hcor); +} + +static int xhci_imx8_remove(struct udevice *dev) +{ + int ret = xhci_deregister(dev); + if (!ret) + imx8_xhci_reset(); + +#if CONFIG_IS_ENABLED(CLK) + clk_release_bulk(&imx8_data.clks); +#endif + if (generic_phy_valid(&imx8_data.phy)) + device_remove(imx8_data.phy.dev, DM_REMOVE_NORMAL); + + return ret; +} + +static const struct udevice_id xhci_usb_ids[] = { + { .compatible = "Cadence,usb3-host", }, + { } +}; + +U_BOOT_DRIVER(xhci_imx8) = { + .name = "xhci_imx8", + .id = UCLASS_USB, + .of_match = xhci_usb_ids, + .probe = xhci_imx8_probe, + .remove = xhci_imx8_remove, + .ops = &xhci_usb_ops, + .platdata_auto_alloc_size = sizeof(struct usb_platdata), + .priv_auto_alloc_size = sizeof(struct xhci_ctrl), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +};