usb: ether: avoid NULL check before free()
[oweals/u-boot.git] / drivers / usb / gadget / dwc2_udc_otg.c
index 5c7d131a5d3efb4a4e743fb76b3ec0ded9104433..b9c814cf73e22832194c8f75b305a54179d62511 100644 (file)
@@ -23,6 +23,8 @@
 #include <generic-phy.h>
 #include <malloc.h>
 #include <reset.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
 
 #include <linux/errno.h>
 #include <linux/list.h>
@@ -31,6 +33,7 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/gadget.h>
 
+#include <phys2bus.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <asm/io.h>
@@ -457,6 +460,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 +546,20 @@ static void reconfig_usbd(struct dwc2_udc *dev)
        /* retrieve the number of IN Endpoints (excluding ep0) */
        max_hw_ep = (readl(&reg->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, &reg->dieptxf[i]);
-
+       }
        /* Flush the RX FIFO */
        writel(RX_FIFO_FLUSH, &reg->grstctl);
        while (readl(&reg->grstctl) & RX_FIFO_FLUSH)
@@ -932,6 +945,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)
@@ -1025,9 +1039,12 @@ void dwc2_phy_shutdown(struct udevice *dev, struct phy *usb_phys, int num_phys)
 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);
+       int ret;
 
-       if (usb_get_dr_mode(node) != USB_DR_MODE_PERIPHERAL) {
+       if (usb_get_dr_mode(dev->node) != USB_DR_MODE_PERIPHERAL &&
+           usb_get_dr_mode(dev->node) != USB_DR_MODE_OTG) {
                dev_dbg(dev, "Invalid mode\n");
                return -ENODEV;
        }
@@ -1037,14 +1054,47 @@ static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *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->tx_fifo_sz_nb =
+               dev_read_size(dev, "g-tx-fifo-size") / sizeof(u32);
+       if (platdata->tx_fifo_sz_nb > DWC2_MAX_HW_ENDPOINTS)
+               platdata->tx_fifo_sz_nb = DWC2_MAX_HW_ENDPOINTS;
+       if (platdata->tx_fifo_sz_nb) {
+               ret = dev_read_u32_array(dev, "g-tx-fifo-size",
+                                        platdata->tx_fifo_sz_array,
+                                        platdata->tx_fifo_sz_nb);
+               if (ret)
+                       return ret;
+       }
 
        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);
+       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)
 {
@@ -1112,9 +1162,30 @@ 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);
+               setbits_le32(&usbotg_reg->gotgctl,
+                            A_VALOEN | A_VALOVAL | B_VALOEN | B_VALOVAL);
 
        ret = dwc2_udc_probe(platdata);
        if (ret)
@@ -1144,6 +1215,10 @@ static int dwc2_udc_otg_remove(struct udevice *dev)
 
 static const struct udevice_id dwc2_udc_otg_ids[] = {
        { .compatible = "snps,dwc2" },
+       { .compatible = "brcm,bcm2835-usb" },
+       { .compatible = "st,stm32mp1-hsotg",
+         .data = (ulong)dwc2_set_stm32mp1_hsotg_params },
+       {},
 };
 
 U_BOOT_DRIVER(dwc2_udc_otg) = {