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>
13 #include <asm/compiler.h>
16 #include <asm/system_info.h>
20 #define efuse_readl(offset) readl_relaxed(RK_EFUSE_VIRT + offset)
21 #define efuse_writel(val, offset) writel_relaxed(val, RK_EFUSE_VIRT + offset)
23 static u8 efuse_buf[32] = {};
25 struct rockchip_efuse {
26 int (*get_leakage)(int ch);
27 int (*get_temp)(int ch);
32 static struct rockchip_efuse efuse;
35 /****************************secure reg access****************************/
37 #define SEC_REG_RW_SHT (0x0)
38 #define SEC_REG_RD (0x0)
39 #define SEC_REG_WR (0x1)
41 #define SEC_REG_BITS_SHT (0x1)
42 #define SEC_REG_32 (0x0)
43 #define SEC_REG_64 (0x2)
45 #define SEC_REG_RD_32 (SEC_REG_RD | SEC_REG_32)
46 #define SEC_REG_RD_64 (SEC_REG_RD | SEC_REG_64)
47 #define SEC_REG_WR_32 (SEC_REG_WR | SEC_REG_32)
48 #define SEC_REG_WR_64 (SEC_REG_WR | SEC_REG_64)
50 #define PSCI_OS_ACCESS_REG (0xa600ffb0)
51 #define EFUSE_BASE 0xffb00000
53 * arg2: rd/wr control, bit[0] 0-rd 1-rt, bit[1] 0-32bit, 1-64bit
55 * arg0: read or write val
56 * function_id: return fail/succes
58 noinline int __invoke_reg_access_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2, u64 *val)
66 : "+r" (function_id), "+r" (arg0)
67 : "r" (arg1), "r" (arg2));
69 if(!(arg2 & SEC_REG_WR))
75 noinline int __invoke_reg_wr_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2)
83 : "+r" (function_id) ,"+r" (arg0)
84 : "r" (arg1), "r" (arg2));
89 noinline int __invoke_reg_rd_fn_smc(u64 function_id, u64 arg0, u64 arg1,
98 : "+r" (function_id) ,"+r" (arg0)
99 : "r" (arg1), "r" (arg2));
106 int (*invoke_regs_wr_fn)(u64, u64 , u64, u64) = __invoke_reg_wr_fn_smc;
108 int (*invoke_regs_rd_fn)(u64, u64 , u64, u64, u64 *) = __invoke_reg_rd_fn_smc;
111 int secure_regs_rd(u64 addr_phy)
116 ret = invoke_regs_rd_fn(PSCI_OS_ACCESS_REG, 0, addr_phy, SEC_REG_RD_32, &val_64);
121 int secure_regs_wr_32(u64 addr_phy, u32 val)
124 return invoke_regs_wr_fn(PSCI_OS_ACCESS_REG, val_64, addr_phy, SEC_REG_WR_32);
127 static int rk3368_efuse_readregs(u32 addr, u32 length, u8 *buf)
135 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL , EFUSE_CSB);
136 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL , EFUSE_LOAD | EFUSE_PGENB);
139 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
140 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) &
141 (~(EFUSE_A_MASK << EFUSE_A_SHIFT)));
142 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL,
143 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) |
144 ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT));
146 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
147 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) | EFUSE_STROBE);
149 *buf = secure_regs_rd(EFUSE_BASE+REG_EFUSE_DOUT);
150 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
151 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) & (~EFUSE_STROBE));
157 secure_regs_wr_32(EFUSE_BASE+REG_EFUSE_CTRL ,
158 secure_regs_rd(EFUSE_BASE+REG_EFUSE_CTRL) | EFUSE_CSB);
164 static int rk3368_efuse_readregs(u32 addr, u32 length, u8 *buf)
170 static int __init rk3288_efuse_readregs(u32 addr, u32 length, u8 *buf)
179 efuse_writel(EFUSE_CSB, REG_EFUSE_CTRL);
180 efuse_writel(EFUSE_LOAD | EFUSE_PGENB, REG_EFUSE_CTRL);
183 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
184 (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), REG_EFUSE_CTRL);
185 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
186 ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
189 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
190 EFUSE_STROBE, REG_EFUSE_CTRL);
192 *buf = efuse_readl(REG_EFUSE_DOUT);
193 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
194 (~EFUSE_STROBE), REG_EFUSE_CTRL);
200 efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_CSB, REG_EFUSE_CTRL);
206 static int __init rk3288_get_efuse_version(void)
208 int ret = efuse_buf[4] & (~(0x1 << 3));
212 static int __init rk3288_get_process_version(void)
214 int ret = efuse_buf[6]&0x0f;
219 static int rk3288_get_leakage(int ch)
221 if ((ch < 0) || (ch > 2))
224 return efuse_buf[23+ch];
228 static void __init rk3288_set_system_serial(void)
233 for (i = 0; i < 8; i++) {
234 buf[i] = efuse_buf[8 + (i << 1)];
235 buf[i + 8] = efuse_buf[7 + (i << 1)];
238 system_serial_low = crc32(0, buf, 8);
239 system_serial_high = crc32(system_serial_low, buf + 8, 8);
242 static inline void __init rk3288_set_system_serial(void) {}
245 int rk312x_efuse_readregs(u32 addr, u32 length, u8 *buf)
252 efuse_writel(EFUSE_LOAD, REG_EFUSE_CTRL);
255 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
256 (~(EFUSE_A_MASK << RK312X_EFUSE_A_SHIFT)),
258 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
259 ((addr & EFUSE_A_MASK) << RK312X_EFUSE_A_SHIFT),
262 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
263 EFUSE_STROBE, REG_EFUSE_CTRL);
265 *buf = efuse_readl(REG_EFUSE_DOUT);
266 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
267 (~EFUSE_STROBE), REG_EFUSE_CTRL);
273 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
274 (~EFUSE_LOAD) , REG_EFUSE_CTRL);
280 int rockchip_efuse_version(void)
282 return efuse.efuse_version;
285 int rockchip_process_version(void)
287 return efuse.process_version;
290 int rockchip_get_leakage(int ch)
293 if (efuse.get_leakage){
294 return efuse.get_leakage(ch);
296 ret = rk3368_efuse_readregs(0,32,efuse_buf);
298 return efuse_buf[23+ch];
303 int rockchip_efuse_get_temp_adjust(int ch)
307 ret = rk3368_efuse_readregs(0,32,efuse_buf);
309 temp = efuse_buf[31+ch];
310 if(efuse_buf[31+ch] & 0x80)
312 temp = -(efuse_buf[31+ch] & 0x7f);
319 void __init rockchip_efuse_init(void)
322 if (cpu_is_rk3288()) {
323 ret = rk3288_efuse_readregs(0, 32, efuse_buf);
325 efuse.get_leakage = rk3288_get_leakage;
326 efuse.efuse_version = rk3288_get_efuse_version();
327 efuse.process_version = rk3288_get_process_version();
328 rockchip_set_cpu_version((efuse_buf[6] >> 4) & 3);
329 rk3288_set_system_serial();
331 pr_err("failed to read eFuse, return %d\n", ret);
333 } else if (cpu_is_rk312x()) {
334 ret = rk312x_efuse_readregs(0, 32, efuse_buf);
336 efuse.get_leakage = rk3288_get_leakage;
338 pr_err("failed to read eFuse, return %d\n", ret);