rk3368: efuse: change efuse get temp func
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / efuse.c
1 /*
2  * Copyright (C) 2013-2014 ROCKCHIP, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include <linux/crc32.h>
10 #include <linux/delay.h>
11 #include <linux/rockchip/cpu.h>
12 #include <linux/rockchip/iomap.h>
13
14 #include <linux/cpuidle.h>
15 #include <linux/init.h>
16 #include <linux/of.h>
17 #include <linux/smp.h>
18 #include <linux/slab.h>
19 #include <linux/reboot.h>
20 #include <linux/pm.h>
21 #include <linux/delay.h>
22 #include <linux/slab.h>
23 #include <uapi/linux/psci.h>
24
25 #include <asm/compiler.h>
26 #include <asm/cpu_ops.h>
27 #include <asm/errno.h>
28 #include <asm/psci.h>
29 #include <asm/smp_plat.h>
30 #include <asm/suspend.h>
31 #include <asm/system_misc.h>
32
33 #ifdef CONFIG_ARM
34 #include <asm/system_info.h>
35 #endif
36 #include "efuse.h"
37
38
39 #define efuse_readl(offset) readl_relaxed(RK_EFUSE_VIRT + offset)
40 #define efuse_writel(val, offset) writel_relaxed(val, RK_EFUSE_VIRT + offset)
41
42 static u8 efuse_buf[32] = {};
43
44 struct rockchip_efuse {
45         int (*get_leakage)(int ch);
46         int (*get_temp)(int ch);
47         int efuse_version;
48         int process_version;
49 };
50
51 static struct rockchip_efuse efuse;
52
53
54
55 /****************************secure reg access****************************/
56
57 #define SEC_REG_RW_SHT (0x0)
58 #define SEC_REG_RD (0x0)
59 #define SEC_REG_WR (0x1)
60
61 #define SEC_REG_BITS_SHT (0x1)
62 #define SEC_REG_32 (0x0)
63 #define SEC_REG_64 (0x2)
64
65 #define SEC_REG_RD_32 (SEC_REG_RD | SEC_REG_32)
66 #define SEC_REG_RD_64 (SEC_REG_RD | SEC_REG_64)
67 #define SEC_REG_WR_32 (SEC_REG_WR | SEC_REG_32)
68 #define SEC_REG_WR_64 (SEC_REG_WR | SEC_REG_64)
69
70 #define PSCI_OS_ACCESS_REG              (0xba00ffb0)
71 #define EFUSE_BASE        0xffb00000
72 /*
73  * arg2: rd/wr control, bit[0] 0-rd 1-rt, bit[1] 0-32bit, 1-64bit
74  * arg1: base addr
75  * arg0: read or write val
76  * function_id: return fail/succes
77  */
78 noinline int __invoke_reg_access_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2, u64 *val)
79 {
80         asm volatile(
81                         __asmeq("%0", "x0")
82                         __asmeq("%1", "x1")
83                         __asmeq("%2", "x2")
84                         __asmeq("%3", "x3")
85                         "hvc    #0\n"
86                 : "+r" (function_id), "+r" (arg0)
87                 : "r" (arg1), "r" (arg2));
88
89         if(!(arg2 & SEC_REG_WR))
90                 *val = arg0;
91
92         return function_id;
93 }
94
95 noinline int __invoke_reg_wr_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2)
96 {
97         asm volatile(
98                         __asmeq("%0", "x0")
99                         __asmeq("%1", "x1")
100                         __asmeq("%2", "x2")
101                         __asmeq("%3", "x3")
102                         "smc    #0\n"
103                 : "+r" (function_id) ,"+r" (arg0)
104                 : "r" (arg1), "r" (arg2));
105
106         return function_id;
107 }
108
109 noinline int __invoke_reg_rd_fn_smc(u64 function_id, u64 arg0, u64 arg1,
110                                          u64 arg2, u64 *val)
111 {
112         asm volatile(
113                         __asmeq("%0", "x0")
114                         __asmeq("%1", "x1")
115                         __asmeq("%2", "x2")
116                         __asmeq("%3", "x3")
117                         "smc    #0\n"
118                 : "+r" (function_id) ,"+r" (arg0)
119                 : "r" (arg1), "r" (arg2));
120
121                 *val = arg0;
122
123         return function_id;
124 }
125
126 int (*invoke_regs_wr_fn)(u64, u64 , u64, u64) = __invoke_reg_wr_fn_smc;
127
128 int (*invoke_regs_rd_fn)(u64, u64 , u64, u64, u64 *) = __invoke_reg_rd_fn_smc;
129
130
131 int secure_regs_rd(u64 addr_phy)
132 {
133         u64 val_64;
134         u32 val;
135         int ret;
136         ret = invoke_regs_rd_fn(PSCI_OS_ACCESS_REG, 0, addr_phy, SEC_REG_RD_32, &val_64);
137         val = val_64;
138         return val;
139 }
140
141 int secure_regs_wr_32(u64 addr_phy, u32 val)
142 {
143         u64 val_64 = val;
144         return invoke_regs_wr_fn(PSCI_OS_ACCESS_REG, val_64, addr_phy, SEC_REG_WR_32);
145 }
146
147 static int __init rk3368_efuse_readregs(u32 addr, u32 length, u8 *buf)
148 {
149         int ret = length;
150                 if (!length)
151                 return 0;
152         if (!buf)
153                 return 0;
154
155         secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL , EFUSE_CSB);
156         secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL , EFUSE_LOAD | EFUSE_PGENB);
157         udelay(2);
158         do {
159                 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
160                                 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) &
161                                         (~(EFUSE_A_MASK << EFUSE_A_SHIFT)));
162                 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL,
163                                 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) |
164                                                 ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT));
165                 udelay(2);
166                 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
167                                 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) | EFUSE_STROBE);
168                 udelay(2);
169                 *buf = secure_regs_rd(EFUSE_BASE+REG_EFUSE_DOUT);
170                 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
171                                 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) & (~EFUSE_STROBE));
172                 udelay(2);
173                 buf++;
174                 addr++;
175         } while (--length);
176         udelay(2);
177         secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
178                         secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) | EFUSE_CSB);
179         udelay(1);
180
181         return ret;
182 }
183
184 static int __init rk3288_efuse_readregs(u32 addr, u32 length, u8 *buf)
185 {
186         int ret = length;
187
188         if (!length)
189                 return 0;
190         if (!buf)
191                 return 0;
192
193         efuse_writel(EFUSE_CSB, REG_EFUSE_CTRL);
194         efuse_writel(EFUSE_LOAD | EFUSE_PGENB, REG_EFUSE_CTRL);
195         udelay(2);
196         do {
197                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
198                         (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), REG_EFUSE_CTRL);
199                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
200                         ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
201                         REG_EFUSE_CTRL);
202                 udelay(2);
203                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
204                                 EFUSE_STROBE, REG_EFUSE_CTRL);
205                 udelay(2);
206                 *buf = efuse_readl(REG_EFUSE_DOUT);
207                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
208                                 (~EFUSE_STROBE), REG_EFUSE_CTRL);
209                 udelay(2);
210                 buf++;
211                 addr++;
212         } while (--length);
213         udelay(2);
214         efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_CSB, REG_EFUSE_CTRL);
215         udelay(1);
216
217         return ret;
218 }
219
220 static int __init rk3288_get_efuse_version(void)
221 {
222         int ret = efuse_buf[4] & (~(0x1 << 3));
223         return ret;
224 }
225
226 static int __init rk3288_get_process_version(void)
227 {
228         int ret = efuse_buf[6]&0x0f;
229
230         return ret;
231 }
232
233 static int rk3288_get_leakage(int ch)
234 {
235         if ((ch < 0) || (ch > 2))
236                 return 0;
237
238         return efuse_buf[23+ch];
239 }
240
241 #ifdef CONFIG_ARM
242 static void __init rk3288_set_system_serial(void)
243 {
244         int i;
245         u8 buf[16];
246
247         for (i = 0; i < 8; i++) {
248                 buf[i] = efuse_buf[8 + (i << 1)];
249                 buf[i + 8] = efuse_buf[7 + (i << 1)];
250         }
251
252         system_serial_low = crc32(0, buf, 8);
253         system_serial_high = crc32(system_serial_low, buf + 8, 8);
254 }
255 #else
256 static inline void __init rk3288_set_system_serial(void) {}
257 #endif
258
259 int rk312x_efuse_readregs(u32 addr, u32 length, u8 *buf)
260 {
261         int ret = length;
262
263         if (!length)
264                 return 0;
265
266         efuse_writel(EFUSE_LOAD, REG_EFUSE_CTRL);
267         udelay(2);
268         do {
269                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
270                                 (~(EFUSE_A_MASK << RK312X_EFUSE_A_SHIFT)),
271                                 REG_EFUSE_CTRL);
272                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
273                                 ((addr & EFUSE_A_MASK) << RK312X_EFUSE_A_SHIFT),
274                                 REG_EFUSE_CTRL);
275                 udelay(2);
276                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
277                                 EFUSE_STROBE, REG_EFUSE_CTRL);
278                 udelay(2);
279                 *buf = efuse_readl(REG_EFUSE_DOUT);
280                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
281                                 (~EFUSE_STROBE), REG_EFUSE_CTRL);
282                 udelay(2);
283                 buf++;
284                 addr++;
285         } while (--length);
286         udelay(2);
287         efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
288                         (~EFUSE_LOAD) , REG_EFUSE_CTRL);
289         udelay(1);
290
291         return ret;
292 }
293
294 int rockchip_efuse_version(void)
295 {
296         return efuse.efuse_version;
297 }
298
299 int rockchip_process_version(void)
300 {
301         return efuse.process_version;
302 }
303
304 int rockchip_get_leakage(int ch)
305 {
306         int ret = 0;
307         if (efuse.get_leakage){
308                 return efuse.get_leakage(ch);
309         }else{
310                 ret = rk3368_efuse_readregs(0,32,efuse_buf);
311                 if (ret == 32){
312                         return efuse_buf[23+ch];
313                 }
314         }
315         return 0;
316 }
317 int rockchip_efuse_get_temp(int ch)
318 {
319         int ret = 0;
320         int temp = 0;
321         ret = rk3368_efuse_readregs(0,32,efuse_buf);
322         if (ret == 32){
323                 temp = efuse_buf[31+ch];
324                 if(efuse_buf[31+ch] & 0x80)
325                 {
326                         temp = -(efuse_buf[31+ch] & 0x7f);
327                 }
328                 return temp;
329         }
330         return 0;
331 }
332
333 void __init rockchip_efuse_init(void)
334 {
335         int ret;
336         if (cpu_is_rk3288()) {
337                 ret = rk3288_efuse_readregs(0, 32, efuse_buf);
338                 if (ret == 32) {
339                         efuse.get_leakage = rk3288_get_leakage;
340                         efuse.efuse_version = rk3288_get_efuse_version();
341                         efuse.process_version = rk3288_get_process_version();
342                         rockchip_set_cpu_version((efuse_buf[6] >> 4) & 3);
343                         rk3288_set_system_serial();
344                 } else {
345                         pr_err("failed to read eFuse, return %d\n", ret);
346                 }
347         } else if (cpu_is_rk312x()) {
348                 ret = rk312x_efuse_readregs(0, 32, efuse_buf);
349                 if (ret == 32)
350                         efuse.get_leakage = rk3288_get_leakage;
351                 else
352                         pr_err("failed to read eFuse, return %d\n", ret);
353         }
354 }