From: Mian Yousaf Kaukab <yousaf.kau...@intel.com>

As descriptor dma mode does not support split transfers, it can't be
enabled for high speed devices. Add a core parameter to enable it for
full speed devices.

Ensure frame list and descriptor list are correctly freed during
disconnect.

Signed-off-by: Mian Yousaf Kaukab <yousaf.kau...@intel.com>
Signed-off-by: Gregory Herrero <gregory.herr...@intel.com>
---
 drivers/usb/dwc2/core.c      | 24 ++++++++++++++++++++++++
 drivers/usb/dwc2/core.h      | 20 ++++++++++++++++++++
 drivers/usb/dwc2/hcd.c       | 22 ++++++++++++++++++++++
 drivers/usb/dwc2/hcd_intr.c  | 15 +++++++++++++--
 drivers/usb/dwc2/hcd_queue.c |  2 +-
 drivers/usb/dwc2/platform.c  |  4 ++++
 6 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index ef73e49..5568d9c 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -2485,6 +2485,29 @@ void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg 
*hsotg, int val)
        hsotg->core_params->dma_desc_enable = val;
 }
 
+void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg, int val)
+{
+       int valid = 1;
+
+       if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
+                       !hsotg->hw_params.dma_desc_enable))
+               valid = 0;
+       if (val < 0)
+               valid = 0;
+
+       if (!valid) {
+               if (val >= 0)
+                       dev_err(hsotg->dev,
+                               "%d invalid for dma_desc_fs_enable parameter. 
Check HW configuration.\n",
+                               val);
+               val = (hsotg->core_params->dma_enable > 0 &&
+                       hsotg->hw_params.dma_desc_enable);
+       }
+
+       hsotg->core_params->dma_desc_fs_enable = val;
+       dev_dbg(hsotg->dev, "Setting dma_desc_fs_enable to %d\n", val);
+}
+
 void dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,
                                                 int val)
 {
@@ -3016,6 +3039,7 @@ void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
        dwc2_set_param_otg_cap(hsotg, params->otg_cap);
        dwc2_set_param_dma_enable(hsotg, params->dma_enable);
        dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable);
+       dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable);
        dwc2_set_param_host_support_fs_ls_low_power(hsotg,
                        params->host_support_fs_ls_low_power);
        dwc2_set_param_enable_dynamic_fifo(hsotg,
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index a66d3cb..fd4c236 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -246,6 +246,13 @@ enum dwc2_ep0_state {
  *                      value for this if none is specified.
  *                       0 - Address DMA
  *                       1 - Descriptor DMA (default, if available)
+ * @dma_desc_fs_enable: When DMA mode is enabled, specifies whether to use
+ *                      address DMA mode or descriptor DMA mode for accessing
+ *                      the data FIFOs in Full Speed mode only. The driver
+ *                      will automatically detect the value for this if none is
+ *                      specified.
+ *                       0 - Address DMA
+ *                       1 - Descriptor DMA in FS (default, if available)
  * @speed:              Specifies the maximum speed of operation in host and
  *                      device mode. The actual speed depends on the speed of
  *                      the attached device and the value of phy_type.
@@ -375,6 +382,7 @@ struct dwc2_core_params {
        int otg_ver;
        int dma_enable;
        int dma_desc_enable;
+       int dma_desc_fs_enable;
        int speed;
        int enable_dynamic_fifo;
        int en_multiple_tx_fifo;
@@ -456,6 +464,7 @@ struct dwc2_hw_params {
        unsigned op_mode:3;
        unsigned arch:2;
        unsigned dma_desc_enable:1;
+       unsigned dma_desc_fs_enable:1;
        unsigned enable_dynamic_fifo:1;
        unsigned en_multiple_tx_fifo:1;
        unsigned host_rx_fifo_size:16;
@@ -770,6 +779,7 @@ struct dwc2_hsotg {
        u16 frame_number;
        u16 periodic_qh_count;
        bool bus_suspended;
+       bool new_connection;
 
 #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
 #define FRAME_NUM_ARRAY_SIZE 1000
@@ -942,6 +952,16 @@ extern void dwc2_set_param_dma_enable(struct dwc2_hsotg 
*hsotg, int val);
 extern void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val);
 
 /*
+ * When DMA mode is enabled specifies whether to use
+ * address DMA or DMA Descritor mode with full speed devices
+ * for accessing the data FIFOs in host mode.
+ * 0 - address DMA
+ * 1 - FS DMA Descriptor(default, if available)
+ */
+extern void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg,
+                                             int val);
+
+/*
  * Specifies the maximum speed of operation in host and device mode.
  * The actual speed depends on the speed of the attached device and
  * the value of phy_type. The actual speed depends on the speed of the
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index e79baf7..45b1c6a 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -1733,6 +1733,28 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg 
*hsotg, u16 typereq,
                        port_status |= USB_PORT_STAT_TEST;
                /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
 
+               if (hsotg->core_params->dma_desc_fs_enable) {
+                       /*
+                        * Enable descriptor DMA only if a full speed
+                        * device is connected.
+                        */
+                       if (hsotg->new_connection &&
+                           ((port_status &
+                             (USB_PORT_STAT_CONNECTION |
+                              USB_PORT_STAT_HIGH_SPEED |
+                              USB_PORT_STAT_LOW_SPEED)) ==
+                              USB_PORT_STAT_CONNECTION)) {
+                               u32 hcfg;
+
+                               dev_info(hsotg->dev, "Enabling descriptor DMA 
mode\n");
+                               hsotg->core_params->dma_desc_enable = 1;
+                               hcfg = dwc2_readl(hsotg->regs + HCFG);
+                               hcfg |= HCFG_DESCDMA;
+                               dwc2_writel(hcfg, hsotg->regs + HCFG);
+                               hsotg->new_connection = false;
+                       }
+               }
+
                dev_vdbg(hsotg->dev, "port_status=%08x\n", port_status);
                *(__le32 *)buf = cpu_to_le32(port_status);
                break;
diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c
index bda0b21..7c15f03 100644
--- a/drivers/usb/dwc2/hcd_intr.c
+++ b/drivers/usb/dwc2/hcd_intr.c
@@ -372,10 +372,21 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
                         "  --Port Interrupt HPRT0=0x%08x Port Enable Changed 
(now %d)--\n",
                         hprt0, !!(hprt0 & HPRT0_ENA));
                hprt0_modify |= HPRT0_ENACHG;
-               if (hprt0 & HPRT0_ENA)
+               if (hprt0 & HPRT0_ENA) {
+                       hsotg->new_connection = true;
                        dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify);
-               else
+               } else {
                        hsotg->flags.b.port_enable_change = 1;
+                       if (hsotg->core_params->dma_desc_fs_enable) {
+                               u32 hcfg;
+
+                               hsotg->core_params->dma_desc_enable = 0;
+                               hsotg->new_connection = false;
+                               hcfg = dwc2_readl(hsotg->regs + HCFG);
+                               hcfg &= ~HCFG_DESCDMA;
+                               dwc2_writel(hcfg, hsotg->regs + HCFG);
+                       }
+               }
        }
 
        /* Overcurrent Change Interrupt */
diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c
index 7d8d06c..27d402f 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -232,7 +232,7 @@ struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
  */
 void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
 {
-       if (hsotg->core_params->dma_desc_enable > 0) {
+       if (qh->desc_list) {
                dwc2_hcd_qh_free_ddma(hsotg, qh);
        } else {
                /* kfree(NULL) is safe */
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 5859b0f..fb93b9d 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -59,6 +59,7 @@ static const struct dwc2_core_params params_bcm2835 = {
        .otg_ver                        = 0,    /* 1.3 */
        .dma_enable                     = 1,
        .dma_desc_enable                = 0,
+       .dma_desc_fs_enable             = 0,
        .speed                          = 0,    /* High Speed */
        .enable_dynamic_fifo            = 1,
        .en_multiple_tx_fifo            = 1,
@@ -89,6 +90,7 @@ static const struct dwc2_core_params params_rk3066 = {
        .otg_ver                        = -1,
        .dma_enable                     = -1,
        .dma_desc_enable                = 0,
+       .dma_desc_fs_enable             = 0,
        .speed                          = -1,
        .enable_dynamic_fifo            = 1,
        .en_multiple_tx_fifo            = -1,
@@ -322,8 +324,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
                /*
                 * Disable descriptor dma mode by default as the HW can support
                 * it, but does not support it for SPLIT transactions.
+                * Disable it for FS devices as well.
                 */
                defparams.dma_desc_enable = 0;
+               defparams.dma_desc_fs_enable = 0;
        }
 
        hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
-- 
2.6.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to