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> 18*bb42fb4fSPeng Fan #include <dm.h> 193f467529SWolfgang Grandegger 203f467529SWolfgang Grandegger #include "ehci.h" 213f467529SWolfgang Grandegger 223f467529SWolfgang Grandegger #define USB_OTGREGS_OFFSET 0x000 233f467529SWolfgang Grandegger #define USB_H1REGS_OFFSET 0x200 243f467529SWolfgang Grandegger #define USB_H2REGS_OFFSET 0x400 253f467529SWolfgang Grandegger #define USB_H3REGS_OFFSET 0x600 263f467529SWolfgang Grandegger #define USB_OTHERREGS_OFFSET 0x800 273f467529SWolfgang Grandegger 283f467529SWolfgang Grandegger #define USB_H1_CTRL_OFFSET 0x04 293f467529SWolfgang Grandegger 303f467529SWolfgang Grandegger #define USBPHY_CTRL 0x00000030 313f467529SWolfgang Grandegger #define USBPHY_CTRL_SET 0x00000034 323f467529SWolfgang Grandegger #define USBPHY_CTRL_CLR 0x00000038 333f467529SWolfgang Grandegger #define USBPHY_CTRL_TOG 0x0000003c 343f467529SWolfgang Grandegger 353f467529SWolfgang Grandegger #define USBPHY_PWD 0x00000000 363f467529SWolfgang Grandegger #define USBPHY_CTRL_SFTRST 0x80000000 373f467529SWolfgang Grandegger #define USBPHY_CTRL_CLKGATE 0x40000000 383f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL3 0x00008000 393f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL2 0x00004000 40d1a52860STroy Kisky #define USBPHY_CTRL_OTG_ID 0x08000000 413f467529SWolfgang Grandegger 423f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000 433f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000 443f467529SWolfgang Grandegger 453f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000 463f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000 473f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000 483f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 493f467529SWolfgang Grandegger 5035554fc9SAdrian Alonso #define USBNC_OFFSET 0x200 5135554fc9SAdrian Alonso #define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */ 5235554fc9SAdrian Alonso #define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */ 539a88180bSStefan Agner #define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */ 543f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ 553f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ 563f467529SWolfgang Grandegger 573f467529SWolfgang Grandegger /* USBCMD */ 583f467529SWolfgang Grandegger #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ 593f467529SWolfgang Grandegger #define UCMD_RESET (1 << 1) /* controller reset */ 603f467529SWolfgang Grandegger 6135554fc9SAdrian Alonso #if defined(CONFIG_MX6) 62d1a52860STroy Kisky static const unsigned phy_bases[] = { 63d1a52860STroy Kisky USB_PHY0_BASE_ADDR, 64d1a52860STroy Kisky USB_PHY1_BASE_ADDR, 65d1a52860STroy Kisky }; 663f467529SWolfgang Grandegger 67d1a52860STroy Kisky static void usb_internal_phy_clock_gate(int index, int on) 68d1a52860STroy Kisky { 69d1a52860STroy Kisky void __iomem *phy_reg; 70d1a52860STroy Kisky 71d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 72d1a52860STroy Kisky return; 73d1a52860STroy Kisky 74d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 753f467529SWolfgang Grandegger phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET; 76e38ff30aSAdrian Alonso writel(USBPHY_CTRL_CLKGATE, phy_reg); 773f467529SWolfgang Grandegger } 783f467529SWolfgang Grandegger 79d1a52860STroy Kisky static void usb_power_config(int index) 803f467529SWolfgang Grandegger { 813f29d962SWolfgang Grandegger struct anatop_regs __iomem *anatop = 823f29d962SWolfgang Grandegger (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; 83d1a52860STroy Kisky void __iomem *chrg_detect; 84d1a52860STroy Kisky void __iomem *pll_480_ctrl_clr; 85d1a52860STroy Kisky void __iomem *pll_480_ctrl_set; 86d1a52860STroy Kisky 87d1a52860STroy Kisky switch (index) { 88d1a52860STroy Kisky case 0: 89d1a52860STroy Kisky chrg_detect = &anatop->usb1_chrg_detect; 90d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr; 91d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set; 92d1a52860STroy Kisky break; 93d1a52860STroy Kisky case 1: 94d1a52860STroy Kisky chrg_detect = &anatop->usb2_chrg_detect; 95d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr; 96d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set; 97d1a52860STroy Kisky break; 98d1a52860STroy Kisky default: 99d1a52860STroy Kisky return; 100d1a52860STroy Kisky } 1013f467529SWolfgang Grandegger /* 102d1a52860STroy Kisky * Some phy and power's special controls 1033f467529SWolfgang Grandegger * 1. The external charger detector needs to be disabled 1043f467529SWolfgang Grandegger * or the signal at DP will be poor 105d1a52860STroy Kisky * 2. The PLL's power and output to usb 1063f467529SWolfgang Grandegger * is totally controlled by IC, so the Software only needs 1073f467529SWolfgang Grandegger * to enable them at initializtion. 1083f467529SWolfgang Grandegger */ 109e38ff30aSAdrian Alonso writel(ANADIG_USB2_CHRG_DETECT_EN_B | 1103f467529SWolfgang Grandegger ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, 111d1a52860STroy Kisky chrg_detect); 1123f467529SWolfgang Grandegger 113e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_BYPASS, 114d1a52860STroy Kisky pll_480_ctrl_clr); 1153f467529SWolfgang Grandegger 116e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_ENABLE | 1173f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_POWER | 1183f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, 119d1a52860STroy Kisky pll_480_ctrl_set); 1203f467529SWolfgang Grandegger } 1213f467529SWolfgang Grandegger 122d1a52860STroy Kisky /* Return 0 : host node, <>0 : device mode */ 123d1a52860STroy Kisky static int usb_phy_enable(int index, struct usb_ehci *ehci) 1243f467529SWolfgang Grandegger { 125d1a52860STroy Kisky void __iomem *phy_reg; 126d1a52860STroy Kisky void __iomem *phy_ctrl; 127d1a52860STroy Kisky void __iomem *usb_cmd; 128f0c89d54SAdrian Alonso int ret; 1293f467529SWolfgang Grandegger 130d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 131d1a52860STroy Kisky return 0; 132d1a52860STroy Kisky 133d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 134d1a52860STroy Kisky phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 135d1a52860STroy Kisky usb_cmd = (void __iomem *)&ehci->usbcmd; 136d1a52860STroy Kisky 1373f467529SWolfgang Grandegger /* Stop then Reset */ 138e38ff30aSAdrian Alonso clrbits_le32(usb_cmd, UCMD_RUN_STOP); 1398c25c259SMateusz Kulikowski ret = wait_for_bit(__func__, usb_cmd, UCMD_RUN_STOP, false, 10000, 1408c25c259SMateusz Kulikowski false); 141f0c89d54SAdrian Alonso if (ret) 142f0c89d54SAdrian Alonso return ret; 1433f467529SWolfgang Grandegger 144e38ff30aSAdrian Alonso setbits_le32(usb_cmd, UCMD_RESET); 1458c25c259SMateusz Kulikowski ret = wait_for_bit(__func__, usb_cmd, UCMD_RESET, false, 10000, false); 146f0c89d54SAdrian Alonso if (ret) 147f0c89d54SAdrian Alonso return ret; 1483f467529SWolfgang Grandegger 1493f467529SWolfgang Grandegger /* Reset USBPHY module */ 150e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST); 1513f467529SWolfgang Grandegger udelay(10); 1523f467529SWolfgang Grandegger 1533f467529SWolfgang Grandegger /* Remove CLKGATE and SFTRST */ 154e38ff30aSAdrian Alonso clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); 1553f467529SWolfgang Grandegger udelay(10); 1563f467529SWolfgang Grandegger 1573f467529SWolfgang Grandegger /* Power up the PHY */ 158e38ff30aSAdrian Alonso writel(0, phy_reg + USBPHY_PWD); 1593f467529SWolfgang Grandegger /* enable FS/LS device */ 160e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 | 161e38ff30aSAdrian Alonso USBPHY_CTRL_ENUTMILEVEL3); 1623f467529SWolfgang Grandegger 163229dbba9SPeng Fan return 0; 1643f467529SWolfgang Grandegger } 1653f467529SWolfgang Grandegger 166229dbba9SPeng Fan int usb_phy_mode(int port) 167229dbba9SPeng Fan { 168229dbba9SPeng Fan void __iomem *phy_reg; 169229dbba9SPeng Fan void __iomem *phy_ctrl; 170229dbba9SPeng Fan u32 val; 171229dbba9SPeng Fan 172229dbba9SPeng Fan phy_reg = (void __iomem *)phy_bases[port]; 173229dbba9SPeng Fan phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 174229dbba9SPeng Fan 175e38ff30aSAdrian Alonso val = readl(phy_ctrl); 176229dbba9SPeng Fan 177229dbba9SPeng Fan if (val & USBPHY_CTRL_OTG_ID) 178229dbba9SPeng Fan return USB_INIT_DEVICE; 179229dbba9SPeng Fan else 180229dbba9SPeng Fan return USB_INIT_HOST; 181229dbba9SPeng Fan } 182229dbba9SPeng Fan 18335554fc9SAdrian Alonso /* Base address for this IP block is 0x02184800 */ 18435554fc9SAdrian Alonso struct usbnc_regs { 18535554fc9SAdrian Alonso u32 ctrl[4]; /* otg/host1-3 */ 18635554fc9SAdrian Alonso u32 uh2_hsic_ctrl; 18735554fc9SAdrian Alonso u32 uh3_hsic_ctrl; 18835554fc9SAdrian Alonso u32 otg_phy_ctrl_0; 18935554fc9SAdrian Alonso u32 uh1_phy_ctrl_0; 19035554fc9SAdrian Alonso }; 19135554fc9SAdrian Alonso #elif defined(CONFIG_MX7) 19235554fc9SAdrian Alonso struct usbnc_regs { 19335554fc9SAdrian Alonso u32 ctrl1; 19435554fc9SAdrian Alonso u32 ctrl2; 19535554fc9SAdrian Alonso u32 reserve1[10]; 19635554fc9SAdrian Alonso u32 phy_cfg1; 19735554fc9SAdrian Alonso u32 phy_cfg2; 198429ff447SPeng Fan u32 reserve2; 19935554fc9SAdrian Alonso u32 phy_status; 200429ff447SPeng Fan u32 reserve3[4]; 20135554fc9SAdrian Alonso u32 adp_cfg1; 20235554fc9SAdrian Alonso u32 adp_cfg2; 20335554fc9SAdrian Alonso u32 adp_status; 20435554fc9SAdrian Alonso }; 20535554fc9SAdrian Alonso 20635554fc9SAdrian Alonso static void usb_power_config(int index) 20735554fc9SAdrian Alonso { 20835554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 20935554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET); 21035554fc9SAdrian Alonso void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2); 2119a88180bSStefan Agner void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); 21235554fc9SAdrian Alonso 21357de41e9SPeng Fan /* 21457de41e9SPeng Fan * Clear the ACAENB to enable usb_otg_id detection, 21557de41e9SPeng Fan * otherwise it is the ACA detection enabled. 21657de41e9SPeng Fan */ 21757de41e9SPeng Fan clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB); 2189a88180bSStefan Agner 2199a88180bSStefan Agner /* Set power polarity to high active */ 220c4483093SStefan Agner #ifdef CONFIG_MXC_USB_OTG_HACTIVE 2219a88180bSStefan Agner setbits_le32(ctrl, UCTRL_PWR_POL); 222c4483093SStefan Agner #else 223c4483093SStefan Agner clrbits_le32(ctrl, UCTRL_PWR_POL); 224c4483093SStefan Agner #endif 22535554fc9SAdrian Alonso } 22635554fc9SAdrian Alonso 22735554fc9SAdrian Alonso int usb_phy_mode(int port) 22835554fc9SAdrian Alonso { 22935554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 23035554fc9SAdrian Alonso (0x10000 * port) + USBNC_OFFSET); 23135554fc9SAdrian Alonso void __iomem *status = (void __iomem *)(&usbnc->phy_status); 23235554fc9SAdrian Alonso u32 val; 23335554fc9SAdrian Alonso 23435554fc9SAdrian Alonso val = readl(status); 23535554fc9SAdrian Alonso 23635554fc9SAdrian Alonso if (val & USBNC_PHYSTATUS_ID_DIG) 23735554fc9SAdrian Alonso return USB_INIT_DEVICE; 23835554fc9SAdrian Alonso else 23935554fc9SAdrian Alonso return USB_INIT_HOST; 24035554fc9SAdrian Alonso } 24135554fc9SAdrian Alonso #endif 24235554fc9SAdrian Alonso 24335554fc9SAdrian Alonso static void usb_oc_config(int index) 24435554fc9SAdrian Alonso { 24535554fc9SAdrian Alonso #if defined(CONFIG_MX6) 24635554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 24735554fc9SAdrian Alonso USB_OTHERREGS_OFFSET); 24835554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]); 24935554fc9SAdrian Alonso #elif defined(CONFIG_MX7) 25035554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 25135554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET); 25235554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); 25335554fc9SAdrian Alonso #endif 25435554fc9SAdrian Alonso 25535554fc9SAdrian Alonso #if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2 25635554fc9SAdrian Alonso /* mx6qarm2 seems to required a different setting*/ 25735554fc9SAdrian Alonso clrbits_le32(ctrl, UCTRL_OVER_CUR_POL); 25835554fc9SAdrian Alonso #else 25935554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_POL); 26035554fc9SAdrian Alonso #endif 26135554fc9SAdrian Alonso 26235554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); 26335554fc9SAdrian Alonso } 26435554fc9SAdrian Alonso 26574f0610eSAdrian Alonso /** 26679d867c2SStefan Agner * board_usb_phy_mode - override usb phy mode 26774f0610eSAdrian Alonso * @port: usb host/otg port 26874f0610eSAdrian Alonso * 26974f0610eSAdrian Alonso * Target board specific, override usb_phy_mode. 27074f0610eSAdrian Alonso * When usb-otg is used as usb host port, iomux pad usb_otg_id can be 27174f0610eSAdrian Alonso * left disconnected in this case usb_phy_mode will not be able to identify 27274f0610eSAdrian Alonso * the phy mode that usb port is used. 27374f0610eSAdrian Alonso * Machine file overrides board_usb_phy_mode. 27474f0610eSAdrian Alonso * 27574f0610eSAdrian Alonso * Return: USB_INIT_DEVICE or USB_INIT_HOST 27674f0610eSAdrian Alonso */ 277229dbba9SPeng Fan int __weak board_usb_phy_mode(int port) 278229dbba9SPeng Fan { 279229dbba9SPeng Fan return usb_phy_mode(port); 280229dbba9SPeng Fan } 281229dbba9SPeng Fan 28274f0610eSAdrian Alonso /** 28374f0610eSAdrian Alonso * board_ehci_hcd_init - set usb vbus voltage 28474f0610eSAdrian Alonso * @port: usb otg port 28574f0610eSAdrian Alonso * 28674f0610eSAdrian Alonso * Target board specific, setup iomux pad to setup supply vbus voltage 28774f0610eSAdrian Alonso * for usb otg port. Machine board file overrides board_ehci_hcd_init 28874f0610eSAdrian Alonso * 28974f0610eSAdrian Alonso * Return: 0 Success 29074f0610eSAdrian Alonso */ 291f22e4faeSBenoît Thébaudeau int __weak board_ehci_hcd_init(int port) 292f22e4faeSBenoît Thébaudeau { 293f22e4faeSBenoît Thébaudeau return 0; 294f22e4faeSBenoît Thébaudeau } 295f22e4faeSBenoît Thébaudeau 29674f0610eSAdrian Alonso /** 29774f0610eSAdrian Alonso * board_ehci_power - enables/disables usb vbus voltage 29874f0610eSAdrian Alonso * @port: usb otg port 29974f0610eSAdrian Alonso * @on: on/off vbus voltage 30074f0610eSAdrian Alonso * 30174f0610eSAdrian Alonso * Enables/disables supply vbus voltage for usb otg port. 30274f0610eSAdrian Alonso * Machine board file overrides board_ehci_power 30374f0610eSAdrian Alonso * 30474f0610eSAdrian Alonso * Return: 0 Success 30574f0610eSAdrian Alonso */ 306d1a52860STroy Kisky int __weak board_ehci_power(int port, int on) 307d1a52860STroy Kisky { 308d1a52860STroy Kisky return 0; 309d1a52860STroy Kisky } 310d1a52860STroy Kisky 311*bb42fb4fSPeng Fan int ehci_mx6_common_init(struct usb_ehci *ehci, int index) 3123f467529SWolfgang Grandegger { 31379d867c2SStefan Agner int ret; 3143f467529SWolfgang Grandegger 3153f467529SWolfgang Grandegger enable_usboh3_clk(1); 3163f467529SWolfgang Grandegger mdelay(1); 3173f467529SWolfgang Grandegger 3183f467529SWolfgang Grandegger /* Do board specific initialization */ 31979d867c2SStefan Agner ret = board_ehci_hcd_init(index); 32079d867c2SStefan Agner if (ret) 32179d867c2SStefan Agner return ret; 3223f467529SWolfgang Grandegger 323d1a52860STroy Kisky usb_power_config(index); 324d1a52860STroy Kisky usb_oc_config(index); 32535554fc9SAdrian Alonso 32635554fc9SAdrian Alonso #if defined(CONFIG_MX6) 327d1a52860STroy Kisky usb_internal_phy_clock_gate(index, 1); 328229dbba9SPeng Fan usb_phy_enable(index, ehci); 32935554fc9SAdrian Alonso #endif 330*bb42fb4fSPeng Fan 331*bb42fb4fSPeng Fan return 0; 332*bb42fb4fSPeng Fan } 333*bb42fb4fSPeng Fan 334*bb42fb4fSPeng Fan #ifndef CONFIG_DM_USB 335*bb42fb4fSPeng Fan int ehci_hcd_init(int index, enum usb_init_type init, 336*bb42fb4fSPeng Fan struct ehci_hccr **hccr, struct ehci_hcor **hcor) 337*bb42fb4fSPeng Fan { 338*bb42fb4fSPeng Fan enum usb_init_type type; 339*bb42fb4fSPeng Fan #if defined(CONFIG_MX6) 340*bb42fb4fSPeng Fan u32 controller_spacing = 0x200; 341*bb42fb4fSPeng Fan #elif defined(CONFIG_MX7) 342*bb42fb4fSPeng Fan u32 controller_spacing = 0x10000; 343*bb42fb4fSPeng Fan #endif 344*bb42fb4fSPeng Fan struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR + 345*bb42fb4fSPeng Fan (controller_spacing * index)); 346*bb42fb4fSPeng Fan int ret; 347*bb42fb4fSPeng Fan 348*bb42fb4fSPeng Fan if (index > 3) 349*bb42fb4fSPeng Fan return -EINVAL; 350*bb42fb4fSPeng Fan 351*bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, index); 352*bb42fb4fSPeng Fan if (ret) 353*bb42fb4fSPeng Fan return ret; 354*bb42fb4fSPeng Fan 355229dbba9SPeng Fan type = board_usb_phy_mode(index); 3563f467529SWolfgang Grandegger 357*bb42fb4fSPeng Fan if (hccr && hcor) { 358676ae068SLucas Stach *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 359676ae068SLucas Stach *hcor = (struct ehci_hcor *)((uint32_t)*hccr + 360676ae068SLucas Stach HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 361*bb42fb4fSPeng Fan } 3623f467529SWolfgang Grandegger 363d1a52860STroy Kisky if ((type == init) || (type == USB_INIT_DEVICE)) 364d1a52860STroy Kisky board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1); 365d1a52860STroy Kisky if (type != init) 366d1a52860STroy Kisky return -ENODEV; 367d1a52860STroy Kisky if (type == USB_INIT_DEVICE) 368d1a52860STroy Kisky return 0; 36935554fc9SAdrian Alonso 370d1a52860STroy Kisky setbits_le32(&ehci->usbmode, CM_HOST); 371e38ff30aSAdrian Alonso writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 3723f467529SWolfgang Grandegger setbits_le32(&ehci->portsc, USB_EN); 3733f467529SWolfgang Grandegger 3743f467529SWolfgang Grandegger mdelay(10); 3753f467529SWolfgang Grandegger 3763f467529SWolfgang Grandegger return 0; 3773f467529SWolfgang Grandegger } 3783f467529SWolfgang Grandegger 379676ae068SLucas Stach int ehci_hcd_stop(int index) 3803f467529SWolfgang Grandegger { 3813f467529SWolfgang Grandegger return 0; 3823f467529SWolfgang Grandegger } 383*bb42fb4fSPeng Fan #else 384*bb42fb4fSPeng Fan struct ehci_mx6_priv_data { 385*bb42fb4fSPeng Fan struct ehci_ctrl ctrl; 386*bb42fb4fSPeng Fan struct usb_ehci *ehci; 387*bb42fb4fSPeng Fan enum usb_init_type init_type; 388*bb42fb4fSPeng Fan int portnr; 389*bb42fb4fSPeng Fan }; 390*bb42fb4fSPeng Fan 391*bb42fb4fSPeng Fan static int mx6_init_after_reset(struct ehci_ctrl *dev) 392*bb42fb4fSPeng Fan { 393*bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev->priv; 394*bb42fb4fSPeng Fan enum usb_init_type type = priv->init_type; 395*bb42fb4fSPeng Fan struct usb_ehci *ehci = priv->ehci; 396*bb42fb4fSPeng Fan int ret; 397*bb42fb4fSPeng Fan 398*bb42fb4fSPeng Fan ret = ehci_mx6_common_init(priv->ehci, priv->portnr); 399*bb42fb4fSPeng Fan if (ret) 400*bb42fb4fSPeng Fan return ret; 401*bb42fb4fSPeng Fan 402*bb42fb4fSPeng Fan board_ehci_power(priv->portnr, (type == USB_INIT_DEVICE) ? 0 : 1); 403*bb42fb4fSPeng Fan 404*bb42fb4fSPeng Fan if (type == USB_INIT_DEVICE) 405*bb42fb4fSPeng Fan return 0; 406*bb42fb4fSPeng Fan 407*bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 408*bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 409*bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 410*bb42fb4fSPeng Fan 411*bb42fb4fSPeng Fan mdelay(10); 412*bb42fb4fSPeng Fan 413*bb42fb4fSPeng Fan return 0; 414*bb42fb4fSPeng Fan } 415*bb42fb4fSPeng Fan 416*bb42fb4fSPeng Fan static const struct ehci_ops mx6_ehci_ops = { 417*bb42fb4fSPeng Fan .init_after_reset = mx6_init_after_reset 418*bb42fb4fSPeng Fan }; 419*bb42fb4fSPeng Fan 420*bb42fb4fSPeng Fan static int ehci_usb_probe(struct udevice *dev) 421*bb42fb4fSPeng Fan { 422*bb42fb4fSPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 423*bb42fb4fSPeng Fan struct usb_ehci *ehci = (struct usb_ehci *)dev_get_addr(dev); 424*bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev_get_priv(dev); 425*bb42fb4fSPeng Fan struct ehci_hccr *hccr; 426*bb42fb4fSPeng Fan struct ehci_hcor *hcor; 427*bb42fb4fSPeng Fan int ret; 428*bb42fb4fSPeng Fan 429*bb42fb4fSPeng Fan priv->ehci = ehci; 430*bb42fb4fSPeng Fan priv->portnr = dev->seq; 431*bb42fb4fSPeng Fan priv->init_type = plat->init_type; 432*bb42fb4fSPeng Fan 433*bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, priv->portnr); 434*bb42fb4fSPeng Fan if (ret) 435*bb42fb4fSPeng Fan return ret; 436*bb42fb4fSPeng Fan 437*bb42fb4fSPeng Fan board_ehci_power(priv->portnr, (priv->init_type == USB_INIT_DEVICE) ? 0 : 1); 438*bb42fb4fSPeng Fan 439*bb42fb4fSPeng Fan if (priv->init_type == USB_INIT_HOST) { 440*bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 441*bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 442*bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 443*bb42fb4fSPeng Fan } 444*bb42fb4fSPeng Fan 445*bb42fb4fSPeng Fan mdelay(10); 446*bb42fb4fSPeng Fan 447*bb42fb4fSPeng Fan hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 448*bb42fb4fSPeng Fan hcor = (struct ehci_hcor *)((uint32_t)hccr + 449*bb42fb4fSPeng Fan HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); 450*bb42fb4fSPeng Fan 451*bb42fb4fSPeng Fan return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type); 452*bb42fb4fSPeng Fan } 453*bb42fb4fSPeng Fan 454*bb42fb4fSPeng Fan static int ehci_usb_remove(struct udevice *dev) 455*bb42fb4fSPeng Fan { 456*bb42fb4fSPeng Fan int ret; 457*bb42fb4fSPeng Fan 458*bb42fb4fSPeng Fan ret = ehci_deregister(dev); 459*bb42fb4fSPeng Fan if (ret) 460*bb42fb4fSPeng Fan return ret; 461*bb42fb4fSPeng Fan 462*bb42fb4fSPeng Fan return 0; 463*bb42fb4fSPeng Fan } 464*bb42fb4fSPeng Fan 465*bb42fb4fSPeng Fan static const struct udevice_id mx6_usb_ids[] = { 466*bb42fb4fSPeng Fan { .compatible = "fsl,imx27-usb" }, 467*bb42fb4fSPeng Fan { } 468*bb42fb4fSPeng Fan }; 469*bb42fb4fSPeng Fan 470*bb42fb4fSPeng Fan U_BOOT_DRIVER(usb_mx6) = { 471*bb42fb4fSPeng Fan .name = "ehci_mx6", 472*bb42fb4fSPeng Fan .id = UCLASS_USB, 473*bb42fb4fSPeng Fan .of_match = mx6_usb_ids, 474*bb42fb4fSPeng Fan .probe = ehci_usb_probe, 475*bb42fb4fSPeng Fan .remove = ehci_usb_remove, 476*bb42fb4fSPeng Fan .ops = &ehci_usb_ops, 477*bb42fb4fSPeng Fan .platdata_auto_alloc_size = sizeof(struct usb_platdata), 478*bb42fb4fSPeng Fan .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data), 479*bb42fb4fSPeng Fan .flags = DM_FLAG_ALLOC_PRIV_DMA, 480*bb42fb4fSPeng Fan }; 481*bb42fb4fSPeng Fan #endif 482