Commit d62ffbb7fa3136062a977d4f8bdc0f03b464b8e4

Authored by Ye Li
1 parent a678bfef83

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>

Showing 1 changed file with 37 additions and 18 deletions Side-by-side Diff

drivers/usb/host/ehci-mx6.c
... ... @@ -519,6 +519,8 @@
519 519 return 0;
520 520 }
521 521 #else
  522 +#define USB_INIT_UNKNOWN (USB_INIT_DEVICE + 1)
  523 +
522 524 struct ehci_mx6_priv_data {
523 525 struct ehci_ctrl ctrl;
524 526 struct usb_ehci *ehci;
... ... @@ -592,7 +594,7 @@
592 594  
593 595 static int ehci_usb_phy_mode(struct udevice *dev)
594 596 {
595   - struct usb_platdata *plat = dev_get_platdata(dev);
  597 + struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
596 598 void *__iomem addr = (void *__iomem)devfdt_get_addr(dev);
597 599 void *__iomem phy_ctrl, *__iomem phy_status;
598 600 const void *blob = gd->fdt_blob;
599 601  
600 602  
601 603  
... ... @@ -631,18 +633,18 @@
631 633 val = readl(phy_ctrl);
632 634  
633 635 if (val & USBPHY_CTRL_OTG_ID)
634   - plat->init_type = USB_INIT_DEVICE;
  636 + priv->init_type = USB_INIT_DEVICE;
635 637 else
636   - plat->init_type = USB_INIT_HOST;
  638 + priv->init_type = USB_INIT_HOST;
637 639 } else if (is_mx7() || is_imx8mm()) {
638 640 phy_status = (void __iomem *)(addr +
639 641 USBNC_PHY_STATUS_OFFSET);
640 642 val = readl(phy_status);
641 643  
642 644 if (val & USBNC_PHYSTATUS_ID_DIG)
643   - plat->init_type = USB_INIT_DEVICE;
  645 + priv->init_type = USB_INIT_DEVICE;
644 646 else
645   - plat->init_type = USB_INIT_HOST;
  647 + priv->init_type = USB_INIT_HOST;
646 648 } else {
647 649 return -EINVAL;
648 650 }
649 651  
650 652  
651 653  
652 654  
653 655  
654 656  
... ... @@ -653,31 +655,36 @@
653 655 static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
654 656 {
655 657 struct usb_platdata *plat = dev_get_platdata(dev);
  658 + struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
656 659 const char *mode;
657 660 const struct fdt_property *extcon;
658 661  
659 662 mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "dr_mode", NULL);
660 663 if (mode) {
661 664 if (strcmp(mode, "peripheral") == 0)
662   - plat->init_type = USB_INIT_DEVICE;
  665 + priv->init_type = USB_INIT_DEVICE;
663 666 else if (strcmp(mode, "host") == 0)
664   - plat->init_type = USB_INIT_HOST;
  667 + priv->init_type = USB_INIT_HOST;
665 668 else if (strcmp(mode, "otg") == 0)
666   - return ehci_usb_phy_mode(dev);
  669 + priv->init_type = USB_INIT_UNKNOWN;
667 670 else
668 671 return -EINVAL;
669   -
670   - return 0;
671 672 } else {
672 673 extcon = fdt_get_property(gd->fdt_blob, dev_of_offset(dev),
673 674 "extcon", NULL);
674   - if (extcon) {
675   - plat->init_type = board_ehci_usb_phy_mode(dev);
676   - return 0;
677   - }
  675 + if (extcon)
  676 + priv->init_type = board_ehci_usb_phy_mode(dev);
  677 + else
  678 + priv->init_type = USB_INIT_UNKNOWN;
678 679 }
679 680  
680   - return ehci_usb_phy_mode(dev);
  681 + if (priv->init_type != USB_INIT_UNKNOWN && priv->init_type != plat->init_type) {
  682 + debug("Request USB type is %u, board forced type is %u\n",
  683 + plat->init_type, priv->init_type);
  684 + return -ENODEV;
  685 + }
  686 +
  687 + return 0;
681 688 }
682 689  
683 690 static int ehci_usb_probe(struct udevice *dev)
684 691  
... ... @@ -699,9 +706,9 @@
699 706  
700 707 priv->ehci = ehci;
701 708 priv->portnr = dev->seq;
702   - priv->init_type = type;
703 709  
704   - ret = board_usb_init(priv->portnr, priv->init_type);
  710 + /* Init usb board level according to the requested init type */
  711 + ret = board_usb_init(priv->portnr, type);
705 712 if (ret) {
706 713 printf("Failed to initialize board for USB\n");
707 714 return ret;
708 715  
... ... @@ -716,9 +723,18 @@
716 723 if (ret)
717 724 return ret;
718 725  
  726 + /* If the init_type is unknown due to it is not forced in DTB, we use USB ID to detect */
  727 + if (priv->init_type == USB_INIT_UNKNOWN) {
  728 + ret = ehci_usb_phy_mode(dev);
  729 + if (ret)
  730 + return ret;
  731 + if (priv->init_type != type)
  732 + return -ENODEV;
  733 + }
  734 +
719 735 if (priv->vbus_supply) {
720 736 ret = regulator_set_enable(priv->vbus_supply,
721   - (type == USB_INIT_DEVICE) ?
  737 + (priv->init_type == USB_INIT_DEVICE) ?
722 738 false : true);
723 739 if (ret) {
724 740 puts("Error enabling VBUS supply\n");
725 741  
... ... @@ -744,8 +760,11 @@
744 760 int ehci_usb_remove(struct udevice *dev)
745 761 {
746 762 struct ehci_mx6_priv_data *priv = dev_get_priv(dev);
  763 + struct usb_platdata *plat = dev_get_platdata(dev);
747 764  
748 765 ehci_deregister(dev);
  766 +
  767 + plat->init_type = 0; /* Clean the requested usb type to host mode */
749 768  
750 769 return board_usb_cleanup(dev->seq, priv->init_type);
751 770 }