11ca56202SWolfgang Grandegger /* 21ca56202SWolfgang Grandegger * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> 31ca56202SWolfgang Grandegger * Copyright (C) 2010 Freescale Semiconductor, Inc. 41ca56202SWolfgang Grandegger * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 61ca56202SWolfgang Grandegger */ 71ca56202SWolfgang Grandegger 81ca56202SWolfgang Grandegger #include <common.h> 91ca56202SWolfgang Grandegger #include <usb.h> 101ca56202SWolfgang Grandegger #include <errno.h> 111ca56202SWolfgang Grandegger #include <linux/compiler.h> 12e162c6b1SMateusz Kulikowski #include <usb/ehci-ci.h> 131ca56202SWolfgang Grandegger #include <asm/io.h> 141ca56202SWolfgang Grandegger #include <asm/arch/imx-regs.h> 151ca56202SWolfgang Grandegger #include <asm/arch/clock.h> 16*0163d8d8SLukasz Majewski #include <dm.h> 17*0163d8d8SLukasz Majewski #include <power/regulator.h> 181ca56202SWolfgang Grandegger 191ca56202SWolfgang Grandegger #include "ehci.h" 201ca56202SWolfgang Grandegger 211ca56202SWolfgang Grandegger #define MX5_USBOTHER_REGS_OFFSET 0x800 221ca56202SWolfgang Grandegger 231ca56202SWolfgang Grandegger 241ca56202SWolfgang Grandegger #define MXC_OTG_OFFSET 0 251ca56202SWolfgang Grandegger #define MXC_H1_OFFSET 0x200 261ca56202SWolfgang Grandegger #define MXC_H2_OFFSET 0x400 272cfe0b8fSBenoît Thébaudeau #define MXC_H3_OFFSET 0x600 281ca56202SWolfgang Grandegger 291ca56202SWolfgang Grandegger #define MXC_USBCTRL_OFFSET 0 301ca56202SWolfgang Grandegger #define MXC_USB_PHY_CTR_FUNC_OFFSET 0x8 311ca56202SWolfgang Grandegger #define MXC_USB_PHY_CTR_FUNC2_OFFSET 0xc 321ca56202SWolfgang Grandegger #define MXC_USB_CTRL_1_OFFSET 0x10 331ca56202SWolfgang Grandegger #define MXC_USBH2CTRL_OFFSET 0x14 342cfe0b8fSBenoît Thébaudeau #define MXC_USBH3CTRL_OFFSET 0x18 351ca56202SWolfgang Grandegger 361ca56202SWolfgang Grandegger /* USB_CTRL */ 37bdc52020SBenoît Thébaudeau /* OTG wakeup intr enable */ 38bdc52020SBenoît Thébaudeau #define MXC_OTG_UCTRL_OWIE_BIT (1 << 27) 39bdc52020SBenoît Thébaudeau /* OTG power mask */ 40bdc52020SBenoît Thébaudeau #define MXC_OTG_UCTRL_OPM_BIT (1 << 24) 4131ac2d0cSBenoît Thébaudeau /* OTG power pin polarity */ 4231ac2d0cSBenoît Thébaudeau #define MXC_OTG_UCTRL_O_PWR_POL_BIT (1 << 24) 43bdc52020SBenoît Thébaudeau /* Host1 ULPI interrupt enable */ 44bdc52020SBenoît Thébaudeau #define MXC_H1_UCTRL_H1UIE_BIT (1 << 12) 45bdc52020SBenoît Thébaudeau /* HOST1 wakeup intr enable */ 46bdc52020SBenoît Thébaudeau #define MXC_H1_UCTRL_H1WIE_BIT (1 << 11) 47bdc52020SBenoît Thébaudeau /* HOST1 power mask */ 48bdc52020SBenoît Thébaudeau #define MXC_H1_UCTRL_H1PM_BIT (1 << 8) 4931ac2d0cSBenoît Thébaudeau /* HOST1 power pin polarity */ 5031ac2d0cSBenoît Thébaudeau #define MXC_H1_UCTRL_H1_PWR_POL_BIT (1 << 8) 511ca56202SWolfgang Grandegger 521ca56202SWolfgang Grandegger /* USB_PHY_CTRL_FUNC */ 5331ac2d0cSBenoît Thébaudeau /* OTG Polarity of Overcurrent */ 5431ac2d0cSBenoît Thébaudeau #define MXC_OTG_PHYCTRL_OC_POL_BIT (1 << 9) 55bdc52020SBenoît Thébaudeau /* OTG Disable Overcurrent Event */ 56bdc52020SBenoît Thébaudeau #define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) 5731ac2d0cSBenoît Thébaudeau /* UH1 Polarity of Overcurrent */ 5831ac2d0cSBenoît Thébaudeau #define MXC_H1_OC_POL_BIT (1 << 6) 59bdc52020SBenoît Thébaudeau /* UH1 Disable Overcurrent Event */ 60bdc52020SBenoît Thébaudeau #define MXC_H1_OC_DIS_BIT (1 << 5) 6131ac2d0cSBenoît Thébaudeau /* OTG Power Pin Polarity */ 6231ac2d0cSBenoît Thébaudeau #define MXC_OTG_PHYCTRL_PWR_POL_BIT (1 << 3) 631ca56202SWolfgang Grandegger 641ca56202SWolfgang Grandegger /* USBH2CTRL */ 6531ac2d0cSBenoît Thébaudeau #define MXC_H2_UCTRL_H2_OC_POL_BIT (1 << 31) 662cfe0b8fSBenoît Thébaudeau #define MXC_H2_UCTRL_H2_OC_DIS_BIT (1 << 30) 671ca56202SWolfgang Grandegger #define MXC_H2_UCTRL_H2UIE_BIT (1 << 8) 681ca56202SWolfgang Grandegger #define MXC_H2_UCTRL_H2WIE_BIT (1 << 7) 691ca56202SWolfgang Grandegger #define MXC_H2_UCTRL_H2PM_BIT (1 << 4) 7031ac2d0cSBenoît Thébaudeau #define MXC_H2_UCTRL_H2_PWR_POL_BIT (1 << 4) 711ca56202SWolfgang Grandegger 722cfe0b8fSBenoît Thébaudeau /* USBH3CTRL */ 7331ac2d0cSBenoît Thébaudeau #define MXC_H3_UCTRL_H3_OC_POL_BIT (1 << 31) 742cfe0b8fSBenoît Thébaudeau #define MXC_H3_UCTRL_H3_OC_DIS_BIT (1 << 30) 752cfe0b8fSBenoît Thébaudeau #define MXC_H3_UCTRL_H3UIE_BIT (1 << 8) 762cfe0b8fSBenoît Thébaudeau #define MXC_H3_UCTRL_H3WIE_BIT (1 << 7) 7731ac2d0cSBenoît Thébaudeau #define MXC_H3_UCTRL_H3_PWR_POL_BIT (1 << 4) 782cfe0b8fSBenoît Thébaudeau 791ca56202SWolfgang Grandegger /* USB_CTRL_1 */ 801ca56202SWolfgang Grandegger #define MXC_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) 811ca56202SWolfgang Grandegger 821ca56202SWolfgang Grandegger int mxc_set_usbcontrol(int port, unsigned int flags) 831ca56202SWolfgang Grandegger { 841ca56202SWolfgang Grandegger unsigned int v; 851ca56202SWolfgang Grandegger void __iomem *usb_base = (void __iomem *)OTG_BASE_ADDR; 861ca56202SWolfgang Grandegger void __iomem *usbother_base; 871ca56202SWolfgang Grandegger int ret = 0; 881ca56202SWolfgang Grandegger 891ca56202SWolfgang Grandegger usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; 901ca56202SWolfgang Grandegger 911ca56202SWolfgang Grandegger switch (port) { 921ca56202SWolfgang Grandegger case 0: /* OTG port */ 931ca56202SWolfgang Grandegger if (flags & MXC_EHCI_INTERNAL_PHY) { 941ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + 951ca56202SWolfgang Grandegger MXC_USB_PHY_CTR_FUNC_OFFSET); 9631ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 9731ac2d0cSBenoît Thébaudeau v |= MXC_OTG_PHYCTRL_OC_POL_BIT; 9831ac2d0cSBenoît Thébaudeau else 9931ac2d0cSBenoît Thébaudeau v &= ~MXC_OTG_PHYCTRL_OC_POL_BIT; 1001ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1011ca56202SWolfgang Grandegger /* OC/USBPWR is used */ 1021ca56202SWolfgang Grandegger v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT; 1037d42432dSBenoît Thébaudeau else 1047d42432dSBenoît Thébaudeau /* OC/USBPWR is not used */ 1057d42432dSBenoît Thébaudeau v |= MXC_OTG_PHYCTRL_OC_DIS_BIT; 10631ac2d0cSBenoît Thébaudeau #ifdef CONFIG_MX51 10731ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 10831ac2d0cSBenoît Thébaudeau v |= MXC_OTG_PHYCTRL_PWR_POL_BIT; 10931ac2d0cSBenoît Thébaudeau else 11031ac2d0cSBenoît Thébaudeau v &= ~MXC_OTG_PHYCTRL_PWR_POL_BIT; 11131ac2d0cSBenoît Thébaudeau #endif 1121ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + 1131ca56202SWolfgang Grandegger MXC_USB_PHY_CTR_FUNC_OFFSET); 1141ca56202SWolfgang Grandegger 1151ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET); 116661052f4SBenoît Thébaudeau #ifdef CONFIG_MX51 1171ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1181ca56202SWolfgang Grandegger v &= ~MXC_OTG_UCTRL_OPM_BIT; 119394c00dcSBenoît Thébaudeau else 120394c00dcSBenoît Thébaudeau v |= MXC_OTG_UCTRL_OPM_BIT; 121661052f4SBenoît Thébaudeau #endif 12231ac2d0cSBenoît Thébaudeau #ifdef CONFIG_MX53 12331ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 12431ac2d0cSBenoît Thébaudeau v |= MXC_OTG_UCTRL_O_PWR_POL_BIT; 12531ac2d0cSBenoît Thébaudeau else 12631ac2d0cSBenoît Thébaudeau v &= ~MXC_OTG_UCTRL_O_PWR_POL_BIT; 12731ac2d0cSBenoît Thébaudeau #endif 1281ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET); 1291ca56202SWolfgang Grandegger } 1301ca56202SWolfgang Grandegger break; 131bdc52020SBenoît Thébaudeau case 1: /* Host 1 ULPI */ 1321ca56202SWolfgang Grandegger #ifdef CONFIG_MX51 1331ca56202SWolfgang Grandegger /* The clock for the USBH1 ULPI port will come externally 1341ca56202SWolfgang Grandegger from the PHY. */ 1351ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USB_CTRL_1_OFFSET); 1361ca56202SWolfgang Grandegger __raw_writel(v | MXC_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + 1371ca56202SWolfgang Grandegger MXC_USB_CTRL_1_OFFSET); 1381ca56202SWolfgang Grandegger #endif 1391ca56202SWolfgang Grandegger 1401ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET); 141661052f4SBenoît Thébaudeau #ifdef CONFIG_MX51 1421ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 143bdc52020SBenoît Thébaudeau v &= ~MXC_H1_UCTRL_H1PM_BIT; /* H1 power mask unused */ 1441ca56202SWolfgang Grandegger else 145bdc52020SBenoît Thébaudeau v |= MXC_H1_UCTRL_H1PM_BIT; /* H1 power mask used */ 146661052f4SBenoît Thébaudeau #endif 14731ac2d0cSBenoît Thébaudeau #ifdef CONFIG_MX53 14831ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 14931ac2d0cSBenoît Thébaudeau v |= MXC_H1_UCTRL_H1_PWR_POL_BIT; 15031ac2d0cSBenoît Thébaudeau else 15131ac2d0cSBenoît Thébaudeau v &= ~MXC_H1_UCTRL_H1_PWR_POL_BIT; 15231ac2d0cSBenoît Thébaudeau #endif 1531ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET); 1541ca56202SWolfgang Grandegger 1551ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); 15631ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 15731ac2d0cSBenoît Thébaudeau v |= MXC_H1_OC_POL_BIT; 15831ac2d0cSBenoît Thébaudeau else 15931ac2d0cSBenoît Thébaudeau v &= ~MXC_H1_OC_POL_BIT; 1601ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1611ca56202SWolfgang Grandegger v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */ 1621ca56202SWolfgang Grandegger else 1631ca56202SWolfgang Grandegger v |= MXC_H1_OC_DIS_BIT; /* OC is not used */ 1641ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); 1651ca56202SWolfgang Grandegger 1661ca56202SWolfgang Grandegger break; 1671ca56202SWolfgang Grandegger case 2: /* Host 2 ULPI */ 1681ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET); 169661052f4SBenoît Thébaudeau #ifdef CONFIG_MX51 1701ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 171bdc52020SBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2PM_BIT; /* H2 power mask unused */ 1721ca56202SWolfgang Grandegger else 173bdc52020SBenoît Thébaudeau v |= MXC_H2_UCTRL_H2PM_BIT; /* H2 power mask used */ 174661052f4SBenoît Thébaudeau #endif 1752cfe0b8fSBenoît Thébaudeau #ifdef CONFIG_MX53 17631ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 17731ac2d0cSBenoît Thébaudeau v |= MXC_H2_UCTRL_H2_OC_POL_BIT; 17831ac2d0cSBenoît Thébaudeau else 17931ac2d0cSBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2_OC_POL_BIT; 1802cfe0b8fSBenoît Thébaudeau if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1812cfe0b8fSBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2_OC_DIS_BIT; /* OC is used */ 1822cfe0b8fSBenoît Thébaudeau else 1832cfe0b8fSBenoît Thébaudeau v |= MXC_H2_UCTRL_H2_OC_DIS_BIT; /* OC is not used */ 18431ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 18531ac2d0cSBenoît Thébaudeau v |= MXC_H2_UCTRL_H2_PWR_POL_BIT; 18631ac2d0cSBenoît Thébaudeau else 18731ac2d0cSBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2_PWR_POL_BIT; 1882cfe0b8fSBenoît Thébaudeau #endif 1891ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET); 1901ca56202SWolfgang Grandegger break; 1912cfe0b8fSBenoît Thébaudeau #ifdef CONFIG_MX53 1922cfe0b8fSBenoît Thébaudeau case 3: /* Host 3 ULPI */ 1932cfe0b8fSBenoît Thébaudeau v = __raw_readl(usbother_base + MXC_USBH3CTRL_OFFSET); 19431ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 19531ac2d0cSBenoît Thébaudeau v |= MXC_H3_UCTRL_H3_OC_POL_BIT; 19631ac2d0cSBenoît Thébaudeau else 19731ac2d0cSBenoît Thébaudeau v &= ~MXC_H3_UCTRL_H3_OC_POL_BIT; 1982cfe0b8fSBenoît Thébaudeau if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1992cfe0b8fSBenoît Thébaudeau v &= ~MXC_H3_UCTRL_H3_OC_DIS_BIT; /* OC is used */ 2002cfe0b8fSBenoît Thébaudeau else 2012cfe0b8fSBenoît Thébaudeau v |= MXC_H3_UCTRL_H3_OC_DIS_BIT; /* OC is not used */ 20231ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 20331ac2d0cSBenoît Thébaudeau v |= MXC_H3_UCTRL_H3_PWR_POL_BIT; 20431ac2d0cSBenoît Thébaudeau else 20531ac2d0cSBenoît Thébaudeau v &= ~MXC_H3_UCTRL_H3_PWR_POL_BIT; 2062cfe0b8fSBenoît Thébaudeau __raw_writel(v, usbother_base + MXC_USBH3CTRL_OFFSET); 2072cfe0b8fSBenoît Thébaudeau break; 2082cfe0b8fSBenoît Thébaudeau #endif 2091ca56202SWolfgang Grandegger } 2101ca56202SWolfgang Grandegger 2111ca56202SWolfgang Grandegger return ret; 2121ca56202SWolfgang Grandegger } 2131ca56202SWolfgang Grandegger 214f22e4faeSBenoît Thébaudeau int __weak board_ehci_hcd_init(int port) 2151b80f270SMarek Vasut { 216f22e4faeSBenoît Thébaudeau return 0; 2171b80f270SMarek Vasut } 2181b80f270SMarek Vasut 219f22e4faeSBenoît Thébaudeau void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port) 220f22e4faeSBenoît Thébaudeau { 221f22e4faeSBenoît Thébaudeau } 2221b80f270SMarek Vasut 223deb8508cSSimon Glass __weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg, 224deb8508cSSimon Glass uint32_t *reg) 225deb8508cSSimon Glass { 226deb8508cSSimon Glass mdelay(50); 227deb8508cSSimon Glass } 228deb8508cSSimon Glass 229*0163d8d8SLukasz Majewski #if !CONFIG_IS_ENABLED(DM_USB) 230deb8508cSSimon Glass static const struct ehci_ops mx5_ehci_ops = { 231deb8508cSSimon Glass .powerup_fixup = mx5_ehci_powerup_fixup, 232deb8508cSSimon Glass }; 233deb8508cSSimon Glass 234127efc4fSTroy Kisky int ehci_hcd_init(int index, enum usb_init_type init, 235127efc4fSTroy Kisky struct ehci_hccr **hccr, struct ehci_hcor **hcor) 2361ca56202SWolfgang Grandegger { 2371ca56202SWolfgang Grandegger struct usb_ehci *ehci; 2381ca56202SWolfgang Grandegger 239deb8508cSSimon Glass /* The only user for this is efikamx-usb */ 240deb8508cSSimon Glass ehci_set_controller_priv(index, NULL, &mx5_ehci_ops); 2411ca56202SWolfgang Grandegger set_usboh3_clk(); 24276b6b196SFabio Estevam enable_usboh3_clk(true); 243414e1660SBenoît Thébaudeau set_usb_phy_clk(); 24476b6b196SFabio Estevam enable_usb_phy1_clk(true); 24576b6b196SFabio Estevam enable_usb_phy2_clk(true); 2461ca56202SWolfgang Grandegger mdelay(1); 2471ca56202SWolfgang Grandegger 2481b80f270SMarek Vasut /* Do board specific initialization */ 2491ca56202SWolfgang Grandegger board_ehci_hcd_init(CONFIG_MXC_USB_PORT); 2501ca56202SWolfgang Grandegger 2511ca56202SWolfgang Grandegger ehci = (struct usb_ehci *)(OTG_BASE_ADDR + 2521ca56202SWolfgang Grandegger (0x200 * CONFIG_MXC_USB_PORT)); 253676ae068SLucas Stach *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 254676ae068SLucas Stach *hcor = (struct ehci_hcor *)((uint32_t)*hccr + 255676ae068SLucas Stach HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 2561ca56202SWolfgang Grandegger setbits_le32(&ehci->usbmode, CM_HOST); 2571ca56202SWolfgang Grandegger 2581ca56202SWolfgang Grandegger __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 2591ca56202SWolfgang Grandegger setbits_le32(&ehci->portsc, USB_EN); 2601ca56202SWolfgang Grandegger 2611ca56202SWolfgang Grandegger mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS); 2621ca56202SWolfgang Grandegger mdelay(10); 2631ca56202SWolfgang Grandegger 2641b80f270SMarek Vasut /* Do board specific post-initialization */ 2651b80f270SMarek Vasut board_ehci_hcd_postinit(ehci, CONFIG_MXC_USB_PORT); 2661b80f270SMarek Vasut 2671ca56202SWolfgang Grandegger return 0; 2681ca56202SWolfgang Grandegger } 2691ca56202SWolfgang Grandegger 270676ae068SLucas Stach int ehci_hcd_stop(int index) 2711ca56202SWolfgang Grandegger { 2721ca56202SWolfgang Grandegger return 0; 2731ca56202SWolfgang Grandegger } 274*0163d8d8SLukasz Majewski #else /* CONFIG_IS_ENABLED(DM_USB) */ 275*0163d8d8SLukasz Majewski struct ehci_mx5_priv_data { 276*0163d8d8SLukasz Majewski struct ehci_ctrl ctrl; 277*0163d8d8SLukasz Majewski struct usb_ehci *ehci; 278*0163d8d8SLukasz Majewski struct udevice *vbus_supply; 279*0163d8d8SLukasz Majewski enum usb_init_type init_type; 280*0163d8d8SLukasz Majewski int portnr; 281*0163d8d8SLukasz Majewski }; 282*0163d8d8SLukasz Majewski 283*0163d8d8SLukasz Majewski static const struct ehci_ops mx5_ehci_ops = { 284*0163d8d8SLukasz Majewski .powerup_fixup = mx5_ehci_powerup_fixup, 285*0163d8d8SLukasz Majewski }; 286*0163d8d8SLukasz Majewski 287*0163d8d8SLukasz Majewski static int ehci_usb_ofdata_to_platdata(struct udevice *dev) 288*0163d8d8SLukasz Majewski { 289*0163d8d8SLukasz Majewski struct usb_platdata *plat = dev_get_platdata(dev); 290*0163d8d8SLukasz Majewski const char *mode; 291*0163d8d8SLukasz Majewski 292*0163d8d8SLukasz Majewski mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL); 293*0163d8d8SLukasz Majewski if (mode) { 294*0163d8d8SLukasz Majewski if (strcmp(mode, "peripheral") == 0) 295*0163d8d8SLukasz Majewski plat->init_type = USB_INIT_DEVICE; 296*0163d8d8SLukasz Majewski else if (strcmp(mode, "host") == 0) 297*0163d8d8SLukasz Majewski plat->init_type = USB_INIT_HOST; 298*0163d8d8SLukasz Majewski else 299*0163d8d8SLukasz Majewski return -EINVAL; 300*0163d8d8SLukasz Majewski } 301*0163d8d8SLukasz Majewski 302*0163d8d8SLukasz Majewski return 0; 303*0163d8d8SLukasz Majewski } 304*0163d8d8SLukasz Majewski 305*0163d8d8SLukasz Majewski static int ehci_usb_probe(struct udevice *dev) 306*0163d8d8SLukasz Majewski { 307*0163d8d8SLukasz Majewski struct usb_platdata *plat = dev_get_platdata(dev); 308*0163d8d8SLukasz Majewski struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev); 309*0163d8d8SLukasz Majewski struct ehci_mx5_priv_data *priv = dev_get_priv(dev); 310*0163d8d8SLukasz Majewski enum usb_init_type type = plat->init_type; 311*0163d8d8SLukasz Majewski struct ehci_hccr *hccr; 312*0163d8d8SLukasz Majewski struct ehci_hcor *hcor; 313*0163d8d8SLukasz Majewski int ret; 314*0163d8d8SLukasz Majewski 315*0163d8d8SLukasz Majewski set_usboh3_clk(); 316*0163d8d8SLukasz Majewski enable_usboh3_clk(true); 317*0163d8d8SLukasz Majewski set_usb_phy_clk(); 318*0163d8d8SLukasz Majewski enable_usb_phy1_clk(true); 319*0163d8d8SLukasz Majewski enable_usb_phy2_clk(true); 320*0163d8d8SLukasz Majewski mdelay(1); 321*0163d8d8SLukasz Majewski 322*0163d8d8SLukasz Majewski priv->ehci = ehci; 323*0163d8d8SLukasz Majewski priv->portnr = dev->seq; 324*0163d8d8SLukasz Majewski priv->init_type = type; 325*0163d8d8SLukasz Majewski 326*0163d8d8SLukasz Majewski ret = device_get_supply_regulator(dev, "vbus-supply", 327*0163d8d8SLukasz Majewski &priv->vbus_supply); 328*0163d8d8SLukasz Majewski if (ret) 329*0163d8d8SLukasz Majewski debug("%s: No vbus supply\n", dev->name); 330*0163d8d8SLukasz Majewski 331*0163d8d8SLukasz Majewski if (!ret && priv->vbus_supply) { 332*0163d8d8SLukasz Majewski ret = regulator_set_enable(priv->vbus_supply, 333*0163d8d8SLukasz Majewski (type == USB_INIT_DEVICE) ? 334*0163d8d8SLukasz Majewski false : true); 335*0163d8d8SLukasz Majewski if (ret) { 336*0163d8d8SLukasz Majewski puts("Error enabling VBUS supply\n"); 337*0163d8d8SLukasz Majewski return ret; 338*0163d8d8SLukasz Majewski } 339*0163d8d8SLukasz Majewski } 340*0163d8d8SLukasz Majewski 341*0163d8d8SLukasz Majewski hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 342*0163d8d8SLukasz Majewski hcor = (struct ehci_hcor *)((uint32_t)hccr + 343*0163d8d8SLukasz Majewski HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); 344*0163d8d8SLukasz Majewski setbits_le32(&ehci->usbmode, CM_HOST); 345*0163d8d8SLukasz Majewski 346*0163d8d8SLukasz Majewski __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 347*0163d8d8SLukasz Majewski setbits_le32(&ehci->portsc, USB_EN); 348*0163d8d8SLukasz Majewski 349*0163d8d8SLukasz Majewski mxc_set_usbcontrol(priv->portnr, CONFIG_MXC_USB_FLAGS); 350*0163d8d8SLukasz Majewski mdelay(10); 351*0163d8d8SLukasz Majewski 352*0163d8d8SLukasz Majewski return ehci_register(dev, hccr, hcor, &mx5_ehci_ops, 0, 353*0163d8d8SLukasz Majewski priv->init_type); 354*0163d8d8SLukasz Majewski } 355*0163d8d8SLukasz Majewski 356*0163d8d8SLukasz Majewski static const struct udevice_id mx5_usb_ids[] = { 357*0163d8d8SLukasz Majewski { .compatible = "fsl,imx53-usb" }, 358*0163d8d8SLukasz Majewski { } 359*0163d8d8SLukasz Majewski }; 360*0163d8d8SLukasz Majewski 361*0163d8d8SLukasz Majewski U_BOOT_DRIVER(usb_mx5) = { 362*0163d8d8SLukasz Majewski .name = "ehci_mx5", 363*0163d8d8SLukasz Majewski .id = UCLASS_USB, 364*0163d8d8SLukasz Majewski .of_match = mx5_usb_ids, 365*0163d8d8SLukasz Majewski .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, 366*0163d8d8SLukasz Majewski .probe = ehci_usb_probe, 367*0163d8d8SLukasz Majewski .remove = ehci_deregister, 368*0163d8d8SLukasz Majewski .ops = &ehci_usb_ops, 369*0163d8d8SLukasz Majewski .platdata_auto_alloc_size = sizeof(struct usb_platdata), 370*0163d8d8SLukasz Majewski .priv_auto_alloc_size = sizeof(struct ehci_mx5_priv_data), 371*0163d8d8SLukasz Majewski .flags = DM_FLAG_ALLOC_PRIV_DMA, 372*0163d8d8SLukasz Majewski }; 373*0163d8d8SLukasz Majewski #endif /* !CONFIG_IS_ENABLED(DM_USB) */ 374