summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorYe Li <ye.li@nxp.com>2018-10-24 01:08:26 -0700
committerYe Li <ye.li@nxp.com>2018-10-25 18:34:13 -0700
commitd62ffbb7fa3136062a977d4f8bdc0f03b464b8e4 (patch)
tree6a736ec9dc0e8f644fef127814e0962a9ccf6f63 /drivers
parenta678bfef83e7ca7c4ff3a599b23d6af176803ea1 (diff)
MLK-20057 usb: ehci-mx6: Fix usb type issue in DM driver
Currently the clocks and power of USB controller and USB PHY are both controlled by ehci-mx6 driver in device probe. However, the function "ehci_usb_ofdata_to_platdata" calls "ehci_usb_phy_mode" to access PHY registers when "dr_mode" is set to OTG, both "dr_mode" and "extcon" properties are not set in DTB. This may cause hang at accessing USB PHY registers if the power and clocks are not enabled. Change the usb type logic to more clear way: 1. plat->init_type: The requested USB mode type from uplayers 2. priv->init_type: The USB mode type specified by DTB or by the USB ID pin or by external controller like tcpc or GPIO. 3. If two init_type are not same, return failure. Align with non-DM driver. 4. USB PHY access is moved after power and clock enabled. Signed-off-by: Ye Li <ye.li@nxp.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-mx6.c55
1 files changed, 37 insertions, 18 deletions
diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c
index 494ce9e919..8f9d90a5ac 100644
--- a/drivers/usb/host/ehci-mx6.c
+++ b/drivers/usb/host/ehci-mx6.c
@@ -519,6 +519,8 @@ int ehci_hcd_stop(int index)
return 0;
}
#else
+#define USB_INIT_UNKNOWN (USB_INIT_DEVICE + 1)
+
struct ehci_mx6_priv_data {
struct ehci_ctrl ctrl;
struct usb_ehci *ehci;
@@ -592,7 +594,7 @@ int __weak board_ehci_usb_phy_mode(struct udevice *dev)
static int ehci_usb_phy_mode(struct udevice *dev)
{
- struct usb_platdata *plat = dev_get_platdata(dev);
+ struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
void *__iomem addr = (void *__iomem)devfdt_get_addr(dev);
void *__iomem phy_ctrl, *__iomem phy_status;
const void *blob = gd->fdt_blob;
@@ -631,18 +633,18 @@ static int ehci_usb_phy_mode(struct udevice *dev)
val = readl(phy_ctrl);
if (val & USBPHY_CTRL_OTG_ID)
- plat->init_type = USB_INIT_DEVICE;
+ priv->init_type = USB_INIT_DEVICE;
else
- plat->init_type = USB_INIT_HOST;
+ priv->init_type = USB_INIT_HOST;
} else if (is_mx7() || is_imx8mm()) {
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;
+ priv->init_type = USB_INIT_DEVICE;
else
- plat->init_type = USB_INIT_HOST;
+ priv->init_type = USB_INIT_HOST;
} else {
return -EINVAL;
}
@@ -653,31 +655,36 @@ static int ehci_usb_phy_mode(struct udevice *dev)
static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
{
struct usb_platdata *plat = dev_get_platdata(dev);
+ struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
const char *mode;
const struct fdt_property *extcon;
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;
+ priv->init_type = USB_INIT_DEVICE;
else if (strcmp(mode, "host") == 0)
- plat->init_type = USB_INIT_HOST;
+ priv->init_type = USB_INIT_HOST;
else if (strcmp(mode, "otg") == 0)
- return ehci_usb_phy_mode(dev);
+ priv->init_type = USB_INIT_UNKNOWN;
else
return -EINVAL;
-
- return 0;
} else {
extcon = fdt_get_property(gd->fdt_blob, dev_of_offset(dev),
"extcon", NULL);
- if (extcon) {
- plat->init_type = board_ehci_usb_phy_mode(dev);
- return 0;
- }
+ if (extcon)
+ priv->init_type = board_ehci_usb_phy_mode(dev);
+ else
+ priv->init_type = USB_INIT_UNKNOWN;
}
- return ehci_usb_phy_mode(dev);
+ if (priv->init_type != USB_INIT_UNKNOWN && priv->init_type != plat->init_type) {
+ debug("Request USB type is %u, board forced type is %u\n",
+ plat->init_type, priv->init_type);
+ return -ENODEV;
+ }
+
+ return 0;
}
static int ehci_usb_probe(struct udevice *dev)
@@ -699,9 +706,9 @@ static int ehci_usb_probe(struct udevice *dev)
priv->ehci = ehci;
priv->portnr = dev->seq;
- priv->init_type = type;
- ret = board_usb_init(priv->portnr, priv->init_type);
+ /* Init usb board level according to the requested init type */
+ ret = board_usb_init(priv->portnr, type);
if (ret) {
printf("Failed to initialize board for USB\n");
return ret;
@@ -716,9 +723,18 @@ static int ehci_usb_probe(struct udevice *dev)
if (ret)
return ret;
+ /* If the init_type is unknown due to it is not forced in DTB, we use USB ID to detect */
+ if (priv->init_type == USB_INIT_UNKNOWN) {
+ ret = ehci_usb_phy_mode(dev);
+ if (ret)
+ return ret;
+ if (priv->init_type != type)
+ return -ENODEV;
+ }
+
if (priv->vbus_supply) {
ret = regulator_set_enable(priv->vbus_supply,
- (type == USB_INIT_DEVICE) ?
+ (priv->init_type == USB_INIT_DEVICE) ?
false : true);
if (ret) {
puts("Error enabling VBUS supply\n");
@@ -744,9 +760,12 @@ static int ehci_usb_probe(struct udevice *dev)
int ehci_usb_remove(struct udevice *dev)
{
struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
+ struct usb_platdata *plat = dev_get_platdata(dev);
ehci_deregister(dev);
+ plat->init_type = 0; /* Clean the requested usb type to host mode */
+
return board_usb_cleanup(dev->seq, priv->init_type);
}