From 70dbff1f9e462117cebd6721703a353368a7f6a6 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Sat, 19 Feb 2022 17:08:45 -0600 Subject: [PATCH] usb: ehci-omap: Use PHY system to manage phy resets There are a few boards that use hard-coded GPIO definitions in their respective defconfig files. If the GPIO's are listed in their device trees, the nop-phy can toggle the GPIO's, so the EHCI driver does not need to know anything about the GPIO's. Add functions for getting the phys and remove the GPIO toggles since the phy will now do that. Signed-off-by: Adam Ford --- drivers/usb/host/ehci-omap.c | 106 +++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 5f79279..765336a 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -128,47 +128,25 @@ static void omap_ehci_soft_phy_reset(int port) } #endif -#if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \ - defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) || \ - defined(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO) -/* controls PHY(s) reset signal(s) */ -static inline void omap_ehci_phy_reset(int on, int delay) -{ - /* - * Refer ISSUE1: - * Hold the PHY in RESET for enough time till - * PHY is settled and ready - */ - if (delay && !on) - udelay(delay); -#ifdef CONFIG_OMAP_EHCI_PHY1_RESET_GPIO - gpio_request(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, "USB PHY1 reset"); - gpio_direction_output(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO, !on); -#endif -#ifdef CONFIG_OMAP_EHCI_PHY2_RESET_GPIO - gpio_request(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, "USB PHY2 reset"); - gpio_direction_output(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO, !on); -#endif -#ifdef CONFIG_OMAP_EHCI_PHY3_RESET_GPIO - gpio_request(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, "USB PHY3 reset"); - gpio_direction_output(CONFIG_OMAP_EHCI_PHY3_RESET_GPIO, !on); -#endif - - /* Hold the PHY in RESET for enough time till DIR is high */ - /* Refer: ISSUE1 */ - if (delay && on) - udelay(delay); -} -#else -#define omap_ehci_phy_reset(on, delay) do {} while (0) +struct ehci_omap_priv_data { + struct ehci_ctrl ctrl; + struct omap_ehci *ehci; +#ifdef CONFIG_DM_REGULATOR + struct udevice *vbus_supply; #endif + enum usb_init_type init_type; + int portnr; + struct phy phy[OMAP_HS_USB_PORTS]; + int nports; +}; /* * Initialize the OMAP EHCI controller and PHY. * Based on "drivers/usb/host/ehci-omap.c" from Linux 3.1 * See there for additional Copyrights. */ -static int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata) +static int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pdata, + struct udevice *dev) { int ret; unsigned int i, reg = 0, rev = 0; @@ -179,8 +157,9 @@ static int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pda if (ret < 0) return ret; - /* Put the PHY in RESET */ - omap_ehci_phy_reset(1, 10); + /* Hold the PHY in RESET for enough time till DIR is high */ + /* Refer: ISSUE1 */ + udelay(10); ret = omap_uhh_reset(); if (ret < 0) @@ -259,7 +238,12 @@ static int omap_ehci_hcd_init(int index, struct omap_usbhs_board_data *usbhs_pda if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i])) omap_usbhs_hsic_init(i); - omap_ehci_phy_reset(0, 10); + /* + * Refer ISSUE1: + * Hold the PHY in RESET for enough time till + * PHY is settled and ready + */ + udelay(10); /* * An undocumented "feature" in the OMAP3 EHCI controller, @@ -328,18 +312,6 @@ U_BOOT_DRIVER(usb_omaphs_host) = { .flags = DM_FLAG_ALLOC_PRIV_DMA, }; -struct ehci_omap_priv_data { - struct ehci_ctrl ctrl; - struct omap_ehci *ehci; -#ifdef CONFIG_DM_REGULATOR - struct udevice *vbus_supply; -#endif - enum usb_init_type init_type; - int portnr; - struct phy phy[OMAP_HS_USB_PORTS]; - int nports; -}; - static int ehci_usb_of_to_plat(struct udevice *dev) { struct usb_plat *plat = dev_get_plat(dev); @@ -349,6 +321,26 @@ static int ehci_usb_of_to_plat(struct udevice *dev) return 0; } +/* + * This driver references phys based on the USB port. If + * the port is unused, the corresponding phy is listed as NULL + * which generic_phy_init_bulk treats as an error, so we need + * a custom one that tolerates empty phys + */ +static int omap_ehci_phy_get(struct udevice *dev) +{ + struct ehci_omap_priv_data *priv = dev_get_priv(dev); + int i, ret; + + for (i = 0; i < OMAP_HS_USB_PORTS; i++) { + ret = generic_phy_get_by_index(dev, i, &priv->phy[i]); + if (ret && ret != -ENOENT) + return ret; + }; + + return 0; +}; + static int omap_ehci_probe(struct udevice *dev) { struct usb_plat *plat = dev_get_plat(dev); @@ -364,7 +356,21 @@ static int omap_ehci_probe(struct udevice *dev) hccr = (struct ehci_hccr *)&priv->ehci->hccapbase; hcor = (struct ehci_hcor *)&priv->ehci->usbcmd; - ret = omap_ehci_hcd_init(0, &usbhs_bdata); + /* Identify Phys */ + ret = omap_ehci_phy_get(dev); + if (ret) { + printf("Failed to get phys\n"); + return ret; + } + + /* Register the EHCI */ + ret = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); + if (ret) { + printf("Failed to register EHCI\n"); + return ret; + } + + ret = omap_ehci_hcd_init(0, &usbhs_bdata, dev); if (ret) return ret; -- 2.7.4