Need help with usb otg on custom board.

I’m trying to wake up usb on a custom board. It only has the otg/recovery port, and I’ve disabled xhci/echi2/ehci3 in the kernel. The kernel seems happy enough when I boot, but it sees no usb devices. If I try to run lsusb I get “unable to initialize libusb: -99”.

When I try to set the port to device mode and load g_ether.ko I get no complaints, but no usb0 interface shows up. Logs with some extra debug below.

Anyone got an idea what parts of my kernel/dtb that could be wrong/missing based on these logs?

root@bored:~# dmesg | egrep -i 'usb|otg|udc'
[    0.000000] Kernel command line: console=ttyS0,115200n8 console=tty1 no_console_suspend=1 lp0_vec=2064@0xf46ff000 mem=2015M@2048M memtype=255 ddr_die=2048t
[    0.513197] usbcore: registered new interface driver usbfs
[    0.513267] usbcore: registered new interface driver hub
[    0.513373] usbcore: registered new device driver usb
[    0.552609] avdd_usb: at 3300 mV 
[    0.552829] avdd_usb: supplied by vdd-out2-5v0
[    0.690899] usb0-vbus: 5000 mV
[    0.691090] tegra-otg tegra-otg: otg transceiver registered
[    2.635291] usbcore: registered new interface driver asix
[    2.640786] usbcore: registered new interface driver ax88179_178a
[    2.646972] usbcore: registered new interface driver cdc_ether
[    2.652895] usbcore: registered new interface driver smsc95xx
[    2.658699] usbcore: registered new interface driver cdc_subset
[    2.664698] usbcore: registered new interface driver cdc_ncm
[    2.670431] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    2.681626] Nvidia Tegra High-Speed USB Device Controller driver (Apr 30, 2012)
[    2.689065] tegra_udc: tegra_udc_probe(2814) BEGIN
[    2.693924] tegra_udc: tegra_udc_probe: QC2 voltage = 1, current = 1200000
[    2.700822] usb_phy: tegra_usb_phy_open(794) inst:[0]
[    2.705901] tegra USB phy - inst[0] platform info:
[    2.710709] port_otg: yes
[    2.716182] phy_interface: USB_PHY_INTF_UTMI
[    2.720478] op_mode: TEGRA_USB_OPMODE_DEVICE
[    2.739931] usb_phy: tegra_usb_phy_init_ops(157) inst:[0]
[    2.746378] usb_phy: tegra_usb_phy_power_on(420) inst:[0]
[    2.755457] usb_phy: tegra_usb_phy_init(354) inst:[0]
[    2.760583] tegra_udc: dr_controller_setup(321) BEGIN
[    2.765656] tegra_udc: dr_controller_reset(290) BEGIN
[    2.770735] tegra_udc: dr_controller_reset(311) END
[    2.775632] tegra_udc: dr_controller_setup(367) END
[    2.780937] tegra-udc tegra-udc.0: usb_bat_chg regulator not registered: USB charging will not be enabled
[    2.790539] tegra_udc: dr_controller_stop(460) BEGIN
[    2.795524] tegra_udc: dr_controller_stop(477) END
[    2.800361] tegra_udc: dr_controller_reset(290) BEGIN
[    2.805442] tegra_udc: dr_controller_reset(311) END
[    2.810338] usb_phy: tegra_usb_phy_power_off(369) inst:[0]
[    2.815902] tegra-otg: tegra_otg_set_peripheral(524) BEGIN
[    2.821463] tegra-otg: enable_interrupt(257) interrupt mask = 0x700
[    2.827754] tegra-otg: tegra_otg_set_peripheral(555) END
[    2.833082] tegra_udc: tegra_udc_probe(3023) END
[    2.932070] usbcore: registered new interface driver uvcvideo
[    2.937844] USB Video Class driver (1.1.1)
[    3.066639] usbcore: registered new interface driver usbhid
[    3.072249] usbhid: USB HID core driver
[    3.173357] usbcore: registered new interface driver snd-usb-audio

root@bored:~# echo 0 > /sys/devices/platform/tegra-otg/enable_host
[  112.981059] tegra-otg: tegra_change_otg_state(411) requested otg state SUSPEND-->SUSPEND
[  112.989224] tegra-otg: enable_interrupt(257) interrupt mask = 0x700

root@bored:~# echo 1 > /sys/devices/platform/tegra-otg/enable_device
[  127.277108] tegra-otg: enable_interrupt(257) interrupt mask = 0x700
[  127.283436] tegra-otg: tegra_change_otg_state(411) requested otg state SUSPEND-->SUSPEND
[  127.291569] tegra-otg: tegra_change_otg_state(411) requested otg state SUSPEND-->PERIPHERAL
[  127.299960] otg state changed: SUSPEND --> PERIPHERAL
[  127.305053] tegra_udc: tegra_vbus_session(1560) turn VBUS state from off to on
[  127.312131] usb_phy: tegra_usb_phy_power_on(420) inst:[0]
[  127.321441] tegra_udc: dr_controller_setup(321) BEGIN
[  127.326528] tegra_udc: dr_controller_reset(290) BEGIN
[  127.331624] tegra_udc: dr_controller_reset(311) END
[  127.336538] tegra_udc: dr_controller_setup(367) END
[  127.341452] usb_phy: tegra_usb_phy_charger_detected(603) inst:[0]
[  127.537755] usb_phy: tegra_usb_phy_apple_500ma_charger_detected(679) inst:[0]
[  127.601068] usb_phy: tegra_usb_phy_apple_1000ma_charger_detected(659) inst:[0]
[  127.664467] usb_phy: tegra_usb_phy_apple_2000ma_charger_detected(669) inst:[0]
[  127.727876] usb_phy: tegra_usb_phy_nv_charger_detected(649) inst:[0]
[  127.752539] tegra_udc: dr_controller_run(376) BEGIN
[  127.757457] tegra_udc: can_pullup(282) driver = 0 softconnect = 0 vbus_active = 1
[  127.764981] tegra_udc: can_pullup(282) driver = 0 softconnect = 0 vbus_active = 1
[  127.772498] tegra_udc: dr_controller_run(453) END

root@bored:~# modprobe g_ether
[  180.611695] g_ether gadget: using random self ethernet address
[  180.619257] g_ether gadget: using random host ethernet address
[  180.628110] usb0: MAC b6:76:4f:34:a1:95
[  180.632159] usb0: HOST MAC 26:06:f7:12:dc:cd
[  180.636647] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
[  180.643346] g_ether gadget: g_ether ready
[  180.647414] tegra_udc: tegra_udc_start(2617) BEGIN
[  180.652265] tegra-udc: bind to driver g_ether
[  180.656677] tegra_udc: tegra_udc_start(2635) END

root@bored:~# echo connect > /sys/devices/platform/tegra-udc.0/udc/tegra-udc.0/soft_connect
[  223.621022] tegra_udc: tegra_udc_start(2617) BEGIN
[  223.625890] tegra-udc: bind to driver g_ether
[  223.630333] tegra_udc: tegra_udc_start(2635) END
[  223.635101] tegra_udc: tegra_pullup(1642) BEGIN
[  223.639676] tegra_udc: can_pullup(282) driver = 1 softconnect = 1 vbus_active = 1
[  223.647197] tegra_udc: tegra_pullup(1674) END
[  224.648845] tegra_udc: tegra_udc_non_std_charger_detect_work(2477) BEGIN
[  224.655592] tegra-udc tegra-udc.0: connected to non-standard charger
[  224.663294] tegra_udc: tegra_udc_non_std_charger_detect_work(2482) END

Found out now that I actually can configure an usb0 interface on the device after running these commands, but not on my host machine. There I just get:

SIOCSIFADDR: No such device
usb0: ERROR while getting interface flags: No such device

By “wake up”, what’s the specific condition or goal you are working on? I’m not sure if you are speaking of USB sleep mode.

Just in general, the gadget interface is basically just an empty “stub”…you need to implement some of the code itself, so something like g_ether is a framework, not a complete ethernet device. One of the things you have to do is mimic the USB side device information before your other machine will be able to tell there is a “synthetic device” there instead of a Jetson (e.g., transfer mode, control setup, product ID and vendor ID).

Bad choice of words. By waking up, I mean making it work :)

On Jetson the commands above were all I needed to make it work.

Host:
sudo modprobe cdc_ether

Device:
echo 0 > /sys/devices/platform/tegra-otg/enable_host
echo 1 > /sys/devices/platform/tegra-otg/enable_device
modprobe g_ether
echo connect > /sys/devices/platform/tegra-udc.0/udc/tegra-udc.0/soft_connect

Then 'sudo ifconfig usb0 ’ on both sides, and I could use ethernet over usb.

I have the same rootfs on my custom target (built with Yocto), so I suspect it is something I’ve done wrong (or not done at all) when adapting regulators/vbus/id stuff to my board. But with little usb knowledge and no error messages it’s hard to know where to start :)

Can you post the output from dmesg on the host after connecting the usb cable to the device?

Additional things I would check:
0. This is an obvious one, but easy to miss: check that the device is on your host is indeed usb0 and not usb1 or something else (ifconfig -a).

  1. Make sure network-manager on the host/target isn’t messing with the connection.
  2. Diff USB-device related configuration in the kernel between Jetson and your board.

BR,
Michael

The output there is not very interesting. All is silent after:
[ 1018.430136] usbcore: registered new interface driver cdc_ether

  1. After loading g_ether, and interface called usb0 shows up on my target. On my host, no usb device every shows up.
  2. I think stuff has not gotten far enought that network-manager can ruin it :)
  3. That’s where I’ll have to continue. A diff between my board and Jetson is that vbus does not come from the pmic and is alway on. Also, id detection does not work, so I must control host/device selection myself.

I’m also quite unsure about the regulator/pmic stuff I’ve done in the kernel, so I must read up on that. The usb related things I’ve tried creating supplies for are “tegra-ehci.0”, “tegra-udc.0” and “tegra-otg”.

“… On my host, no usb device every shows up…”

If the host does not see a device, then either (1) device is not reporting as a device (software), or (2) the cable is type-A instead of type-B at the Jetson side. About cables and connectors…the flash cable Jetson comes with is correct for when Jetson is in device mode (device mode is what you want). It’s actually difficult to find a cable out there which has a micro-A connector…you’d have to try hard or be very lucky/unlucky to get a cable that fails by being type-A. However, it’s easy to check.

If the cable is the nVidia-supplied flash cable, it is correct for device mode (type-B). If the micro connector has a “B” on it, it is correct for device mode. If the micro connector has a couple of beveled corners, and not entirely square corners, this is also a type-B connector and correct for device mode (all corners square describes type-A). Can you verify the cable itself is correct?

As a side note on USB cable testing, if your host sees the Jetson using that cable on the micro port while in recovery mode, then you’ve just guaranteed the problem is not cabling and must be software. You don’t have to actually flash, just go into recovery mode and see if anything shows up via:

lsusb -d 0955:7140

The cable is the nvidia-supplied one, and flashing works just fine, so I’ll have to work on my kernel code.

Connected a usb analyzer and added some debug. The same thing happens on the wire for my board and jetson when I put them in device mode. When I soft_connect, however, I never get a tegra_udc_irq on my board, and it ends up assuming a non standard charger.

I noticed the cdc_ether, and of course g_ether. So it’s obvious you want the device to show up and behave as ethernet over USB. However, you mention that “it ends up assuming a non standard charger”. This seems like a conflict, and I’m not positive from above whether there is a USB charger attached, or you are saying it thinks there is one attached and should not. However, back at the original issue making the device act as ethernet over USB, you have communications over USB mostly handled by the gadget code. The kernel modules have mostly handed API/protocol to a standardized “stub”, after which you must write what that stub actually talks to. At this point you probably want to write a kernel module which depends on g_ether and cdc_ether…I have not looked at tegra_udc_irq, but this is probably something the new kernel module would handle. Presumably the module would bridge to something like ethernet using the protocols of cdc_ether. If there is no USB response, it may be that it is because the code was never written.

I try to configure it as ethernet over USB. The reason it ends up as non standard charger is that it does not get any setup packet from the host. After waiting for 4s the kernel times out and just assumes non standard charger.

I suspect my issue is at a very low level now. The soft_connect writes to the USB Command Register to “enable a pull-up on D+ and initiate an attach event.” That event is never registered by the analyzer on my custom board, so I suspect it never happens.

The code that initiates this is one line.

udc_writel(udc, tmp | USB_CMD_RUN_STOP, USB_CMD_REG_OFFSET);

I believe the pinmux is okay, so I’m trying to find other misconfigurations I may have done.

You mentioned:

lsusb I get "unable to initialize libusb: -99"

The custom board with the TK1…if it has only device mode USB, and no host mode…is probably correct to behave this way. But what about the host to which the TK1 device is connected to? The thing about lsusb is that it is for devices plugged into a host, but this does not apply to a device acting as a device. So to clarify, the lsusb unable to initialize is from the custom TK1 board, is this correct? If correct, what shows up under lsusb of the host?

Is the actual USB connector being used for both recovery mode and ethernet function, but never as a host? The connector seems to be OTG by what you’ve said, rather than just type “B”.

What kernel USB options were changed versus a stock Jetson TK1?

What you say is correct. No NVIDIA devices show up in the lsusb output on host.

The actual connector is used for recovery, mass storage in u-boot, and hopefully soon as ethernet in linux :)

No kernel USB options have been changed. I tried removing CONFIG_USB_XHCI_HCD=y and CONFIG_TEGRA_XUSB_PLATFORM=y, but it had no effect, so I put it back.

Some more debug results/suspicions:

From the analyzer output it seems that something happens with D+ when I enable_device, but nothing happens when I soft_connect.

vbus and id are not supplied by pmu/gpio, but always present. I’ve tried to configure for this with:

tegra_udc_pdata.id_det_type = TEGRA_USB_VIRTUAL_ID;
tegra_ehci1_utmi_pdata.id_det_type = TEGRA_USB_VIRTUAL_ID;

but the following code in vbus_enabled alway returns 0, and I wonder if that is a sign of misconfiguration:

} else if (!udc->support_pmu_vbus) {
    status = (udc_readl(udc, VBUS_WAKEUP_REG_OFFSET)
	& USB_SYS_VBUS_STATUS);
}

Regarding the ID pin: Only the custom TK1 would notice this, not the host. However, manual switch between host/device modes would do exactly the same thing (just manually instead of automatic). I wanted to be sure the pin is not doing something to be detected and conflicting with manual setting of host/device mode.

In terms of lsusb on the host, I would not expect an nVidia device to show up unless the USB setup has set a manufacturer ID as nVidia. This is in fact one of the things a gadget interface would need to be set up, else it would fail…but it wouldn’t be an nVidia response (well, one exception being recovery mode because flash software could use this). However, something should show up on host…a brief host side lsusb output before and after plugging in a device mode board to the host should differ by at least 1 additional line. Although the device would not be listed as nVidia, does your host see anything in lsusb when your ethernet configured device port is attached to the host or when detached? If not, then manufacturer and product ID fields probably need setup from the Jetson side (assuming the USB is electrically correct, then drivers at the host side will only work if information is transferred about the device…if information does not exist, things will halt). The host and device ID is required in the chain of events prior to actual device details (if the device doesn’t identify itself, USB can’t ask for device-specific informaiton).

I have not experimented with this, but under kernel “Device Drivers -> USB support -> USB Gadget Support” there are three debugging message options available. Do not use the first “Debugging messages”, but perhaps enable the remaining two “Debugging information files”…but do this on your host, not on the Jetson. You’ll see these enable messages in /proc and /sys. I’m thinking that watching these as you plug in the USB cable (e.g., "tail -f ") to the host might give a hint as to what your gadget is within the host’s driver. Establish whether manufacturer ID and/or product ID are sent to the host.

It works!

The problem turned out to be a pulldown on vbus that pulled it to 0.9V instead of 3.3V. When we fixed that, Stuff Started Working. Thanks for helping out.