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> 121ca56202SWolfgang Grandegger #include <usb/ehci-fsl.h> 131ca56202SWolfgang Grandegger #include <asm/io.h> 141ca56202SWolfgang Grandegger #include <asm/arch/imx-regs.h> 151ca56202SWolfgang Grandegger #include <asm/arch/clock.h> 161ca56202SWolfgang Grandegger 171ca56202SWolfgang Grandegger #include "ehci.h" 181ca56202SWolfgang Grandegger 191ca56202SWolfgang Grandegger #define MX5_USBOTHER_REGS_OFFSET 0x800 201ca56202SWolfgang Grandegger 211ca56202SWolfgang Grandegger 221ca56202SWolfgang Grandegger #define MXC_OTG_OFFSET 0 231ca56202SWolfgang Grandegger #define MXC_H1_OFFSET 0x200 241ca56202SWolfgang Grandegger #define MXC_H2_OFFSET 0x400 252cfe0b8fSBenoît Thébaudeau #define MXC_H3_OFFSET 0x600 261ca56202SWolfgang Grandegger 271ca56202SWolfgang Grandegger #define MXC_USBCTRL_OFFSET 0 281ca56202SWolfgang Grandegger #define MXC_USB_PHY_CTR_FUNC_OFFSET 0x8 291ca56202SWolfgang Grandegger #define MXC_USB_PHY_CTR_FUNC2_OFFSET 0xc 301ca56202SWolfgang Grandegger #define MXC_USB_CTRL_1_OFFSET 0x10 311ca56202SWolfgang Grandegger #define MXC_USBH2CTRL_OFFSET 0x14 322cfe0b8fSBenoît Thébaudeau #define MXC_USBH3CTRL_OFFSET 0x18 331ca56202SWolfgang Grandegger 341ca56202SWolfgang Grandegger /* USB_CTRL */ 35bdc52020SBenoît Thébaudeau /* OTG wakeup intr enable */ 36bdc52020SBenoît Thébaudeau #define MXC_OTG_UCTRL_OWIE_BIT (1 << 27) 37bdc52020SBenoît Thébaudeau /* OTG power mask */ 38bdc52020SBenoît Thébaudeau #define MXC_OTG_UCTRL_OPM_BIT (1 << 24) 3931ac2d0cSBenoît Thébaudeau /* OTG power pin polarity */ 4031ac2d0cSBenoît Thébaudeau #define MXC_OTG_UCTRL_O_PWR_POL_BIT (1 << 24) 41bdc52020SBenoît Thébaudeau /* Host1 ULPI interrupt enable */ 42bdc52020SBenoît Thébaudeau #define MXC_H1_UCTRL_H1UIE_BIT (1 << 12) 43bdc52020SBenoît Thébaudeau /* HOST1 wakeup intr enable */ 44bdc52020SBenoît Thébaudeau #define MXC_H1_UCTRL_H1WIE_BIT (1 << 11) 45bdc52020SBenoît Thébaudeau /* HOST1 power mask */ 46bdc52020SBenoît Thébaudeau #define MXC_H1_UCTRL_H1PM_BIT (1 << 8) 4731ac2d0cSBenoît Thébaudeau /* HOST1 power pin polarity */ 4831ac2d0cSBenoît Thébaudeau #define MXC_H1_UCTRL_H1_PWR_POL_BIT (1 << 8) 491ca56202SWolfgang Grandegger 501ca56202SWolfgang Grandegger /* USB_PHY_CTRL_FUNC */ 5131ac2d0cSBenoît Thébaudeau /* OTG Polarity of Overcurrent */ 5231ac2d0cSBenoît Thébaudeau #define MXC_OTG_PHYCTRL_OC_POL_BIT (1 << 9) 53bdc52020SBenoît Thébaudeau /* OTG Disable Overcurrent Event */ 54bdc52020SBenoît Thébaudeau #define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) 5531ac2d0cSBenoît Thébaudeau /* UH1 Polarity of Overcurrent */ 5631ac2d0cSBenoît Thébaudeau #define MXC_H1_OC_POL_BIT (1 << 6) 57bdc52020SBenoît Thébaudeau /* UH1 Disable Overcurrent Event */ 58bdc52020SBenoît Thébaudeau #define MXC_H1_OC_DIS_BIT (1 << 5) 5931ac2d0cSBenoît Thébaudeau /* OTG Power Pin Polarity */ 6031ac2d0cSBenoît Thébaudeau #define MXC_OTG_PHYCTRL_PWR_POL_BIT (1 << 3) 611ca56202SWolfgang Grandegger 621ca56202SWolfgang Grandegger /* USBH2CTRL */ 6331ac2d0cSBenoît Thébaudeau #define MXC_H2_UCTRL_H2_OC_POL_BIT (1 << 31) 642cfe0b8fSBenoît Thébaudeau #define MXC_H2_UCTRL_H2_OC_DIS_BIT (1 << 30) 651ca56202SWolfgang Grandegger #define MXC_H2_UCTRL_H2UIE_BIT (1 << 8) 661ca56202SWolfgang Grandegger #define MXC_H2_UCTRL_H2WIE_BIT (1 << 7) 671ca56202SWolfgang Grandegger #define MXC_H2_UCTRL_H2PM_BIT (1 << 4) 6831ac2d0cSBenoît Thébaudeau #define MXC_H2_UCTRL_H2_PWR_POL_BIT (1 << 4) 691ca56202SWolfgang Grandegger 702cfe0b8fSBenoît Thébaudeau /* USBH3CTRL */ 7131ac2d0cSBenoît Thébaudeau #define MXC_H3_UCTRL_H3_OC_POL_BIT (1 << 31) 722cfe0b8fSBenoît Thébaudeau #define MXC_H3_UCTRL_H3_OC_DIS_BIT (1 << 30) 732cfe0b8fSBenoît Thébaudeau #define MXC_H3_UCTRL_H3UIE_BIT (1 << 8) 742cfe0b8fSBenoît Thébaudeau #define MXC_H3_UCTRL_H3WIE_BIT (1 << 7) 7531ac2d0cSBenoît Thébaudeau #define MXC_H3_UCTRL_H3_PWR_POL_BIT (1 << 4) 762cfe0b8fSBenoît Thébaudeau 771ca56202SWolfgang Grandegger /* USB_CTRL_1 */ 781ca56202SWolfgang Grandegger #define MXC_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) 791ca56202SWolfgang Grandegger 801ca56202SWolfgang Grandegger int mxc_set_usbcontrol(int port, unsigned int flags) 811ca56202SWolfgang Grandegger { 821ca56202SWolfgang Grandegger unsigned int v; 831ca56202SWolfgang Grandegger void __iomem *usb_base = (void __iomem *)OTG_BASE_ADDR; 841ca56202SWolfgang Grandegger void __iomem *usbother_base; 851ca56202SWolfgang Grandegger int ret = 0; 861ca56202SWolfgang Grandegger 871ca56202SWolfgang Grandegger usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; 881ca56202SWolfgang Grandegger 891ca56202SWolfgang Grandegger switch (port) { 901ca56202SWolfgang Grandegger case 0: /* OTG port */ 911ca56202SWolfgang Grandegger if (flags & MXC_EHCI_INTERNAL_PHY) { 921ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + 931ca56202SWolfgang Grandegger MXC_USB_PHY_CTR_FUNC_OFFSET); 9431ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 9531ac2d0cSBenoît Thébaudeau v |= MXC_OTG_PHYCTRL_OC_POL_BIT; 9631ac2d0cSBenoît Thébaudeau else 9731ac2d0cSBenoît Thébaudeau v &= ~MXC_OTG_PHYCTRL_OC_POL_BIT; 981ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 991ca56202SWolfgang Grandegger /* OC/USBPWR is used */ 1001ca56202SWolfgang Grandegger v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT; 1017d42432dSBenoît Thébaudeau else 1027d42432dSBenoît Thébaudeau /* OC/USBPWR is not used */ 1037d42432dSBenoît Thébaudeau v |= MXC_OTG_PHYCTRL_OC_DIS_BIT; 10431ac2d0cSBenoît Thébaudeau #ifdef CONFIG_MX51 10531ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 10631ac2d0cSBenoît Thébaudeau v |= MXC_OTG_PHYCTRL_PWR_POL_BIT; 10731ac2d0cSBenoît Thébaudeau else 10831ac2d0cSBenoît Thébaudeau v &= ~MXC_OTG_PHYCTRL_PWR_POL_BIT; 10931ac2d0cSBenoît Thébaudeau #endif 1101ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + 1111ca56202SWolfgang Grandegger MXC_USB_PHY_CTR_FUNC_OFFSET); 1121ca56202SWolfgang Grandegger 1131ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET); 114661052f4SBenoît Thébaudeau #ifdef CONFIG_MX51 1151ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1161ca56202SWolfgang Grandegger v &= ~MXC_OTG_UCTRL_OPM_BIT; 117394c00dcSBenoît Thébaudeau else 118394c00dcSBenoît Thébaudeau v |= MXC_OTG_UCTRL_OPM_BIT; 119661052f4SBenoît Thébaudeau #endif 12031ac2d0cSBenoît Thébaudeau #ifdef CONFIG_MX53 12131ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 12231ac2d0cSBenoît Thébaudeau v |= MXC_OTG_UCTRL_O_PWR_POL_BIT; 12331ac2d0cSBenoît Thébaudeau else 12431ac2d0cSBenoît Thébaudeau v &= ~MXC_OTG_UCTRL_O_PWR_POL_BIT; 12531ac2d0cSBenoît Thébaudeau #endif 1261ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET); 1271ca56202SWolfgang Grandegger } 1281ca56202SWolfgang Grandegger break; 129bdc52020SBenoît Thébaudeau case 1: /* Host 1 ULPI */ 1301ca56202SWolfgang Grandegger #ifdef CONFIG_MX51 1311ca56202SWolfgang Grandegger /* The clock for the USBH1 ULPI port will come externally 1321ca56202SWolfgang Grandegger from the PHY. */ 1331ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USB_CTRL_1_OFFSET); 1341ca56202SWolfgang Grandegger __raw_writel(v | MXC_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + 1351ca56202SWolfgang Grandegger MXC_USB_CTRL_1_OFFSET); 1361ca56202SWolfgang Grandegger #endif 1371ca56202SWolfgang Grandegger 1381ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET); 139661052f4SBenoît Thébaudeau #ifdef CONFIG_MX51 1401ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 141bdc52020SBenoît Thébaudeau v &= ~MXC_H1_UCTRL_H1PM_BIT; /* H1 power mask unused */ 1421ca56202SWolfgang Grandegger else 143bdc52020SBenoît Thébaudeau v |= MXC_H1_UCTRL_H1PM_BIT; /* H1 power mask used */ 144661052f4SBenoît Thébaudeau #endif 14531ac2d0cSBenoît Thébaudeau #ifdef CONFIG_MX53 14631ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 14731ac2d0cSBenoît Thébaudeau v |= MXC_H1_UCTRL_H1_PWR_POL_BIT; 14831ac2d0cSBenoît Thébaudeau else 14931ac2d0cSBenoît Thébaudeau v &= ~MXC_H1_UCTRL_H1_PWR_POL_BIT; 15031ac2d0cSBenoît Thébaudeau #endif 1511ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET); 1521ca56202SWolfgang Grandegger 1531ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); 15431ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 15531ac2d0cSBenoît Thébaudeau v |= MXC_H1_OC_POL_BIT; 15631ac2d0cSBenoît Thébaudeau else 15731ac2d0cSBenoît Thébaudeau v &= ~MXC_H1_OC_POL_BIT; 1581ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1591ca56202SWolfgang Grandegger v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */ 1601ca56202SWolfgang Grandegger else 1611ca56202SWolfgang Grandegger v |= MXC_H1_OC_DIS_BIT; /* OC is not used */ 1621ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); 1631ca56202SWolfgang Grandegger 1641ca56202SWolfgang Grandegger break; 1651ca56202SWolfgang Grandegger case 2: /* Host 2 ULPI */ 1661ca56202SWolfgang Grandegger v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET); 167661052f4SBenoît Thébaudeau #ifdef CONFIG_MX51 1681ca56202SWolfgang Grandegger if (flags & MXC_EHCI_POWER_PINS_ENABLED) 169bdc52020SBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2PM_BIT; /* H2 power mask unused */ 1701ca56202SWolfgang Grandegger else 171bdc52020SBenoît Thébaudeau v |= MXC_H2_UCTRL_H2PM_BIT; /* H2 power mask used */ 172661052f4SBenoît Thébaudeau #endif 1732cfe0b8fSBenoît Thébaudeau #ifdef CONFIG_MX53 17431ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 17531ac2d0cSBenoît Thébaudeau v |= MXC_H2_UCTRL_H2_OC_POL_BIT; 17631ac2d0cSBenoît Thébaudeau else 17731ac2d0cSBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2_OC_POL_BIT; 1782cfe0b8fSBenoît Thébaudeau if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1792cfe0b8fSBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2_OC_DIS_BIT; /* OC is used */ 1802cfe0b8fSBenoît Thébaudeau else 1812cfe0b8fSBenoît Thébaudeau v |= MXC_H2_UCTRL_H2_OC_DIS_BIT; /* OC is not used */ 18231ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 18331ac2d0cSBenoît Thébaudeau v |= MXC_H2_UCTRL_H2_PWR_POL_BIT; 18431ac2d0cSBenoît Thébaudeau else 18531ac2d0cSBenoît Thébaudeau v &= ~MXC_H2_UCTRL_H2_PWR_POL_BIT; 1862cfe0b8fSBenoît Thébaudeau #endif 1871ca56202SWolfgang Grandegger __raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET); 1881ca56202SWolfgang Grandegger break; 1892cfe0b8fSBenoît Thébaudeau #ifdef CONFIG_MX53 1902cfe0b8fSBenoît Thébaudeau case 3: /* Host 3 ULPI */ 1912cfe0b8fSBenoît Thébaudeau v = __raw_readl(usbother_base + MXC_USBH3CTRL_OFFSET); 19231ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_OC_PIN_ACTIVE_LOW) 19331ac2d0cSBenoît Thébaudeau v |= MXC_H3_UCTRL_H3_OC_POL_BIT; 19431ac2d0cSBenoît Thébaudeau else 19531ac2d0cSBenoît Thébaudeau v &= ~MXC_H3_UCTRL_H3_OC_POL_BIT; 1962cfe0b8fSBenoît Thébaudeau if (flags & MXC_EHCI_POWER_PINS_ENABLED) 1972cfe0b8fSBenoît Thébaudeau v &= ~MXC_H3_UCTRL_H3_OC_DIS_BIT; /* OC is used */ 1982cfe0b8fSBenoît Thébaudeau else 1992cfe0b8fSBenoît Thébaudeau v |= MXC_H3_UCTRL_H3_OC_DIS_BIT; /* OC is not used */ 20031ac2d0cSBenoît Thébaudeau if (flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH) 20131ac2d0cSBenoît Thébaudeau v |= MXC_H3_UCTRL_H3_PWR_POL_BIT; 20231ac2d0cSBenoît Thébaudeau else 20331ac2d0cSBenoît Thébaudeau v &= ~MXC_H3_UCTRL_H3_PWR_POL_BIT; 2042cfe0b8fSBenoît Thébaudeau __raw_writel(v, usbother_base + MXC_USBH3CTRL_OFFSET); 2052cfe0b8fSBenoît Thébaudeau break; 2062cfe0b8fSBenoît Thébaudeau #endif 2071ca56202SWolfgang Grandegger } 2081ca56202SWolfgang Grandegger 2091ca56202SWolfgang Grandegger return ret; 2101ca56202SWolfgang Grandegger } 2111ca56202SWolfgang Grandegger 212f22e4faeSBenoît Thébaudeau int __weak board_ehci_hcd_init(int port) 2131b80f270SMarek Vasut { 214f22e4faeSBenoît Thébaudeau return 0; 2151b80f270SMarek Vasut } 2161b80f270SMarek Vasut 217f22e4faeSBenoît Thébaudeau void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port) 218f22e4faeSBenoît Thébaudeau { 219f22e4faeSBenoît Thébaudeau } 2201b80f270SMarek Vasut 221*127efc4fSTroy Kisky int ehci_hcd_init(int index, enum usb_init_type init, 222*127efc4fSTroy Kisky struct ehci_hccr **hccr, struct ehci_hcor **hcor) 2231ca56202SWolfgang Grandegger { 2241ca56202SWolfgang Grandegger struct usb_ehci *ehci; 2251ca56202SWolfgang Grandegger 2261ca56202SWolfgang Grandegger set_usboh3_clk(); 22776b6b196SFabio Estevam enable_usboh3_clk(true); 228414e1660SBenoît Thébaudeau set_usb_phy_clk(); 22976b6b196SFabio Estevam enable_usb_phy1_clk(true); 23076b6b196SFabio Estevam enable_usb_phy2_clk(true); 2311ca56202SWolfgang Grandegger mdelay(1); 2321ca56202SWolfgang Grandegger 2331b80f270SMarek Vasut /* Do board specific initialization */ 2341ca56202SWolfgang Grandegger board_ehci_hcd_init(CONFIG_MXC_USB_PORT); 2351ca56202SWolfgang Grandegger 2361ca56202SWolfgang Grandegger ehci = (struct usb_ehci *)(OTG_BASE_ADDR + 2371ca56202SWolfgang Grandegger (0x200 * CONFIG_MXC_USB_PORT)); 238676ae068SLucas Stach *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 239676ae068SLucas Stach *hcor = (struct ehci_hcor *)((uint32_t)*hccr + 240676ae068SLucas Stach HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 2411ca56202SWolfgang Grandegger setbits_le32(&ehci->usbmode, CM_HOST); 2421ca56202SWolfgang Grandegger 2431ca56202SWolfgang Grandegger __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 2441ca56202SWolfgang Grandegger setbits_le32(&ehci->portsc, USB_EN); 2451ca56202SWolfgang Grandegger 2461ca56202SWolfgang Grandegger mxc_set_usbcontrol(CONFIG_MXC_USB_PORT, CONFIG_MXC_USB_FLAGS); 2471ca56202SWolfgang Grandegger mdelay(10); 2481ca56202SWolfgang Grandegger 2491b80f270SMarek Vasut /* Do board specific post-initialization */ 2501b80f270SMarek Vasut board_ehci_hcd_postinit(ehci, CONFIG_MXC_USB_PORT); 2511b80f270SMarek Vasut 2521ca56202SWolfgang Grandegger return 0; 2531ca56202SWolfgang Grandegger } 2541ca56202SWolfgang Grandegger 255676ae068SLucas Stach int ehci_hcd_stop(int index) 2561ca56202SWolfgang Grandegger { 2571ca56202SWolfgang Grandegger return 0; 2581ca56202SWolfgang Grandegger } 259