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 #define ARM_PSCI_0_2_CPU_ON ARM_PSCI_0_2_FN64_CPU_ON 17 #else 18 #define ARM_PSCI_1_0_SYSTEM_SUSPEND ARM_PSCI_1_0_FN_SYSTEM_SUSPEND 19 #define ARM_PSCI_0_2_CPU_ON ARM_PSCI_0_2_FN_CPU_ON 20 #endif 21 22 #define SIZE_PAGE(n) ((n) << 12) 23 24 static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id, 25 unsigned long arg0, 26 unsigned long arg1, 27 unsigned long arg2) 28 { 29 struct arm_smccc_res res; 30 31 arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); 32 return res; 33 } 34 35 int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) 36 { 37 struct arm_smccc_res res; 38 39 res = __invoke_sip_fn_smc(ARM_PSCI_0_2_CPU_ON, cpuid, entry_point, 0); 40 41 return res.a0; 42 } 43 44 #ifdef CONFIG_ARM_CPU_SUSPEND 45 int psci_system_suspend(unsigned long unused) 46 { 47 struct arm_smccc_res res; 48 49 res = __invoke_sip_fn_smc(ARM_PSCI_1_0_SYSTEM_SUSPEND, 50 virt_to_phys(cpu_resume), 0, 0); 51 return res.a0; 52 } 53 #endif 54 55 int sip_smc_set_suspend_mode(unsigned long ctrl, 56 unsigned long config1, 57 unsigned long config2) 58 { 59 struct arm_smccc_res res; 60 61 res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2); 62 return res.a0; 63 } 64 65 struct arm_smccc_res sip_smc_dram(unsigned long arg0, 66 unsigned long arg1, 67 unsigned long arg2) 68 { 69 return __invoke_sip_fn_smc(SIP_DRAM_CONFIG, arg0, arg1, arg2); 70 } 71 72 struct arm_smccc_res sip_smc_request_share_mem(unsigned long page_num, 73 share_page_type_t page_type) 74 { 75 struct arm_smccc_res res; 76 unsigned long share_mem_phy; 77 78 res = __invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0); 79 if (IS_SIP_ERROR(res.a0)) 80 goto error; 81 82 share_mem_phy = res.a1; 83 res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num)); 84 85 error: 86 return res; 87 } 88 89 struct arm_smccc_res sip_smc_secure_reg_read(unsigned long addr_phy) 90 { 91 struct arm_smccc_res res; 92 93 res = __invoke_sip_fn_smc(SIP_ACCESS_REG, 0, addr_phy, SECURE_REG_RD); 94 return res; 95 } 96 97 int sip_smc_secure_reg_write(unsigned long addr_phy, unsigned long val) 98 { 99 struct arm_smccc_res res; 100 101 res = __invoke_sip_fn_smc(SIP_ACCESS_REG, val, addr_phy, SECURE_REG_WR); 102 return res.a0; 103 } 104 105 struct arm_smccc_res sip_smc_get_sip_version(void) 106 { 107 return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0); 108 } 109 110 /* 111 * OP-TEE works both for kernel 3.10 and 4.4, and these two kernels have 112 * different sip implement that 3.10 uses SIP_IMPLEMENT_V1 and 4.4 uses 113 * SIP_IMPLEMENT_V2. So we should tell OP-TEE the current rockchip sip 114 * version(default SIP_IMPLEMENT_V1) before use. 115 */ 116 int sip_smc_set_sip_version(unsigned long version) 117 { 118 struct arm_smccc_res res; 119 120 res = __invoke_sip_fn_smc(SIP_SIP_VERSION, version, SECURE_REG_WR, 0); 121 if (IS_SIP_ERROR(res.a0)) { 122 printf("%s: set rockchip sip version v%ld failed\n", 123 __func__, version); 124 return res.a0; 125 } 126 127 return 0; 128 } 129