X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=inline;f=drivers%2Fusb%2Fhost%2Fehci-mx6.c;h=e9e6ed596d599100124e8af90a24ca5a3c823efe;hb=5939afc9611e8ba4a86b96e67670b765ee27668e;hp=48889c19562b0b91bc006cc109e5ea5688fdd4ba;hpb=cbe7706ab8aab06c18edaa9b120371f9c8012728;p=oweals%2Fu-boot.git diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 48889c1956..e9e6ed596d 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2009 Daniel Mack * Copyright (C) 2010 Freescale Semiconductor, Inc. - * - * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -14,11 +13,17 @@ #include #include #include -#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 @@ -48,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 */ @@ -136,13 +142,12 @@ static int usb_phy_enable(int index, struct usb_ehci *ehci) /* Stop then Reset */ clrbits_le32(usb_cmd, UCMD_RUN_STOP); - ret = wait_for_bit(__func__, usb_cmd, UCMD_RUN_STOP, false, 10000, - false); + ret = wait_for_bit_le32(usb_cmd, UCMD_RUN_STOP, false, 10000, false); if (ret) return ret; setbits_le32(usb_cmd, UCMD_RESET); - ret = wait_for_bit(__func__, usb_cmd, UCMD_RESET, false, 10000, false); + ret = wait_for_bit_le32(usb_cmd, UCMD_RESET, false, 10000, false); if (ret) return ret; @@ -331,7 +336,7 @@ int ehci_mx6_common_init(struct usb_ehci *ehci, int index) return 0; } -#ifndef CONFIG_DM_USB +#if !CONFIG_IS_ENABLED(DM_USB) int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { @@ -384,6 +389,7 @@ int ehci_hcd_stop(int index) 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; }; @@ -399,7 +405,17 @@ static int mx6_init_after_reset(struct ehci_ctrl *dev) if (ret) return ret; - board_ehci_power(priv->portnr, (type == USB_INIT_DEVICE) ? 0 : 1); +#if CONFIG_IS_ENABLED(DM_REGULATOR) + 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; + } + } +#endif if (type == USB_INIT_DEVICE) return 0; @@ -417,24 +433,147 @@ 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); + enum usb_dr_mode dr_mode; + + dr_mode = usb_get_dr_mode(dev_of_offset(dev)); + + switch (dr_mode) { + case USB_DR_MODE_HOST: + plat->init_type = USB_INIT_HOST; + break; + case USB_DR_MODE_PERIPHERAL: + plat->init_type = USB_INIT_DEVICE; + break; + case USB_DR_MODE_OTG: + case USB_DR_MODE_UNKNOWN: + return ehci_usb_phy_mode(dev); + }; + + return 0; +} + +static int ehci_usb_bind(struct udevice *dev) +{ + /* + * TODO: + * This driver is only partly converted to DT probing and still uses + * a tremendous amount of hard-coded addresses. To make things worse, + * the driver depends on specific sequential indexing of controllers, + * from which it derives offsets in the PHY and ANATOP register sets. + * + * Here we attempt to calculate these indexes from DT information as + * well as we can. The USB controllers on all existing iMX6/iMX7 SoCs + * are placed next to each other, at addresses incremented by 0x200. + * Thus, the index is derived from the multiple of 0x200 offset from + * the first controller address. + * + * However, to complete conversion of this driver to DT probing, the + * following has to be done: + * - DM clock framework support for iMX must be implemented + * - usb_power_config() has to be converted to clock framework + * -> Thus, the ad-hoc "index" variable goes away. + * - USB PHY handling has to be factored out into separate driver + * -> Thus, the ad-hoc "index" variable goes away from the PHY + * code, the PHY driver must parse it's address from DT. This + * USB driver must find the PHY driver via DT phandle. + * -> usb_power_config() shall be moved to PHY driver + * With these changes in place, the ad-hoc indexing goes away and + * the driver is fully converted to DT probing. + */ + fdt_size_t size; + fdt_addr_t addr = devfdt_get_addr_size_index(dev, 0, &size); + + dev->req_seq = (addr - USB_BASE_ADDR) / size; + + return 0; +} + static int ehci_usb_probe(struct udevice *dev) { struct usb_platdata *plat = dev_get_platdata(dev); - struct usb_ehci *ehci = (struct usb_ehci *)dev_get_addr(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 = plat->init_type; + priv->init_type = type; +#if CONFIG_IS_ENABLED(DM_REGULATOR) + ret = device_get_supply_regulator(dev, "vbus-supply", + &priv->vbus_supply); + if (ret) + debug("%s: No vbus supply\n", dev->name); +#endif ret = ehci_mx6_common_init(ehci, priv->portnr); if (ret) return ret; - board_ehci_power(priv->portnr, (priv->init_type == USB_INIT_DEVICE) ? 0 : 1); +#if CONFIG_IS_ENABLED(DM_REGULATOR) + 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; + } + } +#endif if (priv->init_type == USB_INIT_HOST) { setbits_le32(&ehci->usbmode, CM_HOST); @@ -460,6 +599,8 @@ U_BOOT_DRIVER(usb_mx6) = { .name = "ehci_mx6", .id = UCLASS_USB, .of_match = mx6_usb_ids, + .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, + .bind = ehci_usb_bind, .probe = ehci_usb_probe, .remove = ehci_deregister, .ops = &ehci_usb_ops,