ARM: rockchip: rk3288 set system serial when efuse init
[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 };
25
26 static struct rockchip_efuse efuse;
27
28 static int __init rk3288_efuse_readregs(u32 addr, u32 length, u8 *buf)
29 {
30         int ret = length;
31
32         if (!length)
33                 return 0;
34         if (!buf)
35                 return 0;
36
37         efuse_writel(EFUSE_CSB, REG_EFUSE_CTRL);
38         efuse_writel(EFUSE_LOAD | EFUSE_PGENB, REG_EFUSE_CTRL);
39         udelay(2);
40         do {
41                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
42                         (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), REG_EFUSE_CTRL);
43                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
44                         ((addr & EFUSE_A_MASK) << EFUSE_A_SHIFT),
45                         REG_EFUSE_CTRL);
46                 udelay(2);
47                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) |
48                                 EFUSE_STROBE, REG_EFUSE_CTRL);
49                 udelay(2);
50                 *buf = efuse_readl(REG_EFUSE_DOUT);
51                 efuse_writel(efuse_readl(REG_EFUSE_CTRL) &
52                                 (~EFUSE_STROBE), REG_EFUSE_CTRL);
53                 udelay(2);
54                 buf++;
55                 addr++;
56         } while (--length);
57         udelay(2);
58         efuse_writel(efuse_readl(REG_EFUSE_CTRL) | EFUSE_CSB, REG_EFUSE_CTRL);
59         udelay(1);
60
61         return ret;
62 }
63
64 static int __init rk3288_get_efuse_version(void)
65 {
66         int ret = efuse_buf[4] & (~(0x1 << 3));
67         return ret;
68 }
69
70 static int rk3288_get_leakage(int ch)
71 {
72         if ((ch < 0) || (ch > 2))
73                 return 0;
74
75         return efuse_buf[23+ch];
76 }
77
78 static void __init rk3288_set_system_serial(void)
79 {
80         int i;
81         u8 buf[16];
82
83         for (i = 0; i < 8; i++) {
84                 buf[i] = efuse_buf[8 + (i << 1)];
85                 buf[i + 8] = efuse_buf[7 + (i << 1)];
86         }
87
88         system_serial_low = crc32(0, buf, 8);
89         system_serial_high = crc32(system_serial_low, buf + 8, 8);
90 }
91
92 int rockchip_efuse_version(void)
93 {
94         return efuse.efuse_version;
95 }
96
97 int rockchip_get_leakage(int ch)
98 {
99         if (efuse.get_leakage)
100                 return efuse.get_leakage(ch);
101         return 0;
102 }
103
104 void __init rockchip_efuse_init(void)
105 {
106         int ret;
107
108         if (cpu_is_rk3288()) {
109                 ret = rk3288_efuse_readregs(0, 32, efuse_buf);
110                 if (ret == 32) {
111                         efuse.get_leakage = rk3288_get_leakage;
112                         efuse.efuse_version = rk3288_get_efuse_version();
113                         rockchip_set_cpu_version((efuse_buf[6] >> 4) & 3);
114                         rk3288_set_system_serial();
115                 } else {
116                         pr_err("failed to read eFuse, return %d\n", ret);
117                 }
118         }
119 }