diff options
author | Tom Rini <trini@konsulko.com> | 2019-04-21 19:00:04 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-04-21 19:00:04 -0400 |
commit | 6c5f8dd540d7a8eff244d4c27a09451ca12c8d20 (patch) | |
tree | 9eaba554d99f15aa5dfc302c338f59895f9b43e4 /drivers/usb | |
parent | b4fde1633e67bb618fd33aad6e6322b7cecf1154 (diff) | |
parent | 7fd9f31c6bd13609da61b985cf8f5f65ebebd913 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-usb
- Various fastboot, dwc2/stm32 updates
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/dwc2_udc_otg.c | 388 | ||||
-rw-r--r-- | drivers/usb/gadget/dwc2_udc_otg_priv.h | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/dwc2_udc_otg_regs.h | 37 | ||||
-rw-r--r-- | drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 14 | ||||
-rw-r--r-- | drivers/usb/musb-new/Kconfig | 10 |
5 files changed, 431 insertions, 19 deletions
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 3c7ad033e3..494ab533cc 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -18,11 +18,17 @@ */ #undef DEBUG #include <common.h> +#include <clk.h> +#include <dm.h> +#include <generic-phy.h> +#include <malloc.h> +#include <reset.h> + #include <linux/errno.h> #include <linux/list.h> -#include <malloc.h> #include <linux/usb/ch9.h> +#include <linux/usb/otg.h> #include <linux/usb/gadget.h> #include <asm/byteorder.h> @@ -31,6 +37,8 @@ #include <asm/mach-types.h> +#include <power/regulator.h> + #include "dwc2_udc_otg_regs.h" #include "dwc2_udc_otg_priv.h" @@ -140,7 +148,6 @@ static struct usb_ep_ops dwc2_ep_ops = { /***********************************************************/ -void __iomem *regs_otg; struct dwc2_usbotg_reg *reg; bool dfu_usb_get_reset(void) @@ -223,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. */ @@ -297,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 @@ -400,6 +456,8 @@ 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; + int pdata_hw_ep; debug("Reseting OTG controller\n"); @@ -482,10 +540,23 @@ 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; + 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]; + 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) @@ -731,6 +802,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 = { @@ -818,8 +893,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; @@ -844,12 +917,311 @@ 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; + struct udevice *usb33d_supply; +}; + +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); + 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"); + 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); + + platdata->force_b_session_valid = + dev_read_bool(dev, "u-boot,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**/ + + 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, + struct reset_ctl_bulk *resets) +{ + int ret; + + ret = reset_get_bulk(dev, resets); + if (ret == -ENOTSUPP) + return 0; + + if (ret) + return ret; + + ret = reset_assert_bulk(resets); + + if (!ret) { + udelay(2); + 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); + struct dwc2_usbotg_reg *usbotg_reg = + (struct dwc2_usbotg_reg *)platdata->regs_otg; + 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; + + 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, + A_VALOEN | A_VALOVAL | B_VALOEN | B_VALOVAL); + + 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" }, + { .compatible = "st,stm32mp1-hsotg", + .data = (ulong)dwc2_set_stm32mp1_hsotg_params }, + {}, +}; + +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), +}; + +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) */ 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 a1829b3fd1..434db5ba39 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -60,22 +60,26 @@ 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 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 */ - 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]; }; @@ -83,8 +87,15 @@ 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_GOTINT */ +#define GOTGINT_SES_END_DET (1<<2) /* DWC2_UDC_OTG_GAHBCFG */ #define PTXFE_HALF (0<<8) @@ -118,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) @@ -246,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\ @@ -269,4 +281,13 @@ 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 + +/* 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 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) { diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig index f8f2205a62..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 @@ -54,6 +55,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 |