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> 220457b2cdSAdam Ford #include <linux/usb/otg.h> 233f467529SWolfgang Grandegger 243f467529SWolfgang Grandegger #include "ehci.h" 253f467529SWolfgang Grandegger 26cccbddc3SPeng Fan DECLARE_GLOBAL_DATA_PTR; 27cccbddc3SPeng Fan 283f467529SWolfgang Grandegger #define USB_OTGREGS_OFFSET 0x000 293f467529SWolfgang Grandegger #define USB_H1REGS_OFFSET 0x200 303f467529SWolfgang Grandegger #define USB_H2REGS_OFFSET 0x400 313f467529SWolfgang Grandegger #define USB_H3REGS_OFFSET 0x600 323f467529SWolfgang Grandegger #define USB_OTHERREGS_OFFSET 0x800 333f467529SWolfgang Grandegger 343f467529SWolfgang Grandegger #define USB_H1_CTRL_OFFSET 0x04 353f467529SWolfgang Grandegger 363f467529SWolfgang Grandegger #define USBPHY_CTRL 0x00000030 373f467529SWolfgang Grandegger #define USBPHY_CTRL_SET 0x00000034 383f467529SWolfgang Grandegger #define USBPHY_CTRL_CLR 0x00000038 393f467529SWolfgang Grandegger #define USBPHY_CTRL_TOG 0x0000003c 403f467529SWolfgang Grandegger 413f467529SWolfgang Grandegger #define USBPHY_PWD 0x00000000 423f467529SWolfgang Grandegger #define USBPHY_CTRL_SFTRST 0x80000000 433f467529SWolfgang Grandegger #define USBPHY_CTRL_CLKGATE 0x40000000 443f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL3 0x00008000 453f467529SWolfgang Grandegger #define USBPHY_CTRL_ENUTMILEVEL2 0x00004000 46d1a52860STroy Kisky #define USBPHY_CTRL_OTG_ID 0x08000000 473f467529SWolfgang Grandegger 483f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000 493f467529SWolfgang Grandegger #define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000 503f467529SWolfgang Grandegger 513f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000 523f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000 533f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000 543f467529SWolfgang Grandegger #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 553f467529SWolfgang Grandegger 5635554fc9SAdrian Alonso #define USBNC_OFFSET 0x200 57cccbddc3SPeng Fan #define USBNC_PHY_STATUS_OFFSET 0x23C 5835554fc9SAdrian Alonso #define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */ 5935554fc9SAdrian Alonso #define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */ 609a88180bSStefan Agner #define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */ 613f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ 623f467529SWolfgang Grandegger #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ 633f467529SWolfgang Grandegger 643f467529SWolfgang Grandegger /* USBCMD */ 653f467529SWolfgang Grandegger #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ 663f467529SWolfgang Grandegger #define UCMD_RESET (1 << 1) /* controller reset */ 673f467529SWolfgang Grandegger 6835554fc9SAdrian Alonso #if defined(CONFIG_MX6) 69d1a52860STroy Kisky static const unsigned phy_bases[] = { 70d1a52860STroy Kisky USB_PHY0_BASE_ADDR, 71d1a52860STroy Kisky USB_PHY1_BASE_ADDR, 72d1a52860STroy Kisky }; 733f467529SWolfgang Grandegger 74d1a52860STroy Kisky static void usb_internal_phy_clock_gate(int index, int on) 75d1a52860STroy Kisky { 76d1a52860STroy Kisky void __iomem *phy_reg; 77d1a52860STroy Kisky 78d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 79d1a52860STroy Kisky return; 80d1a52860STroy Kisky 81d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 823f467529SWolfgang Grandegger phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET; 83e38ff30aSAdrian Alonso writel(USBPHY_CTRL_CLKGATE, phy_reg); 843f467529SWolfgang Grandegger } 853f467529SWolfgang Grandegger 86d1a52860STroy Kisky static void usb_power_config(int index) 873f467529SWolfgang Grandegger { 883f29d962SWolfgang Grandegger struct anatop_regs __iomem *anatop = 893f29d962SWolfgang Grandegger (struct anatop_regs __iomem *)ANATOP_BASE_ADDR; 90d1a52860STroy Kisky void __iomem *chrg_detect; 91d1a52860STroy Kisky void __iomem *pll_480_ctrl_clr; 92d1a52860STroy Kisky void __iomem *pll_480_ctrl_set; 93d1a52860STroy Kisky 94d1a52860STroy Kisky switch (index) { 95d1a52860STroy Kisky case 0: 96d1a52860STroy Kisky chrg_detect = &anatop->usb1_chrg_detect; 97d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb1_pll_480_ctrl_clr; 98d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb1_pll_480_ctrl_set; 99d1a52860STroy Kisky break; 100d1a52860STroy Kisky case 1: 101d1a52860STroy Kisky chrg_detect = &anatop->usb2_chrg_detect; 102d1a52860STroy Kisky pll_480_ctrl_clr = &anatop->usb2_pll_480_ctrl_clr; 103d1a52860STroy Kisky pll_480_ctrl_set = &anatop->usb2_pll_480_ctrl_set; 104d1a52860STroy Kisky break; 105d1a52860STroy Kisky default: 106d1a52860STroy Kisky return; 107d1a52860STroy Kisky } 1083f467529SWolfgang Grandegger /* 109d1a52860STroy Kisky * Some phy and power's special controls 1103f467529SWolfgang Grandegger * 1. The external charger detector needs to be disabled 1113f467529SWolfgang Grandegger * or the signal at DP will be poor 112d1a52860STroy Kisky * 2. The PLL's power and output to usb 1133f467529SWolfgang Grandegger * is totally controlled by IC, so the Software only needs 1143f467529SWolfgang Grandegger * to enable them at initializtion. 1153f467529SWolfgang Grandegger */ 116e38ff30aSAdrian Alonso writel(ANADIG_USB2_CHRG_DETECT_EN_B | 1173f467529SWolfgang Grandegger ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, 118d1a52860STroy Kisky chrg_detect); 1193f467529SWolfgang Grandegger 120e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_BYPASS, 121d1a52860STroy Kisky pll_480_ctrl_clr); 1223f467529SWolfgang Grandegger 123e38ff30aSAdrian Alonso writel(ANADIG_USB2_PLL_480_CTRL_ENABLE | 1243f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_POWER | 1253f467529SWolfgang Grandegger ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, 126d1a52860STroy Kisky pll_480_ctrl_set); 1273f467529SWolfgang Grandegger } 1283f467529SWolfgang Grandegger 129d1a52860STroy Kisky /* Return 0 : host node, <>0 : device mode */ 130d1a52860STroy Kisky static int usb_phy_enable(int index, struct usb_ehci *ehci) 1313f467529SWolfgang Grandegger { 132d1a52860STroy Kisky void __iomem *phy_reg; 133d1a52860STroy Kisky void __iomem *phy_ctrl; 134d1a52860STroy Kisky void __iomem *usb_cmd; 135f0c89d54SAdrian Alonso int ret; 1363f467529SWolfgang Grandegger 137d1a52860STroy Kisky if (index >= ARRAY_SIZE(phy_bases)) 138d1a52860STroy Kisky return 0; 139d1a52860STroy Kisky 140d1a52860STroy Kisky phy_reg = (void __iomem *)phy_bases[index]; 141d1a52860STroy Kisky phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 142d1a52860STroy Kisky usb_cmd = (void __iomem *)&ehci->usbcmd; 143d1a52860STroy Kisky 1443f467529SWolfgang Grandegger /* Stop then Reset */ 145e38ff30aSAdrian Alonso clrbits_le32(usb_cmd, UCMD_RUN_STOP); 146b491b498SJon Lin ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false); 147f0c89d54SAdrian Alonso if (ret) 148f0c89d54SAdrian Alonso return ret; 1493f467529SWolfgang Grandegger 150e38ff30aSAdrian Alonso setbits_le32(usb_cmd, UCMD_RESET); 151b491b498SJon Lin ret = wait_for_bit_le32(usb_cmd, UCMD_RESET, false, 10000, false); 152f0c89d54SAdrian Alonso if (ret) 153f0c89d54SAdrian Alonso return ret; 1543f467529SWolfgang Grandegger 1553f467529SWolfgang Grandegger /* Reset USBPHY module */ 156e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST); 1573f467529SWolfgang Grandegger udelay(10); 1583f467529SWolfgang Grandegger 1593f467529SWolfgang Grandegger /* Remove CLKGATE and SFTRST */ 160e38ff30aSAdrian Alonso clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); 1613f467529SWolfgang Grandegger udelay(10); 1623f467529SWolfgang Grandegger 1633f467529SWolfgang Grandegger /* Power up the PHY */ 164e38ff30aSAdrian Alonso writel(0, phy_reg + USBPHY_PWD); 1653f467529SWolfgang Grandegger /* enable FS/LS device */ 166e38ff30aSAdrian Alonso setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 | 167e38ff30aSAdrian Alonso USBPHY_CTRL_ENUTMILEVEL3); 1683f467529SWolfgang Grandegger 169229dbba9SPeng Fan return 0; 1703f467529SWolfgang Grandegger } 1713f467529SWolfgang Grandegger 172229dbba9SPeng Fan int usb_phy_mode(int port) 173229dbba9SPeng Fan { 174229dbba9SPeng Fan void __iomem *phy_reg; 175229dbba9SPeng Fan void __iomem *phy_ctrl; 176229dbba9SPeng Fan u32 val; 177229dbba9SPeng Fan 178229dbba9SPeng Fan phy_reg = (void __iomem *)phy_bases[port]; 179229dbba9SPeng Fan phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 180229dbba9SPeng Fan 181e38ff30aSAdrian Alonso val = readl(phy_ctrl); 182229dbba9SPeng Fan 183229dbba9SPeng Fan if (val & USBPHY_CTRL_OTG_ID) 184229dbba9SPeng Fan return USB_INIT_DEVICE; 185229dbba9SPeng Fan else 186229dbba9SPeng Fan return USB_INIT_HOST; 187229dbba9SPeng Fan } 188229dbba9SPeng Fan 18935554fc9SAdrian Alonso /* Base address for this IP block is 0x02184800 */ 19035554fc9SAdrian Alonso struct usbnc_regs { 19135554fc9SAdrian Alonso u32 ctrl[4]; /* otg/host1-3 */ 19235554fc9SAdrian Alonso u32 uh2_hsic_ctrl; 19335554fc9SAdrian Alonso u32 uh3_hsic_ctrl; 19435554fc9SAdrian Alonso u32 otg_phy_ctrl_0; 19535554fc9SAdrian Alonso u32 uh1_phy_ctrl_0; 19635554fc9SAdrian Alonso }; 19735554fc9SAdrian Alonso #elif defined(CONFIG_MX7) 19835554fc9SAdrian Alonso struct usbnc_regs { 19935554fc9SAdrian Alonso u32 ctrl1; 20035554fc9SAdrian Alonso u32 ctrl2; 20135554fc9SAdrian Alonso u32 reserve1[10]; 20235554fc9SAdrian Alonso u32 phy_cfg1; 20335554fc9SAdrian Alonso u32 phy_cfg2; 204429ff447SPeng Fan u32 reserve2; 20535554fc9SAdrian Alonso u32 phy_status; 206429ff447SPeng Fan u32 reserve3[4]; 20735554fc9SAdrian Alonso u32 adp_cfg1; 20835554fc9SAdrian Alonso u32 adp_cfg2; 20935554fc9SAdrian Alonso u32 adp_status; 21035554fc9SAdrian Alonso }; 21135554fc9SAdrian Alonso 21235554fc9SAdrian Alonso static void usb_power_config(int index) 21335554fc9SAdrian Alonso { 21435554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 21535554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET); 21635554fc9SAdrian Alonso void __iomem *phy_cfg2 = (void __iomem *)(&usbnc->phy_cfg2); 2179a88180bSStefan Agner void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); 21835554fc9SAdrian Alonso 21957de41e9SPeng Fan /* 22057de41e9SPeng Fan * Clear the ACAENB to enable usb_otg_id detection, 22157de41e9SPeng Fan * otherwise it is the ACA detection enabled. 22257de41e9SPeng Fan */ 22357de41e9SPeng Fan clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB); 2249a88180bSStefan Agner 2259a88180bSStefan Agner /* Set power polarity to high active */ 226c4483093SStefan Agner #ifdef CONFIG_MXC_USB_OTG_HACTIVE 2279a88180bSStefan Agner setbits_le32(ctrl, UCTRL_PWR_POL); 228c4483093SStefan Agner #else 229c4483093SStefan Agner clrbits_le32(ctrl, UCTRL_PWR_POL); 230c4483093SStefan Agner #endif 23135554fc9SAdrian Alonso } 23235554fc9SAdrian Alonso 23335554fc9SAdrian Alonso int usb_phy_mode(int port) 23435554fc9SAdrian Alonso { 23535554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 23635554fc9SAdrian Alonso (0x10000 * port) + USBNC_OFFSET); 23735554fc9SAdrian Alonso void __iomem *status = (void __iomem *)(&usbnc->phy_status); 23835554fc9SAdrian Alonso u32 val; 23935554fc9SAdrian Alonso 24035554fc9SAdrian Alonso val = readl(status); 24135554fc9SAdrian Alonso 24235554fc9SAdrian Alonso if (val & USBNC_PHYSTATUS_ID_DIG) 24335554fc9SAdrian Alonso return USB_INIT_DEVICE; 24435554fc9SAdrian Alonso else 24535554fc9SAdrian Alonso return USB_INIT_HOST; 24635554fc9SAdrian Alonso } 24735554fc9SAdrian Alonso #endif 24835554fc9SAdrian Alonso 24935554fc9SAdrian Alonso static void usb_oc_config(int index) 25035554fc9SAdrian Alonso { 25135554fc9SAdrian Alonso #if defined(CONFIG_MX6) 25235554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 25335554fc9SAdrian Alonso USB_OTHERREGS_OFFSET); 25435554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl[index]); 25535554fc9SAdrian Alonso #elif defined(CONFIG_MX7) 25635554fc9SAdrian Alonso struct usbnc_regs *usbnc = (struct usbnc_regs *)(USB_BASE_ADDR + 25735554fc9SAdrian Alonso (0x10000 * index) + USBNC_OFFSET); 25835554fc9SAdrian Alonso void __iomem *ctrl = (void __iomem *)(&usbnc->ctrl1); 25935554fc9SAdrian Alonso #endif 26035554fc9SAdrian Alonso 26135554fc9SAdrian Alonso #if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2 26235554fc9SAdrian Alonso /* mx6qarm2 seems to required a different setting*/ 26335554fc9SAdrian Alonso clrbits_le32(ctrl, UCTRL_OVER_CUR_POL); 26435554fc9SAdrian Alonso #else 26535554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_POL); 26635554fc9SAdrian Alonso #endif 26735554fc9SAdrian Alonso 26835554fc9SAdrian Alonso setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); 26935554fc9SAdrian Alonso } 27035554fc9SAdrian Alonso 27174f0610eSAdrian Alonso /** 27279d867c2SStefan Agner * board_usb_phy_mode - override usb phy mode 27374f0610eSAdrian Alonso * @port: usb host/otg port 27474f0610eSAdrian Alonso * 27574f0610eSAdrian Alonso * Target board specific, override usb_phy_mode. 27674f0610eSAdrian Alonso * When usb-otg is used as usb host port, iomux pad usb_otg_id can be 27774f0610eSAdrian Alonso * left disconnected in this case usb_phy_mode will not be able to identify 27874f0610eSAdrian Alonso * the phy mode that usb port is used. 27974f0610eSAdrian Alonso * Machine file overrides board_usb_phy_mode. 28074f0610eSAdrian Alonso * 28174f0610eSAdrian Alonso * Return: USB_INIT_DEVICE or USB_INIT_HOST 28274f0610eSAdrian Alonso */ 283229dbba9SPeng Fan int __weak board_usb_phy_mode(int port) 284229dbba9SPeng Fan { 285229dbba9SPeng Fan return usb_phy_mode(port); 286229dbba9SPeng Fan } 287229dbba9SPeng Fan 28874f0610eSAdrian Alonso /** 28974f0610eSAdrian Alonso * board_ehci_hcd_init - set usb vbus voltage 29074f0610eSAdrian Alonso * @port: usb otg port 29174f0610eSAdrian Alonso * 29274f0610eSAdrian Alonso * Target board specific, setup iomux pad to setup supply vbus voltage 29374f0610eSAdrian Alonso * for usb otg port. Machine board file overrides board_ehci_hcd_init 29474f0610eSAdrian Alonso * 29574f0610eSAdrian Alonso * Return: 0 Success 29674f0610eSAdrian Alonso */ 297f22e4faeSBenoît Thébaudeau int __weak board_ehci_hcd_init(int port) 298f22e4faeSBenoît Thébaudeau { 299f22e4faeSBenoît Thébaudeau return 0; 300f22e4faeSBenoît Thébaudeau } 301f22e4faeSBenoît Thébaudeau 30274f0610eSAdrian Alonso /** 30374f0610eSAdrian Alonso * board_ehci_power - enables/disables usb vbus voltage 30474f0610eSAdrian Alonso * @port: usb otg port 30574f0610eSAdrian Alonso * @on: on/off vbus voltage 30674f0610eSAdrian Alonso * 30774f0610eSAdrian Alonso * Enables/disables supply vbus voltage for usb otg port. 30874f0610eSAdrian Alonso * Machine board file overrides board_ehci_power 30974f0610eSAdrian Alonso * 31074f0610eSAdrian Alonso * Return: 0 Success 31174f0610eSAdrian Alonso */ 312d1a52860STroy Kisky int __weak board_ehci_power(int port, int on) 313d1a52860STroy Kisky { 314d1a52860STroy Kisky return 0; 315d1a52860STroy Kisky } 316d1a52860STroy Kisky 317bb42fb4fSPeng Fan int ehci_mx6_common_init(struct usb_ehci *ehci, int index) 3183f467529SWolfgang Grandegger { 31979d867c2SStefan Agner int ret; 3203f467529SWolfgang Grandegger 3213f467529SWolfgang Grandegger enable_usboh3_clk(1); 3223f467529SWolfgang Grandegger mdelay(1); 3233f467529SWolfgang Grandegger 3243f467529SWolfgang Grandegger /* Do board specific initialization */ 32579d867c2SStefan Agner ret = board_ehci_hcd_init(index); 32679d867c2SStefan Agner if (ret) 32779d867c2SStefan Agner return ret; 3283f467529SWolfgang Grandegger 329d1a52860STroy Kisky usb_power_config(index); 330d1a52860STroy Kisky usb_oc_config(index); 33135554fc9SAdrian Alonso 33235554fc9SAdrian Alonso #if defined(CONFIG_MX6) 333d1a52860STroy Kisky usb_internal_phy_clock_gate(index, 1); 334229dbba9SPeng Fan usb_phy_enable(index, ehci); 33535554fc9SAdrian Alonso #endif 336bb42fb4fSPeng Fan 337bb42fb4fSPeng Fan return 0; 338bb42fb4fSPeng Fan } 339bb42fb4fSPeng Fan 3403739bf7eSSven Schwermer #if !CONFIG_IS_ENABLED(DM_USB) 341bb42fb4fSPeng Fan int ehci_hcd_init(int index, enum usb_init_type init, 342bb42fb4fSPeng Fan struct ehci_hccr **hccr, struct ehci_hcor **hcor) 343bb42fb4fSPeng Fan { 344bb42fb4fSPeng Fan enum usb_init_type type; 345bb42fb4fSPeng Fan #if defined(CONFIG_MX6) 346bb42fb4fSPeng Fan u32 controller_spacing = 0x200; 347bb42fb4fSPeng Fan #elif defined(CONFIG_MX7) 348bb42fb4fSPeng Fan u32 controller_spacing = 0x10000; 349bb42fb4fSPeng Fan #endif 350bb42fb4fSPeng Fan struct usb_ehci *ehci = (struct usb_ehci *)(USB_BASE_ADDR + 351bb42fb4fSPeng Fan (controller_spacing * index)); 352bb42fb4fSPeng Fan int ret; 353bb42fb4fSPeng Fan 354bb42fb4fSPeng Fan if (index > 3) 355bb42fb4fSPeng Fan return -EINVAL; 356bb42fb4fSPeng Fan 357bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, index); 358bb42fb4fSPeng Fan if (ret) 359bb42fb4fSPeng Fan return ret; 360bb42fb4fSPeng Fan 361229dbba9SPeng Fan type = board_usb_phy_mode(index); 3623f467529SWolfgang Grandegger 363bb42fb4fSPeng Fan if (hccr && hcor) { 364676ae068SLucas Stach *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 365676ae068SLucas Stach *hcor = (struct ehci_hcor *)((uint32_t)*hccr + 366676ae068SLucas Stach HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 367bb42fb4fSPeng Fan } 3683f467529SWolfgang Grandegger 369d1a52860STroy Kisky if ((type == init) || (type == USB_INIT_DEVICE)) 370d1a52860STroy Kisky board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1); 371d1a52860STroy Kisky if (type != init) 372d1a52860STroy Kisky return -ENODEV; 373d1a52860STroy Kisky if (type == USB_INIT_DEVICE) 374d1a52860STroy Kisky return 0; 37535554fc9SAdrian Alonso 376d1a52860STroy Kisky setbits_le32(&ehci->usbmode, CM_HOST); 377e38ff30aSAdrian Alonso writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 3783f467529SWolfgang Grandegger setbits_le32(&ehci->portsc, USB_EN); 3793f467529SWolfgang Grandegger 3803f467529SWolfgang Grandegger mdelay(10); 3813f467529SWolfgang Grandegger 3823f467529SWolfgang Grandegger return 0; 3833f467529SWolfgang Grandegger } 3843f467529SWolfgang Grandegger 385676ae068SLucas Stach int ehci_hcd_stop(int index) 3863f467529SWolfgang Grandegger { 3873f467529SWolfgang Grandegger return 0; 3883f467529SWolfgang Grandegger } 389bb42fb4fSPeng Fan #else 390bb42fb4fSPeng Fan struct ehci_mx6_priv_data { 391bb42fb4fSPeng Fan struct ehci_ctrl ctrl; 392bb42fb4fSPeng Fan struct usb_ehci *ehci; 393fcf9f9f9SPeng Fan struct udevice *vbus_supply; 394bb42fb4fSPeng Fan enum usb_init_type init_type; 395bb42fb4fSPeng Fan int portnr; 396bb42fb4fSPeng Fan }; 397bb42fb4fSPeng Fan 398bb42fb4fSPeng Fan static int mx6_init_after_reset(struct ehci_ctrl *dev) 399bb42fb4fSPeng Fan { 400bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev->priv; 401bb42fb4fSPeng Fan enum usb_init_type type = priv->init_type; 402bb42fb4fSPeng Fan struct usb_ehci *ehci = priv->ehci; 403bb42fb4fSPeng Fan int ret; 404bb42fb4fSPeng Fan 405bb42fb4fSPeng Fan ret = ehci_mx6_common_init(priv->ehci, priv->portnr); 406bb42fb4fSPeng Fan if (ret) 407bb42fb4fSPeng Fan return ret; 408bb42fb4fSPeng Fan 4098a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR) 410fcf9f9f9SPeng Fan if (priv->vbus_supply) { 411fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply, 412fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ? 413fcf9f9f9SPeng Fan false : true); 414fcf9f9f9SPeng Fan if (ret) { 415fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n"); 416fcf9f9f9SPeng Fan return ret; 417fcf9f9f9SPeng Fan } 418fcf9f9f9SPeng Fan } 4198a4a81a1SAbel Vesa #endif 420bb42fb4fSPeng Fan 421bb42fb4fSPeng Fan if (type == USB_INIT_DEVICE) 422bb42fb4fSPeng Fan return 0; 423bb42fb4fSPeng Fan 424bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 425bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 426bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 427bb42fb4fSPeng Fan 428bb42fb4fSPeng Fan mdelay(10); 429bb42fb4fSPeng Fan 430bb42fb4fSPeng Fan return 0; 431bb42fb4fSPeng Fan } 432bb42fb4fSPeng Fan 433bb42fb4fSPeng Fan static const struct ehci_ops mx6_ehci_ops = { 434bb42fb4fSPeng Fan .init_after_reset = mx6_init_after_reset 435bb42fb4fSPeng Fan }; 436bb42fb4fSPeng Fan 437cccbddc3SPeng Fan static int ehci_usb_phy_mode(struct udevice *dev) 438cccbddc3SPeng Fan { 439cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 440a821c4afSSimon Glass void *__iomem addr = (void *__iomem)devfdt_get_addr(dev); 441cccbddc3SPeng Fan void *__iomem phy_ctrl, *__iomem phy_status; 442cccbddc3SPeng Fan const void *blob = gd->fdt_blob; 443e160f7d4SSimon Glass int offset = dev_of_offset(dev), phy_off; 444cccbddc3SPeng Fan u32 val; 445cccbddc3SPeng Fan 446cccbddc3SPeng Fan /* 447cccbddc3SPeng Fan * About fsl,usbphy, Refer to 448cccbddc3SPeng Fan * Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt. 449cccbddc3SPeng Fan */ 450cccbddc3SPeng Fan if (is_mx6()) { 451cccbddc3SPeng Fan phy_off = fdtdec_lookup_phandle(blob, 452cccbddc3SPeng Fan offset, 453cccbddc3SPeng Fan "fsl,usbphy"); 454cccbddc3SPeng Fan if (phy_off < 0) 455cccbddc3SPeng Fan return -EINVAL; 456cccbddc3SPeng Fan 457cccbddc3SPeng Fan addr = (void __iomem *)fdtdec_get_addr(blob, phy_off, 458cccbddc3SPeng Fan "reg"); 459cccbddc3SPeng Fan if ((fdt_addr_t)addr == FDT_ADDR_T_NONE) 460cccbddc3SPeng Fan return -EINVAL; 461cccbddc3SPeng Fan 462cccbddc3SPeng Fan phy_ctrl = (void __iomem *)(addr + USBPHY_CTRL); 463cccbddc3SPeng Fan val = readl(phy_ctrl); 464cccbddc3SPeng Fan 465cccbddc3SPeng Fan if (val & USBPHY_CTRL_OTG_ID) 466cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 467cccbddc3SPeng Fan else 468cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 469cccbddc3SPeng Fan } else if (is_mx7()) { 470cccbddc3SPeng Fan phy_status = (void __iomem *)(addr + 471cccbddc3SPeng Fan USBNC_PHY_STATUS_OFFSET); 472cccbddc3SPeng Fan val = readl(phy_status); 473cccbddc3SPeng Fan 474cccbddc3SPeng Fan if (val & USBNC_PHYSTATUS_ID_DIG) 475cccbddc3SPeng Fan plat->init_type = USB_INIT_DEVICE; 476cccbddc3SPeng Fan else 477cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 478cccbddc3SPeng Fan } else { 479cccbddc3SPeng Fan return -EINVAL; 480cccbddc3SPeng Fan } 481cccbddc3SPeng Fan 482cccbddc3SPeng Fan return 0; 483cccbddc3SPeng Fan } 484cccbddc3SPeng Fan 485cccbddc3SPeng Fan static int ehci_usb_ofdata_to_platdata(struct udevice *dev) 486cccbddc3SPeng Fan { 487cccbddc3SPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 4880457b2cdSAdam Ford enum usb_dr_mode dr_mode; 489cccbddc3SPeng Fan 4900457b2cdSAdam Ford dr_mode = usb_get_dr_mode(dev_of_offset(dev)); 4910457b2cdSAdam Ford 4920457b2cdSAdam Ford switch (dr_mode) { 4930457b2cdSAdam Ford case USB_DR_MODE_HOST: 494cccbddc3SPeng Fan plat->init_type = USB_INIT_HOST; 4950457b2cdSAdam Ford break; 4960457b2cdSAdam Ford case USB_DR_MODE_PERIPHERAL: 4970457b2cdSAdam Ford plat->init_type = USB_INIT_DEVICE; 4980457b2cdSAdam Ford break; 4990457b2cdSAdam Ford case USB_DR_MODE_OTG: 5000457b2cdSAdam Ford case USB_DR_MODE_UNKNOWN: 501cccbddc3SPeng Fan return ehci_usb_phy_mode(dev); 5020457b2cdSAdam Ford }; 503cccbddc3SPeng Fan 504cccbddc3SPeng Fan return 0; 505cccbddc3SPeng Fan } 506cccbddc3SPeng Fan 507920516c8SMarek Vasut static int ehci_usb_bind(struct udevice *dev) 508920516c8SMarek Vasut { 509920516c8SMarek Vasut /* 510920516c8SMarek Vasut * TODO: 511920516c8SMarek Vasut * This driver is only partly converted to DT probing and still uses 512920516c8SMarek Vasut * a tremendous amount of hard-coded addresses. To make things worse, 513920516c8SMarek Vasut * the driver depends on specific sequential indexing of controllers, 514920516c8SMarek Vasut * from which it derives offsets in the PHY and ANATOP register sets. 515920516c8SMarek Vasut * 516920516c8SMarek Vasut * Here we attempt to calculate these indexes from DT information as 517*a9aeb7eeSIgor Opaniuk * well as we can. The USB controllers on all existing iMX6 SoCs 518*a9aeb7eeSIgor Opaniuk * are placed next to each other, at addresses incremented by 0x200, 519*a9aeb7eeSIgor Opaniuk * and iMX7 their addresses are shifted by 0x10000. 520*a9aeb7eeSIgor Opaniuk * Thus, the index is derived from the multiple of 0x200 (0x10000 for 521*a9aeb7eeSIgor Opaniuk * iMX7) offset from the first controller address. 522920516c8SMarek Vasut * 523920516c8SMarek Vasut * However, to complete conversion of this driver to DT probing, the 524920516c8SMarek Vasut * following has to be done: 525920516c8SMarek Vasut * - DM clock framework support for iMX must be implemented 526920516c8SMarek Vasut * - usb_power_config() has to be converted to clock framework 527920516c8SMarek Vasut * -> Thus, the ad-hoc "index" variable goes away. 528920516c8SMarek Vasut * - USB PHY handling has to be factored out into separate driver 529920516c8SMarek Vasut * -> Thus, the ad-hoc "index" variable goes away from the PHY 530920516c8SMarek Vasut * code, the PHY driver must parse it's address from DT. This 531920516c8SMarek Vasut * USB driver must find the PHY driver via DT phandle. 532920516c8SMarek Vasut * -> usb_power_config() shall be moved to PHY driver 533920516c8SMarek Vasut * With these changes in place, the ad-hoc indexing goes away and 534920516c8SMarek Vasut * the driver is fully converted to DT probing. 535920516c8SMarek Vasut */ 536*a9aeb7eeSIgor Opaniuk u32 controller_spacing = is_mx7() ? 0x10000 : 0x200; 537*a9aeb7eeSIgor Opaniuk fdt_addr_t addr = devfdt_get_addr_index(dev, 0); 538920516c8SMarek Vasut 539*a9aeb7eeSIgor Opaniuk dev->req_seq = (addr - USB_BASE_ADDR) / controller_spacing; 540920516c8SMarek Vasut 541920516c8SMarek Vasut return 0; 542920516c8SMarek Vasut } 543920516c8SMarek Vasut 544bb42fb4fSPeng Fan static int ehci_usb_probe(struct udevice *dev) 545bb42fb4fSPeng Fan { 546bb42fb4fSPeng Fan struct usb_platdata *plat = dev_get_platdata(dev); 547a821c4afSSimon Glass struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev); 548bb42fb4fSPeng Fan struct ehci_mx6_priv_data *priv = dev_get_priv(dev); 549fcf9f9f9SPeng Fan enum usb_init_type type = plat->init_type; 550bb42fb4fSPeng Fan struct ehci_hccr *hccr; 551bb42fb4fSPeng Fan struct ehci_hcor *hcor; 552bb42fb4fSPeng Fan int ret; 553bb42fb4fSPeng Fan 554bb42fb4fSPeng Fan priv->ehci = ehci; 555bb42fb4fSPeng Fan priv->portnr = dev->seq; 556fcf9f9f9SPeng Fan priv->init_type = type; 557fcf9f9f9SPeng Fan 5588a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR) 559fcf9f9f9SPeng Fan ret = device_get_supply_regulator(dev, "vbus-supply", 560fcf9f9f9SPeng Fan &priv->vbus_supply); 561fcf9f9f9SPeng Fan if (ret) 562fcf9f9f9SPeng Fan debug("%s: No vbus supply\n", dev->name); 5638a4a81a1SAbel Vesa #endif 564bb42fb4fSPeng Fan ret = ehci_mx6_common_init(ehci, priv->portnr); 565bb42fb4fSPeng Fan if (ret) 566bb42fb4fSPeng Fan return ret; 567bb42fb4fSPeng Fan 5688a4a81a1SAbel Vesa #if CONFIG_IS_ENABLED(DM_REGULATOR) 569fcf9f9f9SPeng Fan if (priv->vbus_supply) { 570fcf9f9f9SPeng Fan ret = regulator_set_enable(priv->vbus_supply, 571fcf9f9f9SPeng Fan (type == USB_INIT_DEVICE) ? 572fcf9f9f9SPeng Fan false : true); 573fcf9f9f9SPeng Fan if (ret) { 574fcf9f9f9SPeng Fan puts("Error enabling VBUS supply\n"); 575fcf9f9f9SPeng Fan return ret; 576fcf9f9f9SPeng Fan } 577fcf9f9f9SPeng Fan } 5788a4a81a1SAbel Vesa #endif 579bb42fb4fSPeng Fan 580bb42fb4fSPeng Fan if (priv->init_type == USB_INIT_HOST) { 581bb42fb4fSPeng Fan setbits_le32(&ehci->usbmode, CM_HOST); 582bb42fb4fSPeng Fan writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); 583bb42fb4fSPeng Fan setbits_le32(&ehci->portsc, USB_EN); 584bb42fb4fSPeng Fan } 585bb42fb4fSPeng Fan 586bb42fb4fSPeng Fan mdelay(10); 587bb42fb4fSPeng Fan 588bb42fb4fSPeng Fan hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 589bb42fb4fSPeng Fan hcor = (struct ehci_hcor *)((uint32_t)hccr + 590bb42fb4fSPeng Fan HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); 591bb42fb4fSPeng Fan 592bb42fb4fSPeng Fan return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type); 593bb42fb4fSPeng Fan } 594bb42fb4fSPeng Fan 595bb42fb4fSPeng Fan static const struct udevice_id mx6_usb_ids[] = { 596bb42fb4fSPeng Fan { .compatible = "fsl,imx27-usb" }, 597bb42fb4fSPeng Fan { } 598bb42fb4fSPeng Fan }; 599bb42fb4fSPeng Fan 600bb42fb4fSPeng Fan U_BOOT_DRIVER(usb_mx6) = { 601bb42fb4fSPeng Fan .name = "ehci_mx6", 602bb42fb4fSPeng Fan .id = UCLASS_USB, 603bb42fb4fSPeng Fan .of_match = mx6_usb_ids, 604cccbddc3SPeng Fan .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, 605920516c8SMarek Vasut .bind = ehci_usb_bind, 606bb42fb4fSPeng Fan .probe = ehci_usb_probe, 60740527342SMasahiro Yamada .remove = ehci_deregister, 608bb42fb4fSPeng Fan .ops = &ehci_usb_ops, 609bb42fb4fSPeng Fan .platdata_auto_alloc_size = sizeof(struct usb_platdata), 610bb42fb4fSPeng Fan .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data), 611bb42fb4fSPeng Fan .flags = DM_FLAG_ALLOC_PRIV_DMA, 612bb42fb4fSPeng Fan }; 613bb42fb4fSPeng Fan #endif 614