USB Load Switches

I need manual control over the TEGRA_PIN_USB_VBUS_EN1 pin that goes to the load switch for the USB3 port. I was using a switchable USB hub controlled by a logic level MOSFET in place of the switch, but it looks like I should be able to take manual control over the load switch on the dev board and later integrate that into my own carrier board.

I’ll be using a USB camera that has an integrated IR LED array and will need to disable the camera at night when possible to conserve power.

I tried exporting the GPIO (229), but that failed. I don’t see a way to enable this control. From the TRM section “ APB_MISC_GP_USB_VBUS_EN1_CFGPADCTRL_0” I see that there are registers available that apparently do what I need but I am struggling to find the link between the device-tree, kernel drivers, etc., and those registers.

Does it show busy when you export the gpio? Then you need to find which driver use it and unload that driver otherwise you need to change to another pin.

I think if I use the regulator-gpio instead of regulator-fixed-sync I’ll be able to dig through the bindings and configure it to do what I need.

Before I flash another device tree blob to it and fooling around with that, is there a way to flash the dtb without overwriting the work I’ve done configuring the ML libraries?

You can flash DTB by itself and not flash rootfs. You could clone first for safety (highly advised).

See the docs for what files to change first (and this changes somewhat with release version), but this is the basic command for flashing just DTB:

sudo ./ -r -d /where/ever/dtb/is/file.dtb mmcblk0p1 jetson-tx2

The “-r” says to not regenerate a system.img, the “-d ” tells it to flash this device tree.

A typical clone of the APP partition (the GPT label for rootfs is “APP”) is:

sudo ./ -r -k APP -G backup.img mmcblk0p1

(beware this requires a lot of disk space)

Hi linuxdev, can you confirm that the -r switch is working as expected on the latest version? I had previously done quite a bit of work before updating the device tree and used the the “flash -r -d” command to update it (with the target being the jetson-tx1) and it overwrote the filesystem.

I’ll be doing a backup before flashing another, but I don’t expect it to perform differently this time…

/Linux_for_Tegra$ ./ --help

Usage: sudo ./ [options] <target_board> <rootdev>
	target board: Valid target board name.
	rootdev: Proper root device.
        -b <bctfile> --------- nvflash boot control table config file.
        -c <cfgfile> --------- nvflash partition table config file.
        -d <dtbfile> --------- device tree file.
        -e <emmc size> ------- Target device's eMMC size.
        -f <flashapp> -------- Path to flash application: nvflash or tegra-rcm.
        -h ------------------- print this message.
        -i ------------------- pass user kernel commandline as-is to kernel.
        -k <partition id> ---- partition name or number specified in flash.cfg.
        -m <mts preboot> ----- MTS preboot such as mts_preboot_si.
        -n <nfs args> -------- Static nfs network assignments
                               <Client IP>:<Server IP>:<Gateway IP>:<Netmask>
        -o <odmdata> --------- ODM data.
        -p <bp size> --------- Total eMMC HW boot partition size.
        -r ------------------- skip building and reuse existing system.img.
        -s <PKC key file>----- PKC key used for signing and building bl_update_payload.
        -t <tegraboot> ------- tegraboot binary such as nvtboot.bin
        -u <dbmaster> -------- PKC server in <user>@<IP address> format.
        -w <wb0boot> --------- warm boot binary such as nvtbootwb0.bin
        -x <tegraid> --------- Tegra CHIPID. default = 0x18(jetson-tx2)
                               0x21(jetson-tx1), 0x40(jetson-tk1).
        -y <fusetype> -------- PKC for secureboot, NS for non-secureboot.
        -z <sn> -------------- Serial Number of target board.
        -B <boardid> --------- BoardId.
        -C <cmdline> --------- Kernel commandline arguments.
                               Each option in this kernel commandline gets
                               higher preference over the same option from
                               fastboot. In case of NFS booting, this script
                               adds NFS booting related arguments, if -i option
                               is omitted.
        -F <flasher> --------- Flash server such as fastboot.bin.
        -G <file name> ------- Read partition and save image to file.
        -I <initrd> ---------- initrd file. Null initrd is default.
        -K <kernel> ---------- Kernel image file such as zImage or Image.
        -L <bootloader> ------ Bootloader such as cboot.bin or u-boot-dtb.bin.
        -M <mts boot> -------- MTS boot file such as mts_si.
        -N <nfsroot> --------- i.e. <my IP addr>:/my/exported/nfs/rootfs.
        -P <end of PPT + 1> -- Primary GPT start address + size of PPT + 1.
        -R <rootfs dir> ------ Sample rootfs directory.
        -S <size> ------------ Rootfs size in bytes. Valid only for internal
                               rootdev. KiB, MiB, GiB short hands are allowed,
                               for example, 1GiB means 1024 * 1024 * 1024 bytes.
        -T <its file> -------- ITS file name. Valid only for u-boot.
        --no-flash ----------- perform all steps except physically flashing the board.
                               This will create a system.img.
        --bup ---------------- Generate bootloader update payload(BUP).
        --multi-spec---------- Enable support for building multi-spec BUP.
        --clean-up------------ Clean up BUP buffer when multi-spec is enabled.
        --usb-instance <id> -- Specify the USB instance to connect to; integer
                               ID (e.g. 0, 1), bus/dev (e.g. 003/091), or USB
                               port path (e.g. 3-14). The latter is best.

I don’t know but my guess is it overwrites the jetson using the already generated image as opposed to the one on the Jetson.

It’s always a good idea to clone first, and I’ll be doing that before I check (this takes plenty of time and disk space). To be sure I’m not testing the wrong thing though, what was your device tree file from, and what was the command used?

The command copied from the terminal history:

$ sudo ./ -r -d ~/jetson_dev/dtb/compiled.dtb jetson-tx1 mmcblk0p1

What device tree was the original source from before modifying/compiling? Is this R28.2 (“head -n 1 /etc/nv_tegra_release”). R28.2 is what JetPack3.2 flashes.

R28.2 it is, yes.

Before modification which device tree source was used originally? E.g., one from the “Linux_for_Tegra/kernel/dtb/” directory? I’m looking to reproduce what you did (though without modifications).

As near as I can tell that should be it. The file at “/boot/dtb/tegra210-jetson-tx1-p2597-2180-a01-devit.dtb” was copied from the Jetson, decompiled, modified, and recompiled.

My experiment is failing. I want to document this now, but have not looked closely yet.

I wanted to be sneaky in case rootfs did get flashed and reduce work. What I did was clone the rootfs. Then I put a file in “/” of the clone via loopback mount to distinctly identify the clone. I put a similar file in “/” of the running TX1 to distinctly identify this file system.

Next I put a copy of my clone in “Linux_for_Tegra/” as file “system.img”, while removing “system.img.raw” from the original flash. If it turns out I reuse the image here, then the flashed image will be a match for the one I already run…except for that marker file I added to distinctly identify source as from the backup clone versus the original.

I verified my original flash (a log from installing R28.2) used the dtb file “kernel/dtb/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb”. So I ran this command to flash just dtb (and to log it):

<s>sudo ./ -r -d ./kernel/dtb/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb jetson-tx1 mmcblk0p1 2>&1 | tee log_dtb-flash_TX1_R28-2.txt</s>
# Corrected:
sudo ./ -r <b>-k DTB</b> -d ./kernel/dtb/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb jetson-tx1 mmcblk0p1 2>&1 | tee log_dtb-flash_TX1_R28-2.txt

I received this failure:

[   5.8635 ] 00000004: Filesize is bigger than partition size

Investigation shows this original file is size 449415 bytes. A log from a previous “gdisk -l” shows this for the DTB partition:

Number  Start (sector)    End (sector)  Size       Code  Name
  14        30482466        30490657   4.0 MiB     0700  DTB

This is a sector count of 8191. At 512 bytes per sector this is 4193792 bytes (about 4MiB). If the command was just filling in the DTB partition there should have been plenty of room (a signature though would increase requirements).

I can verify that the DTB flash command will fail and you won’t be able to boot.
(see corrected command above which has “-k DTB”)

Apparently this does not work with all release versions. I’m reflashing now before I can add anything.

[s]Can someone at NVIDIA confirm if this command is valid for flashing the DTB using the original “kernel/dtb/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb” file?

sudo ./ -r -d ./kernel/dtb/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb jetson-tx1 mmcblk0p1


It looks like this is needed:

sudo ./ -r <b>-k DTB</b> -d ~/jetson_dev/dtb/compiled.dtb jetson-tx1 mmcblk0p1

…even with “-r” the “-k DTB” is still required or it doesn’t know you want to flash only that particular partition.

So I’m testing with:

sudo ./ -r <b>-k DTB</b> -d ./kernel/dtb/tegra210-jetson-tx1-p2597-2180-a01-devkit.dtb jetson-tx1 mmcblk0p1

I can verify this flashed and booted correctly on my TX1.

Here’s an additional note on this. In the past the GPT partition labels differed between the TX1 and TX2…“DTB” was only for TX2, the TX1 had used “kernel-dtb” instead. At R28.2 they both seem to have unified partition labels and “DTB” is valid for both the TX1 and TX2.

Also, I had got the “-r” command from another post and had not verified by actual flashing…sorry, I should have. I had assumed (and should not have) that naming the device tree file would tell to flash device tree…but it does not. You will still need to use “-k DTB”. If partition labels change in the future it will be a good idea to verify you have “DTB” with “sudo gdisk -l /dev/mmcblk0”.

Thanks for the awesome help. I couldn’t find any info about the -k option (sudo find / -iname flash.cfg => no result), but I see how it is used now.

I am still struggling to find a way to control that load switch. It looks like the GPIO should be owned by the xhci-tegra driver. In an #ifdef CONFIG_PM block there are some useful looking static functions, but I can’t find any way to interface with them either directly or indirectly without hacking the kernel driver. It appears that the PMIC supports shutting down USB in suspend mode which is almost exactly what I want, but I seem to be overlooking some critical piece of information. Can anybody give me some pointers on turning off USB power? I want to completely disable the USB port before I put the device to sleep and leave it off until the device is awakened.

I can’t help on the specifics, just advise to check that “/proc/device-tree/” reflects changes you made to know if dtb edits actually participated.

In general it sounds like you need to find out how to have USB manually enter or leave suspend mode (versus auto-suspend). I know how to disable auto-suspend, but I don’t know how to manually force one mode or the other outside of normal system function.

Sorry, I should have been more clear, but the suspend mode I am referring to isn’t the USB suspend, it’s the LP0 sleep mode of the device, I think - power manager suspend.

I think that when the Jetson is sleeping (LP0), USB devices are told to suspend but it will still wake on a change via the PMC sleepwalker monitoring it. While the bus devices are told to suspend, it doesn’t make a difference to me because the USB camera I’m using doesn’t support the USB suspend mode.

This is where I need the PMIC to actually switch off the 5V power bus feeding the USB port to disable the IR LEDs from drawing the battery down and engaging the lower safety limit of the solar charge controller. The xhci-tegra driver seems to enable powergating and it’s defined in the device tree. Is there a way to check which options the default 28.2 kernel was compiled with? If this option was disabled than it makes perfect sense why it behaves the way it does. If it was enabled for the compilation, then my problem is likely in the device tree…

xhci-tegra.c: 244-256

static struct of_device_id tegra_xusba_pd[] = {
	{ .compatible = "nvidia,tegra186-xusba-pd", },
	{ .compatible = "nvidia,tegra210-xusba-pd", },

static struct of_device_id tegra_xusbc_pd[] = {
	{ .compatible = "nvidia,tegra186-xusbc-pd", },
	{ .compatible = "nvidia,tegra210-xusbc-pd", },

Typically USB ties its modes to the system’s modes. Are you trying to force USB to change differently than the system? Or perhaps trying force the system to a given state in order to get USB to follow? What would you like to see occur and what would you like to trigger that occurrence?

The result I am looking for is the 5V USB power to be off and disabled completely, either under my control or during sleep. If it was under my control, I would immediately put the system to sleep after disabling it anyway. From what follows, I’m fairly certain the xhci-tegra driver is capable of disabling USB completely entering the LP0 sleep via writing “mem” to /sys/power/state.

Here USB and the system mode are different and can be controlled to do different things. And to be clear, the USB suspend mode if I remember correctly is not a hard suspend - some devices may follow the command and others may not suspend. I think mice and keyboards and maybe other human interface devices are the only ones that implement USB suspension. By LP0, I am referring to the system’s low power mode where it disables as much hardware as possible to conserve power via power-gating.

The concept schematic on page 3 gives a diagram of the power tree showing the load switches I want control over, specifically the one feeding the USB 3.0 Type A Connector. On page 6 you will find a pin labeles USB_VBUS_EN1. On page 8 this feeds the enable pin of a USB switch (APL3511CBI-TRG - a power switch designed for USB application). This output is the 5V output of the USB connector. The alternate control point would be the VDD_5V0_IO_SYS but that appears to come straight off a buck converter beyond control of software. So the premise I am working from is that USB_VBUS_EN1, being a GPIO is controllable somewhere.

The TRM defines power-gating as powering-off a partition. 12.6.13 APBDEV_PMC_PWRGATE_TOGGLE_0 is a programmable register that provides three bits to control XUSB A, B, and C, followed by the related clamping register. This is where things start getting fuzzy. For one, my extracted DTS is pointing to the wrong PWRGATE_TOGGLE register (0x14 - 0x16). The kernel source accurately defines it per the TRM (TEGRA210_POWER_DOMAIN_XUSB macros: 0x20 - 0x22 in /dt-bindings/soc/tegra210-powergate.h:37-39).


	partition_id_xusba = tegra_pd_get_powergate_id(tegra_xusba_pd);
	partition_id_xusba = TEGRA_POWERGATE_XUSBA;

My kernel has CONFIG_PM_GENERIC_DOMAINS enabled (per /proc/config.gz), so I expect it will be using the incorrect PWRGATE_TOGGLE register bit. The pmc.c file defines a set of TEGRA_POWERGATE_XUSB macros which are accurately labeled per the TRM; however, as noted the kernel is compiled to ignore them and read the configuration from the dtb.

tegra210-soc-power-domain.dsti:124-140; from the kernel source

xusba_pd: xusba-pd {
			compatible = "nvidia,tegra210-xusba-pd";
			#power-domain-cells = <0>;
			partition-id = <TEGRA210_POWER_DOMAIN_XUSBA>; // defined as <s>0x20</s> 20 in src

		xusbb_pd: xusbb-pd {
			compatible = "nvidia,tegra210-xusbb-pd";
			#power-domain-cells = <0>;
			partition-id = <TEGRA210_POWER_DOMAIN_XUSBB>; // defined as <s>0x21</s> 21 in src

		xusbc_pd: xusbc-pd {
			compatible = "nvidia,tegra210-xusbc-pd";
			#power-domain-cells = <0>;
			partition-id = <TEGRA210_POWER_DOMAIN_XUSBC>; // defined as <s>0x22</s> 22 in src

extracted.dts:968-984; the actual values that made it to the .dtb

xusba-pd {
			compatible = "nvidia,tegra210-xusba-pd";
			#power-domain-cells = <0x0>;
			partition-id = <0x14>;

		xusbb-pd {
			compatible = "nvidia,tegra210-xusbb-pd";
			#power-domain-cells = <0x0>;
			partition-id = <0x15>;

		xusbc-pd {
			compatible = "nvidia,tegra210-xusbc-pd";
			#power-domain-cells = <0x0>;
			partition-id = <0x16>;

Looking at the options and what I expect is the driver source, I should be able to modify the .dtb file again with the correct power management registers to achieve the result I want. I suspect that the power gating registers were configured to the CE0, C0NC, and an undefined address to enable the USB wake function to continue working even in LP0…

I’ll be working on this soon and update when I have a chance and confirm what happens when I change the dtb.

Something else that should be mentioned: in, there are several “readlink -f ${val}” commands. These will fail if the path passed to them contains spaces. When choosing a path, use underscores instead of spaces.

You are correct that suspend mode does provide a very tiny power to USB…this is part of the standard for USB. It was added for activities such as “wake up” from pressing a keyboard key or moving a mouse.

Someone else will have to suggest how to force USB standby power to actually be power completely off. Realize that this would likely result in re-enumerating devices each time you come back from what would have been a simple suspend. This may not be a problem for your case.