Commit e6a3b5e2 authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Felipe Balbi

usb: dwc3: ep0: add LPM handling

On device loading the driver enables LPM and the acceptance of U1 and U2
states. The [Set|Clear]Feature requests for "U1/U2" are forwarded
directly to the hardware and allow / forbid the initiation of the low
power links.
Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 51249dca
...@@ -194,6 +194,7 @@ ...@@ -194,6 +194,7 @@
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
/* Device Configuration Register */ /* Device Configuration Register */
#define DWC3_DCFG_LPM_CAP (1 << 22)
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
......
...@@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, ...@@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
{ {
struct dwc3_ep *dep; struct dwc3_ep *dep;
u32 recip; u32 recip;
u32 reg;
u16 usb_status = 0; u16 usb_status = 0;
__le16 *response_pkt; __le16 *response_pkt;
...@@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, ...@@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
switch (recip) { switch (recip) {
case USB_RECIP_DEVICE: case USB_RECIP_DEVICE:
/* /*
* We are self-powered. U1/U2/LTM will be set later * LTM will be set once we know how to set this in HW.
* once we handle this states. RemoteWakeup is 0 on SS
*/ */
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (reg & DWC3_DCTL_INITU1ENA)
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
if (reg & DWC3_DCTL_INITU2ENA)
usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
}
break; break;
case USB_RECIP_INTERFACE: case USB_RECIP_INTERFACE:
...@@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, ...@@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 recip; u32 recip;
u32 wValue; u32 wValue;
u32 wIndex; u32 wIndex;
u32 reg;
int ret; int ret;
wValue = le16_to_cpu(ctrl->wValue); wValue = le16_to_cpu(ctrl->wValue);
...@@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, ...@@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
switch (recip) { switch (recip) {
case USB_RECIP_DEVICE: case USB_RECIP_DEVICE:
switch (wValue) {
case USB_DEVICE_REMOTE_WAKEUP:
break;
/* /*
* 9.4.1 says only only for SS, in AddressState only for * 9.4.1 says only only for SS, in AddressState only for
* default control pipe * default control pipe
*/ */
switch (wValue) {
case USB_DEVICE_U1_ENABLE: case USB_DEVICE_U1_ENABLE:
case USB_DEVICE_U2_ENABLE:
case USB_DEVICE_LTM_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE) if (dwc->dev_state != DWC3_CONFIGURED_STATE)
return -EINVAL; return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED) if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL; return -EINVAL;
}
/* XXX add U[12] & LTM */ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
switch (wValue) { if (set)
case USB_DEVICE_REMOTE_WAKEUP: reg |= DWC3_DCTL_INITU1ENA;
break; else
case USB_DEVICE_U1_ENABLE: reg &= ~DWC3_DCTL_INITU1ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break; break;
case USB_DEVICE_U2_ENABLE: case USB_DEVICE_U2_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU2ENA;
else
reg &= ~DWC3_DCTL_INITU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break; break;
case USB_DEVICE_LTM_ENABLE: case USB_DEVICE_LTM_ENABLE:
return -EINVAL;
break; break;
case USB_DEVICE_TEST_MODE: case USB_DEVICE_TEST_MODE:
......
...@@ -1933,6 +1933,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) ...@@ -1933,6 +1933,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK; reg &= ~DWC3_DCTL_TSTCTRL_MASK;
reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->test_mode = false; dwc->test_mode = false;
...@@ -2330,6 +2331,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) ...@@ -2330,6 +2331,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err5; goto err5;
} }
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/* Enable all but Start and End of Frame IRQs */ /* Enable all but Start and End of Frame IRQs */
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
DWC3_DEVTEN_EVNTOVERFLOWEN | DWC3_DEVTEN_EVNTOVERFLOWEN |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment