efuse: add rk312x_efuse_readregs()
[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 #include <asm/system_info.h>
14 #include "efuse.h"
15
16 #define efuse_readl(offset) readl_relaxed(RK_EFUSE_VIRT + offset)
17 #define efuse_writel(val, offset) writel_relaxed(val, RK_EFUSE_VIRT + offset)
18
19 static u8 efuse_buf[32] = {};
20
21 struct rockchip_efuse {
22         int (*get_leakage)(int ch);
23         int efuse_version;
24         int process_version;
25 };
26
27 static struct rockchip_efuse efuse;
28
29 static int __init rk3288_efuse_readregs(u32 addr, u32 length, u8 *buf)
30 {
31         int ret = length;
32
33         if (!length)
34                 return 0;
35         if (!buf)
36                 return 0;
37
38         efuse_writel(EFUSE_CSB, REG_EFUSE_CTRL);
39         efuse_writel(EFUSE_LOAD | EFUSE_PGENB, REG_EFUSE_CTRL);
40         udelay(2);
41         do {
42                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
43                         (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), REG_EFUSE_CTRL);
44                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
45                         ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
46                         REG_EFUSE_CTRL);
47                 udelay(2);
48                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
49                                 EFUSE_STROBE, REG_EFUSE_CTRL);
50                 udelay(2);
51                 *buf = efuse_readl(REG_EFUSE_DOUT);
52                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
53                                 (~EFUSE_STROBE), REG_EFUSE_CTRL);
54                 udelay(2);
55                 buf++;
56                 addr++;
57         } while (--length);
58         udelay(2);
59         efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_CSB, REG_EFUSE_CTRL);
60         udelay(1);
61
62         return ret;
63 }
64
65 static int __init rk3288_get_efuse_version(void)
66 {
67         int ret = efuse_buf[4] & (~(0x1 << 3));
68         return ret;
69 }
70
71 static int __init rk3288_get_process_version(void)
72 {
73         int ret = efuse_buf[6]&0x0f;
74
75         return ret;
76 }
77
78 static int rk3288_get_leakage(int ch)
79 {
80         if ((ch < 0) || (ch > 2))
81                 return 0;
82
83         return efuse_buf[23+ch];
84 }
85
86 static void __init rk3288_set_system_serial(void)
87 {
88         int i;
89         u8 buf[16];
90
91         for (i = 0; i < 8; i++) {
92                 buf[i] = efuse_buf[8 + (i << 1)];
93                 buf[i + 8] = efuse_buf[7 + (i << 1)];
94         }
95
96         system_serial_low = crc32(0, buf, 8);
97         system_serial_high = crc32(system_serial_low, buf + 8, 8);
98 }
99
100 int rk312x_efuse_readregs(u32 addr, u32 length, u8 *buf)
101 {
102         unsigned long flags;
103         int ret = length;
104
105         if (!length)
106                 return 0;
107
108         efuse_writel(EFUSE_LOAD, REG_EFUSE_CTRL);
109         udelay(2);
110         do {
111                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
112                                 (~(EFUSE_A_MASK << RK312X_EFUSE_A_SHIFT)),
113                                 REG_EFUSE_CTRL);
114                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
115                                 ((addr & EFUSE_A_MASK) << RK312X_EFUSE_A_SHIFT),
116                                 REG_EFUSE_CTRL);
117                 udelay(2);
118                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
119                                 EFUSE_STROBE, REG_EFUSE_CTRL);
120                 udelay(2);
121                 *buf = efuse_readl(REG_EFUSE_DOUT);
122                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
123                                 (~EFUSE_STROBE), REG_EFUSE_CTRL);
124                 udelay(2);
125                 buf++;
126                 addr++;
127         } while (--length);
128         udelay(2);
129         efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
130                         (~EFUSE_LOAD) , REG_EFUSE_CTRL);
131         udelay(1);
132
133         return ret;
134 }
135
136 int rockchip_efuse_version(void)
137 {
138         return efuse.efuse_version;
139 }
140
141 int rockchip_process_version(void)
142 {
143         return efuse.process_version;
144 }
145
146 int rockchip_get_leakage(int ch)
147 {
148         if (efuse.get_leakage)
149                 return efuse.get_leakage(ch);
150         return 0;
151 }
152
153 void __init rockchip_efuse_init(void)
154 {
155         int ret;
156
157         if (cpu_is_rk3288()) {
158                 ret = rk3288_efuse_readregs(0, 32, efuse_buf);
159                 if (ret == 32) {
160                         efuse.get_leakage = rk3288_get_leakage;
161                         efuse.efuse_version = rk3288_get_efuse_version();
162                         efuse.process_version = rk3288_get_process_version();
163                         rockchip_set_cpu_version((efuse_buf[6] >> 4) & 3);
164                         rk3288_set_system_serial();
165                 } else {
166                         pr_err("failed to read eFuse, return %d\n", ret);
167                 }
168         } else if (cpu_is_rk312x()) {
169                 ret = rk312x_efuse_readregs(0, 32, efuse_buf);
170                 if (ret == 32)
171                         efuse.get_leakage = rk3288_get_leakage;
172                 else
173                         pr_err("failed to read eFuse, return %d\n", ret);
174         }
175 }