/******************************************************************************* * This function is responsible for handling all SiP calls from the NS world ******************************************************************************/ uint64_t tegra_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { uint32_t ns; int err; /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); if (!ns) SMC_RET1(handle, SMC_UNK); switch (smc_fid) { case TEGRA_SIP_NEW_VIDEOMEM_REGION: /* * Check if Video Memory overlaps TZDRAM (contains bl31/bl32) * or falls outside of the valid DRAM range */ err = bl31_check_ns_address(x1, x2); if (err) SMC_RET1(handle, err); /* * Check if Video Memory is aligned to 1MB. */ if ((x1 & 0xFFFFF) || (x2 & 0xFFFFF)) { ERROR("Unaligned Video Memory base address!\n"); SMC_RET1(handle, -ENOTSUP); } /* new video memory carveout settings */ tegra_memctrl_videomem_setup(x1, x2); SMC_RET1(handle, 0); default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; } SMC_RET1(handle, SMC_UNK); }
/******************************************************************************* * This function is responsible for handling all SiP calls ******************************************************************************/ uint64_t tegra_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { uint32_t regval; int err; /* Check if this is a SoC specific SiP */ err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); if (err == 0) SMC_RET1(handle, (uint64_t)err); switch (smc_fid) { case TEGRA_SIP_NEW_VIDEOMEM_REGION: /* clean up the high bits */ x2 = (uint32_t)x2; /* * Check if Video Memory overlaps TZDRAM (contains bl31/bl32) * or falls outside of the valid DRAM range */ err = bl31_check_ns_address(x1, x2); if (err) SMC_RET1(handle, err); /* * Check if Video Memory is aligned to 1MB. */ if ((x1 & 0xFFFFF) || (x2 & 0xFFFFF)) { ERROR("Unaligned Video Memory base address!\n"); SMC_RET1(handle, -ENOTSUP); } /* * The GPU is the user of the Video Memory region. In order to * transition to the new memory region smoothly, we program the * new base/size ONLY if the GPU is in reset mode. */ regval = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET); if ((regval & GPU_RESET_BIT) == 0U) { ERROR("GPU not in reset! Video Memory setup failed\n"); SMC_RET1(handle, -ENOTSUP); } /* new video memory carveout settings */ tegra_memctrl_videomem_setup(x1, x2); SMC_RET1(handle, 0); break; /* * The NS world registers the address of its handler to be * used for processing the FIQ. This is normally used by the * NS FIQ debugger driver to detect system hangs by programming * a watchdog timer to fire a FIQ interrupt. */ case TEGRA_SIP_FIQ_NS_ENTRYPOINT: if (!x1) SMC_RET1(handle, SMC_UNK); /* * TODO: Check if x1 contains a valid DRAM address */ /* store the NS world's entrypoint */ tegra_fiq_set_ns_entrypoint(x1); SMC_RET1(handle, 0); break; /* * The NS world's FIQ handler issues this SMC to get the NS EL1/EL0 * CPU context when the FIQ interrupt was triggered. This allows the * NS world to understand the CPU state when the watchdog interrupt * triggered. */ case TEGRA_SIP_FIQ_NS_GET_CONTEXT: /* retrieve context registers when FIQ triggered */ tegra_fiq_get_intr_context(); SMC_RET0(handle); break; case TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND: /* * System suspend fake mode is set if we are on VDK and we make * a debug SIP call. This mode ensures that we excercise debug * path instead of the regular code path to suit the pre-silicon * platform needs. These include replacing the call to WFI by * a warm reset request. */ if (tegra_platform_is_emulation() != 0U) { tegra_fake_system_suspend = 1; SMC_RET1(handle, 0); } /* * We return to the external world as if this SIP is not * implemented in case, we are not running on VDK. */ break; default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; } SMC_RET1(handle, SMC_UNK); }
/******************************************************************************* * Perform any BL31 specific platform actions. Populate the BL33 and BL32 image * info. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct tegra_bl31_params *arg_from_bl2 = (struct tegra_bl31_params *) arg0; plat_params_from_bl2_t *plat_params = (plat_params_from_bl2_t *)arg1; image_info_t bl32_img_info = { {0} }; uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end; uint32_t console_clock; int32_t ret; /* * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so * there's no argument to relay from a previous bootloader. Platforms * might use custom ways to get arguments, so provide handlers which * they can override. */ if (arg_from_bl2 == NULL) { arg_from_bl2 = plat_get_bl31_params(); } if (plat_params == NULL) { plat_params = plat_get_bl31_plat_params(); } /* * Copy BL3-3, BL3-2 entry point information. * They are stored in Secure RAM, in BL2's address space. */ assert(arg_from_bl2 != NULL); assert(arg_from_bl2->bl33_ep_info != NULL); bl33_image_ep_info = *arg_from_bl2->bl33_ep_info; if (arg_from_bl2->bl32_ep_info != NULL) { bl32_image_ep_info = *arg_from_bl2->bl32_ep_info; bl32_mem_size = arg_from_bl2->bl32_ep_info->args.arg0; bl32_boot_params = arg_from_bl2->bl32_ep_info->args.arg2; } /* * Parse platform specific parameters - TZDRAM aperture base and size */ assert(plat_params != NULL); plat_bl31_params_from_bl2.tzdram_base = plat_params->tzdram_base; plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size; plat_bl31_params_from_bl2.uart_id = plat_params->uart_id; plat_bl31_params_from_bl2.l2_ecc_parity_prot_dis = plat_params->l2_ecc_parity_prot_dis; /* * It is very important that we run either from TZDRAM or TZSRAM base. * Add an explicit check here. */ if ((plat_bl31_params_from_bl2.tzdram_base != (uint64_t)BL31_BASE) && (TEGRA_TZRAM_BASE != BL31_BASE)) { panic(); } /* * Reference clock used by the FPGAs is a lot slower. */ if (tegra_platform_is_fpga()) { console_clock = TEGRA_BOOT_UART_CLK_13_MHZ; } else { console_clock = TEGRA_BOOT_UART_CLK_408_MHZ; } /* * Get the base address of the UART controller to be used for the * console */ tegra_console_base = plat_get_console_from_id(plat_params->uart_id); if (tegra_console_base != 0U) { /* * Configure the UART port to be used as the console */ (void)console_init(tegra_console_base, console_clock, TEGRA_CONSOLE_BAUDRATE); } /* * The previous bootloader passes the base address of the shared memory * location to store the boot profiler logs. Sanity check the * address and initilise the profiler library, if it looks ok. */ if (plat_params->boot_profiler_shmem_base != 0ULL) { ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base, PROFILER_SIZE_BYTES); if (ret == (int32_t)0) { /* store the membase for the profiler lib */ plat_bl31_params_from_bl2.boot_profiler_shmem_base = plat_params->boot_profiler_shmem_base; /* initialise the profiler library */ boot_profiler_init(plat_params->boot_profiler_shmem_base, TEGRA_TMRUS_BASE); } } /* * Add timestamp for platform early setup entry. */ boot_profiler_add_record("[TF] early setup entry"); /* * Initialize delay timer */ tegra_delay_timer_init(); /* Early platform setup for Tegra SoCs */ plat_early_platform_setup(); /* * Do initial security configuration to allow DRAM/device access. */ tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base, (uint32_t)plat_bl31_params_from_bl2.tzdram_size); /* * The previous bootloader might not have placed the BL32 image * inside the TZDRAM. We check the BL32 image info to find out * the base/PC values and relocate the image if necessary. */ if (arg_from_bl2->bl32_image_info != NULL) { bl32_img_info = *arg_from_bl2->bl32_image_info; /* Relocate BL32 if it resides outside of the TZDRAM */ tzdram_start = plat_bl31_params_from_bl2.tzdram_base; tzdram_end = plat_bl31_params_from_bl2.tzdram_base + plat_bl31_params_from_bl2.tzdram_size; bl32_start = bl32_img_info.image_base; bl32_end = bl32_img_info.image_base + bl32_img_info.image_size; assert(tzdram_end > tzdram_start); assert(bl32_end > bl32_start); assert(bl32_image_ep_info.pc > tzdram_start); assert(bl32_image_ep_info.pc < tzdram_end); /* relocate BL32 */ if ((bl32_start >= tzdram_end) || (bl32_end <= tzdram_start)) { INFO("Relocate BL32 to TZDRAM\n"); (void)memcpy16((void *)(uintptr_t)bl32_image_ep_info.pc, (void *)(uintptr_t)bl32_start, bl32_img_info.image_size); /* clean up non-secure intermediate buffer */ zeromem((void *)(uintptr_t)bl32_start, bl32_img_info.image_size); } } /* * Add timestamp for platform early setup exit. */ boot_profiler_add_record("[TF] early setup exit"); INFO("BL3-1: Boot CPU: %s Processor [%lx]\n", (((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK) == DENVER_IMPL) ? "Denver" : "ARM", read_mpidr()); }