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> 223f467529SWolfgang Grandegger 233f467529SWolfgang Grandegger #include "ehci.h" 243f467529SWolfgang Grandegger 25cccbddc3SPeng Fan DECLARE_GLOBAL_DATA_PTR; 26cccbddc3SPeng Fan 273f467529SWolfgang Grandegger #define USB_OTGREGS_OFFSET 0x000 283f467529SWolfgang Grandegger #define USB_H1REGS_OFFSET 0x200 293f467529SWolfgang Grandegger #define USB_H2REGS_OFFSET 0x400 303f467529SWolfgang Grandegger #define USB_H3REGS_OFFSET 0x600 313f467529SWolfgang Grandegger #define USB_OTHERREGS_OFFSET 0x800 323f467529SWolfgang Grandegger 333f467529SWolfgang Grandegger #define USB_H1_CTRL_OFFSET 0x04 343f467529SWolfgang Grandegger 353f467529SWolfgang Grandegger #define USBPHY_CTRL 0x00000030 363f467529SWolfgang Grandegger #define USBPHY_CTRL_SET 0x00000034 373f467529SWolfgang Grandegger #define USBPHY_CTRL_CLR 0x00000038 383f467529SWolfgang Grandegger #define USBPHY_CTRL_TOG 0x0000003c 393f467529SWolfgang Grandegger 403f467529SWolfgang Grandegger #define USBPHY_PWD 0x00000000 413f467529SWolfgang Grandegger #define USBPHY_CTRL_SFTRST 0x80000000 423f467529SWolfgang Grandegger #define USBPHY_CTRL_CLKGATE 0x40000000 433f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL3 0x00008000 443f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL2 0x00004000 45d1a52860STroy Kisky #define USBPHY_CTRL_OTG_ID 0x08000000 463f467529SWolfgang Grandegger 473f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000 483f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000 493f467529SWolfgang Grandegger 503f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000 513f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000 523f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000 533f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 543f467529SWolfgang Grandegger 5535554fc9SAdrian Alonso #define USBNC_OFFSET 0x200 56cccbddc3SPeng Fan #define USBNC_PHY_STATUS_OFFSET 0x23C 5735554fc9SAdrian Alonso #define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */ 5835554fc9SAdrian Alonso #define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */ 599a88180bSStefan Agner #define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */ 603f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ 613f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ 623f467529SWolfgang Grandegger 633f467529SWolfgang Grandegger /* USBCMD */ 643f467529SWolfgang Grandegger #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ 653f467529SWolfgang Grandegger #define UCMD_RESET (1 << 1) /* controller reset */ 663f467529SWolfgang Grandegger 6735554fc9SAdrian Alonso #if defined(CONFIG_MX6) 68d1a52860STroy Kisky static const unsigned phy_bases[] = { 69d1a52860STroy Kisky USB_PHY0_BASE_ADDR, 70d1a52860STroy Kisky USB_PHY1_BASE_ADDR, 71d1a52860STroy Kisky }; 723f467529SWolfgang Grandegger 73d1a52860STroy Kisky static void usb_internal_phy_clock_gate(int index, int on) 74d1a52860STroy Kisky { 75d1a52860STroy Kisky void __iomem *phy_reg; 76d1a52860STroy Kisky 77d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 78d1a52860STroy Kisky return; 79d1a52860STroy Kisky 80d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 813f467529SWolfgang Grandegger phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET; 82e38ff30aSAdrian Alonso writel(USBPHY_CTRL_CLKGATE, phy_reg); 833f467529SWolfgang Grandegger } 843f467529SWolfgang Grandegger 85d1a52860STroy Kisky static void usb_power_config(int index) 863f467529SWolfgang Grandegger { 873f29d962SWolfgang Grandegger struct anatop_regs __iomem *anatop = 883f29d962SWolfgang Grandegger (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; 89d1a52860STroy Kisky void __iomem *chrg_detect; 90d1a52860STroy Kisky void __iomem *pll_480_ctrl_clr; 91d1a52860STroy Kisky void __iomem *pll_480_ctrl_set; 92d1a52860STroy Kisky 93d1a52860STroy Kisky switch (index) { 94d1a52860STroy Kisky case 0: 95d1a52860STroy Kisky chrg_detect = &anatop->usb1_chrg_detect; 96d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr; 97d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set; 98d1a52860STroy Kisky break; 99d1a52860STroy Kisky case 1: 100d1a52860STroy Kisky chrg_detect = &anatop->usb2_chrg_detect; 101d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr; 102d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set; 103d1a52860STroy Kisky break; 104d1a52860STroy Kisky default: 105d1a52860STroy Kisky return; 106d1a52860STroy Kisky } 1073f467529SWolfgang Grandegger /* 108d1a52860STroy Kisky * Some phy and power's special controls 1093f467529SWolfgang Grandegger * 1. The external charger detector needs to be disabled 1103f467529SWolfgang Grandegger * or the signal at DP will be poor 111d1a52860STroy Kisky * 2. The PLL's power and output to usb 1123f467529SWolfgang Grandegger * is totally controlled by IC, so the Software only needs 1133f467529SWolfgang Grandegger * to enable them at initializtion. 1143f467529SWolfgang Grandegger */ 115e38ff30aSAdrian Alonso writel(ANADIG_USB2_CHRG_DETECT_EN_B | 1163f467529SWolfgang Grandegger ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, 117d1a52860STroy Kisky chrg_detect); 1183f467529SWolfgang Grandegger 119e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_BYPASS, 120d1a52860STroy Kisky pll_480_ctrl_clr); 1213f467529SWolfgang Grandegger 122e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_ENABLE | 1233f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_POWER | 1243f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, 125d1a52860STroy Kisky pll_480_ctrl_set); 1263f467529SWolfgang Grandegger } 1273f467529SWolfgang Grandegger 128d1a52860STroy Kisky /* Return 0 : host node, <>0 : device mode */ 129d1a52860STroy Kisky static int usb_phy_enable(int index, struct usb_ehci *ehci) 1303f467529SWolfgang Grandegger { 131d1a52860STroy Kisky void __iomem *phy_reg; 132d1a52860STroy Kisky void __iomem *phy_ctrl; 133d1a52860STroy Kisky void __iomem *usb_cmd; 134f0c89d54SAdrian Alonso int ret; 1353f467529SWolfgang Grandegger 136d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 137d1a52860STroy Kisky return 0; 138d1a52860STroy Kisky 139d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 140d1a52860STroy Kisky phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 141d1a52860STroy Kisky usb_cmd = (void __iomem *)&ehci->usbcmd; 142d1a52860STroy Kisky 1433f467529SWolfgang Grandegger /* Stop then Reset */ 144e38ff30aSAdrian Alonso clrbits_le32(usb_cmd, UCMD_RUN_STOP); 145b491b498SJon Lin ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false); 146f0c89d54SAdrian Alonso if (ret) 147f0c89d54SAdrian Alonso return ret; 1483f467529SWolfgang Grandegger 149e38ff30aSAdrian Alonso setbits_le32(usb_cmd, UCMD_RESET); 150b491b498SJon Lin ret = wait_for_bit_le32(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 3393739bf7eSSven Schwermer #if !CONFIG_IS_ENABLED(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; 392fcf9f9f9SPeng 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*8a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR) 409fcf9f9f9SPeng Fan if (priv->vbus_supply) { 410fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply, 411fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ? 412fcf9f9f9SPeng Fan false : true); 413fcf9f9f9SPeng Fan if (ret) { 414fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n"); 415fcf9f9f9SPeng Fan return ret; 416fcf9f9f9SPeng Fan } 417fcf9f9f9SPeng Fan } 418*8a4a81a1SAbel Vesa #endif 419bb42fb4fSPeng Fan 420bb42fb4fSPeng Fan if (type == USB_INIT_DEVICE) 421bb42fb4fSPeng Fan return 0; 422bb42fb4fSPeng Fan 423bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 424bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 425bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 426bb42fb4fSPeng Fan 427bb42fb4fSPeng Fan mdelay(10); 428bb42fb4fSPeng Fan 429bb42fb4fSPeng Fan return 0; 430bb42fb4fSPeng Fan } 431bb42fb4fSPeng Fan 432bb42fb4fSPeng Fan static const struct ehci_ops mx6_ehci_ops = { 433bb42fb4fSPeng Fan .init_after_reset = mx6_init_after_reset 434bb42fb4fSPeng Fan }; 435bb42fb4fSPeng Fan 436cccbddc3SPeng Fan static int ehci_usb_phy_mode(struct udevice *dev) 437cccbddc3SPeng Fan { 438cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 439a821c4afSSimon Glass void *__iomem addr = (void *__iomem)devfdt_get_addr(dev); 440cccbddc3SPeng Fan void *__iomem phy_ctrl, *__iomem phy_status; 441cccbddc3SPeng Fan const void *blob = gd->fdt_blob; 442e160f7d4SSimon Glass int offset = dev_of_offset(dev), phy_off; 443cccbddc3SPeng Fan u32 val; 444cccbddc3SPeng Fan 445cccbddc3SPeng Fan /* 446cccbddc3SPeng Fan * About fsl,usbphy, Refer to 447cccbddc3SPeng Fan * Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt. 448cccbddc3SPeng Fan */ 449cccbddc3SPeng Fan if (is_mx6()) { 450cccbddc3SPeng Fan phy_off = fdtdec_lookup_phandle(blob, 451cccbddc3SPeng Fan offset, 452cccbddc3SPeng Fan "fsl,usbphy"); 453cccbddc3SPeng Fan if (phy_off < 0) 454cccbddc3SPeng Fan return -EINVAL; 455cccbddc3SPeng Fan 456cccbddc3SPeng Fan addr = (void __iomem *)fdtdec_get_addr(blob, phy_off, 457cccbddc3SPeng Fan "reg"); 458cccbddc3SPeng Fan if ((fdt_addr_t)addr == FDT_ADDR_T_NONE) 459cccbddc3SPeng Fan return -EINVAL; 460cccbddc3SPeng Fan 461cccbddc3SPeng Fan phy_ctrl = (void __iomem *)(addr + USBPHY_CTRL); 462cccbddc3SPeng Fan val = readl(phy_ctrl); 463cccbddc3SPeng Fan 464cccbddc3SPeng Fan if (val & USBPHY_CTRL_OTG_ID) 465cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 466cccbddc3SPeng Fan else 467cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 468cccbddc3SPeng Fan } else if (is_mx7()) { 469cccbddc3SPeng Fan phy_status = (void __iomem *)(addr + 470cccbddc3SPeng Fan USBNC_PHY_STATUS_OFFSET); 471cccbddc3SPeng Fan val = readl(phy_status); 472cccbddc3SPeng Fan 473cccbddc3SPeng Fan if (val & USBNC_PHYSTATUS_ID_DIG) 474cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 475cccbddc3SPeng Fan else 476cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 477cccbddc3SPeng Fan } else { 478cccbddc3SPeng Fan return -EINVAL; 479cccbddc3SPeng Fan } 480cccbddc3SPeng Fan 481cccbddc3SPeng Fan return 0; 482cccbddc3SPeng Fan } 483cccbddc3SPeng Fan 484cccbddc3SPeng Fan static int ehci_usb_ofdata_to_platdata(struct udevice *dev) 485cccbddc3SPeng Fan { 486cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 487cccbddc3SPeng Fan const char *mode; 488cccbddc3SPeng Fan 489e160f7d4SSimon Glass mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL); 490cccbddc3SPeng Fan if (mode) { 491cccbddc3SPeng Fan if (strcmp(mode, "peripheral") == 0) 492cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 493cccbddc3SPeng Fan else if (strcmp(mode, "host") == 0) 494cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 495cccbddc3SPeng Fan else if (strcmp(mode, "otg") == 0) 496cccbddc3SPeng Fan return ehci_usb_phy_mode(dev); 497cccbddc3SPeng Fan else 498cccbddc3SPeng Fan return -EINVAL; 499cccbddc3SPeng Fan 500cccbddc3SPeng Fan return 0; 501cccbddc3SPeng Fan } 502cccbddc3SPeng Fan 503cccbddc3SPeng Fan return ehci_usb_phy_mode(dev); 504cccbddc3SPeng Fan } 505cccbddc3SPeng Fan 506bb42fb4fSPeng Fan static int ehci_usb_probe(struct udevice *dev) 507bb42fb4fSPeng Fan { 508bb42fb4fSPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 509a821c4afSSimon Glass struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev); 510bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev_get_priv(dev); 511fcf9f9f9SPeng Fan enum usb_init_type type = plat->init_type; 512bb42fb4fSPeng Fan struct ehci_hccr *hccr; 513bb42fb4fSPeng Fan struct ehci_hcor *hcor; 514bb42fb4fSPeng Fan int ret; 515bb42fb4fSPeng Fan 516bb42fb4fSPeng Fan priv->ehci = ehci; 517bb42fb4fSPeng Fan priv->portnr = dev->seq; 518fcf9f9f9SPeng Fan priv->init_type = type; 519fcf9f9f9SPeng Fan 520*8a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR) 521fcf9f9f9SPeng Fan ret = device_get_supply_regulator(dev, "vbus-supply", 522fcf9f9f9SPeng Fan &priv->vbus_supply); 523fcf9f9f9SPeng Fan if (ret) 524fcf9f9f9SPeng Fan debug("%s: No vbus supply\n", dev->name); 525*8a4a81a1SAbel Vesa #endif 526bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, priv->portnr); 527bb42fb4fSPeng Fan if (ret) 528bb42fb4fSPeng Fan return ret; 529bb42fb4fSPeng Fan 530*8a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR) 531fcf9f9f9SPeng Fan if (priv->vbus_supply) { 532fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply, 533fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ? 534fcf9f9f9SPeng Fan false : true); 535fcf9f9f9SPeng Fan if (ret) { 536fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n"); 537fcf9f9f9SPeng Fan return ret; 538fcf9f9f9SPeng Fan } 539fcf9f9f9SPeng Fan } 540*8a4a81a1SAbel Vesa #endif 541bb42fb4fSPeng Fan 542bb42fb4fSPeng Fan if (priv->init_type == USB_INIT_HOST) { 543bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 544bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 545bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 546bb42fb4fSPeng Fan } 547bb42fb4fSPeng Fan 548bb42fb4fSPeng Fan mdelay(10); 549bb42fb4fSPeng Fan 550bb42fb4fSPeng Fan hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 551bb42fb4fSPeng Fan hcor = (struct ehci_hcor *)((uint32_t)hccr + 552bb42fb4fSPeng Fan HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); 553bb42fb4fSPeng Fan 554bb42fb4fSPeng Fan return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type); 555bb42fb4fSPeng Fan } 556bb42fb4fSPeng Fan 557bb42fb4fSPeng Fan static const struct udevice_id mx6_usb_ids[] = { 558bb42fb4fSPeng Fan { .compatible = "fsl,imx27-usb" }, 559bb42fb4fSPeng Fan { } 560bb42fb4fSPeng Fan }; 561bb42fb4fSPeng Fan 562bb42fb4fSPeng Fan U_BOOT_DRIVER(usb_mx6) = { 563bb42fb4fSPeng Fan .name = "ehci_mx6", 564bb42fb4fSPeng Fan .id = UCLASS_USB, 565bb42fb4fSPeng Fan .of_match = mx6_usb_ids, 566cccbddc3SPeng Fan .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, 567bb42fb4fSPeng Fan .probe = ehci_usb_probe, 56840527342SMasahiro Yamada .remove = ehci_deregister, 569bb42fb4fSPeng Fan .ops = &ehci_usb_ops, 570bb42fb4fSPeng Fan .platdata_auto_alloc_size = sizeof(struct usb_platdata), 571bb42fb4fSPeng Fan .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data), 572bb42fb4fSPeng Fan .flags = DM_FLAG_ALLOC_PRIV_DMA, 573bb42fb4fSPeng Fan }; 574bb42fb4fSPeng Fan #endif 575