From a2a302b9d528bbc3a791062d2a8a173ecfb19849 Mon Sep 17 00:00:00 2001 From: CTCaer Date: Tue, 20 Dec 2022 17:00:33 +0200 Subject: [PATCH] l4t: Add L4T loader for T210 and T210B01 --- Makefile | 2 +- README.md | 9 +- bootloader/l4t/l4t.c | 1213 +++++++++++++++++++++++++++++++++ bootloader/l4t/l4t.h | 24 + bootloader/l4t/l4t_config.inl | 36 + bootloader/main.c | 32 +- 6 files changed, 1311 insertions(+), 5 deletions(-) create mode 100644 bootloader/l4t/l4t.c create mode 100644 bootloader/l4t/l4t.h create mode 100644 bootloader/l4t/l4t_config.inl diff --git a/Makefile b/Makefile index a55e193..58f0134 100755 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \ start.o exception_handlers.o \ main.o heap.o \ gfx.o logos.o tui.o \ - fe_info.o fe_tools.o \ + l4t.o fe_info.o fe_tools.o \ ) # Hardware. diff --git a/README.md b/README.md index ad176bc..46dd35a 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,12 @@ There are four possible type of entries. "**[ ]**": Boot entry, "**{ }**": Capti | ---------------------- | ---------------------------------------------------------- | | payload={FILE path} | Payload launching. Tools, Android/Linux, CFW bootloaders, etc. Any key above when used with that, doesn't get into account. | | ---------------------- | ---------------------------------------------------------- | +| l4t=1 | L4T Linux/Android native launching. | +| boot_prefixes={FOLDER path} | L4T bootstack directory. | +| ram_oc=0 | L4T RAM Overclocking. Check README_CONFIG.txt for more info. | +| uart_port=0 | Enables logging on serial port for L4T uboot/kernel. | +| Additional keys | Each distro supports more keys. Check README_CONFIG.txt for more info. | +| ---------------------- | ---------------------------------------------------------- | | id=IDNAME | Identifies boot entry for forced boot via id. Max 7 chars. | | logopath={FILE path} | If it exists, it will load the specified bitmap. Otherwise `bootloader/bootlogo.bmp` will be used if exists | | icon={FILE path} | Force Nyx to use the icon defined here. If this is not found, it will check for a bmp named as the boot entry ([Test 2] -> `bootloader/res/Test 2.bmp`). Otherwise defaults will be used. | @@ -160,9 +166,6 @@ hekate has a boot storage in the binary that helps it configure it outside of BP | '0xA0' emummc_path[120] | When `Boot to emuMMC` is set, it will override the current emuMMC (boot entry or emummc.ini). Must be NULL terminated. | -If the main .ini is not found, it is created on the first hekate boot and only has the `[config]` entry. - - ### Nyx Configuration keys/values (nyx.ini): | Config option | Description | diff --git a/bootloader/l4t/l4t.c b/bootloader/l4t/l4t.c new file mode 100644 index 0000000..cc6e001 --- /dev/null +++ b/bootloader/l4t/l4t.c @@ -0,0 +1,1213 @@ +/* + * L4T Loader for Tegra X1 + * + * Copyright (c) 2020-2022 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include + +#include "../hos/hos.h" +#include "../hos/pkg1.h" +#include "l4t.h" +#include "l4t_config.inl" + +#ifdef DEBUG_UART_PORT + #include + #define UPRINTF(...) uart_printf(__VA_ARGS__) +#else + #define UPRINTF(...) +#endif + +#if CARVEOUT_NVDEC_TSEC_ENABLE && CARVEOUT_SECFW_ENABLE +#error "NVDEC and SECFW carveouts can't be used together!" +#endif + +#if CARVEOUT_NVDEC_TSEC_ENABLE + #define TZ_SIZE SZ_8M +#else + #define TZ_SIZE SZ_1M +#endif + +// TZDRAM addresses and sizes. +#define TZDRAM_SIZE TZ_SIZE // Secure Element. +#define TZDRAM_BASE (0xFFFFFFFF - TZDRAM_SIZE + 1) // 0xFFF00000 or 0xFF800000. +#define TZDRAM_COLD_ENTRY (TZDRAM_BASE) +#define TZDRAM_WARM_ENTRY (TZDRAM_BASE + 0x200) + +// Carveout sizes. +#define CARVEOUT_NVDEC_SIZE SZ_1M +#define CARVEOUT_TSEC_SIZE SZ_1M +#define CARVEOUT_SECFW_SIZE SZ_1M +#define CARVEOUT_GPUFW_SIZE SZ_256K +#if CARVEOUT_NVDEC_TSEC_ENABLE + #define CARVEOUT_GPUWPR_SIZE CARVEOUT_GPUWPR_SIZE_CFG +#else + #define CARVEOUT_GPUWPR_SIZE (SZ_512K + SZ_256K) +#endif + +#define SC7ENTRY_HDR_SIZE 0x400 + +// Secure Elements addresses for T210. +#define SECFW_BASE (TZDRAM_BASE - SZ_1M) // 0xFFE00000 or 0xFF700000. +#define SC7ENTRY_HDR_BASE (SECFW_BASE + 0) +#define SC7ENTRY_BASE (SECFW_BASE + SC7ENTRY_HDR_SIZE) // After header. +#define SC7EXIT_BASE (SECFW_BASE + SZ_64K) // 64KB after SECFW_BASE. +#define R2P_PAYLOAD_BASE (SECFW_BASE + SZ_256K) // 256KB after SECFW_BASE. +#define MTCTABLE_BASE (SECFW_BASE + SZ_512K) // 512KB after SECFW_BASE. + +// Secure Elements addresses for T210B01. +#define BPMPFW_BASE (SECFW_BASE) // !! DTS carveout-start must match !! +#define BPMPFW_ENTRYPOINT (BPMPFW_BASE + 0x40) // Used internally also. +#define BPMPFW_HEAP_BASE (BPMPFW_BASE + SZ_256K - SZ_1K) // 255KB after BPMPFW_BASE. +#define BPMPFW_EDTB_BASE (BPMPFW_BASE + SZ_1M - 0) // Top BPMPFW carveout minus EMC DTB size. +#define BPMPFW_ADTB_BASE (BPMPFW_BASE + 0x26008) // Attached BPMP-FW DTB address. +#define SC7EXIT_B01_BASE (BPMPFW_HEAP_BASE - SZ_4K) // 4KB before BPMP heap. + +// BPMP-FW defines. Offsets are 0xD8 below real main binary. +#define BPMPFW_DTB_ADDR (BPMPFW_BASE + 0x14) // u32. DTB address if not attached. +#define BPMPFW_CC_INIT_OP (BPMPFW_BASE + 0x17324) // u8. Initial table training OP. 0: OP_SWITCH, 1: OP_TRAIN, 2: OP_TRAIN_SWITCH. Default: OP_TRAIN. +#define BPMPFW_LOGLEVEL (BPMPFW_BASE + 0x2547C) // u32. Log level. Default 3. +#define BPMPFW_LOGLEVEL (BPMPFW_BASE + 0x2547C) // u32. Log level. Default 3. +#define BPMPFW_CC_PT_TIME (BPMPFW_BASE + 0x25644) // u32. Periodic training period (in ms). Default 100 ms. +#define BPMPFW_CC_DEBUG (BPMPFW_BASE + 0x257F8) // u32. EMC Clock Change debug mask. Default: 0x50000101. + +// BPMP-FW attached DTB defines. Can be generalized. +#define BPMPFW_DTB_EMC_ENTRIES 4 +#define BPMPFW_DTB_SERIAL_PORT_VAL (BPMPFW_ADTB_BASE + 0x5B) // u8. DTB UART port offset. 0: Disabled. +#define BPMPFW_DTB_SET_SERIAL_PORT(port) (*(u8 *)BPMPFW_DTB_SERIAL_PORT_VAL = port) +#define BPMPFW_DTB_EMC_TBL_OFF (BPMPFW_ADTB_BASE + 0xA0) +#define BPMPFW_DTB_EMC_TBL_SZ 0x1120 +#define BPMPFW_DTB_EMC_NAME_VAL 0xA +#define BPMPFW_DTB_EMC_ENABLE_OFF 0x20 +#define BPMPFW_DTB_EMC_VALUES_OFF 0x4C +#define BPMPFW_DTB_EMC_FREQ_VAL 0x8C +#define BPMPFW_DTB_EMC_SCC_OFF 0x108C +#define BPMPFW_DTB_EMC_PLLM_DIVM_VAL 0x10A4 +#define BPMPFW_DTB_EMC_PLLM_DIVN_VAL 0x10A8 +#define BPMPFW_DTB_EMC_PLLM_DIVP_VAL 0x10AC +#define BPMPFW_DTB_EMC_TBL_START(idx) (BPMPFW_DTB_EMC_TBL_OFF + BPMPFW_DTB_EMC_TBL_SZ * (idx)) +#define BPMPFW_DTB_EMC_TBL_SET_VAL(idx, off, val) (*(u32 *)(BPMPFW_DTB_EMC_TBL_START(idx) + (off)) = (val)) +#define BPMPFW_DTB_EMC_TBL_SET_FREQ(idx, freq) (*(u32 *)(BPMPFW_DTB_EMC_TBL_START(idx) + BPMPFW_DTB_EMC_FREQ_VAL) = (freq)) +#define BPMPFW_DTB_EMC_TBL_SCC_OFFSET(idx) ((void *)(BPMPFW_DTB_EMC_TBL_START(idx) + BPMPFW_DTB_EMC_SCC_OFF)) +#define BPMPFW_DTB_EMC_TBL_SET_PLLM_DIVN(idx, n) (*(u32 *)(BPMPFW_DTB_EMC_TBL_START(idx) + BPMPFW_DTB_EMC_PLLM_DIVN_VAL) = (n)) +#define BPMPFW_DTB_EMC_TBL_SET_NAME(idx, name) (strcpy((char *)(BPMPFW_DTB_EMC_TBL_START(idx) + BPMPFW_DTB_EMC_NAME_VAL), (name))) +#define BPMPFW_DTB_EMC_TBL_ENABLE(idx) (*(char *)(BPMPFW_DTB_EMC_TBL_START(idx) + BPMPFW_DTB_EMC_ENABLE_OFF) = 'n') +#define BPMPFW_DTB_EMC_TBL_OFFSET(idx) ((void *)(BPMPFW_DTB_EMC_TBL_START(idx) + BPMPFW_DTB_EMC_VALUES_OFF)) + +// MTC table defines for T210B01. +#define BPMPFW_MTC_TABLE_BASE 0xA0000000 +#define BPMPFW_MTC_FREQ_TABLE_SIZE 4300 +#define BPMPFW_MTC_TABLE_SIZE (BPMPFW_MTC_FREQ_TABLE_SIZE * 3) +#define BPMPFW_MTC_TABLE(idx) (BPMPFW_MTC_TABLE_BASE + BPMPFW_MTC_TABLE_SIZE * (idx)) +#define BPMPFW_MTC_TABLE_OFFSET(idx, fidx) ((void *)(BPMPFW_MTC_TABLE(idx) + BPMPFW_MTC_FREQ_TABLE_SIZE * (fidx))) + +// BL31 Enable IRAM based config. +#define BL31_IRAM_PARAMS 0x4D415249 // "IRAM". +#define BL31_EXTRA_FEATURES_ENABLE 0x52545845 // "EXTR". + +// BL31 Flags. +#define FLAGS_PMC_NON_SECURE BIT(0) +#define FLAGS_SC7_NO_BASE_RESTRICTION BIT(1) + +// BL31 config. +#define PARAM_EP 1 +#define PARAM_BL31 3 +#define PARAM_EP_SECURE 0 +#define PARAM_EP_NON_SECURE 1 +#define VERSION_1 1 +#define SPSR_EL2T BIT(3) + +// BL33 config. +#define BL33_LOAD_BASE 0xAA000000 // DTB is loaded at 0xA8000000, so 32MB above. +#define BL33_ENV_BASE (BL33_LOAD_BASE - SZ_256K) // Before BL33_LOAD_BASE. +#define BL33_ENV_MAGIC_OFFSET (BL33_ENV_BASE - 4) +#define BL33_ENV_MAGIC 0x33334C42 +#define BL33_DTB_OFFSET (BL33_LOAD_BASE + 0x10) // After code end. +#define BL33_DTB_BASE (BL33_LOAD_BASE + *(u32 *)BL33_DTB_OFFSET) +#define BL33_DTB_UART_STATUS 0x1C94 +#define BL33_DTB_UART_STS_OF 0x12C +#define BL33_DTB_STDOUT_PATH 0x3F34 +#define BL33_DTB_STDERR_PATH 0x3F54 +#define BL33_DTB_SET_UART_STATUS(port) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_UART_STATUS + (port - 1) * BL33_DTB_UART_STS_OF), "okay")) +#define BL33_DTB_SET_STDOUT_PATH(path) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_STDOUT_PATH), (path))) +#define BL33_DTB_SET_STDERR_PATH(path) (strcpy((char *)(BL33_DTB_BASE + BL33_DTB_STDERR_PATH), (path))) + +// Misc. +#define DTB_MAGIC 0xEDFE0DD0 // D00DFEED. +#define FALCON_DMA_PAGE_SIZE 0x100 +#define ACR_GSC3_ENABLE_MAGIC 0xC0EDBBCC +#define SOC_ID_T210 0x210 +#define SOC_ID_T210B01 0x214 +#define SKU_NX 0x83 +#define HDCP22 2 + +typedef struct _tsec_init_t { + u32 sku; + u32 hdcp; + u32 soc; +} tsec_init_t; + +typedef struct _param_header { + u8 type; // type of the structure. + u8 version; // version of this structure. + u16 size; // size of this structure in bytes. + u32 attr; // attributes: unused bits SBZ. +} param_header_t; + +typedef struct _aapcs64_params { + u64 x0; + u64 x1; + u64 x2; + u64 x3; + u64 x4; + u64 x5; + u64 x6; + u64 x7; +} aapcs64_params_t; + +typedef struct _entry_point_info { + param_header_t hdr; + u64 pc; + u32 spsr; + u32 align0; // Alignment to u64 for the above member. + aapcs64_params_t args; +} entry_point_info_t; + +typedef struct _image_info { + param_header_t hdr; + u64 image_base; // physical address of base of image. + u32 image_size; // bytes read from image file. + u32 image_max_size; +} image_info_t; + +typedef struct _bl_v1_params { + param_header_t hdr; + u64 bl31_image_info; + u64 bl32_ep_info; + u64 bl32_image_info; + u64 bl33_ep_info; + u64 bl33_image_info; +} bl_v1_params_t; + +typedef struct _plat_params_from_bl2 { + // TZDRAM. + u64 tzdram_size; + u64 tzdram_base; + + s32 uart_id; // UART port ID. + s32 l2_ecc_parity_prot_dis; // L2 ECC parity protection disable flag. + u64 boot_profiler_shmem_base; // SHMEM base address for storing the boot logs. + + // SC7-Entry firmware. + u64 sc7entry_fw_size; + u64 sc7entry_fw_base; + + s32 enable_ccplex_lock_step; // Enable dual execution. + + // Enable below features. + s32 enable_extra_features; + + // MTC table. + u64 emc_table_size; + u64 emc_table_base; + + // Initial R2P payload. + u64 r2p_payload_size; + u64 r2p_payload_base; + + u64 flags; // Platform flags. +} plat_params_from_bl2_t; + +typedef struct _pll_spread_spectrum_t210b01_t { + u32 ss_cfg; + u32 ss_ctrl1; + u32 ss_ctrl2; + u32 ss2_cfg; + u32 ss2_ctrl1; + u32 ss2_ctrl2; + u32 divm; + u32 divn; + u32 pdivp; +} pll_spread_spectrum_t210b01_t; + +typedef struct _pll_ssc_t210b01_t { + u32 ss_ctrl1; + u32 ss_ctrl2; + u32 divn; +} pll_ssc_t210b01_t; + +typedef struct _l4t_fw_t +{ + u32 addr; + char *name; +} l4t_fw_t; + +typedef struct _l4t_ctxt_t +{ + char *path; + + char *ram_oc_txt; + int ram_oc_freq; + + u32 serial_port; + u32 sc7entry_size; + + emc_table_t *mtc_table; +} l4t_ctxt_t; + +#define DRAM_T210_OC_VOLTAGE 1187500 +#define DRAM_T210_OC_THRESHOLD_FREQ 1862400 + +#define DRAM_TBL_PROVIDED_MAX_FREQ 1600000 + +// JEDEC frequency table. +static const u32 ram_jd_t210b01[] = { + 1866000, + 2133000, +}; + +#define DRAM_T210B01_SSC_PARAMS 2 + +static const pll_ssc_t210b01_t pll_jd_ssc_t210b01[DRAM_T210B01_SSC_PARAMS] = { + { 0x300FB3A, 0x30300, 48 }, + { 0x180F89D, 0x10070180, 55 }, +}; + +//! TODO: Update on dram config changes. +static const u8 mtc_table_idx_t210b01[] = { +/* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 */ + -1, -1, -1, 7, -1, 7, 7, -1, 0, 1, 2, 3, 0, 1, 2, 3, -1, 4, 5, 4, 8, 8, 8, 5, 4, 6, 6, 6, 5, 9, 9, 9, 10, 10, 10 +}; + +static const l4t_fw_t l4t_fw[] = { + { TZDRAM_BASE, "bl31.bin" }, + { BL33_LOAD_BASE, "bl33.bin" }, + { SC7ENTRY_BASE, "sc7entry.bin" }, + { SC7EXIT_BASE, "sc7exit.bin" }, + { SC7EXIT_B01_BASE, "sc7exit_b01.bin" }, + { BPMPFW_BASE, "bpmpfw_b01.bin" }, + { BPMPFW_MTC_TABLE_BASE, "mtc_tbl_b01.bin" }, +}; + +enum { + BL31_FW = 0, + BL33_FW = 1, + SC7ENTRY_FW = 2, + SC7EXIT_FW = 3, + SC7EXIT_B01_FW = 4, + BPMPFW_FW = 5, + BPMPFW_MTC_TBL = 6 +}; + +static void _l4t_crit_error(const char *text) +{ + gfx_con.mute = false; + gfx_printf("%kL4T Error: %s!\nFailed to launch L4T!\n%k", TXT_CLR_ERROR, text, TXT_CLR_DEFAULT); +} + +char *sd_path; +u32 sd_path_len; +static int _l4t_sd_load(u32 idx) +{ + FIL fp; + void *load_address = (void *)l4t_fw[idx].addr; + + if (idx == SC7EXIT_B01_FW) + load_address -= sizeof(u32); + + strcpy(sd_path + sd_path_len, l4t_fw[idx].name); + + if (f_open(&fp, sd_path, FA_READ) != FR_OK) + return 0; + + u32 size = f_size(&fp); + if (f_read(&fp, load_address, size, NULL) != FR_OK) + size = 0; + + f_close(&fp); + + return size; +} + +static void _l4t_sdram_lp0_save_params(bool t210b01) +{ + struct tegra_pmc_regs *pmc = (struct tegra_pmc_regs *)PMC_BASE; + +#define _REG_S(base, off) *(u32 *)((base) + (off)) +#define MC_S(off) _REG_S(MC_BASE, off) + +#define pack(src, src_bits, dst, dst_bits) { \ + u32 mask = 0xffffffff >> (31 - ((1 ? src_bits) - (0 ? src_bits))); \ + dst &= ~(mask << (0 ? dst_bits)); \ + dst |= ((src >> (0 ? src_bits)) & mask) << (0 ? dst_bits); } + +#define s(param, src_bits, pmcreg, dst_bits) \ + pack(MC_S(param), src_bits, pmc->pmcreg, dst_bits) + +// 32 bits version of s macro. +#define s32(param, pmcreg) pmc->pmcreg = MC_S(param) + + // Only save changed carveout registers into PMC for SC7 Exit. + + // VPR. + s(MC_VIDEO_PROTECT_BOM, 31:20, secure_scratch52, 26:15); + s(MC_VIDEO_PROTECT_SIZE_MB, 11:0, secure_scratch53, 11:0); + if (!t210b01) { + s(MC_VIDEO_PROTECT_REG_CTRL, 1:0, secure_scratch13, 31:30); + } else { + s(MC_VIDEO_PROTECT_REG_CTRL, 1:0, secure_scratch14, 31:30); + } + s32(MC_VIDEO_PROTECT_GPU_OVERRIDE_0, secure_scratch12); + s(MC_VIDEO_PROTECT_GPU_OVERRIDE_1, 15:0, secure_scratch49, 15:0); + + // TZD. + s(MC_SEC_CARVEOUT_BOM, 31:20, secure_scratch53, 23:12); + s(MC_SEC_CARVEOUT_SIZE_MB, 11:0, secure_scratch54, 11:0); + if (!t210b01) { + s(MC_SEC_CARVEOUT_REG_CTRL, 0:0, secure_scratch18, 30:30); + } else { + s(MC_SEC_CARVEOUT_REG_CTRL, 0:0, secure_scratch19, 29:29); + } + + // NVDEC or SECFW. + s(MC_SECURITY_CARVEOUT1_BOM, 31:17, secure_scratch50, 29:15); + s(MC_SECURITY_CARVEOUT1_SIZE_128KB, 11:0, secure_scratch57, 11:0); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0, secure_scratch59); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1, secure_scratch60); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2, secure_scratch61); + s32(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3, secure_scratch62); + if (!t210b01) + { + s(MC_SECURITY_CARVEOUT1_CFG0, 2:0, secure_scratch56, 27:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 6:3, secure_scratch41, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 13:7, secure_scratch42, 31:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 17:14, secure_scratch43, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 21:18, secure_scratch44, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 25:22, secure_scratch56, 31:28); + s(MC_SECURITY_CARVEOUT1_CFG0, 26:26, secure_scratch57, 24:24); + } + else + { + s(MC_SECURITY_CARVEOUT1_CFG0, 1:0, secure_scratch56, 31:30); + s(MC_SECURITY_CARVEOUT1_CFG0, 2:2, secure_scratch57, 24:24); + s(MC_SECURITY_CARVEOUT1_CFG0, 6:3, secure_scratch42, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 10:7, secure_scratch43, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 13:11, secure_scratch42, 31:29); + s(MC_SECURITY_CARVEOUT1_CFG0, 17:14, secure_scratch44, 28:25); + s(MC_SECURITY_CARVEOUT1_CFG0, 21:18, secure_scratch47, 25:22); + s(MC_SECURITY_CARVEOUT1_CFG0, 26:22, secure_scratch57, 29:25); + } + + // GPU FW. + s(MC_SECURITY_CARVEOUT2_BOM, 31:17, secure_scratch51, 29:15); + s(MC_SECURITY_CARVEOUT2_SIZE_128KB, 11:0, secure_scratch56, 23:12); + if (!t210b01) + { + s(MC_SECURITY_CARVEOUT2_CFG0, 2:0, secure_scratch55, 27:25); + s(MC_SECURITY_CARVEOUT2_CFG0, 6:3, secure_scratch19, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 10:7, secure_scratch20, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 13:11, secure_scratch41, 31:29); + s(MC_SECURITY_CARVEOUT2_CFG0, 17:14, secure_scratch39, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 21:18, secure_scratch40, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 25:22, secure_scratch55, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 26:26, secure_scratch56, 24:24); + } + else + { + s(MC_SECURITY_CARVEOUT2_CFG0, 1:0, secure_scratch55, 31:30); + s(MC_SECURITY_CARVEOUT2_CFG0, 2:2, secure_scratch56, 24:24); + s(MC_SECURITY_CARVEOUT2_CFG0, 6:3, secure_scratch20, 31:28); + s(MC_SECURITY_CARVEOUT2_CFG0, 10:7, secure_scratch39, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 13:11, secure_scratch41, 31:29); + s(MC_SECURITY_CARVEOUT2_CFG0, 17:14, secure_scratch40, 30:27); + s(MC_SECURITY_CARVEOUT2_CFG0, 21:18, secure_scratch41, 28:25); + s(MC_SECURITY_CARVEOUT2_CFG0, 26:22, secure_scratch56, 29:25); + } + + // GPU WPR. + s(MC_SECURITY_CARVEOUT3_BOM, 31:17, secure_scratch50, 14:0); + s(MC_SECURITY_CARVEOUT3_SIZE_128KB, 11:0, secure_scratch56, 11:0); + s32(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2, secure_scratch71); + s32(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4, secure_scratch73); + if (!t210b01) + { + s(MC_SECURITY_CARVEOUT3_CFG0, 2:0, secure_scratch57, 27:25); + s(MC_SECURITY_CARVEOUT3_CFG0, 10:3, secure_scratch47, 29:22); + s(MC_SECURITY_CARVEOUT3_CFG0, 13:11, secure_scratch43, 31:29); + s(MC_SECURITY_CARVEOUT3_CFG0, 21:14, secure_scratch48, 29:22); + s(MC_SECURITY_CARVEOUT3_CFG0, 25:22, secure_scratch57, 31:28); + s(MC_SECURITY_CARVEOUT3_CFG0, 26:26, secure_scratch58, 0:0); + } + else + { + s(MC_SECURITY_CARVEOUT3_CFG0, 1:0, secure_scratch57, 31:30); + s(MC_SECURITY_CARVEOUT3_CFG0, 2:2, secure_scratch58, 0:0); + s(MC_SECURITY_CARVEOUT3_CFG0, 6:3, secure_scratch47, 29:26); + s(MC_SECURITY_CARVEOUT3_CFG0, 10:7, secure_scratch48, 25:22); + s(MC_SECURITY_CARVEOUT3_CFG0, 13:11, secure_scratch43, 31:29); + s(MC_SECURITY_CARVEOUT3_CFG0, 17:14, secure_scratch48, 29:26); + s(MC_SECURITY_CARVEOUT3_CFG0, 21:18, secure_scratch52, 30:27); + s(MC_SECURITY_CARVEOUT3_CFG0, 26:22, secure_scratch58, 5:1); + } + + // TSECA. + s(MC_SECURITY_CARVEOUT4_BOM, 31:17, secure_scratch51, 14:0); + s(MC_SECURITY_CARVEOUT4_SIZE_128KB, 11:0, secure_scratch55, 23:12); + s(MC_SECURITY_CARVEOUT4_CFG0, 26:0, secure_scratch39, 26:0); + + // TSECB. + s(MC_SECURITY_CARVEOUT5_BOM, 31:17, secure_scratch52, 14:0); + s(MC_SECURITY_CARVEOUT5_SIZE_128KB, 11:0, secure_scratch57, 23:12); + s(MC_SECURITY_CARVEOUT5_CFG0, 26:0, secure_scratch40, 26:0); +} + +static void _l4t_mc_config_carveout(bool t210b01) +{ + // Disabled VPR carveout. DT decides if enabled or not. + MC(MC_VIDEO_PROTECT_BOM) = 0xFFF00000; + MC(MC_VIDEO_PROTECT_SIZE_MB) = 0; + if (!t210b01) + { + // For T210 force the following values for Falcon to configure WPR access. + // For T210B01 use default, already set from dram config. + // HOS forces 1 and 0. + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_0) = 0x2A800000; + MC(MC_VIDEO_PROTECT_GPU_OVERRIDE_1) = 2; + } + MC(MC_VIDEO_PROTECT_REG_CTRL) = VPR_CTRL_TZ_SECURE | VPR_CTRL_LOCKED; + + // Temporarily disable TZDRAM carveout. For launching coldboot TZ. + MC(MC_SEC_CARVEOUT_BOM) = 0xFFF00000; + MC(MC_SEC_CARVEOUT_SIZE_MB) = 0; + MC(MC_SEC_CARVEOUT_REG_CTRL) = 0; + + // Disable MTS carveout. Only CCPLEX has access. + MC(MC_SEC_CARVEOUT_BOM) = 0xFFF00000; + MC(MC_SEC_CARVEOUT_SIZE_MB) = 0; + MC(MC_SEC_CARVEOUT_REG_CTRL) = 0; + + // Print real one, not temp disabled. + UPRINTF("TZD: TZDRAM Carveout: %08X - %08X\n", TZDRAM_BASE, TZDRAM_BASE - 1 + TZDRAM_SIZE); + + // Configure generalized security carveouts. + u32 carveout_base = TZDRAM_BASE - SZ_1M; // Always leave space for Secure Firmware. + +#if CARVEOUT_NVDEC_TSEC_ENABLE + + // Set NVDEC keyslot sticky bits. + clock_enable_nvdec(); + clock_enable_nvjpg(); + NVDEC(NVDEC_SA_KEYSLOT_GLOBAL_RW) = 0xFFFF; // Read disable. + NVDEC(NVDEC_SA_KEYSLOT_TZ) = 0xFFFFFFFF; // TZ enable. + NVDEC(NVDEC_SA_KEYSLOT_FALCON) = 0; // Falcon disable. + NVDEC(NVDEC_SA_KEYSLOT_OTF) = 0; // OTF disable. + NVDEC(NVDEC_VPR_ALL_OTF_GOTO_VPR) = 1; // Enable. + clock_disable_nvjpg(); + clock_disable_nvdec(); + + // Set NVDEC carveout. Only for NVDEC bl/prod. + carveout_base -= ALIGN(CARVEOUT_NVDEC_SIZE, SZ_1M); + MC(MC_SECURITY_CARVEOUT1_BOM) = carveout_base; + MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = CARVEOUT_NVDEC_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC | SEC_CARVEOUT_CA2_W_TSEC; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = SEC_CARVEOUT_CA3_R_NVDEC | SEC_CARVEOUT_CA3_W_NVDEC; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_SEC | + SEC_CARVEOUT_CFG_RD_FALCON_LS | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(1) | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; + UPRINTF("GSC1: NVDEC Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT1_BOM), MC(MC_SECURITY_CARVEOUT1_BOM) + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) * SZ_128K); + +#elif CARVEOUT_SECFW_ENABLE + + // Set SC7-Entry/SC7-Exit/R2P/MTC Table or SC7-Exit/BPMP-FW carveout. Only BPMP, CCPLEX and AHB have R/W access. + MC(MC_SECURITY_CARVEOUT1_BOM) = carveout_base; + MC(MC_SECURITY_CARVEOUT1_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) = CARVEOUT_SECFW_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0) = SEC_CARVEOUT_CA0_R_BPMP_C | + SEC_CARVEOUT_CA0_R_PPCSAHBSLV; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1) = SEC_CARVEOUT_CA1_W_BPMP_C | + SEC_CARVEOUT_CA1_R_CCPLEX_C | + SEC_CARVEOUT_CA1_R_CCPLEXLP_C | + SEC_CARVEOUT_CA1_W_CCPLEX_C | + SEC_CARVEOUT_CA1_W_CCPLEXLP_C | + SEC_CARVEOUT_CA1_W_PPCSAHBSLV; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT1_CFG0) = SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_WR_NS | + SEC_CARVEOUT_CFG_LOCKED; + UPRINTF("GSC1: SECFW Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT1_BOM), MC(MC_SECURITY_CARVEOUT1_BOM) + MC(MC_SECURITY_CARVEOUT1_SIZE_128KB) * SZ_128K); + +#endif + + // Set GPU FW WPR carveout. Same value is used for GPU WPR carveout calculation if not full TOS. + carveout_base -= ALIGN(CARVEOUT_GPUFW_SIZE, SZ_1M); + + // Sanitize it and enable GSC3 for ACR. + memset((void *)carveout_base, 0, CARVEOUT_GPUFW_SIZE); + *(u32 *)(carveout_base + CARVEOUT_GPUFW_SIZE - sizeof(u32)) = ACR_GSC3_ENABLE_MAGIC; + + tsec_init_t *tsec_init = (tsec_init_t *)(carveout_base + CARVEOUT_GPUFW_SIZE - FALCON_DMA_PAGE_SIZE); + + // Set TSEC init info. + tsec_init->sku = SKU_NX; + tsec_init->hdcp = HDCP22; + tsec_init->soc = t210b01 ? SOC_ID_T210B01 : SOC_ID_T210; + + // Flush data to ram. + bpmp_mmu_maintenance(BPMP_MMU_MAINT_INVALID_WAY, false); + + // Set carveout config. + MC(MC_SECURITY_CARVEOUT2_BOM) = carveout_base; + MC(MC_SECURITY_CARVEOUT2_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) = CARVEOUT_GPUFW_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU | SEC_CARVEOUT_CA2_R_TSEC; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT2_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT2_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_RD_SEC | + SEC_CARVEOUT_CFG_RD_FALCON_LS | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_LS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(2) | + SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; // SEC_CARVEOUT_CFG_IS_WPR is set from GPU. + UPRINTF("GSC2: GPUFW Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT2_BOM), MC(MC_SECURITY_CARVEOUT2_BOM) + MC(MC_SECURITY_CARVEOUT2_SIZE_128KB) * SZ_128K); + + // Set GPU WPR carveout. +#if CARVEOUT_NVDEC_TSEC_ENABLE + carveout_base -= ALIGN(CARVEOUT_GPUWPR_SIZE, SZ_1M); + MC(MC_SECURITY_CARVEOUT3_BOM) = carveout_base; +#else + MC(MC_SECURITY_CARVEOUT3_BOM) = carveout_base + CARVEOUT_GPUFW_SIZE; +#endif + MC(MC_SECURITY_CARVEOUT3_BOM_HI) = 0x0; + MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) = CARVEOUT_GPUWPR_SIZE / SZ_128K; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2) = 0; // HOS: SEC_CARVEOUT_CA2_R_GPU | SEC_CARVEOUT_CA2_W_GPU + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4) = 0; // HOS: SEC_CARVEOUT_CA4_R_GPU2 | SEC_CARVEOUT_CA4_W_GPU2 + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT3_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_UNTRANSLATED_ONLY | + SEC_CARVEOUT_CFG_RD_NS | + SEC_CARVEOUT_CFG_RD_SEC | + SEC_CARVEOUT_CFG_RD_FALCON_LS | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_LS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(3) | + SEC_CARVEOUT_CFG_SEND_CFG_TO_GPU | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; // SEC_CARVEOUT_CFG_IS_WPR is set from GPU. + UPRINTF("GSC3: GPUW2 Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT3_BOM), MC(MC_SECURITY_CARVEOUT3_BOM) + MC(MC_SECURITY_CARVEOUT3_SIZE_128KB) * SZ_128K); + + /* + * Set TSECA/B carveout. Only for NVDEC bl/prod and TSEC. + * + * Otherwise disabled. + * + * With HOS SC7-Exit fw, it gets set to disallow RAM access for BPMP. But TZ can change it. + * We lock the carveout and save it in restore scratch registers so SC7-Exit can't touch it. + */ + carveout_base -= CARVEOUT_NVDEC_TSEC_ENABLE ? ALIGN(CARVEOUT_TSEC_SIZE, SZ_1M) : 0; + MC(MC_SECURITY_CARVEOUT4_BOM) = CARVEOUT_NVDEC_TSEC_ENABLE ? carveout_base : 0; + MC(MC_SECURITY_CARVEOUT4_BOM_HI) = 0x0; + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) = CARVEOUT_NVDEC_TSEC_ENABLE ? CARVEOUT_TSEC_SIZE / SZ_128K : 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC | SEC_CARVEOUT_CA2_W_TSEC; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4) = SEC_CARVEOUT_CA4_R_TSECB | SEC_CARVEOUT_CA4_W_TSECB; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT4_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(4) | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; + + UPRINTF("GSC4: TSEC1 Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT4_BOM), MC(MC_SECURITY_CARVEOUT4_BOM) + MC(MC_SECURITY_CARVEOUT4_SIZE_128KB) * SZ_128K); + + // Set TSECA carveout. Only for NVDEC bl/prod and TSEC. Otherwise disabled. + carveout_base -= CARVEOUT_NVDEC_TSEC_ENABLE ? ALIGN(CARVEOUT_TSEC_SIZE, SZ_1M) : 0; + MC(MC_SECURITY_CARVEOUT5_BOM) = CARVEOUT_NVDEC_TSEC_ENABLE ? carveout_base : 0; + MC(MC_SECURITY_CARVEOUT5_BOM_HI) = 0; + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) = CARVEOUT_NVDEC_TSEC_ENABLE ? CARVEOUT_TSEC_SIZE / SZ_128K : 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2) = SEC_CARVEOUT_CA2_R_TSEC | SEC_CARVEOUT_CA2_W_TSEC; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3) = 0; + MC(MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4) = 0; + MC(MC_SECURITY_CARVEOUT5_CFG0) = SEC_CARVEOUT_CFG_LOCKED | + SEC_CARVEOUT_CFG_RD_FALCON_HS | + SEC_CARVEOUT_CFG_WR_FALCON_HS | + SEC_CARVEOUT_CFG_APERTURE_ID(5) | + SEC_CARVEOUT_CFG_FORCE_APERTURE_ID_MATCH; + UPRINTF("GSC5: TSEC2 Carveout: %08X - %08X\n", + MC(MC_SECURITY_CARVEOUT5_BOM), MC(MC_SECURITY_CARVEOUT5_BOM) + MC(MC_SECURITY_CARVEOUT5_SIZE_128KB) * SZ_128K); + + UPRINTF("DRAM Bank 0 TOP: %08X\n", carveout_base); + + // Save carveouts to lp0 pmc registers. + _l4t_sdram_lp0_save_params(t210b01); +} + +static void _l4t_late_hw_config(bool t210b01) +{ + // Turn on PLLC to default OUT0 frequency to mitigate kernel broken init. + clock_enable_pllc(53); // VCO/OUT0: 508.8 MHz. (VCO is half.) + + // Reset System Counters. + for (u32 i = 0; i < SYSCTR0_COUNTERS; i += sizeof(u32)) + SYSCTR0(SYSCTR0_COUNTERS_BASE + i) = 0; + + /* + * PMIC config scratch register + * + * bit00: active cluster slow + * bit01: Set: max77621/max77812. Unset: OVR/OVR2. + * bit02-07: unused + * bit08-15: pmic cpu i2c address + * bit16:23: pmic cpu i2c en reg + * bit24:31: pmic cpu i2c en val + */ + PMC(APBDEV_PMC_SCRATCH201) = BIT(1); + + // Clear PLLM override for SC7. + PMC(APBDEV_PMC_PLLP_WB0_OVERRIDE) &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE_ENABLE; + + // Set spare reg to 0xE0000 and clear everything else. + if (t210b01 && (SYSREG(AHB_AHB_SPARE_REG) & 0xE0000000) != 0xE0000000) + SYSREG(AHB_AHB_SPARE_REG) = 0xE0000 << 12; + + // HDA loopback disable on prod. + PMC(APBDEV_PMC_STICKY_BITS) = PMC_STICKY_BITS_HDA_LPBK_DIS; + + // Clear any MC error. + MC(MC_INTSTATUS) = MC(MC_INTSTATUS); + + +#if LOCK_PMC_REGISTERS + // Lock LP0 parameters and misc secure registers. Always happens on warmboot. + #if CARVEOUT_NVDEC_TSEC_ENABLE + pmc_scratch_lock(PMC_SEC_LOCK_CARVEOUTS_L4T | PMC_SEC_LOCK_SE_SRK); + #else + pmc_scratch_lock(PMC_SEC_LOCK_LP0_PARAMS | PMC_SEC_LOCK_MISC | PMC_SEC_LOCK_SE_SRK); + #endif + + // Lock SE2 SRK and misc secure regs. Also lock writes on normal LP0 scratch regs. + if (t210b01) + pmc_scratch_lock(PMC_SEC_LOCK_MISC_B01 | PMC_SEC_LOCK_SE2_SRK_B01 | PMC_SEC_LOCK_LP0_PARAMS_B01); +#endif +} + +static void _l4t_bpmpfw_config(l4t_ctxt_t *ctxt) +{ + char *ram_oc_txt = ctxt->ram_oc_txt; + u32 ram_oc_freq = ctxt->ram_oc_freq; + u32 ram_oc_divn = 0; + + // Set default parameters. + *(u32 *)BPMPFW_DTB_ADDR = 0; + *(u8 *)BPMPFW_CC_INIT_OP = OP_TRAIN; + *(u32 *)BPMPFW_CC_PT_TIME = 100; + +#if DEBUG_LOG_BPMPFW + // Set default debug parameters. + *(u32 *)BPMPFW_LOGLEVEL = 3; + *(u32 *)BPMPFW_CC_DEBUG = 0x50000101; + + // Set serial debug port. + if (*(u32 *)BPMPFW_ADTB_BASE == DTB_MAGIC) + BPMPFW_DTB_SET_SERIAL_PORT(ctxt->serial_port); +#endif + + // Set and copy MTC tables. + u32 mtc_idx = mtc_table_idx_t210b01[fuse_read_dramid(true)]; + for (u32 i = 0; i < 3; i++) + memcpy(BPMPFW_DTB_EMC_TBL_OFFSET(i), BPMPFW_MTC_TABLE_OFFSET(mtc_idx, i), BPMPFW_MTC_FREQ_TABLE_SIZE); + + if (ram_oc_freq > DRAM_TBL_PROVIDED_MAX_FREQ) + { + // Final table. + const u32 tbl_idx = BPMPFW_DTB_EMC_ENTRIES - 1; + + // Set Overclock. + for (u32 i = 0; i < ARRAY_SIZE(ram_jd_t210b01); i++) + { + // Normalize the check at 38.4 MHz window. + if ((ram_jd_t210b01[i] - 19200) < ram_oc_freq && + (ram_jd_t210b01[i] + 19200) > ram_oc_freq) + { + // Set actual frequency and divider. + ram_oc_freq = ram_jd_t210b01[i]; + ram_oc_divn = i + 1; + + break; + } + } + + if (!ram_oc_divn) + { + ram_oc_divn = ram_oc_freq / 38400; + ram_oc_freq = ram_oc_divn * 38400; + } + + // Copy table and set parameters. + memcpy(BPMPFW_DTB_EMC_TBL_OFFSET(tbl_idx), BPMPFW_MTC_TABLE_OFFSET(mtc_idx, 2), BPMPFW_MTC_FREQ_TABLE_SIZE); + + BPMPFW_DTB_EMC_TBL_SET_NAME(tbl_idx, ram_oc_txt); + BPMPFW_DTB_EMC_TBL_SET_FREQ(tbl_idx, ram_oc_freq); + + pll_spread_spectrum_t210b01_t *ssc = BPMPFW_DTB_EMC_TBL_SCC_OFFSET(tbl_idx); + + if (ram_oc_divn < DRAM_T210B01_SSC_PARAMS) + { + // Standard frequency. + const pll_ssc_t210b01_t *ssc_cfg = &pll_jd_ssc_t210b01[ram_oc_divn - 1]; + + ssc->ss_ctrl1 = ssc_cfg->ss_ctrl1; + ssc->ss_ctrl2 = ssc_cfg->ss_ctrl2; + ssc->ss2_ctrl1 = ssc_cfg->ss_ctrl1; + ssc->ss2_ctrl2 = ssc_cfg->ss_ctrl2; + ssc->divn = ssc_cfg->divn; + } + else + { + // Non standard frequency. + ssc->divn = ram_oc_divn; + } + + // Enable table. + BPMPFW_DTB_EMC_TBL_ENABLE(tbl_idx); + + UPRINTF("RAM Frequency set to: %d KHz. Voltage: %d mV\n", ram_oc_freq, ram_oc_volt); + } + + // Save BPMP-FW entrypoint for TZ. + PMC(APBDEV_PMC_SCRATCH39) = BPMPFW_ENTRYPOINT; + PMC(APBDEV_PMC_SCRATCH_WRITE_DISABLE1) |= BIT(15); +} + +static int _l4t_sc7_exit_config(bool t210b01) +{ + if (!t210b01) + { + // Apply Nintendo Switch (2017) RSA modulus to SC7-Exit firmware. + emmc_initialize(false); + pkg1_warmboot_rsa_mod(SC7EXIT_BASE); + emmc_end(); + + // Set SC7-Exit firmware address for bootrom to find. + PMC(APBDEV_PMC_SCRATCH1) = SC7EXIT_BASE; + } + else + { + launch_ctxt_t hos_ctxt = {0}; + u32 fw_fuses = *(u32 *)(SC7EXIT_B01_BASE - sizeof(u32)); // Fuses count in front of actual firmware. + + // Get latest SC7-Exit if needed and setup PA id. + if (!pkg1_warmboot_config(&hos_ctxt, 0, fw_fuses, 0)) + { + gfx_con.mute = false; + gfx_wputs("\nFailed to match warmboot with fuses!\nIf you continue, sleep wont work!"); + + gfx_puts("\nPress POWER to continue.\nPress VOL to go to the menu.\n"); + + if (!(btn_wait() & BTN_POWER)) + return 0; + } + + // Copy loaded warmboot fw to address if from storage. + if (hos_ctxt.warmboot) + memcpy((void *)SC7EXIT_B01_BASE, hos_ctxt.warmboot, hos_ctxt.warmboot_size); + + // Set SC7-Exit firmware address for bootrom to find. + PMC(APBDEV_PMC_SECURE_SCRATCH119) = SC7EXIT_B01_BASE; + PMC(APBDEV_PMC_SEC_DISABLE8) |= BIT(30); + } + + return 1; +} + +static void _l4t_bl33_cfg_set_key(char *env, char *key, char *val) +{ + strcat(env, key); + strcat(env, "="); + strcat(env, val); + strcat(env, "\n"); +} + +static void _l4t_set_config(l4t_ctxt_t *ctxt, const ini_sec_t *ini_sec, int entry_idx, int is_list) +{ + char *bl33_env = (char *)BL33_ENV_BASE; + bl33_env[0] = '\0'; + char val[4] = {0}; + + // Parse ini section and prepare BL33 env. + LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) + { + if (!strcmp("boot_prefixes", kv->key)) + ctxt->path = kv->val; + else if (!strcmp("ram_oc", kv->key)) + { + ctxt->ram_oc_txt = kv->val; + ctxt->ram_oc_freq = atoi(kv->val); + } + else if (!strcmp("uart_port", kv->key)) + ctxt->serial_port = atoi(kv->val); + + // Set key/val to BL33 env. + _l4t_bl33_cfg_set_key(bl33_env, kv->key, kv->val); + } + +#ifdef DEBUG_UART_PORT + // Override port if bootloader UART debug is enabled. + ctxt->serial_port = DEBUG_UART_PORT + 1; +#endif + + // Set r2p parameters. + if (entry_idx >= 10) + { + val[0] = '1'; + val[1] = '0' + (entry_idx % 10); + } + else + val[0] = '0' + entry_idx; + _l4t_bl33_cfg_set_key(bl33_env, "autoboot", val); + + val[0] = '0' + is_list; + _l4t_bl33_cfg_set_key(bl33_env, "autoboot_list", val); + + // Enable BL33 memory env import. + *(u32 *)(BL33_ENV_MAGIC_OFFSET) = BL33_ENV_MAGIC; + + // Set boot path. + sd_path = (char *)malloc(512); + sd_path_len = strlen(ctxt->path); + strcpy(sd_path, ctxt->path); +} + +void launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01) +{ + l4t_ctxt_t ctxt = {0}; + bl_v1_params_t bl_v1_params = {0}; + plat_params_from_bl2_t plat_params = {0}; + entry_point_info_t bl33_ep_info = {0}; + + gfx_con_setpos(0, 0); + + // Parse config. + _l4t_set_config(&ctxt, ini_sec, entry_idx, is_list); + + if (!ctxt.path) + { + _l4t_crit_error("Path missing"); + return; + } + + // Get MTC table. + ctxt.mtc_table = minerva_get_mtc_table(); + if (!t210b01 && !ctxt.mtc_table) + { + _l4t_crit_error("Minerva missing"); + return; + } + + // U-BOOT does not support exfat. + if (sd_fs.fs_type == FS_EXFAT) + { + _l4t_crit_error("exFAT not supported"); + return; + } + + // Load BL31 (ATF/TrustZone fw). + if (!_l4t_sd_load(BL31_FW)) + { + _l4t_crit_error("BL31 missing"); + return; + } + + // Load BL33 (U-BOOT/CBOOT). + if (!_l4t_sd_load(BL33_FW)) + { + _l4t_crit_error("BL33 missing"); + return; + } + + // Set firmware path. + strcpy(sd_path, "bootloader/sys/l4t/"); + sd_path_len = strlen(sd_path); + + if (!t210b01) + { + // Load SC7-Entry firmware. + ctxt.sc7entry_size = _l4t_sd_load(SC7ENTRY_FW); + if (!ctxt.sc7entry_size) + { + _l4t_crit_error("SC7-Entry missing"); + return; + } + } + else + { + // Load BPMP-FW. Manages SC7-Entry also. + if (!_l4t_sd_load(BPMPFW_FW)) + { + _l4t_crit_error("BPMP-FW missing"); + return; + } + + // Load BPMP-FW MTC table. + if (!_l4t_sd_load(BPMPFW_MTC_TBL)) + { + _l4t_crit_error("BPMP-FW MTC missing"); + return; + } + } + + // Load SC7-Exit firmware. + if (!_l4t_sd_load(!t210b01 ? SC7EXIT_FW : SC7EXIT_B01_FW)) + { + _l4t_crit_error("SC7-Exit missing"); + return; + } + + // Set SC7-Exit firmware address to PMC for bootrom and do further setup. + if (!_l4t_sc7_exit_config(t210b01)) + return; + + // Done loading bootloaders/firmware. + sd_end(); + + // Enable debug port. + if (ctxt.serial_port) + { + pinmux_config_uart(ctxt.serial_port - 1); + clock_enable_uart(ctxt.serial_port - 1); + } + + // Restore UARTB/C TX pins to SPIO. + gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO); + gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO); + + // Configure BL33 parameters. + if (*(u32 *)BL33_DTB_BASE == DTB_MAGIC) + { + // Defaults are for UARTA. + char *bl33_serial_port = NULL; + switch (ctxt.serial_port) + { + case 0: // Disable. + break; + case 1: // UARTA. + bl33_serial_port = "70006000"; + break; + case 2: // UARTB. + bl33_serial_port = "70006040"; + break; + case 3: // UARTC. + bl33_serial_port = "70006200"; + break; + } + + if (bl33_serial_port) + { + BL33_DTB_SET_STDOUT_PATH(bl33_serial_port); + BL33_DTB_SET_STDERR_PATH(bl33_serial_port); + BL33_DTB_SET_UART_STATUS(ctxt.serial_port); + } + } + + // Set BL31 params. + bl_v1_params.hdr.type = PARAM_BL31; + bl_v1_params.hdr.version = VERSION_1; + bl_v1_params.hdr.size = sizeof(bl_v1_params_t); + bl_v1_params.hdr.attr = PARAM_EP_SECURE; + bl_v1_params.bl33_ep_info = (u64)(u32)&bl33_ep_info; + + // Set BL33 params. + bl33_ep_info.hdr.type = PARAM_EP; + bl33_ep_info.hdr.version = VERSION_1; + bl33_ep_info.hdr.size = sizeof(entry_point_info_t); + bl33_ep_info.hdr.attr = PARAM_EP_NON_SECURE; + bl33_ep_info.pc = BL33_LOAD_BASE; + bl33_ep_info.spsr = SPSR_EL2T; + + // Set Platform parameters. + plat_params.tzdram_base = TZDRAM_BASE; + plat_params.tzdram_size = TZDRAM_SIZE; +#if DEBUG_LOG_ATF + plat_params.uart_id = ctxt.serial_port; +#endif + + if (!t210b01) + { + // Set SC7-Entry fw parameters. For now BPMP-FW is not used on T210. + plat_params.sc7entry_fw_base = SC7ENTRY_HDR_BASE; + plat_params.sc7entry_fw_size = ALIGN(ctxt.sc7entry_size + SC7ENTRY_HDR_SIZE, SZ_PAGE); + } + + // Enable below features. + plat_params.enable_extra_features = BL31_EXTRA_FEATURES_ENABLE; + + if (!t210b01) + { + // Set R2P payload. + reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + 0x7C); + memcpy((u8 *)R2P_PAYLOAD_BASE, (u8 *)reloc->start, reloc->end - reloc->start); + memset((u8 *)R2P_PAYLOAD_BASE + 0x94, 0, sizeof(boot_cfg_t)); // Clear Boot Config Storage. + + // Set R2P payload fw parameters. + plat_params.r2p_payload_base = R2P_PAYLOAD_BASE; + plat_params.r2p_payload_size = ALIGN(reloc->end - reloc->start, SZ_PAGE); + } + + // Set PMC access security. NS is mandatory for T210B01. + plat_params.flags = FLAGS_PMC_NON_SECURE; // Unsecure it unconditionally to reduce SMC calls to a minimum. + // Lift SC7 placement restrictions. Disables TZDRAM increased carveout too. + plat_params.flags |= FLAGS_SC7_NO_BASE_RESTRICTION; + + // Prepare EMC table. + if (ctxt.mtc_table) + { + int table_entries = minerva_get_mtc_table_entries(); + + // Set DRAM voltage. + if (ctxt.ram_oc_freq > DRAM_T210_OC_THRESHOLD_FREQ) + max7762x_regulator_set_voltage(REGULATOR_SD1, DRAM_T210_OC_VOLTAGE); + + // Train the rest of the table, apply FSP WAR, set RAM to 800 MHz. + minerva_prep_boot_l4t(ctxt.ram_oc_freq); + + // Set emc table parameters and copy it. + plat_params.emc_table_base = MTCTABLE_BASE; + plat_params.emc_table_size = sizeof(emc_table_t) * table_entries; + memcpy((u32 *)MTCTABLE_BASE, ctxt.mtc_table, sizeof(emc_table_t) * table_entries); + } + + // Set and enable IRAM based BL31 config. + PMC(APBDEV_PMC_SECURE_SCRATCH112) = PMC(APBDEV_PMC_SECURE_SCRATCH108); + PMC(APBDEV_PMC_SECURE_SCRATCH114) = PMC(APBDEV_PMC_SECURE_SCRATCH109); + PMC(APBDEV_PMC_SECURE_SCRATCH108) = (u32)&bl_v1_params; + PMC(APBDEV_PMC_SECURE_SCRATCH109) = (u32)&plat_params; + PMC(APBDEV_PMC_SECURE_SCRATCH110) = BL31_IRAM_PARAMS; + + // Set panel model. + PMC(APBDEV_PMC_SECURE_SCRATCH113) = display_get_decoded_panel_id(); + + // Set charging limit parameters. + if (fuse_read_hw_type() == FUSE_NX_HW_TYPE_HOAG) + { + int in_volt_lim = 0; + bq24193_get_property(BQ24193_ChargeVoltageLimit, &in_volt_lim); + + PMC(APBDEV_PMC_SECURE_SCRATCH113) |= in_volt_lim << 16; + } + + // Disable writes to above registers. + PMC(APBDEV_PMC_SEC_DISABLE8) |= BIT(18) | BIT(16) | BIT(12) | BIT(10) | BIT(8); + + // Set BPMP-FW parameters. + if (t210b01) + _l4t_bpmpfw_config(&ctxt); + + // Set carveouts and save them to PMC for SC7 Exit. + _l4t_mc_config_carveout(t210b01); + + // Deinit any unneeded HW. + hw_reinit_workaround(false, BL_MAGIC_L4TLDR_SLD); + + // Do late hardware config. + _l4t_late_hw_config(t210b01); + + // Launch BL31. + ccplex_boot_cpu0(TZDRAM_COLD_ENTRY); + + // Enable Wrap burst for BPMP, GPU and PCIE. + MSELECT(MSELECT_CONFIG) = (MSELECT(MSELECT_CONFIG) & (~(MSELECT_CFG_ERR_RESP_EN_GPU | MSELECT_CFG_ERR_RESP_EN_PCIE))) | + (MSELECT_CFG_WRAP_TO_INCR_GPU | MSELECT_CFG_WRAP_TO_INCR_PCIE | MSELECT_CFG_WRAP_TO_INCR_BPMP); + + // If T210B01 run BPMP-FW. + if (t210b01) + { + // Prep reset vector for SC7 save state and start BPMP-FW. + EXCP_VEC(EVP_COP_RESET_VECTOR) = BPMPFW_ENTRYPOINT; + void (*bpmp_fw_ptr)() = (void *)BPMPFW_ENTRYPOINT; + (*bpmp_fw_ptr)(); + } + + // Halt BPMP. + while (true) + bpmp_halt(); +} + +// t210 t210b01 hoag/aula +// pp1 b0000001 b0000001 b0000001 pcie_port1_lane_map +// pp0 b0010000 b0001000 b0000000 -- pcie_port0_lane_map +// pci b0011111 b0001101 b0001101 - pcie_lane_map +// usb b1100000 b0110010 b0110010 - usb_lane_map +// rpd b0000011 b0000011 b0000011 root_port_mask_dev +// rpp b0000010 b0000010 b0000010 root_port_mask_prod diff --git a/bootloader/l4t/l4t.h b/bootloader/l4t/l4t.h new file mode 100644 index 0000000..9e02ea6 --- /dev/null +++ b/bootloader/l4t/l4t.h @@ -0,0 +1,24 @@ +/* + * L4T Loader for Tegra X1 + * + * Copyright (c) 2020-2022 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _L4T_H_ +#define _L4T_H_ + +void launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b01); + +#endif diff --git a/bootloader/l4t/l4t_config.inl b/bootloader/l4t/l4t_config.inl new file mode 100644 index 0000000..0810f13 --- /dev/null +++ b/bootloader/l4t/l4t_config.inl @@ -0,0 +1,36 @@ +/* + * L4T Loader for Tegra X1 + * + * Copyright (c) 2020-2022 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// Set to 1 to enable early boot debugging. +#define DEBUG_LOG_ATF 0 +#define DEBUG_LOG_BPMPFW 0 // Do not enable if UART setup is hindered during early boot. + +// Set to 1 to lock PMC registers that contain LP0 parameters. +#define LOCK_PMC_REGISTERS 0 + +// Configurable carveout enable config. Only one can be enabled at a time. +#define CARVEOUT_NVDEC_TSEC_ENABLE 0 // Enable for NVDEC bl/prod and full TOS/DRM. +#define CARVEOUT_SECFW_ENABLE 1 // SECFW is always allocated even if carveout is disabled. + +/* + * WPR Carveout size config. + * + * L4T: 2MB or 13MB. On non SecureOS env, only 0x100 bytes are used, probably also on full TOS. + * On 4GB+ systems, it's normally placed at BANK1_TOP - SIZE; + */ +#define CARVEOUT_GPUWPR_SIZE_CFG (SZ_8M + SZ_4M + SZ_1M) // Mandatory when CARVEOUT_NVDEC_TSEC_ENABLE is 1. diff --git a/bootloader/main.c b/bootloader/main.c index c5b8849..3409758 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -26,6 +26,7 @@ #include "gfx/tui.h" #include "hos/hos.h" #include "hos/secmon_exo.h" +#include "l4t/l4t.h" #include #include #include @@ -458,6 +459,19 @@ parse_failed: // Try to launch Payload or L4T. if (special_path != (char *)-1) _launch_payload(special_path, false, true); + else + { + u32 entry_idx = 0; + for (u32 i = 0; i < sec_idx; i++) + { + if (ments[i].data == cfg_sec) + { + entry_idx = i; + break; + } + } + launch_l4t(cfg_sec, entry_idx, 1, h_cfg.t210b01); + } } else if (!hos_launch(cfg_sec)) { @@ -590,6 +604,19 @@ parse_failed: // Try to launch Payload or L4T. if (special_path != (char *)-1) _launch_payload(special_path, false, true); + else + { + u32 entry_idx = 0; + for (u32 i = 0; i < sec_idx; i++) + { + if (ments[i].data == cfg_sec) + { + entry_idx = i; + break; + } + } + launch_l4t(cfg_sec, entry_idx, 0, h_cfg.t210b01); + } } else if (!hos_launch(cfg_sec)) { @@ -904,7 +931,8 @@ skip_list: // Check if entry is payload or l4t special case. char *special_path = ini_check_special_section(cfg_sec); - if (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && h_cfg.bootwait) + if ((!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && h_cfg.bootwait) || // Conditional for HOS/Payload. + (special_path && special_path == (char *)-1)) // Always show for L4T. { u32 fsize; u8 *logo_buf = NULL; @@ -987,6 +1015,8 @@ skip_list: // Try to launch Payload or L4T. if (special_path != (char *)-1) _launch_payload(special_path, false, false); + else + launch_l4t(cfg_sec, h_cfg.autoboot, h_cfg.autoboot_list, h_cfg.t210b01); goto error; } else