2 * Copyright (C) 2013-2014 ROCKCHIP, Inc.
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.
9 #include <linux/crc32.h>
10 #include <linux/delay.h>
11 #include <linux/rockchip/cpu.h>
12 #include <linux/rockchip/iomap.h>
14 #include <linux/cpuidle.h>
15 #include <linux/init.h>
17 #include <linux/smp.h>
18 #include <linux/slab.h>
19 #include <linux/reboot.h>
21 #include <linux/delay.h>
22 #include <linux/slab.h>
23 #include <uapi/linux/psci.h>
25 #include <asm/compiler.h>
26 #include <asm/cpu_ops.h>
27 #include <asm/errno.h>
29 #include <asm/smp_plat.h>
30 #include <asm/suspend.h>
31 #include <asm/system_misc.h>
34 #include <asm/system_info.h>
39 #define efuse_readl(offset) readl_relaxed(RK_EFUSE_VIRT + offset)
40 #define efuse_writel(val, offset) writel_relaxed(val, RK_EFUSE_VIRT + offset)
42 static u8 efuse_buf[32] = {};
44 struct rockchip_efuse {
45 int (*get_leakage)(int ch);
46 int (*get_temp)(int ch);
51 static struct rockchip_efuse efuse;
55 /****************************secure reg access****************************/
57 #define SEC_REG_RW_SHT (0x0)
58 #define SEC_REG_RD (0x0)
59 #define SEC_REG_WR (0x1)
61 #define SEC_REG_BITS_SHT (0x1)
62 #define SEC_REG_32 (0x0)
63 #define SEC_REG_64 (0x2)
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)
70 #define PSCI_OS_ACCESS_REG (0xba00ffb0)
71 #define EFUSE_BASE 0xffb00000
73 * arg2: rd/wr control, bit[0] 0-rd 1-rt, bit[1] 0-32bit, 1-64bit
75 * arg0: read or write val
76 * function_id: return fail/succes
78 noinline int __invoke_reg_access_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2, u64 *val)
86 : "+r" (function_id), "+r" (arg0)
87 : "r" (arg1), "r" (arg2));
89 if(!(arg2 & SEC_REG_WR))
95 noinline int __invoke_reg_wr_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2)
103 : "+r" (function_id) ,"+r" (arg0)
104 : "r" (arg1), "r" (arg2));
109 noinline int __invoke_reg_rd_fn_smc(u64 function_id, u64 arg0, u64 arg1,
118 : "+r" (function_id) ,"+r" (arg0)
119 : "r" (arg1), "r" (arg2));
126 int (*invoke_regs_wr_fn)(u64, u64 , u64, u64) = __invoke_reg_wr_fn_smc;
128 int (*invoke_regs_rd_fn)(u64, u64 , u64, u64, u64 *) = __invoke_reg_rd_fn_smc;
131 int secure_regs_rd(u64 addr_phy)
136 ret = invoke_regs_rd_fn(PSCI_OS_ACCESS_REG, 0, addr_phy, SEC_REG_RD_32, &val_64);
141 int secure_regs_wr_32(u64 addr_phy, u32 val)
144 return invoke_regs_wr_fn(PSCI_OS_ACCESS_REG, val_64, addr_phy, SEC_REG_WR_32);
147 static int rk3368_efuse_readregs(u32 addr, u32 length, u8 *buf)
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);
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));
166 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
167 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) | EFUSE_STROBE);
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));
177 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
178 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) | EFUSE_CSB);
184 static int __init rk3288_efuse_readregs(u32 addr, u32 length, u8 *buf)
193 efuse_writel(EFUSE_CSB, REG_EFUSE_CTRL);
194 efuse_writel(EFUSE_LOAD | EFUSE_PGENB, REG_EFUSE_CTRL);
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),
203 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
204 EFUSE_STROBE, REG_EFUSE_CTRL);
206 *buf = efuse_readl(REG_EFUSE_DOUT);
207 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
208 (~EFUSE_STROBE), REG_EFUSE_CTRL);
214 efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_CSB, REG_EFUSE_CTRL);
220 static int __init rk3288_get_efuse_version(void)
222 int ret = efuse_buf[4] & (~(0x1 << 3));
226 static int __init rk3288_get_process_version(void)
228 int ret = efuse_buf[6]&0x0f;
233 static int rk3288_get_leakage(int ch)
235 if ((ch < 0) || (ch > 2))
238 return efuse_buf[23+ch];
242 static void __init rk3288_set_system_serial(void)
247 for (i = 0; i < 8; i++) {
248 buf[i] = efuse_buf[8 + (i << 1)];
249 buf[i + 8] = efuse_buf[7 + (i << 1)];
252 system_serial_low = crc32(0, buf, 8);
253 system_serial_high = crc32(system_serial_low, buf + 8, 8);
256 static inline void __init rk3288_set_system_serial(void) {}
259 int rk312x_efuse_readregs(u32 addr, u32 length, u8 *buf)
266 efuse_writel(EFUSE_LOAD, REG_EFUSE_CTRL);
269 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
270 (~(EFUSE_A_MASK << RK312X_EFUSE_A_SHIFT)),
272 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
273 ((addr & EFUSE_A_MASK) << RK312X_EFUSE_A_SHIFT),
276 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
277 EFUSE_STROBE, REG_EFUSE_CTRL);
279 *buf = efuse_readl(REG_EFUSE_DOUT);
280 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
281 (~EFUSE_STROBE), REG_EFUSE_CTRL);
287 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
288 (~EFUSE_LOAD) , REG_EFUSE_CTRL);
294 int rockchip_efuse_version(void)
296 return efuse.efuse_version;
299 int rockchip_process_version(void)
301 return efuse.process_version;
304 int rockchip_get_leakage(int ch)
307 if (efuse.get_leakage){
308 return efuse.get_leakage(ch);
310 ret = rk3368_efuse_readregs(0,32,efuse_buf);
312 return efuse_buf[23+ch];
317 int rockchip_efuse_get_temp_adjust(int ch)
321 ret = rk3368_efuse_readregs(0,32,efuse_buf);
323 temp = efuse_buf[31+ch];
324 if(efuse_buf[31+ch] & 0x80)
326 temp = -(efuse_buf[31+ch] & 0x7f);
333 void __init rockchip_efuse_init(void)
336 if (cpu_is_rk3288()) {
337 ret = rk3288_efuse_readregs(0, 32, efuse_buf);
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();
345 pr_err("failed to read eFuse, return %d\n", ret);
347 } else if (cpu_is_rk312x()) {
348 ret = rk312x_efuse_readregs(0, 32, efuse_buf);
350 efuse.get_leakage = rk3288_get_leakage;
352 pr_err("failed to read eFuse, return %d\n", ret);