firmware: rockchip: update sip interface
[firefly-linux-kernel-4.4.55.git] / drivers / firmware / rockchip_sip.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License version 2 as
4  * published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd
12  */
13
14 #include <linux/arm-smccc.h>
15 #include <linux/io.h>
16 #include <linux/rockchip/rockchip_sip.h>
17 #include <asm/cputype.h>
18 #include <asm/smp_plat.h>
19 #include <uapi/linux/psci.h>
20 #include <linux/ptrace.h>
21
22 #ifdef CONFIG_64BIT
23 #define PSCI_FN_NATIVE(version, name)   PSCI_##version##_FN64_##name
24 #else
25 #define PSCI_FN_NATIVE(version, name)   PSCI_##version##_FN_##name
26 #endif
27
28 #define SIZE_PAGE(n)    ((n) << 12)
29
30 static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id,
31                                                 unsigned long arg0,
32                                                 unsigned long arg1,
33                                                 unsigned long arg2)
34 {
35         struct arm_smccc_res res;
36
37         arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
38         return res;
39 }
40
41 struct arm_smccc_res sip_smc_ddr_cfg(u32 arg0, u32 arg1, u32 arg2)
42 {
43         return __invoke_sip_fn_smc(SIP_DDR_CFG, arg0, arg1, arg2);
44 }
45
46 struct arm_smccc_res sip_smc_get_atf_version(void)
47 {
48         return __invoke_sip_fn_smc(SIP_ATF_VERSION, 0, 0, 0);
49 }
50
51 struct arm_smccc_res sip_smc_get_sip_version(void)
52 {
53         return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0);
54 }
55
56 int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 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_virtual_poweroff(void)
65 {
66         struct arm_smccc_res res;
67
68         res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 0, 0, 0);
69         return res.a0;
70 }
71
72 u32 sip_smc_secure_reg_read(u32 addr_phy)
73 {
74         struct arm_smccc_res res;
75
76         res = __invoke_sip_fn_smc(SIP_ACCESS_REG, 0, addr_phy, SECURE_REG_RD);
77         if (res.a0)
78                 pr_err("%s error: %d, addr phy: 0x%x\n",
79                        __func__, (int)res.a0, addr_phy);
80
81         return res.a1;
82 }
83
84 int sip_smc_secure_reg_write(u32 addr_phy, u32 val)
85 {
86         struct arm_smccc_res res;
87
88         res = __invoke_sip_fn_smc(SIP_ACCESS_REG, val, addr_phy, SECURE_REG_WR);
89         if (res.a0)
90                 pr_err("%s error: %d, addr phy: 0x%x\n",
91                        __func__, (int)res.a0, addr_phy);
92
93         return res.a0;
94 }
95
96 struct arm_smccc_res sip_smc_request_share_mem(u32 page_num,
97                                                share_page_type_t page_type)
98 {
99         struct arm_smccc_res res;
100         unsigned long share_mem_phy;
101
102         res = __invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0);
103         if (IS_SIP_ERROR(res.a0))
104                 goto error;
105
106         share_mem_phy = res.a1;
107         res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num));
108
109 error:
110         return res;
111 }
112
113 struct arm_smccc_res sip_smc_mcu_el3fiq(u32 arg0, u32 arg1, u32 arg2)
114 {
115         return __invoke_sip_fn_smc(SIP_MCU_EL3FIQ_CFG, arg0, arg1, arg2);
116 }
117
118 /************************** fiq debugger **************************************/
119 #ifdef CONFIG_ARM64
120 #define SIP_UARTDBG_FN          SIP_UARTDBG_CFG64
121 #else
122 #define SIP_UARTDBG_FN          SIP_UARTDBG_CFG
123 #endif
124
125 static int fiq_sip_enabled;
126 static int fiq_target_cpu;
127 static phys_addr_t ft_fiq_mem_phy;
128 static void __iomem *ft_fiq_mem_base;
129 static void (*sip_fiq_debugger_uart_irq_tf)(struct pt_regs _pt_regs,
130                                             unsigned long cpu);
131 int sip_fiq_debugger_is_enabled(void)
132 {
133         return fiq_sip_enabled;
134 }
135
136 static struct pt_regs sip_fiq_debugger_get_pt_regs(void *reg_base,
137                                                    unsigned long sp_el1)
138 {
139         struct pt_regs fiq_pt_regs;
140
141 #ifdef CONFIG_ARM64
142         /* copy cpu context */
143         memcpy(&fiq_pt_regs, reg_base, 8 * 31);
144
145         /* copy pstate */
146         memcpy(&fiq_pt_regs.pstate, reg_base + 0x110, 8);
147
148         /* EL1 mode */
149         if (fiq_pt_regs.pstate & 0x10)
150                 memcpy(&fiq_pt_regs.sp, reg_base + 0xf8, 8);
151         /* EL0 mode */
152         else
153                 fiq_pt_regs.sp = sp_el1;
154
155         /* copy pc */
156         memcpy(&fiq_pt_regs.pc, reg_base + 0x118, 8);
157 #else
158         struct sm_nsec_ctx *nsec_ctx = reg_base;
159
160         fiq_pt_regs.ARM_r0 = nsec_ctx->r0;
161         fiq_pt_regs.ARM_r1 = nsec_ctx->r1;
162         fiq_pt_regs.ARM_r2 = nsec_ctx->r2;
163         fiq_pt_regs.ARM_r3 = nsec_ctx->r3;
164         fiq_pt_regs.ARM_r4 = nsec_ctx->r4;
165         fiq_pt_regs.ARM_r5 = nsec_ctx->r5;
166         fiq_pt_regs.ARM_r6 = nsec_ctx->r6;
167         fiq_pt_regs.ARM_r7 = nsec_ctx->r7;
168         fiq_pt_regs.ARM_r8 = nsec_ctx->r8;
169         fiq_pt_regs.ARM_r9 = nsec_ctx->r9;
170         fiq_pt_regs.ARM_r10 = nsec_ctx->r10;
171         fiq_pt_regs.ARM_fp = nsec_ctx->r11;
172         fiq_pt_regs.ARM_ip = nsec_ctx->r12;
173         fiq_pt_regs.ARM_sp = nsec_ctx->svc_sp;
174         fiq_pt_regs.ARM_lr = nsec_ctx->svc_lr;
175         fiq_pt_regs.ARM_pc = nsec_ctx->mon_lr;
176         fiq_pt_regs.ARM_cpsr = nsec_ctx->mon_spsr;
177 #endif
178
179         return fiq_pt_regs;
180 }
181
182 static void sip_fiq_debugger_uart_irq_tf_cb(unsigned long sp_el1,
183                                             unsigned long offset,
184                                             unsigned long cpu)
185 {
186         struct pt_regs fiq_pt_regs;
187         char *cpu_context;
188
189         /* calling fiq handler */
190         if (ft_fiq_mem_base) {
191                 cpu_context = (char *)ft_fiq_mem_base + offset;
192                 fiq_pt_regs = sip_fiq_debugger_get_pt_regs(cpu_context, sp_el1);
193                 sip_fiq_debugger_uart_irq_tf(fiq_pt_regs, cpu);
194         }
195
196         /* fiq handler done, return to EL3(then EL3 return to EL1 entry) */
197         __invoke_sip_fn_smc(SIP_UARTDBG_FN, 0, 0, UARTDBG_CFG_OSHDL_TO_OS);
198 }
199
200 int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback_fn)
201 {
202         struct arm_smccc_res res;
203
204         fiq_target_cpu = 0;
205
206         /* init fiq debugger callback */
207         sip_fiq_debugger_uart_irq_tf = callback_fn;
208         res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, irq_id,
209                                   (unsigned long)sip_fiq_debugger_uart_irq_tf_cb,
210                                   UARTDBG_CFG_INIT);
211         if (IS_SIP_ERROR(res.a0)) {
212                 pr_err("%s error: %d\n", __func__, (int)res.a0);
213                 return res.a0;
214         }
215
216         /* share memory ioremap */
217         if (!ft_fiq_mem_base) {
218                 ft_fiq_mem_phy = res.a1;
219                 ft_fiq_mem_base = ioremap(ft_fiq_mem_phy,
220                                           FIQ_UARTDBG_SHARE_MEM_SIZE);
221                 if (!ft_fiq_mem_base) {
222                         pr_err("%s: share memory ioremap failed\n", __func__);
223                         return -ENOMEM;
224                 }
225         }
226
227         fiq_sip_enabled = 1;
228
229         return SIP_RET_SUCCESS;
230 }
231
232 int sip_fiq_debugger_switch_cpu(u32 cpu)
233 {
234         struct arm_smccc_res res;
235
236         fiq_target_cpu = cpu;
237         res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, cpu_logical_map(cpu),
238                                   0, UARTDBG_CFG_OSHDL_CPUSW);
239         return res.a0;
240 }
241
242 void sip_fiq_debugger_enable_debug(bool enable)
243 {
244         unsigned long val;
245
246         val = enable ? UARTDBG_CFG_OSHDL_DEBUG_ENABLE :
247                        UARTDBG_CFG_OSHDL_DEBUG_DISABLE;
248
249         __invoke_sip_fn_smc(SIP_UARTDBG_FN, 0, 0, val);
250 }
251
252 int sip_fiq_debugger_set_print_port(u32 port_phyaddr, u32 baudrate)
253 {
254         struct arm_smccc_res res;
255
256         res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, port_phyaddr, baudrate,
257                                   UARTDBG_CFG_PRINT_PORT);
258         return res.a0;
259 }
260
261 int sip_fiq_debugger_request_share_memory(void)
262 {
263         struct arm_smccc_res res;
264
265         /* request page share memory */
266         res = sip_smc_request_share_mem(FIQ_UARTDBG_PAGE_NUMS,
267                                         SHARE_PAGE_TYPE_UARTDBG);
268         if (IS_SIP_ERROR(res.a0))
269                 return res.a0;
270
271         return SIP_RET_SUCCESS;
272 }
273
274 int sip_fiq_debugger_get_target_cpu(void)
275 {
276         return fiq_target_cpu;
277 }
278
279 void sip_fiq_debugger_enable_fiq(bool enable, uint32_t tgt_cpu)
280 {
281         u32 en;
282
283         fiq_target_cpu = tgt_cpu;
284         en = enable ? UARTDBG_CFG_FIQ_ENABEL : UARTDBG_CFG_FIQ_DISABEL;
285         __invoke_sip_fn_smc(SIP_UARTDBG_FN, tgt_cpu, 0, en);
286 }
287