13f467529SWolfgang Grandegger /*
23f467529SWolfgang Grandegger * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
33f467529SWolfgang Grandegger * Copyright (C) 2010 Freescale Semiconductor, Inc.
43f467529SWolfgang Grandegger *
51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+
63f467529SWolfgang Grandegger */
73f467529SWolfgang Grandegger
83f467529SWolfgang Grandegger #include <common.h>
93f467529SWolfgang Grandegger #include <usb.h>
103f467529SWolfgang Grandegger #include <errno.h>
118c25c259SMateusz Kulikowski #include <wait_bit.h>
123f467529SWolfgang Grandegger #include <linux/compiler.h>
13e162c6b1SMateusz Kulikowski #include <usb/ehci-ci.h>
143f467529SWolfgang Grandegger #include <asm/io.h>
153f467529SWolfgang Grandegger #include <asm/arch/imx-regs.h>
163f467529SWolfgang Grandegger #include <asm/arch/clock.h>
17552a848eSStefano Babic #include <asm/mach-imx/iomux-v3.h>
18552a848eSStefano Babic #include <asm/mach-imx/sys_proto.h>
19bb42fb4fSPeng Fan #include <dm.h>
20c62db35dSSimon Glass #include <asm/mach-types.h>
21fcf9f9f9SPeng Fan #include <power/regulator.h>
220457b2cdSAdam Ford #include <linux/usb/otg.h>
233f467529SWolfgang Grandegger
243f467529SWolfgang Grandegger #include "ehci.h"
253f467529SWolfgang Grandegger
26cccbddc3SPeng Fan DECLARE_GLOBAL_DATA_PTR;
27cccbddc3SPeng Fan
283f467529SWolfgang Grandegger #define USB_OTGREGS_OFFSET 0x000
293f467529SWolfgang Grandegger #define USB_H1REGS_OFFSET 0x200
303f467529SWolfgang Grandegger #define USB_H2REGS_OFFSET 0x400
313f467529SWolfgang Grandegger #define USB_H3REGS_OFFSET 0x600
323f467529SWolfgang Grandegger #define USB_OTHERREGS_OFFSET 0x800
333f467529SWolfgang Grandegger
343f467529SWolfgang Grandegger #define USB_H1_CTRL_OFFSET 0x04
353f467529SWolfgang Grandegger
363f467529SWolfgang Grandegger #define USBPHY_CTRL 0x00000030
373f467529SWolfgang Grandegger #define USBPHY_CTRL_SET 0x00000034
383f467529SWolfgang Grandegger #define USBPHY_CTRL_CLR 0x00000038
393f467529SWolfgang Grandegger #define USBPHY_CTRL_TOG 0x0000003c
403f467529SWolfgang Grandegger
413f467529SWolfgang Grandegger #define USBPHY_PWD 0x00000000
423f467529SWolfgang Grandegger #define USBPHY_CTRL_SFTRST 0x80000000
433f467529SWolfgang Grandegger #define USBPHY_CTRL_CLKGATE 0x40000000
443f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL3 0x00008000
453f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL2 0x00004000
46d1a52860STroy Kisky #define USBPHY_CTRL_OTG_ID 0x08000000
473f467529SWolfgang Grandegger
483f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000
493f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000
503f467529SWolfgang Grandegger
513f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000
523f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000
533f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000
543f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040
553f467529SWolfgang Grandegger
5635554fc9SAdrian Alonso #define USBNC_OFFSET 0x200
57cccbddc3SPeng Fan #define USBNC_PHY_STATUS_OFFSET 0x23C
5835554fc9SAdrian Alonso #define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */
5935554fc9SAdrian Alonso #define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */
609a88180bSStefan Agner #define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */
613f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */
623f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
633f467529SWolfgang Grandegger
643f467529SWolfgang Grandegger /* USBCMD */
653f467529SWolfgang Grandegger #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
663f467529SWolfgang Grandegger #define UCMD_RESET (1 << 1) /* controller reset */
673f467529SWolfgang Grandegger
6848afbe4fSYe Li #if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP)
69d1a52860STroy Kisky static const unsigned phy_bases[] = {
70d1a52860STroy Kisky USB_PHY0_BASE_ADDR,
7148afbe4fSYe Li #if defined(USB_PHY1_BASE_ADDR)
72d1a52860STroy Kisky USB_PHY1_BASE_ADDR,
7348afbe4fSYe Li #endif
74d1a52860STroy Kisky };
753f467529SWolfgang Grandegger
usb_internal_phy_clock_gate(int index,int on)76d1a52860STroy Kisky static void usb_internal_phy_clock_gate(int index, int on)
77d1a52860STroy Kisky {
78d1a52860STroy Kisky void __iomem *phy_reg;
79d1a52860STroy Kisky
80d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases))
81d1a52860STroy Kisky return;
82d1a52860STroy Kisky
83d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index];
843f467529SWolfgang Grandegger phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
85e38ff30aSAdrian Alonso writel(USBPHY_CTRL_CLKGATE, phy_reg);
863f467529SWolfgang Grandegger }
873f467529SWolfgang Grandegger
usb_power_config(int index)88d1a52860STroy Kisky static void usb_power_config(int index)
893f467529SWolfgang Grandegger {
9048afbe4fSYe Li #if defined(CONFIG_MX7ULP)
9148afbe4fSYe Li struct usbphy_regs __iomem *usbphy =
9248afbe4fSYe Li (struct usbphy_regs __iomem *)USB_PHY0_BASE_ADDR;
9348afbe4fSYe Li
9448afbe4fSYe Li if (index > 0)
9548afbe4fSYe Li return;
9648afbe4fSYe Li
9748afbe4fSYe Li writel(ANADIG_USB2_CHRG_DETECT_EN_B |
9848afbe4fSYe Li ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
9948afbe4fSYe Li &usbphy->usb1_chrg_detect);
10048afbe4fSYe Li
10148afbe4fSYe Li scg_enable_usb_pll(true);
10248afbe4fSYe Li
10348afbe4fSYe Li #else
1043f29d962SWolfgang Grandegger struct anatop_regs __iomem *anatop =
1053f29d962SWolfgang Grandegger (struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
106d1a52860STroy Kisky void __iomem *chrg_detect;
107d1a52860STroy Kisky void __iomem *pll_480_ctrl_clr;
108d1a52860STroy Kisky void __iomem *pll_480_ctrl_set;
109d1a52860STroy Kisky
110d1a52860STroy Kisky switch (index) {
111d1a52860STroy Kisky case 0:
112d1a52860STroy Kisky chrg_detect = &anatop->usb1_chrg_detect;
113d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr;
114d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set;
115d1a52860STroy Kisky break;
116d1a52860STroy Kisky case 1:
117d1a52860STroy Kisky chrg_detect = &anatop->usb2_chrg_detect;
118d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr;
119d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set;
120d1a52860STroy Kisky break;
121d1a52860STroy Kisky default:
122d1a52860STroy Kisky return;
123d1a52860STroy Kisky }
1243f467529SWolfgang Grandegger /*
125d1a52860STroy Kisky * Some phy and power's special controls
1263f467529SWolfgang Grandegger * 1. The external charger detector needs to be disabled
1273f467529SWolfgang Grandegger * or the signal at DP will be poor
128d1a52860STroy Kisky * 2. The PLL's power and output to usb
1293f467529SWolfgang Grandegger * is totally controlled by IC, so the Software only needs
1303f467529SWolfgang Grandegger * to enable them at initializtion.
1313f467529SWolfgang Grandegger */
132e38ff30aSAdrian Alonso writel(ANADIG_USB2_CHRG_DETECT_EN_B |
1333f467529SWolfgang Grandegger ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
134d1a52860STroy Kisky chrg_detect);
1353f467529SWolfgang Grandegger
136e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_BYPASS,
137d1a52860STroy Kisky pll_480_ctrl_clr);
1383f467529SWolfgang Grandegger
139e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_ENABLE |
1403f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_POWER |
1413f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
142d1a52860STroy Kisky pll_480_ctrl_set);
14348afbe4fSYe Li
14448afbe4fSYe Li #endif
1453f467529SWolfgang Grandegger }
1463f467529SWolfgang Grandegger
147d1a52860STroy Kisky /* Return 0 : host node, <>0 : device mode */
usb_phy_enable(int index,struct usb_ehci * ehci)148d1a52860STroy Kisky static int usb_phy_enable(int index, struct usb_ehci *ehci)
1493f467529SWolfgang Grandegger {
150d1a52860STroy Kisky void __iomem *phy_reg;
151d1a52860STroy Kisky void __iomem *phy_ctrl;
152d1a52860STroy Kisky void __iomem *usb_cmd;
153f0c89d54SAdrian Alonso int ret;
1543f467529SWolfgang Grandegger
155d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases))
156d1a52860STroy Kisky return 0;
157d1a52860STroy Kisky
158d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index];
159d1a52860STroy Kisky phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
160d1a52860STroy Kisky usb_cmd = (void __iomem *)&ehci->usbcmd;
161d1a52860STroy Kisky
1623f467529SWolfgang Grandegger /* Stop then Reset */
163e38ff30aSAdrian Alonso clrbits_le32(usb_cmd, UCMD_RUN_STOP);
164b491b498SJon Lin ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false);
165f0c89d54SAdrian Alonso if (ret)
166f0c89d54SAdrian Alonso return ret;
1673f467529SWolfgang Grandegger
168e38ff30aSAdrian Alonso setbits_le32(usb_cmd, UCMD_RESET);
169b491b498SJon Lin ret = wait_for_bit_le32(usb_cmd, UCMD_RESET, false, 10000, false);
170f0c89d54SAdrian Alonso if (ret)
171f0c89d54SAdrian Alonso return ret;
1723f467529SWolfgang Grandegger
1733f467529SWolfgang Grandegger /* Reset USBPHY module */
174e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST);
1753f467529SWolfgang Grandegger udelay(10);
1763f467529SWolfgang Grandegger
1773f467529SWolfgang Grandegger /* Remove CLKGATE and SFTRST */
178e38ff30aSAdrian Alonso clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST);
1793f467529SWolfgang Grandegger udelay(10);
1803f467529SWolfgang Grandegger
1813f467529SWolfgang Grandegger /* Power up the PHY */
182e38ff30aSAdrian Alonso writel(0, phy_reg + USBPHY_PWD);
1833f467529SWolfgang Grandegger /* enable FS/LS device */
184e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 |
185e38ff30aSAdrian Alonso USBPHY_CTRL_ENUTMILEVEL3);
1863f467529SWolfgang Grandegger
187229dbba9SPeng Fan return 0;
1883f467529SWolfgang Grandegger }
1893f467529SWolfgang Grandegger
usb_phy_mode(int port)190229dbba9SPeng Fan int usb_phy_mode(int port)
191229dbba9SPeng Fan {
192229dbba9SPeng Fan void __iomem *phy_reg;
193229dbba9SPeng Fan void __iomem *phy_ctrl;
194229dbba9SPeng Fan u32 val;
195229dbba9SPeng Fan
196229dbba9SPeng Fan phy_reg = (void __iomem *)phy_bases[port];
197229dbba9SPeng Fan phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
198229dbba9SPeng Fan
199e38ff30aSAdrian Alonso val = readl(phy_ctrl);
200229dbba9SPeng Fan
201229dbba9SPeng Fan if (val & USBPHY_CTRL_OTG_ID)
202229dbba9SPeng Fan return USB_INIT_DEVICE;
203229dbba9SPeng Fan else
204229dbba9SPeng Fan return USB_INIT_HOST;
205229dbba9SPeng Fan }
206229dbba9SPeng Fan
20748afbe4fSYe Li #if defined(CONFIG_MX7ULP)
20848afbe4fSYe Li struct usbnc_regs {
20948afbe4fSYe Li u32 ctrl1;
21048afbe4fSYe Li u32 ctrl2;
21148afbe4fSYe Li u32 reserve0[2];
21248afbe4fSYe Li u32 hsic_ctrl;
21348afbe4fSYe Li };
21448afbe4fSYe Li #else
21535554fc9SAdrian Alonso /* Base address for this IP block is 0x02184800 */
21635554fc9SAdrian Alonso struct usbnc_regs {
21735554fc9SAdrian Alonso u32 ctrl[4]; /* otg/host1-3 */
21835554fc9SAdrian Alonso u32 uh2_hsic_ctrl;
21935554fc9SAdrian Alonso u32 uh3_hsic_ctrl;
22035554fc9SAdrian Alonso u32 otg_phy_ctrl_0;
22135554fc9SAdrian Alonso u32 uh1_phy_ctrl_0;
22235554fc9SAdrian Alonso };
22348afbe4fSYe Li #endif
22448afbe4fSYe Li
22535554fc9SAdrian Alonso #elif defined(CONFIG_MX7)
22635554fc9SAdrian Alonso struct usbnc_regs {
22735554fc9SAdrian Alonso u32 ctrl1;
22835554fc9SAdrian Alonso u32 ctrl2;
22935554fc9SAdrian Alonso u32 reserve1[10];
23035554fc9SAdrian Alonso u32 phy_cfg1;
23135554fc9SAdrian Alonso u32 phy_cfg2;
232429ff447SPeng Fan u32 reserve2;
23335554fc9SAdrian Alonso u32 phy_status;
234429ff447SPeng Fan u32 reserve3[4];
23535554fc9SAdrian Alonso u32 adp_cfg1;
23635554fc9SAdrian Alonso u32 adp_cfg2;
23735554fc9SAdrian Alonso u32 adp_status;
23835554fc9SAdrian Alonso };
23935554fc9SAdrian Alonso
usb_power_config(int index)24035554fc9SAdrian Alonso static void usb_power_config(int index)
24135554fc9SAdrian Alonso {
24235554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
24335554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET);
24435554fc9SAdrian Alonso void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2);
24535554fc9SAdrian Alonso
24657de41e9SPeng Fan /*
24757de41e9SPeng Fan * Clear the ACAENB to enable usb_otg_id detection,
24857de41e9SPeng Fan * otherwise it is the ACA detection enabled.
24957de41e9SPeng Fan */
25057de41e9SPeng Fan clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB);
25135554fc9SAdrian Alonso }
25235554fc9SAdrian Alonso
usb_phy_mode(int port)25335554fc9SAdrian Alonso int usb_phy_mode(int port)
25435554fc9SAdrian Alonso {
25535554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
25635554fc9SAdrian Alonso (0x10000 * port) + USBNC_OFFSET);
25735554fc9SAdrian Alonso void __iomem *status = (void __iomem *)(&usbnc->phy_status);
25835554fc9SAdrian Alonso u32 val;
25935554fc9SAdrian Alonso
26035554fc9SAdrian Alonso val = readl(status);
26135554fc9SAdrian Alonso
26235554fc9SAdrian Alonso if (val & USBNC_PHYSTATUS_ID_DIG)
26335554fc9SAdrian Alonso return USB_INIT_DEVICE;
26435554fc9SAdrian Alonso else
26535554fc9SAdrian Alonso return USB_INIT_HOST;
26635554fc9SAdrian Alonso }
26735554fc9SAdrian Alonso #endif
26835554fc9SAdrian Alonso
usb_oc_config(int index)26935554fc9SAdrian Alonso static void usb_oc_config(int index)
27035554fc9SAdrian Alonso {
27135554fc9SAdrian Alonso #if defined(CONFIG_MX6)
27235554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
27335554fc9SAdrian Alonso USB_OTHERREGS_OFFSET);
27435554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]);
27548afbe4fSYe Li #elif defined(CONFIG_MX7) || defined(CONFIG_MX7ULP)
27635554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR +
27735554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET);
27835554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1);
27935554fc9SAdrian Alonso #endif
28035554fc9SAdrian Alonso
28135554fc9SAdrian Alonso #if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2
28235554fc9SAdrian Alonso /* mx6qarm2 seems to required a different setting*/
28335554fc9SAdrian Alonso clrbits_le32(ctrl, UCTRL_OVER_CUR_POL);
28435554fc9SAdrian Alonso #else
28535554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_POL);
28635554fc9SAdrian Alonso #endif
28735554fc9SAdrian Alonso
28835554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_DIS);
28948afbe4fSYe Li
29048afbe4fSYe Li /* Set power polarity to high active */
29148afbe4fSYe Li #ifdef CONFIG_MXC_USB_OTG_HACTIVE
29248afbe4fSYe Li setbits_le32(ctrl, UCTRL_PWR_POL);
29348afbe4fSYe Li #else
29448afbe4fSYe Li clrbits_le32(ctrl, UCTRL_PWR_POL);
29548afbe4fSYe Li #endif
29635554fc9SAdrian Alonso }
29735554fc9SAdrian Alonso
29874f0610eSAdrian Alonso /**
29979d867c2SStefan Agner * board_usb_phy_mode - override usb phy mode
30074f0610eSAdrian Alonso * @port: usb host/otg port
30174f0610eSAdrian Alonso *
30274f0610eSAdrian Alonso * Target board specific, override usb_phy_mode.
30374f0610eSAdrian Alonso * When usb-otg is used as usb host port, iomux pad usb_otg_id can be
30474f0610eSAdrian Alonso * left disconnected in this case usb_phy_mode will not be able to identify
30574f0610eSAdrian Alonso * the phy mode that usb port is used.
30674f0610eSAdrian Alonso * Machine file overrides board_usb_phy_mode.
30774f0610eSAdrian Alonso *
30874f0610eSAdrian Alonso * Return: USB_INIT_DEVICE or USB_INIT_HOST
30974f0610eSAdrian Alonso */
board_usb_phy_mode(int port)310229dbba9SPeng Fan int __weak board_usb_phy_mode(int port)
311229dbba9SPeng Fan {
312229dbba9SPeng Fan return usb_phy_mode(port);
313229dbba9SPeng Fan }
314229dbba9SPeng Fan
31574f0610eSAdrian Alonso /**
31674f0610eSAdrian Alonso * board_ehci_hcd_init - set usb vbus voltage
31774f0610eSAdrian Alonso * @port: usb otg port
31874f0610eSAdrian Alonso *
31974f0610eSAdrian Alonso * Target board specific, setup iomux pad to setup supply vbus voltage
32074f0610eSAdrian Alonso * for usb otg port. Machine board file overrides board_ehci_hcd_init
32174f0610eSAdrian Alonso *
32274f0610eSAdrian Alonso * Return: 0 Success
32374f0610eSAdrian Alonso */
board_ehci_hcd_init(int port)324f22e4faeSBenoît Thébaudeau int __weak board_ehci_hcd_init(int port)
325f22e4faeSBenoît Thébaudeau {
326f22e4faeSBenoît Thébaudeau return 0;
327f22e4faeSBenoît Thébaudeau }
328f22e4faeSBenoît Thébaudeau
32974f0610eSAdrian Alonso /**
33074f0610eSAdrian Alonso * board_ehci_power - enables/disables usb vbus voltage
33174f0610eSAdrian Alonso * @port: usb otg port
33274f0610eSAdrian Alonso * @on: on/off vbus voltage
33374f0610eSAdrian Alonso *
33474f0610eSAdrian Alonso * Enables/disables supply vbus voltage for usb otg port.
33574f0610eSAdrian Alonso * Machine board file overrides board_ehci_power
33674f0610eSAdrian Alonso *
33774f0610eSAdrian Alonso * Return: 0 Success
33874f0610eSAdrian Alonso */
board_ehci_power(int port,int on)339d1a52860STroy Kisky int __weak board_ehci_power(int port, int on)
340d1a52860STroy Kisky {
341d1a52860STroy Kisky return 0;
342d1a52860STroy Kisky }
343d1a52860STroy Kisky
ehci_mx6_common_init(struct usb_ehci * ehci,int index)344bb42fb4fSPeng Fan int ehci_mx6_common_init(struct usb_ehci *ehci, int index)
3453f467529SWolfgang Grandegger {
34679d867c2SStefan Agner int ret;
3473f467529SWolfgang Grandegger
3483f467529SWolfgang Grandegger enable_usboh3_clk(1);
3493f467529SWolfgang Grandegger mdelay(1);
3503f467529SWolfgang Grandegger
3513f467529SWolfgang Grandegger /* Do board specific initialization */
35279d867c2SStefan Agner ret = board_ehci_hcd_init(index);
35379d867c2SStefan Agner if (ret)
35479d867c2SStefan Agner return ret;
3553f467529SWolfgang Grandegger
356d1a52860STroy Kisky usb_power_config(index);
357d1a52860STroy Kisky usb_oc_config(index);
35835554fc9SAdrian Alonso
35948afbe4fSYe Li #if defined(CONFIG_MX6) || defined(CONFIG_MX7ULP)
360d1a52860STroy Kisky usb_internal_phy_clock_gate(index, 1);
361229dbba9SPeng Fan usb_phy_enable(index, ehci);
36235554fc9SAdrian Alonso #endif
363bb42fb4fSPeng Fan
364bb42fb4fSPeng Fan return 0;
365bb42fb4fSPeng Fan }
366bb42fb4fSPeng Fan
3673739bf7eSSven Schwermer #if !CONFIG_IS_ENABLED(DM_USB)
ehci_hcd_init(int index,enum usb_init_type init,struct ehci_hccr ** hccr,struct ehci_hcor ** hcor)368bb42fb4fSPeng Fan int ehci_hcd_init(int index, enum usb_init_type init,
369bb42fb4fSPeng Fan struct ehci_hccr **hccr, struct ehci_hcor **hcor)
370bb42fb4fSPeng Fan {
371bb42fb4fSPeng Fan enum usb_init_type type;
372bb42fb4fSPeng Fan #if defined(CONFIG_MX6)
373bb42fb4fSPeng Fan u32 controller_spacing = 0x200;
37448afbe4fSYe Li #elif defined(CONFIG_MX7) || defined(CONFIG_MX7ULP)
375bb42fb4fSPeng Fan u32 controller_spacing = 0x10000;
376bb42fb4fSPeng Fan #endif
377bb42fb4fSPeng Fan struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR +
378bb42fb4fSPeng Fan (controller_spacing * index));
379bb42fb4fSPeng Fan int ret;
380bb42fb4fSPeng Fan
381bb42fb4fSPeng Fan if (index > 3)
382bb42fb4fSPeng Fan return -EINVAL;
383bb42fb4fSPeng Fan
384bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, index);
385bb42fb4fSPeng Fan if (ret)
386bb42fb4fSPeng Fan return ret;
387bb42fb4fSPeng Fan
388229dbba9SPeng Fan type = board_usb_phy_mode(index);
3893f467529SWolfgang Grandegger
390bb42fb4fSPeng Fan if (hccr && hcor) {
391676ae068SLucas Stach *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
392676ae068SLucas Stach *hcor = (struct ehci_hcor *)((uint32_t)*hccr +
393676ae068SLucas Stach HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
394bb42fb4fSPeng Fan }
3953f467529SWolfgang Grandegger
396d1a52860STroy Kisky if ((type == init) || (type == USB_INIT_DEVICE))
397d1a52860STroy Kisky board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1);
398d1a52860STroy Kisky if (type != init)
399d1a52860STroy Kisky return -ENODEV;
400d1a52860STroy Kisky if (type == USB_INIT_DEVICE)
401d1a52860STroy Kisky return 0;
40235554fc9SAdrian Alonso
403d1a52860STroy Kisky setbits_le32(&ehci->usbmode, CM_HOST);
404e38ff30aSAdrian Alonso writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
4053f467529SWolfgang Grandegger setbits_le32(&ehci->portsc, USB_EN);
4063f467529SWolfgang Grandegger
4073f467529SWolfgang Grandegger mdelay(10);
4083f467529SWolfgang Grandegger
4093f467529SWolfgang Grandegger return 0;
4103f467529SWolfgang Grandegger }
4113f467529SWolfgang Grandegger
ehci_hcd_stop(int index)412676ae068SLucas Stach int ehci_hcd_stop(int index)
4133f467529SWolfgang Grandegger {
4143f467529SWolfgang Grandegger return 0;
4153f467529SWolfgang Grandegger }
416bb42fb4fSPeng Fan #else
417bb42fb4fSPeng Fan struct ehci_mx6_priv_data {
418bb42fb4fSPeng Fan struct ehci_ctrl ctrl;
419bb42fb4fSPeng Fan struct usb_ehci *ehci;
420fcf9f9f9SPeng Fan struct udevice *vbus_supply;
421bb42fb4fSPeng Fan enum usb_init_type init_type;
422bb42fb4fSPeng Fan int portnr;
423bb42fb4fSPeng Fan };
424bb42fb4fSPeng Fan
mx6_init_after_reset(struct ehci_ctrl * dev)425bb42fb4fSPeng Fan static int mx6_init_after_reset(struct ehci_ctrl *dev)
426bb42fb4fSPeng Fan {
427bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev->priv;
428bb42fb4fSPeng Fan enum usb_init_type type = priv->init_type;
429bb42fb4fSPeng Fan struct usb_ehci *ehci = priv->ehci;
430bb42fb4fSPeng Fan int ret;
431bb42fb4fSPeng Fan
432bb42fb4fSPeng Fan ret = ehci_mx6_common_init(priv->ehci, priv->portnr);
433bb42fb4fSPeng Fan if (ret)
434bb42fb4fSPeng Fan return ret;
435bb42fb4fSPeng Fan
4368a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR)
437fcf9f9f9SPeng Fan if (priv->vbus_supply) {
438fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply,
439fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ?
440fcf9f9f9SPeng Fan false : true);
441fcf9f9f9SPeng Fan if (ret) {
442fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n");
443fcf9f9f9SPeng Fan return ret;
444fcf9f9f9SPeng Fan }
445fcf9f9f9SPeng Fan }
4468a4a81a1SAbel Vesa #endif
447bb42fb4fSPeng Fan
448bb42fb4fSPeng Fan if (type == USB_INIT_DEVICE)
449bb42fb4fSPeng Fan return 0;
450bb42fb4fSPeng Fan
451bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST);
452bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
453bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN);
454bb42fb4fSPeng Fan
455bb42fb4fSPeng Fan mdelay(10);
456bb42fb4fSPeng Fan
457bb42fb4fSPeng Fan return 0;
458bb42fb4fSPeng Fan }
459bb42fb4fSPeng Fan
460bb42fb4fSPeng Fan static const struct ehci_ops mx6_ehci_ops = {
461bb42fb4fSPeng Fan .init_after_reset = mx6_init_after_reset
462bb42fb4fSPeng Fan };
463bb42fb4fSPeng Fan
ehci_usb_phy_mode(struct udevice * dev)464cccbddc3SPeng Fan static int ehci_usb_phy_mode(struct udevice *dev)
465cccbddc3SPeng Fan {
466cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev);
467a821c4afSSimon Glass void *__iomem addr = (void *__iomem)devfdt_get_addr(dev);
468cccbddc3SPeng Fan void *__iomem phy_ctrl, *__iomem phy_status;
469cccbddc3SPeng Fan const void *blob = gd->fdt_blob;
470e160f7d4SSimon Glass int offset = dev_of_offset(dev), phy_off;
471cccbddc3SPeng Fan u32 val;
472cccbddc3SPeng Fan
473cccbddc3SPeng Fan /*
474cccbddc3SPeng Fan * About fsl,usbphy, Refer to
475cccbddc3SPeng Fan * Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt.
476cccbddc3SPeng Fan */
47748afbe4fSYe Li if (is_mx6() || is_mx7ulp()) {
478cccbddc3SPeng Fan phy_off = fdtdec_lookup_phandle(blob,
479cccbddc3SPeng Fan offset,
480cccbddc3SPeng Fan "fsl,usbphy");
481cccbddc3SPeng Fan if (phy_off < 0)
482cccbddc3SPeng Fan return -EINVAL;
483cccbddc3SPeng Fan
484cccbddc3SPeng Fan addr = (void __iomem *)fdtdec_get_addr(blob, phy_off,
485cccbddc3SPeng Fan "reg");
486cccbddc3SPeng Fan if ((fdt_addr_t)addr == FDT_ADDR_T_NONE)
487cccbddc3SPeng Fan return -EINVAL;
488cccbddc3SPeng Fan
489cccbddc3SPeng Fan phy_ctrl = (void __iomem *)(addr + USBPHY_CTRL);
490cccbddc3SPeng Fan val = readl(phy_ctrl);
491cccbddc3SPeng Fan
492cccbddc3SPeng Fan if (val & USBPHY_CTRL_OTG_ID)
493cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE;
494cccbddc3SPeng Fan else
495cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST;
496cccbddc3SPeng Fan } else if (is_mx7()) {
497cccbddc3SPeng Fan phy_status = (void __iomem *)(addr +
498cccbddc3SPeng Fan USBNC_PHY_STATUS_OFFSET);
499cccbddc3SPeng Fan val = readl(phy_status);
500cccbddc3SPeng Fan
501cccbddc3SPeng Fan if (val & USBNC_PHYSTATUS_ID_DIG)
502cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE;
503cccbddc3SPeng Fan else
504cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST;
505cccbddc3SPeng Fan } else {
506cccbddc3SPeng Fan return -EINVAL;
507cccbddc3SPeng Fan }
508cccbddc3SPeng Fan
509cccbddc3SPeng Fan return 0;
510cccbddc3SPeng Fan }
511cccbddc3SPeng Fan
ehci_usb_ofdata_to_platdata(struct udevice * dev)512cccbddc3SPeng Fan static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
513cccbddc3SPeng Fan {
514cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev);
5150457b2cdSAdam Ford enum usb_dr_mode dr_mode;
516cccbddc3SPeng Fan
517*ef78966dSKever Yang dr_mode = usb_get_dr_mode(dev->node);
5180457b2cdSAdam Ford
5190457b2cdSAdam Ford switch (dr_mode) {
5200457b2cdSAdam Ford case USB_DR_MODE_HOST:
521cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST;
5220457b2cdSAdam Ford break;
5230457b2cdSAdam Ford case USB_DR_MODE_PERIPHERAL:
5240457b2cdSAdam Ford plat->init_type = USB_INIT_DEVICE;
5250457b2cdSAdam Ford break;
5260457b2cdSAdam Ford case USB_DR_MODE_OTG:
5270457b2cdSAdam Ford case USB_DR_MODE_UNKNOWN:
528cccbddc3SPeng Fan return ehci_usb_phy_mode(dev);
5290457b2cdSAdam Ford };
530cccbddc3SPeng Fan
531cccbddc3SPeng Fan return 0;
532cccbddc3SPeng Fan }
533cccbddc3SPeng Fan
ehci_usb_bind(struct udevice * dev)534920516c8SMarek Vasut static int ehci_usb_bind(struct udevice *dev)
535920516c8SMarek Vasut {
536920516c8SMarek Vasut /*
537920516c8SMarek Vasut * TODO:
538920516c8SMarek Vasut * This driver is only partly converted to DT probing and still uses
539920516c8SMarek Vasut * a tremendous amount of hard-coded addresses. To make things worse,
540920516c8SMarek Vasut * the driver depends on specific sequential indexing of controllers,
541920516c8SMarek Vasut * from which it derives offsets in the PHY and ANATOP register sets.
542920516c8SMarek Vasut *
543920516c8SMarek Vasut * Here we attempt to calculate these indexes from DT information as
544a9aeb7eeSIgor Opaniuk * well as we can. The USB controllers on all existing iMX6 SoCs
545a9aeb7eeSIgor Opaniuk * are placed next to each other, at addresses incremented by 0x200,
546a9aeb7eeSIgor Opaniuk * and iMX7 their addresses are shifted by 0x10000.
547a9aeb7eeSIgor Opaniuk * Thus, the index is derived from the multiple of 0x200 (0x10000 for
548a9aeb7eeSIgor Opaniuk * iMX7) offset from the first controller address.
549920516c8SMarek Vasut *
550920516c8SMarek Vasut * However, to complete conversion of this driver to DT probing, the
551920516c8SMarek Vasut * following has to be done:
552920516c8SMarek Vasut * - DM clock framework support for iMX must be implemented
553920516c8SMarek Vasut * - usb_power_config() has to be converted to clock framework
554920516c8SMarek Vasut * -> Thus, the ad-hoc "index" variable goes away.
555920516c8SMarek Vasut * - USB PHY handling has to be factored out into separate driver
556920516c8SMarek Vasut * -> Thus, the ad-hoc "index" variable goes away from the PHY
557920516c8SMarek Vasut * code, the PHY driver must parse it's address from DT. This
558920516c8SMarek Vasut * USB driver must find the PHY driver via DT phandle.
559920516c8SMarek Vasut * -> usb_power_config() shall be moved to PHY driver
560920516c8SMarek Vasut * With these changes in place, the ad-hoc indexing goes away and
561920516c8SMarek Vasut * the driver is fully converted to DT probing.
562920516c8SMarek Vasut */
563a9aeb7eeSIgor Opaniuk u32 controller_spacing = is_mx7() ? 0x10000 : 0x200;
564a9aeb7eeSIgor Opaniuk fdt_addr_t addr = devfdt_get_addr_index(dev, 0);
565920516c8SMarek Vasut
566a9aeb7eeSIgor Opaniuk dev->req_seq = (addr - USB_BASE_ADDR) / controller_spacing;
567920516c8SMarek Vasut
568920516c8SMarek Vasut return 0;
569920516c8SMarek Vasut }
570920516c8SMarek Vasut
ehci_usb_probe(struct udevice * dev)571bb42fb4fSPeng Fan static int ehci_usb_probe(struct udevice *dev)
572bb42fb4fSPeng Fan {
573bb42fb4fSPeng Fan struct usb_platdata *plat = dev_get_platdata(dev);
574a821c4afSSimon Glass struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev);
575bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
576fcf9f9f9SPeng Fan enum usb_init_type type = plat->init_type;
577bb42fb4fSPeng Fan struct ehci_hccr *hccr;
578bb42fb4fSPeng Fan struct ehci_hcor *hcor;
579bb42fb4fSPeng Fan int ret;
580bb42fb4fSPeng Fan
581bb42fb4fSPeng Fan priv->ehci = ehci;
582bb42fb4fSPeng Fan priv->portnr = dev->seq;
583fcf9f9f9SPeng Fan priv->init_type = type;
584fcf9f9f9SPeng Fan
5858a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR)
586fcf9f9f9SPeng Fan ret = device_get_supply_regulator(dev, "vbus-supply",
587fcf9f9f9SPeng Fan &priv->vbus_supply);
588fcf9f9f9SPeng Fan if (ret)
589fcf9f9f9SPeng Fan debug("%s: No vbus supply\n", dev->name);
5908a4a81a1SAbel Vesa #endif
591bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, priv->portnr);
592bb42fb4fSPeng Fan if (ret)
593bb42fb4fSPeng Fan return ret;
594bb42fb4fSPeng Fan
5958a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR)
596fcf9f9f9SPeng Fan if (priv->vbus_supply) {
597fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply,
598fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ?
599fcf9f9f9SPeng Fan false : true);
600fcf9f9f9SPeng Fan if (ret) {
601fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n");
602fcf9f9f9SPeng Fan return ret;
603fcf9f9f9SPeng Fan }
604fcf9f9f9SPeng Fan }
6058a4a81a1SAbel Vesa #endif
606bb42fb4fSPeng Fan
607bb42fb4fSPeng Fan if (priv->init_type == USB_INIT_HOST) {
608bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST);
609bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
610bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN);
611bb42fb4fSPeng Fan }
612bb42fb4fSPeng Fan
613bb42fb4fSPeng Fan mdelay(10);
614bb42fb4fSPeng Fan
615bb42fb4fSPeng Fan hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
616bb42fb4fSPeng Fan hcor = (struct ehci_hcor *)((uint32_t)hccr +
617bb42fb4fSPeng Fan HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
618bb42fb4fSPeng Fan
619bb42fb4fSPeng Fan return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type);
620bb42fb4fSPeng Fan }
621bb42fb4fSPeng Fan
622bb42fb4fSPeng Fan static const struct udevice_id mx6_usb_ids[] = {
623bb42fb4fSPeng Fan { .compatible = "fsl,imx27-usb" },
624bb42fb4fSPeng Fan { }
625bb42fb4fSPeng Fan };
626bb42fb4fSPeng Fan
627bb42fb4fSPeng Fan U_BOOT_DRIVER(usb_mx6) = {
628bb42fb4fSPeng Fan .name = "ehci_mx6",
629bb42fb4fSPeng Fan .id = UCLASS_USB,
630bb42fb4fSPeng Fan .of_match = mx6_usb_ids,
631cccbddc3SPeng Fan .ofdata_to_platdata = ehci_usb_ofdata_to_platdata,
632920516c8SMarek Vasut .bind = ehci_usb_bind,
633bb42fb4fSPeng Fan .probe = ehci_usb_probe,
63440527342SMasahiro Yamada .remove = ehci_deregister,
635bb42fb4fSPeng Fan .ops = &ehci_usb_ops,
636bb42fb4fSPeng Fan .platdata_auto_alloc_size = sizeof(struct usb_platdata),
637bb42fb4fSPeng Fan .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data),
638bb42fb4fSPeng Fan .flags = DM_FLAG_ALLOC_PRIV_DMA,
639bb42fb4fSPeng Fan };
640bb42fb4fSPeng Fan #endif
641