From 2b2f1d49cae196c2dc32393edadc9989bd24a695 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Tue, 14 Aug 2018 16:52:39 +0100 Subject: [PATCH] 2018.09 RC2, improve Jetson TX1, Enable OrangePi 1+ and Avnet Ultra96 --- aarch64-boards | 2 + sources | 2 +- tegra-fix-tx1.patch | 1722 +++++++++++++++++ ...-Add-CONFIG_EFI_LOADER_BOUNCE_BUFFER.patch | 28 + ...a186-jetson-tx2-disable-onboard-emmc.patch | 26 + uboot-tools.spec | 12 +- 6 files changed, 1788 insertions(+), 4 deletions(-) create mode 100644 tegra-fix-tx1.patch diff --git a/aarch64-boards b/aarch64-boards index 0ee6f67..cfe4ffd 100644 --- a/aarch64-boards +++ b/aarch64-boards @@ -1,3 +1,4 @@ +avnet_ultra96_rev1 bananapi_m64 dragonboard410c dragonboard820c @@ -15,6 +16,7 @@ mvebu_mcbin-88f8040 nanopi-k2 nanopi_neo2 odroid-c2 +orangepi_one_plus orangepi_pc2 orangepi_prime orangepi_win diff --git a/sources b/sources index 4800ccb..989dcf7 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (u-boot-2018.09-rc1.tar.bz2) = b158e6bac7c46d371d2782c85780f9a0a39f0b305071b9718bebbb9aac4e85f2e4719145bedd90a69440ea15c7b473a603336c2f5de7da0af53c466adb4654bd +SHA512 (u-boot-2018.09-rc2.tar.bz2) = 09dcb8a8db341af1e7f8a50d4d668e9ea432923e391941ac3a58f65a6a42cad34778cc78e4f4b9e3ec86c62b036b5761af380bd70d6e840563cba5b8dcdcd2f4 diff --git a/tegra-fix-tx1.patch b/tegra-fix-tx1.patch new file mode 100644 index 0000000..2c364df --- /dev/null +++ b/tegra-fix-tx1.patch @@ -0,0 +1,1722 @@ +From 7ef8ffa604feae44e08c7a65f66eb76c9e64cfef Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Wed, 1 Aug 2018 10:32:16 +0100 +Subject: [PATCH 1/7] Revert "efi_loader: efi_allocate_pages is too + restrictive" + +This reverts commit aa909462d01866354f4cd4534db5f571c2cf1fbb. +--- + lib/efi_loader/efi_memory.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c +index 967c3f733e4..4b6269f35e1 100644 +--- a/lib/efi_loader/efi_memory.c ++++ b/lib/efi_loader/efi_memory.c +@@ -305,7 +305,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, + switch (type) { + case EFI_ALLOCATE_ANY_PAGES: + /* Any page */ +- addr = efi_find_free_memory(len, -1ULL); ++ addr = efi_find_free_memory(len, gd->start_addr_sp); + if (!addr) { + r = EFI_NOT_FOUND; + break; +-- +2.17.1 + +From f213c8b5d051dadf0b776828f846d064a55dd03e Mon Sep 17 00:00:00 2001 +From: Stephen Warren +Date: Tue, 31 Jul 2018 12:39:07 -0600 +Subject: [PATCH 2/7] ARM: tegra: avoid more operations in non-secure world + +A secure monitor that runs before U-Boot, and hence causes U-Boot to run +in non-secure world, must implement a few operations that U-Boot +otherwise implements when running in secure world. Fix U-Boot to skip +these operations when running in non-secure world. In particular: + +- The secure monitor must provide the LP0 resume code and own LP0 + configuration in order to maintain security, so must initialize all + the PMC scratch registers used by the boot ROM during LP0 resume. + Consequently, U-Boot should not attempt to clear those registers, + since the register accesses will fail or cause an error. + +- The secure monitor owns system security, and so is responsible for + configuring security-related items such as the VPR. + +Signed-off-by: Stephen Warren +--- + arch/arm/mach-tegra/ap.c | 9 +++++++-- + arch/arm/mach-tegra/gpu.c | 18 ++++++++++++------ + 2 files changed, 19 insertions(+), 8 deletions(-) + +diff --git a/arch/arm/mach-tegra/ap.c b/arch/arm/mach-tegra/ap.c +index bf8001d9db0..84c20a48ad4 100644 +--- a/arch/arm/mach-tegra/ap.c ++++ b/arch/arm/mach-tegra/ap.c +@@ -155,8 +155,13 @@ static void init_pmc_scratch(void) + int i; + + /* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */ +- for (i = 0; i < 23; i++) +- writel(0, &pmc->pmc_scratch1+i); ++#if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) ++ if (!tegra_cpu_is_non_secure()) ++#endif ++ { ++ for (i = 0; i < 23; i++) ++ writel(0, &pmc->pmc_scratch1 + i); ++ } + + /* ODMDATA is for kernel use to determine RAM size, LP config, etc. */ + odmdata = get_odmdata(); +diff --git a/arch/arm/mach-tegra/gpu.c b/arch/arm/mach-tegra/gpu.c +index 2e203f735bf..e047f678211 100644 +--- a/arch/arm/mach-tegra/gpu.c ++++ b/arch/arm/mach-tegra/gpu.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + #include + +@@ -18,12 +19,17 @@ void tegra_gpu_config(void) + { + struct mc_ctlr *mc = (struct mc_ctlr *)NV_PA_MC_BASE; + +- /* Turn VPR off */ +- writel(0, &mc->mc_video_protect_size_mb); +- writel(TEGRA_MC_VIDEO_PROTECT_REG_WRITE_ACCESS_DISABLED, +- &mc->mc_video_protect_reg_ctrl); +- /* read back to ensure the write went through */ +- readl(&mc->mc_video_protect_reg_ctrl); ++#if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) ++ if (!tegra_cpu_is_non_secure()) ++#endif ++ { ++ /* Turn VPR off */ ++ writel(0, &mc->mc_video_protect_size_mb); ++ writel(TEGRA_MC_VIDEO_PROTECT_REG_WRITE_ACCESS_DISABLED, ++ &mc->mc_video_protect_reg_ctrl); ++ /* read back to ensure the write went through */ ++ readl(&mc->mc_video_protect_reg_ctrl); ++ } + + debug("configured VPR\n"); + +-- +2.17.1 + +From 5d62affed1f0feb49f99cad200301b8ab1e0d2b7 Mon Sep 17 00:00:00 2001 +From: Stephen Warren +Date: Tue, 31 Jul 2018 13:44:12 -0600 +Subject: [PATCH 3/7] efi_loader: don't allocate unusable RAM + +Some boards define a maximum usable RAM top that's more restrictive than +the ranges defined by U-Boot's memory bank definitions[1]. In this case, +the unusable RAM isn't mapped in the page tables, and so the EFI code must +not attempt to allocate RAM from outside the usable regions. Fix +efi_find_free_memory() to detect when max_addr is unconstrained or out of +range, and substitue a valid value. + +[1] For example, when some peripherals can't access RAM above 4GiB, it's +simplest to force U-Boot's ram_top to a smaller value to avoid dealing +with this issue more explicitly. However, the RAM bank definitions still +describe the unusable RAM so that the booted OS has access to it, since +the OS can typically deal with such restrictions in a more complex +manner. + +Fixes: aa909462d018 "efi_loader: efi_allocate_pages is too restrictive" +Cc: Heinrich Schuchardt +Cc: Alexander Graf +Signed-off-by: Stephen Warren +--- + lib/efi_loader/efi_memory.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c +index 4b6269f35e1..a078f75b0df 100644 +--- a/lib/efi_loader/efi_memory.c ++++ b/lib/efi_loader/efi_memory.c +@@ -251,6 +251,9 @@ static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr) + { + struct list_head *lhandle; + ++ if ((max_addr == -1ULL) || (max_addr > gd->ram_top)) ++ max_addr = gd->ram_top; ++ + list_for_each(lhandle, &efi_mem) { + struct efi_mem_list *lmem = list_entry(lhandle, + struct efi_mem_list, link); +-- +2.17.1 + +From f288753c36391c7f216d906cde757e793a44fd70 Mon Sep 17 00:00:00 2001 +From: Aaron Kling +Date: Tue, 31 Jul 2018 11:34:50 -0500 +Subject: [PATCH 4/7] T210 devices now chainload from cboot using the kernel + address + +--- + configs/p2371-0000_defconfig | 2 +- + configs/p2371-2180_defconfig | 2 +- + configs/p2571_defconfig | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/configs/p2371-0000_defconfig b/configs/p2371-0000_defconfig +index 62333574105..b63811784f1 100644 +--- a/configs/p2371-0000_defconfig ++++ b/configs/p2371-0000_defconfig +@@ -1,6 +1,6 @@ + CONFIG_ARM=y + CONFIG_TEGRA=y +-CONFIG_SYS_TEXT_BASE=0x80110000 ++CONFIG_SYS_TEXT_BASE=0x80080000 + CONFIG_TEGRA210=y + CONFIG_TARGET_P2371_0000=y + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p2371-0000" +diff --git a/configs/p2371-2180_defconfig b/configs/p2371-2180_defconfig +index 34262c559a0..289d88b31e5 100644 +--- a/configs/p2371-2180_defconfig ++++ b/configs/p2371-2180_defconfig +@@ -1,6 +1,6 @@ + CONFIG_ARM=y + CONFIG_TEGRA=y +-CONFIG_SYS_TEXT_BASE=0x80110000 ++CONFIG_SYS_TEXT_BASE=0x80080000 + CONFIG_TEGRA210=y + CONFIG_TARGET_P2371_2180=y + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p2371-2180" +diff --git a/configs/p2571_defconfig b/configs/p2571_defconfig +index 50675544a7b..a34b191691c 100644 +--- a/configs/p2571_defconfig ++++ b/configs/p2571_defconfig +@@ -1,6 +1,6 @@ + CONFIG_ARM=y + CONFIG_TEGRA=y +-CONFIG_SYS_TEXT_BASE=0x80110000 ++CONFIG_SYS_TEXT_BASE=0x80080000 + CONFIG_TEGRA210=y + CONFIG_TARGET_P2571=y + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p2571" +-- +2.17.1 + +From 9179fd51afdcd67851d8e387481ad87185019d7d Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Wed, 1 Aug 2018 11:08:54 +0100 +Subject: [PATCH 5/7] Cboot logic path now used by t210 + +--- + arch/arm/mach-tegra/board.c | 4 +- + arch/arm/mach-tegra/board2.c | 6 + + arch/arm/mach-tegra/dt-setup.c | 5 +- + arch/arm/mach-tegra/gpu.c | 2 + + arch/arm/mach-tegra/tegra186/Makefile | 6 +- + arch/arm/mach-tegra/tegra186/nvtboot_board.c | 332 ------------------- + arch/arm/mach-tegra/tegra186/nvtboot_ll.S | 20 -- + arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 173 ---------- + arch/arm/mach-tegra/tegra210/Makefile | 3 + + 9 files changed, 19 insertions(+), 532 deletions(-) + delete mode 100644 arch/arm/mach-tegra/tegra186/nvtboot_board.c + delete mode 100644 arch/arm/mach-tegra/tegra186/nvtboot_ll.S + delete mode 100644 arch/arm/mach-tegra/tegra186/nvtboot_mem.c + +diff --git a/arch/arm/mach-tegra/board.c b/arch/arm/mach-tegra/board.c +index f8fc042a1dc..ddef2288317 100644 +--- a/arch/arm/mach-tegra/board.c ++++ b/arch/arm/mach-tegra/board.c +@@ -35,7 +35,7 @@ enum { + + static bool from_spl __attribute__ ((section(".data"))); + +-#ifndef CONFIG_SPL_BUILD ++#if !defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TEGRA210) + void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) + { + from_spl = r0 != UBOOT_NOT_LOADED_FROM_SPL; +@@ -66,6 +66,7 @@ bool tegra_cpu_is_non_secure(void) + } + #endif + ++#if !defined(CONFIG_ARM64) + /* Read the RAM size directly from the memory controller */ + static phys_size_t query_sdram_size(void) + { +@@ -122,6 +123,7 @@ int dram_init(void) + gd->ram_size = query_sdram_size(); + return 0; + } ++#endif + + static int uart_configs[] = { + #if defined(CONFIG_TEGRA20) +diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c +index 421a71b3014..301fd16af61 100644 +--- a/arch/arm/mach-tegra/board2.c ++++ b/arch/arm/mach-tegra/board2.c +@@ -220,9 +220,14 @@ int board_late_init(void) + #endif + start_cpu_fan(); + ++#if defined(CONFIG_TEGRA210) ++ tegra_soc_board_init_late(); ++#endif ++ + return 0; + } + ++#ifndef CONFIG_TEGRA210 + /* + * In some SW environments, a memory carve-out exists to house a secure + * monitor, a trusted OS, and/or various statically allocated media buffers. +@@ -348,3 +353,4 @@ ulong board_get_usable_ram_top(ulong total_size) + { + return CONFIG_SYS_SDRAM_BASE + usable_ram_size_below_4g(); + } ++#endif +diff --git a/arch/arm/mach-tegra/dt-setup.c b/arch/arm/mach-tegra/dt-setup.c +index 8ac723f41e4..a961fab20f6 100644 +--- a/arch/arm/mach-tegra/dt-setup.c ++++ b/arch/arm/mach-tegra/dt-setup.c +@@ -12,12 +12,10 @@ + */ + int ft_system_setup(void *blob, bd_t *bd) + { ++#if !defined(CONFIG_ARM64) + const char *gpu_compats[] = { + #if defined(CONFIG_TEGRA124) + "nvidia,gk20a", +-#endif +-#if defined(CONFIG_TEGRA210) +- "nvidia,gm20b", + #endif + }; + int i, ret; +@@ -28,6 +26,7 @@ int ft_system_setup(void *blob, bd_t *bd) + if (ret) + return ret; + } ++#endif + + return 0; + } +diff --git a/arch/arm/mach-tegra/gpu.c b/arch/arm/mach-tegra/gpu.c +index e047f678211..3b8c1a04342 100644 +--- a/arch/arm/mach-tegra/gpu.c ++++ b/arch/arm/mach-tegra/gpu.c +@@ -17,6 +17,7 @@ static bool _configured; + + void tegra_gpu_config(void) + { ++#if !defined(CONFIG_ARM64) + struct mc_ctlr *mc = (struct mc_ctlr *)NV_PA_MC_BASE; + + #if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE) +@@ -34,6 +35,7 @@ void tegra_gpu_config(void) + debug("configured VPR\n"); + + _configured = true; ++#endif + } + + #if defined(CONFIG_OF_LIBFDT) +diff --git a/arch/arm/mach-tegra/tegra186/Makefile b/arch/arm/mach-tegra/tegra186/Makefile +index 56f3378ecea..1a43ef7a455 100644 +--- a/arch/arm/mach-tegra/tegra186/Makefile ++++ b/arch/arm/mach-tegra/tegra186/Makefile +@@ -4,6 +4,6 @@ + + obj-y += ../board186.o + obj-y += cache.o +-obj-y += nvtboot_board.o +-obj-y += nvtboot_ll.o +-obj-y += nvtboot_mem.o ++obj-y += ../nvtboot_board.o ++obj-y += ../nvtboot_ll.o ++obj-y += ../nvtboot_mem.o +diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_board.c b/arch/arm/mach-tegra/tegra186/nvtboot_board.c +deleted file mode 100644 +index 83c0e931ea2..00000000000 +--- a/arch/arm/mach-tegra/tegra186/nvtboot_board.c ++++ /dev/null +@@ -1,332 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0+ +-/* +- * Copyright (c) 2016-2018, NVIDIA CORPORATION. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-extern unsigned long nvtboot_boot_x0; +- +-/* +- * The following few functions run late during the boot process and dynamically +- * calculate the load address of various binaries. To keep track of multiple +- * allocations, some writable list of RAM banks must be used. tegra_mem_map[] +- * is used for this purpose to avoid making yet another copy of the list of RAM +- * banks. This is safe because tegra_mem_map[] is only used once during very +- * early boot to create U-Boot's page tables, long before this code runs. If +- * this assumption becomes invalid later, we can just fix the code to copy the +- * list of RAM banks into some private data structure before running. +- */ +- +-extern struct mm_region tegra_mem_map[]; +- +-static char *gen_varname(const char *var, const char *ext) +-{ +- size_t len_var = strlen(var); +- size_t len_ext = strlen(ext); +- size_t len = len_var + len_ext + 1; +- char *varext = malloc(len); +- +- if (!varext) +- return 0; +- strcpy(varext, var); +- strcpy(varext + len_var, ext); +- return varext; +-} +- +-static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end) +-{ +- u64 bank_start = tegra_mem_map[bank].virt; +- u64 bank_size = tegra_mem_map[bank].size; +- u64 bank_end = bank_start + bank_size; +- bool keep_front = allocated_start != bank_start; +- bool keep_tail = allocated_end != bank_end; +- +- if (keep_front && keep_tail) { +- /* +- * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array, +- * starting at index 1 (index 0 is MMIO). So, we are at DRAM +- * entry "bank" not "bank - 1" as for a typical 0-base array. +- * The number of remaining DRAM entries is therefore +- * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the +- * current entry and shift up the remaining entries, dropping +- * the last one. Thus, we must copy one fewer entry than the +- * number remaining. +- */ +- memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank], +- CONFIG_NR_DRAM_BANKS - bank - 1); +- tegra_mem_map[bank].size = allocated_start - bank_start; +- bank++; +- tegra_mem_map[bank].virt = allocated_end; +- tegra_mem_map[bank].phys = allocated_end; +- tegra_mem_map[bank].size = bank_end - allocated_end; +- } else if (keep_front) { +- tegra_mem_map[bank].size = allocated_start - bank_start; +- } else if (keep_tail) { +- tegra_mem_map[bank].virt = allocated_end; +- tegra_mem_map[bank].phys = allocated_end; +- tegra_mem_map[bank].size = bank_end - allocated_end; +- } else { +- /* +- * We could move all subsequent banks down in the array but +- * that's not necessary for subsequent allocations to work, so +- * we skip doing so. +- */ +- tegra_mem_map[bank].size = 0; +- } +-} +- +-static void reserve_ram(u64 start, u64 size) +-{ +- int bank; +- u64 end = start + size; +- +- for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { +- u64 bank_start = tegra_mem_map[bank].virt; +- u64 bank_size = tegra_mem_map[bank].size; +- u64 bank_end = bank_start + bank_size; +- +- if (end <= bank_start || start > bank_end) +- continue; +- mark_ram_allocated(bank, start, end); +- break; +- } +-} +- +-static u64 alloc_ram(u64 size, u64 align, u64 offset) +-{ +- int bank; +- +- for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { +- u64 bank_start = tegra_mem_map[bank].virt; +- u64 bank_size = tegra_mem_map[bank].size; +- u64 bank_end = bank_start + bank_size; +- u64 allocated = ROUND(bank_start, align) + offset; +- u64 allocated_end = allocated + size; +- +- if (allocated_end > bank_end) +- continue; +- mark_ram_allocated(bank, allocated, allocated_end); +- return allocated; +- } +- return 0; +-} +- +-static void set_calculated_aliases(char *aliases, u64 address) +-{ +- char *tmp, *alias; +- int err; +- +- aliases = strdup(aliases); +- if (!aliases) { +- pr_err("strdup(aliases) failed"); +- return; +- } +- +- tmp = aliases; +- while (true) { +- alias = strsep(&tmp, " "); +- if (!alias) +- break; +- debug("%s: alias: %s\n", __func__, alias); +- err = env_set_hex(alias, address); +- if (err) +- pr_err("Could not set %s\n", alias); +- } +- +- free(aliases); +-} +- +-static void set_calculated_env_var(const char *var) +-{ +- char *var_size; +- char *var_align; +- char *var_offset; +- char *var_aliases; +- u64 size; +- u64 align; +- u64 offset; +- char *aliases; +- u64 address; +- int err; +- +- var_size = gen_varname(var, "_size"); +- if (!var_size) +- return; +- var_align = gen_varname(var, "_align"); +- if (!var_align) +- goto out_free_var_size; +- var_offset = gen_varname(var, "_offset"); +- if (!var_offset) +- goto out_free_var_align; +- var_aliases = gen_varname(var, "_aliases"); +- if (!var_aliases) +- goto out_free_var_offset; +- +- size = env_get_hex(var_size, 0); +- if (!size) { +- pr_err("%s not set or zero\n", var_size); +- goto out_free_var_aliases; +- } +- align = env_get_hex(var_align, 1); +- /* Handle extant variables, but with a value of 0 */ +- if (!align) +- align = 1; +- offset = env_get_hex(var_offset, 0); +- aliases = env_get(var_aliases); +- +- debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n", +- __func__, var, size, align, offset); +- if (aliases) +- debug("%s: Aliases: %s\n", __func__, aliases); +- +- address = alloc_ram(size, align, offset); +- if (!address) { +- pr_err("Could not allocate %s\n", var); +- goto out_free_var_aliases; +- } +- debug("%s: Address %llx\n", __func__, address); +- +- err = env_set_hex(var, address); +- if (err) +- pr_err("Could not set %s\n", var); +- if (aliases) +- set_calculated_aliases(aliases, address); +- +-out_free_var_aliases: +- free(var_aliases); +-out_free_var_offset: +- free(var_offset); +-out_free_var_align: +- free(var_align); +-out_free_var_size: +- free(var_size); +-} +- +-#ifdef DEBUG +-static void dump_ram_banks(void) +-{ +- int bank; +- +- for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { +- u64 bank_start = tegra_mem_map[bank].virt; +- u64 bank_size = tegra_mem_map[bank].size; +- u64 bank_end = bank_start + bank_size; +- +- if (!bank_size) +- continue; +- printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1, +- bank_start, bank_end, bank_size); +- } +-} +-#endif +- +-static void set_calculated_env_vars(void) +-{ +- char *vars, *tmp, *var; +- +-#ifdef DEBUG +- printf("RAM banks before any calculated env. var.s:\n"); +- dump_ram_banks(); +-#endif +- +- reserve_ram(nvtboot_boot_x0, fdt_totalsize(nvtboot_boot_x0)); +- +-#ifdef DEBUG +- printf("RAM after reserving cboot DTB:\n"); +- dump_ram_banks(); +-#endif +- +- vars = env_get("calculated_vars"); +- if (!vars) { +- debug("%s: No env var calculated_vars\n", __func__); +- return; +- } +- +- vars = strdup(vars); +- if (!vars) { +- pr_err("strdup(calculated_vars) failed"); +- return; +- } +- +- tmp = vars; +- while (true) { +- var = strsep(&tmp, " "); +- if (!var) +- break; +- debug("%s: var: %s\n", __func__, var); +- set_calculated_env_var(var); +-#ifdef DEBUG +- printf("RAM banks affter allocating %s:\n", var); +- dump_ram_banks(); +-#endif +- } +- +- free(vars); +-} +- +-static int set_fdt_addr(void) +-{ +- int ret; +- +- ret = env_set_hex("fdt_addr", nvtboot_boot_x0); +- if (ret) { +- printf("Failed to set fdt_addr to point at DTB: %d\n", ret); +- return ret; +- } +- +- return 0; +-} +- +-/* +- * Attempt to use /chosen/nvidia,ether-mac in the nvtboot DTB to U-Boot's +- * ethaddr environment variable if possible. +- */ +-static int set_ethaddr_from_nvtboot(void) +-{ +- const void *nvtboot_blob = (void *)nvtboot_boot_x0; +- int ret, node, len; +- const u32 *prop; +- +- /* Already a valid address in the environment? If so, keep it */ +- if (env_get("ethaddr")) +- return 0; +- +- node = fdt_path_offset(nvtboot_blob, "/chosen"); +- if (node < 0) { +- printf("Can't find /chosen node in nvtboot DTB\n"); +- return node; +- } +- prop = fdt_getprop(nvtboot_blob, node, "nvidia,ether-mac", &len); +- if (!prop) { +- printf("Can't find nvidia,ether-mac property in nvtboot DTB\n"); +- return -ENOENT; +- } +- +- ret = env_set("ethaddr", (void *)prop); +- if (ret) { +- printf("Failed to set ethaddr from nvtboot DTB: %d\n", ret); +- return ret; +- } +- +- return 0; +-} +- +-int tegra_soc_board_init_late(void) +-{ +- set_calculated_env_vars(); +- /* +- * Ignore errors here; the value may not be used depending on +- * extlinux.conf or boot script content. +- */ +- set_fdt_addr(); +- /* Ignore errors here; not all cases care about Ethernet addresses */ +- set_ethaddr_from_nvtboot(); +- +- return 0; +-} +diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_ll.S b/arch/arm/mach-tegra/tegra186/nvtboot_ll.S +deleted file mode 100644 +index aa7a863d970..00000000000 +--- a/arch/arm/mach-tegra/tegra186/nvtboot_ll.S ++++ /dev/null +@@ -1,20 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0+ */ +-/* +- * Save nvtboot-related boot-time CPU state +- * +- * (C) Copyright 2015-2016 NVIDIA Corporation +- */ +- +-#include +-#include +- +-.align 8 +-.globl nvtboot_boot_x0 +-nvtboot_boot_x0: +- .dword 0 +- +-ENTRY(save_boot_params) +- adr x8, nvtboot_boot_x0 +- str x0, [x8] +- b save_boot_params_ret +-ENDPROC(save_boot_params) +diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c +deleted file mode 100644 +index 5c9467bfe8b..00000000000 +--- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c ++++ /dev/null +@@ -1,173 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0+ +-/* +- * Copyright (c) 2016-2018, NVIDIA CORPORATION. +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#define SZ_4G 0x100000000ULL +- +-/* +- * Size of a region that's large enough to hold the relocated U-Boot and all +- * other allocations made around it (stack, heap, page tables, etc.) +- * In practice, running "bdinfo" at the shell prompt, the stack reaches about +- * 5MB from the address selected for ram_top as of the time of writing, +- * so a 16MB region should be plenty. +- */ +-#define MIN_USABLE_RAM_SIZE SZ_16M +-/* +- * The amount of space we expect to require for stack usage. Used to validate +- * that all reservations fit into the region selected for the relocation target +- */ +-#define MIN_USABLE_STACK_SIZE SZ_1M +- +-DECLARE_GLOBAL_DATA_PTR; +- +-extern unsigned long nvtboot_boot_x0; +-extern struct mm_region tegra_mem_map[]; +- +-/* +- * These variables are written to before relocation, and hence cannot be +- * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary. +- * The section attribute forces this into .data and avoids this issue. This +- * also has the nice side-effect of the content being valid after relocation. +- */ +- +-/* The number of valid entries in ram_banks[] */ +-static int ram_bank_count __attribute__((section(".data"))); +- +-/* +- * The usable top-of-RAM for U-Boot. This is both: +- * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing. +- * b) At the end of a region that has enough space to hold the relocated U-Boot +- * and all other allocations made around it (stack, heap, page tables, etc.) +- */ +-static u64 ram_top __attribute__((section(".data"))); +-/* The base address of the region of RAM that ends at ram_top */ +-static u64 region_base __attribute__((section(".data"))); +- +-int dram_init(void) +-{ +- unsigned int na, ns; +- const void *nvtboot_blob = (void *)nvtboot_boot_x0; +- int node, len, i; +- const u32 *prop; +- +- na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2); +- ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2); +- +- node = fdt_path_offset(nvtboot_blob, "/memory"); +- if (node < 0) { +- pr_err("Can't find /memory node in nvtboot DTB"); +- hang(); +- } +- prop = fdt_getprop(nvtboot_blob, node, "reg", &len); +- if (!prop) { +- pr_err("Can't find /memory/reg property in nvtboot DTB"); +- hang(); +- } +- +- /* Calculate the true # of base/size pairs to read */ +- len /= 4; /* Convert bytes to number of cells */ +- len /= (na + ns); /* Convert cells to number of banks */ +- if (len > CONFIG_NR_DRAM_BANKS) +- len = CONFIG_NR_DRAM_BANKS; +- +- /* Parse the /memory node, and save useful entries */ +- gd->ram_size = 0; +- ram_bank_count = 0; +- for (i = 0; i < len; i++) { +- u64 bank_start, bank_end, bank_size, usable_bank_size; +- +- /* Extract raw memory region data from DTB */ +- bank_start = fdt_read_number(prop, na); +- prop += na; +- bank_size = fdt_read_number(prop, ns); +- prop += ns; +- gd->ram_size += bank_size; +- bank_end = bank_start + bank_size; +- debug("Bank %d: %llx..%llx (+%llx)\n", i, +- bank_start, bank_end, bank_size); +- +- /* +- * Align the bank to MMU section size. This is not strictly +- * necessary, since the translation table construction code +- * handles page granularity without issue. However, aligning +- * the MMU entries reduces the size and number of levels in the +- * page table, so is worth it. +- */ +- bank_start = ROUND(bank_start, SZ_2M); +- bank_end = bank_end & ~(SZ_2M - 1); +- bank_size = bank_end - bank_start; +- debug(" aligned: %llx..%llx (+%llx)\n", +- bank_start, bank_end, bank_size); +- if (bank_end <= bank_start) +- continue; +- +- /* Record data used to create MMU translation tables */ +- ram_bank_count++; +- /* Index below is deliberately 1-based to skip MMIO entry */ +- tegra_mem_map[ram_bank_count].virt = bank_start; +- tegra_mem_map[ram_bank_count].phys = bank_start; +- tegra_mem_map[ram_bank_count].size = bank_size; +- tegra_mem_map[ram_bank_count].attrs = +- PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE; +- +- /* Determine best bank to relocate U-Boot into */ +- if (bank_end > SZ_4G) +- bank_end = SZ_4G; +- debug(" end %llx (usable)\n", bank_end); +- usable_bank_size = bank_end - bank_start; +- debug(" size %llx (usable)\n", usable_bank_size); +- if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && +- (bank_end > ram_top)) { +- ram_top = bank_end; +- region_base = bank_start; +- debug("ram top now %llx\n", ram_top); +- } +- } +- +- /* Ensure memory map contains the desired sentinel entry */ +- tegra_mem_map[ram_bank_count + 1].virt = 0; +- tegra_mem_map[ram_bank_count + 1].phys = 0; +- tegra_mem_map[ram_bank_count + 1].size = 0; +- tegra_mem_map[ram_bank_count + 1].attrs = 0; +- +- /* Error out if a relocation target couldn't be found */ +- if (!ram_top) { +- pr_err("Can't find a usable RAM top"); +- hang(); +- } +- +- return 0; +-} +- +-int dram_init_banksize(void) +-{ +- int i; +- +- if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) { +- pr_err("Reservations exceed chosen region size"); +- hang(); +- } +- +- for (i = 0; i < ram_bank_count; i++) { +- gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt; +- gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size; +- } +- +-#ifdef CONFIG_PCI +- gd->pci_ram_top = ram_top; +-#endif +- +- return 0; +-} +- +-ulong board_get_usable_ram_top(ulong total_size) +-{ +- return ram_top; +-} +diff --git a/arch/arm/mach-tegra/tegra210/Makefile b/arch/arm/mach-tegra/tegra210/Makefile +index b6012fc7baa..6de6d810eb2 100644 +--- a/arch/arm/mach-tegra/tegra210/Makefile ++++ b/arch/arm/mach-tegra/tegra210/Makefile +@@ -8,5 +8,8 @@ + obj-y += clock.o + obj-y += funcmux.o + obj-y += pinmux.o ++obj-y += ../nvtboot_board.o ++obj-y += ../nvtboot_ll.o ++obj-y += ../nvtboot_mem.o + obj-y += xusb-padctl.o + obj-y += ../xusb-padctl-common.o +-- +2.17.1 + +From 8034f76be3face948e6356dcfe5444cf91f12059 Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Wed, 1 Aug 2018 11:10:33 +0100 +Subject: [PATCH 6/7] add nvboot files + +--- + arch/arm/mach-tegra/nvtboot_board.c | 402 ++++++++++++++++++++++++++++ + arch/arm/mach-tegra/nvtboot_ll.S | 20 ++ + arch/arm/mach-tegra/nvtboot_mem.c | 173 ++++++++++++ + 3 files changed, 595 insertions(+) + create mode 100644 arch/arm/mach-tegra/nvtboot_board.c + create mode 100644 arch/arm/mach-tegra/nvtboot_ll.S + create mode 100644 arch/arm/mach-tegra/nvtboot_mem.c + +diff --git a/arch/arm/mach-tegra/nvtboot_board.c b/arch/arm/mach-tegra/nvtboot_board.c +new file mode 100644 +index 00000000000..7b98b502ef2 +--- /dev/null ++++ b/arch/arm/mach-tegra/nvtboot_board.c +@@ -0,0 +1,402 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (c) 2016-2018, NVIDIA CORPORATION. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++extern unsigned long nvtboot_boot_x0; ++ ++/* ++ * The following few functions run late during the boot process and dynamically ++ * calculate the load address of various binaries. To keep track of multiple ++ * allocations, some writable list of RAM banks must be used. tegra_mem_map[] ++ * is used for this purpose to avoid making yet another copy of the list of RAM ++ * banks. This is safe because tegra_mem_map[] is only used once during very ++ * early boot to create U-Boot's page tables, long before this code runs. If ++ * this assumption becomes invalid later, we can just fix the code to copy the ++ * list of RAM banks into some private data structure before running. ++ */ ++ ++extern struct mm_region tegra_mem_map[]; ++ ++static char *gen_varname(const char *var, const char *ext) ++{ ++ size_t len_var = strlen(var); ++ size_t len_ext = strlen(ext); ++ size_t len = len_var + len_ext + 1; ++ char *varext = malloc(len); ++ ++ if (!varext) ++ return 0; ++ strcpy(varext, var); ++ strcpy(varext + len_var, ext); ++ return varext; ++} ++ ++static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end) ++{ ++ u64 bank_start = tegra_mem_map[bank].virt; ++ u64 bank_size = tegra_mem_map[bank].size; ++ u64 bank_end = bank_start + bank_size; ++ bool keep_front = allocated_start != bank_start; ++ bool keep_tail = allocated_end != bank_end; ++ ++ if (keep_front && keep_tail) { ++ /* ++ * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array, ++ * starting at index 1 (index 0 is MMIO). So, we are at DRAM ++ * entry "bank" not "bank - 1" as for a typical 0-base array. ++ * The number of remaining DRAM entries is therefore ++ * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the ++ * current entry and shift up the remaining entries, dropping ++ * the last one. Thus, we must copy one fewer entry than the ++ * number remaining. ++ */ ++ memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank], ++ CONFIG_NR_DRAM_BANKS - bank - 1); ++ tegra_mem_map[bank].size = allocated_start - bank_start; ++ bank++; ++ tegra_mem_map[bank].virt = allocated_end; ++ tegra_mem_map[bank].phys = allocated_end; ++ tegra_mem_map[bank].size = bank_end - allocated_end; ++ } else if (keep_front) { ++ tegra_mem_map[bank].size = allocated_start - bank_start; ++ } else if (keep_tail) { ++ tegra_mem_map[bank].virt = allocated_end; ++ tegra_mem_map[bank].phys = allocated_end; ++ tegra_mem_map[bank].size = bank_end - allocated_end; ++ } else { ++ /* ++ * We could move all subsequent banks down in the array but ++ * that's not necessary for subsequent allocations to work, so ++ * we skip doing so. ++ */ ++ tegra_mem_map[bank].size = 0; ++ } ++} ++ ++static void reserve_ram(u64 start, u64 size) ++{ ++ int bank; ++ u64 end = start + size; ++ ++ for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { ++ u64 bank_start = tegra_mem_map[bank].virt; ++ u64 bank_size = tegra_mem_map[bank].size; ++ u64 bank_end = bank_start + bank_size; ++ ++ if (end <= bank_start || start > bank_end) ++ continue; ++ mark_ram_allocated(bank, start, end); ++ break; ++ } ++} ++ ++static u64 alloc_ram(u64 size, u64 align, u64 offset) ++{ ++ int bank; ++ ++ for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { ++ u64 bank_start = tegra_mem_map[bank].virt; ++ u64 bank_size = tegra_mem_map[bank].size; ++ u64 bank_end = bank_start + bank_size; ++ u64 allocated = ROUND(bank_start, align) + offset; ++ u64 allocated_end = allocated + size; ++ ++ if (allocated_end > bank_end) ++ continue; ++ mark_ram_allocated(bank, allocated, allocated_end); ++ return allocated; ++ } ++ return 0; ++} ++ ++static void set_calculated_aliases(char *aliases, u64 address) ++{ ++ char *tmp, *alias; ++ int err; ++ ++ aliases = strdup(aliases); ++ if (!aliases) { ++ pr_err("strdup(aliases) failed"); ++ return; ++ } ++ ++ tmp = aliases; ++ while (true) { ++ alias = strsep(&tmp, " "); ++ if (!alias) ++ break; ++ debug("%s: alias: %s\n", __func__, alias); ++ err = env_set_hex(alias, address); ++ if (err) ++ pr_err("Could not set %s\n", alias); ++ } ++ ++ free(aliases); ++} ++ ++static void set_calculated_env_var(const char *var) ++{ ++ char *var_size; ++ char *var_align; ++ char *var_offset; ++ char *var_aliases; ++ u64 size; ++ u64 align; ++ u64 offset; ++ char *aliases; ++ u64 address; ++ int err; ++ ++ var_size = gen_varname(var, "_size"); ++ if (!var_size) ++ return; ++ var_align = gen_varname(var, "_align"); ++ if (!var_align) ++ goto out_free_var_size; ++ var_offset = gen_varname(var, "_offset"); ++ if (!var_offset) ++ goto out_free_var_align; ++ var_aliases = gen_varname(var, "_aliases"); ++ if (!var_aliases) ++ goto out_free_var_offset; ++ ++ size = env_get_hex(var_size, 0); ++ if (!size) { ++ pr_err("%s not set or zero\n", var_size); ++ goto out_free_var_aliases; ++ } ++ align = env_get_hex(var_align, 1); ++ /* Handle extant variables, but with a value of 0 */ ++ if (!align) ++ align = 1; ++ offset = env_get_hex(var_offset, 0); ++ aliases = env_get(var_aliases); ++ ++ debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n", ++ __func__, var, size, align, offset); ++ if (aliases) ++ debug("%s: Aliases: %s\n", __func__, aliases); ++ ++ address = alloc_ram(size, align, offset); ++ if (!address) { ++ pr_err("Could not allocate %s\n", var); ++ goto out_free_var_aliases; ++ } ++ debug("%s: Address %llx\n", __func__, address); ++ ++ err = env_set_hex(var, address); ++ if (err) ++ pr_err("Could not set %s\n", var); ++ if (aliases) ++ set_calculated_aliases(aliases, address); ++ ++out_free_var_aliases: ++ free(var_aliases); ++out_free_var_offset: ++ free(var_offset); ++out_free_var_align: ++ free(var_align); ++out_free_var_size: ++ free(var_size); ++} ++ ++#ifdef DEBUG ++static void dump_ram_banks(void) ++{ ++ int bank; ++ ++ for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { ++ u64 bank_start = tegra_mem_map[bank].virt; ++ u64 bank_size = tegra_mem_map[bank].size; ++ u64 bank_end = bank_start + bank_size; ++ ++ if (!bank_size) ++ continue; ++ printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1, ++ bank_start, bank_end, bank_size); ++ } ++} ++#endif ++ ++static void set_calculated_env_vars(void) ++{ ++ char *vars, *tmp, *var; ++ ++#ifdef DEBUG ++ printf("RAM banks before any calculated env. var.s:\n"); ++ dump_ram_banks(); ++#endif ++ ++ reserve_ram(nvtboot_boot_x0, fdt_totalsize(nvtboot_boot_x0)); ++ ++#ifdef DEBUG ++ printf("RAM after reserving cboot DTB:\n"); ++ dump_ram_banks(); ++#endif ++ ++ vars = env_get("calculated_vars"); ++ if (!vars) { ++ debug("%s: No env var calculated_vars\n", __func__); ++ return; ++ } ++ ++ vars = strdup(vars); ++ if (!vars) { ++ pr_err("strdup(calculated_vars) failed"); ++ return; ++ } ++ ++ tmp = vars; ++ while (true) { ++ var = strsep(&tmp, " "); ++ if (!var) ++ break; ++ debug("%s: var: %s\n", __func__, var); ++ set_calculated_env_var(var); ++#ifdef DEBUG ++ printf("RAM banks affter allocating %s:\n", var); ++ dump_ram_banks(); ++#endif ++ } ++ ++ free(vars); ++} ++ ++char *strstrip(char *s) ++{ ++ size_t size; ++ char *end; ++ ++ size = strlen(s); ++ ++ if (!size) ++ return s; ++ ++ end = s + size - 1; ++ while (end >= s && isblank(*end)) ++ end--; ++ *(end + 1) = '\0'; ++ ++ while (*s && isblank(*s)) ++ s++; ++ ++ return s; ++} ++ ++static int set_fdt_addr(void) ++{ ++ int ret; ++ ++ ret = env_set_hex("fdt_addr", nvtboot_boot_x0); ++ if (ret) { ++ printf("Failed to set fdt_addr to point at DTB: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++#if defined(CONFIG_TEGRA186) ++/* ++ * Attempt to use /chosen/nvidia,ether-mac in the nvtboot DTB to U-Boot's ++ * ethaddr environment variable if possible. ++ */ ++static int set_ethaddr_from_nvtboot(void) ++{ ++ const void *nvtboot_blob = (void *)nvtboot_boot_x0; ++ int ret, node, len; ++ const u32 *prop; ++ ++ /* Already a valid address in the environment? If so, keep it */ ++ if (env_get("ethaddr")) ++ return 0; ++ ++ node = fdt_path_offset(nvtboot_blob, "/chosen"); ++ if (node < 0) { ++ printf("Can't find /chosen node in nvtboot DTB\n"); ++ return node; ++ } ++ prop = fdt_getprop(nvtboot_blob, node, "nvidia,ether-mac", &len); ++ if (!prop) { ++ printf("Can't find nvidia,ether-mac property in nvtboot DTB\n"); ++ return -ENOENT; ++ } ++ ++ ret = env_set("ethaddr", (void *)prop); ++ if (ret) { ++ printf("Failed to set ethaddr from nvtboot DTB: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++#endif ++ ++static int set_cbootargs(void) ++{ ++ const void *nvtboot_blob = (void *)nvtboot_boot_x0; ++ const void *prop; ++ char *bargs, *s; ++ int node, len, ret = 0; ++ ++ /* ++ * Save the bootargs passed in the DTB by the previous bootloader ++ * (CBoot) to the env. (pointer in reg x0) ++ */ ++ ++ debug("%s: nvtboot_blob = %p\n", __func__, nvtboot_blob); ++ ++ node = fdt_path_offset(nvtboot_blob, "/chosen"); ++ if (node < 0) { ++ pr_err("Can't find /chosen node in nvtboot DTB"); ++ return node; ++ } ++ debug("%s: found 'chosen' node: %d\n", __func__, node); ++ ++ prop = fdt_getprop(nvtboot_blob, node, "bootargs", &len); ++ if (!prop) { ++ pr_err("Can't find /chosen/bootargs property in nvtboot DTB"); ++ return -ENOENT; ++ } ++ debug("%s: found 'bootargs' property, len =%d\n", __func__, len); ++ ++ /* CBoot seems to add trailing whitespace - strip it here */ ++ s = strdup((char *)prop); ++ bargs = strstrip(s); ++ debug("%s: bootargs = %s!\n", __func__, bargs); ++ ++ /* Set cbootargs to env for later use by extlinux files */ ++ ret = env_set("cbootargs", bargs); ++ if (ret) ++ printf("Failed to set cbootargs from cboot DTB: %d\n", ret); ++ ++ free(s); ++ return ret; ++} ++ ++int tegra_soc_board_init_late(void) ++{ ++ set_calculated_env_vars(); ++ /* ++ * Ignore errors here; the value may not be used depending on ++ * extlinux.conf or boot script content. ++ */ ++ set_fdt_addr(); ++#if defined(CONFIG_TEGRA186) ++ /* Ignore errors here; not all cases care about Ethernet addresses */ ++ set_ethaddr_from_nvtboot(); ++#endif ++ /* Save CBoot bootargs to env */ ++ set_cbootargs(); ++ ++ return 0; ++} +diff --git a/arch/arm/mach-tegra/nvtboot_ll.S b/arch/arm/mach-tegra/nvtboot_ll.S +new file mode 100644 +index 00000000000..aa7a863d970 +--- /dev/null ++++ b/arch/arm/mach-tegra/nvtboot_ll.S +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Save nvtboot-related boot-time CPU state ++ * ++ * (C) Copyright 2015-2016 NVIDIA Corporation ++ */ ++ ++#include ++#include ++ ++.align 8 ++.globl nvtboot_boot_x0 ++nvtboot_boot_x0: ++ .dword 0 ++ ++ENTRY(save_boot_params) ++ adr x8, nvtboot_boot_x0 ++ str x0, [x8] ++ b save_boot_params_ret ++ENDPROC(save_boot_params) +diff --git a/arch/arm/mach-tegra/nvtboot_mem.c b/arch/arm/mach-tegra/nvtboot_mem.c +new file mode 100644 +index 00000000000..5c9467bfe8b +--- /dev/null ++++ b/arch/arm/mach-tegra/nvtboot_mem.c +@@ -0,0 +1,173 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (c) 2016-2018, NVIDIA CORPORATION. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define SZ_4G 0x100000000ULL ++ ++/* ++ * Size of a region that's large enough to hold the relocated U-Boot and all ++ * other allocations made around it (stack, heap, page tables, etc.) ++ * In practice, running "bdinfo" at the shell prompt, the stack reaches about ++ * 5MB from the address selected for ram_top as of the time of writing, ++ * so a 16MB region should be plenty. ++ */ ++#define MIN_USABLE_RAM_SIZE SZ_16M ++/* ++ * The amount of space we expect to require for stack usage. Used to validate ++ * that all reservations fit into the region selected for the relocation target ++ */ ++#define MIN_USABLE_STACK_SIZE SZ_1M ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++extern unsigned long nvtboot_boot_x0; ++extern struct mm_region tegra_mem_map[]; ++ ++/* ++ * These variables are written to before relocation, and hence cannot be ++ * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary. ++ * The section attribute forces this into .data and avoids this issue. This ++ * also has the nice side-effect of the content being valid after relocation. ++ */ ++ ++/* The number of valid entries in ram_banks[] */ ++static int ram_bank_count __attribute__((section(".data"))); ++ ++/* ++ * The usable top-of-RAM for U-Boot. This is both: ++ * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing. ++ * b) At the end of a region that has enough space to hold the relocated U-Boot ++ * and all other allocations made around it (stack, heap, page tables, etc.) ++ */ ++static u64 ram_top __attribute__((section(".data"))); ++/* The base address of the region of RAM that ends at ram_top */ ++static u64 region_base __attribute__((section(".data"))); ++ ++int dram_init(void) ++{ ++ unsigned int na, ns; ++ const void *nvtboot_blob = (void *)nvtboot_boot_x0; ++ int node, len, i; ++ const u32 *prop; ++ ++ na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2); ++ ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2); ++ ++ node = fdt_path_offset(nvtboot_blob, "/memory"); ++ if (node < 0) { ++ pr_err("Can't find /memory node in nvtboot DTB"); ++ hang(); ++ } ++ prop = fdt_getprop(nvtboot_blob, node, "reg", &len); ++ if (!prop) { ++ pr_err("Can't find /memory/reg property in nvtboot DTB"); ++ hang(); ++ } ++ ++ /* Calculate the true # of base/size pairs to read */ ++ len /= 4; /* Convert bytes to number of cells */ ++ len /= (na + ns); /* Convert cells to number of banks */ ++ if (len > CONFIG_NR_DRAM_BANKS) ++ len = CONFIG_NR_DRAM_BANKS; ++ ++ /* Parse the /memory node, and save useful entries */ ++ gd->ram_size = 0; ++ ram_bank_count = 0; ++ for (i = 0; i < len; i++) { ++ u64 bank_start, bank_end, bank_size, usable_bank_size; ++ ++ /* Extract raw memory region data from DTB */ ++ bank_start = fdt_read_number(prop, na); ++ prop += na; ++ bank_size = fdt_read_number(prop, ns); ++ prop += ns; ++ gd->ram_size += bank_size; ++ bank_end = bank_start + bank_size; ++ debug("Bank %d: %llx..%llx (+%llx)\n", i, ++ bank_start, bank_end, bank_size); ++ ++ /* ++ * Align the bank to MMU section size. This is not strictly ++ * necessary, since the translation table construction code ++ * handles page granularity without issue. However, aligning ++ * the MMU entries reduces the size and number of levels in the ++ * page table, so is worth it. ++ */ ++ bank_start = ROUND(bank_start, SZ_2M); ++ bank_end = bank_end & ~(SZ_2M - 1); ++ bank_size = bank_end - bank_start; ++ debug(" aligned: %llx..%llx (+%llx)\n", ++ bank_start, bank_end, bank_size); ++ if (bank_end <= bank_start) ++ continue; ++ ++ /* Record data used to create MMU translation tables */ ++ ram_bank_count++; ++ /* Index below is deliberately 1-based to skip MMIO entry */ ++ tegra_mem_map[ram_bank_count].virt = bank_start; ++ tegra_mem_map[ram_bank_count].phys = bank_start; ++ tegra_mem_map[ram_bank_count].size = bank_size; ++ tegra_mem_map[ram_bank_count].attrs = ++ PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE; ++ ++ /* Determine best bank to relocate U-Boot into */ ++ if (bank_end > SZ_4G) ++ bank_end = SZ_4G; ++ debug(" end %llx (usable)\n", bank_end); ++ usable_bank_size = bank_end - bank_start; ++ debug(" size %llx (usable)\n", usable_bank_size); ++ if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && ++ (bank_end > ram_top)) { ++ ram_top = bank_end; ++ region_base = bank_start; ++ debug("ram top now %llx\n", ram_top); ++ } ++ } ++ ++ /* Ensure memory map contains the desired sentinel entry */ ++ tegra_mem_map[ram_bank_count + 1].virt = 0; ++ tegra_mem_map[ram_bank_count + 1].phys = 0; ++ tegra_mem_map[ram_bank_count + 1].size = 0; ++ tegra_mem_map[ram_bank_count + 1].attrs = 0; ++ ++ /* Error out if a relocation target couldn't be found */ ++ if (!ram_top) { ++ pr_err("Can't find a usable RAM top"); ++ hang(); ++ } ++ ++ return 0; ++} ++ ++int dram_init_banksize(void) ++{ ++ int i; ++ ++ if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) { ++ pr_err("Reservations exceed chosen region size"); ++ hang(); ++ } ++ ++ for (i = 0; i < ram_bank_count; i++) { ++ gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt; ++ gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size; ++ } ++ ++#ifdef CONFIG_PCI ++ gd->pci_ram_top = ram_top; ++#endif ++ ++ return 0; ++} ++ ++ulong board_get_usable_ram_top(ulong total_size) ++{ ++ return ram_top; ++} +-- +2.17.1 + +From 43290aacb9fc3ec05ff57b182fefbfec3be81da7 Mon Sep 17 00:00:00 2001 +From: JC Kuo +Date: Fri, 14 Apr 2017 17:54:21 +0800 +Subject: [PATCH 7/7] T210: do not enable PLLE and UPHY PLL HW PWRSEQ + +This commit removes the programming sequence that enables PLLE +and UPHY PLL hardware power sequencers. Per TRM, boot software +should enable PLLE and UPHY PLLs in software controlled power-on +state and should power down PLL before jumping into kernel or +the next stage boot software. + +Bug 1889735 + +Change-Id: I41b563d613b502abe902393b92ce311720d59ec0 +Signed-off-by: JC Kuo +Reviewed-on: http://git-master/r/1462905 +(cherry picked from commit f6ce7fbb731949fb94187b735ee76d30ef6256ad on dev-other-v2016.07) +Reviewed-on: http://git-master/r/1484083 +Reviewed-by: Stephen Warren +GVS: Gerrit_Virtual_Submit +Reviewed-by: Tom Warren +Tested-by: Tom Warren +--- + arch/arm/include/asm/arch-tegra/xusb-padctl.h | 1 + + arch/arm/mach-tegra/board2.c | 6 ++ + arch/arm/mach-tegra/tegra210/clock.c | 19 ------ + arch/arm/mach-tegra/tegra210/xusb-padctl.c | 68 ++++++++++++------- + arch/arm/mach-tegra/xusb-padctl-dummy.c | 4 ++ + 5 files changed, 54 insertions(+), 44 deletions(-) + +diff --git a/arch/arm/include/asm/arch-tegra/xusb-padctl.h b/arch/arm/include/asm/arch-tegra/xusb-padctl.h +index deccdf455d9..7e14d8109d1 100644 +--- a/arch/arm/include/asm/arch-tegra/xusb-padctl.h ++++ b/arch/arm/include/asm/arch-tegra/xusb-padctl.h +@@ -16,6 +16,7 @@ struct tegra_xusb_phy; + struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type); + + void tegra_xusb_padctl_init(void); ++void tegra_xusb_padctl_exit(void); + int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy); + int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy); + int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy); +diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c +index 301fd16af61..22ecd997600 100644 +--- a/arch/arm/mach-tegra/board2.c ++++ b/arch/arm/mach-tegra/board2.c +@@ -171,6 +171,12 @@ int board_init(void) + return nvidia_board_init(); + } + ++void board_cleanup_before_linux(void) ++{ ++ /* power down UPHY PLL */ ++ tegra_xusb_padctl_exit(); ++} ++ + #ifdef CONFIG_BOARD_EARLY_INIT_F + static void __gpio_early_init(void) + { +diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c +index 06068c4b7b8..341c97f16d9 100644 +--- a/arch/arm/mach-tegra/tegra210/clock.c ++++ b/arch/arm/mach-tegra/tegra210/clock.c +@@ -1235,25 +1235,6 @@ int tegra_plle_enable(void) + value &= ~PLLE_SS_CNTL_INTERP_RESET; + writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL); + +- /* 7. Enable HW power sequencer for PLLE */ +- +- value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC); +- value &= ~PLLE_MISC_IDDQ_SWCTL; +- writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC); +- +- value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX); +- value &= ~PLLE_AUX_SS_SWCTL; +- value &= ~PLLE_AUX_ENABLE_SWCTL; +- value |= PLLE_AUX_SS_SEQ_INCLUDE; +- value |= PLLE_AUX_USE_LOCKDET; +- writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX); +- +- /* 8. Wait 1 us */ +- +- udelay(1); +- value |= PLLE_AUX_SEQ_ENABLE; +- writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX); +- + return 0; + } + +diff --git a/arch/arm/mach-tegra/tegra210/xusb-padctl.c b/arch/arm/mach-tegra/tegra210/xusb-padctl.c +index ab6684f027c..64dc297ae27 100644 +--- a/arch/arm/mach-tegra/tegra210/xusb-padctl.c ++++ b/arch/arm/mach-tegra/tegra210/xusb-padctl.c +@@ -170,6 +170,17 @@ static int phy_unprepare(struct tegra_xusb_phy *phy) + return tegra_xusb_padctl_disable(phy->padctl); + } + ++#define XUSB_PADCTL_USB3_PAD_MUX 0x28 ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE (1 << 0) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK0 (1 << 1) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK1 (1 << 2) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK2 (1 << 3) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK3 (1 << 4) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK4 (1 << 5) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK5 (1 << 6) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK6 (1 << 7) ++#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_SATA_PAD_IDDQ_DISABLE_MASK0 (1 << 8) ++ + #define XUSB_PADCTL_UPHY_PLL_P0_CTL1 0x360 + #define XUSB_PADCTL_UPHY_PLL_P0_CTL1_FREQ_NDIV_MASK (0xff << 20) + #define XUSB_PADCTL_UPHY_PLL_P0_CTL1_FREQ_NDIV(x) (((x) & 0xff) << 20) +@@ -366,31 +377,6 @@ static int pcie_phy_enable(struct tegra_xusb_phy *phy) + value &= ~XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_CLK_EN; + padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); + +- value = readl(NV_PA_CLK_RST_BASE + CLK_RST_XUSBIO_PLL_CFG0); +- value &= ~CLK_RST_XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL; +- value &= ~CLK_RST_XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL; +- value |= CLK_RST_XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET; +- value |= CLK_RST_XUSBIO_PLL_CFG0_PADPLL_SLEEP_IDDQ; +- writel(value, NV_PA_CLK_RST_BASE + CLK_RST_XUSBIO_PLL_CFG0); +- +- value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); +- value &= ~XUSB_PADCTL_UPHY_PLL_P0_CTL1_PWR_OVRD; +- padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); +- +- value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2); +- value &= ~XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_OVRD; +- padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL2); +- +- value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8); +- value &= ~XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_OVRD; +- padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL8); +- +- udelay(1); +- +- value = readl(NV_PA_CLK_RST_BASE + CLK_RST_XUSBIO_PLL_CFG0); +- value |= CLK_RST_XUSBIO_PLL_CFG0_SEQ_ENABLE; +- writel(value, NV_PA_CLK_RST_BASE + CLK_RST_XUSBIO_PLL_CFG0); +- + debug("< %s()\n", __func__); + return 0; + } +@@ -454,3 +440,35 @@ void tegra_xusb_padctl_init(void) + ret = tegra_xusb_process_nodes(nodes, count, &tegra210_socdata); + debug("%s: done, ret=%d\n", __func__, ret); + } ++ ++void tegra_xusb_padctl_exit(void) ++{ ++ u32 value; ++ ++ debug("> %s\n", __func__); ++ ++ value = padctl_readl(&padctl, XUSB_PADCTL_USB3_PAD_MUX); ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK0; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK1; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK2; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK3; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK4; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK5; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK6; ++ value &= ~XUSB_PADCTL_USB3_PAD_MUX_FORCE_SATA_PAD_IDDQ_DISABLE_MASK0; ++ padctl_writel(&padctl, value, XUSB_PADCTL_USB3_PAD_MUX); ++ ++ value = padctl_readl(&padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1); ++ value &= ~XUSB_PADCTL_UPHY_PLL_P0_CTL1_IDDQ; ++ value &= ~XUSB_PADCTL_UPHY_PLL_P0_CTL1_SLEEP_MASK; ++ value |= XUSB_PADCTL_UPHY_PLL_P0_CTL1_SLEEP(3); ++ value &= ~XUSB_PADCTL_UPHY_PLL_P0_CTL1_ENABLE; ++ padctl_writel(&padctl, value, XUSB_PADCTL_UPHY_PLL_P0_CTL1); ++ ++ reset_set_enable(PERIPH_ID_PEX_USB_UPHY, 1); ++ while (padctl.enable) ++ tegra_xusb_padctl_disable(&padctl); ++ ++ debug("< %s()\n", __func__); ++} +diff --git a/arch/arm/mach-tegra/xusb-padctl-dummy.c b/arch/arm/mach-tegra/xusb-padctl-dummy.c +index 3ec27a2e3aa..f2d90302f6d 100644 +--- a/arch/arm/mach-tegra/xusb-padctl-dummy.c ++++ b/arch/arm/mach-tegra/xusb-padctl-dummy.c +@@ -36,3 +36,7 @@ int __weak tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy) + void __weak tegra_xusb_padctl_init(void) + { + } ++ ++void __weak tegra_xusb_padctl_exit(void) ++{ ++} +-- +2.17.1 + diff --git a/tegra-p2771-Add-CONFIG_EFI_LOADER_BOUNCE_BUFFER.patch b/tegra-p2771-Add-CONFIG_EFI_LOADER_BOUNCE_BUFFER.patch index cf5a8da..e001fd3 100644 --- a/tegra-p2771-Add-CONFIG_EFI_LOADER_BOUNCE_BUFFER.patch +++ b/tegra-p2771-Add-CONFIG_EFI_LOADER_BOUNCE_BUFFER.patch @@ -39,3 +39,31 @@ index cc10669608f..9ae61263b5d 100644 -- 2.17.1 +From 74f4d5ee23b768112c1d9977b648945d93d8cd68 Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Tue, 14 Aug 2018 16:46:15 +0100 +Subject: [PATCH] tegra: p2371: Add CONFIG_EFI_LOADER_BOUNCE_BUFFER + +The Jetson TX1 needs EFI loader bounce buffer enabled otherwise grub doesn't see +the storage when it loads. + +Signed-off-by: Peter Robinson +--- + configs/p2371-2180_defconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/configs/p2371-2180_defconfig b/configs/p2371-2180_defconfig +index 289d88b31e5..5db65af4ade 100644 +--- a/configs/p2371-2180_defconfig ++++ b/configs/p2371-2180_defconfig +@@ -5,6 +5,7 @@ CONFIG_TEGRA210=y + CONFIG_TARGET_P2371_2180=y + CONFIG_DEFAULT_DEVICE_TREE="tegra210-p2371-2180" + CONFIG_OF_SYSTEM_SETUP=y ++CONFIG_EFI_LOADER_BOUNCE_BUFFER=y + CONFIG_CONSOLE_MUX=y + CONFIG_SYS_STDIO_DEREGISTER=y + CONFIG_SYS_PROMPT="Tegra210 (P2371-2180) # " +-- +2.17.1 + diff --git a/tegra186-jetson-tx2-disable-onboard-emmc.patch b/tegra186-jetson-tx2-disable-onboard-emmc.patch index ebdb31a..d31a6df 100644 --- a/tegra186-jetson-tx2-disable-onboard-emmc.patch +++ b/tegra186-jetson-tx2-disable-onboard-emmc.patch @@ -24,3 +24,29 @@ index a1319dc493..e220f086ee 100644 -- 2.17.0 +From 7bba3cc32c8b8b5d3688c42a803768761df0a23f Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Wed, 1 Aug 2018 11:47:56 +0100 +Subject: [PATCH] tegra210: Jetson TX1: disable onboard emmc + +Signed-off-by: Peter Robinson +--- + arch/arm/dts/tegra210-p2371-2180.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/dts/tegra210-p2371-2180.dts b/arch/arm/dts/tegra210-p2371-2180.dts +index da4349bd039..87ce030e701 100644 +--- a/arch/arm/dts/tegra210-p2371-2180.dts ++++ b/arch/arm/dts/tegra210-p2371-2180.dts +@@ -80,7 +80,7 @@ + }; + + sdhci@700b0600 { +- status = "okay"; ++ status = "disabled"; + bus-width = <8>; + non-removable; + }; +-- +2.17.1 + diff --git a/uboot-tools.spec b/uboot-tools.spec index 9e5c534..3fd4ea0 100644 --- a/uboot-tools.spec +++ b/uboot-tools.spec @@ -1,8 +1,8 @@ -%global candidate rc1 +%global candidate rc2 Name: uboot-tools Version: 2018.09 -Release: 0.1%{?candidate:.%{candidate}}%{?dist} +Release: 0.2%{?candidate:.%{candidate}}%{?dist} Summary: U-Boot utilities License: GPLv2+ BSD LGPL-2.1+ LGPL-2.0+ URL: http://www.denx.de/wiki/U-Boot @@ -26,7 +26,8 @@ Patch10: dragonboard-fixes.patch Patch11: rockchip-make_fit_atf-fix-warning-unit_address_vs_reg.patch Patch12: rockchip-make_fit_atf-use-elf-entry-point.patch Patch13: tegra186-jetson-tx2-disable-onboard-emmc.patch -Patch14: tegra-p2771-Add-CONFIG_EFI_LOADER_BOUNCE_BUFFER.patch +Patch14: tegra-fix-tx1.patch +Patch15: tegra-p2771-Add-CONFIG_EFI_LOADER_BOUNCE_BUFFER.patch #Patch19: rpi-Enable-using-the-DT-provided-by-the-Raspberry-Pi.patch # Patch99: mvebu-enable-generic-distro-boot-config.patch @@ -292,6 +293,11 @@ cp -p board/warp7/README builds/docs/README.warp7 %endif %changelog +* Tue Aug 14 2018 Peter Robinson 2018.09-0.2.rc2 +- 2018.09 RC2 +- Improve Jetson TX1 support +- Enable OrangePi 1+ and Avnet Ultra96 + * Tue Jul 31 2018 Peter Robinson 2018.09-0.1.rc1 - 2018.09 RC1