xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/rockchip_smccc.c (revision 2c3c84fc7fd0ab439baf1e634c8b5504daa40db4)
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 #define ARM_PSCI_0_2_CPU_OFF		ARM_PSCI_0_2_FN_CPU_OFF
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 #define ARM_PSCI_0_2_CPU_OFF		ARM_PSCI_0_2_FN_CPU_OFF
21 #endif
22 
23 #define SIZE_PAGE(n)	((n) << 12)
24 
25 static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id,
26 						unsigned long arg0,
27 						unsigned long arg1,
28 						unsigned long arg2)
29 {
30 	struct arm_smccc_res res;
31 
32 	arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
33 	return res;
34 }
35 
36 int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
37 {
38 	struct arm_smccc_res res;
39 
40 	res = __invoke_sip_fn_smc(ARM_PSCI_0_2_CPU_ON, cpuid, entry_point, 0);
41 
42 	return res.a0;
43 }
44 
45 int psci_cpu_off(uint32_t state)
46 {
47 	struct arm_smccc_res res;
48 
49 	res = __invoke_sip_fn_smc(ARM_PSCI_0_2_CPU_OFF, state, 0, 0);
50 
51 	return res.a0;
52 }
53 
54 #ifdef CONFIG_ARM_CPU_SUSPEND
55 int psci_system_suspend(unsigned long unused)
56 {
57 	struct arm_smccc_res res;
58 
59 	res = __invoke_sip_fn_smc(ARM_PSCI_1_0_SYSTEM_SUSPEND,
60 				  virt_to_phys(cpu_resume), 0, 0);
61 	return res.a0;
62 }
63 #endif
64 
65 int sip_smc_set_suspend_mode(unsigned long ctrl,
66 			     unsigned long config1,
67 			     unsigned long config2)
68 {
69 	struct arm_smccc_res res;
70 
71 	res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2);
72 	return res.a0;
73 }
74 
75 int sip_smc_remotectl_config(unsigned long func, unsigned long data)
76 {
77 	struct arm_smccc_res res;
78 
79 	res = __invoke_sip_fn_smc(SIP_REMOTECTL_CFG, func, data, 0);
80 
81 	return res.a0;
82 }
83 
84 int sip_smc_amp_cfg(unsigned long func, unsigned long arg0, unsigned long arg1,
85 		    unsigned long arg2)
86 {
87 	struct arm_smccc_res res;
88 
89 	arm_smccc_smc(SIP_AMP_CFG, func, arg0, arg1, arg2, 0, 0, 0, &res);
90 	return res.a0;
91 }
92 
93 struct arm_smccc_res sip_smc_dram(unsigned long arg0,
94 				  unsigned long arg1,
95 				  unsigned long arg2)
96 {
97 	return __invoke_sip_fn_smc(SIP_DRAM_CONFIG, arg0, arg1, arg2);
98 }
99 
100 struct arm_smccc_res sip_smc_request_share_mem(unsigned long page_num,
101 					       share_page_type_t page_type)
102 {
103 	struct arm_smccc_res res;
104 	unsigned long share_mem_phy;
105 
106 	res = __invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0);
107 	if (IS_SIP_ERROR(res.a0))
108 		goto error;
109 
110 	share_mem_phy = res.a1;
111 	res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num));
112 
113 error:
114 	return res;
115 }
116 
117 struct arm_smccc_res sip_smc_secure_reg_read(unsigned long addr_phy)
118 {
119 	struct arm_smccc_res res;
120 
121 	res = __invoke_sip_fn_smc(SIP_ACCESS_REG, 0, addr_phy, SECURE_REG_RD);
122 	return res;
123 }
124 
125 int sip_smc_secure_reg_write(unsigned long addr_phy, unsigned long val)
126 {
127 	struct arm_smccc_res res;
128 
129 	res = __invoke_sip_fn_smc(SIP_ACCESS_REG, val, addr_phy, SECURE_REG_WR);
130 	return res.a0;
131 }
132 
133 int sip_smc_hdcp_config(unsigned long func, unsigned long arg1, unsigned long arg2)
134 {
135 	struct arm_smccc_res res;
136 
137 	res = __invoke_sip_fn_smc(SIP_HDCP_CONFIG, func, arg1, arg2);
138 	return res.a0;
139 }
140 
141 struct arm_smccc_res sip_smc_get_sip_version(void)
142 {
143 	return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0);
144 }
145 
146 /*
147  * OP-TEE works both for kernel 3.10 and 4.4, and these two kernels have
148  * different sip implement that 3.10 uses SIP_IMPLEMENT_V1 and 4.4 uses
149  * SIP_IMPLEMENT_V2. So we should tell OP-TEE the current rockchip sip
150  * version(default SIP_IMPLEMENT_V1) before use.
151  */
152 int sip_smc_set_sip_version(unsigned long version)
153 {
154 	struct arm_smccc_res res;
155 
156 	res = __invoke_sip_fn_smc(SIP_SIP_VERSION, version, SECURE_REG_WR, 0);
157 	if (IS_SIP_ERROR(res.a0)) {
158 		printf("%s: set rockchip sip version v%ld failed\n",
159 		       __func__, version);
160 		return res.a0;
161 	}
162 
163 	return 0;
164 }
165 
166 int sip_smc_mcu_config(unsigned long mcu_id, unsigned long func, unsigned long arg2)
167 {
168 	struct arm_smccc_res res;
169 
170 	res = __invoke_sip_fn_smc(SIP_MCU_CFG, mcu_id, func, arg2);
171 	return res.a0;
172 }
173