summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorYe Li <ye.li@nxp.com>2019-12-11 00:28:17 -0800
committerYe Li <ye.li@nxp.com>2022-04-06 18:03:25 +0800
commit52ec75add16907dff11d479dd8e84adbeced440f (patch)
tree643e6d657e2a6deef426b77e0ea23e39e98f26e0 /drivers
parentc30b8fcfadd34fa376fd8cdf38dee6f6e73e840d (diff)
MLK-23110-1 usb: Decouple the CI_UDC DM gadget driver with EHCI MX6 driver
On 2019.04 SPL, we enabled DM gadget driver for QM/QXP to support dual USB ports. The CI_UDC DM gadget driver will call init function inside EHCI mx6 driver, so when building SPL on iMX8QM/QXP with CI UDC enabled, we have to enable usb host driver as well, and this introduces about more than 40KB size to SPL. Move the common codes to a independent file, so that both host driver and gadget driver can call it, then decouple the host and gadget driver. Note: the patch only applies to ci_udc gadget DM driver. For non-DM gadget driver, it still depends ehci host interfaces. Signed-off-by: Ye Li <ye.li@nxp.com> Acked-by: Peng Fan <peng.fan@nxp.com> (cherry picked from commit 1afed171a77b4c95cd4ea76f29d5a0a6bb199820) (cherry picked from commit 6680499ca4d3a740df5c0aa5a5e66f6d93f827fb) (cherry picked from commit f1fc6faa99e66ceb801503db28b3ce8fc01c4138) (cherry picked from commit 89d47b48f0f598ef080bc99385f831c698ca7c98) (cherry picked from commit 937de0f31667e89e7b4250b233c1fd8da3412d24)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/gadget/ci_udc.c1
-rw-r--r--drivers/usb/host/ehci-mx6.c338
-rw-r--r--drivers/usb/imx/Makefile8
-rw-r--r--drivers/usb/imx/usb-mx6-common.c353
4 files changed, 363 insertions, 337 deletions
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 0aed7a23852..47a71c3df41 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -33,6 +33,7 @@
#include <dm/pinctrl.h>
#include <usb/ci_udc.h>
#include <usb/ehci-ci.h>
+#include <usb/usb_mx6_common.h>
#include "../host/ehci.h"
#include "ci_udc.h"
diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c
index 5e5c03c50c4..1426dc2257d 100644
--- a/drivers/usb/host/ehci-mx6.c
+++ b/drivers/usb/host/ehci-mx6.c
@@ -33,6 +33,7 @@
#include <power-domain.h>
#endif
#include <clk.h>
+#include <usb/usb_mx6_common.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -44,300 +45,13 @@ DECLARE_GLOBAL_DATA_PTR;
#define USB_H1_CTRL_OFFSET 0x04
-#define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000
-#define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000
-
-#define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000
-#define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000
-#define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000
-#define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040
-
#define USBNC_OFFSET 0x200
-#define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */
-#define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */
-#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */
-#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
-
-#define PLL_USB_EN_USB_CLKS_MASK (0x01 << 6)
-#define PLL_USB_PWR_MASK (0x01 << 12)
-#define PLL_USB_ENABLE_MASK (0x01 << 13)
-#define PLL_USB_BYPASS_MASK (0x01 << 16)
-#define PLL_USB_REG_ENABLE_MASK (0x01 << 21)
-#define PLL_USB_DIV_SEL_MASK (0x07 << 22)
-#define PLL_USB_LOCK_MASK (0x01 << 31)
-
-/* USBCMD */
-#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
-#define UCMD_RESET (1 << 1) /* controller reset */
/* If this is not defined, assume MX6/MX7/MX8M SoC default */
#ifndef CONFIG_MXC_USB_PORTSC
#define CONFIG_MXC_USB_PORTSC (PORT_PTS_UTMI | PORT_PTS_PTW)
#endif
-/* Base address for this IP block is 0x02184800 */
-struct usbnc_regs {
- u32 ctrl[4]; /* otg/host1-3 */
- u32 uh2_hsic_ctrl;
- u32 uh3_hsic_ctrl;
- u32 otg_phy_ctrl_0;
- u32 uh1_phy_ctrl_0;
- u32 reserve1[4];
- u32 phy_cfg1;
- u32 phy_cfg2;
- u32 reserve2;
- u32 phy_status;
- u32 reserve3[4];
- u32 adp_cfg1;
- u32 adp_cfg2;
- u32 adp_status;
-};
-
-struct ehci_mx6_phy_data {
- void __iomem *phy_addr;
- void __iomem *misc_addr;
- void __iomem *anatop_addr;
-};
-
-#if defined(CONFIG_MX6) && !CONFIG_IS_ENABLED(PHY)
-static void usb_power_config_mx6(void __iomem *anatop_base,
- int anatop_bits_index)
-{
- struct anatop_regs __iomem *anatop = (struct anatop_regs __iomem *)anatop_base;
- void __iomem *chrg_detect;
- void __iomem *pll_480_ctrl_clr;
- void __iomem *pll_480_ctrl_set;
-
- if (!is_mx6())
- return;
-
- switch (anatop_bits_index) {
- case 0:
- chrg_detect = &anatop->usb1_chrg_detect;
- pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr;
- pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set;
- break;
- case 1:
- chrg_detect = &anatop->usb2_chrg_detect;
- pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr;
- pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set;
- break;
- default:
- return;
- }
- /*
- * Some phy and power's special controls
- * 1. The external charger detector needs to be disabled
- * or the signal at DP will be poor
- * 2. The PLL's power and output to usb
- * is totally controlled by IC, so the Software only needs
- * to enable them at initializtion.
- */
- writel(ANADIG_USB2_CHRG_DETECT_EN_B |
- ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
- chrg_detect);
-
- writel(ANADIG_USB2_PLL_480_CTRL_BYPASS,
- pll_480_ctrl_clr);
-
- writel(ANADIG_USB2_PLL_480_CTRL_ENABLE |
- ANADIG_USB2_PLL_480_CTRL_POWER |
- ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
- pll_480_ctrl_set);
-}
-#else
-static void __maybe_unused
-usb_power_config_mx6(void __iomem *anatop_base, int anatop_bits_index) { }
-#endif
-
-#if defined(CONFIG_USB_EHCI_MX7) && !CONFIG_IS_ENABLED(PHY)
-static void usb_power_config_mx7(void __iomem *usbnc_base)
-{
- struct usbnc_regs __iomem *usbnc = (struct usbnc_regs __iomem *)usbnc_base;
- void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2);
-
- if (!is_mx7())
- return;
-
- /*
- * Clear the ACAENB to enable usb_otg_id detection,
- * otherwise it is the ACA detection enabled.
- */
- clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB);
-}
-#else
-static void __maybe_unused
-usb_power_config_mx7(void __iomem *usbnc_base) { }
-#endif
-
-#if defined(CONFIG_MX7ULP) && !CONFIG_IS_ENABLED(PHY)
-static void usb_power_config_mx7ulp(void __iomem *usbphy_base)
-{
- struct usbphy_regs __iomem *usbphy = (struct usbphy_regs __iomem *)usbphy_base;
-
- if (!is_mx7ulp())
- return;
-
- writel(ANADIG_USB2_CHRG_DETECT_EN_B |
- ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
- &usbphy->usb1_chrg_detect);
-
- scg_enable_usb_pll(true);
-}
-#else
-static void __maybe_unused
-usb_power_config_mx7ulp(void __iomem *usbphy_base) { }
-#endif
-
-#if defined(CONFIG_IMX8)
-static void usb_power_config_imx8(void __iomem *usbphy_base)
-{
- struct usbphy_regs __iomem *usbphy = (struct usbphy_regs __iomem *)usbphy_base;
-
- if (!is_imx8())
- return;
-
- int timeout = 1000000;
-
- writel(ANADIG_USB2_CHRG_DETECT_EN_B |
- ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
- &usbphy->usb1_chrg_detect);
-
- if (!(readl(&usbphy->usb1_pll_480_ctrl) & PLL_USB_LOCK_MASK)) {
-
- /* Enable the regulator first */
- writel(PLL_USB_REG_ENABLE_MASK,
- &usbphy->usb1_pll_480_ctrl_set);
-
- /* Wait at least 25us */
- udelay(25);
-
- /* Enable the power */
- writel(PLL_USB_PWR_MASK, &usbphy->usb1_pll_480_ctrl_set);
-
- /* Wait lock */
- while (timeout--) {
- if (readl(&usbphy->usb1_pll_480_ctrl) &
- PLL_USB_LOCK_MASK)
- break;
- udelay(10);
- }
-
- if (timeout <= 0) {
- /* If timeout, we power down the pll */
- writel(PLL_USB_PWR_MASK,
- &usbphy->usb1_pll_480_ctrl_clr);
- return;
- }
- }
-
- /* Clear the bypass */
- writel(PLL_USB_BYPASS_MASK, &usbphy->usb1_pll_480_ctrl_clr);
-
- /* Enable the PLL clock out to USB */
- writel((PLL_USB_EN_USB_CLKS_MASK | PLL_USB_ENABLE_MASK),
- &usbphy->usb1_pll_480_ctrl_set);
-}
-#else
-static void __maybe_unused
-usb_power_config_imx8(void __iomem *usbphy_base) { }
-#endif
-
-
-#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMXRT) || defined(CONFIG_IMX8)
-static const ulong phy_bases[] = {
- USB_PHY0_BASE_ADDR,
-#if defined(USB_PHY1_BASE_ADDR)
- USB_PHY1_BASE_ADDR,
-#endif
-};
-
-#if !CONFIG_IS_ENABLED(PHY)
-static void usb_internal_phy_clock_gate(void __iomem *phy_reg, int on)
-{
- if (phy_reg == NULL)
- return;
-
- phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
- writel(USBPHY_CTRL_CLKGATE, phy_reg);
-}
-
-/* Return 0 : host node, <>0 : device mode */
-static int usb_phy_enable(struct usb_ehci *ehci, void __iomem *phy_reg)
-{
- void __iomem *phy_ctrl;
- void __iomem *usb_cmd;
- int ret;
-
- if (phy_reg == NULL)
- return -EINVAL;
-
- phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
- usb_cmd = (void __iomem *)&ehci->usbcmd;
-
- /* Stop then Reset */
- clrbits_le32(usb_cmd, UCMD_RUN_STOP);
- ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false);
- if (ret)
- return ret;
-
- setbits_le32(usb_cmd, UCMD_RESET);
- ret = wait_for_bit_le32(usb_cmd, UCMD_RESET, false, 10000, false);
- if (ret)
- return ret;
-
- /* Reset USBPHY module */
- setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST);
- udelay(10);
-
- /* Remove CLKGATE and SFTRST */
- clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST);
- udelay(10);
-
- /* Power up the PHY */
- writel(0, phy_reg + USBPHY_PWD);
- /* enable FS/LS device */
- setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 |
- USBPHY_CTRL_ENUTMILEVEL3);
-
- return 0;
-}
-#endif
-
-int usb_phy_mode(int port)
-{
- void __iomem *phy_reg;
- void __iomem *phy_ctrl;
- u32 val;
-
- phy_reg = (void __iomem *)phy_bases[port];
- phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
-
- val = readl(phy_ctrl);
-
- if (val & USBPHY_CTRL_OTG_ID)
- return USB_INIT_DEVICE;
- else
- return USB_INIT_HOST;
-}
-
-#elif defined(CONFIG_USB_EHCI_MX7)
-int usb_phy_mode(int port)
-{
- struct usbnc_regs *usbnc = (struct usbnc_regs *)(ulong)(USB_BASE_ADDR +
- (0x10000 * port) + USBNC_OFFSET);
- void __iomem *status = (void __iomem *)(&usbnc->phy_status);
- u32 val;
-
- val = readl(status);
-
- if (val & USBNC_PHYSTATUS_ID_DIG)
- return USB_INIT_DEVICE;
- else
- return USB_INIT_HOST;
-}
-#endif
-
static void ehci_mx6_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
uint32_t *reg)
{
@@ -357,56 +71,6 @@ static void ehci_mx6_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
*reg = ehci_readl(status_reg);
}
-/* Should be done in the MXS PHY driver */
-static void usb_oc_config(void __iomem *usbnc_base, int index)
-{
- struct usbnc_regs __iomem *usbnc = (struct usbnc_regs __iomem *)usbnc_base;
-#if defined(CONFIG_MX6)
- void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]);
-#elif defined(CONFIG_USB_EHCI_MX7) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMX8)
- void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[0]);
-#endif
-
-#if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2
- /* mx6qarm2 seems to required a different setting*/
- clrbits_le32(ctrl, UCTRL_OVER_CUR_POL);
-#else
- setbits_le32(ctrl, UCTRL_OVER_CUR_POL);
-#endif
-
- setbits_le32(ctrl, UCTRL_OVER_CUR_DIS);
-
- /* Set power polarity to high active */
-#ifdef CONFIG_MXC_USB_OTG_HACTIVE
- setbits_le32(ctrl, UCTRL_PWR_POL);
-#else
- clrbits_le32(ctrl, UCTRL_PWR_POL);
-#endif
-}
-
-void ehci_mx6_phy_init(struct usb_ehci *ehci, struct ehci_mx6_phy_data *phy_data, int index)
-{
- u32 portsc;
-
- portsc = readl(&ehci->portsc);
- if (portsc & PORT_PTS_PHCD) {
- debug("suspended: portsc %x, enabled it.\n", portsc);
- clrbits_le32(&ehci->portsc, PORT_PTS_PHCD);
- }
-
- usb_power_config_mx6(phy_data->anatop_addr, index);
- usb_power_config_mx7(phy_data->misc_addr);
- usb_power_config_mx7ulp(phy_data->phy_addr);
- usb_power_config_imx8(phy_data->phy_addr);
-
- usb_oc_config(phy_data->misc_addr, index);
-
-#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMXRT) || defined(CONFIG_IMX8)
- usb_internal_phy_clock_gate(phy_data->phy_addr, 1);
- usb_phy_enable(ehci, phy_data->phy_addr);
-#endif
-}
-
#if !CONFIG_IS_ENABLED(DM_USB)
/**
* board_usb_phy_mode - override usb phy mode
diff --git a/drivers/usb/imx/Makefile b/drivers/usb/imx/Makefile
new file mode 100644
index 00000000000..30c06b7bf83
--- /dev/null
+++ b/drivers/usb/imx/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright 2019 NXP
+#
+
+obj-$(CONFIG_USB_EHCI_MX6) += usb-mx6-common.o
+obj-$(CONFIG_USB_EHCI_MX7) += usb-mx6-common.o
+obj-$(CONFIG_CI_UDC) += usb-mx6-common.o
diff --git a/drivers/usb/imx/usb-mx6-common.c b/drivers/usb/imx/usb-mx6-common.c
new file mode 100644
index 00000000000..e036cf14686
--- /dev/null
+++ b/drivers/usb/imx/usb-mx6-common.c
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ *
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <errno.h>
+#include <wait_bit.h>
+#include <linux/compiler.h>
+#include <usb/ehci-ci.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/regs-usbphy.h>
+#include <asm/mach-imx/sys_proto.h>
+#include <asm/mach-types.h>
+#include <asm/arch/sys_proto.h>
+#include <usb/usb_mx6_common.h>
+
+#define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000
+#define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000
+
+#define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000
+#define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000
+#define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000
+#define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040
+
+#define USBNC_OFFSET 0x200
+#define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */
+#define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */
+#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */
+#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
+
+#define PLL_USB_EN_USB_CLKS_MASK (0x01 << 6)
+#define PLL_USB_PWR_MASK (0x01 << 12)
+#define PLL_USB_ENABLE_MASK (0x01 << 13)
+#define PLL_USB_BYPASS_MASK (0x01 << 16)
+#define PLL_USB_REG_ENABLE_MASK (0x01 << 21)
+#define PLL_USB_DIV_SEL_MASK (0x07 << 22)
+#define PLL_USB_LOCK_MASK (0x01 << 31)
+
+/* USBCMD */
+#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
+#define UCMD_RESET (1 << 1) /* controller reset */
+
+/* Base address for this IP block is 0x02184800 */
+struct usbnc_regs {
+ u32 ctrl[4]; /* otg/host1-3 */
+ u32 uh2_hsic_ctrl;
+ u32 uh3_hsic_ctrl;
+ u32 otg_phy_ctrl_0;
+ u32 uh1_phy_ctrl_0;
+ u32 reserve1[4];
+ u32 phy_cfg1;
+ u32 phy_cfg2;
+ u32 reserve2;
+ u32 phy_status;
+ u32 reserve3[4];
+ u32 adp_cfg1;
+ u32 adp_cfg2;
+ u32 adp_status;
+};
+
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMXRT) || defined(CONFIG_IMX8)
+static const ulong phy_bases[] = {
+ USB_PHY0_BASE_ADDR,
+#if defined(USB_PHY1_BASE_ADDR)
+ USB_PHY1_BASE_ADDR,
+#endif
+};
+
+int usb_phy_mode(int port)
+{
+ void __iomem *phy_reg;
+ void __iomem *phy_ctrl;
+ u32 val;
+
+ phy_reg = (void __iomem *)phy_bases[port];
+ phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
+
+ val = readl(phy_ctrl);
+
+ if (val & USBPHY_CTRL_OTG_ID)
+ return USB_INIT_DEVICE;
+ else
+ return USB_INIT_HOST;
+}
+
+static void usb_internal_phy_clock_gate(void __iomem *phy_reg, int on)
+{
+ if (phy_reg == NULL)
+ return;
+
+ phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
+ writel(USBPHY_CTRL_CLKGATE, phy_reg);
+}
+
+/* Return 0 : host node, <>0 : device mode */
+static int usb_phy_enable(struct usb_ehci *ehci, void __iomem *phy_reg)
+{
+ void __iomem *phy_ctrl;
+ void __iomem *usb_cmd;
+ int ret;
+
+ if (phy_reg == NULL)
+ return -EINVAL;
+
+ phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
+ usb_cmd = (void __iomem *)&ehci->usbcmd;
+
+ /* Stop then Reset */
+ clrbits_le32(usb_cmd, UCMD_RUN_STOP);
+ ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false);
+ if (ret)
+ return ret;
+
+ setbits_le32(usb_cmd, UCMD_RESET);
+ ret = wait_for_bit_le32(usb_cmd, UCMD_RESET, false, 10000, false);
+ if (ret)
+ return ret;
+
+ /* Reset USBPHY module */
+ setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST);
+ udelay(10);
+
+ /* Remove CLKGATE and SFTRST */
+ clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST);
+ udelay(10);
+
+ /* Power up the PHY */
+ writel(0, phy_reg + USBPHY_PWD);
+ /* enable FS/LS device */
+ setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 |
+ USBPHY_CTRL_ENUTMILEVEL3);
+
+ return 0;
+}
+#elif defined(CONFIG_USB_EHCI_MX7)
+int usb_phy_mode(int port)
+{
+ struct usbnc_regs *usbnc = (struct usbnc_regs *)(ulong)(USB_BASE_ADDR +
+ (0x10000 * port) + USBNC_OFFSET);
+ void __iomem *status = (void __iomem *)(&usbnc->phy_status);
+ u32 val;
+
+ val = readl(status);
+
+ if (val & USBNC_PHYSTATUS_ID_DIG)
+ return USB_INIT_DEVICE;
+ else
+ return USB_INIT_HOST;
+}
+#endif
+
+#if defined(CONFIG_MX6) && !CONFIG_IS_ENABLED(PHY)
+static void usb_power_config_mx6(void __iomem *anatop_base,
+ int anatop_bits_index)
+{
+ struct anatop_regs __iomem *anatop = (struct anatop_regs __iomem *)anatop_base;
+ void __iomem *chrg_detect;
+ void __iomem *pll_480_ctrl_clr;
+ void __iomem *pll_480_ctrl_set;
+
+ if (!is_mx6())
+ return;
+
+ switch (anatop_bits_index) {
+ case 0:
+ chrg_detect = &anatop->usb1_chrg_detect;
+ pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr;
+ pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set;
+ break;
+ case 1:
+ chrg_detect = &anatop->usb2_chrg_detect;
+ pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr;
+ pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set;
+ break;
+ default:
+ return;
+ }
+ /*
+ * Some phy and power's special controls
+ * 1. The external charger detector needs to be disabled
+ * or the signal at DP will be poor
+ * 2. The PLL's power and output to usb
+ * is totally controlled by IC, so the Software only needs
+ * to enable them at initializtion.
+ */
+ writel(ANADIG_USB2_CHRG_DETECT_EN_B |
+ ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
+ chrg_detect);
+
+ writel(ANADIG_USB2_PLL_480_CTRL_BYPASS,
+ pll_480_ctrl_clr);
+
+ writel(ANADIG_USB2_PLL_480_CTRL_ENABLE |
+ ANADIG_USB2_PLL_480_CTRL_POWER |
+ ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
+ pll_480_ctrl_set);
+}
+#else
+static void __maybe_unused
+usb_power_config_mx6(void __iomem *anatop_base, int anatop_bits_index) { }
+#endif
+
+#if defined(CONFIG_USB_EHCI_MX7) && !CONFIG_IS_ENABLED(PHY)
+static void usb_power_config_mx7(void __iomem *usbnc_base)
+{
+ struct usbnc_regs __iomem *usbnc = (struct usbnc_regs __iomem *)usbnc_base;
+ void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2);
+
+ if (!is_mx7())
+ return;
+
+ /*
+ * Clear the ACAENB to enable usb_otg_id detection,
+ * otherwise it is the ACA detection enabled.
+ */
+ clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB);
+}
+#else
+static void __maybe_unused
+usb_power_config_mx7(void __iomem *usbnc_base) { }
+#endif
+
+#if defined(CONFIG_MX7ULP) && !CONFIG_IS_ENABLED(PHY)
+static void usb_power_config_mx7ulp(void __iomem *usbphy_base)
+{
+ struct usbphy_regs __iomem *usbphy = (struct usbphy_regs __iomem *)usbphy_base;
+
+ if (!is_mx7ulp())
+ return;
+
+ writel(ANADIG_USB2_CHRG_DETECT_EN_B |
+ ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
+ &usbphy->usb1_chrg_detect);
+
+ scg_enable_usb_pll(true);
+}
+#else
+static void __maybe_unused
+usb_power_config_mx7ulp(void __iomem *usbphy_base) { }
+#endif
+
+#if defined(CONFIG_IMX8)
+static void usb_power_config_imx8(void __iomem *usbphy_base)
+{
+ struct usbphy_regs __iomem *usbphy = (struct usbphy_regs __iomem *)usbphy_base;
+
+ if (!is_imx8())
+ return;
+
+ int timeout = 1000000;
+
+ writel(ANADIG_USB2_CHRG_DETECT_EN_B |
+ ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
+ &usbphy->usb1_chrg_detect);
+
+ if (!(readl(&usbphy->usb1_pll_480_ctrl) & PLL_USB_LOCK_MASK)) {
+
+ /* Enable the regulator first */
+ writel(PLL_USB_REG_ENABLE_MASK,
+ &usbphy->usb1_pll_480_ctrl_set);
+
+ /* Wait at least 25us */
+ udelay(25);
+
+ /* Enable the power */
+ writel(PLL_USB_PWR_MASK, &usbphy->usb1_pll_480_ctrl_set);
+
+ /* Wait lock */
+ while (timeout--) {
+ if (readl(&usbphy->usb1_pll_480_ctrl) &
+ PLL_USB_LOCK_MASK)
+ break;
+ udelay(10);
+ }
+
+ if (timeout <= 0) {
+ /* If timeout, we power down the pll */
+ writel(PLL_USB_PWR_MASK,
+ &usbphy->usb1_pll_480_ctrl_clr);
+ return;
+ }
+ }
+
+ /* Clear the bypass */
+ writel(PLL_USB_BYPASS_MASK, &usbphy->usb1_pll_480_ctrl_clr);
+
+ /* Enable the PLL clock out to USB */
+ writel((PLL_USB_EN_USB_CLKS_MASK | PLL_USB_ENABLE_MASK),
+ &usbphy->usb1_pll_480_ctrl_set);
+}
+#else
+static void __maybe_unused
+usb_power_config_imx8(void __iomem *usbphy_base) { }
+#endif
+
+
+/* Should be done in the MXS PHY driver */
+static void usb_oc_config(void __iomem *usbnc_base, int index)
+{
+ struct usbnc_regs __iomem *usbnc = (struct usbnc_regs __iomem *)usbnc_base;
+#if defined(CONFIG_MX6)
+ void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]);
+#elif defined(CONFIG_USB_EHCI_MX7) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMX8)
+ void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[0]);
+#endif
+
+#if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2
+ /* mx6qarm2 seems to required a different setting*/
+ clrbits_le32(ctrl, UCTRL_OVER_CUR_POL);
+#else
+ setbits_le32(ctrl, UCTRL_OVER_CUR_POL);
+#endif
+
+ setbits_le32(ctrl, UCTRL_OVER_CUR_DIS);
+
+ /* Set power polarity to high active */
+#ifdef CONFIG_MXC_USB_OTG_HACTIVE
+ setbits_le32(ctrl, UCTRL_PWR_POL);
+#else
+ clrbits_le32(ctrl, UCTRL_PWR_POL);
+#endif
+}
+
+void ehci_mx6_phy_init(struct usb_ehci *ehci, struct ehci_mx6_phy_data *phy_data, int index)
+{
+ u32 portsc;
+
+ portsc = readl(&ehci->portsc);
+ if (portsc & PORT_PTS_PHCD) {
+ debug("suspended: portsc %x, enabled it.\n", portsc);
+ clrbits_le32(&ehci->portsc, PORT_PTS_PHCD);
+ }
+
+ usb_power_config_mx6(phy_data->anatop_addr, index);
+ usb_power_config_mx7(phy_data->misc_addr);
+ usb_power_config_mx7ulp(phy_data->phy_addr);
+ usb_power_config_imx8(phy_data->phy_addr);
+
+ usb_oc_config(phy_data->misc_addr, index);
+
+#if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP) || defined(CONFIG_IMXRT) || defined(CONFIG_IMX8)
+ usb_internal_phy_clock_gate(phy_data->phy_addr, 1);
+ usb_phy_enable(ehci, phy_data->phy_addr);
+#endif
+}