[Letux-kernel] [PATCH 0/3] MIPS: CI20: USB EHCI/OHCI

H. Nikolaus Schaller hns at goldelico.com
Sat Sep 26 11:26:25 CEST 2020


> Am 26.09.2020 um 10:41 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
> 
> Hi Paul,
> 
>> Am 26.09.2020 um 10:27 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
>> 
>> 
>>> Am 26.09.2020 um 10:10 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
>>> 
>>>> 
>>>> Am 26.09.2020 um 08:21 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
>>>> 
>>>> 
>>>>> Am 25.09.2020 um 22:55 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
>>>>> 
>>>>> 
>>>>>> Am 25.09.2020 um 22:53 schrieb H. Nikolaus Schaller <hns at goldelico.com>:
>>>>>> 
>>>>>> I still get the problem with "usb usb2-port1: Cannot enable. Maybe the USB cable is bad?".
>>>>>> 
>>>>>> Some analysis shows that this code returns -EBUSY:
>>>>>> 
>>>>>> https://elixir.bootlin.com/linux/latest/source/drivers/usb/core/hub.c#L2825
>>>>>> 
>>>>>> which means the port is not enabled (portstatus == 0x101).
>>>>>> 
>>>>>> Since this is coming from some USB communication message
>>>>>> (https://elixir.bootlin.com/linux/latest/source/drivers/usb/core/hub.c#L566),
>>>>>> I think it is not related to our drivers.
>>>>>> 
>>>>>> Could it be that the EHCI/OHCI do not have the clock running? This could
>>>>>> IMHO result in no response or the module not being enabled.
>>>>> 
>>>>> Or is it not allowed to share the phy between ehci and ohci?
>>>>> This is something which may be tested easily by disabling either one.
>>>> 
>>>> Ok, if I have EHCI only, the message is gone. But EHCI alone doesn't show a connected device.
>>>> If I have OHCI only, the message is back.
>>> 
>>> I have found something by comparing jz4740.dtsi. This also has
>>> 
>>> 		assigned-clocks = <&cgu JZ4740_CLK_UHC>;
>>> 		assigned-clock-rates = <48000000>;
>>> 
>>> Unfortunately adding this (with JZ4780_CLK_UHC) makes no difference:
>>> 
>>> root at letux:~# dmesg|fgrep 'usb usb1-port1'
>>> [   11.115855] usb usb1-port1: Cannot enable. Maybe the USB cable is bad?
>>> [   12.666946] usb usb1-port1: Cannot enable. Maybe the USB cable is bad?
>>> [   12.719847] usb usb1-port1: attempt power cycle
>>> [   14.883641] usb usb1-port1: Cannot enable. Maybe the USB cable is bad?
>>> [   17.270381] usb usb1-port1: Cannot enable. Maybe the USB cable is bad?
>>> [   17.334813] usb usb1-port1: unable to enumerate USB device
>>> root at letux:~# lsusb
>>> Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
>>> Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
>>> root at letux:~# 
>>> 
>>> So to summarise what we know:
>>> * error message comes from OHCI driver after several attempts (incl. power cycle)
>>> * specifically from get_port_status() [which sends some URB]
>>> * portstatus = 0x101 and therefore USB_PORT_STAT_ENABLE (0x0002) is false
>>> * does not depend on EHCI "okay" or "disabled"
>>> * assigned-clocks does not help
>>> * phy-names doesn't seem to have an influence
>>> * 1.1 root hub is initialized
>>> * power is on (I have my LCD panel/touch screen connected and would expect to see the touch device)
>> * hub_port_connect() is called when plugging/unplugging the device
>> 
>> This means that the USB-PHY is almost working and detecting plug events. Only communication to enumerate the device is failing.
>> This seems to be a positive effect of using the assigned-clocks. Have to cross-check. No. Doesn't matter.
>> 
>> Theoretically my board hardware could be broken... I can verify this by booting the NAND kernel. Yes, works there.
>> 
>> So we are missing just one bit in portstatus...
>> 
>>> 
>>> Ideas and suggestions are welcome :)
> 
> If you find a little time to experiment with my code on your CI20:
> 
> https://git.goldelico.com/?p=letux-kernel.git;a=shortlog;h=refs/heads/work-jz4780%2Busb
> 
> Please use letux_defconfig.

Some more info from studying the old 3.18 code:

ohci-jz4740.c did there call jz4780_cgu_set_usb_suspend() for jz4780:

drivers/usb/host/ohci-jz4740.c:

+       if (of_machine_is_compatible("ingenic,jz4780-ohci")) {
+               ret = jz4780_cgu_set_usb_suspend(USB_PORT_HOST, false);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to unsuspend port\n");
+                       goto err_disable;
+               }
+       }
+

drivers/clk/jz47xx/jz4780-cgu.c:
+int jz4780_cgu_set_usb_suspend(enum jz4780_usb_port port, bool suspend)
+{
+       unsigned long flags;
+       u32 opcr, bit;
+
+       switch (port) {
+       case USB_PORT_OTG:
+               bit = OPCR_SPENDN0;
+               break;
+
+       case USB_PORT_HOST:
+               bit = OPCR_SPENDN1;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&cgu->power_lock, flags);
+
+       opcr = readl(cgu->base + CGU_REG_OPCR);
+       if (suspend)
+               opcr &= ~bit;
+       else
+               opcr |= bit;
+       writel(opcr, cgu->base + CGU_REG_OPCR);
+
+       spin_unlock_irqrestore(&cgu->power_lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(jz4780_cgu_set_usb_suspend);

And EHCI does some calls like:
+       jz4780_cgu_start_ehci();
+
 
+       /* Set utmi data bus width of controller to 16bit */
+       temp = readl((volatile int *)EHCI_REG_UTMI_BUS);
+       writel(temp | UTMIBUS_WIDTH, (volatile int *)EHCI_REG_UTMI_BUS);


So this means that the ohci-generic driver doesn't really work because
it can't handle writing some very special bits for the jz4780 cgu.

Now we can try to
a) can hack that into the clock handling
b) hack something into generic-ohci
c) switch back to SoC specific ohci-jz4780.c

NOTE: drivers/clk/ingenic/jz4780-cgu.c defines CGU_REG_OPCR and OPCR_SPENDN*

BR,
Nikolaus



More information about the Letux-kernel mailing list