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> 17af2a35fbSTroy Kisky #include <asm/imx-common/iomux-v3.h> 18cccbddc3SPeng Fan #include <asm/imx-common/sys_proto.h> 19bb42fb4fSPeng Fan #include <dm.h> 20*fcf9f9f9SPeng Fan #include <power/regulator.h> 213f467529SWolfgang Grandegger 223f467529SWolfgang Grandegger #include "ehci.h" 233f467529SWolfgang Grandegger 24cccbddc3SPeng Fan DECLARE_GLOBAL_DATA_PTR; 25cccbddc3SPeng Fan 263f467529SWolfgang Grandegger #define USB_OTGREGS_OFFSET 0x000 273f467529SWolfgang Grandegger #define USB_H1REGS_OFFSET 0x200 283f467529SWolfgang Grandegger #define USB_H2REGS_OFFSET 0x400 293f467529SWolfgang Grandegger #define USB_H3REGS_OFFSET 0x600 303f467529SWolfgang Grandegger #define USB_OTHERREGS_OFFSET 0x800 313f467529SWolfgang Grandegger 323f467529SWolfgang Grandegger #define USB_H1_CTRL_OFFSET 0x04 333f467529SWolfgang Grandegger 343f467529SWolfgang Grandegger #define USBPHY_CTRL 0x00000030 353f467529SWolfgang Grandegger #define USBPHY_CTRL_SET 0x00000034 363f467529SWolfgang Grandegger #define USBPHY_CTRL_CLR 0x00000038 373f467529SWolfgang Grandegger #define USBPHY_CTRL_TOG 0x0000003c 383f467529SWolfgang Grandegger 393f467529SWolfgang Grandegger #define USBPHY_PWD 0x00000000 403f467529SWolfgang Grandegger #define USBPHY_CTRL_SFTRST 0x80000000 413f467529SWolfgang Grandegger #define USBPHY_CTRL_CLKGATE 0x40000000 423f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL3 0x00008000 433f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL2 0x00004000 44d1a52860STroy Kisky #define USBPHY_CTRL_OTG_ID 0x08000000 453f467529SWolfgang Grandegger 463f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000 473f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000 483f467529SWolfgang Grandegger 493f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000 503f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000 513f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000 523f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 533f467529SWolfgang Grandegger 5435554fc9SAdrian Alonso #define USBNC_OFFSET 0x200 55cccbddc3SPeng Fan #define USBNC_PHY_STATUS_OFFSET 0x23C 5635554fc9SAdrian Alonso #define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */ 5735554fc9SAdrian Alonso #define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */ 589a88180bSStefan Agner #define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */ 593f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ 603f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ 613f467529SWolfgang Grandegger 623f467529SWolfgang Grandegger /* USBCMD */ 633f467529SWolfgang Grandegger #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ 643f467529SWolfgang Grandegger #define UCMD_RESET (1 << 1) /* controller reset */ 653f467529SWolfgang Grandegger 6635554fc9SAdrian Alonso #if defined(CONFIG_MX6) 67d1a52860STroy Kisky static const unsigned phy_bases[] = { 68d1a52860STroy Kisky USB_PHY0_BASE_ADDR, 69d1a52860STroy Kisky USB_PHY1_BASE_ADDR, 70d1a52860STroy Kisky }; 713f467529SWolfgang Grandegger 72d1a52860STroy Kisky static void usb_internal_phy_clock_gate(int index, int on) 73d1a52860STroy Kisky { 74d1a52860STroy Kisky void __iomem *phy_reg; 75d1a52860STroy Kisky 76d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 77d1a52860STroy Kisky return; 78d1a52860STroy Kisky 79d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 803f467529SWolfgang Grandegger phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET; 81e38ff30aSAdrian Alonso writel(USBPHY_CTRL_CLKGATE, phy_reg); 823f467529SWolfgang Grandegger } 833f467529SWolfgang Grandegger 84d1a52860STroy Kisky static void usb_power_config(int index) 853f467529SWolfgang Grandegger { 863f29d962SWolfgang Grandegger struct anatop_regs __iomem *anatop = 873f29d962SWolfgang Grandegger (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; 88d1a52860STroy Kisky void __iomem *chrg_detect; 89d1a52860STroy Kisky void __iomem *pll_480_ctrl_clr; 90d1a52860STroy Kisky void __iomem *pll_480_ctrl_set; 91d1a52860STroy Kisky 92d1a52860STroy Kisky switch (index) { 93d1a52860STroy Kisky case 0: 94d1a52860STroy Kisky chrg_detect = &anatop->usb1_chrg_detect; 95d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr; 96d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set; 97d1a52860STroy Kisky break; 98d1a52860STroy Kisky case 1: 99d1a52860STroy Kisky chrg_detect = &anatop->usb2_chrg_detect; 100d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr; 101d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set; 102d1a52860STroy Kisky break; 103d1a52860STroy Kisky default: 104d1a52860STroy Kisky return; 105d1a52860STroy Kisky } 1063f467529SWolfgang Grandegger /* 107d1a52860STroy Kisky * Some phy and power's special controls 1083f467529SWolfgang Grandegger * 1. The external charger detector needs to be disabled 1093f467529SWolfgang Grandegger * or the signal at DP will be poor 110d1a52860STroy Kisky * 2. The PLL's power and output to usb 1113f467529SWolfgang Grandegger * is totally controlled by IC, so the Software only needs 1123f467529SWolfgang Grandegger * to enable them at initializtion. 1133f467529SWolfgang Grandegger */ 114e38ff30aSAdrian Alonso writel(ANADIG_USB2_CHRG_DETECT_EN_B | 1153f467529SWolfgang Grandegger ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, 116d1a52860STroy Kisky chrg_detect); 1173f467529SWolfgang Grandegger 118e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_BYPASS, 119d1a52860STroy Kisky pll_480_ctrl_clr); 1203f467529SWolfgang Grandegger 121e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_ENABLE | 1223f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_POWER | 1233f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, 124d1a52860STroy Kisky pll_480_ctrl_set); 1253f467529SWolfgang Grandegger } 1263f467529SWolfgang Grandegger 127d1a52860STroy Kisky /* Return 0 : host node, <>0 : device mode */ 128d1a52860STroy Kisky static int usb_phy_enable(int index, struct usb_ehci *ehci) 1293f467529SWolfgang Grandegger { 130d1a52860STroy Kisky void __iomem *phy_reg; 131d1a52860STroy Kisky void __iomem *phy_ctrl; 132d1a52860STroy Kisky void __iomem *usb_cmd; 133f0c89d54SAdrian Alonso int ret; 1343f467529SWolfgang Grandegger 135d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 136d1a52860STroy Kisky return 0; 137d1a52860STroy Kisky 138d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 139d1a52860STroy Kisky phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 140d1a52860STroy Kisky usb_cmd = (void __iomem *)&ehci->usbcmd; 141d1a52860STroy Kisky 1423f467529SWolfgang Grandegger /* Stop then Reset */ 143e38ff30aSAdrian Alonso clrbits_le32(usb_cmd, UCMD_RUN_STOP); 1448c25c259SMateusz Kulikowski ret = wait_for_bit(__func__, usb_cmd, UCMD_RUN_STOP, false, 10000, 1458c25c259SMateusz Kulikowski false); 146f0c89d54SAdrian Alonso if (ret) 147f0c89d54SAdrian Alonso return ret; 1483f467529SWolfgang Grandegger 149e38ff30aSAdrian Alonso setbits_le32(usb_cmd, UCMD_RESET); 1508c25c259SMateusz Kulikowski ret = wait_for_bit(__func__, usb_cmd, UCMD_RESET, false, 10000, false); 151f0c89d54SAdrian Alonso if (ret) 152f0c89d54SAdrian Alonso return ret; 1533f467529SWolfgang Grandegger 1543f467529SWolfgang Grandegger /* Reset USBPHY module */ 155e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST); 1563f467529SWolfgang Grandegger udelay(10); 1573f467529SWolfgang Grandegger 1583f467529SWolfgang Grandegger /* Remove CLKGATE and SFTRST */ 159e38ff30aSAdrian Alonso clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); 1603f467529SWolfgang Grandegger udelay(10); 1613f467529SWolfgang Grandegger 1623f467529SWolfgang Grandegger /* Power up the PHY */ 163e38ff30aSAdrian Alonso writel(0, phy_reg + USBPHY_PWD); 1643f467529SWolfgang Grandegger /* enable FS/LS device */ 165e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 | 166e38ff30aSAdrian Alonso USBPHY_CTRL_ENUTMILEVEL3); 1673f467529SWolfgang Grandegger 168229dbba9SPeng Fan return 0; 1693f467529SWolfgang Grandegger } 1703f467529SWolfgang Grandegger 171229dbba9SPeng Fan int usb_phy_mode(int port) 172229dbba9SPeng Fan { 173229dbba9SPeng Fan void __iomem *phy_reg; 174229dbba9SPeng Fan void __iomem *phy_ctrl; 175229dbba9SPeng Fan u32 val; 176229dbba9SPeng Fan 177229dbba9SPeng Fan phy_reg = (void __iomem *)phy_bases[port]; 178229dbba9SPeng Fan phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 179229dbba9SPeng Fan 180e38ff30aSAdrian Alonso val = readl(phy_ctrl); 181229dbba9SPeng Fan 182229dbba9SPeng Fan if (val & USBPHY_CTRL_OTG_ID) 183229dbba9SPeng Fan return USB_INIT_DEVICE; 184229dbba9SPeng Fan else 185229dbba9SPeng Fan return USB_INIT_HOST; 186229dbba9SPeng Fan } 187229dbba9SPeng Fan 18835554fc9SAdrian Alonso /* Base address for this IP block is 0x02184800 */ 18935554fc9SAdrian Alonso struct usbnc_regs { 19035554fc9SAdrian Alonso u32 ctrl[4]; /* otg/host1-3 */ 19135554fc9SAdrian Alonso u32 uh2_hsic_ctrl; 19235554fc9SAdrian Alonso u32 uh3_hsic_ctrl; 19335554fc9SAdrian Alonso u32 otg_phy_ctrl_0; 19435554fc9SAdrian Alonso u32 uh1_phy_ctrl_0; 19535554fc9SAdrian Alonso }; 19635554fc9SAdrian Alonso #elif defined(CONFIG_MX7) 19735554fc9SAdrian Alonso struct usbnc_regs { 19835554fc9SAdrian Alonso u32 ctrl1; 19935554fc9SAdrian Alonso u32 ctrl2; 20035554fc9SAdrian Alonso u32 reserve1[10]; 20135554fc9SAdrian Alonso u32 phy_cfg1; 20235554fc9SAdrian Alonso u32 phy_cfg2; 203429ff447SPeng Fan u32 reserve2; 20435554fc9SAdrian Alonso u32 phy_status; 205429ff447SPeng Fan u32 reserve3[4]; 20635554fc9SAdrian Alonso u32 adp_cfg1; 20735554fc9SAdrian Alonso u32 adp_cfg2; 20835554fc9SAdrian Alonso u32 adp_status; 20935554fc9SAdrian Alonso }; 21035554fc9SAdrian Alonso 21135554fc9SAdrian Alonso static void usb_power_config(int index) 21235554fc9SAdrian Alonso { 21335554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 21435554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET); 21535554fc9SAdrian Alonso void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2); 2169a88180bSStefan Agner void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); 21735554fc9SAdrian Alonso 21857de41e9SPeng Fan /* 21957de41e9SPeng Fan * Clear the ACAENB to enable usb_otg_id detection, 22057de41e9SPeng Fan * otherwise it is the ACA detection enabled. 22157de41e9SPeng Fan */ 22257de41e9SPeng Fan clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB); 2239a88180bSStefan Agner 2249a88180bSStefan Agner /* Set power polarity to high active */ 225c4483093SStefan Agner #ifdef CONFIG_MXC_USB_OTG_HACTIVE 2269a88180bSStefan Agner setbits_le32(ctrl, UCTRL_PWR_POL); 227c4483093SStefan Agner #else 228c4483093SStefan Agner clrbits_le32(ctrl, UCTRL_PWR_POL); 229c4483093SStefan Agner #endif 23035554fc9SAdrian Alonso } 23135554fc9SAdrian Alonso 23235554fc9SAdrian Alonso int usb_phy_mode(int port) 23335554fc9SAdrian Alonso { 23435554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 23535554fc9SAdrian Alonso (0x10000 * port) + USBNC_OFFSET); 23635554fc9SAdrian Alonso void __iomem *status = (void __iomem *)(&usbnc->phy_status); 23735554fc9SAdrian Alonso u32 val; 23835554fc9SAdrian Alonso 23935554fc9SAdrian Alonso val = readl(status); 24035554fc9SAdrian Alonso 24135554fc9SAdrian Alonso if (val & USBNC_PHYSTATUS_ID_DIG) 24235554fc9SAdrian Alonso return USB_INIT_DEVICE; 24335554fc9SAdrian Alonso else 24435554fc9SAdrian Alonso return USB_INIT_HOST; 24535554fc9SAdrian Alonso } 24635554fc9SAdrian Alonso #endif 24735554fc9SAdrian Alonso 24835554fc9SAdrian Alonso static void usb_oc_config(int index) 24935554fc9SAdrian Alonso { 25035554fc9SAdrian Alonso #if defined(CONFIG_MX6) 25135554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 25235554fc9SAdrian Alonso USB_OTHERREGS_OFFSET); 25335554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]); 25435554fc9SAdrian Alonso #elif defined(CONFIG_MX7) 25535554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 25635554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET); 25735554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); 25835554fc9SAdrian Alonso #endif 25935554fc9SAdrian Alonso 26035554fc9SAdrian Alonso #if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2 26135554fc9SAdrian Alonso /* mx6qarm2 seems to required a different setting*/ 26235554fc9SAdrian Alonso clrbits_le32(ctrl, UCTRL_OVER_CUR_POL); 26335554fc9SAdrian Alonso #else 26435554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_POL); 26535554fc9SAdrian Alonso #endif 26635554fc9SAdrian Alonso 26735554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); 26835554fc9SAdrian Alonso } 26935554fc9SAdrian Alonso 27074f0610eSAdrian Alonso /** 27179d867c2SStefan Agner * board_usb_phy_mode - override usb phy mode 27274f0610eSAdrian Alonso * @port: usb host/otg port 27374f0610eSAdrian Alonso * 27474f0610eSAdrian Alonso * Target board specific, override usb_phy_mode. 27574f0610eSAdrian Alonso * When usb-otg is used as usb host port, iomux pad usb_otg_id can be 27674f0610eSAdrian Alonso * left disconnected in this case usb_phy_mode will not be able to identify 27774f0610eSAdrian Alonso * the phy mode that usb port is used. 27874f0610eSAdrian Alonso * Machine file overrides board_usb_phy_mode. 27974f0610eSAdrian Alonso * 28074f0610eSAdrian Alonso * Return: USB_INIT_DEVICE or USB_INIT_HOST 28174f0610eSAdrian Alonso */ 282229dbba9SPeng Fan int __weak board_usb_phy_mode(int port) 283229dbba9SPeng Fan { 284229dbba9SPeng Fan return usb_phy_mode(port); 285229dbba9SPeng Fan } 286229dbba9SPeng Fan 28774f0610eSAdrian Alonso /** 28874f0610eSAdrian Alonso * board_ehci_hcd_init - set usb vbus voltage 28974f0610eSAdrian Alonso * @port: usb otg port 29074f0610eSAdrian Alonso * 29174f0610eSAdrian Alonso * Target board specific, setup iomux pad to setup supply vbus voltage 29274f0610eSAdrian Alonso * for usb otg port. Machine board file overrides board_ehci_hcd_init 29374f0610eSAdrian Alonso * 29474f0610eSAdrian Alonso * Return: 0 Success 29574f0610eSAdrian Alonso */ 296f22e4faeSBenoît Thébaudeau int __weak board_ehci_hcd_init(int port) 297f22e4faeSBenoît Thébaudeau { 298f22e4faeSBenoît Thébaudeau return 0; 299f22e4faeSBenoît Thébaudeau } 300f22e4faeSBenoît Thébaudeau 30174f0610eSAdrian Alonso /** 30274f0610eSAdrian Alonso * board_ehci_power - enables/disables usb vbus voltage 30374f0610eSAdrian Alonso * @port: usb otg port 30474f0610eSAdrian Alonso * @on: on/off vbus voltage 30574f0610eSAdrian Alonso * 30674f0610eSAdrian Alonso * Enables/disables supply vbus voltage for usb otg port. 30774f0610eSAdrian Alonso * Machine board file overrides board_ehci_power 30874f0610eSAdrian Alonso * 30974f0610eSAdrian Alonso * Return: 0 Success 31074f0610eSAdrian Alonso */ 311d1a52860STroy Kisky int __weak board_ehci_power(int port, int on) 312d1a52860STroy Kisky { 313d1a52860STroy Kisky return 0; 314d1a52860STroy Kisky } 315d1a52860STroy Kisky 316bb42fb4fSPeng Fan int ehci_mx6_common_init(struct usb_ehci *ehci, int index) 3173f467529SWolfgang Grandegger { 31879d867c2SStefan Agner int ret; 3193f467529SWolfgang Grandegger 3203f467529SWolfgang Grandegger enable_usboh3_clk(1); 3213f467529SWolfgang Grandegger mdelay(1); 3223f467529SWolfgang Grandegger 3233f467529SWolfgang Grandegger /* Do board specific initialization */ 32479d867c2SStefan Agner ret = board_ehci_hcd_init(index); 32579d867c2SStefan Agner if (ret) 32679d867c2SStefan Agner return ret; 3273f467529SWolfgang Grandegger 328d1a52860STroy Kisky usb_power_config(index); 329d1a52860STroy Kisky usb_oc_config(index); 33035554fc9SAdrian Alonso 33135554fc9SAdrian Alonso #if defined(CONFIG_MX6) 332d1a52860STroy Kisky usb_internal_phy_clock_gate(index, 1); 333229dbba9SPeng Fan usb_phy_enable(index, ehci); 33435554fc9SAdrian Alonso #endif 335bb42fb4fSPeng Fan 336bb42fb4fSPeng Fan return 0; 337bb42fb4fSPeng Fan } 338bb42fb4fSPeng Fan 339bb42fb4fSPeng Fan #ifndef CONFIG_DM_USB 340bb42fb4fSPeng Fan int ehci_hcd_init(int index, enum usb_init_type init, 341bb42fb4fSPeng Fan struct ehci_hccr **hccr, struct ehci_hcor **hcor) 342bb42fb4fSPeng Fan { 343bb42fb4fSPeng Fan enum usb_init_type type; 344bb42fb4fSPeng Fan #if defined(CONFIG_MX6) 345bb42fb4fSPeng Fan u32 controller_spacing = 0x200; 346bb42fb4fSPeng Fan #elif defined(CONFIG_MX7) 347bb42fb4fSPeng Fan u32 controller_spacing = 0x10000; 348bb42fb4fSPeng Fan #endif 349bb42fb4fSPeng Fan struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR + 350bb42fb4fSPeng Fan (controller_spacing * index)); 351bb42fb4fSPeng Fan int ret; 352bb42fb4fSPeng Fan 353bb42fb4fSPeng Fan if (index > 3) 354bb42fb4fSPeng Fan return -EINVAL; 355bb42fb4fSPeng Fan 356bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, index); 357bb42fb4fSPeng Fan if (ret) 358bb42fb4fSPeng Fan return ret; 359bb42fb4fSPeng Fan 360229dbba9SPeng Fan type = board_usb_phy_mode(index); 3613f467529SWolfgang Grandegger 362bb42fb4fSPeng Fan if (hccr && hcor) { 363676ae068SLucas Stach *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 364676ae068SLucas Stach *hcor = (struct ehci_hcor *)((uint32_t)*hccr + 365676ae068SLucas Stach HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 366bb42fb4fSPeng Fan } 3673f467529SWolfgang Grandegger 368d1a52860STroy Kisky if ((type == init) || (type == USB_INIT_DEVICE)) 369d1a52860STroy Kisky board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1); 370d1a52860STroy Kisky if (type != init) 371d1a52860STroy Kisky return -ENODEV; 372d1a52860STroy Kisky if (type == USB_INIT_DEVICE) 373d1a52860STroy Kisky return 0; 37435554fc9SAdrian Alonso 375d1a52860STroy Kisky setbits_le32(&ehci->usbmode, CM_HOST); 376e38ff30aSAdrian Alonso writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 3773f467529SWolfgang Grandegger setbits_le32(&ehci->portsc, USB_EN); 3783f467529SWolfgang Grandegger 3793f467529SWolfgang Grandegger mdelay(10); 3803f467529SWolfgang Grandegger 3813f467529SWolfgang Grandegger return 0; 3823f467529SWolfgang Grandegger } 3833f467529SWolfgang Grandegger 384676ae068SLucas Stach int ehci_hcd_stop(int index) 3853f467529SWolfgang Grandegger { 3863f467529SWolfgang Grandegger return 0; 3873f467529SWolfgang Grandegger } 388bb42fb4fSPeng Fan #else 389bb42fb4fSPeng Fan struct ehci_mx6_priv_data { 390bb42fb4fSPeng Fan struct ehci_ctrl ctrl; 391bb42fb4fSPeng Fan struct usb_ehci *ehci; 392*fcf9f9f9SPeng Fan struct udevice *vbus_supply; 393bb42fb4fSPeng Fan enum usb_init_type init_type; 394bb42fb4fSPeng Fan int portnr; 395bb42fb4fSPeng Fan }; 396bb42fb4fSPeng Fan 397bb42fb4fSPeng Fan static int mx6_init_after_reset(struct ehci_ctrl *dev) 398bb42fb4fSPeng Fan { 399bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev->priv; 400bb42fb4fSPeng Fan enum usb_init_type type = priv->init_type; 401bb42fb4fSPeng Fan struct usb_ehci *ehci = priv->ehci; 402bb42fb4fSPeng Fan int ret; 403bb42fb4fSPeng Fan 404bb42fb4fSPeng Fan ret = ehci_mx6_common_init(priv->ehci, priv->portnr); 405bb42fb4fSPeng Fan if (ret) 406bb42fb4fSPeng Fan return ret; 407bb42fb4fSPeng Fan 408*fcf9f9f9SPeng Fan if (priv->vbus_supply) { 409*fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply, 410*fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ? 411*fcf9f9f9SPeng Fan false : true); 412*fcf9f9f9SPeng Fan if (ret) { 413*fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n"); 414*fcf9f9f9SPeng Fan return ret; 415*fcf9f9f9SPeng Fan } 416*fcf9f9f9SPeng Fan } 417bb42fb4fSPeng Fan 418bb42fb4fSPeng Fan if (type == USB_INIT_DEVICE) 419bb42fb4fSPeng Fan return 0; 420bb42fb4fSPeng Fan 421bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 422bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 423bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 424bb42fb4fSPeng Fan 425bb42fb4fSPeng Fan mdelay(10); 426bb42fb4fSPeng Fan 427bb42fb4fSPeng Fan return 0; 428bb42fb4fSPeng Fan } 429bb42fb4fSPeng Fan 430bb42fb4fSPeng Fan static const struct ehci_ops mx6_ehci_ops = { 431bb42fb4fSPeng Fan .init_after_reset = mx6_init_after_reset 432bb42fb4fSPeng Fan }; 433bb42fb4fSPeng Fan 434cccbddc3SPeng Fan static int ehci_usb_phy_mode(struct udevice *dev) 435cccbddc3SPeng Fan { 436cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 437cccbddc3SPeng Fan void *__iomem addr = (void *__iomem)dev_get_addr(dev); 438cccbddc3SPeng Fan void *__iomem phy_ctrl, *__iomem phy_status; 439cccbddc3SPeng Fan const void *blob = gd->fdt_blob; 440cccbddc3SPeng Fan int offset = dev->of_offset, phy_off; 441cccbddc3SPeng Fan u32 val; 442cccbddc3SPeng Fan 443cccbddc3SPeng Fan /* 444cccbddc3SPeng Fan * About fsl,usbphy, Refer to 445cccbddc3SPeng Fan * Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt. 446cccbddc3SPeng Fan */ 447cccbddc3SPeng Fan if (is_mx6()) { 448cccbddc3SPeng Fan phy_off = fdtdec_lookup_phandle(blob, 449cccbddc3SPeng Fan offset, 450cccbddc3SPeng Fan "fsl,usbphy"); 451cccbddc3SPeng Fan if (phy_off < 0) 452cccbddc3SPeng Fan return -EINVAL; 453cccbddc3SPeng Fan 454cccbddc3SPeng Fan addr = (void __iomem *)fdtdec_get_addr(blob, phy_off, 455cccbddc3SPeng Fan "reg"); 456cccbddc3SPeng Fan if ((fdt_addr_t)addr == FDT_ADDR_T_NONE) 457cccbddc3SPeng Fan return -EINVAL; 458cccbddc3SPeng Fan 459cccbddc3SPeng Fan phy_ctrl = (void __iomem *)(addr + USBPHY_CTRL); 460cccbddc3SPeng Fan val = readl(phy_ctrl); 461cccbddc3SPeng Fan 462cccbddc3SPeng Fan if (val & USBPHY_CTRL_OTG_ID) 463cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 464cccbddc3SPeng Fan else 465cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 466cccbddc3SPeng Fan } else if (is_mx7()) { 467cccbddc3SPeng Fan phy_status = (void __iomem *)(addr + 468cccbddc3SPeng Fan USBNC_PHY_STATUS_OFFSET); 469cccbddc3SPeng Fan val = readl(phy_status); 470cccbddc3SPeng Fan 471cccbddc3SPeng Fan if (val & USBNC_PHYSTATUS_ID_DIG) 472cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 473cccbddc3SPeng Fan else 474cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 475cccbddc3SPeng Fan } else { 476cccbddc3SPeng Fan return -EINVAL; 477cccbddc3SPeng Fan } 478cccbddc3SPeng Fan 479cccbddc3SPeng Fan return 0; 480cccbddc3SPeng Fan } 481cccbddc3SPeng Fan 482cccbddc3SPeng Fan static int ehci_usb_ofdata_to_platdata(struct udevice *dev) 483cccbddc3SPeng Fan { 484cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 485cccbddc3SPeng Fan const char *mode; 486cccbddc3SPeng Fan 487cccbddc3SPeng Fan mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "dr_mode", NULL); 488cccbddc3SPeng Fan if (mode) { 489cccbddc3SPeng Fan if (strcmp(mode, "peripheral") == 0) 490cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 491cccbddc3SPeng Fan else if (strcmp(mode, "host") == 0) 492cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 493cccbddc3SPeng Fan else if (strcmp(mode, "otg") == 0) 494cccbddc3SPeng Fan return ehci_usb_phy_mode(dev); 495cccbddc3SPeng Fan else 496cccbddc3SPeng Fan return -EINVAL; 497cccbddc3SPeng Fan 498cccbddc3SPeng Fan return 0; 499cccbddc3SPeng Fan } 500cccbddc3SPeng Fan 501cccbddc3SPeng Fan return ehci_usb_phy_mode(dev); 502cccbddc3SPeng Fan } 503cccbddc3SPeng Fan 504bb42fb4fSPeng Fan static int ehci_usb_probe(struct udevice *dev) 505bb42fb4fSPeng Fan { 506bb42fb4fSPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 507bb42fb4fSPeng Fan struct usb_ehci *ehci = (struct usb_ehci *)dev_get_addr(dev); 508bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev_get_priv(dev); 509*fcf9f9f9SPeng Fan enum usb_init_type type = plat->init_type; 510bb42fb4fSPeng Fan struct ehci_hccr *hccr; 511bb42fb4fSPeng Fan struct ehci_hcor *hcor; 512bb42fb4fSPeng Fan int ret; 513bb42fb4fSPeng Fan 514bb42fb4fSPeng Fan priv->ehci = ehci; 515bb42fb4fSPeng Fan priv->portnr = dev->seq; 516*fcf9f9f9SPeng Fan priv->init_type = type; 517*fcf9f9f9SPeng Fan 518*fcf9f9f9SPeng Fan ret = device_get_supply_regulator(dev, "vbus-supply", 519*fcf9f9f9SPeng Fan &priv->vbus_supply); 520*fcf9f9f9SPeng Fan if (ret) 521*fcf9f9f9SPeng Fan debug("%s: No vbus supply\n", dev->name); 522bb42fb4fSPeng Fan 523bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, priv->portnr); 524bb42fb4fSPeng Fan if (ret) 525bb42fb4fSPeng Fan return ret; 526bb42fb4fSPeng Fan 527*fcf9f9f9SPeng Fan if (priv->vbus_supply) { 528*fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply, 529*fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ? 530*fcf9f9f9SPeng Fan false : true); 531*fcf9f9f9SPeng Fan if (ret) { 532*fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n"); 533*fcf9f9f9SPeng Fan return ret; 534*fcf9f9f9SPeng Fan } 535*fcf9f9f9SPeng Fan } 536bb42fb4fSPeng Fan 537bb42fb4fSPeng Fan if (priv->init_type == USB_INIT_HOST) { 538bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 539bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 540bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 541bb42fb4fSPeng Fan } 542bb42fb4fSPeng Fan 543bb42fb4fSPeng Fan mdelay(10); 544bb42fb4fSPeng Fan 545bb42fb4fSPeng Fan hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 546bb42fb4fSPeng Fan hcor = (struct ehci_hcor *)((uint32_t)hccr + 547bb42fb4fSPeng Fan HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); 548bb42fb4fSPeng Fan 549bb42fb4fSPeng Fan return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type); 550bb42fb4fSPeng Fan } 551bb42fb4fSPeng Fan 552bb42fb4fSPeng Fan static const struct udevice_id mx6_usb_ids[] = { 553bb42fb4fSPeng Fan { .compatible = "fsl,imx27-usb" }, 554bb42fb4fSPeng Fan { } 555bb42fb4fSPeng Fan }; 556bb42fb4fSPeng Fan 557bb42fb4fSPeng Fan U_BOOT_DRIVER(usb_mx6) = { 558bb42fb4fSPeng Fan .name = "ehci_mx6", 559bb42fb4fSPeng Fan .id = UCLASS_USB, 560bb42fb4fSPeng Fan .of_match = mx6_usb_ids, 561cccbddc3SPeng Fan .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, 562bb42fb4fSPeng Fan .probe = ehci_usb_probe, 56340527342SMasahiro Yamada .remove = ehci_deregister, 564bb42fb4fSPeng Fan .ops = &ehci_usb_ops, 565bb42fb4fSPeng Fan .platdata_auto_alloc_size = sizeof(struct usb_platdata), 566bb42fb4fSPeng Fan .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data), 567bb42fb4fSPeng Fan .flags = DM_FLAG_ALLOC_PRIV_DMA, 568bb42fb4fSPeng Fan }; 569bb42fb4fSPeng Fan #endif 570