summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r--drivers/usb/dwc3/core.c235
1 files changed, 233 insertions, 2 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index fea4469..e34ef90 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -58,6 +58,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
enum usb_dr_mode mode;
struct device *dev = dwc->dev;
unsigned int hw_mode;
+ struct device_node *node = dev->of_node;
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
dwc->dr_mode = USB_DR_MODE_OTG;
@@ -83,6 +84,24 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
mode = USB_DR_MODE_HOST;
break;
default:
+ /* Adjust Frame Length */
+ if (dwc->configure_gfladj)
+ dwc3_writel(dwc->regs, DWC3_GFLADJ, GFLADJ_30MHZ_REG_SEL |
+ GFLADJ_30MHZ(GFLADJ_30MHZ_DEFAULT));
+
+ /* Change burst beat and outstanding pipelined transfers requests */
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0,
+ (dwc3_readl(dwc->regs, DWC3_GSBUSCFG0) & ~0xff) | 0xf);
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG1,
+ dwc3_readl(dwc->regs, DWC3_GSBUSCFG1) | 0xf00);
+
+ /* Enable Snooping */
+ if (node && of_dma_is_coherent(node)) {
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0,
+ dwc3_readl(dwc->regs, DWC3_GSBUSCFG0) | 0x22220000);
+ dev_dbg(dev, "enabled snooping for usb\n");
+ }
+
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
mode = USB_DR_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
@@ -213,8 +232,9 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
dft = reg & DWC3_GFLADJ_30MHZ_MASK;
- if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj,
- "request value same as default, ignoring\n")) {
+ if (dft == dwc->fladj) {
+ dev_warn(dwc->dev, "request value same as default, ignoring\n");
+ } else {
reg &= ~DWC3_GFLADJ_30MHZ_MASK;
reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
@@ -579,6 +599,99 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
return 0;
}
+/* set global soc bus configuration registers */
+static void dwc3_set_soc_bus_cfg(struct dwc3 *dwc)
+{
+ struct device *dev = dwc->dev;
+ u32 *vals;
+ u32 cfg;
+ int ntype;
+ int ret;
+ int i;
+
+ cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
+
+ /*
+ * 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.
+ */
+ ntype = device_property_read_u32_array(dev,
+ "snps,incr-burst-type-adjustment", NULL, 0);
+ if (ntype > 0) {
+ vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL);
+ if (!vals) {
+ dev_err(dev, "Error to get memory\n");
+ return;
+ }
+ /* Get INCR burst type, and parse it */
+ ret = device_property_read_u32_array(dev,
+ "snps,incr-burst-type-adjustment", vals, ntype);
+ if (ret) {
+ dev_err(dev, "Error to get property\n");
+ return;
+ }
+ *(dwc->incrx_type + 1) = vals[0];
+ if (ntype > 1) {
+ *dwc->incrx_type = 1;
+ for (i = 1; i < ntype; i++) {
+ if (vals[i] > *(dwc->incrx_type + 1))
+ *(dwc->incrx_type + 1) = vals[i];
+ }
+ } else
+ *dwc->incrx_type = 0;
+
+ /* Enable Undefined Length INCR Burst and Enable INCRx Burst */
+ cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
+ if (*dwc->incrx_type)
+ cfg |= DWC3_GSBUSCFG0_INCRBRSTENA;
+ switch (*(dwc->incrx_type + 1)) {
+ case 256:
+ cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA;
+ break;
+ case 128:
+ cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA;
+ break;
+ case 64:
+ cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA;
+ break;
+ case 32:
+ cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA;
+ break;
+ case 16:
+ cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA;
+ break;
+ case 8:
+ cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA;
+ break;
+ case 4:
+ cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA;
+ break;
+ case 1:
+ break;
+ default:
+ dev_err(dev, "Invalid property\n");
+ break;
+ }
+ }
+
+ /* Handle usb snooping */
+ if (dwc->dma_snooping_quirk) {
+ cfg &= ~DWC3_GSBUSCFG0_SNP_MASK;
+ cfg |= (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DATARD_SHIFT) |
+ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DESCRD_SHIFT) |
+ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DATAWR_SHIFT) |
+ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DESCWR_SHIFT);
+ }
+
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
+
+}
+
+
+
static void dwc3_core_exit(struct dwc3 *dwc)
{
dwc3_event_buffers_cleanup(dwc);
@@ -721,6 +834,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (ret)
goto err1;
+ dwc3_set_soc_bus_cfg(dwc);
+
/* Adjust Frame Length */
dwc3_frame_length_adjustment(dwc);
@@ -919,11 +1034,109 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
}
}
+static void dwc3_get_properties(struct dwc3 *dwc)
+{
+ struct device *dev = dwc->dev;
+ struct device_node *node = dev->of_node;
+ u8 lpm_nyet_threshold;
+ u8 tx_de_emphasis;
+ u8 hird_threshold;
+
+ /* 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 = usb_get_maximum_speed(dev);
+ dwc->dr_mode = usb_get_dr_mode(dev);
+ dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node);
+
+ dwc->sysdev_is_parent = device_property_read_bool(dev,
+ "linux,sysdev_is_parent");
+ if (dwc->sysdev_is_parent)
+ dwc->sysdev = dwc->dev->parent;
+ else
+ dwc->sysdev = dwc->dev;
+
+ dwc->has_lpm_erratum = device_property_read_bool(dev,
+ "snps,has-lpm-erratum");
+ device_property_read_u8(dev, "snps,lpm-nyet-threshold",
+ &lpm_nyet_threshold);
+ dwc->is_utmi_l1_suspend = device_property_read_bool(dev,
+ "snps,is-utmi-l1-suspend");
+ device_property_read_u8(dev, "snps,hird-threshold",
+ &hird_threshold);
+ dwc->usb3_lpm_capable = device_property_read_bool(dev,
+ "snps,usb3_lpm_capable");
+
+ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+
+ dwc->configure_gfladj =
+ of_property_read_bool(node, "configure-gfladj");
+ dwc->dr_mode = usb_get_dr_mode(dev);
+
+ dwc->disable_scramble_quirk = device_property_read_bool(dev,
+ "snps,disable_scramble_quirk");
+ dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
+ "snps,u2exit_lfps_quirk");
+ dwc->u2ss_inp3_quirk = device_property_read_bool(dev,
+ "snps,u2ss_inp3_quirk");
+ dwc->req_p1p2p3_quirk = device_property_read_bool(dev,
+ "snps,req_p1p2p3_quirk");
+ dwc->del_p1p2p3_quirk = device_property_read_bool(dev,
+ "snps,del_p1p2p3_quirk");
+ dwc->del_phy_power_chg_quirk = device_property_read_bool(dev,
+ "snps,del_phy_power_chg_quirk");
+ dwc->lfps_filter_quirk = device_property_read_bool(dev,
+ "snps,lfps_filter_quirk");
+ dwc->rx_detect_poll_quirk = device_property_read_bool(dev,
+ "snps,rx_detect_poll_quirk");
+ dwc->dis_u3_susphy_quirk = device_property_read_bool(dev,
+ "snps,dis_u3_susphy_quirk");
+ dwc->dis_u2_susphy_quirk = device_property_read_bool(dev,
+ "snps,dis_u2_susphy_quirk");
+ dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
+ "snps,dis_enblslpm_quirk");
+ dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
+ "snps,dis_rxdet_inp3_quirk");
+ dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
+ "snps,dis-u2-freeclk-exists-quirk");
+ dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
+ "snps,dis-del-phy-power-chg-quirk");
+ dwc->dma_snooping_quirk = device_property_read_bool(dev,
+ "snps,dma-snooping");
+
+ dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
+ "snps,tx_de_emphasis_quirk");
+ device_property_read_u8(dev, "snps,tx_de_emphasis",
+ &tx_de_emphasis);
+ device_property_read_string(dev, "snps,hsphy_interface",
+ &dwc->hsphy_interface);
+ device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
+ &dwc->fladj);
+
+ 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->imod_interval = 0;
+}
+
#define DWC3_ALIGN_MASK (16 - 1)
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
struct resource *res;
struct dwc3 *dwc;
u8 lpm_nyet_threshold;
@@ -955,6 +1168,11 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->xhci_resources[0].flags = res->flags;
dwc->xhci_resources[0].name = res->name;
+ if (node) {
+ dwc->configure_gfladj =
+ of_property_read_bool(node, "configure-gfladj");
+ }
+
res->start += DWC3_GLOBALS_REGS_START;
/*
@@ -997,6 +1215,12 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->usb3_lpm_capable = device_property_read_bool(dev,
"snps,usb3_lpm_capable");
+ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");
+
+ dwc->configure_gfladj =
+ of_property_read_bool(node, "configure-gfladj");
+ dwc->dr_mode = of_usb_get_dr_mode(node);
+
dwc->disable_scramble_quirk = device_property_read_bool(dev,
"snps,disable_scramble_quirk");
dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
@@ -1041,6 +1265,8 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->hird_threshold = hird_threshold
| (dwc->is_utmi_l1_suspend << 4);
+ dwc3_get_properties(dwc);
+
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
@@ -1064,6 +1290,11 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret < 0)
goto err1;
+ /* Adjust Frame Length */
+ if (dwc->configure_gfladj)
+ dwc3_writel(dwc->regs, DWC3_GFLADJ, GFLADJ_30MHZ_REG_SEL |
+ GFLADJ_30MHZ(GFLADJ_30MHZ_DEFAULT));
+
pm_runtime_forbid(dev);
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);