From patchwork Thu Dec 10 21:41:41 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mateusz Kulikowski X-Patchwork-Id: 555343 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 9174D1401DE for ; Fri, 11 Dec 2015 08:44:16 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=Kw4VHsil; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 241244B70B; Thu, 10 Dec 2015 22:44:00 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SwJwd2nZcDmr; Thu, 10 Dec 2015 22:44:00 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 67D534B70D; Thu, 10 Dec 2015 22:43:46 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 88E674B6E6 for ; Thu, 10 Dec 2015 22:43:37 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aNgCexm8Nz2Q for ; Thu, 10 Dec 2015 22:43:37 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-lb0-f176.google.com (mail-lb0-f176.google.com [209.85.217.176]) by theia.denx.de (Postfix) with ESMTPS id 4B5254B6DB for ; Thu, 10 Dec 2015 22:43:34 +0100 (CET) Received: by lbbcs9 with SMTP id cs9so59422548lbb.1 for ; Thu, 10 Dec 2015 13:43:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ygYKdHl6NYgagcPqbJ6Pj6qlAMZrSH0A0EmBzZmZTdU=; b=Kw4VHsil6nDrEZ5+B9tZsSsUUwv8NiWHzXRkw3y0pEmAEBDXtm6WtMF8ZMVlK6565i IwFEDB5mCT9lAVZXcj3BIM+RdwtUUqoAKy6qbVNnHu/X9SAtFqU/HGQ9l57beve27Ze4 Te0ad5tpjXMsSNTYYuhYiJJvyp5IUw9o9KFB5flDEUHm+zRQau6kamOlJgw/kPs3s2UP jWO4FjOYAbOdBPQKWdsBLNBE8nPVc/hR/JSrhHsbRJbiNrKeSjDogWZXjKDJjoKK7KLZ EsCrdvsEV2k3z74NnbKGNB/cqWibKm9wnYIDy6b6+OGYNfW72cFirc2aGWQwaW9sioQw trvw== X-Received: by 10.112.199.71 with SMTP id ji7mr6224935lbc.61.1449783814493; Thu, 10 Dec 2015 13:43:34 -0800 (PST) Received: from localhost.localdomain (095160097038.warszawa.vectranet.pl. [95.160.97.38]) by smtp.gmail.com with ESMTPSA id h9sm2624233lbj.42.2015.12.10.13.43.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 10 Dec 2015 13:43:34 -0800 (PST) From: Mateusz Kulikowski To: u-boot@lists.denx.de, Przemyslaw Marczak , sk.syed2@gmail.com, Tom Rini Date: Thu, 10 Dec 2015 22:41:41 +0100 Message-Id: <1449783707-23594-6-git-send-email-mateusz.kulikowski@gmail.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1449783707-23594-1-git-send-email-mateusz.kulikowski@gmail.com> References: <1449783707-23594-1-git-send-email-mateusz.kulikowski@gmail.com> Cc: Marek Vasut , Pantelis Antoniou Subject: [U-Boot] [RFC PATCH 05/11] ehci: Add support for Qualcomm EHCI X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 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" This driver is able to reconfigure OTG controller into HOST mode. Board can add board-specific initialization as board_prepare_usb(). It requires USB_ULPI_VIEWPORT enabled in board configuration. Signed-off-by: Mateusz Kulikowski --- drivers/usb/host/Kconfig | 8 ++ drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-msm.c | 198 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 drivers/usb/host/ehci-msm.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0096a2f..5a63475 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -66,6 +66,14 @@ config USB_EHCI_MX6 ---help--- Enables support for the on-chip EHCI controller on i.MX6 SoCs. +config USB_EHCI_MSM + bool "Support for Qualcomm on-chip EHCI USB controller" + depends on DM_USB + default n + ---help--- + Enables support for the on-chip EHCI controller on Qualcomm + Snapdragon SoCs. + config USB_EHCI_UNIPHIER bool "Support for UniPhier on-chip EHCI USB controller" depends on ARCH_UNIPHIER && OF_CONTROL diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 0b4b458..d4a556a 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_USB_EHCI_MX7) += ehci-mx6.o obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o obj-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o +obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c new file mode 100644 index 0000000..d17a29a --- /dev/null +++ b/drivers/usb/host/ehci-msm.c @@ -0,0 +1,198 @@ +/* + * Qualcomm EHCI driver + * + * (C) Copyright 2015 Mateusz Kulikowski + * + * Based on Linux driver + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ehci.h" + +#ifndef CONFIG_USB_ULPI_VIEWPORT +#error Please enable CONFIG_USB_ULPI_VIEWPORT +#endif + +#define MSM_USB_ULPI_OFFSET 0x170 /* ULPI viewport (PHY) */ +#define MSM_USB_EHCI_OFFSET 0x100 /* Start of EHCI registers */ + +/* PHY viewport regs */ +#define ULPI_MISC_A_READ 0x96 +#define ULPI_MISC_A_SET 0x97 +#define ULPI_MISC_A_CLEAR 0x98 +#define ULPI_MISC_A_VBUSVLDEXTSEL (1 << 1) +#define ULPI_MISC_A_VBUSVLDEXT (1 << 0) + +/* qcom specific registers (OTG) */ +#define USB_GENCONFIG_2 0x00A0 +#define GEN2_SESS_VLD_CTRL_EN (1 << 7) + +#define USB_USBCMD (0x0140) +#define SESS_VLD_CTRL (1 << 25) +#define USBCMD_RESET 2 +#define USBCMD_ATTACH 1 + +/* USB2_HSIC_USB_OTG_HS_BASE_USB_OTG_HS_PORTSC */ +#define USB_PORTSC 0x0184 +#define USB_SBUSCFG 0x0090 +#define USB_AHB_MODE 0x0098 + +#define USB_USBMODE 0x01A8 +#define USBMODE_DEVICE 2 +#define USBMODE_HOST 3 + +struct msm_ehci_priv { + struct ehci_ctrl ctrl; /* Needed by EHCI */ + phys_addr_t base; + phys_addr_t ehci_base; + u32 ulpi_base; + u32 ulpi_port; +}; + +int __weak board_prepare_usb(enum usb_init_type type) +{ + return 0; +} + +static void setup_usb_phy(struct msm_ehci_priv *priv) +{ + struct ulpi_viewport ulpi_vp = {.port_num = priv->ulpi_port, + .viewport_addr = priv->ulpi_base}; + + /* Select and enable external configuration with USB PHY */ + ulpi_write(&ulpi_vp, (u8 *)ULPI_MISC_A_SET, + ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); +} + +static void reset_usb_phy(struct msm_ehci_priv *priv) +{ + struct ulpi_viewport ulpi_vp = {.port_num = priv->ulpi_port, + .viewport_addr = priv->ulpi_base}; + + /* Disable VBUS mimicing in the controller. */ + ulpi_write(&ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR, + ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); +} + + +static int msm_init_after_reset(struct ehci_ctrl *dev) +{ + struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl); + uint32_t val; + + /* select ULPI phy */ + writel(0x80000000, p->base + USB_PORTSC); + setup_usb_phy(p); + + /* Enable sess_vld */ + val = readl(p->base + USB_GENCONFIG_2) | GEN2_SESS_VLD_CTRL_EN; + writel(val, p->base + USB_GENCONFIG_2); + + /* Enable external vbus configuration in the LINK */ + val = readl(p->base + USB_USBCMD); + val |= SESS_VLD_CTRL; + writel(val, p->base + USB_USBCMD); + + /* USB_OTG_HS_AHB_BURST */ + writel(0x0, p->base + USB_SBUSCFG); + + /* USB_OTG_HS_AHB_MODE: HPROT_MODE */ + /* Bus access related config. */ + writel(0x08, p->base + USB_AHB_MODE); + + /* set mode to host controller */ + writel(USBMODE_HOST, p->base + USB_USBMODE); + + return 0; +} + +static const struct ehci_ops msm_ehci_ops = { + .init_after_reset = msm_init_after_reset +}; + +static int ehci_usb_probe(struct udevice *dev) +{ + struct msm_ehci_priv *p = dev_get_priv(dev); + struct ehci_hccr *cr; + struct ehci_hcor *or; + int ret; + + cr = (struct ehci_hccr *)p->ehci_base; + or = (struct ehci_hcor *)(p->ehci_base + + HC_LENGTH(readl(p->ehci_base))); + + ret = board_prepare_usb(USB_INIT_HOST); + if (ret < 0) + return ret; + + + return ehci_register(dev, cr, or, &msm_ehci_ops, 0, USB_INIT_HOST); +} + +static int ehci_usb_remove(struct udevice *dev) +{ + struct msm_ehci_priv *p = dev_get_priv(dev); + phys_addr_t reg = p->base + USB_USBCMD; + int ret; + + ret = ehci_deregister(dev); + if (ret) + return ret; + + /* Stop controller. */ + writel(readl(reg) & ~USBCMD_ATTACH, reg); + + reset_usb_phy(p); + + ret = board_prepare_usb(USB_INIT_DEVICE); /* Board specific hook */ + if (ret < 0) + return ret; + + /* Reset controller */ + writel(0x00080002, reg); /* reset usb */ + mdelay(20); + /* Wait for completion */ + while (readl(reg) & 2) + ; + + return 0; +} + +static int ehci_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct msm_ehci_priv *priv = dev_get_priv(dev); + + priv->base = dev_get_addr(dev); + priv->ehci_base = priv->base + MSM_USB_EHCI_OFFSET; + priv->ulpi_base = priv->base + MSM_USB_ULPI_OFFSET; + priv->ulpi_port = 0; + return 0; +} + +static const struct udevice_id ehci_usb_ids[] = { + { .compatible = "qcom,ehci-host", }, + { } +}; + +U_BOOT_DRIVER(usb_ehci) = { + .name = "ehci_msm", + .id = UCLASS_USB, + .of_match = ehci_usb_ids, + .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, + .probe = ehci_usb_probe, + .remove = ehci_usb_remove, + .ops = &ehci_usb_ops, + .priv_auto_alloc_size = sizeof(struct msm_ehci_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +};