[PATCH v2 1/2] usb: dwc3-generic: set "mode" based on caller of dwc3_generic_probe()

Roger Quadros rogerq at kernel.org
Wed Dec 4 10:57:14 CET 2024



On 04/12/2024 09:47, Siddharth Vadapalli wrote:
> On Wed, Dec 04, 2024 at 09:32:23AM +0200, Roger Quadros wrote:
>>
>>
>> On 04/12/2024 07:16, Siddharth Vadapalli wrote:
>>> On Tue, Dec 03, 2024 at 09:23:11PM +0200, Roger Quadros wrote:
> 
> [...]
> 
>>>>> +++ b/drivers/usb/dwc3/dwc3-generic.c
>>>>> @@ -51,7 +51,8 @@ struct dwc3_generic_host_priv {
>>>>>  };
>>>>>  
>>>>>  static int dwc3_generic_probe(struct udevice *dev,
>>>>> -			      struct dwc3_generic_priv *priv)
>>>>> +			      struct dwc3_generic_priv *priv,
>>>>> +			      enum usb_dr_mode mode)
>>>>
>>>> This is not necessary as dwc3_generic_host_probe will only be
>>>> registered if dr_mode == "host" and dwc3_generic_peripheral_probe
>>>> will only be registered if dr_mode == "host" or "peripheral"
>>>
>>> But I don't see it happening that way. dwc3_generic_host_probe() or
>>> dwc3_generic_peripheral_probe() seem to be invoked based on the command
>>> executed - USB Host command will trigger generic_host_probe() while USB
>>> Device/Gadget command will trigger generic_peripheral_probe().
>>>
>>
>> But, when dr_mode is "otg" generic host driver is *not* bound to the
>> DWC3 device. So dwc3_generic_host_probe() will never be called for it.
> 
> In USB DFU boot, "dwc3_generic_peripheral_boot()" is invoked. Please
> test it out on AM625-SK. I was able to observe this on AM62A7-SK.

We do want dwc3_generic_peripheral_boot() to be invoked with dr_mode is "otg".
As we still do not support dual-role switching in u-boot.

And you need that for DFU as well. Did I miss something?

> 
>>
>>>
>>>>
>>>>>  {
>>>>>  	int rc;
>>>>>  	struct dwc3_generic_plat *plat = dev_get_plat(dev);
>>>>> @@ -62,7 +63,19 @@ static int dwc3_generic_probe(struct udevice *dev,
>>>>>  
>>>>>  	dwc3->dev = dev;
>>>>>  	dwc3->maximum_speed = plat->maximum_speed;
>>>>> -	dwc3->dr_mode = plat->dr_mode;
>>>>> +
>>>>> +	/*
>>>>> +	 * If the controller supports OTG as indicated by plat->dr_mode,
>>>>> +	 * then either Host or Peripheral mode is acceptable.
>>>>> +	 * Otherwise, error out since the platform cannot support the mode
>>>>> +	 * being requested by the caller of dwc3_generic_probe().
>>>>> +	 */
>>>>> +	if (plat->dr_mode != mode && plat->dr_mode != USB_DR_MODE_OTG) {
>>>>> +		pr_err("Requested usb mode is not supported by platform\n");
>>>>
>>>> This is actually not necessary. Sorry for suggesting this approach before.
>>>
>>> While the check may not be necessary, dr_mode *should* be set based on
>>> the caller and not based on plat->dr_mode. The reason I say so is that
>>> plat->dr_mode could be "otg" in the device-tree. But "otg" shouldn't be
>>> used for further configuration. I had indicated the reason for this in
>>> the cover-letter, which I am pasting below for your reference:
>>>
>>> ---------------------------------------------------------------------------
>>> Currently, dwc3_generic_probe() sets the mode based on the device-tree
>>> rather than setting it on the basis of the caller. While this might be
>>> correct when the mode is "host" or "peripheral" in the device-tree, it is
>>> wrong when the mode is "otg" in the device-tree. It is wrong because of two
>>> reasons:
>>> 1. There is no OTG state machine in U-Boot. Hence the role will never
>>> switch to the correct one eventually among host or peripheral.
>>> 2. dr_mode = "otg" results in the "PRTCAPDIR" field of the "GCTL"
>>> register of the USB Controller being set to 11b. According to the
>>> datasheet of the Designware USB Dual Role Controller, "PRTCAPDIR"
>>> should never be set to any value other than 01b (Host) and 10b (Device).
>>> Quoting the datasheet:
>>> "Programming this field with random data causes the controller
>>> to keep toggling between the host mode and the device mode."
>>>
>>> Therefore, in order to avoid programming 11b in "PRTCAPDIR", and, given
>>> that the caller specifies the intended role, rather than simply using
>>> the "dr_mode" property to set the role, set the role on the basis of the
>>> caller (intended role) and the device-tree (platform support).
>>> ----------------------------------------------------------------------------
>>>
>>> Point #2 above is the main reason why dr_mode cannot be set to "otg" in
>>> dwc3_generic_probe(). The only difference now is that the check can be
>>> dropped as you have indicated, so the last paragraph above will change
>>
>> Finally we are at the root of the problem. But the solution is not to
>> change the dr_mode but instead handle it correctly in dwc3_core_init_mode()
>>
>> diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
>> index a35b8c2f646..7f42b6e62c6 100644
>> --- a/drivers/usb/dwc3/core.c
>> +++ b/drivers/usb/dwc3/core.c
>> @@ -752,13 +752,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
>>  		}
>>  		break;
>>  	case USB_DR_MODE_OTG:
>> -		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
>> -		ret = dwc3_host_init(dwc);
>> -		if (ret) {
>> -			dev_err(dwc->dev, "failed to initialize host\n");
>> -			return ret;
>> -		}
>> -
>> +		/* We don't support dual-role so restrict to Device mode */
>> +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
> 
> But is this acceptable? Why not default to Host? I went through a series

I will let others chime in if it is acceptable or not.

> Why not default to host? 

Because we don't bind the generic_host driver at all when dr_mode = "otg".
So XHCI driver will not be probed and host mode will not function.

> I went through a series
> for defaulting OTG to Device for the Cadence Controller which was
> objected at:
> https://lore.kernel.org/r/62c5fe13-7f0e-e736-273e-31a8bbddbf13@kernel.org/
> with the suggestion to use the cable to determine the role.
> 

dual-role is a new feature for this driver in u-boot which can be added
in the future if needed.
The current problem is to get DFU/device mode to work when dr_mode is "otg".

As the dwc3-generic driver only registers the device controller when
dr_mode is "otg" I don't see any other neater way to fix it than to
limit the controller to device mode if dr_mode is "otg".

The only only other driver calling dwc3_init() is dwc3-layerscape.c. whose
commit log states
"OTG mode is not supported yet. The dr_mode in the devicetree will either
 have to be set to peripheral or host."

Or you can go all the way and get the dual-role mode working the right way
where you check user request along with cable status and allow/prevent a
certain role.

-- 
cheers,
-roger



More information about the U-Boot mailing list