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
__invoke_sip_fn_smc(unsigned long function_id,unsigned long arg0,unsigned long arg1,unsigned long arg2)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
psci_cpu_on(unsigned long cpuid,unsigned long entry_point)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
psci_cpu_off(uint32_t state)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
psci_system_suspend(unsigned long unused)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
sip_smc_set_suspend_mode(unsigned long ctrl,unsigned long config1,unsigned long config2)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
sip_smc_remotectl_config(unsigned long func,unsigned long data)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
sip_smc_access_mem_os_reg(unsigned long func,unsigned long id,unsigned long * val)84 int sip_smc_access_mem_os_reg(unsigned long func, unsigned long id,
85 unsigned long *val)
86 {
87 struct arm_smccc_res res;
88
89 if (val == NULL)
90 return SIP_RET_INVALID_PARAMS;
91
92 res = __invoke_sip_fn_smc(SIP_ACCESS_MEM_OS_REG, func, id, *val);
93
94 if (func == RK_MEM_OS_REG_READ)
95 *val = res.a1;
96
97 return res.a0;
98 }
99
sip_smc_amp_cfg(unsigned long func,unsigned long arg0,unsigned long arg1,unsigned long arg2)100 int sip_smc_amp_cfg(unsigned long func, unsigned long arg0, unsigned long arg1,
101 unsigned long arg2)
102 {
103 struct arm_smccc_res res;
104
105 arm_smccc_smc(SIP_AMP_CFG, func, arg0, arg1, arg2, 0, 0, 0, &res);
106 return res.a0;
107 }
108
sip_smc_dram(unsigned long arg0,unsigned long arg1,unsigned long arg2)109 struct arm_smccc_res sip_smc_dram(unsigned long arg0,
110 unsigned long arg1,
111 unsigned long arg2)
112 {
113 return __invoke_sip_fn_smc(SIP_DRAM_CONFIG, arg0, arg1, arg2);
114 }
115
sip_smc_request_share_mem(unsigned long page_num,share_page_type_t page_type)116 struct arm_smccc_res sip_smc_request_share_mem(unsigned long page_num,
117 share_page_type_t page_type)
118 {
119 struct arm_smccc_res res;
120 unsigned long share_mem_phy;
121
122 res = __invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0);
123 if (IS_SIP_ERROR(res.a0))
124 goto error;
125
126 share_mem_phy = res.a1;
127 res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num));
128
129 error:
130 return res;
131 }
132
sip_smc_secure_reg_read(unsigned long addr_phy)133 struct arm_smccc_res sip_smc_secure_reg_read(unsigned long addr_phy)
134 {
135 struct arm_smccc_res res;
136
137 res = __invoke_sip_fn_smc(SIP_ACCESS_REG, 0, addr_phy, SECURE_REG_RD);
138 return res;
139 }
140
sip_smc_secure_reg_write(unsigned long addr_phy,unsigned long val)141 int sip_smc_secure_reg_write(unsigned long addr_phy, unsigned long val)
142 {
143 struct arm_smccc_res res;
144
145 res = __invoke_sip_fn_smc(SIP_ACCESS_REG, val, addr_phy, SECURE_REG_WR);
146 return res.a0;
147 }
148
sip_smc_hdcp_config(unsigned long func,unsigned long arg1,unsigned long arg2)149 int sip_smc_hdcp_config(unsigned long func, unsigned long arg1, unsigned long arg2)
150 {
151 struct arm_smccc_res res;
152
153 res = __invoke_sip_fn_smc(SIP_HDCP_CONFIG, func, arg1, arg2);
154 return res.a0;
155 }
156
sip_smc_get_sip_version(void)157 struct arm_smccc_res sip_smc_get_sip_version(void)
158 {
159 return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0);
160 }
161
162 /*
163 * OP-TEE works both for kernel 3.10 and 4.4, and these two kernels have
164 * different sip implement that 3.10 uses SIP_IMPLEMENT_V1 and 4.4 uses
165 * SIP_IMPLEMENT_V2. So we should tell OP-TEE the current rockchip sip
166 * version(default SIP_IMPLEMENT_V1) before use.
167 */
sip_smc_set_sip_version(unsigned long version)168 int sip_smc_set_sip_version(unsigned long version)
169 {
170 struct arm_smccc_res res;
171
172 res = __invoke_sip_fn_smc(SIP_SIP_VERSION, version, SECURE_REG_WR, 0);
173 if (IS_SIP_ERROR(res.a0)) {
174 printf("%s: set rockchip sip version v%ld failed\n",
175 __func__, version);
176 return res.a0;
177 }
178
179 return 0;
180 }
181
sip_smc_mcu_config(unsigned long mcu_id,unsigned long func,unsigned long arg2)182 int sip_smc_mcu_config(unsigned long mcu_id, unsigned long func, unsigned long arg2)
183 {
184 struct arm_smccc_res res;
185
186 res = __invoke_sip_fn_smc(SIP_MCU_CFG, mcu_id, func, arg2);
187 return res.a0;
188 }
189