From ad991472e7b112ef6ba96d8a0672e4caa5a07ae4 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Fri, 12 Apr 2019 10:51:05 +0000 Subject: configs: Migrate USB_MUSB_DISABLE_BULK_COMBINE_SPLIT to Kconfig Migrate support for disable MUSB bulk split/combine to Kconfig Green Travis build: https://travis-ci.org/akiernan/u-boot/builds/519101867 Signed-off-by: Alex Kiernan --- drivers/usb/musb-new/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig index f8f2205a62..fdf9ca61da 100644 --- a/drivers/usb/musb-new/Kconfig +++ b/drivers/usb/musb-new/Kconfig @@ -54,6 +54,15 @@ config USB_MUSB_SUNXI Say y here to enable support for the sunxi OTG / DRC USB controller used on almost all sunxi boards. +config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT + bool "Disable MUSB bulk split/combine" + default y + help + On TI AM335x devices, MUSB has bulk split/combine feature enabled + in the ConfigData register, but the current MUSB driver does not + support it yet. Select this option to disable the feature until the + driver adds the support. + endif config USB_MUSB_PIO_ONLY -- cgit From 17982a2855b920a855350ea920a965cfdd1863c0 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Thu, 18 Apr 2019 11:10:50 +0000 Subject: usb: Select USB_MUSB_DSPS with USB_MUSB_TI USB_MUSB_TI requires USB_MUSB_DSPS, failing at link time if it's not selected: drivers/usb/musb-new/built-in.o: In function `ti_musb_host_ofdata_to_platdata': drivers/usb/musb-new/ti-musb.c:193: undefined reference to `musb_dsps_ops' or if OF_CONTROL is not selected: arch/arm/mach-omap2/built-in.o:(.data.usb0+0x24): undefined reference to `musb_dsps_ops' Reviewed-by: Hannes Schmelzer Tested-by: Hannes Schmelzer Signed-off-by: Alex Kiernan --- drivers/usb/musb-new/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb') diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig index fdf9ca61da..75005ccdd1 100644 --- a/drivers/usb/musb-new/Kconfig +++ b/drivers/usb/musb-new/Kconfig @@ -21,6 +21,7 @@ config USB_MUSB_GADGET config USB_MUSB_TI bool "Enable TI OTG USB controller" depends on DM_USB + select USB_MUSB_DSPS default n help Say y here to enable support for the dual role high -- cgit From a812d77617749eeaddfa8b9796b9a2eece1ad2f5 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:14 +0100 Subject: usb: dwc2: remove unused variable regs_otg Remove the global regs_otg variable. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 3c7ad033e3..edca05d009 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -140,7 +140,6 @@ static struct usb_ep_ops dwc2_ep_ops = { /***********************************************************/ -void __iomem *regs_otg; struct dwc2_usbotg_reg *reg; bool dfu_usb_get_reset(void) @@ -818,8 +817,6 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata) reg = (struct dwc2_usbotg_reg *)pdata->regs_otg; - /* regs_otg = (void *)pdata->regs_otg; */ - dev->gadget.is_dualspeed = 1; /* Hack only*/ dev->gadget.is_otg = 0; dev->gadget.is_a_peripheral = 0; -- cgit From c791c8431c34da803fdac4a308999879a6a33834 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:15 +0100 Subject: usb: dwc2: convert driver to DM_USB_GADGET Minimal conversion to driver model by using the uclass UCLASS_USB_GADGET_GENERIC based on: - reset uclass - clock uclass - generic uclass. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 292 +++++++++++++++++++++++++++++++++++++- 1 file changed, 290 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index edca05d009..af16fc1ed4 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -18,11 +18,17 @@ */ #undef DEBUG #include +#include +#include +#include +#include +#include + #include #include -#include #include +#include #include #include @@ -31,6 +37,8 @@ #include +#include + #include "dwc2_udc_otg_regs.h" #include "dwc2_udc_otg_priv.h" @@ -222,6 +230,7 @@ static int udc_enable(struct dwc2_udc *dev) return 0; } +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) /* Register entry point for the peripheral controller driver. */ @@ -296,6 +305,54 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) udc_disable(dev); return 0; } +#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ + +static int dwc2_gadget_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) +{ + struct dwc2_udc *dev = the_controller; + + debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name"); + + if (!driver || + (driver->speed != USB_SPEED_FULL && + driver->speed != USB_SPEED_HIGH) || + !driver->bind || !driver->disconnect || !driver->setup) + return -EINVAL; + + if (!dev) + return -ENODEV; + + if (dev->driver) + return -EBUSY; + + /* first hook up the driver ... */ + dev->driver = driver; + + debug_cond(DEBUG_SETUP != 0, + "Registered gadget driver %s\n", dev->gadget.name); + return udc_enable(dev); +} + +static int dwc2_gadget_stop(struct usb_gadget *g) +{ + struct dwc2_udc *dev = the_controller; + + if (!dev) + return -ENODEV; + + if (!dev->driver) + return -EINVAL; + + dev->driver = 0; + stop_activity(dev, dev->driver); + + udc_disable(dev); + + return 0; +} + +#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */ /* * done - retire a request; caller blocked irqs @@ -730,6 +787,10 @@ static void dwc2_fifo_flush(struct usb_ep *_ep) static const struct usb_gadget_ops dwc2_udc_ops = { /* current versions must always be self-powered */ +#if CONFIG_IS_ENABLED(DM_USB_GADGET) + .udc_start = dwc2_gadget_start, + .udc_stop = dwc2_gadget_stop, +#endif }; static struct dwc2_udc memory = { @@ -841,12 +902,239 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata) return retval; } -int usb_gadget_handle_interrupts(int index) +int dwc2_udc_handle_interrupt(void) { u32 intr_status = readl(®->gintsts); u32 gintmsk = readl(®->gintmsk); if (intr_status & gintmsk) return dwc2_udc_irq(1, (void *)the_controller); + + return 0; +} + +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) + +int usb_gadget_handle_interrupts(int index) +{ + return dwc2_udc_handle_interrupt(); +} + +#else /* CONFIG_IS_ENABLED(DM_USB_GADGET) */ + +struct dwc2_priv_data { + struct clk_bulk clks; + struct reset_ctl_bulk resets; + struct phy *phys; + int num_phys; +}; + +int dm_usb_gadget_handle_interrupts(struct udevice *dev) +{ + return dwc2_udc_handle_interrupt(); +} + +int dwc2_phy_setup(struct udevice *dev, struct phy **array, int *num_phys) +{ + int i, ret, count; + struct phy *usb_phys; + + /* Return if no phy declared */ + if (!dev_read_prop(dev, "phys", NULL)) + return 0; + + count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); + if (count <= 0) + return count; + + usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), + GFP_KERNEL); + if (!usb_phys) + return -ENOMEM; + + for (i = 0; i < count; i++) { + ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); + if (ret && ret != -ENOENT) { + dev_err(dev, "Failed to get USB PHY%d for %s\n", + i, dev->name); + return ret; + } + } + + for (i = 0; i < count; i++) { + ret = generic_phy_init(&usb_phys[i]); + if (ret) { + dev_err(dev, "Can't init USB PHY%d for %s\n", + i, dev->name); + goto phys_init_err; + } + } + + for (i = 0; i < count; i++) { + ret = generic_phy_power_on(&usb_phys[i]); + if (ret) { + dev_err(dev, "Can't power USB PHY%d for %s\n", + i, dev->name); + goto phys_poweron_err; + } + } + + *array = usb_phys; + *num_phys = count; + return 0; + +phys_poweron_err: + for (i = count - 1; i >= 0; i--) + generic_phy_power_off(&usb_phys[i]); + + for (i = 0; i < count; i++) + generic_phy_exit(&usb_phys[i]); + + return ret; + +phys_init_err: + for (; i >= 0; i--) + generic_phy_exit(&usb_phys[i]); + + return ret; } + +void dwc2_phy_shutdown(struct udevice *dev, struct phy *usb_phys, int num_phys) +{ + int i, ret; + + for (i = 0; i < num_phys; i++) { + if (!generic_phy_valid(&usb_phys[i])) + continue; + + ret = generic_phy_power_off(&usb_phys[i]); + ret |= generic_phy_exit(&usb_phys[i]); + if (ret) { + dev_err(dev, "Can't shutdown USB PHY%d for %s\n", + i, dev->name); + } + } +} + +static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev) +{ + struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev); + int node = dev_of_offset(dev); + + if (usb_get_dr_mode(node) != USB_DR_MODE_PERIPHERAL) { + dev_dbg(dev, "Invalid mode\n"); + return -ENODEV; + } + + platdata->regs_otg = dev_read_addr(dev); + + platdata->rx_fifo_sz = dev_read_u32_default(dev, "g-rx-fifo-size", 0); + platdata->np_tx_fifo_sz = dev_read_u32_default(dev, + "g-np-tx-fifo-size", 0); + platdata->tx_fifo_sz = dev_read_u32_default(dev, "g-tx-fifo-size", 0); + + return 0; +} + +static int dwc2_udc_otg_reset_init(struct udevice *dev, + struct reset_ctl_bulk *resets) +{ + int ret; + + ret = reset_get_bulk(dev, resets); + if (ret == -ENOTSUPP) + return 0; + + if (ret) + return ret; + + ret = reset_deassert_bulk(resets); + if (ret) { + reset_release_bulk(resets); + return ret; + } + + return 0; +} + +static int dwc2_udc_otg_clk_init(struct udevice *dev, + struct clk_bulk *clks) +{ + int ret; + + ret = clk_get_bulk(dev, clks); + if (ret == -ENOSYS) + return 0; + + if (ret) + return ret; + + ret = clk_enable_bulk(clks); + if (ret) { + clk_release_bulk(clks); + return ret; + } + + return 0; +} + +static int dwc2_udc_otg_probe(struct udevice *dev) +{ + struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev); + struct dwc2_priv_data *priv = dev_get_priv(dev); + int ret; + + ret = dwc2_udc_otg_clk_init(dev, &priv->clks); + if (ret) + return ret; + + ret = dwc2_udc_otg_reset_init(dev, &priv->resets); + if (ret) + return ret; + + ret = dwc2_phy_setup(dev, &priv->phys, &priv->num_phys); + if (ret) + return ret; + + ret = dwc2_udc_probe(platdata); + if (ret) + return ret; + + the_controller->driver = 0; + + ret = usb_add_gadget_udc((struct device *)dev, &the_controller->gadget); + + return ret; +} + +static int dwc2_udc_otg_remove(struct udevice *dev) +{ + struct dwc2_priv_data *priv = dev_get_priv(dev); + + usb_del_gadget_udc(&the_controller->gadget); + + reset_release_bulk(&priv->resets); + + clk_release_bulk(&priv->clks); + + dwc2_phy_shutdown(dev, priv->phys, priv->num_phys); + + return dm_scan_fdt_dev(dev); +} + +static const struct udevice_id dwc2_udc_otg_ids[] = { + { .compatible = "snps,dwc2" }, +}; + +U_BOOT_DRIVER(dwc2_udc_otg) = { + .name = "dwc2-udc-otg", + .id = UCLASS_USB_GADGET_GENERIC, + .of_match = dwc2_udc_otg_ids, + .ofdata_to_platdata = dwc2_udc_otg_ofdata_to_platdata, + .probe = dwc2_udc_otg_probe, + .remove = dwc2_udc_otg_remove, + .platdata_auto_alloc_size = sizeof(struct dwc2_plat_otg_data), + .priv_auto_alloc_size = sizeof(struct dwc2_priv_data), +}; +#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */ -- cgit From c2c74f97afff9351077f2236ab6fa5638de9bd86 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:16 +0100 Subject: usb: dwc2: force reset assert before to probe the driver Reset the hardware to be sure of the device state. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index af16fc1ed4..8169fdbb11 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -1049,7 +1049,12 @@ static int dwc2_udc_otg_reset_init(struct udevice *dev, if (ret) return ret; - ret = reset_deassert_bulk(resets); + ret = reset_assert_bulk(resets); + + if (!ret) { + udelay(2); + ret = reset_deassert_bulk(resets); + } if (ret) { reset_release_bulk(resets); return ret; -- cgit From 0fdd0bc621f060fcf60fd4ba48a2a32f338ffeac Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:17 +0100 Subject: usb: dwc2: Add force-b-session-valid support Handle "force-b-session-valid" property from DT. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 9 +++++++++ drivers/usb/gadget/dwc2_udc_otg_regs.h | 8 ++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 8169fdbb11..146f11e710 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -1034,6 +1034,9 @@ static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev) "g-np-tx-fifo-size", 0); platdata->tx_fifo_sz = dev_read_u32_default(dev, "g-tx-fifo-size", 0); + platdata->force_b_session_valid = + dev_read_bool(dev, "force-b-session-valid"); + return 0; } @@ -1088,6 +1091,8 @@ static int dwc2_udc_otg_probe(struct udevice *dev) { struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev); struct dwc2_priv_data *priv = dev_get_priv(dev); + struct dwc2_usbotg_reg *usbotg_reg = + (struct dwc2_usbotg_reg *)platdata->regs_otg; int ret; ret = dwc2_udc_otg_clk_init(dev, &priv->clks); @@ -1102,6 +1107,10 @@ static int dwc2_udc_otg_probe(struct udevice *dev) if (ret) return ret; + if (platdata->force_b_session_valid) + /* Override B session bits : value and enable */ + setbits_le32(&usbotg_reg->gotgctl, B_VALOEN | B_VALOVAL); + ret = dwc2_udc_probe(platdata); if (ret) return ret; diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index a1829b3fd1..0aee4ee929 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -83,8 +83,12 @@ struct dwc2_usbotg_reg { /*definitions related to CSR setting */ /* DWC2_UDC_OTG_GOTGCTL */ -#define B_SESSION_VALID (0x1<<19) -#define A_SESSION_VALID (0x1<<18) +#define B_SESSION_VALID BIT(19) +#define A_SESSION_VALID BIT(18) +#define B_VALOVAL BIT(7) +#define B_VALOEN BIT(6) +#define A_VALOVAL BIT(5) +#define A_VALOEN BIT(4) /* DWC2_UDC_OTG_GAHBCFG */ #define PTXFE_HALF (0<<8) -- cgit From 2d76160f049c42087011cfa0e6e878aa2ed6b406 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:18 +0100 Subject: usb: dwc2: Add function for session B check Add a new function to check the session B validity, to be use to check cable connection. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 146f11e710..b1efad115e 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -1151,4 +1151,13 @@ U_BOOT_DRIVER(dwc2_udc_otg) = { .platdata_auto_alloc_size = sizeof(struct dwc2_plat_otg_data), .priv_auto_alloc_size = sizeof(struct dwc2_priv_data), }; + +int dwc2_udc_B_session_valid(struct udevice *dev) +{ + struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev); + struct dwc2_usbotg_reg *usbotg_reg = + (struct dwc2_usbotg_reg *)platdata->regs_otg; + + return readl(&usbotg_reg->gotgctl) & B_SESSION_VALID; +} #endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */ -- cgit From 5bd97e80730bdda59656ca927d67d62fb2a4ecb6 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:19 +0100 Subject: usb: dwc2_udc_otg: Read MAX_HW_ENDPOINT from HWCFG4 register Some DWC2 ip variant doesn't use 16 hardware endpoint as hardcoded in the driver. Bits INEps [29:26] of HWCFG4 register allows to get this information. Signed-off-by: Patrice Chotard Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 11 ++++++++--- drivers/usb/gadget/dwc2_udc_otg_priv.h | 1 - drivers/usb/gadget/dwc2_udc_otg_regs.h | 17 ++++++++++++----- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index b1efad115e..5c7d131a5d 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -456,6 +456,7 @@ static void reconfig_usbd(struct dwc2_udc *dev) unsigned int uTemp = writel(CORE_SOFT_RESET, ®->grstctl); uint32_t dflt_gusbcfg; uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz; + u32 max_hw_ep; debug("Reseting OTG controller\n"); @@ -538,9 +539,13 @@ static void reconfig_usbd(struct dwc2_udc *dev) writel((np_tx_fifo_sz << 16) | rx_fifo_sz, ®->gnptxfsiz); - for (i = 1; i < DWC2_MAX_HW_ENDPOINTS; i++) - writel((rx_fifo_sz + np_tx_fifo_sz + tx_fifo_sz*(i-1)) | - tx_fifo_sz << 16, ®->dieptxf[i-1]); + /* retrieve the number of IN Endpoints (excluding ep0) */ + max_hw_ep = (readl(®->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >> + GHWCFG4_NUM_IN_EPS_SHIFT; + + for (i = 0; i < max_hw_ep; i++) + writel((rx_fifo_sz + np_tx_fifo_sz + (tx_fifo_sz * i)) | + tx_fifo_sz << 16, ®->dieptxf[i]); /* Flush the RX FIFO */ writel(RX_FIFO_FLUSH, ®->grstctl); diff --git a/drivers/usb/gadget/dwc2_udc_otg_priv.h b/drivers/usb/gadget/dwc2_udc_otg_priv.h index aaa90187fb..e72b22ac61 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_priv.h +++ b/drivers/usb/gadget/dwc2_udc_otg_priv.h @@ -23,7 +23,6 @@ #define EP_FIFO_SIZE2 1024 /* ep0-control, ep1in-bulk, ep2out-bulk, ep3in-int */ #define DWC2_MAX_ENDPOINTS 4 -#define DWC2_MAX_HW_ENDPOINTS 16 #define WAIT_FOR_SETUP 0 #define DATA_STATE_XMIT 1 diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index 0aee4ee929..a3899236fc 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -60,22 +60,25 @@ struct dwc2_usbotg_reg { u32 grxstsp; /* Receive Status Debug Pop/Status Pop */ u32 grxfsiz; /* Receive FIFO Size */ u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */ - u8 res1[216]; + + u8 res1[36]; + u32 ghwcfg4; /* User HW Config4 */ + u8 res2[176]; u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */ - u8 res2[1728]; + u8 res3[1728]; /* Device Configuration */ u32 dcfg; /* Device Configuration Register */ u32 dctl; /* Device Control */ u32 dsts; /* Device Status */ - u8 res3[4]; + u8 res4[4]; u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */ u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */ u32 daint; /* Device All Endpoints Interrupt */ u32 daintmsk; /* Device All Endpoints Interrupt Mask */ - u8 res4[224]; + u8 res5[224]; struct dwc2_dev_in_endp in_endp[16]; struct dwc2_dev_out_endp out_endp[16]; - u8 res5[768]; + u8 res6[768]; struct ep_fifo ep[16]; }; @@ -273,4 +276,8 @@ struct dwc2_usbotg_reg { /* Device ALL Endpoints Interrupt Register (DAINT) */ #define DAINT_IN_EP_INT(x) (x << 0) #define DAINT_OUT_EP_INT(x) (x << 16) + +/* User HW Config4 */ +#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) +#define GHWCFG4_NUM_IN_EPS_SHIFT 26 #endif -- cgit From 763bb106f66c147b7d0c3046dbba66a07d7a9dd2 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Fri, 29 Mar 2019 15:42:20 +0100 Subject: usb: dwc2_udc_otg: Add tx_fifo_sz array support All TX fifo size can be different, add tx_fifo_sz_array[] into dwc2_plat_otg_data to be able to set them. tx_fifo_sz_array[] is 17 Bytes long and can contains max 16 tx fifo size (synopsys IP supports max 16 IN endpoints). First entry of tx_fifo_sz_array[] is the number of valid fifo size the array contains. In case of tx_fifo_sz_array[] doesn't contains the same number of element than max hardware endpoint, display a warning message. Compatibility with board which doesn't use tx_fifo_sz_array[] (Rockchip rk322x/rk3128/rv1108/rk3288/rk3036) is kept. Signed-off-by: Patrice Chotard Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 5c7d131a5d..106dec5d09 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -457,6 +457,7 @@ static void reconfig_usbd(struct dwc2_udc *dev) uint32_t dflt_gusbcfg; uint32_t rx_fifo_sz, tx_fifo_sz, np_tx_fifo_sz; u32 max_hw_ep; + int pdata_hw_ep; debug("Reseting OTG controller\n"); @@ -542,11 +543,20 @@ static void reconfig_usbd(struct dwc2_udc *dev) /* retrieve the number of IN Endpoints (excluding ep0) */ max_hw_ep = (readl(®->ghwcfg4) & GHWCFG4_NUM_IN_EPS_MASK) >> GHWCFG4_NUM_IN_EPS_SHIFT; + pdata_hw_ep = dev->pdata->tx_fifo_sz_nb; + + /* tx_fifo_sz_nb should equal to number of IN Endpoint */ + if (pdata_hw_ep && max_hw_ep != pdata_hw_ep) + pr_warn("Got %d hw endpoint but %d tx-fifo-size in array !!\n", + max_hw_ep, pdata_hw_ep); + + for (i = 0; i < max_hw_ep; i++) { + if (pdata_hw_ep) + tx_fifo_sz = dev->pdata->tx_fifo_sz_array[i]; - for (i = 0; i < max_hw_ep; i++) writel((rx_fifo_sz + np_tx_fifo_sz + (tx_fifo_sz * i)) | tx_fifo_sz << 16, ®->dieptxf[i]); - + } /* Flush the RX FIFO */ writel(RX_FIFO_FLUSH, ®->grstctl); while (readl(®->grstctl) & RX_FIFO_FLUSH) -- cgit From 931e9d7aa7228867eec7e33fd45718e6018cc96d Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:21 +0100 Subject: usb: dwc2: add support for STM32MP1 Add compatible "st,stm32mp1-hsotg" and associated driver data to manage the usb33d-supply and the ST specific register for VBus sensing. Signed-off-by: Patrick Delaunay # Conflicts: # drivers/usb/gadget/dwc2_udc_otg.c Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 45 ++++++++++++++++++++++++++++++++++ drivers/usb/gadget/dwc2_udc_otg_regs.h | 10 ++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 106dec5d09..3fdaa102ba 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -942,6 +942,7 @@ struct dwc2_priv_data { struct reset_ctl_bulk resets; struct phy *phys; int num_phys; + struct udevice *usb33d_supply; }; int dm_usb_gadget_handle_interrupts(struct udevice *dev) @@ -1036,6 +1037,8 @@ static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev) { struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev); int node = dev_of_offset(dev); + ulong drvdata; + void (*set_params)(struct dwc2_plat_otg_data *data); if (usb_get_dr_mode(node) != USB_DR_MODE_PERIPHERAL) { dev_dbg(dev, "Invalid mode\n"); @@ -1052,9 +1055,28 @@ static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev) platdata->force_b_session_valid = dev_read_bool(dev, "force-b-session-valid"); + /* force platdata according compatible */ + drvdata = dev_get_driver_data(dev); + if (drvdata) { + set_params = (void *)drvdata; + set_params(platdata); + } + return 0; } +static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_plat_otg_data *p) +{ + p->activate_stm_id_vb_detection = true; + p->usb_gusbcfg = + 0 << 15 /* PHY Low Power Clock sel*/ + | 0x9 << 10 /* USB Turnaround time (0x9 for HS phy) */ + | 0 << 9 /* [0:HNP disable,1:HNP enable]*/ + | 0 << 8 /* [0:SRP disable 1:SRP enable]*/ + | 0 << 6 /* 0: high speed utmi+, 1: full speed serial*/ + | 0x7 << 0; /* FS timeout calibration**/ +} + static int dwc2_udc_otg_reset_init(struct udevice *dev, struct reset_ctl_bulk *resets) { @@ -1122,6 +1144,26 @@ static int dwc2_udc_otg_probe(struct udevice *dev) if (ret) return ret; + if (CONFIG_IS_ENABLED(DM_REGULATOR) && + platdata->activate_stm_id_vb_detection && + !platdata->force_b_session_valid) { + ret = device_get_supply_regulator(dev, "usb33d-supply", + &priv->usb33d_supply); + if (ret) { + dev_err(dev, "can't get voltage level detector supply\n"); + return ret; + } + ret = regulator_set_enable(priv->usb33d_supply, true); + if (ret) { + dev_err(dev, "can't enable voltage level detector supply\n"); + return ret; + } + /* Enable vbus sensing */ + setbits_le32(&usbotg_reg->ggpio, + GGPIO_STM32_OTG_GCCFG_VBDEN | + GGPIO_STM32_OTG_GCCFG_IDEN); + } + if (platdata->force_b_session_valid) /* Override B session bits : value and enable */ setbits_le32(&usbotg_reg->gotgctl, B_VALOEN | B_VALOVAL); @@ -1154,6 +1196,9 @@ static int dwc2_udc_otg_remove(struct udevice *dev) static const struct udevice_id dwc2_udc_otg_ids[] = { { .compatible = "snps,dwc2" }, + { .compatible = "st,stm32mp1-hsotg", + .data = (ulong)dwc2_set_stm32mp1_hsotg_params }, + {}, }; U_BOOT_DRIVER(dwc2_udc_otg) = { diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index a3899236fc..b2a28d7a5d 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -60,8 +60,9 @@ struct dwc2_usbotg_reg { u32 grxstsp; /* Receive Status Debug Pop/Status Pop */ u32 grxfsiz; /* Receive FIFO Size */ u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */ - - u8 res1[36]; + u8 res0[12]; + u32 ggpio; /* 0x038 */ + u8 res1[20]; u32 ghwcfg4; /* User HW Config4 */ u8 res2[176]; u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */ @@ -280,4 +281,9 @@ struct dwc2_usbotg_reg { /* User HW Config4 */ #define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) #define GHWCFG4_NUM_IN_EPS_SHIFT 26 + +/* OTG general core configuration register (OTG_GCCFG:0x38) for STM32MP1 */ +#define GGPIO_STM32_OTG_GCCFG_VBDEN BIT(21) +#define GGPIO_STM32_OTG_GCCFG_IDEN BIT(22) + #endif -- cgit From 6fe7dd3327d552bacf4266d7f1ed074bf98ffb92 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 29 Mar 2019 15:42:24 +0100 Subject: stm32mp1: add stusb1600 support for DK1 and DK2 board The DK1 and DK2 boards use the USB Type-C controller STUSB1600. This patch updates: - the device tree to add the I2C node in the DT - the board stm32mp1 to probe this I2C device and use this controller to check cable detection. - the DWC2 driver to support a new dt property "u-boot,force-b-session-valid" which forces B session and device mode; it is a workaround because the VBUS sensing and ID detection isn't available with stusb1600. Signed-off-by: Patrick Delaunay Reviewed-by: Lukasz Majewski --- drivers/usb/gadget/dwc2_udc_otg.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 3fdaa102ba..494ab533cc 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -1053,7 +1053,7 @@ static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev) platdata->tx_fifo_sz = dev_read_u32_default(dev, "g-tx-fifo-size", 0); platdata->force_b_session_valid = - dev_read_bool(dev, "force-b-session-valid"); + dev_read_bool(dev, "u-boot,force-b-session-valid"); /* force platdata according compatible */ drvdata = dev_get_driver_data(dev); @@ -1075,6 +1075,9 @@ static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_plat_otg_data *p) | 0 << 8 /* [0:SRP disable 1:SRP enable]*/ | 0 << 6 /* 0: high speed utmi+, 1: full speed serial*/ | 0x7 << 0; /* FS timeout calibration**/ + + if (p->force_b_session_valid) + p->usb_gusbcfg |= 1 << 30; /* FDMOD: Force device mode */ } static int dwc2_udc_otg_reset_init(struct udevice *dev, @@ -1166,7 +1169,8 @@ static int dwc2_udc_otg_probe(struct udevice *dev) if (platdata->force_b_session_valid) /* Override B session bits : value and enable */ - setbits_le32(&usbotg_reg->gotgctl, B_VALOEN | B_VALOVAL); + setbits_le32(&usbotg_reg->gotgctl, + A_VALOEN | A_VALOVAL | B_VALOEN | B_VALOVAL); ret = dwc2_udc_probe(platdata); if (ret) -- cgit From 7fd9f31c6bd13609da61b985cf8f5f65ebebd913 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 17 Apr 2019 16:46:13 +0200 Subject: usb: dwc2: fix gadget disconnect This fixes a disconnect issue detected with fastboot command, when using dwc2 driver. - On u-boot side: uboot>$ fastboot 0 - On USB host PC side, few seconds after PC>$ fastboot reboot # Get stuck, uboot target never reboots By enabling DEBUG_ISR logs, the bus suspend interrupt is seen before the PC command has been issued. When the USB bus suspend occurs, there's a HACK that disables the fastboot (composite driver). Here is the call stack upon USB bus suspend: - dwc2_handle_usb_suspend_intr() - dev->driver->disconnect() - composite_disconnect() - reset_config() - f->disable() - fastboot_disable() - usb_ep_disable(f_fb->out_ep); - usb_ep_disable(f_fb->in_ep); .. other disable calls. When the resume interrupt happens, everything has been disabled, then nothing happens. fastboot command gets stuck on HOST side. Remove original HACK, that disconnects the composite driver upon USB bus suspend. Implement disconnect detection instead: - check GINTSTS OTG interrupt - read GOTGINT register - check GOTGINT, SesEndDet bit (e.g. session end) This is inspired by what is implemented currently in Linux dwc2 driver. Signed-off-by: Fabrice Gasnier Reviewed-by: Marek Vasut --- drivers/usb/gadget/dwc2_udc_otg_regs.h | 6 +++++- drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'drivers/usb') diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index b2a28d7a5d..434db5ba39 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -94,6 +94,9 @@ struct dwc2_usbotg_reg { #define A_VALOVAL BIT(5) #define A_VALOEN BIT(4) +/* DWC2_UDC_OTG_GOTINT */ +#define GOTGINT_SES_END_DET (1<<2) + /* DWC2_UDC_OTG_GAHBCFG */ #define PTXFE_HALF (0<<8) #define PTXFE_ZERO (1<<8) @@ -126,6 +129,7 @@ struct dwc2_usbotg_reg { #define INT_NP_TX_FIFO_EMPTY (0x1<<5) #define INT_RX_FIFO_NOT_EMPTY (0x1<<4) #define INT_SOF (0x1<<3) +#define INT_OTG (0x1<<2) #define INT_DEV_MODE (0x0<<0) #define INT_HOST_MODE (0x1<<1) #define INT_GOUTNakEff (0x01<<7) @@ -254,7 +258,7 @@ struct dwc2_usbotg_reg { /* Masks definitions */ #define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\ - | INT_RESET | INT_SUSPEND) + | INT_RESET | INT_SUSPEND | INT_OTG) #define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE) #define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE) #define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\ diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index a75af4987f..7eb632d3b1 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -467,7 +467,7 @@ static void process_ep_out_intr(struct dwc2_udc *dev) static int dwc2_udc_irq(int irq, void *_dev) { struct dwc2_udc *dev = _dev; - u32 intr_status; + u32 intr_status, gotgint; u32 usb_status, gintmsk; unsigned long flags = 0; @@ -521,14 +521,24 @@ static int dwc2_udc_irq(int irq, void *_dev) && dev->driver) { if (dev->driver->suspend) dev->driver->suspend(&dev->gadget); + } + } + + if (intr_status & INT_OTG) { + gotgint = readl(®->gotgint); + debug_cond(DEBUG_ISR, + "\tOTG interrupt: (GOTGINT):0x%x\n", gotgint); - /* HACK to let gadget detect disconnected state */ + if (gotgint & GOTGINT_SES_END_DET) { + debug_cond(DEBUG_ISR, "\t\tSession End Detected\n"); + /* Let gadget detect disconnected state */ if (dev->driver->disconnect) { spin_unlock_irqrestore(&dev->lock, flags); dev->driver->disconnect(&dev->gadget); spin_lock_irqsave(&dev->lock, flags); } } + writel(gotgint, ®->gotgint); } if (intr_status & INT_RESUME) { -- cgit