X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fehci-mx6.c;h=f348ec9bca9d8ff1c6b4bf0bb8018986e0d384ce;hb=ebba9d1daf7745483c8078bdae18875a84df5bc1;hp=277f4616464955aa7a29aee6e9473e3236658d6a;hpb=9a88180bfbb6ee7b2fba5516391ff0e611794de5;p=u-boot diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 277f461646..f348ec9bca 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -15,9 +15,15 @@ #include #include #include +#include +#include +#include +#include #include "ehci.h" +DECLARE_GLOBAL_DATA_PTR; + #define USB_OTGREGS_OFFSET 0x000 #define USB_H1REGS_OFFSET 0x200 #define USB_H2REGS_OFFSET 0x400 @@ -47,6 +53,7 @@ #define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 #define USBNC_OFFSET 0x200 +#define USBNC_PHY_STATUS_OFFSET 0x23C #define USBNC_PHYSTATUS_ID_DIG (1 << 4) /* otg_id status */ #define USBNC_PHYCFG2_ACAENB (1 << 4) /* otg_id detection enable */ #define UCTRL_PWR_POL (1 << 9) /* OTG Polarity of Power Pin */ @@ -216,7 +223,11 @@ static void usb_power_config(int index) clrbits_le32(phy_cfg2, USBNC_PHYCFG2_ACAENB); /* Set power polarity to high active */ +#ifdef CONFIG_MXC_USB_OTG_HACTIVE setbits_le32(ctrl, UCTRL_PWR_POL); +#else + clrbits_le32(ctrl, UCTRL_PWR_POL); +#endif } int usb_phy_mode(int port) @@ -303,6 +314,30 @@ int __weak board_ehci_power(int port, int on) return 0; } +int ehci_mx6_common_init(struct usb_ehci *ehci, int index) +{ + int ret; + + enable_usboh3_clk(1); + mdelay(1); + + /* Do board specific initialization */ + ret = board_ehci_hcd_init(index); + if (ret) + return ret; + + usb_power_config(index); + usb_oc_config(index); + +#if defined(CONFIG_MX6) + usb_internal_phy_clock_gate(index, 1); + usb_phy_enable(index, ehci); +#endif + + return 0; +} + +#ifndef CONFIG_DM_USB int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { @@ -318,26 +353,18 @@ int ehci_hcd_init(int index, enum usb_init_type init, if (index > 3) return -EINVAL; - enable_usboh3_clk(1); - mdelay(1); - /* Do board specific initialization */ - ret = board_ehci_hcd_init(index); + ret = ehci_mx6_common_init(ehci, index); if (ret) return ret; - usb_power_config(index); - usb_oc_config(index); - -#if defined(CONFIG_MX6) - usb_internal_phy_clock_gate(index, 1); - usb_phy_enable(index, ehci); -#endif type = board_usb_phy_mode(index); - *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); - *hcor = (struct ehci_hcor *)((uint32_t)*hccr + - HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); + if (hccr && hcor) { + *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); + *hcor = (struct ehci_hcor *)((uint32_t)*hccr + + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); + } if ((type == init) || (type == USB_INIT_DEVICE)) board_ehci_power(index, (type == USB_INIT_DEVICE) ? 0 : 1); @@ -359,3 +386,185 @@ int ehci_hcd_stop(int index) { return 0; } +#else +struct ehci_mx6_priv_data { + struct ehci_ctrl ctrl; + struct usb_ehci *ehci; + struct udevice *vbus_supply; + enum usb_init_type init_type; + int portnr; +}; + +static int mx6_init_after_reset(struct ehci_ctrl *dev) +{ + struct ehci_mx6_priv_data *priv = dev->priv; + enum usb_init_type type = priv->init_type; + struct usb_ehci *ehci = priv->ehci; + int ret; + + ret = ehci_mx6_common_init(priv->ehci, priv->portnr); + if (ret) + return ret; + + if (priv->vbus_supply) { + ret = regulator_set_enable(priv->vbus_supply, + (type == USB_INIT_DEVICE) ? + false : true); + if (ret) { + puts("Error enabling VBUS supply\n"); + return ret; + } + } + + if (type == USB_INIT_DEVICE) + return 0; + + setbits_le32(&ehci->usbmode, CM_HOST); + writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); + setbits_le32(&ehci->portsc, USB_EN); + + mdelay(10); + + return 0; +} + +static const struct ehci_ops mx6_ehci_ops = { + .init_after_reset = mx6_init_after_reset +}; + +static int ehci_usb_phy_mode(struct udevice *dev) +{ + struct usb_platdata *plat = dev_get_platdata(dev); + void *__iomem addr = (void *__iomem)devfdt_get_addr(dev); + void *__iomem phy_ctrl, *__iomem phy_status; + const void *blob = gd->fdt_blob; + int offset = dev_of_offset(dev), phy_off; + u32 val; + + /* + * About fsl,usbphy, Refer to + * Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt. + */ + if (is_mx6()) { + phy_off = fdtdec_lookup_phandle(blob, + offset, + "fsl,usbphy"); + if (phy_off < 0) + return -EINVAL; + + addr = (void __iomem *)fdtdec_get_addr(blob, phy_off, + "reg"); + if ((fdt_addr_t)addr == FDT_ADDR_T_NONE) + return -EINVAL; + + phy_ctrl = (void __iomem *)(addr + USBPHY_CTRL); + val = readl(phy_ctrl); + + if (val & USBPHY_CTRL_OTG_ID) + plat->init_type = USB_INIT_DEVICE; + else + plat->init_type = USB_INIT_HOST; + } else if (is_mx7()) { + phy_status = (void __iomem *)(addr + + USBNC_PHY_STATUS_OFFSET); + val = readl(phy_status); + + if (val & USBNC_PHYSTATUS_ID_DIG) + plat->init_type = USB_INIT_DEVICE; + else + plat->init_type = USB_INIT_HOST; + } else { + return -EINVAL; + } + + return 0; +} + +static int ehci_usb_ofdata_to_platdata(struct udevice *dev) +{ + struct usb_platdata *plat = dev_get_platdata(dev); + const char *mode; + + mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL); + if (mode) { + if (strcmp(mode, "peripheral") == 0) + plat->init_type = USB_INIT_DEVICE; + else if (strcmp(mode, "host") == 0) + plat->init_type = USB_INIT_HOST; + else if (strcmp(mode, "otg") == 0) + return ehci_usb_phy_mode(dev); + else + return -EINVAL; + + return 0; + } + + return ehci_usb_phy_mode(dev); +} + +static int ehci_usb_probe(struct udevice *dev) +{ + struct usb_platdata *plat = dev_get_platdata(dev); + struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev); + struct ehci_mx6_priv_data *priv = dev_get_priv(dev); + enum usb_init_type type = plat->init_type; + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; + int ret; + + priv->ehci = ehci; + priv->portnr = dev->seq; + priv->init_type = type; + + ret = device_get_supply_regulator(dev, "vbus-supply", + &priv->vbus_supply); + if (ret) + debug("%s: No vbus supply\n", dev->name); + + ret = ehci_mx6_common_init(ehci, priv->portnr); + if (ret) + return ret; + + if (priv->vbus_supply) { + ret = regulator_set_enable(priv->vbus_supply, + (type == USB_INIT_DEVICE) ? + false : true); + if (ret) { + puts("Error enabling VBUS supply\n"); + return ret; + } + } + + if (priv->init_type == USB_INIT_HOST) { + setbits_le32(&ehci->usbmode, CM_HOST); + writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc); + setbits_le32(&ehci->portsc, USB_EN); + } + + mdelay(10); + + hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); + hcor = (struct ehci_hcor *)((uint32_t)hccr + + HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); + + return ehci_register(dev, hccr, hcor, &mx6_ehci_ops, 0, priv->init_type); +} + +static const struct udevice_id mx6_usb_ids[] = { + { .compatible = "fsl,imx27-usb" }, + { } +}; + +U_BOOT_DRIVER(usb_mx6) = { + .name = "ehci_mx6", + .id = UCLASS_USB, + .of_match = mx6_usb_ids, + .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, + .probe = ehci_usb_probe, + .remove = ehci_deregister, + .ops = &ehci_usb_ops, + .platdata_auto_alloc_size = sizeof(struct usb_platdata), + .priv_auto_alloc_size = sizeof(struct ehci_mx6_priv_data), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif