summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/dwc3-generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/dwc3-generic.c')
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c132
1 files changed, 83 insertions, 49 deletions
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index ed1b9b630e..66da5a8d6f 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);