1025514baSAnson Huang /* 2025514baSAnson Huang * Copyright 2019 NXP 3025514baSAnson Huang * 4025514baSAnson Huang * SPDX-License-Identifier: BSD-3-Clause 5025514baSAnson Huang */ 6025514baSAnson Huang 74a0ac3e3SPeng Fan #include <arch.h> 8025514baSAnson Huang #include <stdlib.h> 9025514baSAnson Huang #include <stdint.h> 106e756f6dSAmbroise Vincent #include <services/std_svc.h> 11760f7941SAnson Huang #include <string.h> 12758ccb80SChris Kay #include <common/build_message.h> 13025514baSAnson Huang #include <common/debug.h> 14025514baSAnson Huang #include <common/runtime_svc.h> 15758ccb80SChris Kay #include <platform_def.h> 16025514baSAnson Huang #include <imx_sip_svc.h> 174a0ac3e3SPeng Fan #include <lib/el3_runtime/context_mgmt.h> 189ce232feSIgor Opaniuk #include <lib/mmio.h> 19025514baSAnson Huang #include <sci/sci.h> 20025514baSAnson Huang 216d2c502aSIgor Opaniuk #if defined(PLAT_imx8mn) || defined(PLAT_imx8mp) 226d2c502aSIgor Opaniuk /* 236d2c502aSIgor Opaniuk * Defined in 246d2c502aSIgor Opaniuk * table 11. ROM event log buffer address location 256d2c502aSIgor Opaniuk * AN12853 "i.MX ROMs Log Events" 266d2c502aSIgor Opaniuk */ 276d2c502aSIgor Opaniuk #define ROM_LOG_BUFFER_ADDR 0x9E0 286d2c502aSIgor Opaniuk #endif 296d2c502aSIgor Opaniuk 30f56afc1fSLeonard Crestez #if defined(PLAT_imx8qm) || defined(PLAT_imx8qx) 31950d05f7SLeonard Crestez 32f56afc1fSLeonard Crestez #ifdef PLAT_imx8qm 33f4b8470fSBoyan Karatotev static const int ap_cluster_index[PLATFORM_CLUSTER_COUNT] = { 34d3996c59SAnson Huang SC_R_A53, SC_R_A72, 35d3996c59SAnson Huang }; 36d3996c59SAnson Huang #endif 37d3996c59SAnson Huang 38025514baSAnson Huang static int imx_srtc_set_time(uint32_t year_mon, 39025514baSAnson Huang unsigned long day_hour, 40025514baSAnson Huang unsigned long min_sec) 41025514baSAnson Huang { 42025514baSAnson Huang return sc_timer_set_rtc_time(ipc_handle, 43025514baSAnson Huang year_mon >> 16, year_mon & 0xffff, 44025514baSAnson Huang day_hour >> 16, day_hour & 0xffff, 45025514baSAnson Huang min_sec >> 16, min_sec & 0xffff); 46025514baSAnson Huang } 47025514baSAnson Huang 48025514baSAnson Huang int imx_srtc_handler(uint32_t smc_fid, 49025514baSAnson Huang void *handle, 50025514baSAnson Huang u_register_t x1, 51025514baSAnson Huang u_register_t x2, 52025514baSAnson Huang u_register_t x3, 53025514baSAnson Huang u_register_t x4) 54025514baSAnson Huang { 55025514baSAnson Huang int ret; 56025514baSAnson Huang 57025514baSAnson Huang switch (x1) { 58025514baSAnson Huang case IMX_SIP_SRTC_SET_TIME: 59025514baSAnson Huang ret = imx_srtc_set_time(x2, x3, x4); 60025514baSAnson Huang break; 61025514baSAnson Huang default: 62025514baSAnson Huang ret = SMC_UNK; 63025514baSAnson Huang } 64025514baSAnson Huang 65025514baSAnson Huang SMC_RET1(handle, ret); 66025514baSAnson Huang } 67d3996c59SAnson Huang 68d3996c59SAnson Huang static void imx_cpufreq_set_target(uint32_t cluster_id, unsigned long freq) 69d3996c59SAnson Huang { 70*cbe42e11SJacky Bai /* Return if not a valid cluster */ 71*cbe42e11SJacky Bai if (cluster_id >= PLATFORM_CLUSTER_COUNT) { 72*cbe42e11SJacky Bai return; 73*cbe42e11SJacky Bai } 74*cbe42e11SJacky Bai 75d3996c59SAnson Huang sc_pm_clock_rate_t rate = (sc_pm_clock_rate_t)freq; 76d3996c59SAnson Huang 77f56afc1fSLeonard Crestez #ifdef PLAT_imx8qm 78d3996c59SAnson Huang sc_pm_set_clock_rate(ipc_handle, ap_cluster_index[cluster_id], SC_PM_CLK_CPU, &rate); 79d3996c59SAnson Huang #endif 80f56afc1fSLeonard Crestez #ifdef PLAT_imx8qx 81d3996c59SAnson Huang sc_pm_set_clock_rate(ipc_handle, SC_R_A35, SC_PM_CLK_CPU, &rate); 82d3996c59SAnson Huang #endif 83d3996c59SAnson Huang } 84d3996c59SAnson Huang 85d3996c59SAnson Huang int imx_cpufreq_handler(uint32_t smc_fid, 86d3996c59SAnson Huang u_register_t x1, 87d3996c59SAnson Huang u_register_t x2, 88d3996c59SAnson Huang u_register_t x3) 89d3996c59SAnson Huang { 90d3996c59SAnson Huang switch (x1) { 91d3996c59SAnson Huang case IMX_SIP_SET_CPUFREQ: 92d3996c59SAnson Huang imx_cpufreq_set_target(x2, x3); 93d3996c59SAnson Huang break; 94d3996c59SAnson Huang default: 95d3996c59SAnson Huang return SMC_UNK; 96d3996c59SAnson Huang } 97d3996c59SAnson Huang 98d3996c59SAnson Huang return 0; 99d3996c59SAnson Huang } 100ebdbc25bSAnson Huang 101ebdbc25bSAnson Huang static bool wakeup_src_irqsteer; 102ebdbc25bSAnson Huang 103ebdbc25bSAnson Huang bool imx_is_wakeup_src_irqsteer(void) 104ebdbc25bSAnson Huang { 105ebdbc25bSAnson Huang return wakeup_src_irqsteer; 106ebdbc25bSAnson Huang } 107ebdbc25bSAnson Huang 108ebdbc25bSAnson Huang int imx_wakeup_src_handler(uint32_t smc_fid, 109ebdbc25bSAnson Huang u_register_t x1, 110ebdbc25bSAnson Huang u_register_t x2, 111ebdbc25bSAnson Huang u_register_t x3) 112ebdbc25bSAnson Huang { 113ebdbc25bSAnson Huang switch (x1) { 114ebdbc25bSAnson Huang case IMX_SIP_WAKEUP_SRC_IRQSTEER: 115ebdbc25bSAnson Huang wakeup_src_irqsteer = true; 116ebdbc25bSAnson Huang break; 117ebdbc25bSAnson Huang case IMX_SIP_WAKEUP_SRC_SCU: 118ebdbc25bSAnson Huang wakeup_src_irqsteer = false; 119ebdbc25bSAnson Huang break; 120ebdbc25bSAnson Huang default: 121ebdbc25bSAnson Huang return SMC_UNK; 122ebdbc25bSAnson Huang } 123ebdbc25bSAnson Huang 124ebdbc25bSAnson Huang return SMC_OK; 125ebdbc25bSAnson Huang } 126dbfa45e8SAnson Huang 127dbfa45e8SAnson Huang int imx_otp_handler(uint32_t smc_fid, 128dbfa45e8SAnson Huang void *handle, 129dbfa45e8SAnson Huang u_register_t x1, 130dbfa45e8SAnson Huang u_register_t x2) 131dbfa45e8SAnson Huang { 132dbfa45e8SAnson Huang int ret; 133dbfa45e8SAnson Huang uint32_t fuse; 134dbfa45e8SAnson Huang 135dbfa45e8SAnson Huang switch (smc_fid) { 136dbfa45e8SAnson Huang case IMX_SIP_OTP_READ: 137dbfa45e8SAnson Huang ret = sc_misc_otp_fuse_read(ipc_handle, x1, &fuse); 138dbfa45e8SAnson Huang SMC_RET2(handle, ret, fuse); 139dbfa45e8SAnson Huang break; 140dbfa45e8SAnson Huang case IMX_SIP_OTP_WRITE: 141dbfa45e8SAnson Huang ret = sc_misc_otp_fuse_write(ipc_handle, x1, x2); 142dbfa45e8SAnson Huang SMC_RET1(handle, ret); 143dbfa45e8SAnson Huang break; 144dbfa45e8SAnson Huang default: 145dbfa45e8SAnson Huang ret = SMC_UNK; 146dbfa45e8SAnson Huang SMC_RET1(handle, ret); 147dbfa45e8SAnson Huang break; 148dbfa45e8SAnson Huang } 149dbfa45e8SAnson Huang 150dbfa45e8SAnson Huang return ret; 151dbfa45e8SAnson Huang } 152869eebc3SAnson Huang 153869eebc3SAnson Huang int imx_misc_set_temp_handler(uint32_t smc_fid, 154869eebc3SAnson Huang u_register_t x1, 155869eebc3SAnson Huang u_register_t x2, 156869eebc3SAnson Huang u_register_t x3, 157869eebc3SAnson Huang u_register_t x4) 158869eebc3SAnson Huang { 159869eebc3SAnson Huang return sc_misc_set_temp(ipc_handle, x1, x2, x3, x4); 160869eebc3SAnson Huang } 161760f7941SAnson Huang 162f56afc1fSLeonard Crestez #endif /* defined(PLAT_imx8qm) || defined(PLAT_imx8qx) */ 163950d05f7SLeonard Crestez 1649ce232feSIgor Opaniuk #if defined(PLAT_imx8mm) || defined(PLAT_imx8mq) 1659ce232feSIgor Opaniuk int imx_src_handler(uint32_t smc_fid, 1669ce232feSIgor Opaniuk u_register_t x1, 1679ce232feSIgor Opaniuk u_register_t x2, 1689ce232feSIgor Opaniuk u_register_t x3, 1699ce232feSIgor Opaniuk void *handle) 1709ce232feSIgor Opaniuk { 1719ce232feSIgor Opaniuk uint32_t val; 1729ce232feSIgor Opaniuk 1739ce232feSIgor Opaniuk switch (x1) { 1749ce232feSIgor Opaniuk case IMX_SIP_SRC_SET_SECONDARY_BOOT: 1759ce232feSIgor Opaniuk if (x2 != 0U) { 1769ce232feSIgor Opaniuk mmio_setbits_32(IMX_SRC_BASE + SRC_GPR10_OFFSET, 1779ce232feSIgor Opaniuk SRC_GPR10_PERSIST_SECONDARY_BOOT); 1789ce232feSIgor Opaniuk } else { 1799ce232feSIgor Opaniuk mmio_clrbits_32(IMX_SRC_BASE + SRC_GPR10_OFFSET, 1809ce232feSIgor Opaniuk SRC_GPR10_PERSIST_SECONDARY_BOOT); 1819ce232feSIgor Opaniuk } 1829ce232feSIgor Opaniuk break; 1839ce232feSIgor Opaniuk case IMX_SIP_SRC_IS_SECONDARY_BOOT: 1849ce232feSIgor Opaniuk val = mmio_read_32(IMX_SRC_BASE + SRC_GPR10_OFFSET); 1859ce232feSIgor Opaniuk return !!(val & SRC_GPR10_PERSIST_SECONDARY_BOOT); 1869ce232feSIgor Opaniuk default: 1879ce232feSIgor Opaniuk return SMC_UNK; 1889ce232feSIgor Opaniuk 1899ce232feSIgor Opaniuk }; 1909ce232feSIgor Opaniuk 1919ce232feSIgor Opaniuk return 0; 1929ce232feSIgor Opaniuk } 1939ce232feSIgor Opaniuk #endif /* defined(PLAT_imx8mm) || defined(PLAT_imx8mq) */ 1949ce232feSIgor Opaniuk 1956d2c502aSIgor Opaniuk #if defined(PLAT_imx8mn) || defined(PLAT_imx8mp) 1966d2c502aSIgor Opaniuk static bool is_secondary_boot(void) 1976d2c502aSIgor Opaniuk { 1986d2c502aSIgor Opaniuk uint32_t *rom_log_addr = (uint32_t *)ROM_LOG_BUFFER_ADDR; 1996d2c502aSIgor Opaniuk bool is_secondary = false; 2006d2c502aSIgor Opaniuk uint32_t *rom_log; 2016d2c502aSIgor Opaniuk uint8_t event_id; 2026d2c502aSIgor Opaniuk 2036d2c502aSIgor Opaniuk /* If the ROM event log pointer is not valid. */ 2046d2c502aSIgor Opaniuk if (*rom_log_addr < 0x900000 || *rom_log_addr >= 0xB00000 || 2056d2c502aSIgor Opaniuk *rom_log_addr & 0x3) { 2066d2c502aSIgor Opaniuk return false; 2076d2c502aSIgor Opaniuk } 2086d2c502aSIgor Opaniuk 2096d2c502aSIgor Opaniuk /* Parse the ROM event ID version 2 log */ 2106d2c502aSIgor Opaniuk rom_log = (uint32_t *)(uintptr_t)(*rom_log_addr); 2116d2c502aSIgor Opaniuk for (size_t i = 0; i < 128; i++) { 2126d2c502aSIgor Opaniuk event_id = rom_log[i] >> 24; 2136d2c502aSIgor Opaniuk switch (event_id) { 2146d2c502aSIgor Opaniuk case 0x00: /* End of list */ 2156d2c502aSIgor Opaniuk return is_secondary; 2166d2c502aSIgor Opaniuk /* Log entries with 1 parameter, skip 1 */ 2176d2c502aSIgor Opaniuk case 0x80: /* Perform the device initialization */ 2186d2c502aSIgor Opaniuk case 0x81: /* The boot device initialization completes */ 2196d2c502aSIgor Opaniuk case 0x82: /* Execute boot device driver pre-config */ 2206d2c502aSIgor Opaniuk case 0x8F: /* The boot device initialization fails */ 2216d2c502aSIgor Opaniuk case 0x90: /* Start to read data from boot device */ 2226d2c502aSIgor Opaniuk case 0x91: /* Reading data from boot device completes */ 2236d2c502aSIgor Opaniuk case 0x9F: /* Reading data from boot device fails */ 2246d2c502aSIgor Opaniuk i += 1; 2256d2c502aSIgor Opaniuk continue; 2266d2c502aSIgor Opaniuk /* Log entries with 2 parameters, skip 2 */ 2276d2c502aSIgor Opaniuk case 0xA0: /* Image authentication result */ 2286d2c502aSIgor Opaniuk case 0xC0: /* Jump to the boot image soon */ 2296d2c502aSIgor Opaniuk i += 2; 2306d2c502aSIgor Opaniuk continue; 2316d2c502aSIgor Opaniuk /* Booted the primary boot image */ 2326d2c502aSIgor Opaniuk case 0x50: 2336d2c502aSIgor Opaniuk is_secondary = false; 2346d2c502aSIgor Opaniuk continue; 2356d2c502aSIgor Opaniuk /* Booted the secondary boot image */ 2366d2c502aSIgor Opaniuk case 0x51: 2376d2c502aSIgor Opaniuk is_secondary = true; 2386d2c502aSIgor Opaniuk continue; 2396d2c502aSIgor Opaniuk } 2406d2c502aSIgor Opaniuk } 2416d2c502aSIgor Opaniuk 2426d2c502aSIgor Opaniuk return is_secondary; 2436d2c502aSIgor Opaniuk } 2446d2c502aSIgor Opaniuk 2456d2c502aSIgor Opaniuk int imx_src_handler(uint32_t smc_fid, 2466d2c502aSIgor Opaniuk u_register_t x1, 2476d2c502aSIgor Opaniuk u_register_t x2, 2486d2c502aSIgor Opaniuk u_register_t x3, 2496d2c502aSIgor Opaniuk void *handle) 2506d2c502aSIgor Opaniuk { 2516d2c502aSIgor Opaniuk switch (x1) { 2526d2c502aSIgor Opaniuk case IMX_SIP_SRC_SET_SECONDARY_BOOT: 2536d2c502aSIgor Opaniuk /* we do support that on these SoCs */ 2546d2c502aSIgor Opaniuk break; 2556d2c502aSIgor Opaniuk case IMX_SIP_SRC_IS_SECONDARY_BOOT: 2566d2c502aSIgor Opaniuk return is_secondary_boot(); 2576d2c502aSIgor Opaniuk default: 2586d2c502aSIgor Opaniuk return SMC_UNK; 2596d2c502aSIgor Opaniuk }; 2606d2c502aSIgor Opaniuk 2616d2c502aSIgor Opaniuk return 0; 2626d2c502aSIgor Opaniuk } 2636d2c502aSIgor Opaniuk #endif /* defined(PLAT_imx8mn) || defined(PLAT_imx8mp) */ 2646d2c502aSIgor Opaniuk 265760f7941SAnson Huang static uint64_t imx_get_commit_hash(u_register_t x2, 266760f7941SAnson Huang u_register_t x3, 267760f7941SAnson Huang u_register_t x4) 268760f7941SAnson Huang { 269760f7941SAnson Huang /* Parse the version_string */ 270758ccb80SChris Kay char *parse = (char *)build_version_string; 271760f7941SAnson Huang uint64_t hash = 0; 272760f7941SAnson Huang 273760f7941SAnson Huang do { 274760f7941SAnson Huang parse = strchr(parse, '-'); 275760f7941SAnson Huang if (parse) { 276760f7941SAnson Huang parse += 1; 277760f7941SAnson Huang if (*(parse) == 'g') { 278760f7941SAnson Huang /* Default is 7 hexadecimal digits */ 279760f7941SAnson Huang memcpy((void *)&hash, (void *)(parse + 1), 7); 280760f7941SAnson Huang break; 281760f7941SAnson Huang } 282760f7941SAnson Huang } 283760f7941SAnson Huang 284760f7941SAnson Huang } while (parse != NULL); 285760f7941SAnson Huang 286760f7941SAnson Huang return hash; 287760f7941SAnson Huang } 288760f7941SAnson Huang 289760f7941SAnson Huang uint64_t imx_buildinfo_handler(uint32_t smc_fid, 290760f7941SAnson Huang u_register_t x1, 291760f7941SAnson Huang u_register_t x2, 292760f7941SAnson Huang u_register_t x3, 293760f7941SAnson Huang u_register_t x4) 294760f7941SAnson Huang { 295760f7941SAnson Huang uint64_t ret; 296760f7941SAnson Huang 297760f7941SAnson Huang switch (x1) { 298760f7941SAnson Huang case IMX_SIP_BUILDINFO_GET_COMMITHASH: 299760f7941SAnson Huang ret = imx_get_commit_hash(x2, x3, x4); 300760f7941SAnson Huang break; 301760f7941SAnson Huang default: 302760f7941SAnson Huang return SMC_UNK; 303760f7941SAnson Huang } 304760f7941SAnson Huang 305760f7941SAnson Huang return ret; 306760f7941SAnson Huang } 3074a0ac3e3SPeng Fan 3084a0ac3e3SPeng Fan int imx_kernel_entry_handler(uint32_t smc_fid, 3094a0ac3e3SPeng Fan u_register_t x1, 3104a0ac3e3SPeng Fan u_register_t x2, 3114a0ac3e3SPeng Fan u_register_t x3, 3124a0ac3e3SPeng Fan u_register_t x4) 3134a0ac3e3SPeng Fan { 3144a0ac3e3SPeng Fan static entry_point_info_t bl33_image_ep_info; 3154a0ac3e3SPeng Fan entry_point_info_t *next_image_info; 3164a0ac3e3SPeng Fan unsigned int mode; 3174a0ac3e3SPeng Fan 3184a0ac3e3SPeng Fan if (x1 < (PLAT_NS_IMAGE_OFFSET & 0xF0000000)) 3194a0ac3e3SPeng Fan return SMC_UNK; 3204a0ac3e3SPeng Fan 3214a0ac3e3SPeng Fan mode = MODE32_svc; 3224a0ac3e3SPeng Fan 3234a0ac3e3SPeng Fan next_image_info = &bl33_image_ep_info; 3244a0ac3e3SPeng Fan 3254a0ac3e3SPeng Fan next_image_info->pc = x1; 3264a0ac3e3SPeng Fan 3274a0ac3e3SPeng Fan next_image_info->spsr = SPSR_MODE32(mode, SPSR_T_ARM, SPSR_E_LITTLE, 3284a0ac3e3SPeng Fan (DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT)); 3294a0ac3e3SPeng Fan 3304a0ac3e3SPeng Fan next_image_info->args.arg0 = 0; 3314a0ac3e3SPeng Fan next_image_info->args.arg1 = 0; 3324a0ac3e3SPeng Fan next_image_info->args.arg2 = x3; 3334a0ac3e3SPeng Fan 3344a0ac3e3SPeng Fan SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE); 3354a0ac3e3SPeng Fan 3364a0ac3e3SPeng Fan cm_init_my_context(next_image_info); 3374a0ac3e3SPeng Fan cm_prepare_el3_exit(NON_SECURE); 3384a0ac3e3SPeng Fan 3394a0ac3e3SPeng Fan return 0; 3404a0ac3e3SPeng Fan } 341ac5d69b6SJacky Bai 342ac5d69b6SJacky Bai #if defined(PLAT_imx8ulp) 343ac5d69b6SJacky Bai int imx_hifi_xrdc(uint32_t smc_fid) 344ac5d69b6SJacky Bai { 345ac5d69b6SJacky Bai mmio_setbits_32(IMX_SIM2_BASE + 0x8, BIT_32(19) | BIT_32(17) | BIT_32(18)); 346ac5d69b6SJacky Bai mmio_clrbits_32(IMX_SIM2_BASE + 0x8, BIT_32(16)); 347ac5d69b6SJacky Bai 348ac5d69b6SJacky Bai extern int xrdc_apply_hifi_config(void); 349ac5d69b6SJacky Bai xrdc_apply_hifi_config(); 350ac5d69b6SJacky Bai 351ac5d69b6SJacky Bai return 0; 352ac5d69b6SJacky Bai } 353ac5d69b6SJacky Bai #endif 354