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).
xhci-tegra.c:2311-2315
#if IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)
partition_id_xusba = tegra_pd_get_powergate_id(tegra_xusba_pd);
#else
partition_id_xusba = TEGRA_POWERGATE_XUSBA;
#endif
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.