static unsigned long __invoke_psci_fn_smc(unsigned long function_id, unsigned long arg0, unsigned long arg1, unsigned long arg2) { struct arm_smccc_res res; arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); return res.a0; }
static void show_psci_version(void) { struct arm_smccc_res res; arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); printf("PSCI: v%ld.%ld\n", PSCI_VERSION_MAJOR(res.a0), PSCI_VERSION_MINOR(res.a0)); }
static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct arm_smccc_res res; /* pack 2 time parameters into 1 register, 16 bits for each */ arm_smccc_smc(IMX_SIP_SRTC, IMX_SIP_SRTC_SET_TIME, ((tm->tm_year + 1900) << 16) | (tm->tm_mon + 1), (tm->tm_mday << 16) | tm->tm_hour, (tm->tm_min << 16) | tm->tm_sec, 0, 0, 0, &res); return res.a0; }
/* * This is a TPM Command Response Buffer start method that invokes a * Secure Monitor Call to requrest the firmware to execute or cancel * a TPM 2.0 command. */ static int tpm_crb_smc_start(struct device *dev, unsigned long func_id) { struct arm_smccc_res res; arm_smccc_smc(func_id, 0, 0, 0, 0, 0, 0, 0, &res); if (res.a0 != 0) { dev_err(dev, FW_BUG "tpm_crb_smc_start() returns res.a0 = 0x%lx\n", res.a0); return -EIO; } return 0; }
/** * do_fw_call_smc() - Call system-level platform management layer (SMC) * @arg0: Argument 0 to SMC call * @arg1: Argument 1 to SMC call * @arg2: Argument 2 to SMC call * @ret_payload: Returned value array * * Invoke platform management function via SMC call (no hypervisor present). * * Return: Returns status, either success or error+reason */ static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2, u32 *ret_payload) { struct arm_smccc_res res; arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res); if (ret_payload) { ret_payload[0] = lower_32_bits(res.a0); ret_payload[1] = upper_32_bits(res.a0); ret_payload[2] = lower_32_bits(res.a1); ret_payload[3] = upper_32_bits(res.a1); } return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); }
void __qcom_scm_init(void) { u64 cmd; struct arm_smccc_res res; u32 function = QCOM_SCM_FNID(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD); /* First try a SMC64 call */ cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP, function); arm_smccc_smc(cmd, QCOM_SCM_ARGS(1), cmd & (~BIT(ARM_SMCCC_TYPE_SHIFT)), 0, 0, 0, 0, 0, &res); if (!res.a0 && res.a1) qcom_smccc_convention = ARM_SMCCC_SMC_64; else qcom_smccc_convention = ARM_SMCCC_SMC_32; }
int imx8mq_init(void) { void __iomem *anatop = IOMEM(MX8MQ_ANATOP_BASE_ADDR); void __iomem *src = IOMEM(MX8MQ_SRC_BASE_ADDR); uint32_t type = FIELD_GET(DIGPROG_MAJOR, readl(anatop + MX8MQ_ANATOP_DIGPROG)); struct arm_smccc_res res; const char *cputypestr; imx8_boot_save_loc(); switch (type) { case IMX8M_CPUTYPE_IMX8MQ: cputypestr = "i.MX8MQ"; break; default: cputypestr = "unknown i.MX8M"; break; }; imx_set_silicon_revision(cputypestr, imx8mq_cpu_revision()); /* * Reset reasons seem to be identical to that of i.MX7 */ imx_set_reset_reason(src + IMX7_SRC_SRSR, imx7_reset_reasons); if (IS_ENABLED(CONFIG_ARM_SMCCC) && IS_ENABLED(CONFIG_FIRMWARE_IMX8MQ_ATF)) { arm_smccc_smc(FSL_SIP_BUILDINFO, FSL_SIP_BUILDINFO_GET_COMMITHASH, 0, 0, 0, 0, 0, 0, &res); pr_info("i.MX ARM Trusted Firmware: %s\n", (char *)&res.a0); } return 0; }
/** * qcom_scm_call() - Invoke a syscall in the secure world * @dev: device * @svc_id: service identifier * @cmd_id: command identifier * @desc: Descriptor structure containing arguments and return values * * Sends a command to the SCM and waits for the command to finish processing. * This should *only* be called in pre-emptible context. */ static int qcom_scm_call(struct device *dev, u32 svc_id, u32 cmd_id, const struct qcom_scm_desc *desc, struct arm_smccc_res *res) { int arglen = desc->arginfo & 0xf; int retry_count = 0, i; u32 fn_id = QCOM_SCM_FNID(svc_id, cmd_id); u64 cmd, x5 = desc->args[FIRST_EXT_ARG_IDX]; dma_addr_t args_phys = 0; void *args_virt = NULL; size_t alloc_len; if (unlikely(arglen > N_REGISTER_ARGS)) { alloc_len = N_EXT_QCOM_SCM_ARGS * sizeof(u64); args_virt = kzalloc(PAGE_ALIGN(alloc_len), GFP_KERNEL); if (!args_virt) return -ENOMEM; if (qcom_smccc_convention == ARM_SMCCC_SMC_32) { __le32 *args = args_virt; for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++) args[i] = cpu_to_le32(desc->args[i + FIRST_EXT_ARG_IDX]); } else { __le64 *args = args_virt; for (i = 0; i < N_EXT_QCOM_SCM_ARGS; i++) args[i] = cpu_to_le64(desc->args[i + FIRST_EXT_ARG_IDX]); } args_phys = dma_map_single(dev, args_virt, alloc_len, DMA_TO_DEVICE); if (dma_mapping_error(dev, args_phys)) { kfree(args_virt); return -ENOMEM; } x5 = args_phys; } do { mutex_lock(&qcom_scm_lock); cmd = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, qcom_smccc_convention, ARM_SMCCC_OWNER_SIP, fn_id); do { arm_smccc_smc(cmd, desc->arginfo, desc->args[0], desc->args[1], desc->args[2], x5, 0, 0, res); } while (res->a0 == QCOM_SCM_INTERRUPTED); mutex_unlock(&qcom_scm_lock); if (res->a0 == QCOM_SCM_V2_EBUSY) { if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) break; msleep(QCOM_SCM_EBUSY_WAIT_MS); } } while (res->a0 == QCOM_SCM_V2_EBUSY); if (args_virt) { dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE); kfree(args_virt); } if (res->a0 < 0) return qcom_scm_remap_error(res->a0); return 0; }