Skip to content
Pierre Tardy edited this page May 10, 2018 · 14 revisions

state of USB on the switch linux

Tegra manual contains all info on how usb works on TegraX1: https://developer.nvidia.com/embedded/downloads#?search=TRM (behind nvidia developer program wall) USB Chapter is Chapter 22 (starting page 1321)

image

There are two mutually exclusive controllers in the tegra.

One is usb2 only (ehci), supports otg on the main port. This is what is used by boot rom, coreboot and uboot to do the usb stuff.

The main one codenamed xusb supports the xhci protocol, but requires much more complicated sw stack. This is probably why they kept the ehci IP.

There are two options to supports usb device mode on switch:

  • Enable otg mode on xhci.
  • ENable ehci driver on linux (and disable xhci)

xhci aka xusb

Linux supports only the xusb driver via xhci-tegra.c pinctrl-tegra-xusb.c pinctrl-tegra210.c xusb-tegra210.c and xusb.c

device tree for xusb is: usb@70090000

xhci-tegra is developed by chromos guys. It does not support device mode as per initial commit:

https://github.com/abrestic/linux/commit/a483045bec842de7a2e8fecf7c0474074447aa31

Add support for the on-chip xHCI host controller present on Tegra SoCs.
The controller requires external firmware which must be loaded before
using the controller.  This driver loads the firmware, starts the
controller, and is able to service host-specific messages sent by
the controller's firmware.

The controller also supports USB device mode as well as powergating
of the SuperSpeed and host-controller logic when not in use, but
support for these is not yet implemented.

otg aka udc is supported by nvidia BSP aka L4T as xudc.c, but requires a lot of infrastructure from L4T, which is hard to port in an upstream like kernel.

ChromeOS guys did it for the Pixel C (aka smaug, aka ryu), but the last kernel supported by ChromeOS is 3.18.

So we have the choice of porting xudc.c either from L4T or from chromeOS.

ehci and tegra_udc

device tree for ehci is: usb@7d000000

	usb@7d000000 {
		status = "okay";
	};
	phy1: usb-phy@7d000000 {
		status = "okay";
		vbus-supply = <&usb2_vbus>;
	};

and add the usb regulator (as per uboot own device tree)


		usb2_vbus: regulator@6 {
			compatible = "regulator-fixed";
			reg = <6>;
			regulator-name = "USB2_VBUS";
			regulator-min-microvolt = <5000000>;
			regulator-max-microvolt = <5000000>;
			gpio = <&gpio TEGRA_GPIO(CC, 4) GPIO_ACTIVE_HIGH>;
			enable-active-high;
		};

Then, you can configure the mux to use ehci instead of xhci:

				lanes {
					usb2-0 {
						nvidia,function = "snps"; // for ehci
//						nvidia,function = "xusb"; // for xhci
						status = "okay";
					};
				};

tegra210.dsi says:

	usb@7d000000 {
		compatible = "nvidia,tegra210-ehci", "nvidia,tegra30-ehci", "usb-ehci";
        }

which taken by:

usb/host/ehci-tegra.c:  { .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config },

No driver upstream claims support of tegra210-usb variants.

The phy is claimed by

usb/phy/phy-tegra-usb.c:        { .compatible = "nvidia,tegra30-usb-phy", .data = &tegra30_soc_config },

But this driver harcodes registers that are different from what is in the spec, and the tegra_freq_table do not contain the mapping for 38400000 main cristal (aka OSC or pll_ref).

uboot contains those mapping, which are coherent with what is described in the spec.

// <uboot>/drivers/usb/host/ehci-tegra.c

/* NOTE: 13/26MHz settings are N/A for T210, so dupe 12MHz settings for now */
static const unsigned T210_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
        /* DivN, DivM, DivP, KCP,   KVCO,  Delays              Debounce, Bias */
        { 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  32500,  5 },
        { 0x019, 0x01, 0x01, 0x0,   0,  0x03, 0x4B, 0x0C, 0xBB,  48000,  8 },
        { 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  30000,  5 },
        { 0x028, 0x01, 0x01, 0x0,   0,  0x02, 0x2F, 0x08, 0x76,  65000,  5 },
        { 0x019, 0x02, 0x01, 0x0,   0,  0x05, 0x96, 0x18, 0x177, 96000, 15 },
        { 0x028, 0x04, 0x01, 0x0,   0,  0x04, 0x66, 0x09, 0xFE, 120000, 20 }
};

which maps in linux to:

	{
		.freq = 38400000,
		.enable_delay = 0x05,
		.stable_count = 0x96,
		.active_delay = 0x18,
		.xtal_freq_count = 0x177,
		.debounce = 0x17700,
	},

the DivN, DivM, DivP table is in linux in clk-tegra210.c:

static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
	{ 38400000, 480000000, 25, 2, 0, 0 },
}

note that the p values are different in uboot and in linux.

The previous modifications successfully enable ehci driver for linux, but ehci is host only, we still need the udc driver in order to enable otg. The udc driver was available in L4T, and also visible in early bring-up linux of smaug kernels, but it was later abandoned in favor of xudc.c. The udc driver has been removed from L4T in ebfc015edbe

attempt has been made to enable the tegra_udc driver from chromium in our tree. It is not yet fully working (the host recognise the configured gadget, but communications get stucked for some reason).

USB on u-boot

u-boot supports both host and device modes via ehci-tegra.c

Type C connector

As per teardown by techinsinde, the Type C connector is connected through a Pericom PI3USB30532. This passive mux chip handles the switch between full usb3 mode and display port (DP). Configuring this chip is one key to enabling docking station graphics.

This chip is supported by 4.17 driver which is in our the 4.17 rebase tree.

Power Delivery

Power delivery is managed by chip BM92T36m which sits on i2c 0x18, and has the marking M92T36

This repo may have useful info.

The switch firmware (obviously) has code to interact with the chip, but so does the dock firmware (it has 2 other rohm chips). The overall design is actually quite similar to the rohm evaluation kit design.

dhewg has an usb dump of the comm to that chip:

~/ i2cdump -y 0 0x18
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 00 00 00 80 00 00 e0 a2 00 00 00 00 00 00 00 00    ...?..??........
10: 00 00 00 00 00 00 00 00 00 00 72 00 00 00 00 00    ..........r.....
20: 04 90 12 04 00 00 49 44 04 90 00 04 00 00 ff 06    ????..ID??.?...?
30: 00 00 00 0c 90 36 b0 00 90 92 00 00 04 90 22 00    ...??6?.??..??".
40: 00 00 00 00 00 00 00 00 00 00 00 03 7c b5 b0 01    ...........?|???
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: 00 00 00 00 00 00 00 00 00 80 f4 01 40 00 8f 00    .........???@.?.
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................

fast charging

By default linux setup charge at 500mA. In order to let it charge faster, you can do

echo 1500000 > /sys/class/power_supply/bq24190-charger/input_current_limit

and make sure that works in

cat /sys/class/power_supply/max170xx_battery/current_now

to prevent battery consumption, you can also shutdown the screen

echo 1 >/sys/class/backlight/backlight/brightness
echo 1 >/sys/class/graphics/fb0/blank

usb gadget setup

how to setup gadget using sysfs: https://events.static.linuxfound.org/sites/events/files/slides/USB%20Gadget%20Configfs%20API_0.pdf