Commit 9d6173e1 authored by Thinh Nguyen's avatar Thinh Nguyen Committed by Felipe Balbi

usb: dwc3: Fix dr_mode validation

This patch follows the similar fix in dwc2. See
commit 5268ed9d ("usb: dwc2: Fix dr_mode validation")

Currently, the dr_mode is only checked against the module configuration.
It also needs to be checked against the hardware capablities.

The driver now checks if both the module configuration and hardware are
capable of the dr_mode value. If not, then it will issue a warning and
fall back to a supported value. If it is unable to fall back to a
suitable value, then the probe will fail.

Behavior summary:

      module          :  actual
 HW   config  dr_mode :  dr_mode
---------------------------------
 host  host   any     :  host
 host  dev    any     :  INVALID
 host  otg    any     :  host

 dev   host   any     :  INVALID
 dev   dev    any     :  dev
 dev   otg    any     :  dev

 otg   host   any     :  host
 otg   dev    any     :  dev
 otg   otg    any     :  dr_mode
Signed-off-by: default avatarThinh Nguyen <thinhn@synopsys.com>
Signed-off-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 073c47ac
...@@ -49,6 +49,57 @@ ...@@ -49,6 +49,57 @@
#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */
/**
* dwc3_get_dr_mode - Validates and sets dr_mode
* @dwc: pointer to our context structure
*/
static int dwc3_get_dr_mode(struct dwc3 *dwc)
{
enum usb_dr_mode mode;
struct device *dev = dwc->dev;
unsigned int hw_mode;
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
dwc->dr_mode = USB_DR_MODE_OTG;
mode = dwc->dr_mode;
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
switch (hw_mode) {
case DWC3_GHWPARAMS0_MODE_GADGET:
if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) {
dev_err(dev,
"Controller does not support host mode.\n");
return -EINVAL;
}
mode = USB_DR_MODE_PERIPHERAL;
break;
case DWC3_GHWPARAMS0_MODE_HOST:
if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
dev_err(dev,
"Controller does not support device mode.\n");
return -EINVAL;
}
mode = USB_DR_MODE_HOST;
break;
default:
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
mode = USB_DR_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
mode = USB_DR_MODE_PERIPHERAL;
}
if (mode != dwc->dr_mode) {
dev_warn(dev,
"Configuration mismatch. dr_mode forced to %s\n",
mode == USB_DR_MODE_HOST ? "host" : "gadget");
dwc->dr_mode = mode;
}
return 0;
}
void dwc3_set_mode(struct dwc3 *dwc, u32 mode) void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{ {
u32 reg; u32 reg;
...@@ -1023,17 +1074,9 @@ static int dwc3_probe(struct platform_device *pdev) ...@@ -1023,17 +1074,9 @@ static int dwc3_probe(struct platform_device *pdev)
goto err2; goto err2;
} }
if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && ret = dwc3_get_dr_mode(dwc);
(dwc->dr_mode == USB_DR_MODE_OTG || if (ret)
dwc->dr_mode == USB_DR_MODE_UNKNOWN)) goto err3;
dwc->dr_mode = USB_DR_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
(dwc->dr_mode == USB_DR_MODE_OTG ||
dwc->dr_mode == USB_DR_MODE_UNKNOWN))
dwc->dr_mode = USB_DR_MODE_PERIPHERAL;
if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
dwc->dr_mode = USB_DR_MODE_OTG;
ret = dwc3_alloc_scratch_buffers(dwc); ret = dwc3_alloc_scratch_buffers(dwc);
if (ret) if (ret)
......
...@@ -245,7 +245,10 @@ ...@@ -245,7 +245,10 @@
#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff) #define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
/* Global HWPARAMS0 Register */ /* Global HWPARAMS0 Register */
#define DWC3_GHWPARAMS0_USB3_MODE(n) ((n) & 0x3) #define DWC3_GHWPARAMS0_MODE(n) ((n) & 0x3)
#define DWC3_GHWPARAMS0_MODE_GADGET 0
#define DWC3_GHWPARAMS0_MODE_HOST 1
#define DWC3_GHWPARAMS0_MODE_DRD 2
#define DWC3_GHWPARAMS0_MBUS_TYPE(n) (((n) >> 3) & 0x7) #define DWC3_GHWPARAMS0_MBUS_TYPE(n) (((n) >> 3) & 0x7)
#define DWC3_GHWPARAMS0_SBUS_TYPE(n) (((n) >> 6) & 0x3) #define DWC3_GHWPARAMS0_SBUS_TYPE(n) (((n) >> 6) & 0x3)
#define DWC3_GHWPARAMS0_MDWIDTH(n) (((n) >> 8) & 0xff) #define DWC3_GHWPARAMS0_MDWIDTH(n) (((n) >> 8) & 0xff)
......
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