diff options
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r-- | drivers/usb/dwc3/core.c | 88 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.h | 5 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-pci.c | 21 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-st.c | 12 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 64 | ||||
-rw-r--r-- | drivers/usb/dwc3/platform_data.h | 2 |
6 files changed, 136 insertions, 56 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 51156ec91..22b479738 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -34,6 +34,7 @@ #include <linux/dma-mapping.h> #include <linux/of.h> #include <linux/acpi.h> +#include <linux/pinctrl/consumer.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -143,6 +144,32 @@ static int dwc3_soft_reset(struct dwc3 *dwc) return 0; } +/* + * dwc3_frame_length_adjustment - Adjusts frame length if required + * @dwc3: Pointer to our controller context structure + * @fladj: Value of GFLADJ_30MHZ to adjust frame length + */ +static void dwc3_frame_length_adjustment(struct dwc3 *dwc, u32 fladj) +{ + u32 reg; + u32 dft; + + if (dwc->revision < DWC3_REVISION_250A) + return; + + if (fladj == 0) + return; + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; + if (!dev_WARN_ONCE(dwc->dev, dft == fladj, + "request value same as default, ignoring\n")) { + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | fladj; + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); + } +} + /** * dwc3_free_one_event_buffer - Frees one event buffer * @dwc: Pointer to our controller context structure @@ -782,12 +809,12 @@ static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct dwc3_platform_data *pdata = dev_get_platdata(dev); - struct device_node *node = dev->of_node; struct resource *res; struct dwc3 *dwc; u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; + u32 fladj = 0; int ret; @@ -851,53 +878,56 @@ static int dwc3_probe(struct platform_device *pdev) */ hird_threshold = 12; - if (node) { - dwc->maximum_speed = of_usb_get_maximum_speed(node); - dwc->has_lpm_erratum = of_property_read_bool(node, + dwc->maximum_speed = usb_get_maximum_speed(dev); + dwc->dr_mode = usb_get_dr_mode(dev); + + dwc->has_lpm_erratum = device_property_read_bool(dev, "snps,has-lpm-erratum"); - of_property_read_u8(node, "snps,lpm-nyet-threshold", + device_property_read_u8(dev, "snps,lpm-nyet-threshold", &lpm_nyet_threshold); - dwc->is_utmi_l1_suspend = of_property_read_bool(node, + dwc->is_utmi_l1_suspend = device_property_read_bool(dev, "snps,is-utmi-l1-suspend"); - of_property_read_u8(node, "snps,hird-threshold", + device_property_read_u8(dev, "snps,hird-threshold", &hird_threshold); - dwc->usb3_lpm_capable = of_property_read_bool(node, + dwc->usb3_lpm_capable = device_property_read_bool(dev, "snps,usb3_lpm_capable"); - dwc->needs_fifo_resize = of_property_read_bool(node, + dwc->needs_fifo_resize = device_property_read_bool(dev, "tx-fifo-resize"); - dwc->dr_mode = of_usb_get_dr_mode(node); - dwc->disable_scramble_quirk = of_property_read_bool(node, + dwc->disable_scramble_quirk = device_property_read_bool(dev, "snps,disable_scramble_quirk"); - dwc->u2exit_lfps_quirk = of_property_read_bool(node, + dwc->u2exit_lfps_quirk = device_property_read_bool(dev, "snps,u2exit_lfps_quirk"); - dwc->u2ss_inp3_quirk = of_property_read_bool(node, + dwc->u2ss_inp3_quirk = device_property_read_bool(dev, "snps,u2ss_inp3_quirk"); - dwc->req_p1p2p3_quirk = of_property_read_bool(node, + dwc->req_p1p2p3_quirk = device_property_read_bool(dev, "snps,req_p1p2p3_quirk"); - dwc->del_p1p2p3_quirk = of_property_read_bool(node, + dwc->del_p1p2p3_quirk = device_property_read_bool(dev, "snps,del_p1p2p3_quirk"); - dwc->del_phy_power_chg_quirk = of_property_read_bool(node, + dwc->del_phy_power_chg_quirk = device_property_read_bool(dev, "snps,del_phy_power_chg_quirk"); - dwc->lfps_filter_quirk = of_property_read_bool(node, + dwc->lfps_filter_quirk = device_property_read_bool(dev, "snps,lfps_filter_quirk"); - dwc->rx_detect_poll_quirk = of_property_read_bool(node, + dwc->rx_detect_poll_quirk = device_property_read_bool(dev, "snps,rx_detect_poll_quirk"); - dwc->dis_u3_susphy_quirk = of_property_read_bool(node, + dwc->dis_u3_susphy_quirk = device_property_read_bool(dev, "snps,dis_u3_susphy_quirk"); - dwc->dis_u2_susphy_quirk = of_property_read_bool(node, + 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->tx_de_emphasis_quirk = of_property_read_bool(node, + dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); - of_property_read_u8(node, "snps,tx_de_emphasis", + device_property_read_u8(dev, "snps,tx_de_emphasis", &tx_de_emphasis); - of_property_read_string(node, "snps,hsphy_interface", - &dwc->hsphy_interface); - } else if (pdata) { + device_property_read_string(dev, "snps,hsphy_interface", + &dwc->hsphy_interface); + device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", + &fladj); + + if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; if (pdata->lpm_nyet_threshold) @@ -927,6 +957,7 @@ static int dwc3_probe(struct platform_device *pdev) tx_de_emphasis = pdata->tx_de_emphasis; dwc->hsphy_interface = pdata->hsphy_interface; + fladj = pdata->fladj_value; } /* default to superspeed if no maximum_speed passed */ @@ -983,6 +1014,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err1; } + /* Adjust Frame Length */ + dwc3_frame_length_adjustment(dwc, fladj); + usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); @@ -1103,6 +1137,8 @@ static int dwc3_suspend(struct device *dev) phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); + pinctrl_pm_select_sleep_state(dev); + return 0; } @@ -1112,6 +1148,8 @@ static int dwc3_resume(struct device *dev) unsigned long flags; int ret; + pinctrl_pm_select_default_state(dev); + usb_phy_init(dwc->usb3_phy); usb_phy_init(dwc->usb2_phy); ret = phy_init(dwc->usb2_generic_phy); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 6e53ce9ce..36f1cb745 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -127,6 +127,7 @@ #define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10)) #define DWC3_GHWPARAMS8 0xc600 +#define DWC3_GFLADJ 0xc630 /* Device Registers */ #define DWC3_DCFG 0xc700 @@ -238,6 +239,10 @@ /* Global HWPARAMS6 Register */ #define DWC3_GHWPARAMS6_EN_FPGA (1 << 7) +/* Global Frame Length Adjustment Register */ +#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) +#define DWC3_GFLADJ_30MHZ_MASK 0x3f + /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 2cd33cb07..009d83048 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -26,14 +26,16 @@ #include "platform_data.h" -#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd -#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce -#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf -#define PCI_DEVICE_ID_INTEL_BYT 0x0f37 -#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e -#define PCI_DEVICE_ID_INTEL_BSW 0x22B7 -#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 -#define PCI_DEVICE_ID_INTEL_SPTH 0xa130 +#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd +#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce +#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf +#define PCI_DEVICE_ID_INTEL_BYT 0x0f37 +#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e +#define PCI_DEVICE_ID_INTEL_BSW 0x22b7 +#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 +#define PCI_DEVICE_ID_INTEL_SPTH 0xa130 +#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa +#define PCI_DEVICE_ID_INTEL_APL 0x5aaa static const struct acpi_gpio_params reset_gpios = { 0, 0, false }; static const struct acpi_gpio_params cs_gpios = { 1, 0, false }; @@ -172,6 +174,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, goto err; dwc3->dev.parent = dev; + ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev)); ret = platform_device_add(dwc3); if (ret) { @@ -209,6 +212,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, { } /* Terminating Entry */ }; diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index de4d52f62..5c0adb9c6 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -195,6 +195,7 @@ static int st_dwc3_probe(struct platform_device *pdev) struct resource *res; struct device *dev = &pdev->dev; struct device_node *node = dev->of_node, *child; + struct platform_device *child_pdev; struct regmap *regmap; int ret; @@ -253,8 +254,6 @@ static int st_dwc3_probe(struct platform_device *pdev) goto undo_softreset; } - dwc3_data->dr_mode = of_usb_get_dr_mode(child); - /* Allocate and initialize the core */ ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { @@ -262,6 +261,15 @@ static int st_dwc3_probe(struct platform_device *pdev) goto undo_softreset; } + child_pdev = of_find_device_by_node(child); + if (!child_pdev) { + dev_err(dev, "failed to find dwc3 core device\n"); + ret = -ENODEV; + goto undo_softreset; + } + + dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev); + /* * Configure the USB port as device or host according to the static * configuration passed from DT. diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9c38e4b0a..a58376fd6 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -948,7 +948,6 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name); return -EBUSY; } - dep->flags &= ~DWC3_EP_PENDING_REQUEST; /* * If we are getting here after a short-out-packet we don't enqueue any @@ -1050,6 +1049,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) req->direction = dep->direction; req->epnum = dep->number; + trace_dwc3_ep_queue(req); + /* * We only add to our list of requests now and * start consuming the list once we get XferNotReady @@ -1070,6 +1071,20 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->request_list); /* + * If there are no pending requests and the endpoint isn't already + * busy, we will just start the request straight away. + * + * This will save one IRQ (XFER_NOT_READY) and possibly make it a + * little bit faster. + */ + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && + !usb_endpoint_xfer_int(dep->endpoint.desc) && + !(dep->flags & DWC3_EP_BUSY)) { + ret = __dwc3_gadget_kick_transfer(dep, 0, true); + goto out; + } + + /* * There are a few special cases: * * 1. XferNotReady with empty list of requests. We need to kick the @@ -1096,10 +1111,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) } ret = __dwc3_gadget_kick_transfer(dep, 0, true); - if (ret && ret != -EBUSY) - dev_dbg(dwc->dev, "%s: failed to kick transfers\n", - dep->name); - return ret; + if (!ret) + dep->flags &= ~DWC3_EP_PENDING_REQUEST; + + goto out; } /* @@ -1113,10 +1128,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) WARN_ON_ONCE(!dep->resource_index); ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, false); - if (ret && ret != -EBUSY) - dev_dbg(dwc->dev, "%s: failed to kick transfers\n", - dep->name); - return ret; + goto out; } /* @@ -1124,14 +1136,17 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * right away, otherwise host will not know we have streams to be * handled. */ - if (dep->stream_capable) { + if (dep->stream_capable) ret = __dwc3_gadget_kick_transfer(dep, 0, true); - if (ret && ret != -EBUSY) - dev_dbg(dwc->dev, "%s: failed to kick transfers\n", - dep->name); - } - return 0; +out: + if (ret && ret != -EBUSY) + dev_dbg(dwc->dev, "%s: failed to kick transfers\n", + dep->name); + if (ret == -EBUSY) + ret = 0; + + return ret; } static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, @@ -1159,8 +1174,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, goto out; } - trace_dwc3_ep_queue(req); - ret = __dwc3_gadget_ep_queue(dep, req); out: @@ -1960,6 +1973,14 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, dwc->u1u2 = 0; } + + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { + int ret; + + ret = __dwc3_gadget_kick_transfer(dep, 0, is_xfer_complete); + if (!ret || ret == -EBUSY) + return; + } } static void dwc3_endpoint_interrupt(struct dwc3 *dwc, @@ -1997,15 +2018,16 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dwc3_gadget_start_isoc(dwc, dep, event); } else { + int active; int ret; + active = event->status & DEPEVT_STATUS_TRANSFER_ACTIVE; + dwc3_trace(trace_dwc3_gadget, "%s: reason %s", - dep->name, event->status & - DEPEVT_STATUS_TRANSFER_ACTIVE - ? "Transfer Active" + dep->name, active ? "Transfer Active" : "Transfer Not Active"); - ret = __dwc3_gadget_kick_transfer(dep, 0, 1); + ret = __dwc3_gadget_kick_transfer(dep, 0, !active); if (!ret || ret == -EBUSY) return; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index db2938002..2bb4d3ad0 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -47,5 +47,7 @@ struct dwc3_platform_data { unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; + u32 fladj_value; + const char *hsphy_interface; }; |