diff mbox series

[U-Boot,v2,3/6] usb: dwc3: Add generic DWC3 glue logic driver

Message ID f125fb68a257476436ec14ae31a8ac7c51dfdfd1.1526642103.git.michal.simek@xilinx.com
State Accepted
Commit 49d674547c5bf668802b4b6a24218205fed957f0
Delegated to: Marek Vasut
Headers show
Series Convert Xilinx ZynqMP to DM_USB with generic DWC3 glue logic driver | expand

Commit Message

Michal Simek May 18, 2018, 11:15 a.m. UTC
By enabling BLK by default this is the next driver which needs to get
support for DM_USB. Adding generic DWC3 glue logic which only
parse nodes and read device mode. Based on it probe proper
host/peripheral DWC3 drivers for it.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---

Changes in v2:
- Change style to avoid correct but not nice indentation by using char
  *driver variable (suggested by Marek)

 drivers/usb/dwc3/Kconfig        |   6 ++
 drivers/usb/dwc3/Makefile       |   1 +
 drivers/usb/dwc3/dwc3-generic.c | 157 ++++++++++++++++++++++++++++++++
 3 files changed, 164 insertions(+)
 create mode 100644 drivers/usb/dwc3/dwc3-generic.c

Comments

Jean-Jacques Hiblot May 18, 2018, 1:24 p.m. UTC | #1
On 18/05/2018 13:15, Michal Simek wrote:
> By enabling BLK by default this is the next driver which needs to get
> support for DM_USB. Adding generic DWC3 glue logic which only
> parse nodes and read device mode. Based on it probe proper
> host/peripheral DWC3 drivers for it.
>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
>
> Changes in v2:
> - Change style to avoid correct but not nice indentation by using char
>    *driver variable (suggested by Marek)
>
>   drivers/usb/dwc3/Kconfig        |   6 ++
>   drivers/usb/dwc3/Makefile       |   1 +
>   drivers/usb/dwc3/dwc3-generic.c | 157 ++++++++++++++++++++++++++++++++
>   3 files changed, 164 insertions(+)
>   create mode 100644 drivers/usb/dwc3/dwc3-generic.c
>
> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
> index ae7fc1c6304d..943b7630eba4 100644
> --- a/drivers/usb/dwc3/Kconfig
> +++ b/drivers/usb/dwc3/Kconfig
> @@ -37,6 +37,12 @@ config USB_DWC3_OMAP
>   
>   	  Say 'Y' here if you have one such device
>   
> +config USB_DWC3_GENERIC
> +	bool "Xilinx ZynqMP and similar Platforms"
> +	depends on DM_USB && USB_DWC3
> +	help
> +	  Some platforms can reuse this DWC3 generic implementation.
> +
>   config USB_DWC3_UNIPHIER
>   	bool "DesignWare USB3 Host Support on UniPhier Platforms"
>   	depends on ARCH_UNIPHIER && USB_XHCI_DWC3
> diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
> index cd18b8d9ec02..60b5515a67da 100644
> --- a/drivers/usb/dwc3/Makefile
> +++ b/drivers/usb/dwc3/Makefile
> @@ -7,6 +7,7 @@ dwc3-y					:= core.o
>   obj-$(CONFIG_USB_DWC3_GADGET)		+= gadget.o ep0.o
>   
>   obj-$(CONFIG_USB_DWC3_OMAP)		+= dwc3-omap.o
> +obj-$(CONFIG_USB_DWC3_GENERIC)		+= dwc3-generic.o
>   obj-$(CONFIG_USB_DWC3_UNIPHIER)		+= dwc3-uniphier.o
>   obj-$(CONFIG_USB_DWC3_PHY_OMAP)		+= ti_usb_phy.o
>   obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG)	+= samsung_usb_phy.o
> diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
> new file mode 100644
> index 000000000000..ca63eac3d98e
> --- /dev/null
> +++ b/drivers/usb/dwc3/dwc3-generic.c
> @@ -0,0 +1,157 @@
> +// SPDX-License-Identifier:     GPL-2.0
> +/*
> + * Generic DWC3 Glue layer
> + *
> + * Copyright (C) 2016 - 2018 Xilinx, Inc.
> + *
> + * Based on dwc3-omap.c.
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <dm/device-internal.h>
> +#include <dm/lists.h>
> +#include <linux/usb/otg.h>
> +#include <linux/compat.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +#include <malloc.h>
> +#include <usb.h>
> +#include "core.h"
> +#include "gadget.h"
> +#include "linux-compat.h"
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +int usb_gadget_handle_interrupts(int index)
> +{
> +	struct dwc3 *priv;
> +	struct udevice *dev;
> +	int ret;
> +
> +	ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev);
> +	if (!dev || ret) {
> +		pr_err("No USB device found\n");
> +		return -ENODEV;
> +	}
> +
> +	priv = dev_get_priv(dev);
> +
> +	dwc3_gadget_uboot_handle_interrupt(priv);
> +
> +	return 0;
> +}
> +
> +static int dwc3_generic_peripheral_probe(struct udevice *dev)
> +{
> +	struct dwc3 *priv = dev_get_priv(dev);
> +
> +	return dwc3_init(priv);
> +}
> +
> +static int dwc3_generic_peripheral_remove(struct udevice *dev)
> +{
> +	struct dwc3 *priv = dev_get_priv(dev);
> +
> +	dwc3_remove(priv);
> +
> +	return 0;
> +}
> +
> +static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev)
> +{
> +	struct dwc3 *priv = dev_get_priv(dev);
> +	int node = dev_of_offset(dev);
> +
> +	priv->regs = (void *)devfdt_get_addr(dev);
> +	priv->regs += DWC3_GLOBALS_REGS_START;
> +
> +	priv->maximum_speed = usb_get_maximum_speed(node);
> +	if (priv->maximum_speed == USB_SPEED_UNKNOWN) {
> +		pr_err("Invalid usb maximum speed\n");
> +		return -ENODEV;
> +	}
> +
> +	priv->dr_mode = usb_get_dr_mode(node);
> +	if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
> +		pr_err("Invalid usb mode setup\n");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dwc3_generic_peripheral_bind(struct udevice *dev)
> +{
> +	return device_probe(dev);
This is wrong place to probe the device.
What must be done is to probe the device when it is first used.
I have a patch in progress for this. When it's cleaned up I'll share a 
repo so that you can have look and maybe pick it up.
> +}
> +
> +U_BOOT_DRIVER(dwc3_generic_peripheral) = {
> +	.name	= "dwc3-generic-peripheral",
> +	.id	= UCLASS_USB_DEV_GENERIC,
> +	.ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata,
> +	.probe = dwc3_generic_peripheral_probe,
> +	.remove = dwc3_generic_peripheral_remove,
> +	.bind = dwc3_generic_peripheral_bind,
> +	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
> +	.priv_auto_alloc_size = sizeof(struct dwc3),
> +	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
> +};
> +
> +static int dwc3_generic_bind(struct udevice *parent)
> +{
> +	const void *fdt = gd->fdt_blob;
> +	int node;
> +	int ret;
> +
> +	for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
> +	     node = fdt_next_subnode(fdt, node)) {
> +		const char *name = fdt_get_name(fdt, node, NULL);
> +		enum usb_dr_mode dr_mode;
> +		struct udevice *dev;
> +		const char *driver;
> +
> +		debug("%s: subnode name: %s\n", __func__, name);
> +		if (strncmp(name, "dwc3@", 4))
> +			continue;
> +
> +		dr_mode = usb_get_dr_mode(node);
> +
> +		switch (dr_mode) {
> +		case USB_DR_MODE_PERIPHERAL:
> +		case USB_DR_MODE_OTG:
> +			debug("%s: dr_mode: OTG or Peripheral\n", __func__);
> +			driver = "dwc3-generic-peripheral";
> +			break;
> +		case USB_DR_MODE_HOST:
> +			debug("%s: dr_mode: HOST\n", __func__);
> +			driver = "dwc3-generic-host";
> +			break;
> +		default:
> +			debug("%s: unsupported dr_mode\n", __func__);
> +			return -ENODEV;
> +		};
> +
> +		ret = device_bind_driver_to_node(parent, driver, name,
> +						 offset_to_ofnode(node), &dev);
> +		if (ret) {
> +			debug("%s: not able to bind usb device mode\n",
> +			      __func__);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct udevice_id dwc3_generic_ids[] = {
> +	{ .compatible = "xlnx,zynqmp-dwc3" },
> +	{ }
> +};
> +
> +U_BOOT_DRIVER(dwc3_generic_wrapper) = {
> +	.name	= "dwc3-generic-wrapper",
> +	.id	= UCLASS_MISC,
> +	.of_match = dwc3_generic_ids,
> +	.bind = dwc3_generic_bind,
> +};
Jean-Jacques Hiblot May 18, 2018, 1:26 p.m. UTC | #2
On 18/05/2018 15:24, Jean-Jacques Hiblot wrote:
>
>
> On 18/05/2018 13:15, Michal Simek wrote:
>> By enabling BLK by default this is the next driver which needs to get
>> support for DM_USB. Adding generic DWC3 glue logic which only
>> parse nodes and read device mode. Based on it probe proper
>> host/peripheral DWC3 drivers for it.
>>
>> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>> ---
>>
>> Changes in v2:
>> - Change style to avoid correct but not nice indentation by using char
>>    *driver variable (suggested by Marek)
>>
>>   drivers/usb/dwc3/Kconfig        |   6 ++
>>   drivers/usb/dwc3/Makefile       |   1 +
>>   drivers/usb/dwc3/dwc3-generic.c | 157 ++++++++++++++++++++++++++++++++
>>   3 files changed, 164 insertions(+)
>>   create mode 100644 drivers/usb/dwc3/dwc3-generic.c
>>
>> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
>> index ae7fc1c6304d..943b7630eba4 100644
>> --- a/drivers/usb/dwc3/Kconfig
>> +++ b/drivers/usb/dwc3/Kconfig
>> @@ -37,6 +37,12 @@ config USB_DWC3_OMAP
>>           Say 'Y' here if you have one such device
>>   +config USB_DWC3_GENERIC
>> +    bool "Xilinx ZynqMP and similar Platforms"
>> +    depends on DM_USB && USB_DWC3
>> +    help
>> +      Some platforms can reuse this DWC3 generic implementation.
>> +
>>   config USB_DWC3_UNIPHIER
>>       bool "DesignWare USB3 Host Support on UniPhier Platforms"
>>       depends on ARCH_UNIPHIER && USB_XHCI_DWC3
>> diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
>> index cd18b8d9ec02..60b5515a67da 100644
>> --- a/drivers/usb/dwc3/Makefile
>> +++ b/drivers/usb/dwc3/Makefile
>> @@ -7,6 +7,7 @@ dwc3-y                    := core.o
>>   obj-$(CONFIG_USB_DWC3_GADGET)        += gadget.o ep0.o
>>     obj-$(CONFIG_USB_DWC3_OMAP)        += dwc3-omap.o
>> +obj-$(CONFIG_USB_DWC3_GENERIC)        += dwc3-generic.o
>>   obj-$(CONFIG_USB_DWC3_UNIPHIER)        += dwc3-uniphier.o
>>   obj-$(CONFIG_USB_DWC3_PHY_OMAP)        += ti_usb_phy.o
>>   obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG)    += samsung_usb_phy.o
>> diff --git a/drivers/usb/dwc3/dwc3-generic.c 
>> b/drivers/usb/dwc3/dwc3-generic.c
>> new file mode 100644
>> index 000000000000..ca63eac3d98e
>> --- /dev/null
>> +++ b/drivers/usb/dwc3/dwc3-generic.c
>> @@ -0,0 +1,157 @@
>> +// SPDX-License-Identifier:     GPL-2.0
>> +/*
>> + * Generic DWC3 Glue layer
>> + *
>> + * Copyright (C) 2016 - 2018 Xilinx, Inc.
>> + *
>> + * Based on dwc3-omap.c.
>> + */
>> +
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <dm/device-internal.h>
>> +#include <dm/lists.h>
>> +#include <linux/usb/otg.h>
>> +#include <linux/compat.h>
>> +#include <linux/usb/ch9.h>
>> +#include <linux/usb/gadget.h>
>> +#include <malloc.h>
>> +#include <usb.h>
>> +#include "core.h"
>> +#include "gadget.h"
>> +#include "linux-compat.h"
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +int usb_gadget_handle_interrupts(int index)
>> +{
>> +    struct dwc3 *priv;
>> +    struct udevice *dev;
>> +    int ret;
>> +
>> +    ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev);
>> +    if (!dev || ret) {
>> +        pr_err("No USB device found\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    priv = dev_get_priv(dev);
>> +
>> +    dwc3_gadget_uboot_handle_interrupt(priv);
>> +
>> +    return 0;
>> +}
>> +
>> +static int dwc3_generic_peripheral_probe(struct udevice *dev)
>> +{
>> +    struct dwc3 *priv = dev_get_priv(dev);
>> +
>> +    return dwc3_init(priv);
>> +}
>> +
>> +static int dwc3_generic_peripheral_remove(struct udevice *dev)
>> +{
>> +    struct dwc3 *priv = dev_get_priv(dev);
>> +
>> +    dwc3_remove(priv);
>> +
>> +    return 0;
>> +}
>> +
>> +static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice 
>> *dev)
>> +{
>> +    struct dwc3 *priv = dev_get_priv(dev);
>> +    int node = dev_of_offset(dev);
>> +
>> +    priv->regs = (void *)devfdt_get_addr(dev);
>> +    priv->regs += DWC3_GLOBALS_REGS_START;
>> +
>> +    priv->maximum_speed = usb_get_maximum_speed(node);
>> +    if (priv->maximum_speed == USB_SPEED_UNKNOWN) {
>> +        pr_err("Invalid usb maximum speed\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    priv->dr_mode = usb_get_dr_mode(node);
>> +    if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
>> +        pr_err("Invalid usb mode setup\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int dwc3_generic_peripheral_bind(struct udevice *dev)
>> +{
>> +    return device_probe(dev);
> This is wrong place to probe the device.
> What must be done is to probe the device when it is first used.
> I have a patch in progress for this. When it's cleaned up I'll share a 
> repo so that you can have look and maybe pick it up.
Well the series is already applied. I'll send the patch to ML in this case.
>> +}
>> +
>> +U_BOOT_DRIVER(dwc3_generic_peripheral) = {
>> +    .name    = "dwc3-generic-peripheral",
>> +    .id    = UCLASS_USB_DEV_GENERIC,
>> +    .ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata,
>> +    .probe = dwc3_generic_peripheral_probe,
>> +    .remove = dwc3_generic_peripheral_remove,
>> +    .bind = dwc3_generic_peripheral_bind,
>> +    .platdata_auto_alloc_size = sizeof(struct usb_platdata),
>> +    .priv_auto_alloc_size = sizeof(struct dwc3),
>> +    .flags    = DM_FLAG_ALLOC_PRIV_DMA,
>> +};
>> +
>> +static int dwc3_generic_bind(struct udevice *parent)
>> +{
>> +    const void *fdt = gd->fdt_blob;
>> +    int node;
>> +    int ret;
>> +
>> +    for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node 
>> > 0;
>> +         node = fdt_next_subnode(fdt, node)) {
>> +        const char *name = fdt_get_name(fdt, node, NULL);
>> +        enum usb_dr_mode dr_mode;
>> +        struct udevice *dev;
>> +        const char *driver;
>> +
>> +        debug("%s: subnode name: %s\n", __func__, name);
>> +        if (strncmp(name, "dwc3@", 4))
>> +            continue;
>> +
>> +        dr_mode = usb_get_dr_mode(node);
>> +
>> +        switch (dr_mode) {
>> +        case USB_DR_MODE_PERIPHERAL:
>> +        case USB_DR_MODE_OTG:
>> +            debug("%s: dr_mode: OTG or Peripheral\n", __func__);
>> +            driver = "dwc3-generic-peripheral";
>> +            break;
>> +        case USB_DR_MODE_HOST:
>> +            debug("%s: dr_mode: HOST\n", __func__);
>> +            driver = "dwc3-generic-host";
>> +            break;
>> +        default:
>> +            debug("%s: unsupported dr_mode\n", __func__);
>> +            return -ENODEV;
>> +        };
>> +
>> +        ret = device_bind_driver_to_node(parent, driver, name,
>> +                         offset_to_ofnode(node), &dev);
>> +        if (ret) {
>> +            debug("%s: not able to bind usb device mode\n",
>> +                  __func__);
>> +            return ret;
>> +        }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct udevice_id dwc3_generic_ids[] = {
>> +    { .compatible = "xlnx,zynqmp-dwc3" },
>> +    { }
>> +};
>> +
>> +U_BOOT_DRIVER(dwc3_generic_wrapper) = {
>> +    .name    = "dwc3-generic-wrapper",
>> +    .id    = UCLASS_MISC,
>> +    .of_match = dwc3_generic_ids,
>> +    .bind = dwc3_generic_bind,
>> +};
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> https://lists.denx.de/listinfo/u-boot
Michal Simek May 21, 2018, 6:45 a.m. UTC | #3
On 18.5.2018 15:26, Jean-Jacques Hiblot wrote:
> 
> 
> On 18/05/2018 15:24, Jean-Jacques Hiblot wrote:
>>
>>
>> On 18/05/2018 13:15, Michal Simek wrote:
>>> By enabling BLK by default this is the next driver which needs to get
>>> support for DM_USB. Adding generic DWC3 glue logic which only
>>> parse nodes and read device mode. Based on it probe proper
>>> host/peripheral DWC3 drivers for it.
>>>
>>> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>>> ---
>>>
>>> Changes in v2:
>>> - Change style to avoid correct but not nice indentation by using char
>>>    *driver variable (suggested by Marek)
>>>
>>>   drivers/usb/dwc3/Kconfig        |   6 ++
>>>   drivers/usb/dwc3/Makefile       |   1 +
>>>   drivers/usb/dwc3/dwc3-generic.c | 157 ++++++++++++++++++++++++++++++++
>>>   3 files changed, 164 insertions(+)
>>>   create mode 100644 drivers/usb/dwc3/dwc3-generic.c
>>>
>>> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
>>> index ae7fc1c6304d..943b7630eba4 100644
>>> --- a/drivers/usb/dwc3/Kconfig
>>> +++ b/drivers/usb/dwc3/Kconfig
>>> @@ -37,6 +37,12 @@ config USB_DWC3_OMAP
>>>           Say 'Y' here if you have one such device
>>>   +config USB_DWC3_GENERIC
>>> +    bool "Xilinx ZynqMP and similar Platforms"
>>> +    depends on DM_USB && USB_DWC3
>>> +    help
>>> +      Some platforms can reuse this DWC3 generic implementation.
>>> +
>>>   config USB_DWC3_UNIPHIER
>>>       bool "DesignWare USB3 Host Support on UniPhier Platforms"
>>>       depends on ARCH_UNIPHIER && USB_XHCI_DWC3
>>> diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
>>> index cd18b8d9ec02..60b5515a67da 100644
>>> --- a/drivers/usb/dwc3/Makefile
>>> +++ b/drivers/usb/dwc3/Makefile
>>> @@ -7,6 +7,7 @@ dwc3-y                    := core.o
>>>   obj-$(CONFIG_USB_DWC3_GADGET)        += gadget.o ep0.o
>>>     obj-$(CONFIG_USB_DWC3_OMAP)        += dwc3-omap.o
>>> +obj-$(CONFIG_USB_DWC3_GENERIC)        += dwc3-generic.o
>>>   obj-$(CONFIG_USB_DWC3_UNIPHIER)        += dwc3-uniphier.o
>>>   obj-$(CONFIG_USB_DWC3_PHY_OMAP)        += ti_usb_phy.o
>>>   obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG)    += samsung_usb_phy.o
>>> diff --git a/drivers/usb/dwc3/dwc3-generic.c
>>> b/drivers/usb/dwc3/dwc3-generic.c
>>> new file mode 100644
>>> index 000000000000..ca63eac3d98e
>>> --- /dev/null
>>> +++ b/drivers/usb/dwc3/dwc3-generic.c
>>> @@ -0,0 +1,157 @@
>>> +// SPDX-License-Identifier:     GPL-2.0
>>> +/*
>>> + * Generic DWC3 Glue layer
>>> + *
>>> + * Copyright (C) 2016 - 2018 Xilinx, Inc.
>>> + *
>>> + * Based on dwc3-omap.c.
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <dm.h>
>>> +#include <dm/device-internal.h>
>>> +#include <dm/lists.h>
>>> +#include <linux/usb/otg.h>
>>> +#include <linux/compat.h>
>>> +#include <linux/usb/ch9.h>
>>> +#include <linux/usb/gadget.h>
>>> +#include <malloc.h>
>>> +#include <usb.h>
>>> +#include "core.h"
>>> +#include "gadget.h"
>>> +#include "linux-compat.h"
>>> +
>>> +DECLARE_GLOBAL_DATA_PTR;
>>> +
>>> +int usb_gadget_handle_interrupts(int index)
>>> +{
>>> +    struct dwc3 *priv;
>>> +    struct udevice *dev;
>>> +    int ret;
>>> +
>>> +    ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev);
>>> +    if (!dev || ret) {
>>> +        pr_err("No USB device found\n");
>>> +        return -ENODEV;
>>> +    }
>>> +
>>> +    priv = dev_get_priv(dev);
>>> +
>>> +    dwc3_gadget_uboot_handle_interrupt(priv);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int dwc3_generic_peripheral_probe(struct udevice *dev)
>>> +{
>>> +    struct dwc3 *priv = dev_get_priv(dev);
>>> +
>>> +    return dwc3_init(priv);
>>> +}
>>> +
>>> +static int dwc3_generic_peripheral_remove(struct udevice *dev)
>>> +{
>>> +    struct dwc3 *priv = dev_get_priv(dev);
>>> +
>>> +    dwc3_remove(priv);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice
>>> *dev)
>>> +{
>>> +    struct dwc3 *priv = dev_get_priv(dev);
>>> +    int node = dev_of_offset(dev);
>>> +
>>> +    priv->regs = (void *)devfdt_get_addr(dev);
>>> +    priv->regs += DWC3_GLOBALS_REGS_START;
>>> +
>>> +    priv->maximum_speed = usb_get_maximum_speed(node);
>>> +    if (priv->maximum_speed == USB_SPEED_UNKNOWN) {
>>> +        pr_err("Invalid usb maximum speed\n");
>>> +        return -ENODEV;
>>> +    }
>>> +
>>> +    priv->dr_mode = usb_get_dr_mode(node);
>>> +    if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
>>> +        pr_err("Invalid usb mode setup\n");
>>> +        return -ENODEV;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int dwc3_generic_peripheral_bind(struct udevice *dev)
>>> +{
>>> +    return device_probe(dev);
>> This is wrong place to probe the device.
>> What must be done is to probe the device when it is first used.
>> I have a patch in progress for this. When it's cleaned up I'll share a
>> repo so that you can have look and maybe pick it up.
> Well the series is already applied. I'll send the patch to ML in this case.

Yes. Please cc me if you want to test something.

Thanks,
Michal
diff mbox series

Patch

diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index ae7fc1c6304d..943b7630eba4 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -37,6 +37,12 @@  config USB_DWC3_OMAP
 
 	  Say 'Y' here if you have one such device
 
+config USB_DWC3_GENERIC
+	bool "Xilinx ZynqMP and similar Platforms"
+	depends on DM_USB && USB_DWC3
+	help
+	  Some platforms can reuse this DWC3 generic implementation.
+
 config USB_DWC3_UNIPHIER
 	bool "DesignWare USB3 Host Support on UniPhier Platforms"
 	depends on ARCH_UNIPHIER && USB_XHCI_DWC3
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index cd18b8d9ec02..60b5515a67da 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -7,6 +7,7 @@  dwc3-y					:= core.o
 obj-$(CONFIG_USB_DWC3_GADGET)		+= gadget.o ep0.o
 
 obj-$(CONFIG_USB_DWC3_OMAP)		+= dwc3-omap.o
+obj-$(CONFIG_USB_DWC3_GENERIC)		+= dwc3-generic.o
 obj-$(CONFIG_USB_DWC3_UNIPHIER)		+= dwc3-uniphier.o
 obj-$(CONFIG_USB_DWC3_PHY_OMAP)		+= ti_usb_phy.o
 obj-$(CONFIG_USB_DWC3_PHY_SAMSUNG)	+= samsung_usb_phy.o
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
new file mode 100644
index 000000000000..ca63eac3d98e
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -0,0 +1,157 @@ 
+// SPDX-License-Identifier:     GPL-2.0
+/*
+ * Generic DWC3 Glue layer
+ *
+ * Copyright (C) 2016 - 2018 Xilinx, Inc.
+ *
+ * Based on dwc3-omap.c.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <linux/usb/otg.h>
+#include <linux/compat.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <malloc.h>
+#include <usb.h>
+#include "core.h"
+#include "gadget.h"
+#include "linux-compat.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int usb_gadget_handle_interrupts(int index)
+{
+	struct dwc3 *priv;
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_USB_DEV_GENERIC, &dev);
+	if (!dev || ret) {
+		pr_err("No USB device found\n");
+		return -ENODEV;
+	}
+
+	priv = dev_get_priv(dev);
+
+	dwc3_gadget_uboot_handle_interrupt(priv);
+
+	return 0;
+}
+
+static int dwc3_generic_peripheral_probe(struct udevice *dev)
+{
+	struct dwc3 *priv = dev_get_priv(dev);
+
+	return dwc3_init(priv);
+}
+
+static int dwc3_generic_peripheral_remove(struct udevice *dev)
+{
+	struct dwc3 *priv = dev_get_priv(dev);
+
+	dwc3_remove(priv);
+
+	return 0;
+}
+
+static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev)
+{
+	struct dwc3 *priv = dev_get_priv(dev);
+	int node = dev_of_offset(dev);
+
+	priv->regs = (void *)devfdt_get_addr(dev);
+	priv->regs += DWC3_GLOBALS_REGS_START;
+
+	priv->maximum_speed = usb_get_maximum_speed(node);
+	if (priv->maximum_speed == USB_SPEED_UNKNOWN) {
+		pr_err("Invalid usb maximum speed\n");
+		return -ENODEV;
+	}
+
+	priv->dr_mode = usb_get_dr_mode(node);
+	if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
+		pr_err("Invalid usb mode setup\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int dwc3_generic_peripheral_bind(struct udevice *dev)
+{
+	return device_probe(dev);
+}
+
+U_BOOT_DRIVER(dwc3_generic_peripheral) = {
+	.name	= "dwc3-generic-peripheral",
+	.id	= UCLASS_USB_DEV_GENERIC,
+	.ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata,
+	.probe = dwc3_generic_peripheral_probe,
+	.remove = dwc3_generic_peripheral_remove,
+	.bind = dwc3_generic_peripheral_bind,
+	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
+	.priv_auto_alloc_size = sizeof(struct dwc3),
+	.flags	= DM_FLAG_ALLOC_PRIV_DMA,
+};
+
+static int dwc3_generic_bind(struct udevice *parent)
+{
+	const void *fdt = gd->fdt_blob;
+	int node;
+	int ret;
+
+	for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
+	     node = fdt_next_subnode(fdt, node)) {
+		const char *name = fdt_get_name(fdt, node, NULL);
+		enum usb_dr_mode dr_mode;
+		struct udevice *dev;
+		const char *driver;
+
+		debug("%s: subnode name: %s\n", __func__, name);
+		if (strncmp(name, "dwc3@", 4))
+			continue;
+
+		dr_mode = usb_get_dr_mode(node);
+
+		switch (dr_mode) {
+		case USB_DR_MODE_PERIPHERAL:
+		case USB_DR_MODE_OTG:
+			debug("%s: dr_mode: OTG or Peripheral\n", __func__);
+			driver = "dwc3-generic-peripheral";
+			break;
+		case USB_DR_MODE_HOST:
+			debug("%s: dr_mode: HOST\n", __func__);
+			driver = "dwc3-generic-host";
+			break;
+		default:
+			debug("%s: unsupported dr_mode\n", __func__);
+			return -ENODEV;
+		};
+
+		ret = device_bind_driver_to_node(parent, driver, name,
+						 offset_to_ofnode(node), &dev);
+		if (ret) {
+			debug("%s: not able to bind usb device mode\n",
+			      __func__);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct udevice_id dwc3_generic_ids[] = {
+	{ .compatible = "xlnx,zynqmp-dwc3" },
+	{ }
+};
+
+U_BOOT_DRIVER(dwc3_generic_wrapper) = {
+	.name	= "dwc3-generic-wrapper",
+	.id	= UCLASS_MISC,
+	.of_match = dwc3_generic_ids,
+	.bind = dwc3_generic_bind,
+};