aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/fuse.c
diff options
context:
space:
mode:
authorPeter De Schrijver <pdeschrijver@nvidia.com>2014-06-12 11:36:37 -0400
committerThierry Reding <treding@nvidia.com>2014-07-17 08:36:01 -0400
commit783c8f4c84451bc444e314a71b447239c6ef6fd9 (patch)
treeccf8ed545ac850e06d3e781a99769bd0ea43c597 /arch/arm/mach-tegra/fuse.c
parent35874f3617b38e0c1f72163407c41d554a8f5939 (diff)
soc/tegra: Add efuse driver for Tegra
Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. This replaces functionality previously provided in arch/arm/mach-tegra, which is removed in this patch. While at it, move the only user of the global tegra_revision variable over to tegra_sku_info.revision and export tegra_fuse_readl() to allow drivers to read calibration fuses. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/fuse.c')
-rw-r--r--arch/arm/mach-tegra/fuse.c260
1 files changed, 0 insertions, 260 deletions
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
deleted file mode 100644
index b22e76a40965..000000000000
--- a/arch/arm/mach-tegra/fuse.c
+++ /dev/null
@@ -1,260 +0,0 @@
1/*
2 * arch/arm/mach-tegra/fuse.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
6 *
7 * Author:
8 * Colin Cross <ccross@android.com>
9 *
10 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and
12 * may be copied, distributed, and modified under those terms.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 */
20
21#include <linux/clk.h>
22#include <linux/export.h>
23#include <linux/io.h>
24#include <linux/kernel.h>
25#include <linux/random.h>
26
27#include <soc/tegra/fuse.h>
28
29#include "apbio.h"
30#include "fuse.h"
31#include "iomap.h"
32
33/* Tegra20 only */
34#define FUSE_UID_LOW 0x108
35#define FUSE_UID_HIGH 0x10c
36
37/* Tegra30 and later */
38#define FUSE_VENDOR_CODE 0x200
39#define FUSE_FAB_CODE 0x204
40#define FUSE_LOT_CODE_0 0x208
41#define FUSE_LOT_CODE_1 0x20c
42#define FUSE_WAFER_ID 0x210
43#define FUSE_X_COORDINATE 0x214
44#define FUSE_Y_COORDINATE 0x218
45
46#define FUSE_SKU_INFO 0x110
47
48#define TEGRA20_FUSE_SPARE_BIT 0x200
49#define TEGRA30_FUSE_SPARE_BIT 0x244
50
51int tegra_sku_id;
52int tegra_cpu_process_id;
53int tegra_core_process_id;
54int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
55int tegra_soc_speedo_id;
56enum tegra_revision tegra_revision;
57
58static struct clk *fuse_clk;
59static int tegra_fuse_spare_bit;
60static void (*tegra_init_speedo_data)(void);
61
62/* The BCT to use at boot is specified by board straps that can be read
63 * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
64 */
65int tegra_bct_strapping;
66
67#define STRAP_OPT 0x008
68#define GMI_AD0 (1 << 4)
69#define GMI_AD1 (1 << 5)
70#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
71#define RAM_CODE_SHIFT 4
72
73static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
74 [TEGRA_REVISION_UNKNOWN] = "unknown",
75 [TEGRA_REVISION_A01] = "A01",
76 [TEGRA_REVISION_A02] = "A02",
77 [TEGRA_REVISION_A03] = "A03",
78 [TEGRA_REVISION_A03p] = "A03 prime",
79 [TEGRA_REVISION_A04] = "A04",
80};
81
82static void tegra_fuse_enable_clk(void)
83{
84 if (IS_ERR(fuse_clk))
85 fuse_clk = clk_get_sys(NULL, "fuse");
86 if (IS_ERR(fuse_clk))
87 return;
88 clk_prepare_enable(fuse_clk);
89}
90
91static void tegra_fuse_disable_clk(void)
92{
93 if (IS_ERR(fuse_clk))
94 return;
95 clk_disable_unprepare(fuse_clk);
96}
97
98u32 tegra_fuse_readl(unsigned long offset)
99{
100 return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
101}
102
103bool tegra_spare_fuse(int bit)
104{
105 bool ret;
106
107 tegra_fuse_enable_clk();
108
109 ret = tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4);
110
111 tegra_fuse_disable_clk();
112
113 return ret;
114}
115
116static enum tegra_revision tegra_get_revision(u32 id)
117{
118 u32 minor_rev = (id >> 16) & 0xf;
119
120 switch (minor_rev) {
121 case 1:
122 return TEGRA_REVISION_A01;
123 case 2:
124 return TEGRA_REVISION_A02;
125 case 3:
126 if (tegra_get_chip_id() == TEGRA20 &&
127 (tegra_spare_fuse(18) || tegra_spare_fuse(19)))
128 return TEGRA_REVISION_A03p;
129 else
130 return TEGRA_REVISION_A03;
131 case 4:
132 return TEGRA_REVISION_A04;
133 default:
134 return TEGRA_REVISION_UNKNOWN;
135 }
136}
137
138static void tegra_get_process_id(void)
139{
140 u32 reg;
141
142 tegra_fuse_enable_clk();
143
144 reg = tegra_fuse_readl(tegra_fuse_spare_bit);
145 tegra_cpu_process_id = (reg >> 6) & 3;
146 reg = tegra_fuse_readl(tegra_fuse_spare_bit);
147 tegra_core_process_id = (reg >> 12) & 3;
148
149 tegra_fuse_disable_clk();
150}
151
152u32 tegra_read_chipid(void)
153{
154 return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
155}
156
157u8 tegra_get_chip_id(void)
158{
159 u32 id = tegra_read_chipid();
160
161 return (id >> 8) & 0xff;
162}
163
164static void __init tegra20_fuse_init_randomness(void)
165{
166 u32 randomness[2];
167
168 randomness[0] = tegra_fuse_readl(FUSE_UID_LOW);
169 randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH);
170
171 add_device_randomness(randomness, sizeof(randomness));
172}
173
174/* Applies to Tegra30 or later */
175static void __init tegra30_fuse_init_randomness(void)
176{
177 u32 randomness[7];
178
179 randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE);
180 randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE);
181 randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0);
182 randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1);
183 randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID);
184 randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE);
185 randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE);
186
187 add_device_randomness(randomness, sizeof(randomness));
188}
189
190void __init tegra_init_fuse(void)
191{
192 u32 id;
193 u32 randomness[5];
194 u8 chip_id;
195
196 u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
197 reg |= 1 << 28;
198 writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
199
200 /*
201 * Enable FUSE clock. This needs to be hardcoded because the clock
202 * subsystem is not active during early boot.
203 */
204 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
205 reg |= 1 << 7;
206 writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
207 fuse_clk = ERR_PTR(-EINVAL);
208
209 reg = tegra_fuse_readl(FUSE_SKU_INFO);
210 randomness[0] = reg;
211 tegra_sku_id = reg & 0xFF;
212
213 reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
214 randomness[1] = reg;
215 tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
216
217 id = tegra_read_chipid();
218 randomness[2] = id;
219 chip_id = (id >> 8) & 0xff;
220
221 switch (chip_id) {
222 case TEGRA20:
223 tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
224 tegra_init_speedo_data = &tegra20_init_speedo_data;
225 break;
226 case TEGRA30:
227 tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
228 tegra_init_speedo_data = &tegra30_init_speedo_data;
229 break;
230 case TEGRA114:
231 tegra_init_speedo_data = &tegra114_init_speedo_data;
232 break;
233 default:
234 pr_warn("Tegra: unknown chip id %d\n", chip_id);
235 tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
236 tegra_init_speedo_data = &tegra_get_process_id;
237 }
238
239 tegra_revision = tegra_get_revision(id);
240 tegra_init_speedo_data();
241 randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id;
242 randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id;
243
244 add_device_randomness(randomness, sizeof(randomness));
245 switch (chip_id) {
246 case TEGRA20:
247 tegra20_fuse_init_randomness();
248 break;
249 case TEGRA30:
250 case TEGRA114:
251 default:
252 tegra30_fuse_init_randomness();
253 break;
254 }
255
256 pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
257 tegra_revision_name[tegra_revision],
258 tegra_sku_id, tegra_cpu_process_id,
259 tegra_core_process_id);
260}