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