ARM: rockchip: psci support arch32 and arch64 smc call
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / psci.c
1 /*
2  * arch/arm/mach-rockchip/psci.c
3  *
4  * PSCI call interface for rockchip
5  *
6  * Copyright (C) 2015 ROCKCHIP, Inc.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17
18 #include <linux/of.h>
19 #include <linux/types.h>
20 #include <linux/rockchip/psci.h>
21 #include <asm/compiler.h>
22 #include <asm/smp_plat.h>
23 #ifdef CONFIG_ARM
24 #include <asm/opcodes-sec.h>
25 #endif
26
27 /*
28  * SMC32 id call made from arch32 or arch64
29  */
30 static u32 reg_rd_fn_smc(u32 function_id, u32 arg0, u32 arg1,
31                          u32 arg2, u32 *val)
32 {
33         asm volatile(
34 #ifdef CONFIG_ARM
35                         __asmeq("%0", "r0")
36                         __asmeq("%1", "r1")
37                         __asmeq("%2", "r2")
38                         __asmeq("%3", "r3")
39                         __SMC(0)
40 #else
41                         __asmeq("%w0", "w0")
42                         __asmeq("%w1", "w1")
43                         __asmeq("%w2", "w2")
44                         __asmeq("%w3", "w3")
45                         "smc    #0\n"
46 #endif
47                 : "+r" (function_id), "+r" (arg0)
48                 : "r" (arg1), "r" (arg2));
49
50
51                 if (val)
52                         *val = arg0;
53
54         return function_id;
55 }
56
57 /*
58  * SMC32 id call made from arch32 or arch64
59  */
60 static u32 reg_wr_fn_smc(u32 function_id, u32 arg0,
61                          u32 arg1, u32 arg2)
62 {
63         asm volatile(
64 #ifdef CONFIG_ARM
65                         __asmeq("%0", "r0")
66                         __asmeq("%1", "r1")
67                         __asmeq("%2", "r2")
68                         __asmeq("%3", "r3")
69                         __SMC(0)
70 #else
71                         __asmeq("%w0", "w0")
72                         __asmeq("%w1", "w1")
73                         __asmeq("%w2", "w2")
74                         __asmeq("%w3", "w3")
75                         "smc    #0\n"
76 #endif
77                 : "+r" (function_id), "+r" (arg0)
78                 : "r" (arg1), "r" (arg2));
79
80         return function_id;
81 }
82
83 static u32 (*reg_wr_fn)(u32, u32, u32, u32) = reg_wr_fn_smc;
84 static u32 (*reg_rd_fn)(u32, u32, u32, u32, u32 *) = reg_rd_fn_smc;
85
86
87 #ifdef CONFIG_ARM64
88
89 /*
90  * SMC64 id call only made from arch64
91  */
92 static u32 reg_rd_fn_smc64(u64 function_id, u64 arg0, u64 arg1, u64 arg2,
93                            u64 *val)
94 {
95         asm volatile(
96                         __asmeq("%0", "x0")
97                         __asmeq("%1", "x1")
98                         __asmeq("%2", "x2")
99                         __asmeq("%3", "x3")
100                         "smc    #0\n"
101                 : "+r" (function_id), "+r" (arg0)
102                 : "r" (arg1), "r" (arg2));
103
104                 if (val)
105                         *val = arg0;
106
107         return function_id;
108 }
109
110 /*
111  * SMC64 id call only made from Arch64
112  */
113 static u32 reg_wr_fn_smc64(u64 function_id, u64 arg0, u64 arg1, u64 arg2)
114 {
115         asm volatile(
116                         __asmeq("%0", "x0")
117                         __asmeq("%1", "x1")
118                         __asmeq("%2", "x2")
119                         __asmeq("%3", "x3")
120                         "smc    #0\n"
121                 : "+r" (function_id), "+r" (arg0)
122                 : "r" (arg1), "r" (arg2));
123
124         return function_id;
125 }
126
127 static u32 (*reg_wr_fn64)(u64, u64, u64, u64) = reg_wr_fn_smc64;
128 static u32 (*reg_rd_fn64)(u64, u64, u64, u64, u64 *) = reg_rd_fn_smc64;
129
130 u32 rockchip_psci_smc_read64(u64 function_id, u64 arg0, u64 arg1, u64 arg2,
131                              u64 *val)
132 {
133         return reg_rd_fn64(function_id, arg0, arg1, arg2, val);
134 }
135
136 u32 rockchip_psci_smc_write64(u64 function_id, u64 arg0, u64 arg1, u64 arg2)
137 {
138         return reg_wr_fn64(function_id, arg0, arg1, arg2);
139 }
140
141 u64 rockchip_secure_reg_read64(u64 addr_phy)
142 {
143         u64 val;
144
145         reg_rd_fn64(PSCI_SIP_ACCESS_REG64, 0, addr_phy, SEC_REG_RD, &val);
146
147         return val;
148 }
149
150 u32 rockchip_secure_reg_write64(u64 addr_phy, u64 val)
151 {
152         return reg_wr_fn64(PSCI_SIP_ACCESS_REG64, val, addr_phy, SEC_REG_WR);
153 }
154
155 #endif /*CONFIG_ARM64*/
156
157 u32 rockchip_psci_smc_read(u32 function_id, u32 arg0, u32 arg1, u32 arg2,
158                            u32 *val)
159 {
160         return reg_rd_fn(function_id, arg0, arg1, arg2, val);
161 }
162
163 u32 rockchip_psci_smc_write(u32 function_id, u32 arg0, u32 arg1, u32 arg2)
164 {
165         return reg_wr_fn(function_id, arg0, arg1, arg2);
166 }
167
168 u32 rockchip_secure_reg_read(u32 addr_phy)
169 {
170         u32 val = 0;
171
172         reg_rd_fn(PSCI_SIP_ACCESS_REG, 0, addr_phy, SEC_REG_RD, &val);
173
174         return val;
175 }
176
177 u32 rockchip_secure_reg_write(u32 addr_phy, u32 val)
178 {
179         return reg_wr_fn(PSCI_SIP_ACCESS_REG, val, addr_phy, SEC_REG_WR);
180 }
181
182 /*
183  * get trust firmware verison
184  */
185 u32 rockchip_psci_smc_get_tf_ver(void)
186 {
187         return reg_rd_fn(PSCI_SIP_RKTF_VER, 0, 0, 0, NULL);
188 }
189
190 /*************************** fiq debug *****************************/
191 #ifdef CONFIG_ARM64
192 static u64 ft_fiq_mem_phy;
193 static void __iomem *ft_fiq_mem_base;
194 static void (*psci_fiq_debugger_uart_irq_tf)(void *reg_base, u64 sp_el1);
195
196 void psci_fiq_debugger_uart_irq_tf_cb(u64 sp_el1, u64 offset)
197 {
198         psci_fiq_debugger_uart_irq_tf((char *)ft_fiq_mem_base + offset, sp_el1);
199         reg_wr_fn64(PSCI_SIP_UARTDBG_CFG64, 0, 0, UARTDBG_CFG_OSHDL_TO_OS);
200 }
201
202 void psci_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback)
203 {
204         psci_fiq_debugger_uart_irq_tf = callback;
205         ft_fiq_mem_phy = reg_wr_fn64(PSCI_SIP_UARTDBG_CFG64, irq_id,
206                                      (u64)psci_fiq_debugger_uart_irq_tf_cb,
207                                      UARTDBG_CFG_INIT);
208         ft_fiq_mem_base = ioremap(ft_fiq_mem_phy, 8 * 1024);
209 }
210
211 u32 psci_fiq_debugger_switch_cpu(u32 cpu)
212 {
213         return reg_wr_fn64(PSCI_SIP_UARTDBG_CFG64, cpu_logical_map(cpu),
214                            0, UARTDBG_CFG_OSHDL_CPUSW);
215 }
216
217 void psci_fiq_debugger_enable_debug(bool val)
218 {
219         if (val)
220                 reg_wr_fn64(PSCI_SIP_UARTDBG_CFG64, 0,
221                             0, UARTDBG_CFG_OSHDL_DEBUG_ENABLE);
222         else
223                 reg_wr_fn64(PSCI_SIP_UARTDBG_CFG64, 0,
224                             0, UARTDBG_CFG_OSHDL_DEBUG_DISABLE);
225 }
226 #endif