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 struct arm_smccc_res sip_smc_dram(unsigned long arg0, 65 unsigned long arg1, 66 unsigned long arg2) 67 { 68 return __invoke_sip_fn_smc(SIP_DRAM_CONFIG, arg0, arg1, arg2); 69 } 70 71 struct arm_smccc_res sip_smc_request_share_mem(unsigned long page_num, 72 share_page_type_t page_type) 73 { 74 struct arm_smccc_res res; 75 unsigned long share_mem_phy; 76 77 res = __invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0); 78 if (IS_SIP_ERROR(res.a0)) 79 goto error; 80 81 share_mem_phy = res.a1; 82 res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num)); 83 84 error: 85 return res; 86 } 87 88 struct arm_smccc_res sip_smc_secure_reg_read(unsigned long addr_phy) 89 { 90 struct arm_smccc_res res; 91 92 res = __invoke_sip_fn_smc(SIP_ACCESS_REG, 0, addr_phy, SECURE_REG_RD); 93 return res; 94 } 95 96 int sip_smc_secure_reg_write(unsigned long addr_phy, unsigned long val) 97 { 98 struct arm_smccc_res res; 99 100 res = __invoke_sip_fn_smc(SIP_ACCESS_REG, val, addr_phy, SECURE_REG_WR); 101 return res.a0; 102 } 103 104 struct arm_smccc_res sip_smc_get_sip_version(void) 105 { 106 return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0); 107 } 108 109 /* 110 * OP-TEE works both for kernel 3.10 and 4.4, and these two kernels have 111 * different sip implement that 3.10 uses SIP_IMPLEMENT_V1 and 4.4 uses 112 * SIP_IMPLEMENT_V2. So we should tell OP-TEE the current rockchip sip 113 * version(default SIP_IMPLEMENT_V1) before use. 114 */ 115 int sip_smc_set_sip_version(unsigned long version) 116 { 117 struct arm_smccc_res res; 118 119 res = __invoke_sip_fn_smc(SIP_SIP_VERSION, version, SECURE_REG_WR, 0); 120 if (IS_SIP_ERROR(res.a0)) { 121 printf("%s: set rockchip sip version v%ld failed\n", 122 __func__, version); 123 return res.a0; 124 } 125 126 return 0; 127 } 128