Skip to content

Commit 5268ed9

Browse files
jysnpsFelipe Balbi
authored andcommitted
usb: dwc2: Fix dr_mode validation
The dr_mode parameter was being checked against how the dwc2 module was being configured at compile time. But it wasn't checked against the hardware capabilities, nor were the hardware capabilities checked against the compilation parameters. This commit adds those checks and adjusts dr_mode to an appropriate value, if needed. If the hardware capabilities and module compilation do not match then we fail as it wouldn't be possible to run properly. The hardware, module, and dr_mode, can each be set to host, device, or otg. Check that all these values are compatible and adjust the value of dr_mode if possible. The following table summarizes the behavior: actual HW MOD dr_mode dr_mode ------------------------------ HST HST any : HST HST DEV any : --- HST OTG any : HST DEV HST any : --- DEV DEV any : DEV DEV OTG any : DEV OTG HST any : HST OTG DEV any : DEV OTG OTG any : dr_mode Signed-off-by: John Youn <[email protected]> Signed-off-by: Felipe Balbi <[email protected]>
1 parent 6bea962 commit 5268ed9

File tree

1 file changed

+69
-13
lines changed

1 file changed

+69
-13
lines changed

drivers/usb/dwc2/platform.c

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,71 @@ static const struct dwc2_core_params params_rk3066 = {
149149
.hibernation = -1,
150150
};
151151

152+
/*
153+
* Check the dr_mode against the module configuration and hardware
154+
* capabilities.
155+
*
156+
* The hardware, module, and dr_mode, can each be set to host, device,
157+
* or otg. Check that all these values are compatible and adjust the
158+
* value of dr_mode if possible.
159+
*
160+
* actual
161+
* HW MOD dr_mode dr_mode
162+
* ------------------------------
163+
* HST HST any : HST
164+
* HST DEV any : ---
165+
* HST OTG any : HST
166+
*
167+
* DEV HST any : ---
168+
* DEV DEV any : DEV
169+
* DEV OTG any : DEV
170+
*
171+
* OTG HST any : HST
172+
* OTG DEV any : DEV
173+
* OTG OTG any : dr_mode
174+
*/
175+
static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg)
176+
{
177+
enum usb_dr_mode mode;
178+
179+
hsotg->dr_mode = usb_get_dr_mode(hsotg->dev);
180+
if (hsotg->dr_mode == USB_DR_MODE_UNKNOWN)
181+
hsotg->dr_mode = USB_DR_MODE_OTG;
182+
183+
mode = hsotg->dr_mode;
184+
185+
if (dwc2_hw_is_device(hsotg)) {
186+
if (IS_ENABLED(CONFIG_USB_DWC2_HOST)) {
187+
dev_err(hsotg->dev,
188+
"Controller does not support host mode.\n");
189+
return -EINVAL;
190+
}
191+
mode = USB_DR_MODE_PERIPHERAL;
192+
} else if (dwc2_hw_is_host(hsotg)) {
193+
if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL)) {
194+
dev_err(hsotg->dev,
195+
"Controller does not support device mode.\n");
196+
return -EINVAL;
197+
}
198+
mode = USB_DR_MODE_HOST;
199+
} else {
200+
if (IS_ENABLED(CONFIG_USB_DWC2_HOST))
201+
mode = USB_DR_MODE_HOST;
202+
else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL))
203+
mode = USB_DR_MODE_PERIPHERAL;
204+
}
205+
206+
if (mode != hsotg->dr_mode) {
207+
dev_warn(hsotg->dev,
208+
"Configuration mismatch. dr_mode forced to %s\n",
209+
mode == USB_DR_MODE_HOST ? "host" : "device");
210+
211+
hsotg->dr_mode = mode;
212+
}
213+
214+
return 0;
215+
}
216+
152217
static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
153218
{
154219
struct platform_device *pdev = to_platform_device(hsotg->dev);
@@ -412,19 +477,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
412477
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
413478
(unsigned long)res->start, hsotg->regs);
414479

415-
hsotg->dr_mode = usb_get_dr_mode(&dev->dev);
416-
if (IS_ENABLED(CONFIG_USB_DWC2_HOST) &&
417-
hsotg->dr_mode != USB_DR_MODE_HOST) {
418-
hsotg->dr_mode = USB_DR_MODE_HOST;
419-
dev_warn(hsotg->dev,
420-
"Configuration mismatch. Forcing host mode\n");
421-
} else if (IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) &&
422-
hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
423-
hsotg->dr_mode = USB_DR_MODE_PERIPHERAL;
424-
dev_warn(hsotg->dev,
425-
"Configuration mismatch. Forcing peripheral mode\n");
426-
}
427-
428480
retval = dwc2_lowlevel_hw_init(hsotg);
429481
if (retval)
430482
return retval;
@@ -456,6 +508,10 @@ static int dwc2_driver_probe(struct platform_device *dev)
456508
if (retval)
457509
return retval;
458510

511+
retval = dwc2_get_dr_mode(hsotg);
512+
if (retval)
513+
return retval;
514+
459515
/*
460516
* Reset before dwc2_get_hwparams() then it could get power-on real
461517
* reset value form registers.

0 commit comments

Comments
 (0)