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> 113f467529SWolfgang Grandegger #include <linux/compiler.h> 123f467529SWolfgang Grandegger #include <usb/ehci-fsl.h> 133f467529SWolfgang Grandegger #include <asm/io.h> 143f467529SWolfgang Grandegger #include <asm/arch/imx-regs.h> 153f467529SWolfgang Grandegger #include <asm/arch/clock.h> 16af2a35fbSTroy Kisky #include <asm/imx-common/iomux-v3.h> 173f467529SWolfgang Grandegger 183f467529SWolfgang Grandegger #include "ehci.h" 193f467529SWolfgang Grandegger 203f467529SWolfgang Grandegger #define USB_OTGREGS_OFFSET 0x000 213f467529SWolfgang Grandegger #define USB_H1REGS_OFFSET 0x200 223f467529SWolfgang Grandegger #define USB_H2REGS_OFFSET 0x400 233f467529SWolfgang Grandegger #define USB_H3REGS_OFFSET 0x600 243f467529SWolfgang Grandegger #define USB_OTHERREGS_OFFSET 0x800 253f467529SWolfgang Grandegger 263f467529SWolfgang Grandegger #define USB_H1_CTRL_OFFSET 0x04 273f467529SWolfgang Grandegger 283f467529SWolfgang Grandegger #define USBPHY_CTRL 0x00000030 293f467529SWolfgang Grandegger #define USBPHY_CTRL_SET 0x00000034 303f467529SWolfgang Grandegger #define USBPHY_CTRL_CLR 0x00000038 313f467529SWolfgang Grandegger #define USBPHY_CTRL_TOG 0x0000003c 323f467529SWolfgang Grandegger 333f467529SWolfgang Grandegger #define USBPHY_PWD 0x00000000 343f467529SWolfgang Grandegger #define USBPHY_CTRL_SFTRST 0x80000000 353f467529SWolfgang Grandegger #define USBPHY_CTRL_CLKGATE 0x40000000 363f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL3 0x00008000 373f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL2 0x00004000 383f467529SWolfgang Grandegger 393f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000 403f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000 413f467529SWolfgang Grandegger 423f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000 433f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000 443f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000 453f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 463f467529SWolfgang Grandegger 473f467529SWolfgang Grandegger 483f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ 493f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ 503f467529SWolfgang Grandegger 513f467529SWolfgang Grandegger /* USBCMD */ 523f467529SWolfgang Grandegger #define UH1_USBCMD_OFFSET 0x140 533f467529SWolfgang Grandegger #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ 543f467529SWolfgang Grandegger #define UCMD_RESET (1 << 1) /* controller reset */ 553f467529SWolfgang Grandegger 563f467529SWolfgang Grandegger static void usbh1_internal_phy_clock_gate(int on) 573f467529SWolfgang Grandegger { 583f467529SWolfgang Grandegger void __iomem *phy_reg = (void __iomem *)USB_PHY1_BASE_ADDR; 593f467529SWolfgang Grandegger 603f467529SWolfgang Grandegger phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET; 613f467529SWolfgang Grandegger __raw_writel(USBPHY_CTRL_CLKGATE, phy_reg); 623f467529SWolfgang Grandegger } 633f467529SWolfgang Grandegger 643f467529SWolfgang Grandegger static void usbh1_power_config(void) 653f467529SWolfgang Grandegger { 663f29d962SWolfgang Grandegger struct anatop_regs __iomem *anatop = 673f29d962SWolfgang Grandegger (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; 683f467529SWolfgang Grandegger /* 693f467529SWolfgang Grandegger * Some phy and power's special controls for host1 703f467529SWolfgang Grandegger * 1. The external charger detector needs to be disabled 713f467529SWolfgang Grandegger * or the signal at DP will be poor 723f467529SWolfgang Grandegger * 2. The PLL's power and output to usb for host 1 733f467529SWolfgang Grandegger * is totally controlled by IC, so the Software only needs 743f467529SWolfgang Grandegger * to enable them at initializtion. 753f467529SWolfgang Grandegger */ 763f467529SWolfgang Grandegger __raw_writel(ANADIG_USB2_CHRG_DETECT_EN_B | 773f467529SWolfgang Grandegger ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, 78522b2a02SFabio Estevam &anatop->usb2_chrg_detect); 793f467529SWolfgang Grandegger 803f467529SWolfgang Grandegger __raw_writel(ANADIG_USB2_PLL_480_CTRL_BYPASS, 813f29d962SWolfgang Grandegger &anatop->usb2_pll_480_ctrl_clr); 823f467529SWolfgang Grandegger 833f467529SWolfgang Grandegger __raw_writel(ANADIG_USB2_PLL_480_CTRL_ENABLE | 843f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_POWER | 853f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, 86522b2a02SFabio Estevam &anatop->usb2_pll_480_ctrl_set); 873f467529SWolfgang Grandegger } 883f467529SWolfgang Grandegger 893f467529SWolfgang Grandegger static int usbh1_phy_enable(void) 903f467529SWolfgang Grandegger { 913f467529SWolfgang Grandegger void __iomem *phy_reg = (void __iomem *)USB_PHY1_BASE_ADDR; 923f467529SWolfgang Grandegger void __iomem *phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 933f467529SWolfgang Grandegger void __iomem *usb_cmd = (void __iomem *)(USBOH3_USB_BASE_ADDR + 943f467529SWolfgang Grandegger USB_H1REGS_OFFSET + 953f467529SWolfgang Grandegger UH1_USBCMD_OFFSET); 963f467529SWolfgang Grandegger u32 val; 973f467529SWolfgang Grandegger 983f467529SWolfgang Grandegger /* Stop then Reset */ 993f467529SWolfgang Grandegger val = __raw_readl(usb_cmd); 1003f467529SWolfgang Grandegger val &= ~UCMD_RUN_STOP; 1013f467529SWolfgang Grandegger __raw_writel(val, usb_cmd); 1023f467529SWolfgang Grandegger while (__raw_readl(usb_cmd) & UCMD_RUN_STOP) 1033f467529SWolfgang Grandegger ; 1043f467529SWolfgang Grandegger 1053f467529SWolfgang Grandegger val = __raw_readl(usb_cmd); 1063f467529SWolfgang Grandegger val |= UCMD_RESET; 1073f467529SWolfgang Grandegger __raw_writel(val, usb_cmd); 1083f467529SWolfgang Grandegger while (__raw_readl(usb_cmd) & UCMD_RESET) 1093f467529SWolfgang Grandegger ; 1103f467529SWolfgang Grandegger 1113f467529SWolfgang Grandegger /* Reset USBPHY module */ 1123f467529SWolfgang Grandegger val = __raw_readl(phy_ctrl); 1133f467529SWolfgang Grandegger val |= USBPHY_CTRL_SFTRST; 1143f467529SWolfgang Grandegger __raw_writel(val, phy_ctrl); 1153f467529SWolfgang Grandegger udelay(10); 1163f467529SWolfgang Grandegger 1173f467529SWolfgang Grandegger /* Remove CLKGATE and SFTRST */ 1183f467529SWolfgang Grandegger val = __raw_readl(phy_ctrl); 1193f467529SWolfgang Grandegger val &= ~(USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); 1203f467529SWolfgang Grandegger __raw_writel(val, phy_ctrl); 1213f467529SWolfgang Grandegger udelay(10); 1223f467529SWolfgang Grandegger 1233f467529SWolfgang Grandegger /* Power up the PHY */ 1243f467529SWolfgang Grandegger __raw_writel(0, phy_reg + USBPHY_PWD); 1253f467529SWolfgang Grandegger /* enable FS/LS device */ 1263f467529SWolfgang Grandegger val = __raw_readl(phy_reg + USBPHY_CTRL); 1273f467529SWolfgang Grandegger val |= (USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3); 1283f467529SWolfgang Grandegger __raw_writel(val, phy_reg + USBPHY_CTRL); 1293f467529SWolfgang Grandegger 1303f467529SWolfgang Grandegger return 0; 1313f467529SWolfgang Grandegger } 1323f467529SWolfgang Grandegger 1333f467529SWolfgang Grandegger static void usbh1_oc_config(void) 1343f467529SWolfgang Grandegger { 1353f467529SWolfgang Grandegger void __iomem *usb_base = (void __iomem *)USBOH3_USB_BASE_ADDR; 1363f467529SWolfgang Grandegger void __iomem *usbother_base = usb_base + USB_OTHERREGS_OFFSET; 1373f467529SWolfgang Grandegger u32 val; 1383f467529SWolfgang Grandegger 1393f467529SWolfgang Grandegger val = __raw_readl(usbother_base + USB_H1_CTRL_OFFSET); 1403f467529SWolfgang Grandegger #if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2 1413f467529SWolfgang Grandegger /* mx6qarm2 seems to required a different setting*/ 1423f467529SWolfgang Grandegger val &= ~UCTRL_OVER_CUR_POL; 1433f467529SWolfgang Grandegger #else 1443f467529SWolfgang Grandegger val |= UCTRL_OVER_CUR_POL; 1453f467529SWolfgang Grandegger #endif 1463f467529SWolfgang Grandegger __raw_writel(val, usbother_base + USB_H1_CTRL_OFFSET); 1473f467529SWolfgang Grandegger 1483f467529SWolfgang Grandegger val = __raw_readl(usbother_base + USB_H1_CTRL_OFFSET); 1493f467529SWolfgang Grandegger val |= UCTRL_OVER_CUR_DIS; 1503f467529SWolfgang Grandegger __raw_writel(val, usbother_base + USB_H1_CTRL_OFFSET); 1513f467529SWolfgang Grandegger } 1523f467529SWolfgang Grandegger 153f22e4faeSBenoît Thébaudeau int __weak board_ehci_hcd_init(int port) 154f22e4faeSBenoît Thébaudeau { 155f22e4faeSBenoît Thébaudeau return 0; 156f22e4faeSBenoît Thébaudeau } 157f22e4faeSBenoît Thébaudeau 158*127efc4fSTroy Kisky int ehci_hcd_init(int index, enum usb_init_type init, 159*127efc4fSTroy Kisky struct ehci_hccr **hccr, struct ehci_hcor **hcor) 1603f467529SWolfgang Grandegger { 1613f467529SWolfgang Grandegger struct usb_ehci *ehci; 1623f467529SWolfgang Grandegger 1633f467529SWolfgang Grandegger enable_usboh3_clk(1); 1643f467529SWolfgang Grandegger mdelay(1); 1653f467529SWolfgang Grandegger 1663f467529SWolfgang Grandegger /* Do board specific initialization */ 1673f467529SWolfgang Grandegger board_ehci_hcd_init(CONFIG_MXC_USB_PORT); 1683f467529SWolfgang Grandegger 1693f467529SWolfgang Grandegger #if CONFIG_MXC_USB_PORT == 1 1703f467529SWolfgang Grandegger /* USB Host 1 */ 1713f467529SWolfgang Grandegger usbh1_power_config(); 1723f467529SWolfgang Grandegger usbh1_oc_config(); 1733f467529SWolfgang Grandegger usbh1_internal_phy_clock_gate(1); 1743f467529SWolfgang Grandegger usbh1_phy_enable(); 1753f467529SWolfgang Grandegger #else 1763f467529SWolfgang Grandegger #error "MXC USB port not yet supported" 1773f467529SWolfgang Grandegger #endif 1783f467529SWolfgang Grandegger 1793f467529SWolfgang Grandegger ehci = (struct usb_ehci *)(USBOH3_USB_BASE_ADDR + 1803f467529SWolfgang Grandegger (0x200 * CONFIG_MXC_USB_PORT)); 181676ae068SLucas Stach *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 182676ae068SLucas Stach *hcor = (struct ehci_hcor *)((uint32_t)*hccr + 183676ae068SLucas Stach HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 1843f467529SWolfgang Grandegger setbits_le32(&ehci->usbmode, CM_HOST); 1853f467529SWolfgang Grandegger 1863f467529SWolfgang Grandegger __raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 1873f467529SWolfgang Grandegger setbits_le32(&ehci->portsc, USB_EN); 1883f467529SWolfgang Grandegger 1893f467529SWolfgang Grandegger mdelay(10); 1903f467529SWolfgang Grandegger 1913f467529SWolfgang Grandegger return 0; 1923f467529SWolfgang Grandegger } 1933f467529SWolfgang Grandegger 194676ae068SLucas Stach int ehci_hcd_stop(int index) 1953f467529SWolfgang Grandegger { 1963f467529SWolfgang Grandegger return 0; 1973f467529SWolfgang Grandegger } 198