diff mbox

[U-Boot,v2,5/6] usb: host: Add ehci-vf USB driver for ARM Vybrid SoC's

Message ID 46735d5d2cbe2d946742db50728198c19dd781ff.1428497492.git.maitysanchayan@gmail.com
State Superseded
Delegated to: Tom Rini
Headers show

Commit Message

Sanchayan Maity April 8, 2015, 1:20 p.m. UTC
This driver adds support for the USB peripheral on Freescale Vybrid
SoC's.

Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
---
 arch/arm/include/asm/arch-vf610/crm_regs.h    |  10 ++
 arch/arm/include/asm/arch-vf610/imx-regs.h    |   4 +
 arch/arm/include/asm/arch-vf610/regs-usbphy.h |  31 ++++
 drivers/usb/host/Makefile                     |   1 +
 drivers/usb/host/ehci-vf.c                    | 196 ++++++++++++++++++++++++++
 5 files changed, 242 insertions(+)
 create mode 100644 arch/arm/include/asm/arch-vf610/regs-usbphy.h
 create mode 100644 drivers/usb/host/ehci-vf.c

Comments

Marek Vasut April 12, 2015, 11:29 p.m. UTC | #1
On Wednesday, April 08, 2015 at 03:20:09 PM, Sanchayan Maity wrote:
> This driver adds support for the USB peripheral on Freescale Vybrid
> SoC's.
> 
> Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
> ---
>  arch/arm/include/asm/arch-vf610/crm_regs.h    |  10 ++
>  arch/arm/include/asm/arch-vf610/imx-regs.h    |   4 +
>  arch/arm/include/asm/arch-vf610/regs-usbphy.h |  31 ++++
>  drivers/usb/host/Makefile                     |   1 +
>  drivers/usb/host/ehci-vf.c                    | 196
> ++++++++++++++++++++++++++ 5 files changed, 242 insertions(+)
>  create mode 100644 arch/arm/include/asm/arch-vf610/regs-usbphy.h
>  create mode 100644 drivers/usb/host/ehci-vf.c

A general hint, you can replace sequences of code like this:

var = readl(foo);
var |= BIT_BAR;
writel(var, addr);

with

setbits_le32(var, BIT_BAR);

Same applies for clearing -- clrbits_le32() and both setting and
clearing -- clrsetbits_le32().

Thanks!

Best regards,
Marek Vasut
Sanchayan Maity April 13, 2015, 5:37 a.m. UTC | #2
Hello,

On 15-04-13 01:29:39, Marek Vasut wrote:
> On Wednesday, April 08, 2015 at 03:20:09 PM, Sanchayan Maity wrote:
> > This driver adds support for the USB peripheral on Freescale Vybrid
> > SoC's.
> > 
> > Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
> > ---
> >  arch/arm/include/asm/arch-vf610/crm_regs.h    |  10 ++
> >  arch/arm/include/asm/arch-vf610/imx-regs.h    |   4 +
> >  arch/arm/include/asm/arch-vf610/regs-usbphy.h |  31 ++++
> >  drivers/usb/host/Makefile                     |   1 +
> >  drivers/usb/host/ehci-vf.c                    | 196
> > ++++++++++++++++++++++++++ 5 files changed, 242 insertions(+)
> >  create mode 100644 arch/arm/include/asm/arch-vf610/regs-usbphy.h
> >  create mode 100644 drivers/usb/host/ehci-vf.c
> 
> A general hint, you can replace sequences of code like this:
> 
> var = readl(foo);
> var |= BIT_BAR;
> writel(var, addr);
> 
> with
> 
> setbits_le32(var, BIT_BAR);
> 
> Same applies for clearing -- clrbits_le32() and both setting and
> clearing -- clrsetbits_le32().

Sorry about that. It is something which I use in the sixth patch 
as well in the board files but it skipped my mind while doing this 
driver. Will take care of it in v3 which seems imminent.

Noted, thanks :).

- Sanchayan.

> 
> Thanks!
> 
> Best regards,
> Marek Vasut
Marek Vasut April 13, 2015, 5:49 a.m. UTC | #3
On Monday, April 13, 2015 at 07:37:42 AM, maitysanchayan@gmail.com wrote:
> Hello,
> 
> On 15-04-13 01:29:39, Marek Vasut wrote:
> > On Wednesday, April 08, 2015 at 03:20:09 PM, Sanchayan Maity wrote:
> > > This driver adds support for the USB peripheral on Freescale Vybrid
> > > SoC's.
> > > 
> > > Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
> > > ---
> > > 
> > >  arch/arm/include/asm/arch-vf610/crm_regs.h    |  10 ++
> > >  arch/arm/include/asm/arch-vf610/imx-regs.h    |   4 +
> > >  arch/arm/include/asm/arch-vf610/regs-usbphy.h |  31 ++++
> > >  drivers/usb/host/Makefile                     |   1 +
> > >  drivers/usb/host/ehci-vf.c                    | 196
> > > 
> > > ++++++++++++++++++++++++++ 5 files changed, 242 insertions(+)
> > > 
> > >  create mode 100644 arch/arm/include/asm/arch-vf610/regs-usbphy.h
> > >  create mode 100644 drivers/usb/host/ehci-vf.c
> > 
> > A general hint, you can replace sequences of code like this:
> > 
> > var = readl(foo);
> > var |= BIT_BAR;
> > writel(var, addr);
> > 
> > with
> > 
> > setbits_le32(var, BIT_BAR);
> > 
> > Same applies for clearing -- clrbits_le32() and both setting and
> > clearing -- clrsetbits_le32().
> 
> Sorry about that. It is something which I use in the sixth patch
> as well in the board files but it skipped my mind while doing this
> driver. Will take care of it in v3 which seems imminent.
> 
> Noted, thanks :).

Thank you :)

Best regards,
Marek Vasut
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-vf610/crm_regs.h b/arch/arm/include/asm/arch-vf610/crm_regs.h
index 78708e2..bc6db2a 100644
--- a/arch/arm/include/asm/arch-vf610/crm_regs.h
+++ b/arch/arm/include/asm/arch-vf610/crm_regs.h
@@ -189,6 +189,7 @@  struct anadig_reg {
 #define CCM_REG_CTRL_MASK			0xffffffff
 #define CCM_CCGR0_UART0_CTRL_MASK               (0x3 << 14)
 #define CCM_CCGR0_UART1_CTRL_MASK		(0x3 << 16)
+#define CCM_CCGR1_USBC0_CTRL_MASK       (0x3 << 8)
 #define CCM_CCGR1_PIT_CTRL_MASK			(0x3 << 14)
 #define CCM_CCGR1_WDOGA5_CTRL_MASK		(0x3 << 28)
 #define CCM_CCGR2_QSPI0_CTRL_MASK		(0x3 << 8)
@@ -207,14 +208,23 @@  struct anadig_reg {
 #define CCM_CCGR6_OCOTP_CTRL_MASK		(0x3 << 10)
 #define CCM_CCGR6_DDRMC_CTRL_MASK		(0x3 << 28)
 #define CCM_CCGR7_SDHC1_CTRL_MASK		(0x3 << 4)
+#define CCM_CCGR7_USBC1_CTRL_MASK       (0x3 << 8)
 #define CCM_CCGR9_FEC0_CTRL_MASK		0x3
 #define CCM_CCGR9_FEC1_CTRL_MASK		(0x3 << 2)
 #define CCM_CCGR10_NFC_CTRL_MASK		0x3
 
+#define ANADIG_PLL7_CTRL_BYPASS         (1 << 16)
+#define ANADIG_PLL7_CTRL_ENABLE         (1 << 13)
+#define ANADIG_PLL7_CTRL_POWERDOWN      (1 << 12)
+#define ANADIG_PLL7_CTRL_DIV_SELECT     (1 << 1)
 #define ANADIG_PLL5_CTRL_BYPASS                 (1 << 16)
 #define ANADIG_PLL5_CTRL_ENABLE                 (1 << 13)
 #define ANADIG_PLL5_CTRL_POWERDOWN              (1 << 12)
 #define ANADIG_PLL5_CTRL_DIV_SELECT		1
+#define ANADIG_PLL3_CTRL_BYPASS         (1 << 16)
+#define ANADIG_PLL3_CTRL_ENABLE         (1 << 13)
+#define ANADIG_PLL3_CTRL_POWERDOWN      (1 << 12)
+#define ANADIG_PLL3_CTRL_DIV_SELECT     (1 << 1)
 #define ANADIG_PLL2_CTRL_ENABLE			(1 << 13)
 #define ANADIG_PLL2_CTRL_POWERDOWN		(1 << 12)
 #define ANADIG_PLL2_CTRL_DIV_SELECT		1
diff --git a/arch/arm/include/asm/arch-vf610/imx-regs.h b/arch/arm/include/asm/arch-vf610/imx-regs.h
index a5908ca..26057fe 100644
--- a/arch/arm/include/asm/arch-vf610/imx-regs.h
+++ b/arch/arm/include/asm/arch-vf610/imx-regs.h
@@ -52,6 +52,7 @@ 
 #define SAI2_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00031000)
 #define SAI3_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00032000)
 #define CRC_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00033000)
+#define USBC0_BASE_ADDR     (AIPS0_BASE_ADDR + 0x00034000)
 #define PDB_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00036000)
 #define PIT_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00037000)
 #define FTM0_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00038000)
@@ -65,6 +66,8 @@ 
 #define QSPI0_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00044000)
 #define IOMUXC_BASE_ADDR	(AIPS0_BASE_ADDR + 0x00048000)
 #define ANADIG_BASE_ADDR	(AIPS0_BASE_ADDR + 0x00050000)
+#define USB_PHY0_BASE_ADDR  (AIPS0_BASE_ADDR + 0x00050800)
+#define USB_PHY1_BASE_ADDR  (AIPS0_BASE_ADDR + 0x00050C00)
 #define SCSC_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00052000)
 #define ASRC_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00060000)
 #define SPDIF_BASE_ADDR		(AIPS0_BASE_ADDR + 0x00061000)
@@ -84,6 +87,7 @@ 
 #define DDR_BASE_ADDR		(AIPS1_BASE_ADDR + 0x0002E000)
 #define ESDHC0_BASE_ADDR	(AIPS1_BASE_ADDR + 0x00031000)
 #define ESDHC1_BASE_ADDR	(AIPS1_BASE_ADDR + 0x00032000)
+#define USBC1_BASE_ADDR     (AIPS1_BASE_ADDR + 0x00034000)
 #define ENET_BASE_ADDR		(AIPS1_BASE_ADDR + 0x00050000)
 #define ENET1_BASE_ADDR		(AIPS1_BASE_ADDR + 0x00051000)
 #define NFC_BASE_ADDR		(AIPS1_BASE_ADDR + 0x00060000)
diff --git a/arch/arm/include/asm/arch-vf610/regs-usbphy.h b/arch/arm/include/asm/arch-vf610/regs-usbphy.h
new file mode 100644
index 0000000..b1b8876
--- /dev/null
+++ b/arch/arm/include/asm/arch-vf610/regs-usbphy.h
@@ -0,0 +1,31 @@ 
+/*
+ * Freescale Vybrid USB PHY Register Definitions
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __REGS_USBPHY_H__
+#define __REGS_USBPHY_H__
+
+#include <asm/imx-common/regs-common.h>
+
+struct vf_usbphy_regs {
+	mxs_reg_32(hw_usbphy_pwd)
+	mxs_reg_32(hw_usbphy_tx)
+	mxs_reg_32(hw_usbphy_rx)
+	mxs_reg_32(hw_usbphy_ctrl)
+	mxs_reg_32(hw_usbphy_status)
+	mxs_reg_32(hw_usbphy_debug)
+	mxs_reg_32(hw_usbphy_debug0_status)
+	mxs_reg_32(hw_usbphy_debug1)
+	mxs_reg_32(hw_usbphy_version)
+	mxs_reg_32(hw_usbphy_ip)
+};
+
+#define USBPHY_CTRL_ENUTMILEVEL2		(1 << 14)
+#define USBPHY_CTRL_ENUTMILEVEL3		(1 << 15)
+#define USBPHY_CTRL_OTG_ID              (1 << 27)
+#define USBPHY_CTRL_CLKGATE				(1 << 30)
+#define USBPHY_CTRL_SFTRST				(1 << 31)
+
+#endif	/* __REGS_USBPHY_H__ */
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index eb6f34b..4bd9321 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -39,6 +39,7 @@  obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o
 obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
 obj-$(CONFIG_USB_EHCI_UNIPHIER) += ehci-uniphier.o
 obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
+obj-$(CONFIG_USB_EHCI_VF) += ehci-vf.o
 obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
 obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
 
diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c
new file mode 100644
index 0000000..cbd3c8c
--- /dev/null
+++ b/drivers/usb/host/ehci-vf.c
@@ -0,0 +1,196 @@ 
+/*
+ * Copyright (c) 2015 Sanchayan Maity <sanchayan.maity@toradex.com>
+ * Copyright (C) 2015 Toradex AG
+ *
+ * Based on ehci-mx6 and ehci-mxs driver
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <errno.h>
+#include <linux/compiler.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/regs-usbphy.h>
+#include <asm/imx-common/iomux-v3.h>
+#include <usb/ehci-fsl.h>
+
+#include "ehci.h"
+
+#define ANADIG_PLL_CTRL_EN_USB_CLKS     (1 << 6)
+
+#define USB_NC_REG_OFFSET				0x00000800
+
+#define UCTRL_OVER_CUR_POL	(1 << 8) /* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS	(1 << 7) /* Disable OTG Overcurrent Detection */
+
+/* USBCMD */
+#define UCMD_RUN_STOP		(1 << 0) /* controller run/stop */
+#define UCMD_RESET			(1 << 1) /* controller reset */
+
+struct ehci_vf_port {
+	uint32_t                 usb_regs;
+	struct vf_usbphy_regs   *phy_regs;
+	struct anadig_reg       *pll;
+	uint32_t                 pll_en_bits;
+};
+
+static const struct ehci_vf_port vf_port[] = {
+	{
+		USBC0_BASE_ADDR,
+		(struct vf_usbphy_regs *)USB_PHY0_BASE_ADDR,
+		(struct anadig_reg *)ANADIG_BASE_ADDR,
+		ANADIG_PLL3_CTRL_ENABLE | ANADIG_PLL3_CTRL_POWERDOWN
+		| ANADIG_PLL_CTRL_EN_USB_CLKS,
+	},
+	{
+		USBC1_BASE_ADDR,
+		(struct vf_usbphy_regs *)USB_PHY1_BASE_ADDR,
+		(struct anadig_reg *)ANADIG_BASE_ADDR,
+		ANADIG_PLL7_CTRL_ENABLE | ANADIG_PLL7_CTRL_POWERDOWN
+		| ANADIG_PLL_CTRL_EN_USB_CLKS,
+	},
+};
+
+static void usb_internal_phy_clock_gate(int index)
+{
+	const struct ehci_vf_port *port;
+
+	port = &vf_port[index];
+	writel(USBPHY_CTRL_CLKGATE, &port->phy_regs->hw_usbphy_ctrl_clr);
+}
+
+static void usb_power_config(int index)
+{
+	u32 reg;
+	const struct ehci_vf_port *port;
+
+	port = &vf_port[index];
+
+	switch (index) {
+	case 0:
+			reg = readl(&port->pll->pll3_ctrl);
+			reg &= ~ANADIG_PLL3_CTRL_BYPASS;
+			writel(reg, &port->pll->pll3_ctrl);
+
+			reg = readl(&port->pll->pll3_ctrl);
+			reg |= port->pll_en_bits;
+			writel(reg, &port->pll->pll3_ctrl);
+		break;
+	case 1:
+			reg = readl(&port->pll->pll7_ctrl);
+			reg &= ~ANADIG_PLL7_CTRL_BYPASS;
+			writel(reg, &port->pll->pll7_ctrl);
+
+			reg = readl(&port->pll->pll7_ctrl);
+			reg |= port->pll_en_bits;
+			writel(reg, &port->pll->pll7_ctrl);
+		break;
+	default:
+		return;
+	}
+}
+
+static void usb_phy_enable(int index, struct usb_ehci *ehci)
+{
+	u32 val;
+	void __iomem *usb_cmd;
+	const struct ehci_vf_port *port;
+
+	port = &vf_port[index];
+	usb_cmd = (void __iomem *)&ehci->usbcmd;
+
+	/* Stop then Reset */
+	val = readl(usb_cmd);
+	val &= ~UCMD_RUN_STOP;
+	writel(val, usb_cmd);
+	while (readl(usb_cmd) & UCMD_RUN_STOP)
+		;
+
+	val = readl(usb_cmd);
+	val |= UCMD_RESET;
+	writel(val, usb_cmd);
+	while (readl(usb_cmd) & UCMD_RESET)
+		;
+
+	/* Reset USBPHY module */
+	writel(USBPHY_CTRL_SFTRST, &port->phy_regs->hw_usbphy_ctrl_set);
+	udelay(10);
+
+	/* Remove CLKGATE and SFTRST */
+	writel(USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST,
+	       &port->phy_regs->hw_usbphy_ctrl_clr);
+	udelay(10);
+
+	/* Power up the PHY */
+	writel(0, &port->phy_regs->hw_usbphy_pwd);
+
+	/* enable FS/LS device */
+	writel(USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3,
+	       &port->phy_regs->hw_usbphy_ctrl_set);
+}
+
+static void usb_oc_config(int index)
+{
+	u32 val;
+	const struct ehci_vf_port *port;
+
+	port = &vf_port[index];
+
+	val = readl(&port->usb_regs + USB_NC_REG_OFFSET);
+	val |= UCTRL_OVER_CUR_POL;
+	writel(val, &port->usb_regs + USB_NC_REG_OFFSET);
+
+	val = readl(&port->usb_regs + USB_NC_REG_OFFSET);
+	val |= UCTRL_OVER_CUR_DIS;
+	writel(val, &port->usb_regs + USB_NC_REG_OFFSET);
+}
+
+int ehci_hcd_init(int index, enum usb_init_type init,
+		struct ehci_hccr **hccr, struct ehci_hcor **hcor)
+{
+	struct usb_ehci *ehci;
+	const struct ehci_vf_port *port;
+
+	if (index >= ARRAY_SIZE(vf_port))
+		return -EINVAL;
+
+	if (init == USB_INIT_DEVICE && index == 1)
+		return -ENODEV;
+	if (init == USB_INIT_HOST && index == 0)
+		return -ENODEV;
+
+	port = &vf_port[index];
+
+	ehci = (struct usb_ehci *)(port->usb_regs);
+
+	usb_power_config(index);
+	usb_oc_config(index);
+	usb_internal_phy_clock_gate(index);
+	usb_phy_enable(index, ehci);
+
+	*hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+	*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+	if (init == USB_INIT_DEVICE) {
+		setbits_le32(&ehci->usbmode, CM_DEVICE);
+		writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc);
+		setbits_le32(&ehci->portsc, USB_EN);
+	} else if (init == USB_INIT_HOST) {
+		setbits_le32(&ehci->usbmode, CM_HOST);
+		writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc);
+		setbits_le32(&ehci->portsc, USB_EN);
+	}
+
+	return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}