// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (C) 2022 Foundries.io Ltd * Jorge Ramirez-Ortiz */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* VERSAL_SIP_UID: 2ab9e4ec-93b9-11e7-a019dfe0dbad0ae0 */ #define VERSAL_SIP_UID_0 U(0xece4b92a) #define VERSAL_SIP_UID_1 U(0xe711b993) #define VERSAL_SIP_UID_2 U(0xe0df19a0) #define VERSAL_SIP_UID_3 U(0xe00aaddb) #define VERSAL_SIP_MAJOR 0 #define VERSAL_SIP_MINOR 1 #define VERSAL_SIP_SVC_VERSION 0x8200ff03 #define VERSAL_SIP_SVC_UID 0x8200ff01 #define VERSAL_SIP_SVC 0xc2000000 #define PAYLOAD_ARG_CNT 8 /* MBOX IPI */ #define PM_MODULE_SHIFT 8 #define PM_MODULE 2 #define PM_API_ID(x) ((PM_MODULE << PM_MODULE_SHIFT) | (x)) #define VERSAL_PM_MAJOR 0 #define VERSAL_PM_MINOR 1 /* PM API ids */ #define PM_GET_API_VERSION 1 #define PM_GET_DEVICE_STATUS 3 #define PM_GET_OP_CHARACTERISTIC 4 #define PM_REGISTER_NOTIFIER 5 #define PM_REQ_SUSPEND 6 #define PM_SELF_SUSPEND 7 #define PM_FORCE_POWERDOWN 8 #define PM_ABORT_SUSPEND 9 #define PM_REQ_WAKEUP 10 #define PM_SET_WAKEUP_SOURCE 11 #define PM_SYSTEM_SHUTDOWN 12 #define PM_REQUEST_DEVICE 13 #define PM_RELEASE_DEVICE 14 #define PM_SET_REQUIREMENT 15 #define PM_SET_MAX_LATENCY 16 #define PM_RESET_ASSERT 17 #define PM_RESET_GET_STATUS 18 #define PM_INIT_FINALIZE 21 #define PM_GET_CHIPID 24 #define PM_PINCTRL_REQUEST 28 #define PM_PINCTRL_RELEASE 29 #define PM_PINCTRL_GET_FUNCTION 30 #define PM_PINCTRL_SET_FUNCTION 31 #define PM_PINCTRL_CONFIG_PARAM_GET 32 #define PM_PINCTRL_CONFIG_PARAM_SET 33 #define PM_IOCTL 34 #define PM_QUERY_DATA 35 #define PM_CLOCK_ENABLE 36 #define PM_CLOCK_DISABLE 37 #define PM_CLOCK_GETSTATE 38 #define PM_CLOCK_SETDIVIDER 39 #define PM_CLOCK_GETDIVIDER 40 #define PM_CLOCK_SETRATE 41 #define PM_CLOCK_GETRATE 42 #define PM_CLOCK_SETPARENT 43 #define PM_CLOCK_GETPARENT 44 #define PM_PLL_SET_PARAMETER 48 #define PM_PLL_GET_PARAMETER 49 #define PM_PLL_SET_MODE 50 #define PM_PLL_GET_MODE 51 #define PM_FEATURE_CHECK 63 /* Loader API id */ #define PM_LOAD_PDI 0x701 /* PDI sources */ #define PDI_SRC_JTAG 0x0 #define PDI_SRC_QSPI24 0x1 #define PDI_SRC_QSPI32 0x2 #define PDI_SRC_SD0 0x3 #define PDI_SRC_EMMC0 0x4 #define PDI_SRC_SD1 0x5 #define PDI_SRC_EMMC1 0x6 #define PDI_SRC_USB 0x7 #define PDI_SRC_OSPI 0x8 #define PDI_SRC_SBI 0x9 #define PDI_SRC_SMAP 0xA #define PDI_SRC_PCIE 0xB #define PDI_SRC_SD1_LS 0xE #define PDI_SRC_DDR 0xF struct versal_sip_payload { uint32_t data[PAYLOAD_ARG_CNT]; }; static uint32_t versal_sip_call(uint32_t smc_fid, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, struct versal_sip_payload *payload) { struct thread_smc_args args = { .a0 = smc_fid, .a1 = reg_pair_to_64(arg1, arg0), .a2 = reg_pair_to_64(arg3, arg2), }; thread_smccc(&args); if (payload) { reg_pair_from_64(args.a0, &payload->data[1], &payload->data[0]); reg_pair_from_64(args.a1, &payload->data[3], &payload->data[2]); reg_pair_from_64(args.a2, &payload->data[5], &payload->data[4]); reg_pair_from_64(args.a3, &payload->data[7], &payload->data[6]); } /* allow the PLM to output its debug information */ if (IS_ENABLED(CFG_VERSAL_TRACE_PLM)) mdelay(500); return args.a0; } /* SIP call to program the FPGA has been obsoleted, use the PLM */ TEE_Result versal_write_fpga(paddr_t pa) { struct versal_ipi_cmd cmd = { }; cmd.data[0] = PM_LOAD_PDI; cmd.data[1] = PDI_SRC_DDR; reg_pair_from_64(pa, &cmd.data[2], &cmd.data[3]); if (versal_mbox_notify(&cmd, NULL, NULL)) return TEE_ERROR_GENERIC; return TEE_SUCCESS; } TEE_Result versal_soc_version(uint8_t *version) { struct versal_sip_payload p = { }; const uint32_t version_shift = 12; if (!version) return TEE_ERROR_BAD_PARAMETERS; if (versal_sip_call(VERSAL_SIP_SVC | PM_GET_CHIPID, 0, 0, 0, 0, &p)) return TEE_ERROR_GENERIC; *version = p.data[2] >> version_shift; return TEE_SUCCESS; } static bool uuid_is_versal_pm(void) { struct versal_sip_payload p = { }; versal_sip_call(VERSAL_SIP_SVC_UID, 0, 0, 0, 0, &p); if (p.data[0] == VERSAL_SIP_UID_0 && p.data[2] == VERSAL_SIP_UID_1 && p.data[4] == VERSAL_SIP_UID_2 && p.data[6] == VERSAL_SIP_UID_3) return true; return false; } static TEE_Result versal_check_pm_abi(void) { struct versal_sip_payload p = { }; struct versal_ipi_cmd cmd = { }; struct versal_ipi_cmd rsp = { }; unsigned int major = 0; unsigned int minor = 0; if (!uuid_is_versal_pm()) { EMSG("Invalid SiP Service"); return TEE_ERROR_GENERIC; } if (versal_sip_call(VERSAL_SIP_SVC_VERSION, 0, 0, 0, 0, &p)) return TEE_ERROR_GENERIC; major = p.data[0]; minor = p.data[2]; if (major != VERSAL_SIP_MAJOR || minor < VERSAL_SIP_MINOR) { EMSG("Invalid SiP version: Major %d, Minor %d", major, minor); return TEE_ERROR_GENERIC; } cmd.data[0] = PM_API_ID(PM_GET_API_VERSION); if (versal_mbox_notify(&cmd, &rsp, NULL)) return TEE_ERROR_GENERIC; major = rsp.data[1] & 0xFFFF; minor = rsp.data[1] >> 16; if (major != VERSAL_PM_MAJOR || minor < VERSAL_PM_MINOR) { EMSG("Invalid PM version: Major %d, Minor %d", major, minor); return TEE_ERROR_GENERIC; } return TEE_SUCCESS; } early_init_late(versal_check_pm_abi);