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