hexdump0815/imagebuilder

chromebook_kukui: usb gadget support, usb-mode-switch

rakslice opened this issue · 6 comments

I'm trying to figure out how to do usb gadget stuff on my system, a Lenovo 10e Chromebook kodama with your debian build with kernel 6.1.11-stb-mt8+

[   19.813592] Hardware name: MediaTek kodama sku288 board (DT)
# uname -a
Linux deb10e 6.1.11-stb-mt8+ #2 SMP PREEMPT Sun Feb 12 12:45:19 CET 2023 aarch64 GNU/Linux

The gadget udc does not appear in /sys/class/udc.

We have mtu3 device in dmesg:

[    0.813310] mtu3 11201000.usb: uwk - reg:0x420, version:101
[    0.813351] mtu3 11201000.usb: supply vbus not found, using dummy regulator
[    0.813415] mtu3 11201000.usb: dr_mode: 1, drd: auto
[    0.813425] mtu3 11201000.usb: u2p_dis_msk: 0, u3p_dis_msk: 0
[    0.813598] mtu3 11201000.usb: usb3-drd: 0
[    0.814007] mtu3 11201000.usb: xHCI platform device register success...

I see the kernel configs seem ok for gadget use:

CONFIG_USB_MTU3=y
CONFIG_USB_MTU3_DUAL_ROLE=y

The v6.1 Kconfig for CONFIG_USB_MTU3_DUAL_ROLE selects USB_ROLE_SWITCH and I see we have it:

CONFIG_USB_ROLE_SWITCH=y

I'm not sure how the role switching here is actioned, but I would guess it is expected to appear as a device in /sys/class/usb_role which can then be used per the kernel docs:
https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-usb_role

However /sys/class/usb_role is empty on my system.

The kernel v6.1 devicetree docs for mtu3 document a devicetree parameter to enable the usb role switching, usb-role-switch:
https://github.com/torvalds/linux/blob/v6.1/Documentation/devicetree/bindings/usb/mediatek%2Cmtu3.yaml#L130

The devicetree in the running system doesn't have it:

# dtc -I fs /sys/firmware/devicetree/base
... snip ...
                usb@11201000 {
                        #address-cells = <0x02>;
                        clock-names = "sys_ck\0ref_ck";
                        reg-names = "mac\0ippc";
                        vusb33-supply = <0x66>;
                        wakeup-source;
                        interrupts = <0x00 0x48 0x08>;
                        clocks = <0x28 0x3d 0x28 0x5a>;
                        #size-cells = <0x02>;
                        compatible = "mediatek,mt8183-mtu3\0mediatek,mtu3";
                        ranges;
                        status = "okay";
                        phys = <0x63 0x03 0x64 0x04>;
                        reg = <0x00 0x11201000 0x00 0x2e00 0x00 0x11203e00 0x00 0x100>;
                        dr_mode = "host";
                        mediatek,syscon-wakeup = <0x65 0x420 0x65>;

                        usb@11200000 {
                                #address-cells = <0x01>;
                                clock-names = "sys_ck\0ref_ck";
                                reg-names = "mac";
                                vusb33-supply = <0x66>;
                                interrupts = <0x00 0x49 0x08>;
                                clocks = <0x28 0x3d 0x28 0x5a>;
                                #size-cells = <0x00>;
                                compatible = "mediatek,mt8183-xhci\0mediatek,mtk-xhci";
                                status = "okay";
                                reg = <0x00 0x11200000 0x00 0x1000>;

                                hub@1 {
                                        compatible = "usb5e3,610";
                                        reg = <0x01>;
                                };
                        };
                };

I guess the usb-role-switch devicetree property is not actually present in the source relevant to this system.
https://github.com/search?q=repo%3Atorvalds%2Flinux+usb-role-switch+path%3Aarch%2Farm64%2Fboot%2Fdts%2Fmediatek&type=code

I see for this kernel we also have /boot/dtb-6.1.11-stb-mt8+/mt8183-pumpkin.dtb, and it also doesn't have usb-role-switch.

The kernel v6.1 devicetree source has usb-role-switch in the pumpkin-common.dtsi
https://github.com/torvalds/linux/blob/v6.1/arch/arm64/boot/dts/mediatek/pumpkin-common.dtsi#L190
But maybe that include isn't used for mt8183-pumpkin.dts.
https://github.com/torvalds/linux/blob/v6.1/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts

Ah, so usb_role is obviously not relevant:

This attribute can be used for requesting role swapping with non-USB Type-C ports.
With USB Type-C ports, the ABI defined for USB Type-C connector class must be used.

https://github.com/torvalds/linux/blob/v6.1/Documentation/ABI/testing/sysfs-class-usb_role

The kernel mtu3 devicetree docs have an example it says is for Dual role switch with type-c that has usb-role-switch;, so the latter is at least still relevant.

https://github.com/torvalds/linux/blob/v6.1/Documentation/devicetree/bindings/usb/mediatek%2Cmtu3.yaml#L298

i did not look at usb gadget mode on chromebooks yet, so i cannot help much here - just a little warning: the usb stack on some chromebooks does not seem to be in perfect shape, so if you do not get it working that might also a potential reason

So modifying the dtb with usb-role-switch; and setting a role-switch-default-mode doesn't get us any further.

In fact to get to the usb_add_gadget_udc call in mtu3_gadget.c
https://github.com/torvalds/linux/blob/v6.1/drivers/usb/mtu3/mtu3_gadget.c#L707
we need to have dr_mode of "peripheral" or "otg"
https://github.com/torvalds/linux/blob/v6.1/drivers/usb/mtu3/mtu3_plat.c#L393

But changing the dtb's dr_mode = "host" to either of those makes it fail to initialize with a clock check failure, so we do not get to it:

[    0.813273] mtu3 11201000.usb: uwk - reg:0x420, version:101
[    0.813316] mtu3 11201000.usb: supply vbus not found, using dummy regulator
[    0.813373] mtu3 11201000.usb: dr_mode: 3, drd: auto
[    0.813383] mtu3 11201000.usb: u2p_dis_msk: 0, u3p_dis_msk: 0
[    0.813556] mtu3 11201000.usb: usb3-drd: 0
[    0.813607] mtu3 11201000.usb: irq 254
[    0.813625] mtu3 11201000.usb: IP version 0x0(U3 IP)
[    0.813635] mtu3 11201000.usb: max_speed: super-speed-plus
[    0.833691] mtu3 11201000.usb: clks of sts1 are not stable!
[    0.833702] mtu3 11201000.usb: device enable failed -110
[    0.833711] mtu3 11201000.usb: mtu3 hw init failed:-110
[    0.833719] mtu3 11201000.usb: failed to initialize gadget
[    0.833756] mtu3: probe of 11201000.usb failed with error -110

The normal dmesg output with dr_mode = "host" is:

[    0.812962] mtu3 11201000.usb: uwk - reg:0x420, version:101
[    0.812998] mtu3 11201000.usb: supply vbus not found, using dummy regulator
[    0.813053] mtu3 11201000.usb: dr_mode: 1, drd: auto
[    0.813063] mtu3 11201000.usb: u2p_dis_msk: 0, u3p_dis_msk: 0
[    0.813237] mtu3 11201000.usb: usb3-drd: 0
[    0.813651] mtu3 11201000.usb: xHCI platform device register success...
[    0.814436] xhci-mtk 11200000.usb: supply vbus not found, using dummy regulator
[    0.814743] xhci-mtk 11200000.usb: xHCI Host Controller
[    0.814761] xhci-mtk 11200000.usb: new USB bus registered, assigned bus number 1
[    0.814833] xhci-mtk 11200000.usb: USB3 root hub has no ports
[    0.814843] xhci-mtk 11200000.usb: hcc params 0x01400f99 hci version 0x110 quirks 0x0000000000210010
[    0.814886] xhci-mtk 11200000.usb: irq 254, io mem 0x11200000

Okay so disabling USB 3 by setting u3p_dis_msk to 1 and speed to "high-speed" along with changing the dr_mode I'm able to get through the init so that the /sys/class/udc entry appears and I can bind the USB gadget config to it.

Incidentally a /sys/class/usb_role entry also appears, but it doesn't have a role device (https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-usb_role).

After adding a port { } stanza per the Dual role switch with type-c example linked above, associated with the connector { } stanza of the typec instance, with dr_mode = "otg", when I plug or unplug a connection to a type A port on another system with the stock cable, I do see the gadget (high-speed) pullup D+ and gadget (high-speed) pullup D- messages respectively from mtu3_dev_on_off()
https://github.com/torvalds/linux/blob/830b3c68c1fb1e9176028d02ef86f3cf76aa2476/drivers/usb/mtu3/mtu3_core.c#L349

However the other system doesn't see any USB device.

From the hub@1 in the dtb provided in the image I wonder if there is onboard hardware between the mtu3 (MediaTek USB3 DRD controller) and the physical usb type-c port, that wouldn't be there in actual DRD applications

i think for the suzyqable ccd there is a small hub somewhere in the path which provides the three usb devices for ccd-, system- and ec-consoles - maybe that one comes into the way somehow?