From 4b3e70e783906cf8b12b467d1a046ddeab695b94 Mon Sep 17 00:00:00 2001 From: Noel Georgi Date: Tue, 29 Mar 2022 19:44:44 +0530 Subject: [PATCH] chore: upstream u-boot for jetson nano Use upstream u-boot for Jetson Nano Signed-off-by: Noel Georgi --- u-boot/jetson_nano/patches/README.md | 17 + .../jetson_nano/patches/tegra-common.h.patch | 15 - u-boot/jetson_nano/patches/tegra.patch | 4325 +++++++++++++++++ .../patches/tegra210-common.h.patch | 35 - u-boot/pkg.yaml | 11 +- 5 files changed, 4345 insertions(+), 58 deletions(-) create mode 100644 u-boot/jetson_nano/patches/README.md delete mode 100644 u-boot/jetson_nano/patches/tegra-common.h.patch create mode 100644 u-boot/jetson_nano/patches/tegra.patch delete mode 100644 u-boot/jetson_nano/patches/tegra210-common.h.patch diff --git a/u-boot/jetson_nano/patches/README.md b/u-boot/jetson_nano/patches/README.md new file mode 100644 index 000000000..d9b266afb --- /dev/null +++ b/u-boot/jetson_nano/patches/README.md @@ -0,0 +1,17 @@ +# Jetson Nano u-boot + +The patches for the jetson nano u-boot are copied over from the [OpenEmbedded for Tegra project](https://github.com/OE4T/u-boot-tegra) + +The OE4T project maintains patches from the NVIDA Tegra u-boot in upstream u-boot. The patches branch can be identified with the `patches-` prefix. + +The diff is generated by looking at the commit history for the `patches-` branch and doing a diff between `HEAD` and the upstream u-boot release. + +Eg: + +For the `v2022.01` release of u-boot we'd be using `patches-v2022.01` branch of the OE4T project. + +The diff is generated as: + +`git diff d637294e264adfeb29f390dfc393106fd4d41b17 HEAD --no-prefix` + +where commit `d637294e264adfeb29f390dfc393106fd4d41b17` is the commit that started of the upstream u-boot [release](https://github.com/OE4T/u-boot-tegra/commit/d637294e264adfeb29f390dfc393106fd4d41b17). diff --git a/u-boot/jetson_nano/patches/tegra-common.h.patch b/u-boot/jetson_nano/patches/tegra-common.h.patch deleted file mode 100644 index 3df5fc071..000000000 --- a/u-boot/jetson_nano/patches/tegra-common.h.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- include/configs/tegra-common.h 2022-01-13 15:45:12.477983016 +0000 -+++ include/configs/tegra-common.h 2022-01-13 15:45:21.250066512 +0000 -@@ -52,6 +52,12 @@ - /* Boot Argument Buffer Size */ - #define CONFIG_SYS_BARGSIZE (CONFIG_SYS_CBSIZE) - -+#ifdef CONFIG_ARM64 -+#define FDTFILE "nvidia/" CONFIG_DEFAULT_DEVICE_TREE ".dtb" -+#else -+#define FDTFILE CONFIG_DEFAULT_DEVICE_TREE ".dtb" -+#endif -+ - #define CONFIG_SYS_MEMTEST_START (NV_PA_SDRC_CS0 + 0x600000) - #define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + 0x100000) - diff --git a/u-boot/jetson_nano/patches/tegra.patch b/u-boot/jetson_nano/patches/tegra.patch new file mode 100644 index 000000000..6ab3b93d3 --- /dev/null +++ b/u-boot/jetson_nano/patches/tegra.patch @@ -0,0 +1,4325 @@ +diff --git arch/arm/dts/Makefile arch/arm/dts/Makefile +index b3e2a9c9d7..8f8dc007df 100644 +--- arch/arm/dts/Makefile ++++ arch/arm/dts/Makefile +@@ -222,7 +222,9 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ + tegra210-p2371-0000.dtb \ + tegra210-p2371-2180.dtb \ + tegra210-p2571.dtb \ +- tegra210-p3450-0000.dtb ++ tegra210-p3450-0000.dtb \ ++ tegra210-p3541-0000.dtb \ ++ tegra186-p3636-0001.dtb + + dtb-$(CONFIG_ARCH_MVEBU) += \ + armada-3720-db.dtb \ +diff --git arch/arm/dts/tegra186-p3636-0001.dts arch/arm/dts/tegra186-p3636-0001.dts +new file mode 100644 +index 0000000000..a9a4cf788a +--- /dev/null ++++ arch/arm/dts/tegra186-p3636-0001.dts +@@ -0,0 +1,32 @@ ++/dts-v1/; ++ ++#include "tegra186-p3636-0001.dtsi" ++ ++/ { ++ model = "NVIDIA P3636-0001"; ++ compatible = "nvidia,p3636-0001", "nvidia,tegra186"; ++ ++ sdhci@3400000 { ++ cd-gpios = <&gpio_main TEGRA_MAIN_GPIO(P, 5) GPIO_ACTIVE_LOW>; ++ power-gpios = <&gpio_main TEGRA_MAIN_GPIO(P, 6) GPIO_ACTIVE_HIGH>; ++ }; ++ ++ pcie@10003000 { ++ status = "okay"; ++ ++ pci@1,0 { ++ status = "okay"; ++ nvidia,num-lanes = <4>; ++ }; ++ ++ pci@2,0 { ++ status = "disabled"; ++ nvidia,num-lanes = <0>; ++ }; ++ ++ pci@3,0 { ++ status = "disabled"; ++ nvidia,num-lanes = <1>; ++ }; ++ }; ++}; +diff --git arch/arm/dts/tegra186-p3636-0001.dtsi arch/arm/dts/tegra186-p3636-0001.dtsi +new file mode 100644 +index 0000000000..192563092f +--- /dev/null ++++ arch/arm/dts/tegra186-p3636-0001.dtsi +@@ -0,0 +1,84 @@ ++#include "tegra186.dtsi" ++ ++/ { ++ model = "NVIDIA P3636-0001"; ++ compatible = "nvidia,p3636-0001", "nvidia,tegra186"; ++ ++ chosen { ++ stdout-path = &uarta; ++ }; ++ ++ aliases { ++ ethernet = "/ethernet@2490000"; ++ mmc0 = "/sdhci@3460000"; ++ mmc1 = "/sdhci@3400000"; ++ i2c0 = "/bpmp/i2c"; ++ i2c1 = "/i2c@3160000"; ++ i2c2 = "/i2c@c240000"; ++ i2c3 = "/i2c@3180000"; ++ i2c4 = "/i2c@3190000"; ++ i2c5 = "/i2c@31c0000"; ++ i2c6 = "/i2c@c250000"; ++ i2c7 = "/i2c@31e0000"; ++ }; ++ ++ memory { ++ reg = <0x0 0x80000000 0x0 0x60000000>; ++ }; ++ ++ ethernet@2490000 { ++ status = "okay"; ++ phy-reset-gpios = <&gpio_main TEGRA_MAIN_GPIO(M, 4) GPIO_ACTIVE_LOW>; ++ local-mac-address = [ 00 00 00 00 00 00 ]; ++ }; ++ ++ i2c@3160000 { ++ status = "okay"; ++ }; ++ ++ i2c@3180000 { ++ status = "okay"; ++ }; ++ ++ i2c@3190000 { ++ status = "okay"; ++ }; ++ ++ i2c@31c0000 { ++ status = "okay"; ++ }; ++ ++ sdhci@3400000 { ++ status = "okay"; ++ wp-gpios = <&gpio_main TEGRA_MAIN_GPIO(P, 4) GPIO_ACTIVE_HIGH>; ++ bus-width = <4>; ++ }; ++ ++ sdhci@3460000 { ++ status = "okay"; ++ bus-width = <8>; ++ non-removable; ++ }; ++ ++ i2c@c240000 { ++ status = "okay"; ++ }; ++ ++ i2c@c250000 { ++ status = "okay"; ++ }; ++ ++ i2c@31e0000 { ++ status = "okay"; ++ }; ++ ++ bpmp { ++ i2c { ++ status = "okay"; ++ }; ++ }; ++}; ++ ++&uarta { ++ status = "okay"; ++}; +diff --git arch/arm/dts/tegra210-p2371-2180.dts arch/arm/dts/tegra210-p2371-2180.dts +index 649c163152..fc749e388b 100644 +--- arch/arm/dts/tegra210-p2371-2180.dts ++++ arch/arm/dts/tegra210-p2371-2180.dts +@@ -17,6 +17,7 @@ + mmc0 = "/sdhci@700b0600"; + mmc1 = "/sdhci@700b0000"; + usb0 = "/usb@7d000000"; ++ usb1 = "/xusb@70090000"; + }; + + memory { +@@ -108,6 +109,11 @@ + nvidia,vbus-gpio = <&gpio TEGRA_GPIO(CC, 4) GPIO_ACTIVE_HIGH>; + }; + ++ xusb@70090000 { ++ status = "okay"; ++ nvidia,vbus-gpio = <&gpio TEGRA_GPIO(CC, 5) GPIO_ACTIVE_HIGH>; ++ }; ++ + clocks { + compatible = "simple-bus"; + #address-cells = <1>; +diff --git arch/arm/dts/tegra210-p3450-0000.dts arch/arm/dts/tegra210-p3450-0000.dts +index 9ef744ac8b..e19f5825b8 100644 +--- arch/arm/dts/tegra210-p3450-0000.dts ++++ arch/arm/dts/tegra210-p3450-0000.dts +@@ -24,6 +24,7 @@ + mmc1 = "/sdhci@700b0000"; + spi0 = "/spi@70410000"; + usb0 = "/usb@7d000000"; ++ usb1 = "/xusb@70090000"; + }; + + memory { +@@ -132,6 +133,11 @@ + dr_mode = "peripheral"; + }; + ++ xusb@70090000 { ++ status = "okay"; ++ nvidia,vbus-gpio = <&gpio TEGRA_GPIO(A, 6) GPIO_ACTIVE_HIGH>; ++ }; ++ + clocks { + compatible = "simple-bus"; + #address-cells = <1>; +diff --git arch/arm/dts/tegra210-p3541-0000.dts arch/arm/dts/tegra210-p3541-0000.dts +new file mode 100644 +index 0000000000..e14d14cad5 +--- /dev/null ++++ arch/arm/dts/tegra210-p3541-0000.dts +@@ -0,0 +1,149 @@ ++/dts-v1/; ++ ++#include "tegra210.dtsi" ++ ++/ { ++ model = "NVIDIA P3541-0000"; ++ compatible = "nvidia,p3541-0000", "nvidia,tegra210"; ++ ++ chosen { ++ stdout-path = &uarta; ++ }; ++ ++ aliases { ++ ethernet = "/pcie@1003000/pci@2,0/ethernet@0,0"; ++ i2c0 = "/i2c@7000d000"; ++ i2c2 = "/i2c@7000c400"; ++ i2c3 = "/i2c@7000c500"; ++ i2c4 = "/i2c@7000c700"; ++ mmc0 = "/sdhci@700b0600"; ++ mmc1 = "/sdhci@700b0000"; ++ spi0 = "/spi@70410000"; ++ usb0 = "/usb@7d000000"; ++ usb1 = "/xusb@70090000"; ++ }; ++ ++ memory { ++ reg = <0x0 0x80000000 0x0 0xc0000000>; ++ }; ++ ++ pcie@1003000 { ++ status = "okay"; ++ ++ pci@1,0 { ++ status = "okay"; ++ }; ++ ++ pci@2,0 { ++ status = "okay"; ++ ++ ethernet@0,0 { ++ reg = <0x000000 0 0 0 0>; ++ local-mac-address = [ 00 00 00 00 00 00 ]; ++ }; ++ }; ++ }; ++ ++ serial@70006000 { ++ status = "okay"; ++ }; ++ ++ padctl@7009f000 { ++ pinctrl-0 = <&padctl_default>; ++ pinctrl-names = "default"; ++ ++ padctl_default: pinmux { ++ xusb { ++ nvidia,lanes = "otg-1", "otg-2"; ++ nvidia,function = "xusb"; ++ nvidia,iddq = <0>; ++ }; ++ ++ usb3 { ++ nvidia,lanes = "pcie-5", "pcie-6"; ++ nvidia,function = "usb3"; ++ nvidia,iddq = <0>; ++ }; ++ ++ pcie-x1 { ++ nvidia,lanes = "pcie-0"; ++ nvidia,function = "pcie-x1"; ++ nvidia,iddq = <0>; ++ }; ++ ++ pcie-x4 { ++ nvidia,lanes = "pcie-1", "pcie-2", ++ "pcie-3", "pcie-4"; ++ nvidia,function = "pcie-x4"; ++ nvidia,iddq = <0>; ++ }; ++ ++ sata { ++ nvidia,lanes = "sata-0"; ++ nvidia,function = "sata"; ++ nvidia,iddq = <0>; ++ }; ++ }; ++ }; ++ ++ sdhci@700b0000 { ++ status = "okay"; ++ cd-gpios = <&gpio TEGRA_GPIO(Z, 1) GPIO_ACTIVE_LOW>; ++ power-gpios = <&gpio TEGRA_GPIO(Z, 3) GPIO_ACTIVE_HIGH>; ++ bus-width = <4>; ++ }; ++ ++ sdhci@700b0600 { ++ status = "okay"; ++ bus-width = <8>; ++ non-removable; ++ }; ++ ++ i2c@7000c400 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ }; ++ ++ i2c@7000c500 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ }; ++ ++ i2c@7000c700 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ }; ++ ++ i2c@7000d000 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ }; ++ ++ spi@70410000 { ++ status = "okay"; ++ spi-max-frequency = <80000000>; ++ }; ++ ++ usb@7d000000 { ++ status = "okay"; ++ dr_mode = "peripheral"; ++ }; ++ ++ xusb@70090000 { ++ status = "okay"; ++ nvidia,vbus-gpio = <&gpio TEGRA_GPIO(A, 6) GPIO_ACTIVE_HIGH>; ++ }; ++ ++ clocks { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ clk32k_in: clock@0 { ++ compatible = "fixed-clock"; ++ reg = <0>; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ }; ++ }; ++}; +diff --git arch/arm/dts/tegra210.dtsi arch/arm/dts/tegra210.dtsi +index a521a43d6c..d1b5fbdfc4 100644 +--- arch/arm/dts/tegra210.dtsi ++++ arch/arm/dts/tegra210.dtsi +@@ -884,4 +884,11 @@ + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; + interrupt-parent = <&gic>; + }; ++ ++ xusb@70090000 { ++ compatible = "nvidia,tegra210-xhci"; ++ reg = <0x0 0x70090000 0x0 0x4000>; ++ #extcon-cells = <1>; ++ status = "okay"; ++ }; + }; +diff --git arch/arm/include/asm/arch-tegra/clock.h arch/arm/include/asm/arch-tegra/clock.h +index 1d80d9e946..5f9ccc65e1 100644 +--- arch/arm/include/asm/arch-tegra/clock.h ++++ arch/arm/include/asm/arch-tegra/clock.h +@@ -372,6 +372,19 @@ enum periph_id clk_id_to_periph_id(int clk_id); + */ + int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon); + ++/** ++ * Adjust peripheral PLL to use the given divider and source. ++ * ++ * @param periph_id peripheral to adjust ++ * @param source Source number (0-3 or 0-7) ++ * @param mux_bits Number of mux bits (2 or 4) ++ * @param divider Required divider in 7.1 or 15.1 format ++ * @return 0 if ok, -1 on error (requesting a parent clock which is not valid ++ * for this peripheral) ++ */ ++int adjust_periph_pll(enum periph_id periph_id, int source, int mux_bits, ++ unsigned divider); ++ + /* return 1 if a peripheral ID is in range */ + #define clock_type_id_isvalid(id) ((id) >= 0 && \ + (id) < CLOCK_TYPE_COUNT) +diff --git arch/arm/include/asm/arch-tegra210/clock-tables.h arch/arm/include/asm/arch-tegra210/clock-tables.h +index c6d7487e62..4149242a9f 100644 +--- arch/arm/include/asm/arch-tegra210/clock-tables.h ++++ arch/arm/include/asm/arch-tegra210/clock-tables.h +@@ -234,7 +234,7 @@ enum periph_id { + PERIPH_ID_W_RESERVED12, + PERIPH_ID_W_RESERVED13, + PERIPH_ID_XUSB_PADCTL, +- PERIPH_ID_W_RESERVED15, ++ PERIPH_ID_XUSB, + + /* 144 */ + PERIPH_ID_W_RESERVED16, +@@ -321,7 +321,7 @@ enum periph_id { + /* 208 */ + PERIPH_ID_VI_I2C, + PERIPH_ID_Y_RESERVED17, +- PERIPH_ID_Y_RESERVED18, ++ PERIPH_ID_USB2_TRK, + PERIPH_ID_QSPI, + PERIPH_ID_Y_RESERVED20, + PERIPH_ID_Y_RESERVED21, +diff --git arch/arm/mach-tegra/Makefile arch/arm/mach-tegra/Makefile +index 7165d70a60..4c107ec150 100644 +--- arch/arm/mach-tegra/Makefile ++++ arch/arm/mach-tegra/Makefile +@@ -21,6 +21,7 @@ obj-$(CONFIG_TEGRA_PMC) += powergate.o + obj-y += xusb-padctl-dummy.o + + obj-$(CONFIG_ARM64) += arm64-mmu.o cboot.o ++obj-y += dt-edit.o + obj-y += dt-setup.o + obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o + obj-$(CONFIG_TEGRA_GPU) += gpu.o +diff --git arch/arm/mach-tegra/ap.c arch/arm/mach-tegra/ap.c +index 532730fe72..45544e96f1 100644 +--- arch/arm/mach-tegra/ap.c ++++ arch/arm/mach-tegra/ap.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* +- * (C) Copyright 2010-2015 ++ * (C) Copyright 2010-2015,2021 + * NVIDIA Corporation + */ + +@@ -151,8 +151,7 @@ static u32 get_odmdata(void) + + static void init_pmc_scratch(void) + { +- struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +- u32 odmdata; ++ u32 odmdata, ofs; + int i; + + /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */ +@@ -160,13 +159,15 @@ static void init_pmc_scratch(void) + if (!tegra_cpu_is_non_secure()) + #endif + { ++ ofs = offsetof(struct pmc_ctlr, pmc_scratch1); + for (i = 0; i < 23; i++) +- writel(0, &pmc->pmc_scratch1 + i); ++ tegra_pmc_writel(0, ofs + (i * 4)); + } + + /* ODMDATA is for kernel use to determine RAM size, LP config, etc. */ + odmdata = get_odmdata(); +- writel(odmdata, &pmc->pmc_scratch20); ++ ofs = offsetof(struct pmc_ctlr, pmc_scratch20); ++ tegra_pmc_writel(odmdata, ofs); + } + + #ifdef CONFIG_ARMV7_SECURE_RESERVE_SIZE +diff --git arch/arm/mach-tegra/cboot.c arch/arm/mach-tegra/cboot.c +index 55eb819860..55c880a966 100644 +--- arch/arm/mach-tegra/cboot.c ++++ arch/arm/mach-tegra/cboot.c +@@ -5,6 +5,9 @@ + + #include + #include ++#ifdef CONFIG_TEGRA210 ++#include ++#endif + #include + #include + #include +@@ -592,6 +595,139 @@ static char *cboot_get_bootargs(const void *fdt) + return strip(args); + } + ++#if defined(CONFIG_TEGRA210) ++static enum env_location parse_env_drv_from_ids(const void *fdt, int offset) ++{ ++ const struct fdt_property *prop = NULL; ++ const char *name; ++ int i; ++ static const struct env_drv { ++ const char *name; /* IDs */ ++ enum env_location loc; /* Env driver need to skip */ ++ } env_drv[] = { ++ {"3448-0000", ENVL_MMC}, ++ {"3448-0002", ENVL_SPI_FLASH} ++ }; ++ ++ prop = fdt_get_property_by_offset(fdt, offset, NULL); ++ if (!prop) ++ goto out; ++ ++ name = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff), NULL); ++ if (!name) ++ goto out; ++ ++ for (i = 0; i < sizeof(env_drv) / sizeof(struct env_drv); i++) { ++ if (!strncmp(name, env_drv[i].name, 9)) ++ return env_drv[i].loc; ++ } ++ ++out: ++ return ENVL_UNKNOWN; ++} ++ ++static struct env_driver *cboot_env_driver_lookup(enum env_location loc) ++{ ++ struct env_driver *drv; ++ const int n_ents = ll_entry_count(struct env_driver, env_driver); ++ struct env_driver *entry; ++ ++ drv = ll_entry_start(struct env_driver, env_driver); ++ for (entry = drv; entry != drv + n_ents; entry++) { ++ if (loc == entry->location) ++ return entry; ++ } ++ ++ /* Not found */ ++ return NULL; ++} ++ ++/* ++ * If current board is Nano eMMC board, set QSPI driver load function ++ * to NULL, env_load() function will skip trying to load env from QSPI; ++ * if current board is Nano QSPI+SD board, set eMMC driver load function ++ * to NULL, env_load() function will skip trying to load env from eMMC. ++ */ ++void tegra210_env_drv_config(void) ++{ ++ struct env_driver *drv = NULL; ++ int offset_node; ++ int offset_first, offset_next; ++ int i; ++ enum env_location loc = ENVL_UNKNOWN; ++ const void *fdt = (const void *)cboot_boot_x0; ++ ++ offset_node = fdt_path_offset(fdt, "/chosen/plugin-manager/ids"); ++ if (offset_node < 0) { ++ printf("%s: find node offset error %d\n", ++ __func__, offset_node); ++ goto out; ++ } ++ ++ offset_first = fdt_first_property_offset(fdt, offset_node); ++ if (offset_first < 0) { ++ printf("%s: find priority offset error %d\n", ++ __func__, offset_first); ++ goto out; ++ } ++ ++ loc = parse_env_drv_from_ids(fdt, offset_first); ++ if (loc != ENVL_UNKNOWN) ++ goto out; ++ ++ for (i = 1; ; i++) { ++ offset_next = fdt_next_property_offset(fdt, offset_first); ++ if (offset_next > 0) { ++ offset_first = offset_next; ++ loc = parse_env_drv_from_ids(fdt, offset_next); ++ if (loc != ENVL_UNKNOWN) ++ break; ++ } else { ++ /* Failed to find properties */ ++ break; ++ } ++ } ++ ++out: ++ drv = cboot_env_driver_lookup(loc); ++ if (drv) ++ drv->load = NULL; ++} ++ ++#if defined(CBOOT_RP4_LOAD) ++int cboot_get_xusb_fw_addr(void) ++{ ++ int node, len, err; ++ const u32 *prop; ++ u32 fw_addr; ++ void *fdt; ++ ++ fdt = (void *)env_get_hex("fdt_addr_r", cboot_boot_x0); ++ ++ node = fdt_path_offset(fdt, "/xusb"); ++ if (node < 0) { ++ printf("xusb node NOT found!"); ++ err = -ENOENT; ++ goto out; ++ } ++ ++ prop = fdt_getprop(fdt, node, "nvidia,xusb-firmware-load-addr", &len); ++ if (!prop) { ++ printf("xusb property NOT found!\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ ++ fw_addr = be32_to_cpu(*prop); ++ debug("XUSB FW address = %X\n", fw_addr); ++ err = env_set_hex("xusb_fw_addr", fw_addr); ++ ++out: ++ return err; ++} ++#endif /* CBOOT_RP4_LOAD */ ++#endif /* T210 */ ++ + int cboot_late_init(void) + { + const void *fdt = (const void *)cboot_boot_x0; +@@ -622,5 +758,11 @@ int cboot_late_init(void) + free(bootargs); + } + ++#if defined(CBOOT_RP4_LOAD) ++ /* T210 XUSB ONLY: get XUSB FW load address from CBoot */ ++ if (cboot_get_xusb_fw_addr()) ++ printf("%s: Failed to get XUSB FW address! err: %d\n", ++ __func__, err); ++#endif + return 0; + } +diff --git arch/arm/mach-tegra/clock.c arch/arm/mach-tegra/clock.c +index 18c19dbf60..910047937d 100644 +--- arch/arm/mach-tegra/clock.c ++++ arch/arm/mach-tegra/clock.c +@@ -406,7 +406,7 @@ static int find_best_divider(unsigned divider_bits, unsigned long parent_rate, + * @return 0 if ok, -1 on error (requesting a parent clock which is not valid + * for this peripheral) + */ +-static int adjust_periph_pll(enum periph_id periph_id, int source, ++int adjust_periph_pll(enum periph_id periph_id, int source, + int mux_bits, unsigned divider) + { + u32 *reg = get_periph_source_reg(periph_id); +diff --git arch/arm/mach-tegra/dt-edit.c arch/arm/mach-tegra/dt-edit.c +new file mode 100644 +index 0000000000..c551df009a +--- /dev/null ++++ arch/arm/mach-tegra/dt-edit.c +@@ -0,0 +1,385 @@ ++/* ++ * Copyright (C) 2010-2021 NVIDIA CORPORATION. ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++#define LOG_CATEGORY LOGC_ARCH ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dt-edit.h" ++ ++#define fdt_for_each_property(fdt, prop, parent) \ ++ for (prop = fdt_first_property_offset(fdt, parent); \ ++ prop >= 0; \ ++ prop = fdt_next_property_offset(fdt, prop)) ++typedef int iter_envitem(void *blob_dst, char *item, void *param); ++ ++static int fdt_copy_node_content(void *blob_src, int ofs_src, void *blob_dst, ++ int ofs_dst, int indent) ++{ ++ int ofs_src_child, ofs_dst_child; ++ ++ /* ++ * FIXME: This doesn't remove properties or nodes in the destination ++ * that are not present in the source. For the nodes we care about ++ * right now, this is not an issue. ++ */ ++ ++ /* Don't copy a node's contents if the phandles don't match */ ++ ++ debug("%s: Getting phandles ....\n", __func__); ++ ++ u32 src_phandle = fdt_get_phandle(blob_src, ofs_src); ++ if (!src_phandle) { ++ debug("%s: No phandle in this node, copying content ...\n", ++ __func__); ++ } else { ++ debug("%s: src phandle = %X\n", __func__, src_phandle); ++ ++ u32 dst_phandle = fdt_get_phandle(blob_dst, ofs_dst); ++ debug("%s: dst phandle = %X\n", __func__, dst_phandle); ++ ++ ++ if (src_phandle != dst_phandle) { ++ const char *node_name = fdt_get_name(blob_src, ofs_src, ++ NULL); ++ ++ printf("WARNING: phandle mismatch was found in node "); ++ printf("'%s'\n. It will not be updated in the " ++ "destination DTB.\n", node_name); ++ return FDT_ERR_NOTFOUND; /* skip this node */ ++ } ++ } ++ ++ fdt_for_each_property(blob_src, ofs_src_child, ofs_src) { ++ const void *prop; ++ const char *name; ++ int len, ret; ++ ++ prop = fdt_getprop_by_offset(blob_src, ofs_src_child, &name, ++ &len); ++ log_debug("%s: %*scopy prop: %s\n", __func__, indent, "", name); ++ ++ ret = fdt_setprop(blob_dst, ofs_dst, name, prop, len); ++ if (ret < 0) { ++ pr_err("Can't copy DT prop %s\n", name); ++ return ret; ++ } ++ } ++ ++ fdt_for_each_subnode(ofs_src_child, blob_src, ofs_src) { ++ const char *name; ++ ++ name = fdt_get_name(blob_src, ofs_src_child, NULL); ++ log_debug("%s: %*scopy node: %s\n", __func__, indent, "", name); ++ ++ ofs_dst_child = fdt_subnode_offset(blob_dst, ofs_dst, name); ++ if (ofs_dst_child < 0) { ++ log_debug("%s: %*s(creating it in dst)\n", __func__, ++ indent, ""); ++ ofs_dst_child = fdt_add_subnode(blob_dst, ofs_dst, ++ name); ++ if (ofs_dst_child < 0) { ++ pr_err("Can't copy DT node %s\n", name); ++ return ofs_dst_child; ++ } ++ } ++ ++ fdt_copy_node_content(blob_src, ofs_src_child, blob_dst, ++ ofs_dst_child, indent + 2); ++ } ++ ++ return 0; ++} ++ ++static int fdt_add_path(void *blob, const char *path) ++{ ++ char *pcopy, *tmp, *node; ++ int ofs_parent, ofs_child, ret; ++ ++ if (path[0] != '/') { ++ pr_err("Can't add path %s; missing leading /", path); ++ return -1; ++ } ++ path++; ++ if (!*path) { ++ log_debug("%s: path points at DT root!", __func__); ++ return 0; ++ } ++ ++ pcopy = strdup(path); ++ if (!pcopy) { ++ pr_err("strdup() failed"); ++ return -1; ++ } ++ ++ tmp = pcopy; ++ ofs_parent = 0; ++ while (true) { ++ node = strsep(&tmp, "/"); ++ if (!node) ++ break; ++ log_debug("%s: node=%s\n", __func__, node); ++ ofs_child = fdt_subnode_offset(blob, ofs_parent, node); ++ if (ofs_child < 0) ++ ofs_child = fdt_add_subnode(blob, ofs_parent, node); ++ if (ofs_child < 0) { ++ pr_err("Can't create DT node %s\n", node); ++ ret = ofs_child; ++ goto out; ++ } ++ ofs_parent = ofs_child; ++ } ++ ret = ofs_parent; ++ ++out: ++ free(pcopy); ++ ++ return ret; ++} ++ ++static iter_envitem fdt_iter_copy_prop; ++static int fdt_iter_copy_prop(void *blob_dst, char *prop_path, void *blob_src) ++{ ++ char *prop_name, *node_path; ++ const void *prop; ++ int ofs_src, ofs_dst, len, ret; ++ ++ prop_name = strrchr(prop_path, '/'); ++ if (!prop_name) { ++ pr_err("Can't copy prop %s; missing /", prop_path); ++ return -1; ++ } ++ *prop_name = 0; ++ prop_name++; ++ node_path = prop_path; ++ ++ if (*node_path) { ++ ofs_src = fdt_path_offset(blob_src, node_path); ++ if (ofs_src < 0) { ++ pr_err("DT node %s missing in source; can't copy %s\n", ++ node_path, prop_name); ++ return -1; ++ } ++ ++ ofs_dst = fdt_path_offset(blob_dst, node_path); ++ if (ofs_src < 0) { ++ pr_err("DT node %s missing in dest; can't copy prop %s\n", ++ node_path, prop_name); ++ return -1; ++ } ++ } else { ++ ofs_src = 0; ++ ofs_dst = 0; ++ } ++ ++ prop = fdt_getprop(blob_src, ofs_src, prop_name, &len); ++ if (!prop) { ++ pr_err("DT property %s/%s missing in source; can't copy\n", ++ node_path, prop_name); ++ return -1; ++ } ++ ++ ret = fdt_setprop(blob_dst, ofs_dst, prop_name, prop, len); ++ if (ret < 0) { ++ pr_err("Can't set DT prop %s/%s\n", node_path, prop_name); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static iter_envitem fdt_iter_copy_node; ++static int fdt_iter_copy_node(void *blob_dst, char *path, void *blob_src) ++{ ++ int ofs_dst, ofs_src; ++ int ret; ++ ++ ofs_dst = fdt_add_path(blob_dst, path); ++ if (ofs_dst < 0) { ++ pr_err("Can't find/create dest DT node %s to copy\n", path); ++ return ofs_dst; ++ } ++ ++ if (!fdtdec_get_is_enabled(blob_dst, ofs_dst)) { ++ log_debug("%s: DT node %s disabled in dest; skipping copy\n", ++ __func__, path); ++ return 0; ++ } ++ ++ ofs_src = fdt_path_offset(blob_src, path); ++ if (ofs_src < 0) { ++ pr_err("DT node %s missing in source; can't copy\n", path); ++ return 0; ++ } ++ ++ ret = fdt_copy_node_content(blob_src, ofs_src, blob_dst, ++ ofs_dst, 2); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static iter_envitem fdt_iter_del_node; ++static int fdt_iter_del_node(void *blob_dst, char *node_path, void *unused_param) ++{ ++ int ofs; ++ ++ ofs = fdt_path_offset(blob_dst, node_path); ++ /* Node doesn't exist -> property can't exist -> it's removed! */ ++ if (ofs == -FDT_ERR_NOTFOUND) ++ return 0; ++ if (ofs < 0) { ++ pr_err("DT node %s lookup failure; can't del node\n", node_path); ++ return ofs; ++ } ++ ++ return fdt_del_node(blob_dst, ofs); ++} ++ ++static iter_envitem fdt_iter_del_prop; ++static int fdt_iter_del_prop(void *blob_dst, char *prop_path, void *unused_param) ++{ ++ char *prop_name, *node_path; ++ int ofs, ret; ++ ++ prop_name = strrchr(prop_path, '/'); ++ if (!prop_name) { ++ pr_err("Can't del prop %s; missing /", prop_path); ++ return -1; ++ } ++ *prop_name = 0; ++ prop_name++; ++ node_path = prop_path; ++ ++ if (*node_path) { ++ ofs = fdt_path_offset(blob_dst, node_path); ++ /* Node doesn't exist -> property can't exist -> it's removed! */ ++ if (ofs == -FDT_ERR_NOTFOUND) ++ return 0; ++ if (ofs < 0) { ++ pr_err("DT node %s lookup failure; can't del prop %s\n", ++ node_path, prop_name); ++ return ofs; ++ } ++ } else { ++ ofs = 0; ++ } ++ ++ ret = fdt_delprop(blob_dst, ofs, prop_name); ++ /* Property doesn't exist -> it's already removed! */ ++ if (ret == -FDT_ERR_NOTFOUND) ++ return 0; ++ return ret; ++} ++ ++static int fdt_iter_envlist(iter_envitem *func, void *blob_dst, const char *env_varname, void *param) ++{ ++ char *items, *tmp, *item; ++ int ret; ++ ++ items = env_get(env_varname); ++ if (!items) { ++ log_debug("%s: No env var %s\n", __func__, env_varname); ++ return 0; ++ } ++ ++ items = strdup(items); ++ if (!items) { ++ pr_err("strdup(%s) failed", env_varname); ++ return -1; ++ } ++ ++ tmp = items; ++ while (true) { ++ item = strsep(&tmp, ":"); ++ if (!item) ++ break; ++ log_debug("%s: item: %s\n", __func__, item); ++ ret = func(blob_dst, item, param); ++ if (ret < 0) { ++ ret = -1; ++ goto out; ++ } ++ } ++ ++ ret = 0; ++ ++out: ++ free(items); ++ ++ return ret; ++} ++ ++__weak void *fdt_copy_get_blob_src_default(void) ++{ ++ return NULL; ++} ++ ++static void *no_self_copy(void *blob_src, void *blob_dst) ++{ ++ if (blob_src == blob_dst) ++ return NULL; ++ return blob_src; ++} ++ ++static void *fdt_get_copy_blob_src(void *blob_dst) ++{ ++ char *src_addr_s; ++ ++ src_addr_s = env_get("fdt_copy_src_addr"); ++ if (!src_addr_s) ++ return no_self_copy(fdt_copy_get_blob_src_default(), blob_dst); ++ return no_self_copy((void *)simple_strtoul(src_addr_s, NULL, 16), ++ blob_dst); ++} ++ ++int fdt_copy_env_nodelist(void *blob_dst) ++{ ++ void *blob_src; ++ ++ log_debug("%s:\n", __func__); ++ ++ blob_src = fdt_get_copy_blob_src(blob_dst); ++ if (!blob_src) { ++ log_debug("%s: No source DT\n", __func__); ++ return 0; ++ } ++ ++ return fdt_iter_envlist(fdt_iter_copy_node, blob_dst, "fdt_copy_node_paths", blob_src); ++} ++ ++int fdt_copy_env_proplist(void *blob_dst) ++{ ++ void *blob_src; ++ ++ log_debug("%s:\n", __func__); ++ ++ blob_src = fdt_get_copy_blob_src(blob_dst); ++ if (!blob_src) { ++ log_debug("%s: No source DT\n", __func__); ++ return 0; ++ } ++ ++ return fdt_iter_envlist(fdt_iter_copy_prop, blob_dst, "fdt_copy_prop_paths", blob_src); ++} ++ ++int fdt_del_env_nodelist(void *blob_dst) ++{ ++ log_debug("%s:\n", __func__); ++ ++ return fdt_iter_envlist(fdt_iter_del_node, blob_dst, "fdt_del_node_paths", NULL); ++} ++ ++int fdt_del_env_proplist(void *blob_dst) ++{ ++ log_debug("%s:\n", __func__); ++ ++ return fdt_iter_envlist(fdt_iter_del_prop, blob_dst, "fdt_del_prop_paths", NULL); ++} +diff --git arch/arm/mach-tegra/dt-edit.h arch/arm/mach-tegra/dt-edit.h +new file mode 100644 +index 0000000000..c2763aa8a7 +--- /dev/null ++++ arch/arm/mach-tegra/dt-edit.h +@@ -0,0 +1,12 @@ ++/* ++ * Copyright (C) 2010-2019 NVIDIA CORPORATION. ++ * ++ * SPDX-License-Identifier: GPL-2.0 ++ */ ++ ++void *fdt_copy_get_blob_src_default(void); ++ ++int fdt_copy_env_proplist(void *blob_dst); ++int fdt_copy_env_nodelist(void *blob_dst); ++int fdt_del_env_nodelist(void *blob_dst); ++int fdt_del_env_proplist(void *blob_dst); +diff --git arch/arm/mach-tegra/dt-setup.c arch/arm/mach-tegra/dt-setup.c +index c11494722b..e389f06e76 100644 +--- arch/arm/mach-tegra/dt-setup.c ++++ arch/arm/mach-tegra/dt-setup.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* +- * Copyright (c) 2010-2016, NVIDIA CORPORATION. ++ * Copyright (c) 2010-2019, NVIDIA CORPORATION. + */ + + #include +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include "dt-edit.h" + + /* + * This function is called right before the kernel is booted. "blob" is the +@@ -32,6 +33,11 @@ int ft_system_setup(void *blob, struct bd_info *bd) + return ret; + } + ++ fdt_del_env_nodelist(blob); ++ fdt_del_env_proplist(blob); ++ fdt_copy_env_nodelist(blob); ++ fdt_copy_env_proplist(blob); ++ + return 0; + } + +diff --git arch/arm/mach-tegra/tegra186/Kconfig arch/arm/mach-tegra/tegra186/Kconfig +index b2e53b58ca..2639120959 100644 +--- arch/arm/mach-tegra/tegra186/Kconfig ++++ arch/arm/mach-tegra/tegra186/Kconfig +@@ -1,4 +1,4 @@ +-# Copyright (c) 2016, NVIDIA CORPORATION. ++# Copyright (c) 2016-2020, NVIDIA CORPORATION. + # + # SPDX-License-Identifier: GPL-2.0 + +@@ -16,11 +16,21 @@ config TARGET_P2771_0000 + micro-B port, Ethernet, USB3 host port, SATA, PCIe, and two GPIO + expansion headers. + ++config TARGET_P3636_0001 ++ bool "NVIDIA Tegra186 P3636-0001 board" ++ select BOARD_LATE_INIT ++ help ++ P3636-0001 is a Lanai CVM module married to a P3449/P3509 CVB ++ baseboard. The combination contains SoC, DRAM, eMMC, HDMI, USB ++ micro-B port, Ethernet, USB3 host port, SATA, PCIe, and a GPIO ++ expansion header. ++ + endchoice + + config SYS_SOC + default "tegra186" + + source "board/nvidia/p2771-0000/Kconfig" ++source "board/nvidia/p3636-0001/Kconfig" + + endif +diff --git arch/arm/mach-tegra/tegra210/Kconfig arch/arm/mach-tegra/tegra210/Kconfig +index 17f18cbf30..b6c53f5d3b 100644 +--- arch/arm/mach-tegra/tegra210/Kconfig ++++ arch/arm/mach-tegra/tegra210/Kconfig +@@ -33,6 +33,12 @@ config TARGET_P3450_0000 + help + P3450-0000 is a P3448 CPU board married to a P3449 I/O board. + ++config TARGET_P3541_0000 ++ bool "NVIDIA Jetson Nano 2GB Developer Kit" ++ select BOARD_LATE_INIT ++ help ++ P3541-0000 is a P3448 SKU3 CVM module married to a P3542 SKU0 CVB carrier. ++ + endchoice + + config SYS_SOC +@@ -42,5 +48,6 @@ source "board/nvidia/p2371-0000/Kconfig" + source "board/nvidia/p2371-2180/Kconfig" + source "board/nvidia/p2571/Kconfig" + source "board/nvidia/p3450-0000/Kconfig" ++source "board/nvidia/p3541-0000/Kconfig" + + endif +diff --git arch/arm/mach-tegra/tegra210/Makefile arch/arm/mach-tegra/tegra210/Makefile +index cfcba5b68f..e6d2bd4db5 100644 +--- arch/arm/mach-tegra/tegra210/Makefile ++++ arch/arm/mach-tegra/tegra210/Makefile +@@ -1,5 +1,5 @@ + # +-# (C) Copyright 2013-2020 ++# (C) Copyright 2013-2021 + # NVIDIA Corporation + # + # SPDX-License-Identifier: GPL-2.0+ +@@ -7,5 +7,6 @@ + + obj-y += clock.o + obj-y += funcmux.o ++obj-y += rp4_support.o + obj-y += xusb-padctl.o + obj-y += ../xusb-padctl-common.o +diff --git arch/arm/mach-tegra/tegra210/clock.c arch/arm/mach-tegra/tegra210/clock.c +index ccc64eb77b..57d477fb05 100644 +--- arch/arm/mach-tegra/tegra210/clock.c ++++ arch/arm/mach-tegra/tegra210/clock.c +@@ -283,7 +283,7 @@ static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { + TYPE(PERIPHC_5fh, CLOCK_TYPE_NONE), + + /* 0x60 */ +- TYPE(PERIPHC_XUSB_CORE_HOST, CLOCK_TYPE_NONE), ++ TYPE(PERIPHC_XUSB_CORE_HOST, CLOCK_TYPE_NONE), /* start with 0x600 */ + TYPE(PERIPHC_XUSB_FALCON, CLOCK_TYPE_NONE), + TYPE(PERIPHC_XUSB_FS, CLOCK_TYPE_NONE), + TYPE(PERIPHC_XUSB_CORE_DEV, CLOCK_TYPE_NONE), +@@ -537,7 +537,7 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = { + NONE(W_RESERVED12), + NONE(W_RESERVED13), + NONE(XUSB_PADCTL), +- NONE(W_RESERVED15), ++ NONE(XUSB), + + /* 144 */ + NONE(W_RESERVED16), +@@ -548,13 +548,19 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = { + NONE(ENTROPY), + NONE(DDS), + NONE(W_RESERVED23), ++ /* ++ * NOTE: These 3 XUSB IDs are here for the clock source routines ++ * like adjust_periph_pll(), they map to the periph_id table, ++ * but don't really correspond to any clock reset/enable bits. ++ * We should rework this odd relationship at some point. ++ */ + + /* 152 */ +- NONE(W_RESERVED24), +- NONE(W_RESERVED25), +- NONE(W_RESERVED26), ++ PERIPHC_XUSB_CORE_HOST, ++ PERIPHC_XUSB_FALCON, ++ PERIPHC_XUSB_FS, + NONE(DVFS), +- NONE(XUSB_SS), ++ PERIPHC_XUSB_SS, + NONE(W_RESERVED29), + NONE(W_RESERVED30), + NONE(W_RESERVED31), +@@ -915,7 +921,6 @@ enum periph_id clk_id_to_periph_id(int clk_id) + case PERIPH_ID_W_RESERVED11: + case PERIPH_ID_W_RESERVED12: + case PERIPH_ID_W_RESERVED13: +- case PERIPH_ID_W_RESERVED15: + case PERIPH_ID_W_RESERVED16: + case PERIPH_ID_W_RESERVED17: + case PERIPH_ID_W_RESERVED18: +@@ -1244,10 +1249,10 @@ int tegra_plle_enable(void) + } + + struct periph_clk_init periph_clk_init_table[] = { +- { PERIPH_ID_SBC1, CLOCK_ID_PERIPH }, +- { PERIPH_ID_SBC2, CLOCK_ID_PERIPH }, +- { PERIPH_ID_SBC3, CLOCK_ID_PERIPH }, +- { PERIPH_ID_SBC4, CLOCK_ID_PERIPH }, ++ { PERIPH_ID_SBC1, CLOCK_ID_OSC }, ++ { PERIPH_ID_SBC2, CLOCK_ID_OSC }, ++ { PERIPH_ID_SBC3, CLOCK_ID_OSC }, ++ { PERIPH_ID_SBC4, CLOCK_ID_OSC }, + { PERIPH_ID_SBC5, CLOCK_ID_PERIPH }, + { PERIPH_ID_SBC6, CLOCK_ID_PERIPH }, + { PERIPH_ID_HOST1X, CLOCK_ID_PERIPH }, +diff --git arch/arm/mach-tegra/tegra210/rp4_support.c arch/arm/mach-tegra/tegra210/rp4_support.c +new file mode 100644 +index 0000000000..618c3fd049 +--- /dev/null ++++ arch/arm/mach-tegra/tegra210/rp4_support.c +@@ -0,0 +1,115 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "rp4_support.h" ++ ++int find_rp4_data(char *buf, long size) ++{ ++ struct udevice *dev; ++ struct mmc *mmc; ++ u32 cnt, n; ++ int i, curr_device = 0; ++ int ret = 0; ++ gpt_entry *gpt_pte = NULL; ++ bool use_spi_flash = true; /* Assume QSPI (Nano SKU0/SKU3) */ ++ long offset = 0x3F8000; /* 4MB QSPI, which has no GPT to parse */ ++ ++ ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, 512 /*dev_desc->blksz*/); ++ ++ printf("Loading XUSB FW blob from RP4 partition ...\n"); ++ ++ /* Find out if QSPI is present, if not use eMMC (TX1, Nano-SKU2) */ ++ ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev); ++ if (ret) { ++ debug("Can't find SPI flash device, using eMMC ..\n"); ++ use_spi_flash = false; ++ } ++ ++ if (use_spi_flash) { ++ debug("%s: Reading QSPI, offset 0x%08lX ...\n", __func__, ++ offset); ++ ret = spi_flash_read_dm(dev, offset, size, buf); ++ if (ret) ++ return log_msg_ret("Cannot read SPI flash", ret); ++ } else { ++ debug("%s: Reading mmc %d, parsing GPT ...\n", __func__, ++ curr_device); ++ ++ mmc = init_mmc_device(curr_device, false); ++ if (!mmc) ++ return -ENODEV; ++ ++ if (find_valid_gpt(mmc_get_blk_desc(mmc), gpt_head, &gpt_pte) != 1) { ++ printf("ERROR reading eMMC GPT!\n"); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) { ++ /* Stop at the first non valid PTE */ ++ if (!is_pte_valid(&gpt_pte[i])) ++ break; ++ ++ debug("%3d 0x%08llx 0x%08llx %s\n", (i + 1), ++ le64_to_cpu(gpt_pte[i].starting_lba), ++ le64_to_cpu(gpt_pte[i].ending_lba), ++ print_efiname(&gpt_pte[i])); ++ ++ if (strcmp("RP4", print_efiname(&gpt_pte[i])) == 0) { ++ offset = le64_to_cpu(gpt_pte[i].starting_lba); ++ debug("Found RP4 partition @ 0x%8lX\n", offset); ++ break; ++ } ++ } ++ ++ /* Remember to free pte */ ++ free(gpt_pte); ++ ++ cnt = size / mmc_get_blk_desc(mmc)->blksz; ++ debug("\neMMC read: dev # %d, block # %ld, count %d ... ", ++ curr_device, offset, cnt); ++ n = blk_dread(mmc_get_blk_desc(mmc), offset, cnt, buf); ++ debug("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR"); ++ } ++again: ++ /* Good read, check for NVBLOB sig */ ++ debug("%s: checking offset %lX\n", __func__, offset); ++ if (strcmp(buf, "NVIDIA__BLOB__V2") == 0) { ++ debug("%s: Found an NV BLOB! ...\n", __func__); ++ if (strcmp(buf+0x58, "XUSB") == 0) { ++ debug("%s: Found XUSB sig!\n", __func__); ++ if (use_spi_flash) { ++ debug("%ld bytes read: %s\n", size, "QSPI"); ++ } else { ++ debug("%d blocks read: %s\n", cnt, "eMMC"); ++ } ++ ++ debug(" XUSB FW @ %p\n", buf); ++ goto done; ++ } ++ } ++ ++ if (use_spi_flash) { ++ /* read next block, work back thru QSPI (RP4 is near the end) */ ++ offset -= PROBE_BUF_SIZE; ++ if (offset <= 0) ++ goto done; ++ ++ ret = spi_flash_read_dm(dev, offset, size, buf); ++ if (ret) ++ return log_msg_ret("Cannot read SPI flash", ret); ++ ++ goto again; ++ } ++ ++done: ++ return 0; ++} +diff --git arch/arm/mach-tegra/tegra210/rp4_support.h arch/arm/mach-tegra/tegra210/rp4_support.h +new file mode 100644 +index 0000000000..d2c6d50c24 +--- /dev/null ++++ arch/arm/mach-tegra/tegra210/rp4_support.h +@@ -0,0 +1,14 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. ++ */ ++ ++struct mmc *init_mmc_device(int dev, bool force_init); ++char *print_efiname(gpt_entry *pte); ++int is_pte_valid(gpt_entry * pte); ++int find_valid_gpt(struct blk_desc *dev_desc, gpt_header *gpt_head, gpt_entry **pgpt_pte); ++int find_rp4_data(char *buf, long size); ++ ++/* The amount of the rp4 header to probe to obtain what we need */ ++#define PROBE_BUF_SIZE 32768 ++ +diff --git arch/arm/mach-tegra/xusb-padctl-common.c arch/arm/mach-tegra/xusb-padctl-common.c +index e56e27c8b6..7fd308a705 100644 +--- arch/arm/mach-tegra/xusb-padctl-common.c ++++ arch/arm/mach-tegra/xusb-padctl-common.c +@@ -84,7 +84,7 @@ tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl, + + len = ofnode_read_string_count(node, "nvidia,lanes"); + if (len < 0) { +- pr_err("failed to parse \"nvidia,lanes\" property"); ++ pr_err("failed to parse \"nvidia,lanes\" property\n"); + return -EINVAL; + } + +@@ -94,7 +94,7 @@ tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl, + ret = ofnode_read_string_index(node, "nvidia,lanes", i, + &group->pins[i]); + if (ret) { +- pr_err("failed to read string from \"nvidia,lanes\" property"); ++ pr_err("failed to read string from \"nvidia,lanes\" property\n"); + return -EINVAL; + } + } +@@ -104,7 +104,7 @@ tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl, + ret = ofnode_read_string_index(node, "nvidia,function", 0, + &group->func); + if (ret) { +- pr_err("failed to parse \"nvidia,func\" property"); ++ pr_err("failed to parse \"nvidia,func\" property\n"); + return -EINVAL; + } + +@@ -157,14 +157,14 @@ tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl, + + lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]); + if (!lane) { +- pr_err("no lane for pin %s", group->pins[i]); ++ pr_err("no lane for pin %s\n", group->pins[i]); + continue; + } + + func = tegra_xusb_padctl_lane_find_function(padctl, lane, + group->func); + if (func < 0) { +- pr_err("function %s invalid for lane %s: %d", ++ pr_err("function %s invalid for lane %s: %d\n", + group->func, lane->name, func); + continue; + } +@@ -206,7 +206,7 @@ tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl, + + err = tegra_xusb_padctl_group_apply(padctl, group); + if (err < 0) { +- pr_err("failed to apply group %s: %d", ++ pr_err("failed to apply group %s: %d\n", + group->name, err); + continue; + } +@@ -232,7 +232,7 @@ tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl, + + err = tegra_xusb_padctl_group_parse_dt(padctl, group, subnode); + if (err < 0) { +- pr_err("failed to parse group %s", group->name); ++ pr_err("failed to parse group %s\n", group->name); + return err; + } + +@@ -250,7 +250,7 @@ static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl, + + err = ofnode_read_resource(node, 0, &padctl->regs); + if (err < 0) { +- pr_err("registers not found"); ++ pr_err("registers not found\n"); + return err; + } + +@@ -261,7 +261,7 @@ static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl, + err = tegra_xusb_padctl_config_parse_dt(padctl, config, + subnode); + if (err < 0) { +- pr_err("failed to parse entry %s: %d", ++ pr_err("failed to parse entry %s: %d\n", + config->name, err); + continue; + } +@@ -289,7 +289,7 @@ int tegra_xusb_process_nodes(ofnode nodes[], unsigned int count, + + err = tegra_xusb_padctl_parse_dt(&padctl, nodes[i]); + if (err < 0) { +- pr_err("failed to parse DT: %d", err); ++ pr_err("failed to parse DT: %d\n", err); + continue; + } + +@@ -298,7 +298,7 @@ int tegra_xusb_process_nodes(ofnode nodes[], unsigned int count, + + err = tegra_xusb_padctl_config_apply(&padctl, &padctl.config); + if (err < 0) { +- pr_err("failed to apply pinmux: %d", err); ++ pr_err("failed to apply pinmux: %d\n", err); + continue; + } + +diff --git board/nvidia/p3450-0000/Kconfig board/nvidia/p3450-0000/Kconfig +index 7a08cd8867..033718d232 100644 +--- board/nvidia/p3450-0000/Kconfig ++++ board/nvidia/p3450-0000/Kconfig +@@ -9,4 +9,7 @@ config SYS_VENDOR + config SYS_CONFIG_NAME + default "p3450-0000" + ++config P3450_EMMC ++ bool "SKU 2 module with eMMC" ++ + endif +diff --git board/nvidia/p3541-0000/Kconfig board/nvidia/p3541-0000/Kconfig +new file mode 100644 +index 0000000000..e12705bce6 +--- /dev/null ++++ board/nvidia/p3541-0000/Kconfig +@@ -0,0 +1,12 @@ ++if TARGET_P3541_0000 ++ ++config SYS_BOARD ++ default "p3541-0000" ++ ++config SYS_VENDOR ++ default "nvidia" ++ ++config SYS_CONFIG_NAME ++ default "p3541-0000" ++ ++endif +diff --git board/nvidia/p3541-0000/MAINTAINERS board/nvidia/p3541-0000/MAINTAINERS +new file mode 100644 +index 0000000000..7a73a67651 +--- /dev/null ++++ board/nvidia/p3541-0000/MAINTAINERS +@@ -0,0 +1,6 @@ ++P3541-0000 BOARD ++M: Tom Warren ++S: Maintained ++F: board/nvidia/p3541-0000/ ++F: include/configs/p3541-0000.h ++F: configs/p3541-0000_defconfig +diff --git board/nvidia/p3541-0000/Makefile board/nvidia/p3541-0000/Makefile +new file mode 100644 +index 0000000000..356e84286c +--- /dev/null ++++ board/nvidia/p3541-0000/Makefile +@@ -0,0 +1,8 @@ ++# ++# (C) Copyright 2020 ++# NVIDIA Corporation ++# ++# SPDX-License-Identifier: GPL-2.0+ ++# ++ ++obj-y += p3541-0000.o +diff --git board/nvidia/p3541-0000/p3541-0000.c board/nvidia/p3541-0000/p3541-0000.c +new file mode 100644 +index 0000000000..45b5ceab6a +--- /dev/null ++++ board/nvidia/p3541-0000/p3541-0000.c +@@ -0,0 +1,97 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * (C) Copyright 2020 ++ * NVIDIA Corporation ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../p2571/max77620_init.h" ++ ++void pin_mux_mmc(void) ++{ ++ struct udevice *dev; ++ uchar val; ++ int ret; ++ ++ /* Turn on MAX77620 LDO2 to 3.3V for SD card power */ ++ debug("%s: Set LDO2 for VDDIO_SDMMC_AP power to 3.3V\n", __func__); ++ ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev); ++ if (ret) { ++ printf("%s: Cannot find MAX77620 I2C chip\n", __func__); ++ return; ++ } ++ /* 0xF2 for 3.3v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */ ++ val = 0xF2; ++ ret = dm_i2c_write(dev, MAX77620_CNFG1_L2_REG, &val, 1); ++ if (ret) ++ printf("i2c_write 0 0x3c 0x27 failed: %d\n", ret); ++ ++ /* Disable LDO4 discharge */ ++ ret = dm_i2c_read(dev, MAX77620_CNFG2_L4_REG, &val, 1); ++ if (ret) { ++ printf("i2c_read 0 0x3c 0x2c failed: %d\n", ret); ++ } else { ++ val &= ~BIT(1); /* ADE */ ++ ret = dm_i2c_write(dev, MAX77620_CNFG2_L4_REG, &val, 1); ++ if (ret) ++ printf("i2c_write 0 0x3c 0x2c failed: %d\n", ret); ++ } ++ ++ /* Set MBLPD */ ++ ret = dm_i2c_read(dev, MAX77620_CNFGGLBL1_REG, &val, 1); ++ if (ret) { ++ printf("i2c_write 0 0x3c 0x00 failed: %d\n", ret); ++ } else { ++ val |= BIT(6); /* MBLPD */ ++ ret = dm_i2c_write(dev, MAX77620_CNFGGLBL1_REG, &val, 1); ++ if (ret) ++ printf("i2c_write 0 0x3c 0x00 failed: %d\n", ret); ++ } ++} ++ ++#ifdef CONFIG_PCI_TEGRA ++int tegra_pcie_board_init(void) ++{ ++ struct udevice *dev; ++ uchar val; ++ int ret; ++ ++ /* Turn on MAX77620 LDO1 to 1.05V for PEX power */ ++ debug("%s: Set LDO1 for PEX power to 1.05V\n", __func__); ++ ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev); ++ if (ret) { ++ printf("%s: Cannot find MAX77620 I2C chip\n", __func__); ++ return -1; ++ } ++ /* 0xCA for 1.05v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */ ++ val = 0xCA; ++ ret = dm_i2c_write(dev, MAX77620_CNFG1_L1_REG, &val, 1); ++ if (ret) ++ printf("i2c_write 0 0x3c 0x25 failed: %d\n", ret); ++ ++ return 0; ++} ++#endif /* PCI */ ++ ++static const char * const nodes[] = { ++ "/host1x@50000000/dc@54200000", ++ "/host1x@50000000/dc@54240000", ++ "/external-memory-controller@7001b000", ++}; ++ ++int ft_board_setup(void *fdt, struct bd_info *bd) ++{ ++ ft_mac_address_setup(fdt); ++ ft_carveout_setup(fdt, nodes, ARRAY_SIZE(nodes)); ++ ++ return 0; ++} +diff --git board/nvidia/p3636-0001/Kconfig board/nvidia/p3636-0001/Kconfig +new file mode 100644 +index 0000000000..1e1855792a +--- /dev/null ++++ board/nvidia/p3636-0001/Kconfig +@@ -0,0 +1,16 @@ ++# Copyright (c) 2020, NVIDIA CORPORATION. ++# ++# SPDX-License-Identifier: GPL-2.0 ++ ++if TARGET_P3636_0001 ++ ++config SYS_BOARD ++ default "p3636-0001" ++ ++config SYS_VENDOR ++ default "nvidia" ++ ++config SYS_CONFIG_NAME ++ default "p3636-0001" ++ ++endif +diff --git board/nvidia/p3636-0001/MAINTAINERS board/nvidia/p3636-0001/MAINTAINERS +new file mode 100644 +index 0000000000..6c49fb8b4d +--- /dev/null ++++ board/nvidia/p3636-0001/MAINTAINERS +@@ -0,0 +1,6 @@ ++P3636-0001 BOARD ++M: Tom Warren ++S: Maintained ++F: board/nvidia/p3636-0001/ ++F: include/configs/p3636-0001.h ++F: configs/p3636-0001_defconfig +diff --git board/nvidia/p3636-0001/Makefile board/nvidia/p3636-0001/Makefile +new file mode 100644 +index 0000000000..21f770d6b2 +--- /dev/null ++++ board/nvidia/p3636-0001/Makefile +@@ -0,0 +1,5 @@ ++# Copyright (c) 2020, NVIDIA CORPORATION. ++# ++# SPDX-License-Identifier: GPL-2.0 ++ ++obj-y += p3636-0001.o +diff --git board/nvidia/p3636-0001/p3636-0001.c board/nvidia/p3636-0001/p3636-0001.c +new file mode 100644 +index 0000000000..c3149026a5 +--- /dev/null ++++ board/nvidia/p3636-0001/p3636-0001.c +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2020, NVIDIA CORPORATION ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../p2571/max77620_init.h" ++ ++void pin_mux_mmc(void) ++{ ++#ifdef CONFIG_LANAI_SD ++ struct udevice *dev; ++ uchar val; ++ int ret; ++ ++ /* ++ * NOTE: Current P3636/Lanai is SKU1 and has no SD-card slot, so ++ * this is not needed. Leaving it here but ifdef'd out in case we ++ * do a Lanai-SD/SKU0 in the future. ++ */ ++ ++ /* Turn on MAX77620 LDO3 to 3.3V for SD card power */ ++ debug("%s: Set LDO3 for VDDIO_SDMMC_AP power to 3.3V\n", __func__); ++ ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev); ++ if (ret) { ++ printf("%s: Cannot find MAX77620 I2C chip\n", __func__); ++ return; ++ } ++ /* 0xF2 for 3.3v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */ ++ val = 0xF2; ++ ret = dm_i2c_write(dev, MAX77620_CNFG1_L3_REG, &val, 1); ++ if (ret) { ++ printf("i2c_write 0 0x3c 0x27 failed: %d\n", ret); ++ return; ++ } ++#endif ++} ++ ++#ifdef CONFIG_PCI_TEGRA ++int tegra_pcie_board_init(void) ++{ ++ struct udevice *dev; ++ uchar val; ++ int ret; ++ ++ /* Turn on MAX77620 LDO7 to 1.05V for PEX power */ ++ debug("%s: Set LDO7 for PEX power to 1.05V\n", __func__); ++ ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev); ++ if (ret) { ++ printf("%s: Cannot find MAX77620 I2C chip\n", __func__); ++ return -1; ++ } ++ /* 0xC5 for 1.05v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */ ++ val = 0xC5; ++ ret = dm_i2c_write(dev, MAX77620_CNFG1_L7_REG, &val, 1); ++ if (ret) ++ printf("i2c_write 0 0x3c 0x31 failed: %d\n", ret); ++ ++ return 0; ++} ++#endif ++ ++static const char * const nodes[] = { ++ "/host1x@13e00000/display-hub@15200000/display@15200000", ++ "/host1x@13e00000/display-hub@15200000/display@15210000", ++ "/host1x@13e00000/display-hub@15200000/display@15220000", ++}; ++ ++int ft_board_setup(void *fdt, struct bd_info *bd) ++{ ++ ft_mac_address_setup(fdt); ++ ft_carveout_setup(fdt, nodes, ARRAY_SIZE(nodes)); ++ ++ return 0; ++} +diff --git boot/pxe_utils.c boot/pxe_utils.c +index a7a84f26c1..b7375c5d4f 100644 +--- boot/pxe_utils.c ++++ boot/pxe_utils.c +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* + * Copyright 2010-2011 Calxeda, Inc. +- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. ++ * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. + */ + + #include +@@ -25,6 +25,9 @@ + + #include "menu.h" + #include "cli.h" ++#ifdef CONFIG_HUSH_PARSER ++#include "cli_hush.h" ++#endif + + #include "pxe_utils.h" + +@@ -319,17 +322,16 @@ static int label_localboot(struct pxe_label *label) + */ + #ifdef CONFIG_OF_LIBFDT_OVERLAY + static void label_boot_fdtoverlay(struct pxe_context *ctx, +- struct pxe_label *label) ++ struct pxe_label *label, ++ ulong fdt_addr) + { + char *fdtoverlay = label->fdtoverlays; + struct fdt_header *working_fdt; + char *fdtoverlay_addr_env; + ulong fdtoverlay_addr; +- ulong fdt_addr; + int err; + + /* Get the main fdt and map it */ +- fdt_addr = hextoul(env_get("fdt_addr_r"), NULL); + working_fdt = map_sysmem(fdt_addr, 0); + err = fdt_check_header(working_fdt); + if (err) +@@ -437,7 +439,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + int len = 0; + ulong kernel_addr_r; + void *buf; +- ++#ifdef CONFIG_OF_LIBFDT_OVERLAY ++ ulong fdt_addr; ++#endif + label_print(label); + + label->attempted = 1; +@@ -455,13 +459,11 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + } + + if (label->initrd) { +- ulong size; ++ ulong size = 0; + + if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", + &size) < 0) { +- printf("Skipping %s for failure retrieving initrd\n", +- label->name); +- return 1; ++ printf("initrd not found or zero, skipping ...\n"); + } + + initrd_addr_str = env_get("ramdisk_addr_r"); +@@ -499,6 +501,10 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + if ((label->ipappend & 0x3) || label->append) { + char bootargs[CONFIG_SYS_CBSIZE] = ""; + char finalbootargs[CONFIG_SYS_CBSIZE]; ++#ifdef CONFIG_HUSH_PARSER ++ char *distro_bootpart, *hush_bootpart; ++ char *env_devnum, *hush_devnum; ++#endif + + if (strlen(label->append ?: "") + + strlen(ip_str) + strlen(mac_str) + 1 > sizeof(bootargs)) { +@@ -515,10 +521,34 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + strcat(bootargs, ip_str); + strcat(bootargs, mac_str); + ++#ifdef CONFIG_HUSH_PARSER ++ env_devnum = env_get("devnum"); ++ hush_devnum = get_local_var("devnum"); ++ if (hush_devnum && !env_devnum) { ++ char devnumstr[32]; ++ unsigned long devnum = simple_strtoul(hush_devnum, NULL, 16); ++ snprintf(devnumstr, sizeof(devnumstr), "%lu", devnum); ++ env_set("devnum", devnumstr); ++ } ++ distro_bootpart = env_get("distro_bootpart"); ++ hush_bootpart = get_local_var("distro_bootpart"); ++ if (hush_bootpart && !distro_bootpart) { ++ char partnumstr[32]; ++ unsigned long partnum = simple_strtoul(hush_bootpart, NULL, 16); ++ snprintf(partnumstr, sizeof(partnumstr), "%lu", partnum); ++ env_set("distro_bootpart", partnumstr); ++ } ++#endif + cli_simple_process_macros(bootargs, finalbootargs, + sizeof(finalbootargs)); + env_set("bootargs", finalbootargs); + printf("append: %s\n", finalbootargs); ++#ifdef CONFIG_HUSH_PARSER ++ if (hush_bootpart && !distro_bootpart) ++ env_set("distro_bootpart", NULL); ++ if (hush_devnum && !env_devnum) ++ env_set("devnum", NULL); ++#endif + } + + kernel_addr = env_get("kernel_addr_r"); +@@ -541,8 +571,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + * It handles the following scenarios. + * + * Scenario 1: If fdt_addr_r specified and "fdt" or "fdtdir" label is +- * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r to +- * bootm, and adjust argc appropriately. ++ * defined in pxe file, retrieve fdt blob from server. Pass fdt_addr_r ++ * to bootm, and adjust argc appropriately. + * + * If retrieve fails and no exact fdt blob is specified in pxe file with + * "fdt" label, try Scenario 2. +@@ -550,7 +580,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + * Scenario 2: If there is an fdt_addr specified, pass it along to + * bootm, and adjust argc appropriately. + * +- * Scenario 3: fdt blob is not available. ++ * Scenario 3: fdt blob is not available, boot without it. + */ + bootm_argv[3] = env_get("fdt_addr_r"); + +@@ -629,8 +659,9 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + } + + #ifdef CONFIG_OF_LIBFDT_OVERLAY ++ fdt_addr = (ulong)simple_strtol(bootm_argv[3], NULL, 16); + if (label->fdtoverlays) +- label_boot_fdtoverlay(ctx, label); ++ label_boot_fdtoverlay(ctx, label, fdt_addr); + #endif + } else { + bootm_argv[3] = NULL; +@@ -652,9 +683,15 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label) + if (!bootm_argv[3]) + bootm_argv[3] = env_get("fdt_addr"); + +- if (bootm_argv[3]) { ++ if (bootm_argv[3]) { /* fdt_addr exists */ ++#ifdef CONFIG_OF_LIBFDT_OVERLAY ++ fdt_addr = (ulong)simple_strtol(bootm_argv[3], NULL, 16); ++ /* apply any FDT overlays to in-RAM DTB (@ fdt_addr) */ ++ if (label->fdtoverlays) ++ label_boot_fdtoverlay(ctx, label, fdt_addr); ++#endif + if (!bootm_argv[2]) +- bootm_argv[2] = "-"; ++ bootm_argv[2] = "-"; /* skip initrd */ + bootm_argc = 4; + } + +diff --git cmd/mmc.c cmd/mmc.c +index 96d81ffdf3..d537273db2 100644 +--- cmd/mmc.c ++++ cmd/mmc.c +@@ -151,7 +151,7 @@ static struct mmc *__init_mmc_device(int dev, bool force_init, + return mmc; + } + +-static struct mmc *init_mmc_device(int dev, bool force_init) ++struct mmc *init_mmc_device(int dev, bool force_init) + { + return __init_mmc_device(dev, force_init, MMC_MODES_END); + } +diff --git configs/p2371-0000_defconfig configs/p2371-0000_defconfig +index 38836696c0..4289c22886 100644 +--- configs/p2371-0000_defconfig ++++ configs/p2371-0000_defconfig +@@ -2,12 +2,12 @@ CONFIG_ARM=y + CONFIG_ARCH_TEGRA=y + CONFIG_SYS_TEXT_BASE=0x80080000 + CONFIG_SYS_MALLOC_LEN=0x2500000 +-CONFIG_NR_DRAM_BANKS=2 ++CONFIG_NR_DRAM_BANKS=16 + CONFIG_ENV_SIZE=0x2000 +-CONFIG_ENV_OFFSET=0xFFFFE000 ++CONFIG_ENV_OFFSET=0xFFFD8000 + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p2371-0000" + CONFIG_TEGRA210=y +-CONFIG_SYS_LOAD_ADDR=0x80080000 ++CONFIG_SYS_LOAD_ADDR=0x84000000 + CONFIG_OF_SYSTEM_SETUP=y + CONFIG_CONSOLE_MUX=y + CONFIG_SYS_STDIO_DEREGISTER=y +@@ -48,3 +48,4 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0955 + CONFIG_USB_GADGET_PRODUCT_NUM=0x701a + CONFIG_CI_UDC=y + CONFIG_USB_GADGET_DOWNLOAD=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p2371-2180_defconfig configs/p2371-2180_defconfig +index ea95943122..1d0228823f 100644 +--- configs/p2371-2180_defconfig ++++ configs/p2371-2180_defconfig +@@ -2,13 +2,13 @@ CONFIG_ARM=y + CONFIG_ARCH_TEGRA=y + CONFIG_SYS_TEXT_BASE=0x80080000 + CONFIG_SYS_MALLOC_LEN=0x2500000 +-CONFIG_NR_DRAM_BANKS=2 +-CONFIG_ENV_SIZE=0x2000 +-CONFIG_ENV_OFFSET=0xFFFFE000 ++CONFIG_NR_DRAM_BANKS=16 ++CONFIG_ENV_SIZE=0x8000 ++CONFIG_ENV_OFFSET=0x3D8000 + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p2371-2180" + CONFIG_TEGRA210=y + CONFIG_TARGET_P2371_2180=y +-CONFIG_SYS_LOAD_ADDR=0x80080000 ++CONFIG_SYS_LOAD_ADDR=0x84000000 + CONFIG_OF_BOARD_SETUP=y + CONFIG_OF_SYSTEM_SETUP=y + CONFIG_CONSOLE_MUX=y +@@ -55,3 +55,10 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0955 + CONFIG_USB_GADGET_PRODUCT_NUM=0x701a + CONFIG_CI_UDC=y + CONFIG_USB_GADGET_DOWNLOAD=y ++CONFIG_NVME=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_TEGRA=y ++CONFIG_USB_STORAGE=y ++CONFIG_DOS_PARTITION=y ++CONFIG_CMD_CACHE=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p2571_defconfig configs/p2571_defconfig +index da33f88d83..fbcc5072d5 100644 +--- configs/p2571_defconfig ++++ configs/p2571_defconfig +@@ -2,9 +2,9 @@ CONFIG_ARM=y + CONFIG_ARCH_TEGRA=y + CONFIG_SYS_TEXT_BASE=0x80080000 + CONFIG_SYS_MALLOC_LEN=0x2500000 +-CONFIG_NR_DRAM_BANKS=2 ++CONFIG_NR_DRAM_BANKS=16 + CONFIG_ENV_SIZE=0x2000 +-CONFIG_ENV_OFFSET=0xFFFFE000 ++CONFIG_ENV_OFFSET=0xFFFD8000 + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p2571" + CONFIG_TEGRA210=y + CONFIG_TARGET_P2571=y +@@ -49,3 +49,4 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0955 + CONFIG_USB_GADGET_PRODUCT_NUM=0x701a + CONFIG_CI_UDC=y + CONFIG_USB_GADGET_DOWNLOAD=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p2771-0000-000_defconfig configs/p2771-0000-000_defconfig +index 90e9396048..e5a1249aeb 100644 +--- configs/p2771-0000-000_defconfig ++++ configs/p2771-0000-000_defconfig +@@ -1,9 +1,9 @@ + CONFIG_ARM=y + CONFIG_ARCH_TEGRA=y + CONFIG_SYS_TEXT_BASE=0x80080000 +-CONFIG_NR_DRAM_BANKS=1026 +-CONFIG_ENV_SIZE=0x2000 +-CONFIG_ENV_OFFSET=0xFFFFE000 ++CONFIG_ENV_SIZE=0x8000 ++CONFIG_ENV_OFFSET=0x3D8000 ++CONFIG_NR_DRAM_BANKS=1043 + CONFIG_DEFAULT_DEVICE_TREE="tegra186-p2771-0000-000" + CONFIG_TEGRA186=y + CONFIG_SYS_LOAD_ADDR=0x80080000 +@@ -35,4 +35,6 @@ CONFIG_PCI_TEGRA=y + CONFIG_POWER_DOMAIN=y + CONFIG_TEGRA186_POWER_DOMAIN=y + CONFIG_SYS_NS16550=y +-CONFIG_USB=y ++CONFIG_CMD_CACHE=y ++CONFIG_NVME=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p2771-0000-500_defconfig configs/p2771-0000-500_defconfig +index 6bdc1132f6..f0b56ec4c7 100644 +--- configs/p2771-0000-500_defconfig ++++ configs/p2771-0000-500_defconfig +@@ -1,9 +1,9 @@ + CONFIG_ARM=y + CONFIG_ARCH_TEGRA=y + CONFIG_SYS_TEXT_BASE=0x80080000 +-CONFIG_NR_DRAM_BANKS=1026 +-CONFIG_ENV_SIZE=0x2000 +-CONFIG_ENV_OFFSET=0xFFFFE000 ++CONFIG_ENV_SIZE=0x8000 ++CONFIG_ENV_OFFSET=0x3D8000 ++CONFIG_NR_DRAM_BANKS=1043 + CONFIG_DEFAULT_DEVICE_TREE="tegra186-p2771-0000-500" + CONFIG_TEGRA186=y + CONFIG_SYS_LOAD_ADDR=0x80080000 +@@ -35,4 +35,6 @@ CONFIG_PCI_TEGRA=y + CONFIG_POWER_DOMAIN=y + CONFIG_TEGRA186_POWER_DOMAIN=y + CONFIG_SYS_NS16550=y +-CONFIG_USB=y ++CONFIG_CMD_CACHE=y ++CONFIG_NVME=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p3450-0000_defconfig configs/p3450-0000_defconfig +index 85402e9b82..815a6773ac 100644 +--- configs/p3450-0000_defconfig ++++ configs/p3450-0000_defconfig +@@ -2,14 +2,14 @@ CONFIG_ARM=y + CONFIG_ARCH_TEGRA=y + CONFIG_SYS_TEXT_BASE=0x80080000 + CONFIG_SYS_MALLOC_LEN=0x2500000 +-CONFIG_NR_DRAM_BANKS=2 +-CONFIG_ENV_SIZE=0x2000 +-CONFIG_ENV_OFFSET=0xFFFFE000 ++CONFIG_NR_DRAM_BANKS=16 ++CONFIG_ENV_SIZE=0x8000 ++CONFIG_ENV_OFFSET=0x3D8000 + CONFIG_ENV_SECT_SIZE=0x1000 + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p3450-0000" + CONFIG_TEGRA210=y + CONFIG_TARGET_P3450_0000=y +-CONFIG_SYS_LOAD_ADDR=0x80080000 ++CONFIG_SYS_LOAD_ADDR=0x84000000 + CONFIG_OF_BOARD_SETUP=y + CONFIG_OF_SYSTEM_SETUP=y + CONFIG_CONSOLE_MUX=y +@@ -58,3 +58,9 @@ CONFIG_USB_GADGET_VENDOR_NUM=0x0955 + CONFIG_USB_GADGET_PRODUCT_NUM=0x701a + CONFIG_CI_UDC=y + CONFIG_USB_GADGET_DOWNLOAD=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_TEGRA=y ++CONFIG_USB_STORAGE=y ++CONFIG_DOS_PARTITION=y ++CONFIG_CMD_CACHE=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p3450-0002_defconfig configs/p3450-0002_defconfig +new file mode 100644 +index 0000000000..595d270b73 +--- /dev/null ++++ configs/p3450-0002_defconfig +@@ -0,0 +1,66 @@ ++CONFIG_ARM=y ++CONFIG_ARCH_TEGRA=y ++CONFIG_SYS_TEXT_BASE=0x80080000 ++CONFIG_SYS_MALLOC_LEN=0x2500000 ++CONFIG_NR_DRAM_BANKS=16 ++CONFIG_ENV_SIZE=0x8000 ++CONFIG_ENV_OFFSET=0x3D8000 ++CONFIG_DEFAULT_DEVICE_TREE="tegra210-p3450-0000" ++CONFIG_TEGRA210=y ++CONFIG_TARGET_P3450_0000=y ++CONFIG_P3450_EMMC=y ++CONFIG_SYS_LOAD_ADDR=0x84000000 ++CONFIG_OF_BOARD_SETUP=y ++CONFIG_OF_SYSTEM_SETUP=y ++CONFIG_CONSOLE_MUX=y ++CONFIG_SYS_STDIO_DEREGISTER=y ++CONFIG_SYS_PROMPT="Tegra210 (P3450-0002) # " ++# CONFIG_CMD_IMI is not set ++CONFIG_CMD_DFU=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_I2C=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SPI=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_USB_MASS_STORAGE=y ++# CONFIG_CMD_SETEXPR is not set ++CONFIG_BOOTP_PREFER_SERVERIP=y ++# CONFIG_CMD_NFS is not set ++CONFIG_CMD_EXT4_WRITE=y ++CONFIG_OF_LIVE=y ++CONFIG_ENV_OVERWRITE=y ++CONFIG_ENV_IS_IN_MMC=y ++# CONFIG_ENV_IS_IN_SPI_FLASH is not set ++CONFIG_DFU_MMC=y ++CONFIG_DFU_RAM=y ++CONFIG_DFU_SF=y ++CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000 ++CONFIG_SYS_DFU_MAX_FILE_SIZE=0x2000000 ++CONFIG_SYS_I2C_TEGRA=y ++CONFIG_SF_DEFAULT_SPEED=24000000 ++CONFIG_SPI_FLASH_MACRONIX=y ++CONFIG_RTL8169=y ++CONFIG_NVME=y ++CONFIG_PCI=y ++CONFIG_PCI_TEGRA=y ++CONFIG_SYS_NS16550=y ++CONFIG_TEGRA114_SPI=y ++CONFIG_TEGRA210_QSPI=y ++CONFIG_USB=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_TEGRA=y ++CONFIG_USB_HOST_ETHER=y ++CONFIG_USB_ETHER_ASIX=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" ++CONFIG_USB_GADGET_VENDOR_NUM=0x0955 ++CONFIG_USB_GADGET_PRODUCT_NUM=0x701a ++CONFIG_CI_UDC=y ++CONFIG_USB_GADGET_DOWNLOAD=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_TEGRA=y ++CONFIG_USB_STORAGE=y ++CONFIG_DOS_PARTITION=y ++CONFIG_CMD_CACHE=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p3541-0000_defconfig configs/p3541-0000_defconfig +new file mode 100644 +index 0000000000..35dda4228b +--- /dev/null ++++ configs/p3541-0000_defconfig +@@ -0,0 +1,66 @@ ++CONFIG_ARM=y ++CONFIG_ARCH_TEGRA=y ++CONFIG_SYS_TEXT_BASE=0x80080000 ++CONFIG_SYS_MALLOC_LEN=0x2500000 ++CONFIG_NR_DRAM_BANKS=16 ++CONFIG_ENV_SIZE=0x8000 ++CONFIG_ENV_OFFSET=0x3D8000 ++CONFIG_ENV_SECT_SIZE=0x1000 ++CONFIG_DEFAULT_DEVICE_TREE="tegra210-p3541-0000" ++CONFIG_TEGRA210=y ++CONFIG_TARGET_P3541_0000=y ++CONFIG_SYS_LOAD_ADDR=0x84000000 ++CONFIG_OF_BOARD_SETUP=y ++CONFIG_OF_SYSTEM_SETUP=y ++CONFIG_CONSOLE_MUX=y ++CONFIG_SYS_STDIO_DEREGISTER=y ++CONFIG_SYS_PROMPT="Tegra210 (P3541-0000) # " ++# CONFIG_CMD_IMI is not set ++CONFIG_CMD_DFU=y ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_I2C=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SPI=y ++CONFIG_CMD_USB=y ++CONFIG_CMD_USB_MASS_STORAGE=y ++# CONFIG_CMD_SETEXPR is not set ++CONFIG_BOOTP_PREFER_SERVERIP=y ++# CONFIG_CMD_NFS is not set ++CONFIG_CMD_EXT4_WRITE=y ++CONFIG_OF_LIVE=y ++CONFIG_ENV_OVERWRITE=y ++# CONFIG_ENV_IS_IN_MMC is not set ++CONFIG_ENV_IS_IN_SPI_FLASH=y ++CONFIG_DFU_MMC=y ++CONFIG_DFU_RAM=y ++CONFIG_DFU_SF=y ++CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000 ++CONFIG_SYS_DFU_MAX_FILE_SIZE=0x2000000 ++CONFIG_SYS_I2C_TEGRA=y ++CONFIG_SF_DEFAULT_SPEED=24000000 ++CONFIG_SPI_FLASH_MACRONIX=y ++CONFIG_RTL8169=y ++CONFIG_NVME=y ++CONFIG_PCI=y ++CONFIG_PCI_TEGRA=y ++CONFIG_SYS_NS16550=y ++CONFIG_TEGRA114_SPI=y ++CONFIG_TEGRA210_QSPI=y ++CONFIG_USB=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_EHCI_TEGRA=y ++CONFIG_USB_HOST_ETHER=y ++CONFIG_USB_ETHER_ASIX=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" ++CONFIG_USB_GADGET_VENDOR_NUM=0x0955 ++CONFIG_USB_GADGET_PRODUCT_NUM=0x701a ++CONFIG_CI_UDC=y ++CONFIG_USB_GADGET_DOWNLOAD=y ++CONFIG_USB_XHCI_HCD=y ++CONFIG_USB_XHCI_TEGRA=y ++CONFIG_USB_STORAGE=y ++CONFIG_DOS_PARTITION=y ++CONFIG_CMD_CACHE=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git configs/p3636-0001_defconfig configs/p3636-0001_defconfig +new file mode 100644 +index 0000000000..9e90f1ff8a +--- /dev/null ++++ configs/p3636-0001_defconfig +@@ -0,0 +1,41 @@ ++CONFIG_ARM=y ++CONFIG_ARCH_TEGRA=y ++CONFIG_SYS_TEXT_BASE=0x80080000 ++CONFIG_ENV_SIZE=0x8000 ++CONFIG_ENV_OFFSET=0x3D8000 ++CONFIG_NR_DRAM_BANKS=1043 ++CONFIG_DEFAULT_DEVICE_TREE="tegra186-p3636-0001" ++CONFIG_TEGRA186=y ++CONFIG_TARGET_P3636_0001=y ++CONFIG_SYS_LOAD_ADDR=0x80080000 ++CONFIG_OF_BOARD_SETUP=y ++CONFIG_OF_SYSTEM_SETUP=y ++CONFIG_CONSOLE_MUX=y ++CONFIG_SYS_STDIO_DEREGISTER=y ++CONFIG_SYS_PROMPT="Tegra186 (P3636-0001) # " ++# CONFIG_CMD_IMI is not set ++CONFIG_CMD_GPIO=y ++CONFIG_CMD_I2C=y ++CONFIG_CMD_MMC=y ++CONFIG_CMD_PCI=y ++CONFIG_CMD_SPI=y ++# CONFIG_CMD_SETEXPR is not set ++CONFIG_BOOTP_PREFER_SERVERIP=y ++# CONFIG_CMD_NFS is not set ++CONFIG_CMD_EXT4_WRITE=y ++CONFIG_ENV_OVERWRITE=y ++CONFIG_SYS_RELOC_GD_ENV_ADDR=y ++CONFIG_SYS_MMC_ENV_PART=2 ++CONFIG_SYS_I2C_TEGRA=y ++CONFIG_TEGRA186_BPMP_I2C=y ++CONFIG_DWC_ETH_QOS=y ++CONFIG_E1000=y ++CONFIG_RTL8169=y ++CONFIG_PCI=y ++CONFIG_PCI_TEGRA=y ++CONFIG_POWER_DOMAIN=y ++CONFIG_TEGRA186_POWER_DOMAIN=y ++CONFIG_SYS_NS16550=y ++CONFIG_CMD_CACHE=y ++CONFIG_NVME=y ++CONFIG_OF_LIBFDT_OVERLAY=y +diff --git disk/part_efi.c disk/part_efi.c +index 0ca7effc32..e8018ecdc0 100644 +--- disk/part_efi.c ++++ disk/part_efi.c +@@ -57,11 +57,11 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba, + gpt_header *pgpt_head, gpt_entry **pgpt_pte); + static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc, + gpt_header *pgpt_head); +-static int is_pte_valid(gpt_entry * pte); +-static int find_valid_gpt(struct blk_desc *dev_desc, gpt_header *gpt_head, ++int is_pte_valid(gpt_entry * pte); ++int find_valid_gpt(struct blk_desc *dev_desc, gpt_header *gpt_head, + gpt_entry **pgpt_pte); + +-static char *print_efiname(gpt_entry *pte) ++char *print_efiname(gpt_entry *pte) + { + static char name[PARTNAME_SZ + 1]; + int i; +@@ -1003,7 +1003,7 @@ static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba, + * Description: returns 1 if found a valid gpt, 0 on error. + * If valid, returns pointers to PTEs. + */ +-static int find_valid_gpt(struct blk_desc *dev_desc, gpt_header *gpt_head, ++int find_valid_gpt(struct blk_desc *dev_desc, gpt_header *gpt_head, + gpt_entry **pgpt_pte) + { + int r; +@@ -1086,7 +1086,7 @@ static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc, + * + * Description: returns 1 if valid, 0 on error. + */ +-static int is_pte_valid(gpt_entry * pte) ++int is_pte_valid(gpt_entry * pte) + { + efi_guid_t unused_guid; + +diff --git drivers/spi/tegra210_qspi.c drivers/spi/tegra210_qspi.c +index 5c8c1859cc..d9dacdf5aa 100644 +--- drivers/spi/tegra210_qspi.c ++++ drivers/spi/tegra210_qspi.c +@@ -316,12 +316,21 @@ static int tegra210_qspi_xfer(struct udevice *dev, unsigned int bitlen, + * Wait for SPI transmit FIFO to empty, or to time out. + * The RX FIFO status will be read and cleared last + */ +- for (tm = 0; tm < QSPI_TIMEOUT; ++tm) { ++ for (tm = 0; tm <= QSPI_TIMEOUT; ++tm) { + u32 fifo_status, xfer_status; + + xfer_status = readl(®s->xfer_status); +- if (!(xfer_status & QSPI_XFER_STS_RDY)) +- continue; ++ if (!(xfer_status & QSPI_XFER_STS_RDY)) { ++ debug("%s: xfer_status = 0x%08X, tm = %d\n", __func__, xfer_status, tm); ++ if (tm >= QSPI_TIMEOUT) { ++ debug("%s: TIMED OUT WAITING ON RDY!\n", __func__); ++ ret = tm; ++ goto done; ++ } else { ++ debug("%s: tm = %d, continuing for loop ...\n", __func__, tm); ++ continue; ++ } ++ } + + fifo_status = readl(®s->fifo_status); + if (fifo_status & QSPI_FIFO_STS_ERR) { +@@ -363,7 +372,7 @@ static int tegra210_qspi_xfer(struct udevice *dev, unsigned int bitlen, + /* clear ACK RDY, etc. bits */ + writel(readl(®s->fifo_status), ®s->fifo_status); + } +- ++done: + if (flags & SPI_XFER_END) + spi_cs_deactivate(dev); + +@@ -371,7 +380,7 @@ static int tegra210_qspi_xfer(struct udevice *dev, unsigned int bitlen, + __func__, tmpdin, readl(®s->fifo_status)); + + if (ret) { +- printf("%s: timeout during SPI transfer, tm %d\n", ++ debug("%s: timeout during SPI transfer, tm %d\n", + __func__, ret); + return -1; + } +diff --git drivers/usb/host/Kconfig drivers/usb/host/Kconfig +index ccecb5a3b0..ffa92d2262 100644 +--- drivers/usb/host/Kconfig ++++ drivers/usb/host/Kconfig +@@ -114,6 +114,12 @@ config USB_XHCI_BRCM + USB controller based on the Broadcom USB3 IP Core. + Supports USB2/3 functionality. + ++config USB_XHCI_TEGRA ++ bool "Support for NVIDIA Tegra T210 on-chip XHCI USB controller" ++ depends on ARCH_TEGRA ++ help ++ Enable support for TegraT210 on-chip XHCI USB controller ++ + endif # USB_XHCI_HCD + + config USB_EHCI_HCD +diff --git drivers/usb/host/Makefile drivers/usb/host/Makefile +index eb6fe9f6b3..5a2a8feadd 100644 +--- drivers/usb/host/Makefile ++++ drivers/usb/host/Makefile +@@ -56,6 +56,7 @@ obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o + obj-$(CONFIG_USB_XHCI_RCAR) += xhci-rcar.o + obj-$(CONFIG_USB_XHCI_STI) += dwc3-sti-glue.o + obj-$(CONFIG_USB_XHCI_OCTEON) += dwc3-octeon-glue.o ++obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o xhci-tegra-padctl.o tegra_xhci_fw.o + + # designware + obj-$(CONFIG_USB_DWC2) += dwc2.o +diff --git drivers/usb/host/tegra_xhci.h drivers/usb/host/tegra_xhci.h +new file mode 100644 +index 0000000000..9e3aa7e793 +--- /dev/null ++++ drivers/usb/host/tegra_xhci.h +@@ -0,0 +1,95 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* Copyright (c) 2020, NVIDIA CORPORATION */ ++ ++#ifndef _TEGRA_XHCI_H_ ++#define _TEGRA_XHCI_H_ ++ ++#define FW_MAJOR_VERSION(x) (((x) >> 24) & 0xff) ++#define FW_MINOR_VERSION(x) (((x) >> 16) & 0xff) ++ ++enum build_info_log { ++ LOG_NONE = 0, ++ LOG_MEMORY ++}; ++ ++/* T210-specific */ ++#define XHCI_PCI_ID (0x0fac10de) ++#define PCIE_DEVICE_CONFIG_BASE 0x70098000ull ++ ++/* FPCI CFG registers */ ++#define XUSB_CFG_0 0x000 ++#define XUSB_CFG_ARU_C11_CSBRANGE 0x41c ++#define XUSB_CFG_CSB_BASE_ADDR 0x800 ++ ++#define CSB_PAGE_SELECT_MASK 0x7fffff ++#define CSB_PAGE_SELECT_SHIFT 9 ++#define CSB_PAGE_OFFSET_MASK 0x1ff ++#define CSB_PAGE_SELECT(addr) ((addr) >> (CSB_PAGE_SELECT_SHIFT) & \ ++ CSB_PAGE_SELECT_MASK) ++#define CSB_PAGE_OFFSET(addr) ((addr) & CSB_PAGE_OFFSET_MASK) ++ ++/* Falcon CSB registers */ ++#define XUSB_FALC_CPUCTL 0x100 ++#define CPUCTL_STARTCPU BIT(1) ++#define CPUCTL_STATE_HALTED BIT(4) ++#define CPUCTL_STATE_STOPPED BIT(5) ++#define XUSB_FALC_BOOTVEC 0x104 ++#define XUSB_FALC_DMACTL 0x10c ++#define XUSB_FALC_IMFILLRNG1 0x154 ++#define IMFILLRNG1_TAG_MASK 0xffff ++#define IMFILLRNG1_TAG_LO_SHIFT 0 ++#define IMFILLRNG1_TAG_HI_SHIFT 16 ++#define XUSB_FALC_IMFILLCTL 0x158 ++ ++/* MP CSB registers */ ++#define XUSB_CSB_MP_ILOAD_ATTR 0x101a00 ++#define XUSB_CSB_MP_ILOAD_BASE_LO 0x101a04 ++#define XUSB_CSB_MP_ILOAD_BASE_HI 0x101a08 ++#define XUSB_CSB_MP_L2IMEMOP_SIZE 0x101a10 ++#define L2IMEMOP_SIZE_SRC_OFFSET_SHIFT 8 ++#define L2IMEMOP_SIZE_SRC_OFFSET_MASK 0x3ff ++#define L2IMEMOP_SIZE_SRC_COUNT_SHIFT 24 ++#define L2IMEMOP_SIZE_SRC_COUNT_MASK 0xff ++#define XUSB_CSB_MP_L2IMEMOP_TRIG 0x101a14 ++#define L2IMEMOP_ACTION_SHIFT 24 ++#define L2IMEMOP_INVALIDATE_ALL (0x40 << L2IMEMOP_ACTION_SHIFT) ++#define L2IMEMOP_LOAD_LOCKED_RESULT (0x11 << L2IMEMOP_ACTION_SHIFT) ++#define XUSB_CSB_MEMPOOL_L2IMEMOP_RESULT 0x00101A18 ++#define L2IMEMOP_RESULT_VLD BIT(31) ++#define XUSB_CSB_MP_APMAP 0x10181C ++#define APMAP_BOOTPATH BIT(31) ++ ++#define IMEM_BLOCK_SIZE 256 ++#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) ++ ++#define FW_IOCTL_LOG_DEQUEUE_LOW 4 ++#define FW_IOCTL_LOG_DEQUEUE_HIGH 5 ++#define FW_IOCTL_DATA_SHIFT 0 ++#define FW_IOCTL_DATA_MASK 0x00ffffff ++#define FW_IOCTL_TYPE_SHIFT 24 ++#define FW_IOCTL_TYPE_MASK 0xff000000 ++ ++#define SIMPLE_PLLE (CLOCK_ID_EPCI - CLOCK_ID_FIRST_SIMPLE) ++ ++#define USB2_BIAS_PAD 18 ++ ++#define EN_FPCI BIT(0) ++#define BUS_MASTER BIT(2) ++#define MEMORY_SPACE BIT(1) ++#define IP_INT_MASK BIT(16) ++#define CLK_DISABLE_CNT 0x80 ++ ++struct tegra_xhci_softc { ++ u32 fw_size; ++ void *fw_data; ++ u64 fw_dma_addr; ++ bool xhci_inited; ++ char *fw_name; ++}; ++ ++int tegra_uphy_pll_enable(void); ++void padctl_usb3_port_init(int); ++void pad_trk_init(u32); ++void do_padctl_usb2_config(void); ++ ++#endif /* _TEGRA_XHCI_H_ */ +diff --git drivers/usb/host/tegra_xhci_fw.c drivers/usb/host/tegra_xhci_fw.c +new file mode 100644 +index 0000000000..1dd28ffafc +--- /dev/null ++++ drivers/usb/host/tegra_xhci_fw.c +@@ -0,0 +1,223 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Copyright (c) 2020 NVIDIA Corporation */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "tegra_xhci_fw.h" ++ ++#define FW_FROM_PARTITION 0 ++ ++static inline u32 fpci_to_phys(u32 fpci_addr) ++{ ++ return PCIE_DEVICE_CONFIG_BASE + fpci_addr; ++} ++ ++u32 fpci_readl(u32 addr) ++{ ++ u64 phys_addr = (u64)fpci_to_phys(addr); ++ u32 val = *(volatile u32 *)phys_addr; ++ ++ debug("%s addr 0x%x val 0x%x\n", __func__, addr, val); ++ ++ return val; ++} ++ ++void fpci_writel(u32 val, u32 addr) ++{ ++ u64 phys_addr = (u64)fpci_to_phys(addr); ++ ++ debug("%s addr 0x%x val 0x%x\n", __func__, addr, val); ++ *(volatile u32 *)phys_addr = val; ++} ++ ++static u32 csb_readl(u32 addr) ++{ ++ u32 page, offset; ++ u32 val; ++ ++ page = CSB_PAGE_SELECT(addr); ++ offset = CSB_PAGE_OFFSET(addr); ++ fpci_writel(page, XUSB_CFG_ARU_C11_CSBRANGE); ++ val = fpci_readl(XUSB_CFG_CSB_BASE_ADDR + offset); ++ ++ debug("%s addr 0x%x val 0x%x\n", __func__, addr, val); ++ ++ return val; ++} ++ ++static void csb_writel(u32 val, u32 addr) ++{ ++ u32 page, offset; ++ ++ debug("%s addr 0x%x val 0x%x\n", __func__, addr, val); ++ ++ page = CSB_PAGE_SELECT(addr); ++ offset = CSB_PAGE_OFFSET(addr); ++ fpci_writel(page, XUSB_CFG_ARU_C11_CSBRANGE); ++ fpci_writel(val, XUSB_CFG_CSB_BASE_ADDR + offset); ++} ++ ++#if FW_FROM_PARTITION ++static void *get_firmware_blob(u32 *size) ++{ ++ /* ++ * Eventually we should make U-Boot find the RP4 partition and read ++ * it in to decouple us from CBoot. TBD in a future patch. ++ */ ++ *size = 124416; ++ return env_get_hex("xusb_fw_addr", 0); ++} ++#endif ++ ++int xhci_load_firmware(u64 fw_addr) ++{ ++#if FW_FROM_PARTITION ++ u8 *fw_buffer = NULL; ++ u32 fw_size = 0; ++#endif ++ struct xhci_firmware_cfgtbl *cfgtbl; ++ struct tegra_xhci_softc *sc; ++ u32 val, code_tag_blocks, code_size_blocks; ++ u64 fw_base; ++ int timeout, err = 0; ++ ++ sc = (struct tegra_xhci_softc *)malloc(sizeof(struct tegra_xhci_softc)); ++ ++#if FW_FROM_PARTITION ++ fw_buffer = get_firmware_blob(&fw_size); ++ if (!fw_buffer) { ++ printf("No USB firmware found!!\n"); ++ err = -ENODEV; ++ goto error; ++ } ++ ++ debug("XUSB blob size %d @ %p\n", fw_size, fw_buffer); ++#endif ++ ++ val = fpci_readl(XUSB_CFG_0); ++ if (val == XHCI_PCI_ID) { ++#if FW_FROM_PARTITION ++ cfgtbl = (struct xhci_firmware_cfgtbl *)fw_buffer; ++#else ++ cfgtbl = (struct xhci_firmware_cfgtbl *)fw_addr; ++ debug("XUSB blob size %d @ %X\n", cfgtbl->fwimg_len, ++ (u32)fw_addr); ++#endif ++ } else { ++ printf("Unknown controller 0x%08x\n", val); ++ err = -ENODEV; ++ goto error; ++ } ++ ++ printf("\nFirmware size %d\n", cfgtbl->fwimg_len); ++ sc->fw_size = cfgtbl->fwimg_len; ++ sc->fw_data = (void *)noncached_alloc(sc->fw_size, 256); ++ sc->fw_dma_addr = (u64)sc->fw_data; ++ ++ if (!sc->fw_data) { ++ printf("Alloc memory for firmware failed\n"); ++ err = -ENOMEM; ++ goto error; ++ } ++ memcpy(sc->fw_data, cfgtbl, sc->fw_size); ++ cfgtbl = sc->fw_data; ++ ++ if (csb_readl(XUSB_CSB_MP_ILOAD_BASE_LO) != 0) { ++ printf("Firmware already loaded, Falcon state %#x\n", ++ csb_readl(XUSB_FALC_CPUCTL)); ++ err = -EEXIST; ++ goto error; ++ } ++ ++ /* Program the size of DFI into ILOAD_ATTR. */ ++ csb_writel(sc->fw_size, XUSB_CSB_MP_ILOAD_ATTR); ++ ++ /* ++ * Boot code of the firmware reads the ILOAD_BASE registers ++ * to get to the start of the DFI in system memory. ++ */ ++ fw_base = sc->fw_dma_addr + sizeof(*cfgtbl); ++ csb_writel(fw_base, XUSB_CSB_MP_ILOAD_BASE_LO); ++ csb_writel(fw_base >> 32, XUSB_CSB_MP_ILOAD_BASE_HI); ++ ++ /* Set BOOTPATH to 1 in APMAP. */ ++ csb_writel(APMAP_BOOTPATH, XUSB_CSB_MP_APMAP); ++ ++ /* Invalidate L2IMEM. */ ++ csb_writel(L2IMEMOP_INVALIDATE_ALL, XUSB_CSB_MP_L2IMEMOP_TRIG); ++ ++ /* ++ * Initiate fetch of bootcode from system memory into L2IMEM. ++ * Program bootcode location and size in system memory. ++ */ ++ code_tag_blocks = DIV_ROUND_UP(cfgtbl->boot_codetag, IMEM_BLOCK_SIZE); ++ code_size_blocks = DIV_ROUND_UP(cfgtbl->boot_codesize, IMEM_BLOCK_SIZE); ++ ++ val = ((code_tag_blocks & L2IMEMOP_SIZE_SRC_OFFSET_MASK) << ++ L2IMEMOP_SIZE_SRC_OFFSET_SHIFT) | ++ ((code_size_blocks & L2IMEMOP_SIZE_SRC_COUNT_MASK) << ++ L2IMEMOP_SIZE_SRC_COUNT_SHIFT); ++ csb_writel(val, XUSB_CSB_MP_L2IMEMOP_SIZE); ++ ++ /* Trigger L2IMEM Load operation. */ ++ csb_writel(L2IMEMOP_LOAD_LOCKED_RESULT, XUSB_CSB_MP_L2IMEMOP_TRIG); ++ ++ /* Setup Falcon Auto-fill. */ ++ csb_writel(code_size_blocks, XUSB_FALC_IMFILLCTL); ++ ++ val = ((code_tag_blocks & IMFILLRNG1_TAG_MASK) << ++ IMFILLRNG1_TAG_LO_SHIFT) | ++ (((code_size_blocks + code_tag_blocks) & IMFILLRNG1_TAG_MASK) << ++ IMFILLRNG1_TAG_HI_SHIFT); ++ csb_writel(val, XUSB_FALC_IMFILLRNG1); ++ ++ printf("Firmware timestamp: 0x%08x, Version: %2x.%02x %s\n\n", ++ cfgtbl->fwimg_created_time, ++ FW_MAJOR_VERSION(cfgtbl->version_id), ++ FW_MINOR_VERSION(cfgtbl->version_id), ++ (cfgtbl->build_log == LOG_MEMORY) ? "debug" : "release"); ++ ++ csb_writel(0, XUSB_FALC_DMACTL); ++ mdelay(50); ++ ++ /* wait for RESULT_VLD to get set */ ++ timeout = 1000; ++ do { ++ val = csb_readl(XUSB_CSB_MEMPOOL_L2IMEMOP_RESULT); ++ if (val & L2IMEMOP_RESULT_VLD) ++ break; ++ udelay(10); ++ } while (timeout--); ++ ++ if (!(val & L2IMEMOP_RESULT_VLD)) ++ printf("DMA controller not ready 0x08%x\n", val); ++ ++ csb_writel(cfgtbl->boot_codetag, XUSB_FALC_BOOTVEC); ++ ++ /* Start Falcon CPU */ ++ csb_writel(CPUCTL_STARTCPU, XUSB_FALC_CPUCTL); ++ udelay(2000); ++ ++ /* wait for Falcon to enter STOPPED mode */ ++ timeout = 200; ++ do { ++ val = csb_readl(XUSB_FALC_CPUCTL); ++ if (val & CPUCTL_STATE_STOPPED) ++ break; ++ mdelay(1); ++ } while (timeout--); ++ ++ val = csb_readl(XUSB_FALC_CPUCTL); ++ if (!(val & CPUCTL_STATE_STOPPED)) { ++ printf("Falcon not stopped. Falcon state: 0x%x\n", ++ csb_readl(XUSB_FALC_CPUCTL)); ++ err = -EIO; ++ } ++ ++error: ++ free(sc); ++ return err; ++} +diff --git drivers/usb/host/tegra_xhci_fw.h drivers/usb/host/tegra_xhci_fw.h +new file mode 100644 +index 0000000000..a439fd9ccb +--- /dev/null ++++ drivers/usb/host/tegra_xhci_fw.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* Copyright (c) 2020 NVIDIA Corporation */ ++ ++#ifndef __TEGRA_XHCI_FW_H__ ++#define __TEGRA_XHCI_FW_H__ ++ ++#include "tegra_xhci.h" ++ ++struct xhci_firmware_cfgtbl { ++ u32 boot_loadaddr_in_imem; ++ u32 boot_codedfi_offset; ++ u32 boot_codetag; ++ u32 boot_codesize; ++ u32 phys_memaddr; ++ u16 reqphys_memsize; ++ u16 alloc_phys_memsize; ++ u32 rodata_img_offset; ++ u32 rodata_section_start; ++ u32 rodata_section_end; ++ u32 main_fnaddr; ++ u32 fwimg_cksum; ++ u32 fwimg_created_time; ++ u32 imem_resident_start; ++ u32 imem_resident_end; ++ u32 idirect_start; ++ u32 idirect_end; ++ u32 l2_imem_start; ++ u32 l2_imem_end; ++ u32 version_id; ++ u8 init_ddirect; ++ u8 reserved[3]; ++ u32 phys_addr_log_buffer; ++ u32 total_log_entries; ++ u32 dequeue_ptr; ++ u32 dummy_var[2]; ++ u32 fwimg_len; ++ u8 magic[8]; ++ u32 ss_low_power_entry_timeout; ++ u8 num_hsic_port; ++ u8 ss_portmap; ++ u8 build_log:4; ++ u8 build_type:4; ++ u8 chip_revision[3]; ++ u8 reserved2[2]; ++ u32 falcon_clock_freq; ++ u32 slots_in_each_vf; ++ u32 port_owner[2]; /* 0: ss, 1: hs */ ++ u8 padding[116]; /* Padding to make 256-byte cfgtbl */ ++}; ++ ++int xhci_load_firmware(u64 fw_addr); ++ ++#endif /* __TEGRA_XHCI_FW_H__ */ +diff --git drivers/usb/host/xhci-mem.c drivers/usb/host/xhci-mem.c +index 0d9da62bab..a41ee5d614 100644 +--- drivers/usb/host/xhci-mem.c ++++ drivers/usb/host/xhci-mem.c +@@ -66,7 +66,10 @@ void xhci_inval_cache(uintptr_t addr, u32 len) + */ + static void xhci_segment_free(struct xhci_segment *seg) + { ++#ifdef CONFIG_SYS_NONCACHED_MEMORY ++#else + free(seg->trbs); ++#endif + seg->trbs = NULL; + + free(seg); +@@ -111,7 +114,10 @@ static void xhci_scratchpad_free(struct xhci_ctrl *ctrl) + ctrl->dcbaa->dev_context_ptrs[0] = 0; + + free(xhci_bus_to_virt(ctrl, le64_to_cpu(ctrl->scratchpad->sp_array[0]))); ++#ifdef CONFIG_SYS_NONCACHED_MEMORY ++#else + free(ctrl->scratchpad->sp_array); ++#endif + free(ctrl->scratchpad); + ctrl->scratchpad = NULL; + } +@@ -124,7 +130,10 @@ static void xhci_scratchpad_free(struct xhci_ctrl *ctrl) + */ + static void xhci_free_container_ctx(struct xhci_container_ctx *ctx) + { ++#ifdef CONFIG_SYS_NONCACHED_MEMORY ++#else + free(ctx->bytes); ++#endif + free(ctx); + } + +@@ -178,8 +187,12 @@ void xhci_cleanup(struct xhci_ctrl *ctrl) + xhci_ring_free(ctrl->cmd_ring); + xhci_scratchpad_free(ctrl); + xhci_free_virt_devices(ctrl); ++#ifdef CONFIG_SYS_NONCACHED_MEMORY ++ /* FIXME: noncached_alloc() has no opposite */ ++#else + free(ctrl->erst.entries); + free(ctrl->dcbaa); ++#endif + memset(ctrl, '\0', sizeof(struct xhci_ctrl)); + } + +@@ -194,7 +207,12 @@ static void *xhci_malloc(unsigned int size) + void *ptr; + size_t cacheline_size = max(XHCI_ALIGNMENT, CACHELINE_SIZE); + ++#ifdef CONFIG_SYS_NONCACHED_MEMORY ++ ptr = (void *)noncached_alloc(ALIGN(size, cacheline_size), ++ cacheline_size); ++#else + ptr = memalign(cacheline_size, ALIGN(size, cacheline_size)); ++#endif + BUG_ON(!ptr); + memset(ptr, '\0', size); + +@@ -404,8 +422,10 @@ static int xhci_scratchpad_alloc(struct xhci_ctrl *ctrl) + return 0; + + fail_sp3: ++#ifdef CONFIG_SYS_NONCACHED_MEMORY ++#else + free(scratchpad->sp_array); +- ++#endif + fail_sp2: + free(scratchpad); + ctrl->scratchpad = NULL; +diff --git drivers/usb/host/xhci-tegra-padctl.c drivers/usb/host/xhci-tegra-padctl.c +new file mode 100644 +index 0000000000..7def1b4071 +--- /dev/null ++++ drivers/usb/host/xhci-tegra-padctl.c +@@ -0,0 +1,397 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Copyright (c) 2021 NVIDIA Corporation */ ++ ++/* Tegra210 XUSB pad ctl init, move to padctl driver later */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "xusb-macros.h" ++#include "tegra_xhci.h" ++ ++int tegra_uphy_pll_enable(void) ++{ ++ u32 val; ++ unsigned long start; ++ ++ debug("%s: entry\n", __func__); ++ ++ /* UPHY PLL init from TRM, page 1391 */ ++ /* 1. Deassert PLL/Lane resets */ ++ reset_set_enable(PERIPH_ID_PEX_USB_UPHY, 0); ++ ++ /* Set cal values and overrides ++ * (0x364, b27:4)- UPHY_PLL_P0_CTL_2_0[PLL0_CAL_CTRL] = 0x136 ++ * (0x370, b23:16)- UPHY_PLL_P0_CTL_5_0[PLL0_DCO_CTRL] = 0x2A ++ * (0x360, b4)- UPHY_PLL_P0_CTL_1_0[PLL0_PWR_OVRD] = 1 (Default) ++ * (0x364, b2)- UPHY_PLL_P0_CTL_2_0[PLL0_CAL_OVRD] = 1 ++ * (0x37C, b15)- UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_OVRD] = 1 ++ */ ++ val = (0x136 << 4); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_2, val); ++ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_5, val); ++ val &= 0x0000FFFF; ++ val |= (0x2A << 16); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_5, val); ++ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_1, val); ++ val |= (1 << 4); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_1, val); ++ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_2, val); ++ val |= (1 << 2); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_2, val); ++ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_8, val); ++ val |= (1 << 15); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_8, val); ++ ++ /* 2. Other reg bits (P0_CTL4, P0_CTL_1 MDIV/NDIV/PSDIV) defaults OK ++ * (0x360, b0)- UPHY_PLL_P0_CTL_1_0[PLL0_IDDQ] = 0 ++ * (0x360, b2:1)- UPHY_PLL_P0_CTL_1_0[PLL0_SLEEP] = 00 ++ */ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_1, val); ++ val &= ~(7 << 0); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_1, val); ++ ++ /* 3. Wait 100 ns */ ++ udelay(1); ++ ++ /* 4. Calibration ++ * (0x364, b0)- UPHY_PLL_P0_CTL_2_0[PLL0_CAL_EN] = 1 ++ * (0x364, b1)- Wait for UPHY_PLL_P0_CTL_2_0[PLL0_CAL_DONE] == 1 ++ * (0x364, b0)- UPHY_PLL_P0_CTL_2_0[PLL0_CAL_EN] = 0 ++ * (0x364), b1- Wait for UPHY_PLL_P0_CTL_2_0[PLL0_CAL_DONE] == 0 ++ */ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_2, val); ++ val |= (1 << 0); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_2, val); ++ ++ debug("%s: Waiting for calibration done ...", __func__); ++ start = get_timer(0); ++ ++ while (get_timer(start) < 250) { ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_2, val); ++ if (val & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE) ++ break; ++ } ++ ++ if (!(val & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE)) { ++ debug(" timeout\n"); ++ return -ETIMEDOUT; ++ } ++ debug("done\n"); ++ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_2, val); ++ val &= ~(1 << 0); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_2, val); ++ ++ debug("%s: Waiting for calibration done == 0 ...", __func__); ++ start = get_timer(0); ++ ++ while (get_timer(start) < 250) { ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_2, val); ++ if ((val & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE) == 0) ++ break; ++ } ++ ++ if (val & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE) { ++ debug(" timeout\n"); ++ return -ETIMEDOUT; ++ } ++ debug("done\n"); ++ ++ /* 5. Enable the PLL (20 µs Lock time) ++ * (0x360, b3)- UPHY_PLL_P0_CTL_1_0[PLL0_ENABLE] = 1 ++ * (0x360, b15)- Wait for UPHY_PLL_P0_CTL_1_0[PLL0_LOCKDET_STATUS] == 1 ++ */ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_1, val); ++ val |= (1 << 3); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_1, val); ++ ++ debug("%s: Waiting for lock detect ...", __func__); ++ start = get_timer(0); ++ ++ while (get_timer(start) < 250) { ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_1, val); ++ if (val & XUSB_PADCTL_UPHY_PLL_P0_CTL1_PLL0_LOCKDET) ++ break; ++ } ++ ++ if (!(val & XUSB_PADCTL_UPHY_PLL_P0_CTL1_PLL0_LOCKDET)) { ++ debug(" timeout\n"); ++ return -ETIMEDOUT; ++ } ++ debug("done\n"); ++ ++ /* 6. RCAL ++ * (0x37C, b12)- UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_EN] = 1 ++ * (0x37C, b13)- UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_CLK_EN] = 1 ++ * (0x37C, b31)- Wait for UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_DONE] == 1 ++ * (0x37C, b12)- UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_EN] = 0 ++ * (0x37C, b31)- Wait for UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_DONE] == 0 ++ * (0x37C, b13)- UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_CLK_EN] = 0 ++ */ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_8, val); ++ val |= (3 << 12); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_8, val); ++ ++ debug("%s: Waiting for rcal done ...", __func__); ++ start = get_timer(0); ++ ++ while (get_timer(start) < 250) { ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_8, val); ++ if (val & XUSB_PADCTL_UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE) ++ break; ++ } ++ ++ if (!(val & XUSB_PADCTL_UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE)) { ++ debug(" timeout\n"); ++ return -ETIMEDOUT; ++ } ++ debug("done\n"); ++ ++ val &= ~(1 << 12); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_8, val); ++ ++ debug("%s: Waiting for rcal done == 0 ...", __func__); ++ start = get_timer(0); ++ ++ while (get_timer(start) < 250) { ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_8, val); ++ if ((val & XUSB_PADCTL_UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE) == 0) ++ break; ++ } ++ ++ if (val & XUSB_PADCTL_UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE) { ++ debug(" timeout\n"); ++ return -ETIMEDOUT; ++ } ++ debug("done\n"); ++ ++ val &= ~(1 << 13); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_8, val); ++ ++ /* Finally, lift PADCTL overrides ++ * (0x360, b4)- UPHY_PLL_P0_CTL_1_0[PLL0_PWR_OVRD] = 0 ++ * (0x364, b2)- UPHY_PLL_P0_CTL_2_0[PLL0_CAL_OVRD] = 0 ++ * (0x37C, b15)- UPHY_PLL_P0_CTL_8_0[PLL0_RCAL_OVRD] = 0 ++ */ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_1, val); ++ val &= ~(1 << 4); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_1, val); ++ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_2, val); ++ val &= ~(1 << 2); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_2, val); ++ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_8, val); ++ val &= ~(1 << 15); ++ NV_XUSB_PADCTL_WRITE(UPHY_PLL_P0_CTL_8, val); ++ ++ return 0; ++} ++ ++void padctl_usb3_port_init(int board_id) ++{ ++ int i, port; ++ u32 reg, val; ++ debug("%s: entry\n", __func__); ++ ++ /* Set SS_PORT_MAP, SS PORT0 maps to USB2 PORT1 on all boards */ ++ reg = XUSB_PADCTL_SS_PORT_MAP_0; ++ NV_XUSB_PADCTL_READ(SS_PORT_MAP, val); ++ debug("%s: reg %X: val read = %X\n", __func__, reg, val); ++ val &= ~SS_PORT_MAP(0, SS_PORT_MAP_PORT_DISABLED); ++ val |= SS_PORT_MAP(0, 1); ++ /* Set SS PORT1 maps to USB2 PORT2 on TX1 */ ++ if (board_id == 2371) { ++ val &= ~SS_PORT_MAP(1, SS_PORT_MAP_PORT_DISABLED); ++ val |= SS_PORT_MAP(1, 2); ++ } ++ NV_XUSB_PADCTL_WRITE(SS_PORT_MAP, val); ++ debug("%s: Wrote 0x%08X to 0x7009F%03X\n", __func__, val, reg); ++ ++ /* Set ELPG_PROGRAM_1 clamp bits next */ ++ reg = XUSB_PADCTL_ELPG_PROGRAM_1_0; ++ NV_XUSB_PADCTL_READ(ELPG_PROGRAM_1, val); ++ debug("%s: reg %X: val read = %X\n", __func__, reg, val); ++ ++ /* Unclamp SSP0 & SSP3 */ ++ port = 0; ++ val &= ~SSPX_ELPG_CLAMP_EN(port); ++ val &= ~SSPX_ELPG_CLAMP_EN_EARLY(port); ++ val &= ~SSPX_ELPG_VCORE_DOWN(port); ++ port = 3; ++ val &= ~SSPX_ELPG_CLAMP_EN(port); ++ val &= ~SSPX_ELPG_CLAMP_EN_EARLY(port); ++ val &= ~SSPX_ELPG_VCORE_DOWN(port); ++ /* Unclamp PORT1 on TX1 */ ++ if (board_id == 2371) { ++ port = 1; ++ val &= ~SSPX_ELPG_CLAMP_EN(port); ++ val &= ~SSPX_ELPG_CLAMP_EN_EARLY(port); ++ val &= ~SSPX_ELPG_VCORE_DOWN(port); ++ } ++ val &= ~AUX_MUX_LP0_CLAMP_EN; ++ val &= ~AUX_MUX_LP0_CLAMP_EN_EARLY; ++ val &= ~AUX_MUX_LP0_VCORE_DOWN; ++ NV_XUSB_PADCTL_WRITE(ELPG_PROGRAM_1, val); ++ debug("%s: Wrote 0x%08X to 0x7009F%03X\n", __func__, val, reg); ++ ++ /* Set USB3_PAD_MUX, XUSB_PADCTL reset clears PCIE IDDQ bits 8-0 */ ++ reg = XUSB_PADCTL_USB3_PAD_MUX_0; ++ NV_XUSB_PADCTL_READ(USB3_PAD_MUX, val); ++ debug("%s: reg %X: val read = %X\n", __func__, reg, val); ++ for (i = 0; i < 7; i++) ++ val |= FORCE_PCIE_PAD_IDDQ_DISABLE(i); ++ val |= FORCE_SATA_PAD_IDDQ_DISABLE(0); ++ NV_XUSB_PADCTL_WRITE(USB3_PAD_MUX, val); ++ debug("%s: Wrote 0x%08X to 0x7009F%03X\n", __func__, val, reg); ++} ++ ++void pad_trk_init(u32 hs_squelch) ++{ ++ u32 val; ++ ++ debug("%s: entry\n", __func__); ++ ++ /* Enable tracking clock */ ++ clock_enable(PERIPH_ID_USB2_TRK); ++ ++ NV_XUSB_PADCTL_READ(USB2_PAD_MUX, val); ++ val &= ~(3 << USB2_BIAS_PAD); ++ val |= (1 << USB2_BIAS_PAD); /* 1 = XUSB */ ++ NV_XUSB_PADCTL_WRITE(USB2_PAD_MUX, val); ++ ++ NV_XUSB_PADCTL_READ(USB2_BIAS_PAD_CTL_1, val); ++ val &= ~USB2_TRK_START_TIMER(~0); ++ val |= USB2_TRK_START_TIMER(0x1E); /* START TIMER = 30 */ ++ val &= ~USB2_TRK_DONE_RESET_TIMER(~0); ++ val |= USB2_TRK_DONE_RESET_TIMER(0x0A); /* DONE TIMER = 10 */ ++ NV_XUSB_PADCTL_WRITE(USB2_BIAS_PAD_CTL_1, val); ++ ++ NV_XUSB_PADCTL_READ(USB2_BIAS_PAD_CTL_0, val); ++ ++ val &= ~BIAS_PAD_PD; /* PD = 0 */ ++ val &= ~HS_DISCON_LEVEL(~0); ++ val |= HS_DISCON_LEVEL(0x7); ++ val &= ~HS_SQUELCH_LEVEL(~0); ++ val |= HS_SQUELCH_LEVEL(hs_squelch); ++ NV_XUSB_PADCTL_WRITE(USB2_BIAS_PAD_CTL_0, val); ++ ++ udelay(1); ++ ++ NV_XUSB_PADCTL_READ(USB2_BIAS_PAD_CTL_1, val); ++ val &= ~USB2_PD_TRK; /* Enable tracking */ ++ NV_XUSB_PADCTL_WRITE(USB2_BIAS_PAD_CTL_1, val); ++} ++ ++void do_padctl_usb2_config(void) ++{ ++ int i, index; ++ u32 reg, val; ++ u32 *xusbpadctl = (u32 *)NV_ADDRESS_MAP_APB_XUSB_PADCTL_BASE; ++ ++ u32 hs_curr_level[4]; ++ u32 hs_curr_level_offset = 0; ++ u32 hs_squelch, hs_term_range_adj, rpd_ctrl; ++ u32 fuse_calib, fuse_calib_ext; ++ ++ debug("%s: entry\n", __func__); ++ ++ /* Set USB2 BIAS pad and USB2 OTG Port0 pad to 'XUSB' */ ++ reg = XUSB_PADCTL_USB2_PAD_MUX_0; ++ NV_XUSB_PADCTL_READ(USB2_PAD_MUX, val); ++ debug("%s: reg %X: val read = %X\n", __func__, reg, val); ++ val &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK << ++ XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT); ++ val |= XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB << ++ XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT; ++ ++ val &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK << ++ XUSB_PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_SHIFT); ++ val |= XUSB_PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB << ++ XUSB_PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_SHIFT; ++ NV_XUSB_PADCTL_WRITE(USB2_PAD_MUX, val); ++ debug("%s: Wrote 0x%08X to 0x7009F%03X\n", __func__, val, reg); ++ ++ /* Clear all SS/USB2/HSIC wakeup event bits */ ++ val = 0x41E00780; ++ reg = XUSB_PADCTL_ELPG_PROGRAM_0_0; ++ NV_XUSB_PADCTL_WRITE(ELPG_PROGRAM_0, val); ++ debug("%s: Wrote 0x%08X to 0x7009F%03X\n", __func__, val, reg); ++ ++ /* Set up USB2 pads */ ++ reg = XUSB_PADCTL_USB2_PORT_CAP_0; ++ NV_XUSB_PADCTL_READ(USB2_PORT_CAP, val); ++ debug("%s: reg %X: val read = %X\n", __func__, reg, val); ++ ++ /* PORT0 = OTG */ ++ index = 0; ++ val &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index); ++ val |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index); ++ /* PORT1 = HOST */ ++ index++; ++ val &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index); ++ val |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index); ++ /* PORT2 = HOST */ ++ index++; ++ val &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index); ++ val |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index); ++ /* PORT3 = DISABLED */ ++ index++; ++ val &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index); ++ val |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index); ++ NV_XUSB_PADCTL_WRITE(USB2_PORT_CAP, val); ++ debug("%s: Wrote 0x%08X to 0x7009F%03X\n", __func__, val, reg); ++ ++ /* Read USB calib fuse & ext values */ ++ fuse_calib = readl(FUSE_USB_CALIB_0); ++ fuse_calib_ext = readl(FUSE_USB_CALIB_EXT_0); ++ debug("%s: FUSE_CALIB regs = 0x%08X/0x%08X\n", __func__, fuse_calib, fuse_calib_ext); ++ ++ for (i = 0; i < ARRAY_SIZE(hs_curr_level); i++) { ++ hs_curr_level[i] = (fuse_calib >> HS_CURR_LEVEL_PADX_SHIFT(i)) & ++ HS_CURR_LEVEL_PAD_MASK; ++ } ++ ++ hs_squelch = (fuse_calib >> HS_SQUELCH_SHIFT) & HS_SQUELCH_MASK; ++ hs_term_range_adj = ++ (fuse_calib >> HS_TERM_RANGE_ADJ_SHIFT) & HS_TERM_RANGE_ADJ_MASK; ++ rpd_ctrl = (fuse_calib_ext >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK; ++ ++ debug("%s: HS_SQUELCH = 0x%X, HS_TERM_RANGE_ADJ = 0x%X\n", __func__, hs_squelch, hs_term_range_adj); ++ debug(" RPD_CTRL = 0x%X\n", rpd_ctrl); ++ ++ for (i = 0; i < ARRAY_SIZE(hs_curr_level); i++) ++ debug("HS_CURR_LEVEL[%d] = 0x%02X\n", i, hs_curr_level[i]); ++ ++ for (index = 0; index < 3; index++) { ++ reg = XUSB_PADCTL_USB2_OTG_PADX_CTL_0(index); ++ val = readl(xusbpadctl + (reg / 4)); ++ val &= ~USB2_OTG_PD; ++ val &= ~USB2_OTG_PD_ZI; ++ val &= ~HS_CURR_LEVEL(~0); ++ val |= HS_CURR_LEVEL(hs_curr_level[index] + hs_curr_level_offset); ++ writel(val, xusbpadctl + (reg / 4)); ++ debug("%s: %d: Wrote 0x%08X to 0x7009F%03X\n", __func__, index, val, reg); ++ ++ reg = XUSB_PADCTL_USB2_OTG_PADX_CTL_1(index); ++ val = readl(xusbpadctl + (reg / 4)); ++ val &= ~TERM_RANGE_ADJ(~0); ++ val &= ~RPD_CTRL(~0); ++ val |= TERM_RANGE_ADJ(hs_term_range_adj); ++ val |= RPD_CTRL(rpd_ctrl); ++ val &= ~USB2_OTG_PD_DR; ++ writel(val, xusbpadctl + (reg / 4)); ++ debug("%s: %d: Wrote 0x%08X to 0x7009F%03X\n", __func__, index, val, reg); ++ } ++ ++ /* Setup pad tracking */ ++ pad_trk_init(hs_squelch); ++} +diff --git drivers/usb/host/xhci-tegra.c drivers/usb/host/xhci-tegra.c +new file mode 100644 +index 0000000000..78903fb90b +--- /dev/null ++++ drivers/usb/host/xhci-tegra.c +@@ -0,0 +1,397 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Copyright (c) 2020-2021 NVIDIA Corporation */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tegra_xhci_fw.h" ++#include "xusb-macros.h" ++ ++/* Declare global data pointer */ ++DECLARE_GLOBAL_DATA_PTR; ++ ++struct tegra_xhci_platdata { ++ fdt_addr_t hcd_base; /* Host controller base address */ ++ struct gpio_desc vbus_gpio; /* VBUS for GPIO enable */ ++ fdt_addr_t fw_addr; /* XUSB firmware address in memory */ ++}; ++ ++/** ++ * Contains pointers to register base addresses for the usb controller. ++ */ ++struct tegra_xhci { ++ struct usb_plat usb_plat; ++ struct xhci_ctrl ctrl; ++ struct xhci_hccr *hcd; ++}; ++ ++int find_rp4_data(char *fwbuffer, long size); ++ ++static int tegra_xhci_usb_ofdata_to_platdata(struct udevice *dev) ++{ ++ struct tegra_xhci_platdata *plat = dev_get_plat(dev); ++ int ret = 0; ++ long size = SZ_128K; /* size of RP4 blob */ ++ char *fwbuf; ++ ++ debug("%s: entry\n", __func__); ++ ++ /* Get the base address for XHCI controller from the device node */ ++ plat->hcd_base = dev_read_addr(dev); ++ debug("%s: dev_get_addr returns HCD base of 0x%08X\n", __func__, ++ (u32)plat->hcd_base); ++ if (plat->hcd_base == FDT_ADDR_T_NONE) { ++ pr_err("Can't get the XHCI register base address!\n"); ++ ret = -ENXIO; ++ goto errout; ++ } ++ ++ /* Vbus gpio */ ++ gpio_request_by_name(dev, "nvidia,vbus-gpio", 0, &plat->vbus_gpio, ++ GPIOD_IS_OUT); ++#ifdef CBOOT_RP4_LOAD ++ /* Get the XUSB firmware address that CBoot saved to DTB, now in env */ ++ plat->fw_addr = env_get_hex("xusb_fw_addr", 0); ++ ++ if (plat->fw_addr) { ++ debug("%s: XUSB FW is @ 0x%08X\n", __func__, ++ (u32)plat->fw_addr); ++ } else { ++ pr_err("Can't get the XUSB firmware load address!\n"); ++ ret = -ENXIO; ++ } ++ ++#else /* !CBOOT_RP4_LOAD */ ++ ++ /* allocate 128KB for RP4 FW, pass to find_rp4_data */ ++ fwbuf = malloc(size); ++ if (!fwbuf) { ++ pr_err("Could not allocate %ld byte RP4 buffer!\n", size); ++ ret = -ENOMEM; ++ } ++ ++ /* Search QSPI (or eMMC) for RP4 blob, load it to fwbuf */ ++ ret = find_rp4_data(fwbuf, size); ++ if (!ret) { ++ debug("%s: Got some RP4 data!\n", __func__ ); ++ debug("[U-Boot] found XUSB FW @ 0x%p\n", fwbuf); ++ plat->fw_addr = (u64)fwbuf; ++ plat->fw_addr += 0x28C; ++ debug(" plat->fw_addr is now 0x%lld!\n", plat->fw_addr); ++ } else { ++ pr_err("Cannot read the RP4 data!\n"); ++ free(fwbuf); ++ ret = -ENXIO; ++ } ++#endif /* CBOOT_RP4_LOAD */ ++ ++errout: ++ return ret; ++} ++ ++ ++static void tegra_pllu_enable(void) ++{ ++ debug("%s: entry\n", __func__); ++ /* TODO: Enable PLLU here */ ++} ++ ++/* Simple hacky way to get board ID (3450, 3541, etc). */ ++static int get_board_id(void) ++{ ++ /* for ex, CONFIG_TEGRA_BOARD_STRING = "NVIDIA P3450-0000" */ ++ const char *board = CONFIG_TEGRA_BOARD_STRING; ++ int board_num; ++ ++ board_num = (int) simple_strtol(board+8, NULL, 10); ++ debug("%s: board = %d\n", __func__, board_num); ++ ++ return board_num; ++} ++ ++void do_tegra_xusb_padctl_init(void) ++{ ++ int board_id; ++ debug("%s: entry\n", __func__); ++ ++ board_id = get_board_id(); ++ debug("%s: Board ID = %d\n", __func__, board_id); ++ ++ /* Set up USB2 pads (MUX, CTLx, CAP, etc.) */ ++ do_padctl_usb2_config(); ++ ++ /* Set up SS port map */ ++ padctl_usb3_port_init(board_id); ++} ++ ++void xhci_clk_rst_init(struct tegra_xhci *tegra) ++{ ++ u32 reg_data; ++ u32 base = (uintptr_t)tegra->hcd; ++ struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; ++ ++ debug("%s: entry, XHCI base @ 0x%08X\n", __func__, base); ++ ++ clock_enable(PERIPH_ID_XUSB); ++ clock_enable(PERIPH_ID_XUSB_HOST); ++ ++ /* enable the clocks to individual XUSB partitions */ ++ clock_enable(PERIPH_ID_XUSB_DEV); ++ /* wait stabilization time (always) */ ++ udelay(NVBOOT_RESET_STABILIZATION_DELAY); ++ ++ clock_enable(PERIPH_ID_XUSB_SS); ++ udelay(NVBOOT_RESET_STABILIZATION_DELAY); ++ ++ /* disable PLLU OUT1 divider reset */ ++ reg_data = readl(&clkrst->crc_pll[CLOCK_ID_USB].pll_out[0]); ++ reg_data |= (1 << 0); /* bit 0 = OUT1_RSTN reset disable */ ++ writel(reg_data, &clkrst->crc_pll[CLOCK_ID_USB].pll_out[0]); ++ ++ /* Wait 2 us before using FO_48M clock */ ++ udelay(2); ++ ++ /* ++ * Set XUSB_CORE_HOST_CLK_SRC to 'PLLP_OUT0', divisor to 6 ++ * Set XUSB_FALCON_CLK_SRC to 'PLLP_OUT0', divisor to 2 ++ * Set XUSB_FS_CLK_SRC to 'FO_48M', divisor to 0 ++ * Set XUSB_SS_CLK_SRC to 'HSIC_480', divisor to 6 ++ */ ++ adjust_periph_pll(CLK_SRC_XUSB_CORE_HOST, 1, MASK_BITS_31_29, 6); ++ ++ adjust_periph_pll(CLK_SRC_XUSB_FALCON, 1, MASK_BITS_31_29, 2); ++ ++ adjust_periph_pll(CLK_SRC_XUSB_FS, 2, MASK_BITS_31_29, 0); ++ ++ /* Maintain default HS_HSICP clock @ 120Mhz */ ++ adjust_periph_pll(CLK_SRC_XUSB_SS, 3, MASK_BITS_31_29, 6); ++ ++ /* ++ * Clear SWR_XUSB_HOST_RST bit to release the reset to the XUSB host ++ * block. The reset to XUSB host block should only be deasserted ++ * after the port and pad programming and the clock programming are ++ * both completed. ++ */ ++ reset_set_enable(PERIPH_ID_XUSB_HOST, 0); ++ udelay(NVBOOT_RESET_STABILIZATION_DELAY); ++ ++ reset_set_enable(PERIPH_ID_XUSB_DEV, 0); ++ udelay(NVBOOT_RESET_STABILIZATION_DELAY); ++ ++ reset_set_enable(PERIPH_ID_XUSB_SS, 0); ++ udelay(NVBOOT_RESET_STABILIZATION_DELAY); ++ ++ reset_set_enable(PERIPH_ID_USBD, 0); ++ udelay(NVBOOT_RESET_STABILIZATION_DELAY); ++ ++ reset_set_enable(PERIPH_ID_USB2, 0); ++ udelay(NVBOOT_RESET_STABILIZATION_DELAY); ++ ++ /* Host controller identification and enumeration */ ++ NV_XUSB_HOST_READ(CONFIGURATION, reg_data); ++ reg_data |= EN_FPCI; ++ NV_XUSB_HOST_WRITE(CONFIGURATION, reg_data); ++ ++ NV_XUSB_CFG_WRITE(4, base); ++ ++ NV_XUSB_CFG_READ(1, reg_data); ++ reg_data |= (BUS_MASTER + MEMORY_SPACE); ++ NV_XUSB_CFG_WRITE(1, reg_data); ++ ++ NV_XUSB_HOST_READ(INTR_MASK, reg_data); ++ reg_data |= IP_INT_MASK; ++ NV_XUSB_HOST_WRITE(INTR_MASK, reg_data); ++ ++ NV_XUSB_HOST_WRITE(CLKGATE_HYSTERESIS, CLK_DISABLE_CNT); ++} ++ ++static int tegra_xhci_core_init(struct tegra_xhci *tegra, u32 fw_addr) ++{ ++ u32 val, val2; ++ struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; ++ int err; ++ ++ debug("%s: entry\n", __func__); ++ ++ /* Setup USB clocks, etc. */ ++ xhci_clk_rst_init(tegra); ++ ++ /* Reset PADCTL (need to setup PADCTL via slams) */ ++ reset_set_enable(PERIPH_ID_XUSB_PADCTL, 1); ++ mdelay(1); ++ reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0); ++ ++ /* Setup PADCTL registers w/default values per board (TX1/Nano) */ ++ do_tegra_xusb_padctl_init(); ++ ++ /* Check PLLU, set up if not enabled & locked */ ++ val = readl(&clkrst->crc_pll[CLOCK_ID_USB].pll_base); ++ if (val & ((1 << 27) | (1 << 30))) { ++ debug("%s: PLLU locked and enabled, skipping init ..\n", ++ __func__); ++ } else { ++ debug("%s: enabling PLLU ...\n", __func__); ++ tegra_pllu_enable(); ++ } ++ ++ /* Setup UTMIPLL (XTAL_FREQ_COUNT = 3, rest of regs s/b default) */ ++ val = readl(&clkrst->crc_utmip_pll_cfg1); ++ val &= 0xFFFFF000; /* bits 11:0 */ ++ val |= 3; ++ writel(val, &clkrst->crc_utmip_pll_cfg1); ++ debug("%s: UTMIPLL: wrote %X to CFG1 reg ...\n", __func__, val); ++ ++ /* Check PLLE, set up if not enabled & locked */ ++ val = readl(&clkrst->crc_pll_simple[SIMPLE_PLLE].pll_base); ++ val2 = readl(&clkrst->crc_pll_simple[SIMPLE_PLLE].pll_misc); ++ if ((val & (1 << 31)) && (val2 & (1 << 11))) { ++ debug("%s: PLLE locked and enabled, skipping init ..\n", ++ __func__); ++ } else { ++ debug("%s: enabling PLLE ...\n", __func__); ++ tegra_plle_enable(); ++ } ++ ++ /* Set up PEX_PAD PLL in PADCTL (skip if enabled/locked) */ ++ NV_XUSB_PADCTL_READ(UPHY_PLL_P0_CTL_1, val); ++ if (val & ((1 << 15) | (1 << 3))) { ++ debug("%s: UPHY PLL locked and enabled, skipping init ..\n", ++ __func__); ++ } else { ++ debug("%s: enabling UPHY PLL ...\n", __func__); ++ tegra_uphy_pll_enable(); ++ } ++ ++ /* Load XUSB FW (RP4, see CBoot FW load code) */ ++ err = xhci_load_firmware((u64)fw_addr); ++ if (err < 0) { ++ if (err == -EEXIST) { ++ /* Firmware already loaded/running */ ++ printf("XUSB firmware already running: %d\n", err); ++ } else { ++ printf("Failed to load XUSB firmware!: %d\n", err); ++ return err; ++ } ++ } ++ ++ /* Done, start XHCI and hub/storage drivers */ ++ ++ return 0; ++} ++ ++static void tegra_xhci_core_exit(struct tegra_xhci *tegra) ++{ ++ u32 val; ++ ++ debug("%s: entry\n", __func__); ++ ++ /* Assert reset to XUSB partitions */ ++ reset_set_enable(PERIPH_ID_XUSB_HOST, 1); ++ reset_set_enable(PERIPH_ID_XUSB_DEV, 1); ++ reset_set_enable(PERIPH_ID_XUSB_SS, 1); ++ ++ reset_set_enable(PERIPH_ID_USBD, 1); ++ reset_set_enable(PERIPH_ID_USB2, 1); ++ ++ /* XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0, power down the bias pad */ ++ NV_XUSB_PADCTL_READ(USB2_BIAS_PAD_CTL_0, val); ++ val |= BIAS_PAD_PD; ++ NV_XUSB_PADCTL_WRITE(USB2_BIAS_PAD_CTL_0, val); ++ ++ /* Assert UPHY reset */ ++ reset_set_enable(PERIPH_ID_PEX_USB_UPHY, 1); ++ ++ /* Reset PADCTL */ ++ debug("%s: Resetting PADCTL block ...\n", __func__); ++ reset_set_enable(PERIPH_ID_XUSB_PADCTL, 1); ++ mdelay(1); ++ reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0); ++ ++ /* Set CLK_SRC_XUSB_FS to 'CLK_M' or LS/FS devices fail in the kernel */ ++ adjust_periph_pll(CLK_SRC_XUSB_FS, 0, MASK_BITS_31_29, 0); ++ ++ debug("%s: done\n", __func__); ++} ++ ++static int tegra_xhci_usb_probe(struct udevice *dev) ++{ ++ struct tegra_xhci_platdata *plat = dev_get_plat(dev); ++ struct tegra_xhci *ctx = dev_get_priv(dev); ++ struct xhci_hcor *hcor; ++ int ret, len; ++ ++ debug("%s: entry\n", __func__); ++ ++ ctx->hcd = (struct xhci_hccr *)plat->hcd_base; ++ ++ /* setup the Vbus gpio here */ ++ if (dm_gpio_is_valid(&plat->vbus_gpio)) { ++ debug("%s: Setting GPIO %d to 1\n", __func__, ++ plat->vbus_gpio.offset); ++ dm_gpio_set_value(&plat->vbus_gpio, 1); ++ } ++ ++ ret = tegra_xhci_core_init(ctx, plat->fw_addr); ++ if (ret) { ++ puts("XHCI: failed to initialize controller\n"); ++ return -EINVAL; ++ } ++ ++ len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase)); ++ hcor = (struct xhci_hcor *)((u64)ctx->hcd + len); ++ ++ debug("XHCI-TEGRA init hccr %lX and hcor %lX hc_length %d\n", ++ (uintptr_t)ctx->hcd, (uintptr_t)hcor, len); ++ ++ return xhci_register(dev, ctx->hcd, hcor); ++} ++ ++static int tegra_xhci_usb_remove(struct udevice *dev) ++{ ++ struct tegra_xhci *ctx = dev_get_priv(dev); ++ int ret; ++ ++ ret = xhci_deregister(dev); ++ if (ret) ++ return ret; ++ ++ tegra_xhci_core_exit(ctx); ++ ++ return 0; ++} ++ ++static const struct udevice_id tegra_xhci_usb_ids[] = { ++ { .compatible = "nvidia,tegra210-xhci" }, ++ { } ++}; ++ ++U_BOOT_DRIVER(usb_xhci) = { ++ .name = "xhci_tegra", ++ .id = UCLASS_USB, ++ .of_match = tegra_xhci_usb_ids, ++ .of_to_plat = tegra_xhci_usb_ofdata_to_platdata, ++ .probe = tegra_xhci_usb_probe, ++ .remove = tegra_xhci_usb_remove, ++ .ops = &xhci_usb_ops, ++ .plat_auto = sizeof(struct tegra_xhci_platdata), ++ .priv_auto = sizeof(struct tegra_xhci), ++ .flags = DM_FLAG_ALLOC_PRIV_DMA, ++}; +diff --git drivers/usb/host/xhci.c drivers/usb/host/xhci.c +index 452dacc0af..240a77b830 100644 +--- drivers/usb/host/xhci.c ++++ drivers/usb/host/xhci.c +@@ -679,6 +679,10 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr) + debug("Successful Address Device command\n"); + udev->status = 0; + break; ++ case COMP_EINVAL: ++ printf("Parameter ERROR: Context parameter is INVALID.\n"); ++ ret = -EINVAL; ++ break; + default: + printf("ERROR: unexpected command completion code 0x%x.\n", + GET_COMP_CODE(le32_to_cpu(event->event_cmd.status))); +diff --git drivers/usb/host/xusb-macros.h drivers/usb/host/xusb-macros.h +new file mode 100644 +index 0000000000..50c9f6950e +--- /dev/null ++++ drivers/usb/host/xusb-macros.h +@@ -0,0 +1,157 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* Copyright (c) 2020 NVIDIA Corporation */ ++ ++/* ++ * Internal definitions and macros for using XHCI/XUSB as a boot device. ++ */ ++ ++#ifndef __XUSB_MACROS_H__ ++#define __XUSB_MACROS_H__ ++ ++#ifndef _MK_ADDR_CONST ++#define _MK_ADDR_CONST(_constant_) _constant_ ++#endif ++ ++#ifndef _MK_ENUM_CONST ++#define _MK_ENUM_CONST(_constant_) (_constant_ ## UL) ++#endif ++ ++#define NV_ADDRESS_MAP_CAR_BASE 0x60006000 ++#define NV_XUSB_HOST_APB_DFPCI_CFG 0x70098000 ++#define NV_XUSB_HOST_IPFS_REGS 0x70099000 ++#define NV_ADDRESS_MAP_APB_XUSB_PADCTL_BASE 0x7009F000 ++ ++#define CLK_SRC_XUSB_CORE_HOST 152 ++#define CLK_SRC_XUSB_FALCON 153 ++#define CLK_SRC_XUSB_FS 154 ++#define CLK_SRC_XUSB_CORE_DEV 155 ++#define CLK_SRC_XUSB_SS 156 ++ ++#define NVBOOT_RESET_STABILIZATION_DELAY 0x2 ++#define NVBOOT_CLOCKS_CLOCK_STABILIZATION_TIME 0x2 ++ ++#define XUSB_HOST_INTR_MASK_0 0x188 ++#define XUSB_HOST_CLKGATE_HYSTERESIS_0 0x1BC ++ ++#define XUSB_HOST_CONFIGURATION_0 _MK_ADDR_CONST(0x0180) ++ ++#define XUSB_CFG_1_0 _MK_ADDR_CONST(0x0004) ++#define XUSB_CFG_4_0 _MK_ADDR_CONST(0x0010) ++ ++// TODO: Move to XUSB PADCTL driver!! ++/* FUSE USB_CALIB registers */ ++#define FUSE_USB_CALIB_0 (NV_PA_FUSE_BASE+0x1F0) ++#define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + ((x) - 1) * 6) : 0) ++#define HS_CURR_LEVEL_PAD_MASK (0x3f) ++#define HS_TERM_RANGE_ADJ_SHIFT (7) ++#define HS_TERM_RANGE_ADJ_MASK (0xf) ++#define HS_SQUELCH_SHIFT (29) ++#define HS_SQUELCH_MASK (0x7) ++/* FUSE_USB_CALIB_EXT_0 */ ++#define FUSE_USB_CALIB_EXT_0 (NV_PA_FUSE_BASE+0x350) ++#define RPD_CTRL_SHIFT (0) ++#define RPD_CTRL_MASK (0x1f) ++ ++#define XUSB_PADCTL_USB2_PAD_MUX_0 (0x004) ++#define XUSB_PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_SHIFT (0) ++#define XUSB_PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_MASK (0x3) ++#define XUSB_PADCTL_USB2_PAD_MUX_USB2_OTG_PAD_PORT0_XUSB (0x1) ++#define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT (18) ++#define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK (0x3) ++#define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB (0x1) ++ ++#define XUSB_PADCTL_USB2_PORT_CAP_0 (0x008) ++#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(x) (0x0 << ((x) * 4)) ++#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4)) ++#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(x) (0x2 << ((x) * 4)) ++#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(x) (0x3 << ((x) * 4)) ++#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4)) ++ ++#define XUSB_PADCTL_SS_PORT_MAP_0 (0x014) ++#define SS_PORT_MAP(_ss, _usb2) (((_usb2) & 0x7) << ((_ss) * 5)) ++#define SS_PORT_MAP_PORT_DISABLED (0x7) ++ ++#define XUSB_PADCTL_ELPG_PROGRAM_0_0 (0x020) ++#define XUSB_PADCTL_ELPG_PROGRAM_1_0 (0x024) ++#define SSPX_ELPG_CLAMP_EN(x) BIT(0 + (x) * 3) ++#define SSPX_ELPG_CLAMP_EN_EARLY(x) BIT(1 + (x) * 3) ++#define SSPX_ELPG_VCORE_DOWN(x) BIT(2 + (x) * 3) ++#define AUX_MUX_LP0_CLAMP_EN BIT(29) ++#define AUX_MUX_LP0_CLAMP_EN_EARLY BIT(30) ++#define AUX_MUX_LP0_VCORE_DOWN BIT(31) ++ ++#define XUSB_PADCTL_USB3_PAD_MUX_0 (0x028) ++#define FORCE_PCIE_PAD_IDDQ_DISABLE(x) (1 << (1 + (x))) ++#define FORCE_SATA_PAD_IDDQ_DISABLE(x) (1 << (8 + (x))) ++ ++#define XUSB_PADCTL_USB2_OTG_PADX_CTL_0(x) (0x088 + (x) * 0x40) ++#define HS_CURR_LEVEL(x) ((x) & 0x3f) ++#define TERM_SEL BIT(25) ++#define USB2_OTG_PD BIT(26) ++#define USB2_OTG_PD2 BIT(27) ++#define USB2_OTG_PD2_OVRD_EN BIT(28) ++#define USB2_OTG_PD_ZI BIT(29) ++ ++#define XUSB_PADCTL_USB2_OTG_PADX_CTL_1(x) (0x8c + (x) * 0x40) ++#define USB2_OTG_PD_DR BIT(2) ++#define TERM_RANGE_ADJ(x) (((x) & 0xf) << 3) ++#define RPD_CTRL(x) (((x) & 0x1f) << 26) ++#define RPD_CTRL_VALUE(x) (((x) >> 26) & 0x1f) ++ ++#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0 (0x284) ++#define BIAS_PAD_PD BIT(11) ++#define HS_DISCON_LEVEL(x) (((x) & 0x7) << 3) ++#define HS_SQUELCH_LEVEL(x) (((x) & 0x7) << 0) ++ ++#define XUSB_PADCTL_USB2_BIAS_PAD_CTL_1_0 (0x288) ++#define TCTRL_VALUE(x) (((x) & 0x3f) >> 0) ++#define PCTRL_VALUE(x) (((x) >> 6) & 0x3f) ++#define USB2_TRK_START_TIMER(x) (((x) & 0x7f) << 12) ++#define USB2_TRK_DONE_RESET_TIMER(x) (((x) & 0x7f) << 19) ++#define USB2_PD_TRK BIT(26) ++ ++#define XUSB_PADCTL_UPHY_PLL_P0_CTL_1_0 _MK_ADDR_CONST(0x0360) ++#define XUSB_PADCTL_UPHY_PLL_P0_CTL_2_0 _MK_ADDR_CONST(0x0364) ++#define XUSB_PADCTL_UPHY_PLL_P0_CTL_5_0 _MK_ADDR_CONST(0x0370) ++#define XUSB_PADCTL_UPHY_PLL_P0_CTL_8_0 _MK_ADDR_CONST(0x037C) ++#define XUSB_PADCTL_UPHY_PLL_P0_CTL1_PLL0_LOCKDET BIT(15) ++#define XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE BIT(1) ++#define XUSB_PADCTL_UPHY_PLL_P0_CTL8_PLL0_RCAL_DONE BIT(31) ++ ++#define XUSB_PADCTL_UPHY_MISC_PAD_PX_CTL_1(x) (0x460 + (x) * 0x40) ++#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL_1 0x960 ++#define AUX_TX_IDDQ BIT(0) ++#define AUX_TX_IDDQ_OVRD BIT(1) ++#define AUX_RX_MODE_OVRD BIT(13) ++#define AUX_RX_TERM_EN BIT(18) ++#define AUX_RX_IDLE_MODE(x) (((x) & 0x3) << 20) ++#define AUX_RX_IDLE_EN BIT(22) ++#define AUX_RX_IDLE_TH(x) (((x) & 0x3) << 24) ++ ++#define XUSB_PADCTL_USB2_VBUS_ID_0 (0xc60) ++#define VBUS_OVERRIDE_VBUS_ON BIT(14) ++#define ID_OVERRIDE(x) (((x) & 0xf) << 18) ++#define ID_OVERRIDE_GROUNDED ID_OVERRIDE(0) ++#define ID_OVERRIDE_FLOATING ID_OVERRIDE(8) ++ ++#define NV_XUSB_PADCTL_READ(reg, value) \ ++ value = readl((NV_ADDRESS_MAP_APB_XUSB_PADCTL_BASE \ ++ + XUSB_PADCTL_##reg##_0)) ++ ++#define NV_XUSB_PADCTL_WRITE(reg, value) \ ++ writel(value, (NV_ADDRESS_MAP_APB_XUSB_PADCTL_BASE \ ++ + XUSB_PADCTL_##reg##_0)) ++ ++#define NV_XUSB_HOST_READ(reg, value) \ ++ value = readl((NV_XUSB_HOST_IPFS_REGS + XUSB_HOST_##reg##_0)) ++ ++#define NV_XUSB_HOST_WRITE(reg, value) \ ++ writel(value, (NV_XUSB_HOST_IPFS_REGS + XUSB_HOST_##reg##_0)) ++ ++#define NV_XUSB_CFG_READ(reg, value) \ ++ value = readl((NV_XUSB_HOST_APB_DFPCI_CFG + XUSB_CFG_##reg##_0)) ++ ++#define NV_XUSB_CFG_WRITE(reg, value) \ ++ writel(value, (NV_XUSB_HOST_APB_DFPCI_CFG + XUSB_CFG_##reg##_0)) ++ ++#endif /* __XUSB_MACROS_H__ */ +diff --git include/config_distro_bootcmd.h include/config_distro_bootcmd.h +index 3f724aa10f..2169695506 100644 +--- include/config_distro_bootcmd.h ++++ include/config_distro_bootcmd.h +@@ -201,6 +201,7 @@ + \ + "nvme_boot=" \ + BOOTENV_RUN_PCI_ENUM \ ++ BOOTENV_RUN_DCACHE_OFF \ + BOOTENV_RUN_NVME_INIT \ + BOOTENV_SHARED_BLKDEV_BODY(nvme) + #define BOOTENV_DEV_NVME BOOTENV_DEV_BLKDEV +@@ -266,6 +267,15 @@ + BOOT_TARGET_DEVICES_references_IDE_without_CONFIG_IDE + #endif + ++#ifdef CONFIG_CMD_CACHE ++#define BOOTENV_RUN_DCACHE_OFF "run boot_dcache_off; " ++#define BOOTENV_SHARED_DCACHE \ ++ "boot_dcache_off=dcache off\0" ++#else ++#define BOOTENV_RUN_DCACHE_OFF ++#define BOOTENV_SHARED_DCACHE ++#endif ++ + #if defined(CONFIG_PCI) + #define BOOTENV_RUN_PCI_ENUM "run boot_pci_enum; " + #define BOOTENV_SHARED_PCI \ +@@ -280,6 +290,7 @@ + #define BOOTENV_SHARED_USB \ + "boot_net_usb_start=usb start\0" \ + "usb_boot=" \ ++ BOOTENV_RUN_PCI_ENUM \ + "usb start; " \ + BOOTENV_SHARED_BLKDEV_BODY(usb) + #define BOOTENV_DEV_USB BOOTENV_DEV_BLKDEV +@@ -425,6 +436,7 @@ + BOOTENV_SHARED_USB \ + BOOTENV_SHARED_SATA \ + BOOTENV_SHARED_SCSI \ ++ BOOTENV_SHARED_DCACHE \ + BOOTENV_SHARED_NVME \ + BOOTENV_SHARED_IDE \ + BOOTENV_SHARED_UBIFS \ +diff --git include/configs/p2371-2180.h include/configs/p2371-2180.h +index 5e1d50b254..fb1a82ac68 100644 +--- include/configs/p2371-2180.h ++++ include/configs/p2371-2180.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0+ */ + /* +- * (C) Copyright 2013-2015 ++ * (C) Copyright 2013-2020 + * NVIDIA Corporation + */ + +@@ -17,6 +17,15 @@ + /* Board-specific serial config */ + #define CONFIG_TEGRA_ENABLE_UARTA + ++/* SD, eMMC, USB, NVME, PXE, DHCP */ ++#define BOOT_TARGET_DEVICES(func) \ ++ func(MMC, mmc, 1) \ ++ func(MMC, mmc, 0) \ ++ func(USB, usb, 0) \ ++ func(NVME, nvme, 0) \ ++ func(PXE, pxe, na) \ ++ func(DHCP, dhcp, na) ++ + /* Environment in eMMC, at the end of 2nd "boot sector" */ + + /* SPI */ +diff --git include/configs/p2771-0000.h include/configs/p2771-0000.h +index 4c3da224c6..b17d674845 100644 +--- include/configs/p2771-0000.h ++++ include/configs/p2771-0000.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + /* +- * Copyright (c) 2013-2016, NVIDIA CORPORATION. ++ * Copyright (c) 2013-2020, NVIDIA CORPORATION. + */ + + #ifndef _P2771_0000_H +@@ -15,12 +15,20 @@ + + /* Environment in eMMC, at the end of 2nd "boot sector" */ + ++/* SD, eMMC, NVME, PXE, DHCP */ ++#define BOOT_TARGET_DEVICES(func) \ ++ func(MMC, mmc, 1) \ ++ func(MMC, mmc, 0) \ ++ func(NVME, nvme, 0) \ ++ func(PXE, pxe, na) \ ++ func(DHCP, dhcp, na) ++ + #define BOARD_EXTRA_ENV_SETTINGS \ + "calculated_vars=kernel_addr_r fdt_addr_r scriptaddr pxefile_addr_r " \ + "ramdisk_addr_r\0" \ + "kernel_addr_r_align=00200000\0" \ + "kernel_addr_r_offset=00080000\0" \ +- "kernel_addr_r_size=02000000\0" \ ++ "kernel_addr_r_size=08000000\0" \ + "kernel_addr_r_aliases=loadaddr\0" \ + "fdt_addr_r_align=00200000\0" \ + "fdt_addr_r_offset=00000000\0" \ +@@ -35,6 +43,30 @@ + "ramdisk_addr_r_offset=00000000\0" \ + "ramdisk_addr_r_size=02000000\0" + ++#ifdef CONFIG_FIT ++#undef CONFIG_BOOTCOMMAND ++#undef BOARD_EXTRA_ENV_SETTINGS ++/* FIT Image environment settings */ ++#define FITIMAGE_ENV_SETTINGS \ ++ "mmcdev=0\0" \ ++ "mmcpart=1\0" \ ++ "devnum=0\0" \ ++ "fitpart=1\0" \ ++ "prefix=/boot\0" \ ++ "mmcfit_name=fitImage\0" \ ++ "fit_addr=0x90000000\0" \ ++ "mmcloadfit=load mmc ${devnum}:${fitpart} ${fit_addr} " \ ++ "${prefix}/${mmcfit_name}\0" \ ++ "mmcargs=setenv bootargs ${cbootargs} " \ ++ "root=/dev/mmcblk${mmcdev}p${mmcpart} rw rootwait\0" \ ++ "mmc_mmc_fit=run mmcloadfit;run mmcargs; bootm ${fit_addr} - ${fdt_addr}\0" ++ ++#define BOARD_EXTRA_ENV_SETTINGS \ ++ FITIMAGE_ENV_SETTINGS ++ ++#define CONFIG_BOOTCOMMAND "run mmc_mmc_fit" ++#endif /* CONFIG_FIT */ ++ + #include "tegra-common-post.h" + + /* Crystal is 38.4MHz. clk_m runs at half that rate */ +diff --git include/configs/p3450-0000.h include/configs/p3450-0000.h +index 7f05bebbcd..0e08181fb3 100644 +--- include/configs/p3450-0000.h ++++ include/configs/p3450-0000.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0+ */ + /* +- * (C) Copyright 2018-2019 NVIDIA Corporation. ++ * (C) Copyright 2018-2020 NVIDIA Corporation. + */ + + #ifndef _P3450_0000_H +@@ -10,16 +10,29 @@ + + #include "tegra210-common.h" + +-/* High-level configuration options */ +-#define CONFIG_TEGRA_BOARD_STRING "NVIDIA P3450-0000" +- + /* Board-specific serial config */ + #define CONFIG_TEGRA_ENABLE_UARTA + ++#ifdef CONFIG_P3450_EMMC ++#define CONFIG_TEGRA_BOARD_STRING "NVIDIA P3450-0002" ++#define BOOT_TARGET_DEVICES(func) \ ++ func(MMC, mmc, 0) \ ++ func(USB, usb, 0) \ ++ func(NVME, nvme, 0) \ ++ func(PXE, pxe, na) \ ++ func(DHCP, dhcp, na) ++#define CONFIG_SYS_MMC_ENV_DEV 0 ++#define CONFIG_SYS_MMC_ENV_PART 2 ++#define DEFAULT_MMC_DEV "0" ++#else ++/* High-level configuration options */ ++#define CONFIG_TEGRA_BOARD_STRING "NVIDIA P3450-0000" ++ + /* Only MMC/PXE/DHCP for now, add USB back in later when supported */ + #define BOOT_TARGET_DEVICES(func) \ + func(MMC, mmc, 1) \ +- func(MMC, mmc, 0) \ ++ func(USB, usb, 0) \ ++ func(NVME, nvme, 0) \ + func(PXE, pxe, na) \ + func(DHCP, dhcp, na) + +@@ -27,14 +40,39 @@ + #define CONFIG_ENV_SPI_MAX_HZ 48000000 + #define CONFIG_ENV_SPI_MODE SPI_MODE_0 + #define CONFIG_SPI_FLASH_SIZE (4 << 20) ++#define DEFAULT_MMC_DEV "1" ++#endif + + #define CONFIG_PREBOOT + ++#ifdef CONFIG_FIT ++#undef CONFIG_BOOTCOMMAND ++/* FIT Image environment settings */ ++#define FITIMAGE_ENV_SETTINGS \ ++ "mmcdev=0\0" \ ++ "mmcpart=1\0" \ ++ "devnum=" DEFAULT_MMC_DEV "\0" \ ++ "fitpart=1\0" \ ++ "prefix=/boot\0" \ ++ "mmcfit_name=fitImage\0" \ ++ "fit_addr=0x90000000\0" \ ++ "mmcloadfit=load mmc ${devnum}:${fitpart} ${fit_addr} " \ ++ "${prefix}/${mmcfit_name}\0" \ ++ "mmcargs=setenv bootargs ${cbootargs} " \ ++ "root=/dev/mmcblk${mmcdev}p${mmcpart} rw rootwait\0" \ ++ "mmc_mmc_fit=run mmcloadfit;run mmcargs; bootm ${fit_addr} - ${fdt_addr}\0" ++ ++#define CONFIG_BOOTCOMMAND "run mmc_mmc_fit" ++#else ++#define FITIMAGE_ENV_SETTINGS ++#endif /* CONFIG_FIT */ ++ + #define BOARD_EXTRA_ENV_SETTINGS \ +- "preboot=if test -e mmc 1:1 /u-boot-preboot.scr; then " \ +- "load mmc 1:1 ${scriptaddr} /u-boot-preboot.scr; " \ ++ "preboot=if test -e mmc " DEFAULT_MMC_DEV ":1 /u-boot-preboot.scr; then " \ ++ "load mmc " DEFAULT_MMC_DEV ":1 ${scriptaddr} /u-boot-preboot.scr; " \ + "source ${scriptaddr}; " \ +- "fi\0" ++ "fi\0" \ ++ FITIMAGE_ENV_SETTINGS + + /* General networking support */ + #include "tegra-common-usb-gadget.h" +diff --git include/configs/p3541-0000.h include/configs/p3541-0000.h +new file mode 100644 +index 0000000000..193b7da1b7 +--- /dev/null ++++ include/configs/p3541-0000.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * (C) Copyright 2018-2019 NVIDIA Corporation. ++ */ ++ ++#ifndef _P3541_0000_H ++#define _P3541_0000_H ++ ++#include ++ ++#include "tegra210-common.h" ++ ++/* Board-specific serial config */ ++#define CONFIG_TEGRA_ENABLE_UARTA ++ ++/* High-level configuration options */ ++#define CONFIG_TEGRA_BOARD_STRING "NVIDIA P3541-0000" ++ ++/* Nano2GB doesn't have eMMC or NVMe, just SD/USB/Net */ ++#define BOOT_TARGET_DEVICES(func) \ ++ func(MMC, mmc, 1) \ ++ func(USB, usb, 0) \ ++ func(PXE, pxe, na) \ ++ func(DHCP, dhcp, na) ++ ++/* Environment at end of QSPI, in the VER partition */ ++#define CONFIG_ENV_SPI_MAX_HZ 48000000 ++#define CONFIG_ENV_SPI_MODE SPI_MODE_0 ++#define CONFIG_SPI_FLASH_SIZE (4 << 20) ++#define DEFAULT_MMC_DEV "1" ++ ++#define CONFIG_PREBOOT ++ ++#define BOARD_EXTRA_ENV_SETTINGS \ ++ "preboot=if test -e mmc " DEFAULT_MMC_DEV ":1 /u-boot-preboot.scr; then " \ ++ "load mmc " DEFAULT_MMC_DEV ":1 ${scriptaddr} /u-boot-preboot.scr; " \ ++ "source ${scriptaddr}; " \ ++ "fi\0" ++ ++/* General networking support */ ++#include "tegra-common-usb-gadget.h" ++#include "tegra-common-post.h" ++ ++/* Crystal is 38.4MHz. clk_m runs at half that rate */ ++#define COUNTER_FREQUENCY 19200000 ++ ++#endif /* _P3541_0000_H */ +diff --git include/configs/p3636-0001.h include/configs/p3636-0001.h +new file mode 100644 +index 0000000000..ba543be98b +--- /dev/null ++++ include/configs/p3636-0001.h +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2021, NVIDIA CORPORATION. ++ */ ++ ++#ifndef _P3636_0001_H ++#define _P3636_0001_H ++ ++#include ++ ++#include "tegra186-common.h" ++ ++/* High-level configuration options */ ++#define CONFIG_TEGRA_BOARD_STRING "NVIDIA P3636-0001" ++ ++/* Environment in eMMC, at the end of 2nd "boot sector" */ ++ ++/* SD, eMMC, NVME, PXE, DHCP */ ++#define BOOT_TARGET_DEVICES(func) \ ++ func(MMC, mmc, 1) \ ++ func(MMC, mmc, 0) \ ++ func(NVME, nvme, 0) \ ++ func(PXE, pxe, na) \ ++ func(DHCP, dhcp, na) ++ ++#define BOARD_EXTRA_ENV_SETTINGS \ ++ "calculated_vars=kernel_addr_r fdt_addr_r scriptaddr pxefile_addr_r " \ ++ "ramdisk_addr_r\0" \ ++ "kernel_addr_r_align=00200000\0" \ ++ "kernel_addr_r_offset=00080000\0" \ ++ "kernel_addr_r_size=08000000\0" \ ++ "kernel_addr_r_aliases=loadaddr\0" \ ++ "fdt_addr_r_align=00200000\0" \ ++ "fdt_addr_r_offset=00000000\0" \ ++ "fdt_addr_r_size=00200000\0" \ ++ "scriptaddr_align=00200000\0" \ ++ "scriptaddr_offset=00000000\0" \ ++ "scriptaddr_size=00200000\0" \ ++ "pxefile_addr_r_align=00200000\0" \ ++ "pxefile_addr_r_offset=00000000\0" \ ++ "pxefile_addr_r_size=00200000\0" \ ++ "ramdisk_addr_r_align=00200000\0" \ ++ "ramdisk_addr_r_offset=00000000\0" \ ++ "ramdisk_addr_r_size=02000000\0" ++ ++#include "tegra-common-post.h" ++ ++/* Crystal is 38.4MHz. clk_m runs at half that rate */ ++#define COUNTER_FREQUENCY 19200000 ++ ++#endif +diff --git include/configs/tegra186-common.h include/configs/tegra186-common.h +index 968501602a..c787f80988 100644 +--- include/configs/tegra186-common.h ++++ include/configs/tegra186-common.h +@@ -1,6 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + /* +- * Copyright 2013-2016, NVIDIA CORPORATION. ++ * Copyright 2013-2021, NVIDIA CORPORATION. + */ + + #ifndef _TEGRA186_COMMON_H_ +@@ -44,14 +44,44 @@ + * fdt_addr_r simply shouldn't overlap anything else. Choosing 32M allows for + * the compressed kernel to be up to 16M too. + * ++ * fdtoverlay_addr_r is used for DTB overlays from extlinux.conf. It's placed ++ * just above pxefile_addr_r. ++ * + * ramdisk_addr_r simply shouldn't overlap anything else. Choosing 33M allows + * for the FDT/DTB to be up to 1M, which is hopefully plenty. + */ + #define MEM_LAYOUT_ENV_SETTINGS \ + "scriptaddr=0x90000000\0" \ + "pxefile_addr_r=0x90100000\0" \ ++ "fdtoverlay_addr_r=0x90200000\0" \ + "kernel_addr_r=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \ + "fdt_addr_r=0x82000000\0" \ +- "ramdisk_addr_r=0x82100000\0" ++ "ramdisk_addr_r=0x82100000\0" \ ++ "fdt_copy_node_paths=" \ ++ "/chosen/plugin-manager:" \ ++ "/chosen/reset:" \ ++ "/memory@80000000\0" \ ++ "fdt_copy_prop_paths=" \ ++ "/bpmp/carveout-start:" \ ++ "/bpmp/carveout-size:" \ ++ "/chosen/nvidia,bluetooth-mac:" \ ++ "/chosen/nvidia,ether-mac:" \ ++ "/chosen/nvidia,wifi-mac:" \ ++ "/chosen/ecid:" \ ++ "/chosen/linux,initrd-start:" \ ++ "/chosen/linux,initrd-end:" \ ++ "/reserved-memory/fb0_carveout/reg:" \ ++ "/reserved-memory/fb1_carveout/reg:" \ ++ "/reserved-memory/fb2_carveout/reg:" \ ++ "/reserved-memory/ramoops_carveout/alignment:" \ ++ "/reserved-memory/ramoops_carveout/alloc-ranges:" \ ++ "/reserved-memory/ramoops_carveout/size:" \ ++ "/reserved-memory/vpr-carveout/alignment:" \ ++ "/reserved-memory/vpr-carveout/alloc-ranges:" \ ++ "/reserved-memory/vpr-carveout/size:" \ ++ "/serial-number:" \ ++ "/trusty/status\0" ++ ++#define CONFIG_SYS_BOOTM_LEN (64 << 20) /* Increase max gunzip size */ + + #endif +diff --git include/configs/tegra210-common.h include/configs/tegra210-common.h +index 3ba12bec0e..0cb3442f71 100644 +--- include/configs/tegra210-common.h ++++ include/configs/tegra210-common.h +@@ -1,7 +1,6 @@ + /* SPDX-License-Identifier: GPL-2.0+ */ + /* +- * (C) Copyright 2013-2015 +- * NVIDIA Corporation ++ * Copyright (c) 2013-2021, NVIDIA CORPORATION. All rights reserved. + */ + + #ifndef _TEGRA210_COMMON_H_ +@@ -35,16 +34,46 @@ + * fdt_addr_r simply shouldn't overlap anything else. Choosing 32M allows for + * the compressed kernel to be up to 16M too. + * ++ * fdtoverlay_addr_r is used for DTB overlays from extlinux.conf. It's placed ++ * just above pxefile_addr_r. ++ * + * ramdisk_addr_r simply shouldn't overlap anything else. Choosing 33M allows + * for the FDT/DTB to be up to 1M, which is hopefully plenty. + */ ++/* ++ * NOTE: fdt_addr (from CBoot) is @ 0x83100000. fdt_addr_r is also from CBoot ++ * and can't be moved. To accomodate a 128MB kernel (for gcov, trace, debug, ++ * etc.), kernel_addr_r is moved to 0x84000000, above fdt/ramdisk and below ++ * pxe/script addresses. ++ */ + #define MEM_LAYOUT_ENV_SETTINGS \ + "scriptaddr=0x90000000\0" \ + "pxefile_addr_r=0x90100000\0" \ ++ "fdtoverlay_addr_r=0x90200000\0" \ + "kernel_addr_r=" __stringify(CONFIG_SYS_LOAD_ADDR) "\0" \ + "fdtfile=" FDTFILE "\0" \ + "fdt_addr_r=0x83000000\0" \ +- "ramdisk_addr_r=0x83420000\0" ++ "ramdisk_addr_r=0x87200000\0" \ ++ "fdt_copy_node_paths=" \ ++ "/chosen/plugin-manager:" \ ++ "/chosen/reset:" \ ++ "/chosen/display-board:" \ ++ "/chosen/proc-board:" \ ++ "/chosen/pmu-board:" \ ++ "/external-memory-controller@7001b000:" \ ++ "/memory@80000000\0" \ ++ "fdt_copy_prop_paths=" \ ++ "/bpmp/carveout-start:" \ ++ "/bpmp/carveout-size:" \ ++ "/chosen/eks_info:" \ ++ "/chosen/nvidia,bluetooth-mac:" \ ++ "/chosen/nvidia,ethernet-mac:" \ ++ "/chosen/nvidia,wifi-mac:" \ ++ "/chosen/uuid:" \ ++ "/chosen/linux,initrd-start:" \ ++ "/chosen/linux,initrd-end:" \ ++ "/serial-number:" \ ++ "/psci/nvidia,system-lp0-disable\0" + + /* For USB EHCI controller */ + #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 +@@ -52,4 +81,6 @@ + /* GPU needs setup */ + #define CONFIG_TEGRA_GPU + ++#define CONFIG_SYS_BOOTM_LEN (64 << 20) /* Increase max gunzip size */ ++ + #endif /* _TEGRA210_COMMON_H_ */ +diff --git scripts/dtc-version.sh scripts/dtc-version.sh +index bfb514e179..4c74cb77e7 100755 +--- scripts/dtc-version.sh ++++ scripts/dtc-version.sh +@@ -20,8 +20,8 @@ if ! which $dtc >/dev/null ; then + exit 1 + fi + +-MAJOR=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 1) ++MAJOR=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 1 | tr -d v) + MINOR=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 2) +-PATCH=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 3 | cut -d - -f 1) ++PATCH=$($dtc -v | head -1 | awk '{print $NF}' | cut -d . -f 3 | cut -d - -f 1 | cut -d '+' -f 1) + + printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCH diff --git a/u-boot/jetson_nano/patches/tegra210-common.h.patch b/u-boot/jetson_nano/patches/tegra210-common.h.patch deleted file mode 100644 index d284c23b2..000000000 --- a/u-boot/jetson_nano/patches/tegra210-common.h.patch +++ /dev/null @@ -1,35 +0,0 @@ ---- include/configs/tegra210-common.h 2022-01-13 15:45:15.834014969 +0000 -+++ include/configs/tegra210-common.h 2022-01-13 15:45:21.250066512 +0000 -@@ -54,30 +54,10 @@ - #define MEM_LAYOUT_ENV_SETTINGS \ - "scriptaddr=0x90000000\0" \ - "pxefile_addr_r=0x90100000\0" \ -- "fdtoverlay_addr_r=0x90200000\0" \ - "kernel_addr_r=" __stringify(CONFIG_LOADADDR) "\0" \ -+ "fdtfile=" FDTFILE "\0" \ - "fdt_addr_r=0x83000000\0" \ -- "ramdisk_addr_r=0x83200000\0" \ -- "fdt_copy_node_paths=" \ -- "/chosen/plugin-manager:" \ -- "/chosen/reset:" \ -- "/chosen/display-board:" \ -- "/chosen/proc-board:" \ -- "/chosen/pmu-board:" \ -- "/external-memory-controller@7001b000:" \ -- "/memory@80000000\0" \ -- "fdt_copy_prop_paths=" \ -- "/bpmp/carveout-start:" \ -- "/bpmp/carveout-size:" \ -- "/chosen/eks_info:" \ -- "/chosen/nvidia,bluetooth-mac:" \ -- "/chosen/nvidia,ethernet-mac:" \ -- "/chosen/nvidia,wifi-mac:" \ -- "/chosen/uuid:" \ -- "/chosen/linux,initrd-start:" \ -- "/chosen/linux,initrd-end:" \ -- "/serial-number:" \ -- "/psci/nvidia,system-lp0-disable\0" -+ "ramdisk_addr_r=0x83200000\0" - - /* For USB EHCI controller */ - #define CONFIG_EHCI_IS_TDI diff --git a/u-boot/pkg.yaml b/u-boot/pkg.yaml index c340267fd..46c2263c2 100644 --- a/u-boot/pkg.yaml +++ b/u-boot/pkg.yaml @@ -24,10 +24,6 @@ steps: destination: u-boot.tar.bz2 sha256: 81b4543227db228c03f8a1bf5ddbc813b0bb8f6555ce46064ef721a6fc680413 sha512: d83c62bd8f0f51664d2aca329a3ce1379cfd1dfff439dccd6cfc2cb33cfef89a2b01855c97716f591b5550bfdf99e2f3aef7efa33f2e7834c820648f9eef3825 - - url: https://github.com/OE4T/u-boot-tegra/archive/refs/tags/tegra-l4t-r32.6.1.tar.gz - destination: u-boot-tegra.tar.gz - sha256: c8737dc20d29586c2c3e6b0232d8c807b3220a22d3f63094c49691b1919636f7 - sha512: 71e96bb84e8265355735d2e43296ba872de9d641dad92ea6e0a3ec4af2ba283243c3a9fa6bdbb9f028d57e5fb878b356b467ae1fd9a477062efecdb368d1d471 env: SUN50I_A64_ARM_TRUSTED_FIRMWARE: sun50i_a64_arm-trusted-firmware RPI_4_A64_ARM_TRUSTED_FIRMWARE: rpi_4_a64_arm-trusted-firmware @@ -107,10 +103,9 @@ steps: # jetson nano - | mkdir ${JETSON_NANO_U_BOOT} - tar -xzf u-boot-tegra.tar.gz --strip-components=1 -C ${JETSON_NANO_U_BOOT} + tar -xjf u-boot.tar.bz2 --strip-components=1 -C ${JETSON_NANO_U_BOOT} cd ${JETSON_NANO_U_BOOT} - patch -p0 < /pkg/jetson_nano/patches/tegra-common.h.patch - patch -p0 < /pkg/jetson_nano/patches/tegra210-common.h.patch + patch -p0 < /pkg/jetson_nano/patches/tegra.patch make p3450-0000_defconfig sed -i "s/CONFIG_TOOLS_LIBCRYPTO=y/# CONFIG_TOOLS_LIBCRYPTO is not set/" .config build: @@ -169,7 +164,7 @@ steps: # jetson nano - | cd ${JETSON_NANO_U_BOOT} - make -j $(nproc) DTC="/toolchain/bin/dtc" HOSTLDLIBS_mkimage="-lssl -lcrypto" + make -j $(nproc) HOSTLDLIBS_mkimage="-lssl -lcrypto" install: # libretech_all_h3_cc_h5 - |