xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/rockchip_smccc.c (revision e8c34540a61ba8ec3ef255e3e8a72e7d3409f5f5)
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