diff options
Diffstat (limited to 'drivers/usb/dwc3/dwc3-generic.c')
-rw-r--r-- | drivers/usb/dwc3/dwc3-generic.c | 132 |
1 files changed, 83 insertions, 49 deletions
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 78966718d0..acbf7acb19 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -28,11 +28,7 @@ #include <usb/xhci.h> #include <asm/gpio.h> -struct dwc3_glue_data { - struct clk_bulk clks; - struct reset_ctl_bulk resets; - fdt_addr_t regs; -}; +#include "dwc3-generic.h" struct dwc3_generic_plat { fdt_addr_t base; @@ -68,10 +64,27 @@ static int dwc3_generic_probe(struct udevice *dev, #if CONFIG_IS_ENABLED(OF_CONTROL) dwc3_of_parse(dwc3); + /* + * There are currently four disparate placement possibilities of DWC3 + * reference clock phandle in SoC DTs: + * - in top level glue node, with generic subnode without clock (ZynqMP) + * - in top level generic node, with no subnode (i.MX8MQ) + * - in generic subnode, with other clock in top level node (i.MX8MP) + * - in both top level node and generic subnode (Rockchip) + * Cover all the possibilities here by looking into both nodes, start + * with the top level node as that seems to be used in majority of DTs + * to reference the clock. + */ node = dev_ofnode(dev->parent); index = ofnode_stringlist_search(node, "clock-names", "ref"); if (index < 0) index = ofnode_stringlist_search(node, "clock-names", "ref_clk"); + if (index < 0) { + node = dev_ofnode(dev); + index = ofnode_stringlist_search(node, "clock-names", "ref"); + if (index < 0) + index = ofnode_stringlist_search(node, "clock-names", "ref_clk"); + } if (index >= 0) dwc3->ref_clk = &glue->clks.clks[index]; #endif @@ -258,11 +271,6 @@ U_BOOT_DRIVER(dwc3_generic_host) = { }; #endif -struct dwc3_glue_ops { - void (*glue_configure)(struct udevice *dev, int index, - enum usb_dr_mode mode); -}; - void dwc3_imx8mp_glue_configure(struct udevice *dev, int index, enum usb_dr_mode mode) { @@ -398,54 +406,74 @@ struct dwc3_glue_ops ti_ops = { .glue_configure = dwc3_ti_glue_configure, }; -static int dwc3_glue_bind(struct udevice *parent) +static int dwc3_glue_bind_common(struct udevice *parent, ofnode node) { - ofnode node; - int ret; + const char *name = ofnode_get_name(node); + const char *driver = NULL; enum usb_dr_mode dr_mode; + struct udevice *dev; + int ret; - dr_mode = usb_get_dr_mode(dev_ofnode(parent)); - - ofnode_for_each_subnode(node, dev_ofnode(parent)) { - const char *name = ofnode_get_name(node); - struct udevice *dev; - const char *driver = NULL; - - debug("%s: subnode name: %s\n", __func__, name); + debug("%s: subnode name: %s\n", __func__, name); - /* if the parent node doesn't have a mode check the leaf */ - if (!dr_mode) - dr_mode = usb_get_dr_mode(node); + /* if the parent node doesn't have a mode check the leaf */ + dr_mode = usb_get_dr_mode(dev_ofnode(parent)); + if (!dr_mode) + dr_mode = usb_get_dr_mode(node); - switch (dr_mode) { - case USB_DR_MODE_PERIPHERAL: - case USB_DR_MODE_OTG: + switch (dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: #if CONFIG_IS_ENABLED(DM_USB_GADGET) - debug("%s: dr_mode: OTG or Peripheral\n", __func__); - driver = "dwc3-generic-peripheral"; + debug("%s: dr_mode: OTG or Peripheral\n", __func__); + driver = "dwc3-generic-peripheral"; #endif - break; + break; #if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD) - case USB_DR_MODE_HOST: - debug("%s: dr_mode: HOST\n", __func__); - driver = "dwc3-generic-host"; - break; + case USB_DR_MODE_HOST: + debug("%s: dr_mode: HOST\n", __func__); + driver = "dwc3-generic-host"; + break; #endif - default: - debug("%s: unsupported dr_mode\n", __func__); - return -ENODEV; - }; + default: + debug("%s: unsupported dr_mode\n", __func__); + return -ENODEV; + }; - if (!driver) - continue; + if (!driver) + return -ENXIO; + + ret = device_bind_driver_to_node(parent, driver, name, + node, &dev); + if (ret) { + debug("%s: not able to bind usb device mode\n", + __func__); + return ret; + } + + return 0; +} - ret = device_bind_driver_to_node(parent, driver, name, - node, &dev); - if (ret) { - debug("%s: not able to bind usb device mode\n", - __func__); +int dwc3_glue_bind(struct udevice *parent) +{ + struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(parent); + ofnode node; + int ret; + + if (ops && ops->glue_get_ctrl_dev) { + ret = ops->glue_get_ctrl_dev(parent, &node); + if (ret) + return ret; + + return dwc3_glue_bind_common(parent, node); + } + + ofnode_for_each_subnode(node, dev_ofnode(parent)) { + ret = dwc3_glue_bind_common(parent, node); + if (ret == -ENXIO) + continue; + if (ret) return ret; - } } return 0; @@ -493,7 +521,7 @@ static int dwc3_glue_clk_init(struct udevice *dev, return 0; } -static int dwc3_glue_probe(struct udevice *dev) +int dwc3_glue_probe(struct udevice *dev) { struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev); struct dwc3_glue_data *glue = dev_get_plat(dev); @@ -514,7 +542,7 @@ static int dwc3_glue_probe(struct udevice *dev) phy.dev = NULL; } - glue->regs = dev_read_addr(dev); + glue->regs = dev_read_addr_size_index(dev, 0, &glue->size); ret = dwc3_glue_clk_init(dev, glue); if (ret) @@ -534,6 +562,12 @@ static int dwc3_glue_probe(struct udevice *dev) if (ret) return ret; + if (glue->clks.count == 0) { + ret = dwc3_glue_clk_init(child, glue); + if (ret) + return ret; + } + if (glue->resets.count == 0) { ret = dwc3_glue_reset_init(child, glue); if (ret) @@ -553,7 +587,7 @@ static int dwc3_glue_probe(struct udevice *dev) return 0; } -static int dwc3_glue_remove(struct udevice *dev) +int dwc3_glue_remove(struct udevice *dev) { struct dwc3_glue_data *glue = dev_get_plat(dev); |