aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/core.c64
-rw-r--r--drivers/usb/dwc3/core.h23
-rw-r--r--drivers/usb/dwc3/host.c9
3 files changed, 91 insertions, 5 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c2ce2f5e60a1..9e8920985d4d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1323,6 +1323,24 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
}
}
+static void dwc3_set_axi_pipe_limit(struct dwc3 *dwc)
+{
+ struct device *dev = dwc->dev;
+ u32 cfg;
+
+ if (!dwc->axi_pipe_limit)
+ return;
+ if (dwc->axi_pipe_limit > 16) {
+ dev_err(dev, "Invalid axi_pipe_limit property\n");
+ return;
+ }
+ cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1);
+ cfg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT(15);
+ cfg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(dwc->axi_pipe_limit - 1);
+
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, cfg);
+}
+
/**
* dwc3_core_init - Low-level initialization of DWC3 Core
* @dwc: Pointer to our controller context structure
@@ -1390,6 +1408,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_config_soc_bus(dwc);
+ dwc3_set_axi_pipe_limit(dwc);
+
ret = dwc3_phy_power_on(dwc);
if (ret)
goto err_exit_phy;
@@ -1463,12 +1483,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->dis_tx_ipgap_linecheck_quirk)
reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
+ if (dwc->enh_nak_fs_quirk)
+ reg |= DWC3_GUCTL1_NAK_PER_ENH_FS;
+
+ if (dwc->enh_nak_hs_quirk)
+ reg |= DWC3_GUCTL1_NAK_PER_ENH_HS;
+
if (dwc->parkmode_disable_ss_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
if (dwc->parkmode_disable_hs_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS;
+ if (dwc->parkmode_disable_fsls_quirk)
+ reg |= DWC3_GUCTL1_PARKMODE_DISABLE_FSLS;
+
if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY)) {
if (dwc->maximum_speed == USB_SPEED_FULL ||
dwc->maximum_speed == USB_SPEED_HIGH)
@@ -1518,6 +1547,24 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
}
+ if (DWC3_IP_IS(DWC3) && dwc->dr_mode == USB_DR_MODE_HOST) {
+ u8 tx_thr_num = dwc->tx_thr_num_pkt_prd;
+ u8 tx_maxburst = dwc->tx_max_burst_prd;
+
+ if (tx_thr_num && tx_maxburst) {
+ reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
+ reg |= DWC3_GTXTHRCFG_PKTCNTSEL;
+
+ reg &= ~DWC3_GTXTHRCFG_TXPKTCNT(~0);
+ reg |= DWC3_GTXTHRCFG_TXPKTCNT(tx_thr_num);
+
+ reg &= ~DWC3_GTXTHRCFG_MAXTXBURSTSIZE(~0);
+ reg |= DWC3_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst);
+
+ dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
+ }
+ }
+
return 0;
err_power_off_phy:
@@ -1703,6 +1750,7 @@ static void dwc3_get_properties(struct dwc3 *dwc)
u8 tx_thr_num_pkt_prd = 0;
u8 tx_max_burst_prd = 0;
u8 tx_fifo_resize_max_num;
+ u8 axi_pipe_limit;
u16 num_hc_interrupters;
/* default to highest possible threshold */
@@ -1724,6 +1772,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
*/
tx_fifo_resize_max_num = 6;
+ /* Default to 0 (don't override hardware defaults) */
+ axi_pipe_limit = 0;
+
/* default to a single XHCI interrupter */
num_hc_interrupters = 1;
@@ -1823,10 +1874,16 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,resume-hs-terminations");
dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev,
"snps,ulpi-ext-vbus-drv");
+ dwc->enh_nak_fs_quirk = device_property_read_bool(dev,
+ "snps,enhanced-nak-fs-quirk");
+ dwc->enh_nak_hs_quirk = device_property_read_bool(dev,
+ "snps,enhanced-nak-hs-quirk");
dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-ss-quirk");
dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-hs-quirk");
+ dwc->parkmode_disable_fsls_quirk = device_property_read_bool(dev,
+ "snps,parkmode-disable-fsls-quirk");
dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev,
"snps,gfladj-refclk-lpm-sel-quirk");
@@ -1847,6 +1904,9 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->dis_split_quirk = device_property_read_bool(dev,
"snps,dis-split-quirk");
+ device_property_read_u8(dev, "snps,axi-pipe-limit",
+ &axi_pipe_limit);
+
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;
@@ -1864,6 +1924,10 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
dwc->tx_max_burst_prd = tx_max_burst_prd;
+ dwc->axi_pipe_limit = axi_pipe_limit;
+
+ dwc->imod_interval = 0;
+
dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
dwc->num_hc_interrupters = num_hc_interrupters;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index a5fc92c4ffa3..9323339481da 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -198,6 +198,9 @@
#define DWC3_GSBUSCFG0_REQINFO(n) (((n) & 0xffff) << 16)
#define DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED 0xffffffff
+/* Global SoC Bus Configuration Register 1 */
+#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) (((n) & 0xf) << 8)
+
/* Global Debug LSP MUX Select */
#define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */
#define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff)
@@ -279,8 +282,11 @@
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
#define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26)
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
+#define DWC3_GUCTL1_NAK_PER_ENH_FS BIT(19)
+#define DWC3_GUCTL1_NAK_PER_ENH_HS BIT(18)
#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17)
#define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16)
+#define DWC3_GUCTL1_PARKMODE_DISABLE_FSLS BIT(15)
#define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10)
/* Global Status Register */
@@ -1095,6 +1101,7 @@ struct dwc3_glue_ops {
* @tx_max_burst_prd: max periodic ESS transmit burst size
* @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize
* @clear_stall_protocol: endpoint number that requires a delayed status phase
+ * @axi_max_pipe: set to override the maximum number of pipelined AXI transfers
* @num_hc_interrupters: number of host controller interrupters
* @hsphy_interface: "utmi" or "ulpi"
* @connected: true when we're connected to a host, false otherwise
@@ -1147,10 +1154,14 @@ struct dwc3_glue_ops {
* generation after resume from suspend.
* @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin
* VBUS with an external supply.
- * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
- * instances in park mode.
- * @parkmode_disable_hs_quirk: set if we need to disable all HishSpeed
- * instances in park mode.
+ * @enh_nak_fs_quirk: Set to schedule more handshakes to Async FS endpoints.
+ * @enh_nak_hs_quirk: Set to schedule more handshakes to Async HS endpoints.
+ * @parkmode_disable_ss_quirk: If set, disable park mode feature for all
+ * Superspeed instances.
+ * @parkmode_disable_hs_quirk: If set, disable park mode feature for all
+ * Highspeed instances.
+ * @parkmode_disable_fsls_quirk: If set, disable park mode feature for all
+ * Full/Lowspeed instances.
* @gfladj_refclk_lpm_sel: set if we need to enable SOF/ITP counter
* running based on ref_clk
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
@@ -1348,6 +1359,7 @@ struct dwc3 {
u8 tx_max_burst_prd;
u8 tx_fifo_resize_max_num;
u8 clear_stall_protocol;
+ u8 axi_pipe_limit;
u16 num_hc_interrupters;
const char *hsphy_interface;
@@ -1390,8 +1402,11 @@ struct dwc3 {
unsigned dis_tx_ipgap_linecheck_quirk:1;
unsigned resume_hs_terminations:1;
unsigned ulpi_ext_vbus_drv:1;
+ unsigned enh_nak_fs_quirk:1;
+ unsigned enh_nak_hs_quirk:1;
unsigned parkmode_disable_ss_quirk:1;
unsigned parkmode_disable_hs_quirk:1;
+ unsigned parkmode_disable_fsls_quirk:1;
unsigned gfladj_refclk_lpm_sel:1;
unsigned tx_de_emphasis_quirk:1;
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 1c513bf8002e..b426ee177162 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -126,10 +126,12 @@ out:
int dwc3_host_init(struct dwc3 *dwc)
{
+ struct platform_device *pdev = to_platform_device(dwc->dev);
struct property_entry props[6];
struct platform_device *xhci;
int ret, irq;
int prop_idx = 0;
+ int id;
/*
* Some platforms need to power off all Root hub ports immediately after DWC3 set to host
@@ -141,7 +143,12 @@ int dwc3_host_init(struct dwc3 *dwc)
if (irq < 0)
return irq;
- xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
+ id = of_alias_get_id(pdev->dev.of_node, "usb");
+ if (id >= 0)
+ xhci = platform_device_alloc("xhci-hcd", id);
+ else
+ xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
+
if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
return -ENOMEM;