diff options
author | Mian Yousaf Kaukab <yousaf.kaukab@intel.com> | 2015-11-20 13:49:28 +0300 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2015-12-15 18:12:41 +0300 |
commit | fbb9e22b15ad3c9a98c66bad801b4d1366e8bf20 (patch) | |
tree | 11c3c1a561b92a95b608e597052c1ae029aa6986 /drivers/usb | |
parent | 75f5c434c30b22a48a1d4a0f827473dc29036d78 (diff) | |
download | linux-fbb9e22b15ad3c9a98c66bad801b4d1366e8bf20.tar.xz |
usb: dwc2: host: enable descriptor dma for fs devices
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/dwc2/core.c | 24 | ||||
-rw-r--r-- | drivers/usb/dwc2/core.h | 20 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd.c | 22 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_intr.c | 15 | ||||
-rw-r--r-- | drivers/usb/dwc2/hcd_queue.c | 2 | ||||
-rw-r--r-- | 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 ef73e498e98f..5568d9c8e213 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 a66d3cb62b65..fd4c2365069a 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 571c21727ff9..32c84e7a81ab 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -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; diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index bda0b21b850f..7c15f03b069c 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 7d8d06cfe3c1..27d402f680a3 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 39c1cbf0e75d..095bc05f76ca 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, @@ -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); |