Commit d62ffbb7fa3136062a977d4f8bdc0f03b464b8e4
1 parent
a678bfef83
Exists in
smarc_8mm-imx_v2018.03_4.14.98_2.0.0_ga
and in
5 other branches
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 | } |
-
mentioned in commit 77f25b
-
mentioned in commit 77f25b
-
mentioned in commit c9499e
-
mentioned in commit c9499e
-
mentioned in commit c9499e
-
mentioned in commit c9499e
-
mentioned in commit ab9f0e
-
mentioned in commit ab9f0e
-
mentioned in commit c9499e
-
mentioned in commit ab9f0e
-
mentioned in commit ab9f0e
-
mentioned in commit ab9f0e
-
mentioned in commit ab9f0e
-
mentioned in commit 55d594