The Linux core.c has no U-Boot entry points like dwc3_uboot_init() and
dwc3_init(). Copy them back unchanged from the core.c we had before
"usb: dwc3: restore to original v3.19-rc1 kernel import", with the
struct members and prototypes they use.

A diff against that old core.c shows no change for them. What they need
for the resynced core comes in the next commit.

Co-developed-by: Jerome Forissier <[email protected]>
Signed-off-by: Jerome Forissier <[email protected]>
Co-developed-by: Jens Wiklander <[email protected]>
Signed-off-by: Jens Wiklander <[email protected]>
Signed-off-by: Anders Roxell <[email protected]>
---
 drivers/usb/dwc3/core.c | 420 ++++++++++++++++++++++++++++++++++++++++
 drivers/usb/dwc3/core.h |  11 ++
 2 files changed, 431 insertions(+)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index dee68745b94a..8db1dd2c29a1 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -45,6 +45,8 @@
 
 #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
 
+static LIST_HEAD(dwc3_list);
+
 void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
 {
        u32 reg;
@@ -1315,6 +1317,14 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
        return 0;
 }
 
+static void dwc3_core_stop(struct dwc3 *dwc)
+{
+       u32 reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+       dwc3_writel(dwc->regs, DWC3_DCTL, reg & ~(DWC3_DCTL_RUN_STOP));
+}
+
 static void dwc3_core_exit_mode(struct dwc3 *dwc)
 {
        switch (dwc->dr_mode) {
@@ -1336,6 +1346,8 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
        dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
 }
 
+#define DWC3_ALIGN_MASK                (16 - 1)
+
 /* check whether the core supports IMOD */
 bool dwc3_has_imod(struct dwc3 *dwc)
 {
@@ -1392,3 +1404,411 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
 
        return 0;
 }
+
+#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB)
+int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys)
+{
+       int ret;
+
+       ret = generic_phy_get_bulk(dev, phys);
+       if (ret)
+               return ret;
+
+       ret = generic_phy_init_bulk(phys);
+       if (ret)
+               return ret;
+
+       ret = generic_phy_power_on_bulk(phys);
+       if (ret)
+               generic_phy_exit_bulk(phys);
+
+       return ret;
+}
+
+int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys)
+{
+       int ret;
+
+       ret = generic_phy_power_off_bulk(phys);
+       ret |= generic_phy_exit_bulk(phys);
+       return ret;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(DM_USB)
+void dwc3_of_parse(struct dwc3 *dwc)
+{
+       const u8 *tmp;
+       struct udevice *dev = dwc->dev;
+       u8 lpm_nyet_threshold;
+       u8 tx_de_emphasis;
+       u8 hird_threshold;
+       u32 val;
+       int i;
+
+       /* default to highest possible threshold */
+       lpm_nyet_threshold = 0xff;
+
+       /* default to -3.5dB de-emphasis */
+       tx_de_emphasis = 1;
+
+       /*
+        * default to assert utmi_sleep_n and use maximum allowed HIRD
+        * threshold value of 0b1100
+        */
+       hird_threshold = 12;
+
+       dwc->hsphy_mode = usb_get_phy_mode(dev_ofnode(dev));
+
+       dwc->has_lpm_erratum = dev_read_bool(dev,
+                               "snps,has-lpm-erratum");
+       tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1);
+       if (tmp)
+               lpm_nyet_threshold = *tmp;
+
+       dwc->is_utmi_l1_suspend = dev_read_bool(dev,
+                               "snps,is-utmi-l1-suspend");
+       tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1);
+       if (tmp)
+               hird_threshold = *tmp;
+
+       dwc->disable_scramble_quirk = dev_read_bool(dev,
+                               "snps,disable_scramble_quirk");
+       dwc->u2exit_lfps_quirk = dev_read_bool(dev,
+                               "snps,u2exit_lfps_quirk");
+       dwc->u2ss_inp3_quirk = dev_read_bool(dev,
+                               "snps,u2ss_inp3_quirk");
+       dwc->req_p1p2p3_quirk = dev_read_bool(dev,
+                               "snps,req_p1p2p3_quirk");
+       dwc->del_p1p2p3_quirk = dev_read_bool(dev,
+                               "snps,del_p1p2p3_quirk");
+       dwc->del_phy_power_chg_quirk = dev_read_bool(dev,
+                               "snps,del_phy_power_chg_quirk");
+       dwc->lfps_filter_quirk = dev_read_bool(dev,
+                               "snps,lfps_filter_quirk");
+       dwc->rx_detect_poll_quirk = dev_read_bool(dev,
+                               "snps,rx_detect_poll_quirk");
+       dwc->dis_u3_susphy_quirk = dev_read_bool(dev,
+                               "snps,dis_u3_susphy_quirk");
+       dwc->dis_u2_susphy_quirk = dev_read_bool(dev,
+                               "snps,dis_u2_susphy_quirk");
+       dwc->dis_del_phy_power_chg_quirk = dev_read_bool(dev,
+                               "snps,dis-del-phy-power-chg-quirk");
+       dwc->dis_tx_ipgap_linecheck_quirk = dev_read_bool(dev,
+                               "snps,dis-tx-ipgap-linecheck-quirk");
+       dwc->dis_enblslpm_quirk = dev_read_bool(dev,
+                               "snps,dis_enblslpm_quirk");
+       dwc->dis_u2_freeclk_exists_quirk = dev_read_bool(dev,
+                               "snps,dis-u2-freeclk-exists-quirk");
+       dwc->tx_de_emphasis_quirk = dev_read_bool(dev,
+                               "snps,tx_de_emphasis_quirk");
+       tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1);
+       if (tmp)
+               tx_de_emphasis = *tmp;
+
+       dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+       dwc->tx_de_emphasis = tx_de_emphasis;
+
+       dwc->hird_threshold = hird_threshold
+               | (dwc->is_utmi_l1_suspend << 4);
+
+       dev_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj);
+
+       /*
+        * Handle property "snps,incr-burst-type-adjustment".
+        * Get the number of value from this property:
+        * result <= 0, means this property is not supported.
+        * result = 1, means INCRx burst mode supported.
+        * result > 1, means undefined length burst mode supported.
+        */
+       dwc->incrx_mode = INCRX_BURST_MODE;
+       dwc->incrx_size = 0;
+       for (i = 0; i < 8; i++) {
+               if (dev_read_u32_index(dev, "snps,incr-burst-type-adjustment",
+                                      i, &val))
+                       break;
+
+               dwc->incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE;
+               dwc->incrx_size = max(dwc->incrx_size, val);
+       }
+}
+
+int dwc3_init(struct dwc3 *dwc)
+{
+       int ret;
+       u32 reg;
+
+       dwc3_cache_hwparams(dwc);
+
+       ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+       if (ret) {
+               dev_err(dwc->dev, "failed to allocate event buffers\n");
+               return -ENOMEM;
+       }
+
+       ret = dwc3_core_init(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to initialize core\n");
+               goto core_fail;
+       }
+
+       ret = dwc3_event_buffers_setup(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to setup event buffers\n");
+               goto event_fail;
+       }
+
+       if (dwc->revision >= DWC3_REVISION_250A) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
+
+               /*
+                * Enable hardware control of sending remote wakeup
+                * in HS when the device is in the L1 state.
+                */
+               if (dwc->revision >= DWC3_REVISION_290A)
+                       reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW;
+
+               if (dwc->dis_tx_ipgap_linecheck_quirk)
+                       reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
+
+               dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
+       }
+
+       if (dwc->dr_mode == USB_DR_MODE_HOST ||
+           dwc->dr_mode == USB_DR_MODE_OTG) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+
+               reg |= DWC3_GUCTL_HSTINAUTORETRY;
+
+               dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+       }
+
+       ret = dwc3_core_init_mode(dwc);
+       if (ret)
+               goto mode_fail;
+
+       return 0;
+
+mode_fail:
+       dwc3_event_buffers_cleanup(dwc);
+
+event_fail:
+       dwc3_core_exit(dwc);
+
+core_fail:
+       dwc3_free_event_buffers(dwc);
+
+       return ret;
+}
+
+void dwc3_remove(struct dwc3 *dwc)
+{
+       dwc3_core_exit_mode(dwc);
+       dwc3_event_buffers_cleanup(dwc);
+       dwc3_free_event_buffers(dwc);
+       dwc3_core_stop(dwc);
+       dwc3_core_exit(dwc);
+       kfree(dwc->mem);
+}
+#endif
+
+/**
+ * dwc3_uboot_init - dwc3 core uboot initialization code
+ * @dwc3_dev: struct dwc3_device containing initialization data
+ *
+ * Entry point for dwc3 driver (equivalent to dwc3_probe in linux
+ * kernel driver). Pointer to dwc3_device should be passed containing
+ * base address and other initialization data. Returns '0' on success and
+ * a negative value on failure.
+ *
+ * Generally called from board_usb_init() implemented in board file.
+ */
+int dwc3_uboot_init(struct dwc3_device *dwc3_dev)
+{
+       struct dwc3             *dwc;
+       struct device           *dev = NULL;
+       u8                      lpm_nyet_threshold;
+       u8                      tx_de_emphasis;
+       u8                      hird_threshold;
+
+       int                     ret;
+
+       void                    *mem;
+
+       mem = devm_kzalloc((struct udevice *)dev,
+                          sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+       if (!mem)
+               return -ENOMEM;
+
+       dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
+       dwc->mem = mem;
+
+       dwc->regs = (void *)(uintptr_t)(dwc3_dev->base +
+                                       DWC3_GLOBALS_REGS_START);
+
+       /* default to highest possible threshold */
+       lpm_nyet_threshold = 0xff;
+
+       /* default to -3.5dB de-emphasis */
+       tx_de_emphasis = 1;
+
+       /*
+        * default to assert utmi_sleep_n and use maximum allowed HIRD
+        * threshold value of 0b1100
+        */
+       hird_threshold = 12;
+
+       dwc->maximum_speed = dwc3_dev->maximum_speed;
+       dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum;
+       if (dwc3_dev->lpm_nyet_threshold)
+               lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold;
+       dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend;
+       if (dwc3_dev->hird_threshold)
+               hird_threshold = dwc3_dev->hird_threshold;
+
+       dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize;
+       dwc->dr_mode = dwc3_dev->dr_mode;
+
+       dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk;
+       dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk;
+       dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk;
+       dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk;
+       dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk;
+       dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk;
+       dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk;
+       dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk;
+       dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk;
+       dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk;
+       dwc->dis_del_phy_power_chg_quirk = 
dwc3_dev->dis_del_phy_power_chg_quirk;
+       dwc->dis_tx_ipgap_linecheck_quirk = 
dwc3_dev->dis_tx_ipgap_linecheck_quirk;
+       dwc->dis_enblslpm_quirk = dwc3_dev->dis_enblslpm_quirk;
+       dwc->dis_u2_freeclk_exists_quirk = 
dwc3_dev->dis_u2_freeclk_exists_quirk;
+
+       dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk;
+       if (dwc3_dev->tx_de_emphasis)
+               tx_de_emphasis = dwc3_dev->tx_de_emphasis;
+
+       /* default to superspeed if no maximum_speed passed */
+       if (dwc->maximum_speed == USB_SPEED_UNKNOWN)
+               dwc->maximum_speed = USB_SPEED_SUPER;
+
+       dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+       dwc->tx_de_emphasis = tx_de_emphasis;
+
+       dwc->hird_threshold = hird_threshold
+               | (dwc->is_utmi_l1_suspend << 4);
+
+       dwc->hsphy_mode = dwc3_dev->hsphy_mode;
+
+       dwc->index = dwc3_dev->index;
+
+       dwc3_cache_hwparams(dwc);
+
+       ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
+       if (ret) {
+               dev_err(dwc->dev, "failed to allocate event buffers\n");
+               return -ENOMEM;
+       }
+
+       if (!IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+               dwc->dr_mode = USB_DR_MODE_HOST;
+       else if (!IS_ENABLED(CONFIG_USB_HOST))
+               dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+       if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
+               dwc->dr_mode = USB_DR_MODE_OTG;
+
+       ret = dwc3_core_init(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to initialize core\n");
+               goto err0;
+       }
+
+       ret = dwc3_event_buffers_setup(dwc);
+       if (ret) {
+               dev_err(dwc->dev, "failed to setup event buffers\n");
+               goto err1;
+       }
+
+       ret = dwc3_core_init_mode(dwc);
+       if (ret)
+               goto err2;
+
+       list_add_tail(&dwc->list, &dwc3_list);
+
+       return 0;
+
+err2:
+       dwc3_event_buffers_cleanup(dwc);
+
+err1:
+       dwc3_core_exit(dwc);
+
+err0:
+       dwc3_free_event_buffers(dwc);
+
+       return ret;
+}
+
+/**
+ * dwc3_uboot_exit - dwc3 core uboot cleanup code
+ * @index: index of this controller
+ *
+ * Performs cleanup of memory allocated in dwc3_uboot_init and other misc
+ * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller
+ * should be passed and should match with the index passed in
+ * dwc3_device during init.
+ *
+ * Generally called from board file.
+ */
+void dwc3_uboot_exit(int index)
+{
+       struct dwc3 *dwc;
+
+       list_for_each_entry(dwc, &dwc3_list, list) {
+               if (dwc->index != index)
+                       continue;
+
+               dwc3_core_exit_mode(dwc);
+               dwc3_event_buffers_cleanup(dwc);
+               dwc3_free_event_buffers(dwc);
+               dwc3_core_exit(dwc);
+               list_del(&dwc->list);
+               kfree(dwc->mem);
+               break;
+       }
+}
+
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
+__weak int dwc3_uboot_interrupt_status(struct udevice *dev)
+{
+       return 1;
+}
+
+/**
+ * dm_usb_gadget_handle_interrupts - handle dwc3 core interrupt
+ * @dev: device of this controller
+ *
+ * Invokes dwc3 gadget interrupts.
+ *
+ * Generally called from board file.
+ */
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+       struct dwc3 *dwc = NULL;
+
+       if (!dwc3_uboot_interrupt_status(dev))
+               return 0;
+
+       list_for_each_entry(dwc, &dwc3_list, list) {
+               if (dwc->dev != dev)
+                       continue;
+
+               dwc3_gadget_uboot_handle_interrupt(dwc);
+               break;
+       }
+
+       return 0;
+}
+#endif
+
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 036a1440c8e8..4c4d7bae2e5f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -418,6 +418,7 @@
 /* Global User Control Register*/
 #define DWC3_GUCTL_REFCLKPER_MASK              0xffc00000
 #define DWC3_GUCTL_REFCLKPER_SEL               22
+#define DWC3_GUCTL_HSTINAUTORETRY              BIT(14)
 
 /* Global User Control Register 2 */
 #define DWC3_GUCTL2_RST_ACTBITLATER            BIT(14)
@@ -1232,6 +1233,8 @@ struct dwc3 {
        enum usb_dr_mode        role_switch_default_mode;
 
        u32                     fladj;
+       u8                      incrx_mode;
+       u32                     incrx_size;
        u32                     ref_clk_per;
        u32                     irq_gadget;
        u32                     otg_irq;
@@ -1313,6 +1316,8 @@ struct dwc3 {
 
        u8                      num_eps;
 
+       void                    *mem;
+
        struct dwc3_hwparams    hwparams;
        struct debugfs_regset32 *regset;
 
@@ -1398,6 +1403,9 @@ struct dwc3 {
        struct dentry           *debug_root;
        u32                     gsbuscfg0_reqinfo;
        u32                     wakeup_pending_funcs;
+
+       int                     index;
+       struct list_head        list;
 };
 
 #define INCRX_BURST_MODE 0
@@ -1564,6 +1572,9 @@ struct dwc3_gadget_ep_cmd_params {
 /* prototypes */
 void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy);
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
+void dwc3_of_parse(struct dwc3 *dwc);
+int dwc3_init(struct dwc3 *dwc);
+void dwc3_remove(struct dwc3 *dwc);
 
 #define DWC3_IP_IS(_ip)                                                        
\
        (dwc->ip == _ip##_IP)
-- 
2.53.0

Reply via email to