You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'usb-for-v3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next
Felipe writes: usb: patches for v3.15 another substantial pull request with new features all over the place. dwc3 got a bit closer towards hibernation support with after a few patches re-factoring code to be reused for hibernation. Also in dwc3 two new workarounds for known silicon bugs have been implemented, some randconfig build errors have been fixed, and it was taught about the new generic phy layer. MUSB on AM335x now supports isochronous transfers thanks to George Cherian's work. The atmel_usba driver got two crash fixes: one when no endpoint was specified in DeviceTree data and another when stopping the UDC in DEBUG builds. Function FS got a much needed fix to ffs_epfile_io() which was copying too much data to userspace in some cases. The printer gadget got a fix for a possible deadlock and plugged a memory leak. Ethernet drivers now use NAPI for RX which gives improved throughput. Other than that, the usual miscelaneous fixes, cleanups, and the like. Signed-of-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
TI PHY: DT DOCUMENTATION FOR PHYs in TI PLATFORMs
|
||||
|
||||
OMAP CONTROL PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of
|
||||
"ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4.
|
||||
"ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register
|
||||
e.g. USB2_PHY on OMAP5.
|
||||
"ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control
|
||||
e.g. USB3 PHY and SATA PHY on OMAP5.
|
||||
"ti,control-phy-usb2-dra7" - if it has power down register like USB2 PHY on
|
||||
DRA7 platform.
|
||||
"ti,control-phy-usb2-am437" - if it has power down register like USB2 PHY on
|
||||
AM437 platform.
|
||||
- reg : Address and length of the register set for the device. It contains
|
||||
the address of "otghs_control" for control-phy-otghs or "power" register
|
||||
for other types.
|
||||
- reg-names: should be "otghs_control" control-phy-otghs and "power" for
|
||||
other types.
|
||||
|
||||
omap_control_usb: omap-control-usb@4a002300 {
|
||||
compatible = "ti,control-phy-otghs";
|
||||
reg = <0x4a00233c 0x4>;
|
||||
reg-names = "otghs_control";
|
||||
};
|
||||
|
||||
OMAP USB2 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,omap-usb2"
|
||||
- reg : Address and length of the register set for the device.
|
||||
- #phy-cells: determine the number of cells that should be given in the
|
||||
phandle while referencing this phy.
|
||||
|
||||
Optional properties:
|
||||
- ctrl-module : phandle of the control module used by PHY driver to power on
|
||||
the PHY.
|
||||
|
||||
This is usually a subnode of ocp2scp to which it is connected.
|
||||
|
||||
usb2phy@4a0ad080 {
|
||||
compatible = "ti,omap-usb2";
|
||||
reg = <0x4a0ad080 0x58>;
|
||||
ctrl-module = <&omap_control_usb>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
TI PIPE3 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,phy-usb3" or "ti,phy-pipe3-sata".
|
||||
"ti,omap-usb3" is deprecated.
|
||||
- reg : Address and length of the register set for the device.
|
||||
- reg-names: The names of the register addresses corresponding to the registers
|
||||
filled in "reg".
|
||||
- #phy-cells: determine the number of cells that should be given in the
|
||||
phandle while referencing this phy.
|
||||
- clocks: a list of phandles and clock-specifier pairs, one for each entry in
|
||||
clock-names.
|
||||
- clock-names: should include:
|
||||
* "wkupclk" - wakeup clock.
|
||||
* "sysclk" - system clock.
|
||||
* "refclk" - reference clock.
|
||||
|
||||
Optional properties:
|
||||
- ctrl-module : phandle of the control module used by PHY driver to power on
|
||||
the PHY.
|
||||
|
||||
This is usually a subnode of ocp2scp to which it is connected.
|
||||
|
||||
usb3phy@4a084400 {
|
||||
compatible = "ti,phy-usb3";
|
||||
reg = <0x4a084400 0x80>,
|
||||
<0x4a084800 0x64>,
|
||||
<0x4a084c00 0x40>;
|
||||
reg-names = "phy_rx", "phy_tx", "pll_ctrl";
|
||||
ctrl-module = <&omap_control_usb>;
|
||||
#phy-cells = <0>;
|
||||
clocks = <&usb_phy_cm_clk32k>,
|
||||
<&sys_clkin>,
|
||||
<&usb_otg_ss_refclk960m>;
|
||||
clock-names = "wkupclk",
|
||||
"sysclk",
|
||||
"refclk";
|
||||
};
|
||||
@@ -6,11 +6,13 @@ Required properties:
|
||||
- compatible: must be "snps,dwc3"
|
||||
- reg : Address and length of the register set for the device
|
||||
- interrupts: Interrupts used by the dwc3 controller.
|
||||
|
||||
Optional properties:
|
||||
- usb-phy : array of phandle for the PHY device. The first element
|
||||
in the array is expected to be a handle to the USB2/HS PHY and
|
||||
the second element is expected to be a handle to the USB3/SS PHY
|
||||
|
||||
Optional properties:
|
||||
- phys: from the *Generic PHY* bindings
|
||||
- phy-names: from the *Generic PHY* bindings
|
||||
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
|
||||
|
||||
This is usually a subnode to DWC3 glue to which it is connected.
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
* Freescale MXS USB Phy Device
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx23-usbphy"
|
||||
- compatible: should contain:
|
||||
* "fsl,imx23-usbphy" for imx23 and imx28
|
||||
* "fsl,imx6q-usbphy" for imx6dq and imx6dl
|
||||
* "fsl,imx6sl-usbphy" for imx6sl
|
||||
"fsl,imx23-usbphy" is still a fallback for other strings
|
||||
- reg: Should contain registers location and length
|
||||
- interrupts: Should contain phy interrupt
|
||||
- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series
|
||||
|
||||
Example:
|
||||
usbphy1: usbphy@020c9000 {
|
||||
compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
|
||||
reg = <0x020c9000 0x1000>;
|
||||
interrupts = <0 44 0x04>;
|
||||
fsl,anatop = <&anatop>;
|
||||
};
|
||||
|
||||
@@ -76,27 +76,3 @@ omap_dwc3 {
|
||||
ranges;
|
||||
};
|
||||
|
||||
OMAP CONTROL USB
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of
|
||||
"ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4.
|
||||
"ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register
|
||||
e.g. USB2_PHY on OMAP5.
|
||||
"ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control
|
||||
e.g. USB3 PHY and SATA PHY on OMAP5.
|
||||
"ti,control-phy-dra7usb2" - if it has power down register like USB2 PHY on
|
||||
DRA7 platform.
|
||||
"ti,control-phy-am437usb2" - if it has power down register like USB2 PHY on
|
||||
AM437 platform.
|
||||
- reg : Address and length of the register set for the device. It contains
|
||||
the address of "otghs_control" for control-phy-otghs or "power" register
|
||||
for other types.
|
||||
- reg-names: should be "otghs_control" control-phy-otghs and "power" for
|
||||
other types.
|
||||
|
||||
omap_control_usb: omap-control-usb@4a002300 {
|
||||
compatible = "ti,control-phy-otghs";
|
||||
reg = <0x4a00233c 0x4>;
|
||||
reg-names = "otghs_control";
|
||||
};
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
USB PHY
|
||||
|
||||
OMAP USB2 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,omap-usb2"
|
||||
- reg : Address and length of the register set for the device.
|
||||
- #phy-cells: determine the number of cells that should be given in the
|
||||
phandle while referencing this phy.
|
||||
|
||||
Optional properties:
|
||||
- ctrl-module : phandle of the control module used by PHY driver to power on
|
||||
the PHY.
|
||||
|
||||
This is usually a subnode of ocp2scp to which it is connected.
|
||||
|
||||
usb2phy@4a0ad080 {
|
||||
compatible = "ti,omap-usb2";
|
||||
reg = <0x4a0ad080 0x58>;
|
||||
ctrl-module = <&omap_control_usb>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
OMAP USB3 PHY
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,omap-usb3"
|
||||
- reg : Address and length of the register set for the device.
|
||||
- reg-names: The names of the register addresses corresponding to the registers
|
||||
filled in "reg".
|
||||
- #phy-cells: determine the number of cells that should be given in the
|
||||
phandle while referencing this phy.
|
||||
|
||||
Optional properties:
|
||||
- ctrl-module : phandle of the control module used by PHY driver to power on
|
||||
the PHY.
|
||||
|
||||
This is usually a subnode of ocp2scp to which it is connected.
|
||||
|
||||
usb3phy@4a084400 {
|
||||
compatible = "ti,omap-usb3";
|
||||
reg = <0x4a084400 0x80>,
|
||||
<0x4a084800 0x64>,
|
||||
<0x4a084c00 0x40>;
|
||||
reg-names = "phy_rx", "phy_tx", "pll_ctrl";
|
||||
ctrl-module = <&omap_control_usb>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
+222
-31
@@ -61,9 +61,10 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
|
||||
* @dwc: pointer to our context structure
|
||||
*/
|
||||
static void dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
static int dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
{
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
/* Before Resetting PHY, put Core in Reset */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
@@ -82,6 +83,15 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
|
||||
usb_phy_init(dwc->usb2_phy);
|
||||
usb_phy_init(dwc->usb3_phy);
|
||||
ret = phy_init(dwc->usb2_generic_phy);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = phy_init(dwc->usb3_generic_phy);
|
||||
if (ret < 0) {
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
return ret;
|
||||
}
|
||||
mdelay(100);
|
||||
|
||||
/* Clear USB3 PHY reset */
|
||||
@@ -100,6 +110,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_CORESOFTRESET;
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,6 +254,90 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
||||
}
|
||||
}
|
||||
|
||||
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
if (!dwc->has_hibernation)
|
||||
return 0;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return 0;
|
||||
|
||||
dwc->scratchbuf = kmalloc_array(dwc->nr_scratch,
|
||||
DWC3_SCRATCHBUF_SIZE, GFP_KERNEL);
|
||||
if (!dwc->scratchbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_setup_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
dma_addr_t scratch_addr;
|
||||
u32 param;
|
||||
int ret;
|
||||
|
||||
if (!dwc->has_hibernation)
|
||||
return 0;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return 0;
|
||||
|
||||
/* should never fall here */
|
||||
if (!WARN_ON(dwc->scratchbuf))
|
||||
return 0;
|
||||
|
||||
scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf,
|
||||
dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE,
|
||||
DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(dwc->dev, scratch_addr)) {
|
||||
dev_err(dwc->dev, "failed to map scratch buffer\n");
|
||||
ret = -EFAULT;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->scratch_addr = scratch_addr;
|
||||
|
||||
param = lower_32_bits(scratch_addr);
|
||||
|
||||
ret = dwc3_send_gadget_generic_command(dwc,
|
||||
DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
param = upper_32_bits(scratch_addr);
|
||||
|
||||
ret = dwc3_send_gadget_generic_command(dwc,
|
||||
DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
|
||||
DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_free_scratch_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
if (!dwc->has_hibernation)
|
||||
return;
|
||||
|
||||
if (!dwc->nr_scratch)
|
||||
return;
|
||||
|
||||
/* should never fall here */
|
||||
if (!WARN_ON(dwc->scratchbuf))
|
||||
return;
|
||||
|
||||
dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch *
|
||||
DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL);
|
||||
kfree(dwc->scratchbuf);
|
||||
}
|
||||
|
||||
static void dwc3_core_num_eps(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||
@@ -277,6 +373,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||
static int dwc3_core_init(struct dwc3 *dwc)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 hwparams4 = dwc->hwparams.hwparams4;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
@@ -306,7 +403,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
cpu_relax();
|
||||
} while (true);
|
||||
|
||||
dwc3_core_soft_reset(dwc);
|
||||
ret = dwc3_core_soft_reset(dwc);
|
||||
if (ret)
|
||||
goto err0;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
||||
@@ -314,7 +413,29 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
|
||||
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
|
||||
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
|
||||
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
|
||||
/**
|
||||
* WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
|
||||
* issue which would cause xHCI compliance tests to fail.
|
||||
*
|
||||
* Because of that we cannot enable clock gating on such
|
||||
* configurations.
|
||||
*
|
||||
* Refers to:
|
||||
*
|
||||
* STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based
|
||||
* SOF/ITP Mode Used
|
||||
*/
|
||||
if ((dwc->dr_mode == USB_DR_MODE_HOST ||
|
||||
dwc->dr_mode == USB_DR_MODE_OTG) &&
|
||||
(dwc->revision >= DWC3_REVISION_210A &&
|
||||
dwc->revision <= DWC3_REVISION_250A))
|
||||
reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC;
|
||||
else
|
||||
reg &= ~DWC3_GCTL_DSBLCLKGTNG;
|
||||
break;
|
||||
case DWC3_GHWPARAMS1_EN_PWROPT_HIB:
|
||||
/* enable hibernation here */
|
||||
dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dwc->dev, "No power optimization available\n");
|
||||
@@ -333,16 +454,36 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
||||
ret = dwc3_alloc_scratch_buffers(dwc);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
ret = dwc3_setup_scratch_buffers(dwc);
|
||||
if (ret)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
dwc3_free_scratch_buffers(dwc);
|
||||
|
||||
err1:
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwc3_core_exit(struct dwc3 *dwc)
|
||||
{
|
||||
dwc3_free_scratch_buffers(dwc);
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
}
|
||||
|
||||
#define DWC3_ALIGN_MASK (16 - 1)
|
||||
@@ -411,32 +552,52 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
|
||||
if (IS_ERR(dwc->usb2_phy)) {
|
||||
ret = PTR_ERR(dwc->usb2_phy);
|
||||
|
||||
/*
|
||||
* if -ENXIO is returned, it means PHY layer wasn't
|
||||
* enabled, so it makes no sense to return -EPROBE_DEFER
|
||||
* in that case, since no PHY driver will ever probe.
|
||||
*/
|
||||
if (ret == -ENXIO)
|
||||
if (ret == -ENXIO || ret == -ENODEV) {
|
||||
dwc->usb2_phy = NULL;
|
||||
} else if (ret == -EPROBE_DEFER) {
|
||||
return ret;
|
||||
|
||||
dev_err(dev, "no usb2 phy configured\n");
|
||||
return -EPROBE_DEFER;
|
||||
} else {
|
||||
dev_err(dev, "no usb2 phy configured\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ERR(dwc->usb3_phy)) {
|
||||
ret = PTR_ERR(dwc->usb3_phy);
|
||||
|
||||
/*
|
||||
* if -ENXIO is returned, it means PHY layer wasn't
|
||||
* enabled, so it makes no sense to return -EPROBE_DEFER
|
||||
* in that case, since no PHY driver will ever probe.
|
||||
*/
|
||||
if (ret == -ENXIO)
|
||||
if (ret == -ENXIO || ret == -ENODEV) {
|
||||
dwc->usb3_phy = NULL;
|
||||
} else if (ret == -EPROBE_DEFER) {
|
||||
return ret;
|
||||
} else {
|
||||
dev_err(dev, "no usb3 phy configured\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(dev, "no usb3 phy configured\n");
|
||||
return -EPROBE_DEFER;
|
||||
dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy");
|
||||
if (IS_ERR(dwc->usb2_generic_phy)) {
|
||||
ret = PTR_ERR(dwc->usb2_generic_phy);
|
||||
if (ret == -ENOSYS || ret == -ENODEV) {
|
||||
dwc->usb2_generic_phy = NULL;
|
||||
} else if (ret == -EPROBE_DEFER) {
|
||||
return ret;
|
||||
} else {
|
||||
dev_err(dev, "no usb2 phy configured\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy");
|
||||
if (IS_ERR(dwc->usb3_generic_phy)) {
|
||||
ret = PTR_ERR(dwc->usb3_generic_phy);
|
||||
if (ret == -ENOSYS || ret == -ENODEV) {
|
||||
dwc->usb3_generic_phy = NULL;
|
||||
} else if (ret == -EPROBE_DEFER) {
|
||||
return ret;
|
||||
} else {
|
||||
dev_err(dev, "no usb3 phy configured\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dwc->xhci_resources[0].start = res->start;
|
||||
@@ -479,6 +640,14 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
|
||||
dwc->dr_mode = USB_DR_MODE_HOST;
|
||||
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
|
||||
dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
|
||||
|
||||
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
|
||||
dwc->dr_mode = USB_DR_MODE_OTG;
|
||||
|
||||
ret = dwc3_core_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize core\n");
|
||||
@@ -487,21 +656,20 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
||||
ret = phy_power_on(dwc->usb2_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
|
||||
ret = phy_power_on(dwc->usb3_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err_usb2phy_power;
|
||||
|
||||
ret = dwc3_event_buffers_setup(dwc);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to setup event buffers\n");
|
||||
goto err1;
|
||||
goto err_usb3phy_power;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
|
||||
dwc->dr_mode = USB_DR_MODE_HOST;
|
||||
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
|
||||
dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
|
||||
|
||||
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
|
||||
dwc->dr_mode = USB_DR_MODE_OTG;
|
||||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
@@ -568,6 +736,12 @@ err3:
|
||||
err2:
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
err_usb3phy_power:
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
|
||||
err_usb2phy_power:
|
||||
phy_power_off(dwc->usb2_generic_phy);
|
||||
|
||||
err1:
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
@@ -585,6 +759,8 @@ static int dwc3_remove(struct platform_device *pdev)
|
||||
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 1);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 1);
|
||||
phy_power_off(dwc->usb2_generic_phy);
|
||||
phy_power_off(dwc->usb3_generic_phy);
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
@@ -682,6 +858,8 @@ static int dwc3_suspend(struct device *dev)
|
||||
|
||||
usb_phy_shutdown(dwc->usb3_phy);
|
||||
usb_phy_shutdown(dwc->usb2_phy);
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
phy_exit(dwc->usb3_generic_phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -690,9 +868,17 @@ static int dwc3_resume(struct device *dev)
|
||||
{
|
||||
struct dwc3 *dwc = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
usb_phy_init(dwc->usb3_phy);
|
||||
usb_phy_init(dwc->usb2_phy);
|
||||
ret = phy_init(dwc->usb2_generic_phy);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = phy_init(dwc->usb3_generic_phy);
|
||||
if (ret < 0)
|
||||
goto err_usb2phy_init;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
@@ -716,6 +902,11 @@ static int dwc3_resume(struct device *dev)
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_usb2phy_init:
|
||||
phy_exit(dwc->usb2_generic_phy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dwc3_dev_pm_ops = {
|
||||
|
||||
+82
-23
@@ -31,11 +31,14 @@
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
/* Global constants */
|
||||
#define DWC3_EP0_BOUNCE_SIZE 512
|
||||
#define DWC3_ENDPOINTS_NUM 32
|
||||
#define DWC3_XHCI_RESOURCES_NUM 2
|
||||
|
||||
#define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */
|
||||
#define DWC3_EVENT_SIZE 4 /* bytes */
|
||||
#define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */
|
||||
#define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
|
||||
@@ -157,6 +160,7 @@
|
||||
#define DWC3_GCTL_PRTCAP_OTG 3
|
||||
|
||||
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
|
||||
#define DWC3_GCTL_SOFITPSYNC (1 << 10)
|
||||
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
|
||||
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
|
||||
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
|
||||
@@ -318,7 +322,7 @@
|
||||
/* Device Endpoint Command Register */
|
||||
#define DWC3_DEPCMD_PARAM_SHIFT 16
|
||||
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
|
||||
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
||||
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
||||
#define DWC3_DEPCMD_STATUS(x) (((x) >> 15) & 1)
|
||||
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
|
||||
#define DWC3_DEPCMD_CMDACT (1 << 10)
|
||||
@@ -393,6 +397,7 @@ struct dwc3_event_buffer {
|
||||
* @busy_slot: first slot which is owned by HW
|
||||
* @desc: usb_endpoint_descriptor pointer
|
||||
* @dwc: pointer to DWC controller
|
||||
* @saved_state: ep state saved during hibernation
|
||||
* @flags: endpoint flags (wedged, stalled, ...)
|
||||
* @current_trb: index of current used trb
|
||||
* @number: endpoint number (1 - 15)
|
||||
@@ -415,6 +420,7 @@ struct dwc3_ep {
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc;
|
||||
struct dwc3 *dwc;
|
||||
|
||||
u32 saved_state;
|
||||
unsigned flags;
|
||||
#define DWC3_EP_ENABLED (1 << 0)
|
||||
#define DWC3_EP_STALL (1 << 1)
|
||||
@@ -598,6 +604,7 @@ struct dwc3_scratchpad_array {
|
||||
* @ep0_trb: dma address of ep0_trb
|
||||
* @ep0_usb_req: dummy req used while handling STD USB requests
|
||||
* @ep0_bounce_addr: dma address of ep0_bounce
|
||||
* @scratch_addr: dma address of scratchbuf
|
||||
* @lock: for synchronizing
|
||||
* @dev: pointer to our struct device
|
||||
* @xhci: pointer to our xHCI child
|
||||
@@ -606,6 +613,7 @@ struct dwc3_scratchpad_array {
|
||||
* @gadget_driver: pointer to the gadget driver
|
||||
* @regs: base address for our registers
|
||||
* @regs_size: address space size
|
||||
* @nr_scratch: number of scratch buffers
|
||||
* @num_event_buffers: calculated number of event buffers
|
||||
* @u1u2: only used on revisions <1.83a for workaround
|
||||
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
||||
@@ -613,16 +621,10 @@ struct dwc3_scratchpad_array {
|
||||
* @dr_mode: requested mode of operation
|
||||
* @usb2_phy: pointer to USB2 PHY
|
||||
* @usb3_phy: pointer to USB3 PHY
|
||||
* @usb2_generic_phy: pointer to USB2 PHY
|
||||
* @usb3_generic_phy: pointer to USB3 PHY
|
||||
* @dcfg: saved contents of DCFG register
|
||||
* @gctl: saved contents of GCTL register
|
||||
* @is_selfpowered: true when we are selfpowered
|
||||
* @three_stage_setup: set if we perform a three phase setup
|
||||
* @ep0_bounced: true when we used bounce buffer
|
||||
* @ep0_expect_in: true when we expect a DATA IN transfer
|
||||
* @start_config_issued: true when StartConfig command has been issued
|
||||
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
|
||||
* @needs_fifo_resize: not all users might want fifo resizing, flag it
|
||||
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
|
||||
* @isoch_delay: wValue from Set Isochronous Delay request;
|
||||
* @u2sel: parameter from Set SEL request.
|
||||
* @u2pel: parameter from Set SEL request.
|
||||
@@ -637,15 +639,31 @@ struct dwc3_scratchpad_array {
|
||||
* @mem: points to start of memory which is used for this struct.
|
||||
* @hwparams: copy of hwparams registers
|
||||
* @root: debugfs root folder pointer
|
||||
* @regset: debugfs pointer to regdump file
|
||||
* @test_mode: true when we're entering a USB test mode
|
||||
* @test_mode_nr: test feature selector
|
||||
* @delayed_status: true when gadget driver asks for delayed status
|
||||
* @ep0_bounced: true when we used bounce buffer
|
||||
* @ep0_expect_in: true when we expect a DATA IN transfer
|
||||
* @has_hibernation: true when dwc3 was configured with Hibernation
|
||||
* @is_selfpowered: true when we are selfpowered
|
||||
* @needs_fifo_resize: not all users might want fifo resizing, flag it
|
||||
* @pullups_connected: true when Run/Stop bit is set
|
||||
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
|
||||
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
|
||||
* @start_config_issued: true when StartConfig command has been issued
|
||||
* @three_stage_setup: set if we perform a three phase setup
|
||||
*/
|
||||
struct dwc3 {
|
||||
struct usb_ctrlrequest *ctrl_req;
|
||||
struct dwc3_trb *ep0_trb;
|
||||
void *ep0_bounce;
|
||||
void *scratchbuf;
|
||||
u8 *setup_buf;
|
||||
dma_addr_t ctrl_req_addr;
|
||||
dma_addr_t ep0_trb_addr;
|
||||
dma_addr_t ep0_bounce_addr;
|
||||
dma_addr_t scratch_addr;
|
||||
struct dwc3_request ep0_usb_req;
|
||||
|
||||
/* device lock */
|
||||
@@ -665,6 +683,9 @@ struct dwc3 {
|
||||
struct usb_phy *usb2_phy;
|
||||
struct usb_phy *usb3_phy;
|
||||
|
||||
struct phy *usb2_generic_phy;
|
||||
struct phy *usb3_generic_phy;
|
||||
|
||||
void __iomem *regs;
|
||||
size_t regs_size;
|
||||
|
||||
@@ -674,6 +695,7 @@ struct dwc3 {
|
||||
u32 dcfg;
|
||||
u32 gctl;
|
||||
|
||||
u32 nr_scratch;
|
||||
u32 num_event_buffers;
|
||||
u32 u1u2;
|
||||
u32 maximum_speed;
|
||||
@@ -695,17 +717,9 @@ struct dwc3 {
|
||||
#define DWC3_REVISION_230A 0x5533230a
|
||||
#define DWC3_REVISION_240A 0x5533240a
|
||||
#define DWC3_REVISION_250A 0x5533250a
|
||||
|
||||
unsigned is_selfpowered:1;
|
||||
unsigned three_stage_setup:1;
|
||||
unsigned ep0_bounced:1;
|
||||
unsigned ep0_expect_in:1;
|
||||
unsigned start_config_issued:1;
|
||||
unsigned setup_packet_pending:1;
|
||||
unsigned delayed_status:1;
|
||||
unsigned needs_fifo_resize:1;
|
||||
unsigned resize_fifos:1;
|
||||
unsigned pullups_connected:1;
|
||||
#define DWC3_REVISION_260A 0x5533260a
|
||||
#define DWC3_REVISION_270A 0x5533270a
|
||||
#define DWC3_REVISION_280A 0x5533280a
|
||||
|
||||
enum dwc3_ep0_next ep0_next_event;
|
||||
enum dwc3_ep0_state ep0state;
|
||||
@@ -730,6 +744,18 @@ struct dwc3 {
|
||||
|
||||
u8 test_mode;
|
||||
u8 test_mode_nr;
|
||||
|
||||
unsigned delayed_status:1;
|
||||
unsigned ep0_bounced:1;
|
||||
unsigned ep0_expect_in:1;
|
||||
unsigned has_hibernation:1;
|
||||
unsigned is_selfpowered:1;
|
||||
unsigned needs_fifo_resize:1;
|
||||
unsigned pullups_connected:1;
|
||||
unsigned resize_fifos:1;
|
||||
unsigned setup_packet_pending:1;
|
||||
unsigned start_config_issued:1;
|
||||
unsigned three_stage_setup:1;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@@ -815,15 +841,15 @@ struct dwc3_event_depevt {
|
||||
* 12 - VndrDevTstRcved
|
||||
* @reserved15_12: Reserved, not used
|
||||
* @event_info: Information about this event
|
||||
* @reserved31_24: Reserved, not used
|
||||
* @reserved31_25: Reserved, not used
|
||||
*/
|
||||
struct dwc3_event_devt {
|
||||
u32 one_bit:1;
|
||||
u32 device_event:7;
|
||||
u32 type:4;
|
||||
u32 reserved15_12:4;
|
||||
u32 event_info:8;
|
||||
u32 reserved31_24:8;
|
||||
u32 event_info:9;
|
||||
u32 reserved31_25:7;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
@@ -856,6 +882,19 @@ union dwc3_event {
|
||||
struct dwc3_event_gevt gevt;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dwc3_gadget_ep_cmd_params - representation of endpoint command
|
||||
* parameters
|
||||
* @param2: third parameter
|
||||
* @param1: second parameter
|
||||
* @param0: first parameter
|
||||
*/
|
||||
struct dwc3_gadget_ep_cmd_params {
|
||||
u32 param2;
|
||||
u32 param1;
|
||||
u32 param0;
|
||||
};
|
||||
|
||||
/*
|
||||
* DWC3 Features to be used as Driver Data
|
||||
*/
|
||||
@@ -881,11 +920,31 @@ static inline void dwc3_host_exit(struct dwc3 *dwc)
|
||||
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||
int dwc3_gadget_init(struct dwc3 *dwc);
|
||||
void dwc3_gadget_exit(struct dwc3 *dwc);
|
||||
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
|
||||
int dwc3_gadget_get_link_state(struct dwc3 *dwc);
|
||||
int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
|
||||
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
|
||||
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
|
||||
#else
|
||||
static inline int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
{ return 0; }
|
||||
static inline void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
{ }
|
||||
static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
|
||||
{ return 0; }
|
||||
static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc)
|
||||
{ return 0; }
|
||||
static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc,
|
||||
enum dwc3_link_state state)
|
||||
{ return 0; }
|
||||
|
||||
static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
|
||||
{ return 0; }
|
||||
static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
|
||||
int cmd, u32 param)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
/* power management interface */
|
||||
|
||||
@@ -424,11 +424,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "missing memory base resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
+152
-31
@@ -67,6 +67,22 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_gadget_get_link_state - Gets current state of USB Link
|
||||
* @dwc: pointer to our context structure
|
||||
*
|
||||
* Caller should take care of locking. This function will
|
||||
* return the link state on success (>= 0) or -ETIMEDOUT.
|
||||
*/
|
||||
int dwc3_gadget_get_link_state(struct dwc3 *dwc)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
|
||||
|
||||
return DWC3_DSTS_USBLNKST(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_gadget_set_link_state - Sets USB Link to a particular State
|
||||
* @dwc: pointer to our context structure
|
||||
@@ -417,7 +433,7 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
const struct usb_endpoint_descriptor *desc,
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc,
|
||||
bool ignore)
|
||||
bool ignore, bool restore)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
|
||||
@@ -436,6 +452,11 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
if (ignore)
|
||||
params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM;
|
||||
|
||||
if (restore) {
|
||||
params.param0 |= DWC3_DEPCFG_ACTION_RESTORE;
|
||||
params.param2 |= dep->saved_state;
|
||||
}
|
||||
|
||||
params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
|
||||
| DWC3_DEPCFG_XFER_NOT_READY_EN;
|
||||
|
||||
@@ -494,7 +515,7 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||
const struct usb_endpoint_descriptor *desc,
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc,
|
||||
bool ignore)
|
||||
bool ignore, bool restore)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
u32 reg;
|
||||
@@ -508,7 +529,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore);
|
||||
ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore,
|
||||
restore);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -548,13 +570,13 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
|
||||
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
|
||||
static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_request *req;
|
||||
|
||||
if (!list_empty(&dep->req_queued)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
|
||||
/* - giveback all requests to gadget driver */
|
||||
while (!list_empty(&dep->req_queued)) {
|
||||
@@ -659,7 +681,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false);
|
||||
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
@@ -771,9 +793,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
else
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
|
||||
|
||||
if (!req->request.no_interrupt && !chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
@@ -788,6 +807,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (!req->request.no_interrupt && !chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CSP;
|
||||
@@ -1077,7 +1099,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
if (list_empty(&dep->req_queued)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
}
|
||||
return 0;
|
||||
@@ -1107,6 +1129,23 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. Stream Capable Bulk Endpoints. We need to start the transfer
|
||||
* right away, otherwise host will not know we have streams to be
|
||||
* handled.
|
||||
*/
|
||||
if (dep->stream_capable) {
|
||||
int ret;
|
||||
|
||||
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
|
||||
if (ret && ret != -EBUSY) {
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
|
||||
dep->name);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1163,7 +1202,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
}
|
||||
if (r == req) {
|
||||
/* wait until it is processed */
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
goto out1;
|
||||
}
|
||||
dev_err(dwc->dev, "request %p was not queued to %s\n",
|
||||
@@ -1194,8 +1233,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
||||
DWC3_DEPCMD_SETSTALL, ¶ms);
|
||||
if (ret)
|
||||
dev_err(dwc->dev, "failed to %s STALL on %s\n",
|
||||
value ? "set" : "clear",
|
||||
dev_err(dwc->dev, "failed to set STALL on %s\n",
|
||||
dep->name);
|
||||
else
|
||||
dep->flags |= DWC3_EP_STALL;
|
||||
@@ -1203,8 +1241,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
||||
DWC3_DEPCMD_CLEARSTALL, ¶ms);
|
||||
if (ret)
|
||||
dev_err(dwc->dev, "failed to %s STALL on %s\n",
|
||||
value ? "set" : "clear",
|
||||
dev_err(dwc->dev, "failed to clear STALL on %s\n",
|
||||
dep->name);
|
||||
else
|
||||
dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);
|
||||
@@ -1387,7 +1424,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
|
||||
{
|
||||
u32 reg;
|
||||
u32 timeout = 500;
|
||||
@@ -1402,9 +1439,17 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
|
||||
if (dwc->revision >= DWC3_REVISION_194A)
|
||||
reg &= ~DWC3_DCTL_KEEP_CONNECT;
|
||||
reg |= DWC3_DCTL_RUN_STOP;
|
||||
|
||||
if (dwc->has_hibernation)
|
||||
reg |= DWC3_DCTL_KEEP_CONNECT;
|
||||
|
||||
dwc->pullups_connected = true;
|
||||
} else {
|
||||
reg &= ~DWC3_DCTL_RUN_STOP;
|
||||
|
||||
if (dwc->has_hibernation && !suspend)
|
||||
reg &= ~DWC3_DCTL_KEEP_CONNECT;
|
||||
|
||||
dwc->pullups_connected = false;
|
||||
}
|
||||
|
||||
@@ -1442,7 +1487,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
|
||||
is_on = !!is_on;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = dwc3_gadget_run_stop(dwc, is_on);
|
||||
ret = dwc3_gadget_run_stop(dwc, is_on, false);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
@@ -1549,14 +1594,16 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
|
||||
false);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
dep = dwc->eps[1];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
|
||||
false);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
goto err3;
|
||||
@@ -1849,15 +1896,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
*/
|
||||
dep->flags = DWC3_EP_PENDING_REQUEST;
|
||||
} else {
|
||||
dwc3_stop_active_transfer(dwc, dep->number);
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((event->status & DEPEVT_STATUS_IOC) &&
|
||||
(trb->ctrl & DWC3_TRB_CTRL_IOC))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1999,7 +2043,25 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
|
||||
static void dwc3_suspend_gadget(struct dwc3 *dwc)
|
||||
{
|
||||
if (dwc->gadget_driver && dwc->gadget_driver->suspend) {
|
||||
spin_unlock(&dwc->lock);
|
||||
dwc->gadget_driver->suspend(&dwc->gadget);
|
||||
spin_lock(&dwc->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_resume_gadget(struct dwc3 *dwc)
|
||||
{
|
||||
if (dwc->gadget_driver && dwc->gadget_driver->resume) {
|
||||
spin_unlock(&dwc->lock);
|
||||
dwc->gadget_driver->resume(&dwc->gadget);
|
||||
spin_lock(&dwc->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
|
||||
{
|
||||
struct dwc3_ep *dep;
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
@@ -2031,7 +2093,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
|
||||
*/
|
||||
|
||||
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
||||
cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
|
||||
cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0;
|
||||
cmd |= DWC3_DEPCMD_CMDIOC;
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
|
||||
@@ -2259,18 +2322,24 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
|
||||
*/
|
||||
reg |= DWC3_DCTL_HIRD_THRES(12);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
} else {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg &= ~DWC3_DCTL_HIRD_THRES_MASK;
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
}
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true,
|
||||
false);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
return;
|
||||
}
|
||||
|
||||
dep = dwc->eps[1];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true,
|
||||
false);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to enable %s\n", dep->name);
|
||||
return;
|
||||
@@ -2378,9 +2447,50 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
|
||||
|
||||
dwc->link_state = next;
|
||||
|
||||
switch (next) {
|
||||
case DWC3_LINK_STATE_U1:
|
||||
if (dwc->speed == USB_SPEED_SUPER)
|
||||
dwc3_suspend_gadget(dwc);
|
||||
break;
|
||||
case DWC3_LINK_STATE_U2:
|
||||
case DWC3_LINK_STATE_U3:
|
||||
dwc3_suspend_gadget(dwc);
|
||||
break;
|
||||
case DWC3_LINK_STATE_RESUME:
|
||||
dwc3_resume_gadget(dwc);
|
||||
break;
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
|
||||
}
|
||||
|
||||
static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
|
||||
unsigned int evtinfo)
|
||||
{
|
||||
unsigned int is_ss = evtinfo & BIT(4);
|
||||
|
||||
/**
|
||||
* WORKAROUND: DWC3 revison 2.20a with hibernation support
|
||||
* have a known issue which can cause USB CV TD.9.23 to fail
|
||||
* randomly.
|
||||
*
|
||||
* Because of this issue, core could generate bogus hibernation
|
||||
* events which SW needs to ignore.
|
||||
*
|
||||
* Refers to:
|
||||
*
|
||||
* STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0
|
||||
* Device Fallback from SuperSpeed
|
||||
*/
|
||||
if (is_ss ^ (dwc->speed == USB_SPEED_SUPER))
|
||||
return;
|
||||
|
||||
/* enter hibernation here */
|
||||
}
|
||||
|
||||
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
|
||||
const struct dwc3_event_devt *event)
|
||||
{
|
||||
@@ -2397,6 +2507,13 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
|
||||
case DWC3_DEVICE_EVENT_WAKEUP:
|
||||
dwc3_gadget_wakeup_interrupt(dwc);
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_HIBER_REQ:
|
||||
if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
|
||||
"unexpected hibernation event\n"))
|
||||
break;
|
||||
|
||||
dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
|
||||
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
|
||||
break;
|
||||
@@ -2661,8 +2778,10 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||
|
||||
int dwc3_gadget_prepare(struct dwc3 *dwc)
|
||||
{
|
||||
if (dwc->pullups_connected)
|
||||
if (dwc->pullups_connected) {
|
||||
dwc3_gadget_disable_irq(dwc);
|
||||
dwc3_gadget_run_stop(dwc, true, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2671,7 +2790,7 @@ void dwc3_gadget_complete(struct dwc3 *dwc)
|
||||
{
|
||||
if (dwc->pullups_connected) {
|
||||
dwc3_gadget_enable_irq(dwc);
|
||||
dwc3_gadget_run_stop(dwc, true);
|
||||
dwc3_gadget_run_stop(dwc, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2694,12 +2813,14 @@ int dwc3_gadget_resume(struct dwc3 *dwc)
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
|
||||
dep = dwc->eps[0];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
|
||||
false);
|
||||
if (ret)
|
||||
goto err0;
|
||||
|
||||
dep = dwc->eps[1];
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
|
||||
ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
|
||||
false);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
|
||||
@@ -56,12 +56,6 @@ struct dwc3;
|
||||
/* DEPXFERCFG parameter 0 */
|
||||
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
|
||||
|
||||
struct dwc3_gadget_ep_cmd_params {
|
||||
u32 param2;
|
||||
u32 param1;
|
||||
u32 param0;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
|
||||
@@ -85,9 +79,6 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
|
||||
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
int status);
|
||||
|
||||
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
|
||||
int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
|
||||
|
||||
void dwc3_ep0_interrupt(struct dwc3 *dwc,
|
||||
const struct dwc3_event_depevt *event);
|
||||
void dwc3_ep0_out_start(struct dwc3 *dwc);
|
||||
@@ -95,9 +86,6 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
|
||||
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
gfp_t gfp_flags);
|
||||
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
|
||||
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
|
||||
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
|
||||
|
||||
/**
|
||||
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
|
||||
|
||||
@@ -301,7 +301,6 @@ config USB_PXA27X
|
||||
gadget drivers to also be dynamically linked.
|
||||
|
||||
config USB_S3C_HSOTG
|
||||
depends on ARM
|
||||
tristate "Designware/S3C HS/OtG USB Device controller"
|
||||
help
|
||||
The Designware USB2.0 high-speed gadget controller
|
||||
|
||||
@@ -1758,15 +1758,15 @@ static int at91udc_probe(struct platform_device *pdev)
|
||||
|
||||
/* newer chips have more FIFO memory than rm9200 */
|
||||
if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[4].ep, 512);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[5].ep, 512);
|
||||
udc->ep[0].maxpacket = 64;
|
||||
udc->ep[3].maxpacket = 64;
|
||||
udc->ep[4].maxpacket = 512;
|
||||
udc->ep[5].maxpacket = 512;
|
||||
} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
|
||||
udc->ep[3].maxpacket = 64;
|
||||
} else if (cpu_is_at91sam9263()) {
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[0].ep, 64);
|
||||
usb_ep_set_maxpacket_limit(&udc->ep[3].ep, 64);
|
||||
udc->ep[0].maxpacket = 64;
|
||||
udc->ep[3].maxpacket = 64;
|
||||
}
|
||||
|
||||
udc->udp_baseaddr = ioremap(res->start, resource_size(res));
|
||||
|
||||
@@ -1661,7 +1661,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
|
||||
if (dma_status) {
|
||||
int i;
|
||||
|
||||
for (i = 1; i < USBA_NR_ENDPOINTS; i++)
|
||||
for (i = 1; i < USBA_NR_DMAS; i++)
|
||||
if (dma_status & (1 << i))
|
||||
usba_dma_irq(udc, &udc->usba_ep[i]);
|
||||
}
|
||||
@@ -1670,7 +1670,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
|
||||
if (ep_status) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < USBA_NR_ENDPOINTS; i++)
|
||||
for (i = 0; i < udc->num_ep; i++)
|
||||
if (ep_status & (1 << i)) {
|
||||
if (ep_is_control(&udc->usba_ep[i]))
|
||||
usba_control_irq(udc, &udc->usba_ep[i]);
|
||||
@@ -1827,12 +1827,12 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
|
||||
toggle_bias(0);
|
||||
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
|
||||
|
||||
udc->driver = NULL;
|
||||
|
||||
clk_disable_unprepare(udc->hclk);
|
||||
clk_disable_unprepare(udc->pclk);
|
||||
|
||||
DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
|
||||
DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name);
|
||||
|
||||
udc->driver = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1914,6 +1914,12 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
dev_err(&pdev->dev, "of_probe: no endpoint specified\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
return eps;
|
||||
err:
|
||||
return ERR_PTR(ret);
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
#define USBA_FIFO_BASE(x) ((x) << 16)
|
||||
|
||||
/* Synth parameters */
|
||||
#define USBA_NR_ENDPOINTS 7
|
||||
#define USBA_NR_DMAS 7
|
||||
|
||||
#define EP0_FIFO_SIZE 64
|
||||
#define EP0_EPT_SIZE USBA_EPT_SIZE_64
|
||||
|
||||
+478
-138
File diff suppressed because it is too large
Load Diff
@@ -225,14 +225,8 @@ static void gr_dfs_create(struct gr_udc *dev)
|
||||
const char *name = "gr_udc_state";
|
||||
|
||||
dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), NULL);
|
||||
if (IS_ERR(dev->dfs_root)) {
|
||||
dev_err(dev->dev, "Failed to create debugfs directory\n");
|
||||
return;
|
||||
}
|
||||
dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root,
|
||||
dev, &gr_dfs_fops);
|
||||
if (IS_ERR(dev->dfs_state))
|
||||
dev_err(dev->dev, "Failed to create debugfs file %s\n", name);
|
||||
dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root, dev,
|
||||
&gr_dfs_fops);
|
||||
}
|
||||
|
||||
static void gr_dfs_delete(struct gr_udc *dev)
|
||||
|
||||
@@ -427,12 +427,17 @@ setup_rx_reqs(struct printer_dev *dev)
|
||||
req->length = USB_BUFSIZE;
|
||||
req->complete = rx_complete;
|
||||
|
||||
/* here, we unlock, and only unlock, to avoid deadlock. */
|
||||
spin_unlock(&dev->lock);
|
||||
error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
|
||||
spin_lock(&dev->lock);
|
||||
if (error) {
|
||||
DBG(dev, "rx submit --> %d\n", error);
|
||||
list_add(&req->list, &dev->rx_reqs);
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
/* if the req is empty, then add it into dev->rx_reqs_active. */
|
||||
else if (list_empty(&req->list)) {
|
||||
list_add(&req->list, &dev->rx_reqs_active);
|
||||
}
|
||||
}
|
||||
@@ -1133,6 +1138,7 @@ static int __init printer_bind_config(struct usb_configuration *c)
|
||||
NULL, "g_printer");
|
||||
if (IS_ERR(dev->pdev)) {
|
||||
ERROR(dev, "Failed to create device: g_printer\n");
|
||||
status = PTR_ERR(dev->pdev);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
+101
-42
@@ -617,7 +617,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
|
||||
to_write = DIV_ROUND_UP(to_write, 4);
|
||||
data = hs_req->req.buf + buf_pos;
|
||||
|
||||
writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
|
||||
iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
|
||||
|
||||
return (to_write >= can_write) ? -ENOSPC : 0;
|
||||
}
|
||||
@@ -720,8 +720,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
|
||||
ureq->length, ureq->actual);
|
||||
if (0)
|
||||
dev_dbg(hsotg->dev,
|
||||
"REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n",
|
||||
ureq->buf, length, ureq->dma,
|
||||
"REQ buf %p len %d dma 0x%pad noi=%d zp=%d snok=%d\n",
|
||||
ureq->buf, length, &ureq->dma,
|
||||
ureq->no_interrupt, ureq->zero, ureq->short_not_ok);
|
||||
|
||||
maxreq = get_ep_limit(hs_ep);
|
||||
@@ -789,8 +789,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
|
||||
dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
|
||||
writel(ureq->dma, hsotg->regs + dma_reg);
|
||||
|
||||
dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n",
|
||||
__func__, ureq->dma, dma_reg);
|
||||
dev_dbg(hsotg->dev, "%s: 0x%pad => 0x%08x\n",
|
||||
__func__, &ureq->dma, dma_reg);
|
||||
}
|
||||
|
||||
ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */
|
||||
@@ -1185,6 +1185,41 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
|
||||
static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
|
||||
static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg);
|
||||
|
||||
/**
|
||||
* s3c_hsotg_stall_ep0 - stall ep0
|
||||
* @hsotg: The device state
|
||||
*
|
||||
* Set stall for ep0 as response for setup request.
|
||||
*/
|
||||
static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) {
|
||||
struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
|
||||
u32 reg;
|
||||
u32 ctrl;
|
||||
|
||||
dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
|
||||
reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
|
||||
|
||||
/*
|
||||
* DxEPCTL_Stall will be cleared by EP once it has
|
||||
* taken effect, so no need to clear later.
|
||||
*/
|
||||
|
||||
ctrl = readl(hsotg->regs + reg);
|
||||
ctrl |= DxEPCTL_Stall;
|
||||
ctrl |= DxEPCTL_CNAK;
|
||||
writel(ctrl, hsotg->regs + reg);
|
||||
|
||||
dev_dbg(hsotg->dev,
|
||||
"written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
|
||||
ctrl, reg, readl(hsotg->regs + reg));
|
||||
|
||||
/*
|
||||
* complete won't be called, so we enqueue
|
||||
* setup request here
|
||||
*/
|
||||
s3c_hsotg_enqueue_setup(hsotg);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c_hsotg_process_control - process a control request
|
||||
* @hsotg: The device state
|
||||
@@ -1262,38 +1297,8 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
|
||||
* so respond with a STALL for the status stage to indicate failure.
|
||||
*/
|
||||
|
||||
if (ret < 0) {
|
||||
u32 reg;
|
||||
u32 ctrl;
|
||||
|
||||
dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
|
||||
reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
|
||||
|
||||
/*
|
||||
* DxEPCTL_Stall will be cleared by EP once it has
|
||||
* taken effect, so no need to clear later.
|
||||
*/
|
||||
|
||||
ctrl = readl(hsotg->regs + reg);
|
||||
ctrl |= DxEPCTL_Stall;
|
||||
ctrl |= DxEPCTL_CNAK;
|
||||
writel(ctrl, hsotg->regs + reg);
|
||||
|
||||
dev_dbg(hsotg->dev,
|
||||
"written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
|
||||
ctrl, reg, readl(hsotg->regs + reg));
|
||||
|
||||
/*
|
||||
* don't believe we need to anything more to get the EP
|
||||
* to reply with a STALL packet
|
||||
*/
|
||||
|
||||
/*
|
||||
* complete won't be called, so we enqueue
|
||||
* setup request here
|
||||
*/
|
||||
s3c_hsotg_enqueue_setup(hsotg);
|
||||
}
|
||||
if (ret < 0)
|
||||
s3c_hsotg_stall_ep0(hsotg);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1488,7 +1493,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
|
||||
* note, we might over-write the buffer end by 3 bytes depending on
|
||||
* alignment of the data.
|
||||
*/
|
||||
readsl(fifo, hs_req->req.buf + read_ptr, to_read);
|
||||
ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2832,6 +2837,15 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
||||
|
||||
dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
|
||||
|
||||
if (index == 0) {
|
||||
if (value)
|
||||
s3c_hsotg_stall_ep0(hs);
|
||||
else
|
||||
dev_warn(hs->dev,
|
||||
"%s: can't clear halt on ep0\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write both IN and OUT control registers */
|
||||
|
||||
epreg = DIEPCTL(index);
|
||||
@@ -3760,10 +3774,55 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 1
|
||||
#define s3c_hsotg_suspend NULL
|
||||
#define s3c_hsotg_resume NULL
|
||||
#endif
|
||||
static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (hsotg->driver)
|
||||
dev_info(hsotg->dev, "suspending usb gadget %s\n",
|
||||
hsotg->driver->driver.name);
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
s3c_hsotg_disconnect(hsotg);
|
||||
s3c_hsotg_phy_disable(hsotg);
|
||||
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
if (hsotg->driver) {
|
||||
int ep;
|
||||
for (ep = 0; ep < hsotg->num_of_eps; ep++)
|
||||
s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
|
||||
|
||||
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
|
||||
hsotg->supplies);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s3c_hsotg_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (hsotg->driver) {
|
||||
dev_info(hsotg->dev, "resuming usb gadget %s\n",
|
||||
hsotg->driver->driver.name);
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
|
||||
hsotg->supplies);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hsotg->lock, flags);
|
||||
hsotg->last_rst = jiffies;
|
||||
s3c_hsotg_phy_enable(hsotg);
|
||||
s3c_hsotg_core_init(hsotg);
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id s3c_hsotg_of_ids[] = {
|
||||
|
||||
@@ -1344,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
err_add_udc:
|
||||
err_add_device:
|
||||
clk_disable(hsudc->uclk);
|
||||
err_res:
|
||||
if (!IS_ERR_OR_NULL(hsudc->transceiver))
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
|
||||
#define UETH__VERSION "29-May-2008"
|
||||
|
||||
#define GETHER_NAPI_WEIGHT 32
|
||||
|
||||
struct eth_dev {
|
||||
/* lock is held while accessing port_usb
|
||||
*/
|
||||
@@ -72,6 +74,7 @@ struct eth_dev {
|
||||
struct sk_buff_head *list);
|
||||
|
||||
struct work_struct work;
|
||||
struct napi_struct rx_napi;
|
||||
|
||||
unsigned long todo;
|
||||
#define WORK_RX_MEMORY 0
|
||||
@@ -253,18 +256,16 @@ enomem:
|
||||
DBG(dev, "rx submit --> %d\n", retval);
|
||||
if (skb)
|
||||
dev_kfree_skb_any(skb);
|
||||
spin_lock_irqsave(&dev->req_lock, flags);
|
||||
list_add(&req->list, &dev->rx_reqs);
|
||||
spin_unlock_irqrestore(&dev->req_lock, flags);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void rx_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
struct sk_buff *skb = req->context, *skb2;
|
||||
struct sk_buff *skb = req->context;
|
||||
struct eth_dev *dev = ep->driver_data;
|
||||
int status = req->status;
|
||||
bool rx_queue = 0;
|
||||
|
||||
switch (status) {
|
||||
|
||||
@@ -288,30 +289,8 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
} else {
|
||||
skb_queue_tail(&dev->rx_frames, skb);
|
||||
}
|
||||
skb = NULL;
|
||||
|
||||
skb2 = skb_dequeue(&dev->rx_frames);
|
||||
while (skb2) {
|
||||
if (status < 0
|
||||
|| ETH_HLEN > skb2->len
|
||||
|| skb2->len > VLAN_ETH_FRAME_LEN) {
|
||||
dev->net->stats.rx_errors++;
|
||||
dev->net->stats.rx_length_errors++;
|
||||
DBG(dev, "rx length %d\n", skb2->len);
|
||||
dev_kfree_skb_any(skb2);
|
||||
goto next_frame;
|
||||
}
|
||||
skb2->protocol = eth_type_trans(skb2, dev->net);
|
||||
dev->net->stats.rx_packets++;
|
||||
dev->net->stats.rx_bytes += skb2->len;
|
||||
|
||||
/* no buffer copies needed, unless hardware can't
|
||||
* use skb buffers.
|
||||
*/
|
||||
status = netif_rx(skb2);
|
||||
next_frame:
|
||||
skb2 = skb_dequeue(&dev->rx_frames);
|
||||
}
|
||||
if (!status)
|
||||
rx_queue = 1;
|
||||
break;
|
||||
|
||||
/* software-driven interface shutdown */
|
||||
@@ -334,22 +313,20 @@ quiesce:
|
||||
/* FALLTHROUGH */
|
||||
|
||||
default:
|
||||
rx_queue = 1;
|
||||
dev_kfree_skb_any(skb);
|
||||
dev->net->stats.rx_errors++;
|
||||
DBG(dev, "rx status %d\n", status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (skb)
|
||||
dev_kfree_skb_any(skb);
|
||||
if (!netif_running(dev->net)) {
|
||||
clean:
|
||||
spin_lock(&dev->req_lock);
|
||||
list_add(&req->list, &dev->rx_reqs);
|
||||
spin_unlock(&dev->req_lock);
|
||||
req = NULL;
|
||||
}
|
||||
if (req)
|
||||
rx_submit(dev, req, GFP_ATOMIC);
|
||||
|
||||
if (rx_queue && likely(napi_schedule_prep(&dev->rx_napi)))
|
||||
__napi_schedule(&dev->rx_napi);
|
||||
}
|
||||
|
||||
static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
|
||||
@@ -414,16 +391,24 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
|
||||
{
|
||||
struct usb_request *req;
|
||||
unsigned long flags;
|
||||
int rx_counts = 0;
|
||||
|
||||
/* fill unused rxq slots with some skb */
|
||||
spin_lock_irqsave(&dev->req_lock, flags);
|
||||
while (!list_empty(&dev->rx_reqs)) {
|
||||
|
||||
if (++rx_counts > qlen(dev->gadget, dev->qmult))
|
||||
break;
|
||||
|
||||
req = container_of(dev->rx_reqs.next,
|
||||
struct usb_request, list);
|
||||
list_del_init(&req->list);
|
||||
spin_unlock_irqrestore(&dev->req_lock, flags);
|
||||
|
||||
if (rx_submit(dev, req, gfp_flags) < 0) {
|
||||
spin_lock_irqsave(&dev->req_lock, flags);
|
||||
list_add(&req->list, &dev->rx_reqs);
|
||||
spin_unlock_irqrestore(&dev->req_lock, flags);
|
||||
defer_kevent(dev, WORK_RX_MEMORY);
|
||||
return;
|
||||
}
|
||||
@@ -433,6 +418,41 @@ static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
|
||||
spin_unlock_irqrestore(&dev->req_lock, flags);
|
||||
}
|
||||
|
||||
static int gether_poll(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct eth_dev *dev = container_of(napi, struct eth_dev, rx_napi);
|
||||
struct sk_buff *skb;
|
||||
unsigned int work_done = 0;
|
||||
int status = 0;
|
||||
|
||||
while ((skb = skb_dequeue(&dev->rx_frames))) {
|
||||
if (status < 0
|
||||
|| ETH_HLEN > skb->len
|
||||
|| skb->len > VLAN_ETH_FRAME_LEN) {
|
||||
dev->net->stats.rx_errors++;
|
||||
dev->net->stats.rx_length_errors++;
|
||||
DBG(dev, "rx length %d\n", skb->len);
|
||||
dev_kfree_skb_any(skb);
|
||||
continue;
|
||||
}
|
||||
skb->protocol = eth_type_trans(skb, dev->net);
|
||||
dev->net->stats.rx_packets++;
|
||||
dev->net->stats.rx_bytes += skb->len;
|
||||
|
||||
status = netif_rx_ni(skb);
|
||||
}
|
||||
|
||||
if (netif_running(dev->net)) {
|
||||
rx_fill(dev, GFP_KERNEL);
|
||||
work_done++;
|
||||
}
|
||||
|
||||
if (work_done < budget)
|
||||
napi_complete(&dev->rx_napi);
|
||||
|
||||
return work_done;
|
||||
}
|
||||
|
||||
static void eth_work(struct work_struct *work)
|
||||
{
|
||||
struct eth_dev *dev = container_of(work, struct eth_dev, work);
|
||||
@@ -625,6 +645,7 @@ static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
|
||||
/* and open the tx floodgates */
|
||||
atomic_set(&dev->tx_qlen, 0);
|
||||
netif_wake_queue(dev->net);
|
||||
napi_enable(&dev->rx_napi);
|
||||
}
|
||||
|
||||
static int eth_open(struct net_device *net)
|
||||
@@ -651,6 +672,7 @@ static int eth_stop(struct net_device *net)
|
||||
unsigned long flags;
|
||||
|
||||
VDBG(dev, "%s\n", __func__);
|
||||
napi_disable(&dev->rx_napi);
|
||||
netif_stop_queue(net);
|
||||
|
||||
DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
|
||||
@@ -768,6 +790,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dev = netdev_priv(net);
|
||||
netif_napi_add(net, &dev->rx_napi, gether_poll, GETHER_NAPI_WEIGHT);
|
||||
spin_lock_init(&dev->lock);
|
||||
spin_lock_init(&dev->req_lock);
|
||||
INIT_WORK(&dev->work, eth_work);
|
||||
@@ -830,6 +853,7 @@ struct net_device *gether_setup_name_default(const char *netname)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dev = netdev_priv(net);
|
||||
netif_napi_add(net, &dev->rx_napi, gether_poll, GETHER_NAPI_WEIGHT);
|
||||
spin_lock_init(&dev->lock);
|
||||
spin_lock_init(&dev->req_lock);
|
||||
INIT_WORK(&dev->work, eth_work);
|
||||
@@ -1113,6 +1137,7 @@ void gether_disconnect(struct gether *link)
|
||||
{
|
||||
struct eth_dev *dev = link->ioport;
|
||||
struct usb_request *req;
|
||||
struct sk_buff *skb;
|
||||
|
||||
WARN_ON(!dev);
|
||||
if (!dev)
|
||||
@@ -1139,6 +1164,12 @@ void gether_disconnect(struct gether *link)
|
||||
spin_lock(&dev->req_lock);
|
||||
}
|
||||
spin_unlock(&dev->req_lock);
|
||||
|
||||
spin_lock(&dev->rx_frames.lock);
|
||||
while ((skb = __skb_dequeue(&dev->rx_frames)))
|
||||
dev_kfree_skb_any(skb);
|
||||
spin_unlock(&dev->rx_frames.lock);
|
||||
|
||||
link->in_ep->driver_data = NULL;
|
||||
link->in_ep->desc = NULL;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user