usb: dwc2: host: enable descriptor dma for fs devices
authorMian Yousaf Kaukab <yousaf.kaukab@intel.com>
Fri, 20 Nov 2015 10:49:28 +0000 (11:49 +0100)
committerFelipe Balbi <balbi@ti.com>
Tue, 15 Dec 2015 15:12:41 +0000 (09:12 -0600)
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.

Acked-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Mian Yousaf Kaukab <yousaf.kaukab@intel.com>
Signed-off-by: Gregory Herrero <gregory.herrero@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd_intr.c
drivers/usb/dwc2/hcd_queue.c
drivers/usb/dwc2/platform.c

index ef73e498e98fc85501ff65cbeeaa20cd13ec9c4c..5568d9c8e213c932992e9f4c04211d54aa5c4428 100644 (file)
@@ -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,
index a66d3cb62b65980fe670bc51bb5f4401a58d9df3..fd4c2365069ae92c080988063c42ccd2689fe20c 100644 (file)
@@ -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
@@ -941,6 +951,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
index 571c21727ff9f5cb8c774eeb1178cfc55e8e88b4..32c84e7a81ab3d58c1e1c2f887a873ab4ce8a30a 100644 (file)
@@ -1734,6 +1734,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;
index bda0b21b850f695627efb5b1e70ae0e63de39638..7c15f03b069c5141d6947794e01d04d3710fa757 100644 (file)
@@ -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 */
index 7d8d06cfe3c1df1d5bc1a5534205464d89f65a56..27d402f680a321edae9c955629b2788062aeb74a 100644 (file)
@@ -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 */
index 39c1cbf0e75d9a5957b1567def5d23fb3631a015..095bc05f76cae6159a395ae32bb08c29155e4da9 100644 (file)
@@ -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,
@@ -348,8 +350,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);