1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <asm/arch/rockchip_smccc.h> 8 #include <asm/io.h> 9 #include <asm/psci.h> 10 #include <asm/suspend.h> 11 #include <linux/arm-smccc.h> 12 #include <linux/io.h> 13 14 #ifdef CONFIG_ARM64 15 #define ARM_PSCI_1_0_SYSTEM_SUSPEND ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND 16 #else 17 #define ARM_PSCI_1_0_SYSTEM_SUSPEND ARM_PSCI_1_0_FN_SYSTEM_SUSPEND 18 #endif 19 20 #define SIZE_PAGE(n) ((n) << 12) 21 22 static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id, 23 unsigned long arg0, 24 unsigned long arg1, 25 unsigned long arg2) 26 { 27 struct arm_smccc_res res; 28 29 arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); 30 return res; 31 } 32 33 int psci_system_suspend(unsigned long unused) 34 { 35 struct arm_smccc_res res; 36 37 res = __invoke_sip_fn_smc(ARM_PSCI_1_0_SYSTEM_SUSPEND, 38 virt_to_phys(cpu_resume), 0, 0); 39 return res.a0; 40 } 41 42 int sip_smc_set_suspend_mode(unsigned long ctrl, 43 unsigned long config1, 44 unsigned long config2) 45 { 46 struct arm_smccc_res res; 47 48 res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2); 49 return res.a0; 50 } 51 52 struct arm_smccc_res sip_smc_dram(unsigned long arg0, 53 unsigned long arg1, 54 unsigned long arg2) 55 { 56 return __invoke_sip_fn_smc(SIP_DRAM_CONFIG, arg0, arg1, arg2); 57 } 58 59 struct arm_smccc_res sip_smc_request_share_mem(unsigned long page_num, 60 share_page_type_t page_type) 61 { 62 struct arm_smccc_res res; 63 unsigned long share_mem_phy; 64 65 res = __invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0); 66 if (IS_SIP_ERROR(res.a0)) 67 goto error; 68 69 share_mem_phy = res.a1; 70 res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num)); 71 72 error: 73 return res; 74 } 75 76 struct arm_smccc_res sip_smc_get_sip_version(void) 77 { 78 return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0); 79 } 80 81 /* 82 * OP-TEE works both for kernel 3.10 and 4.4, and these two kernels have 83 * different sip implement that 3.10 uses SIP_IMPLEMENT_V1 and 4.4 uses 84 * SIP_IMPLEMENT_V2. So we should tell OP-TEE the current rockchip sip 85 * version(default SIP_IMPLEMENT_V1) before use. 86 */ 87 int sip_smc_set_sip_version(unsigned long version) 88 { 89 struct arm_smccc_res res; 90 91 res = __invoke_sip_fn_smc(SIP_SIP_VERSION, version, SECURE_REG_WR, 0); 92 if (IS_SIP_ERROR(res.a0)) { 93 printf("%s: set rockchip sip version v%ld failed\n", 94 __func__, version); 95 return res.a0; 96 } 97 98 return 0; 99 } 100