From patchwork Mon Apr 20 03:21:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 1273114 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=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=mediatek.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.a=rsa-sha256 header.s=dk header.b=I56hcs9H; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 495C1L3btcz9sR4 for ; Mon, 20 Apr 2020 13:32:06 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 9D68081C4C; Mon, 20 Apr 2020 05:31:29 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=mediatek.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=mediatek.com header.i=@mediatek.com header.b="I56hcs9H"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 29EE3819EF; Mon, 20 Apr 2020 05:30:59 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MIME_BASE64_TEXT,RDNS_NONE,SPF_HELO_NONE,UNPARSEABLE_RELAY, URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mailgw02.mediatek.com (unknown [210.61.82.184]) by phobos.denx.de (Postfix) with ESMTP id CFDD681737 for ; Mon, 20 Apr 2020 05:30:27 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=mediatek.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=chunfeng.yun@mediatek.com X-UUID: abb0356b5f2d497b8ce8a23de0d50b32-20200420 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=+MWcXNihqZZQ2dPEXfnZV8mbb6em7T5jKVpQhYXntrU=; b=I56hcs9HPVkF8o/R74DZr8kOqQLCDK0W55Td0AkvQ38I2srliEpJOUcjrN97UAfcsIOjY6heTyumcX+QSnguj1ruyH0ecKKm9RCzXP+RJh8Ft4xe74LqlCSnXqOkwEzLiB62IGFw7vFzLsP7SqtY1KlBL6i1UxwCqF3U2PAEbto=; X-UUID: abb0356b5f2d497b8ce8a23de0d50b32-20200420 Received: from mtkcas10.mediatek.inc [(172.21.101.39)] by mailgw02.mediatek.com (envelope-from ) (Cellopoint E-mail Firewall v4.1.10 Build 0809 with TLS) with ESMTP id 272197473; Mon, 20 Apr 2020 11:22:30 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs05n2.mediatek.inc (172.21.101.140) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Mon, 20 Apr 2020 11:22:27 +0800 Received: from localhost.localdomain (10.17.3.153) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Mon, 20 Apr 2020 11:22:27 +0800 From: Chunfeng Yun To: Simon Glass , Ryder Lee , Marek Vasut , Bin Meng CC: Weijie Gao , GSS_MTK_Uboot_upstream , Jagan Teki , Stefan Roese , Neil Armstrong , Sam Shih , Chunfeng Yun , Frank Wunderlich , Jean-Jacques Hiblot , Alex Marginean , Patrick Delaunay , Lukasz Majewski , AKASHI Takahiro , Anatolij Gustschin , Ye Li , Fabio Estevam , Marcel Ziswiler , Heiko Schocher , Mark Kettenis , Adam Ford , , Masahiro Yamada , Vignesh Raghavendra Subject: [PATCH v6 10/14] xhci: mediatek: Add support for MTK xHCI host controller Date: Mon, 20 Apr 2020 11:21:19 +0800 Message-ID: <1587352883-8641-11-git-send-email-chunfeng.yun@mediatek.com> X-Mailer: git-send-email 1.8.1.1.dirty In-Reply-To: <1587352883-8641-1-git-send-email-chunfeng.yun@mediatek.com> References: <1587352883-8641-1-git-send-email-chunfeng.yun@mediatek.com> MIME-Version: 1.0 X-MTK: N X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.30rc1 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.2 at phobos.denx.de X-Virus-Status: Clean This patch is used to support the on-chip xHCI controller on MediaTek SoCs, currently control/bulk/interrupt transfers are supported. Signed-off-by: Chunfeng Yun Reviewed-by: Weijie Gao --- v6: add Reviewed-by Weijie v5: 1. print error number suggested by Marek 2. support interrupt transfer v4: 1. use phy_bulk API v3: 1. use macro approach to access registers suggested by Marek v2: 1. use clk_bulk to get clocks suggested by Marek 2. use clrsetbits_le32() etc suggeseted by Marek --- drivers/usb/host/Kconfig | 6 + drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-mtk.c | 296 ++++++++++++++++++++++++++++++++++++ drivers/usb/host/xhci.c | 10 ++ include/usb/xhci.h | 3 + 5 files changed, 316 insertions(+) create mode 100644 drivers/usb/host/xhci-mtk.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 94ac969058..2f381dc958 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -30,6 +30,12 @@ config USB_XHCI_DWC3_OF_SIMPLE Support USB2/3 functionality in simple SoC integrations with USB controller based on the DesignWare USB3 IP Core. +config USB_XHCI_MTK + bool "Support for MediaTek on-chip xHCI USB controller" + depends on ARCH_MEDIATEK + help + Enables support for the on-chip xHCI controller on MediaTek SoCs. + config USB_XHCI_MVEBU bool "MVEBU USB 3.0 support" default y diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index b62f346094..e8e3b17e42 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_XHCI_ROCKCHIP) += xhci-rockchip.o obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o +obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk.o obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c new file mode 100644 index 0000000000..93293ca180 --- /dev/null +++ b/drivers/usb/host/xhci-mtk.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019 MediaTek, Inc. + * Authors: Chunfeng Yun + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* IPPC (IP Port Control) registers */ +#define IPPC_IP_PW_CTRL0 0x00 +#define CTRL0_IP_SW_RST BIT(0) + +#define IPPC_IP_PW_CTRL1 0x04 +#define CTRL1_IP_HOST_PDN BIT(0) + +#define IPPC_IP_PW_STS1 0x10 +#define STS1_IP_SLEEP_STS BIT(30) +#define STS1_U3_MAC_RST BIT(16) +#define STS1_XHCI_RST BIT(11) +#define STS1_SYS125_RST BIT(10) +#define STS1_REF_RST BIT(8) +#define STS1_SYSPLL_STABLE BIT(0) + +#define IPPC_IP_XHCI_CAP 0x24 +#define CAP_U3_PORT_NUM(p) ((p) & 0xff) +#define CAP_U2_PORT_NUM(p) (((p) >> 8) & 0xff) + +#define IPPC_U3_CTRL_0P 0x30 +#define CTRL_U3_PORT_HOST_SEL BIT(2) +#define CTRL_U3_PORT_PDN BIT(1) +#define CTRL_U3_PORT_DIS BIT(0) + +#define IPPC_U2_CTRL_0P 0x50 +#define CTRL_U2_PORT_HOST_SEL BIT(2) +#define CTRL_U2_PORT_PDN BIT(1) +#define CTRL_U2_PORT_DIS BIT(0) + +#define IPPC_U3_CTRL(p) (IPPC_U3_CTRL_0P + ((p) * 0x08)) +#define IPPC_U2_CTRL(p) (IPPC_U2_CTRL_0P + ((p) * 0x08)) + +struct mtk_xhci { + struct xhci_ctrl ctrl; /* Needs to come first in this struct! */ + struct xhci_hccr *hcd; + void __iomem *ippc; + struct udevice *dev; + struct udevice *vusb33_supply; + struct udevice *vbus_supply; + struct clk_bulk clks; + struct phy_bulk phys; + int num_u2ports; + int num_u3ports; +}; + +static int xhci_mtk_host_enable(struct mtk_xhci *mtk) +{ + u32 value; + u32 check_val; + int ret; + int i; + + /* power on host ip */ + clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); + + /* power on and enable all u3 ports */ + for (i = 0; i < mtk->num_u3ports; i++) { + clrsetbits_le32(mtk->ippc + IPPC_U3_CTRL(i), + CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS, + CTRL_U3_PORT_HOST_SEL); + } + + /* power on and enable all u2 ports */ + for (i = 0; i < mtk->num_u2ports; i++) { + clrsetbits_le32(mtk->ippc + IPPC_U2_CTRL(i), + CTRL_U2_PORT_PDN | CTRL_U2_PORT_DIS, + CTRL_U2_PORT_HOST_SEL); + } + + /* + * wait for clocks to be stable, and clock domains reset to + * be inactive after power on and enable ports + */ + check_val = STS1_SYSPLL_STABLE | STS1_REF_RST | + STS1_SYS125_RST | STS1_XHCI_RST; + + if (mtk->num_u3ports) + check_val |= STS1_U3_MAC_RST; + + ret = readl_poll_timeout(mtk->ippc + IPPC_IP_PW_STS1, value, + (check_val == (value & check_val)), 20000); + if (ret) + dev_err(mtk->dev, "clocks are not stable 0x%x!\n", value); + + return ret; +} + +static int xhci_mtk_host_disable(struct mtk_xhci *mtk) +{ + int i; + + /* power down all u3 ports */ + for (i = 0; i < mtk->num_u3ports; i++) + setbits_le32(mtk->ippc + IPPC_U3_CTRL(i), CTRL_U3_PORT_PDN); + + /* power down all u2 ports */ + for (i = 0; i < mtk->num_u2ports; i++) + setbits_le32(mtk->ippc + IPPC_U2_CTRL(i), CTRL_U2_PORT_PDN); + + /* power down host ip */ + setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL1, CTRL1_IP_HOST_PDN); + + return 0; +} + +static int xhci_mtk_ssusb_init(struct mtk_xhci *mtk) +{ + u32 value; + + /* reset whole ip */ + setbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST); + udelay(1); + clrbits_le32(mtk->ippc + IPPC_IP_PW_CTRL0, CTRL0_IP_SW_RST); + + value = readl(mtk->ippc + IPPC_IP_XHCI_CAP); + mtk->num_u3ports = CAP_U3_PORT_NUM(value); + mtk->num_u2ports = CAP_U2_PORT_NUM(value); + dev_info(mtk->dev, "u2p:%d, u3p:%d\n", + mtk->num_u2ports, mtk->num_u3ports); + + return xhci_mtk_host_enable(mtk); +} + +static int xhci_mtk_ofdata_get(struct mtk_xhci *mtk) +{ + struct udevice *dev = mtk->dev; + int ret = 0; + + mtk->hcd = devfdt_remap_addr_name(dev, "mac"); + if (!mtk->hcd) { + dev_err(dev, "failed to get xHCI base address\n"); + return -ENXIO; + } + + mtk->ippc = devfdt_remap_addr_name(dev, "ippc"); + if (!mtk->ippc) { + dev_err(dev, "failed to get IPPC base address\n"); + return -ENXIO; + } + + dev_info(dev, "hcd: 0x%p, ippc: 0x%p\n", mtk->hcd, mtk->ippc); + + ret = clk_get_bulk(dev, &mtk->clks); + if (ret) { + dev_err(dev, "failed to get clocks %d!\n", ret); + return ret; + } + + ret = device_get_supply_regulator(dev, "vusb33-supply", + &mtk->vusb33_supply); + if (ret) + debug("can't get vusb33 regulator %d!\n", ret); + + ret = device_get_supply_regulator(dev, "vbus-supply", + &mtk->vbus_supply); + if (ret) + debug("can't get vbus regulator %d!\n", ret); + + return 0; +} + +static int xhci_mtk_ldos_enable(struct mtk_xhci *mtk) +{ + int ret; + + ret = regulator_set_enable(mtk->vusb33_supply, true); + if (ret < 0 && ret != -ENOSYS) { + dev_err(mtk->dev, "failed to enable vusb33 %d!\n", ret); + return ret; + } + + ret = regulator_set_enable(mtk->vbus_supply, true); + if (ret < 0 && ret != -ENOSYS) { + dev_err(mtk->dev, "failed to enable vbus %d!\n", ret); + regulator_set_enable(mtk->vusb33_supply, false); + return ret; + } + + return 0; +} + +static void xhci_mtk_ldos_disable(struct mtk_xhci *mtk) +{ + regulator_set_enable(mtk->vbus_supply, false); + regulator_set_enable(mtk->vusb33_supply, false); +} + +int xhci_mtk_phy_setup(struct mtk_xhci *mtk) +{ + struct udevice *dev = mtk->dev; + struct phy_bulk *phys = &mtk->phys; + int ret; + + ret = generic_phy_get_bulk(dev, phys); + if (ret) { + dev_err(dev, "failed to get phys %d!\n", ret); + return ret; + } + + return generic_phy_enable_bulk(phys); +} + +void xhci_mtk_phy_shutdown(struct mtk_xhci *mtk) +{ + generic_phy_disable_bulk(&mtk->phys); +} + +static int xhci_mtk_probe(struct udevice *dev) +{ + struct mtk_xhci *mtk = dev_get_priv(dev); + struct xhci_hcor *hcor; + int ret; + + mtk->dev = dev; + ret = xhci_mtk_ofdata_get(mtk); + if (ret) + return ret; + + ret = xhci_mtk_ldos_enable(mtk); + if (ret) + goto ldos_err; + + ret = clk_enable_bulk(&mtk->clks); + if (ret) + goto clks_err; + + ret = xhci_mtk_phy_setup(mtk); + if (ret) + goto phys_err; + + ret = xhci_mtk_ssusb_init(mtk); + if (ret) + goto ssusb_init_err; + + hcor = (struct xhci_hcor *)((uintptr_t)mtk->hcd + + HC_LENGTH(xhci_readl(&mtk->hcd->cr_capbase))); + + return xhci_register(dev, mtk->hcd, hcor); + +ssusb_init_err: + xhci_mtk_phy_shutdown(mtk); +phys_err: + clk_disable_bulk(&mtk->clks); +clks_err: + xhci_mtk_ldos_disable(mtk); +ldos_err: + return ret; +} + +static int xhci_mtk_remove(struct udevice *dev) +{ + struct mtk_xhci *mtk = dev_get_priv(dev); + + xhci_deregister(dev); + xhci_mtk_host_disable(mtk); + xhci_mtk_ldos_disable(mtk); + clk_disable_bulk(&mtk->clks); + + return 0; +} + +static const struct udevice_id xhci_mtk_ids[] = { + { .compatible = "mediatek,mtk-xhci" }, + { } +}; + +U_BOOT_DRIVER(usb_xhci) = { + .name = "xhci-mtk", + .id = UCLASS_USB, + .of_match = xhci_mtk_ids, + .probe = xhci_mtk_probe, + .remove = xhci_mtk_remove, + .ops = &xhci_usb_ops, + .bind = dm_scan_fdt_dev, + .priv_auto_alloc_size = sizeof(struct mtk_xhci), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 40dee2e6d9..c370eb6394 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -610,6 +610,16 @@ static int xhci_set_configuration(struct usb_device *udev) ep_ctx[ep_index]->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) | EP_AVG_TRB_LENGTH(avg_trb_len)); + + /* + * The MediaTek xHCI defines some extra SW parameters which + * are put into reserved DWs in Slot and Endpoint Contexts + * for synchronous endpoints. + */ + if (IS_ENABLED(CONFIG_USB_XHCI_MTK)) { + ep_ctx[ep_index]->reserved[0] = + cpu_to_le32(EP_BPKTS(1) | EP_BBM(1)); + } } return xhci_configure_endpoints(udev, false); diff --git a/include/usb/xhci.h b/include/usb/xhci.h index 6017504488..20e4a21066 100644 --- a/include/usb/xhci.h +++ b/include/usb/xhci.h @@ -670,6 +670,9 @@ struct xhci_ep_ctx { /* deq bitmasks */ #define EP_CTX_CYCLE_MASK (1 << 0) +/* reserved[0] bitmasks, MediaTek xHCI used */ +#define EP_BPKTS(p) (((p) & 0x7f) << 0) +#define EP_BBM(p) (((p) & 0x1) << 11) /** * struct xhci_input_control_context