aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/fuse.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/fuse.c')
-rw-r--r--arch/arm/mach-tegra/fuse.c423
1 files changed, 400 insertions, 23 deletions
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index 1fa26d9a1a6..d9fe1b02d0e 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -2,6 +2,7 @@
2 * arch/arm/mach-tegra/fuse.c 2 * arch/arm/mach-tegra/fuse.c
3 * 3 *
4 * Copyright (C) 2010 Google, Inc. 4 * Copyright (C) 2010 Google, Inc.
5 * Copyright (C) 2010-2011 NVIDIA Corp.
5 * 6 *
6 * Author: 7 * Author:
7 * Colin Cross <ccross@android.com> 8 * Colin Cross <ccross@android.com>
@@ -19,24 +20,87 @@
19 20
20#include <linux/kernel.h> 21#include <linux/kernel.h>
21#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/init.h>
24#include <linux/string.h>
25#include <linux/module.h>
26#include <linux/moduleparam.h>
22 27
23#include <mach/iomap.h> 28#include <mach/iomap.h>
29#include <mach/tegra_fuse.h>
24 30
25#include "fuse.h" 31#include "fuse.h"
32#include "apbio.h"
26 33
34#define FUSE_SKU_INFO 0x110
35#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
27#define FUSE_UID_LOW 0x108 36#define FUSE_UID_LOW 0x108
28#define FUSE_UID_HIGH 0x10c 37#define FUSE_UID_HIGH 0x10c
29#define FUSE_SKU_INFO 0x110
30#define FUSE_SPARE_BIT 0x200 38#define FUSE_SPARE_BIT 0x200
39#else
40#define FUSE_VENDOR_CODE 0x200
41#define FUSE_VENDOR_CODE_MASK 0xf
42#define FUSE_FAB_CODE 0x204
43#define FUSE_FAB_CODE_MASK 0x3f
44#define FUSE_LOT_CODE_0 0x208
45#define FUSE_LOT_CODE_1 0x20c
46#define FUSE_WAFER_ID 0x210
47#define FUSE_WAFER_ID_MASK 0x3f
48#define FUSE_X_COORDINATE 0x214
49#define FUSE_X_COORDINATE_MASK 0x1ff
50#define FUSE_Y_COORDINATE 0x218
51#define FUSE_Y_COORDINATE_MASK 0x1ff
52#define FUSE_GPU_INFO 0x390
53#define FUSE_GPU_INFO_MASK (1<<2)
54#define FUSE_SPARE_BIT 0x244
55/* fuse registers used in public fuse data read API */
56#define FUSE_TEST_PROGRAM_REVISION_0 0x128
57/* fuse spare bits are used to get Tj-ADT values */
58#define FUSE_SPARE_BIT_0_0 0x244
59#define NUM_TSENSOR_SPARE_BITS 28
60/* tsensor calibration register */
61#define FUSE_TSENSOR_CALIB_0 0x198
62
63#endif
64
65struct tegra_id {
66 enum tegra_chipid chipid;
67 unsigned int major, minor, netlist, patch;
68 enum tegra_revision revision;
69 char *priv;
70};
71
72static struct tegra_id tegra_id;
73static unsigned int tegra_chip_id;
74static unsigned int tegra_chip_rev;
75
76static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
77 [TEGRA_REVISION_UNKNOWN] = "unknown",
78 [TEGRA_REVISION_A01] = "A01",
79 [TEGRA_REVISION_A02] = "A02",
80 [TEGRA_REVISION_A03] = "A03",
81 [TEGRA_REVISION_A03p] = "A03 prime",
82 [TEGRA_REVISION_A04] = "A04",
83 [TEGRA_REVISION_A04p] = "A04 prime",
84};
85
86u32 tegra_fuse_readl(unsigned long offset)
87{
88 return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
89}
90
91void tegra_fuse_writel(u32 value, unsigned long offset)
92{
93 tegra_apb_writel(value, TEGRA_FUSE_BASE + offset);
94}
31 95
32static inline u32 fuse_readl(unsigned long offset) 96static inline bool get_spare_fuse(int bit)
33{ 97{
34 return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); 98 return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
35} 99}
36 100
37static inline void fuse_writel(u32 value, unsigned long offset) 101const char *tegra_get_revision_name(void)
38{ 102{
39 writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); 103 return tegra_revision_name[tegra_get_revision()];
40} 104}
41 105
42void tegra_init_fuse(void) 106void tegra_init_fuse(void)
@@ -44,41 +108,354 @@ void tegra_init_fuse(void)
44 u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); 108 u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
45 reg |= 1 << 28; 109 reg |= 1 << 28;
46 writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); 110 writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
111 tegra_init_speedo_data();
112
113 pr_info("Tegra Revision: %s "
114 "SKU: 0x%x CPU Process: %d Core Process: %d\n",
115 tegra_get_revision_name(), tegra_sku_id(),
116 tegra_cpu_process_id(), tegra_core_process_id());
117}
47 118
48 pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n", 119#ifdef CONFIG_ARCH_TEGRA_2x_SOC
49 tegra_sku_id(), tegra_cpu_process_id(), 120int tegra_fuse_get_revision(u32 *rev)
50 tegra_core_process_id()); 121{
122 return -ENOENT;
51} 123}
124EXPORT_SYMBOL(tegra_fuse_get_revision);
125
126int tegra_fuse_get_tsensor_calibration_data(u32 *calib)
127{
128 return -ENOENT;
129}
130EXPORT_SYMBOL(tegra_fuse_get_tsensor_calibration_data);
131
132int tegra_fuse_get_tsensor_spare_bits(u32 *spare_bits)
133{
134 return -ENOENT;
135}
136EXPORT_SYMBOL(tegra_fuse_get_tsensor_spare_bits);
137
138#else
139
140int tegra_fuse_get_revision(u32 *rev)
141{
142 /* fuse revision */
143 *rev = tegra_fuse_readl(FUSE_TEST_PROGRAM_REVISION_0);
144 return 0;
145}
146EXPORT_SYMBOL(tegra_fuse_get_revision);
147
148int tegra_fuse_get_tsensor_calibration_data(u32 *calib)
149{
150 /* tsensor calibration fuse */
151 *calib = tegra_fuse_readl(FUSE_TSENSOR_CALIB_0);
152 return 0;
153}
154EXPORT_SYMBOL(tegra_fuse_get_tsensor_calibration_data);
155
156int tegra_fuse_get_tsensor_spare_bits(u32 *spare_bits)
157{
158 u32 value;
159 int i;
160
161 BUG_ON(NUM_TSENSOR_SPARE_BITS > (sizeof(u32) * 8));
162 if (!spare_bits)
163 return -ENOMEM;
164 *spare_bits = 0;
165 /* spare bits 0-27 */
166 for (i = 0; i < NUM_TSENSOR_SPARE_BITS; i++) {
167 value = tegra_fuse_readl(FUSE_SPARE_BIT_0_0 +
168 (i << 2));
169 if (value)
170 *spare_bits |= BIT(i);
171 }
172 return 0;
173}
174EXPORT_SYMBOL(tegra_fuse_get_tsensor_spare_bits);
175#endif
52 176
53unsigned long long tegra_chip_uid(void) 177unsigned long long tegra_chip_uid(void)
54{ 178{
179#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
55 unsigned long long lo, hi; 180 unsigned long long lo, hi;
56 181
57 lo = fuse_readl(FUSE_UID_LOW); 182 lo = tegra_fuse_readl(FUSE_UID_LOW);
58 hi = fuse_readl(FUSE_UID_HIGH); 183 hi = tegra_fuse_readl(FUSE_UID_HIGH);
59 return (hi << 32ull) | lo; 184 return (hi << 32ull) | lo;
185#else
186 u64 uid = 0ull;
187 u32 reg;
188 u32 cid;
189 u32 vendor;
190 u32 fab;
191 u32 lot;
192 u32 wafer;
193 u32 x;
194 u32 y;
195 u32 i;
196
197 /* This used to be so much easier in prior chips. Unfortunately, there
198 is no one-stop shopping for the unique id anymore. It must be
199 constructed from various bits of information burned into the fuses
200 during the manufacturing process. The 64-bit unique id is formed
201 by concatenating several bit fields. The notation used for the
202 various fields is <fieldname:size_in_bits> with the UID composed
203 thusly:
204
205 <CID:4><VENDOR:4><FAB:6><LOT:26><WAFER:6><X:9><Y:9>
206
207 Where:
208
209 Field Bits Position Data
210 ------- ---- -------- ----------------------------------------
211 CID 4 60 Chip id (encoded as zero for T30)
212 VENDOR 4 56 Vendor code
213 FAB 6 50 FAB code
214 LOT 26 24 Lot code (5-digit base-36-coded-decimal,
215 re-encoded to 26 bits binary)
216 WAFER 6 18 Wafer id
217 X 9 9 Wafer X-coordinate
218 Y 9 0 Wafer Y-coordinate
219 ------- ----
220 Total 64
221 */
222
223 /* Get the chip id and encode each chip variant as a unique value. */
224 reg = readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + 0x804));
225 reg = (reg & 0xFF00) >> 8;
226
227 switch (reg) {
228 case TEGRA_CHIPID_TEGRA3:
229 cid = 0;
230 break;
231
232 default:
233 BUG();
234 break;
235 }
236
237 vendor = tegra_fuse_readl(FUSE_VENDOR_CODE) & FUSE_VENDOR_CODE_MASK;
238 fab = tegra_fuse_readl(FUSE_FAB_CODE) & FUSE_FAB_CODE_MASK;
239
240 /* Lot code must be re-encoded from a 5 digit base-36 'BCD' number
241 to a binary number. */
242 lot = 0;
243 reg = tegra_fuse_readl(FUSE_LOT_CODE_0) << 2;
244
245 for (i = 0; i < 5; ++i) {
246 u32 digit = (reg & 0xFC000000) >> 26;
247 BUG_ON(digit >= 36);
248 lot *= 36;
249 lot += digit;
250 reg <<= 6;
251 }
252
253 wafer = tegra_fuse_readl(FUSE_WAFER_ID) & FUSE_WAFER_ID_MASK;
254 x = tegra_fuse_readl(FUSE_X_COORDINATE) & FUSE_X_COORDINATE_MASK;
255 y = tegra_fuse_readl(FUSE_Y_COORDINATE) & FUSE_Y_COORDINATE_MASK;
256
257 uid = ((unsigned long long)cid << 60ull)
258 | ((unsigned long long)vendor << 56ull)
259 | ((unsigned long long)fab << 50ull)
260 | ((unsigned long long)lot << 24ull)
261 | ((unsigned long long)wafer << 18ull)
262 | ((unsigned long long)x << 9ull)
263 | ((unsigned long long)y << 0ull);
264 return uid;
265#endif
266}
267
268unsigned int tegra_spare_fuse(int bit)
269{
270 BUG_ON(bit < 0 || bit > 61);
271 return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
60} 272}
61 273
62int tegra_sku_id(void) 274int tegra_sku_id(void)
63{ 275{
64 int sku_id; 276 static int sku_id = -1;
65 u32 reg = fuse_readl(FUSE_SKU_INFO); 277 if (sku_id == -1) {
66 sku_id = reg & 0xFF; 278 u32 reg = tegra_fuse_readl(FUSE_SKU_INFO);
279 sku_id = reg & 0xFF;
280 }
67 return sku_id; 281 return sku_id;
68} 282}
69 283
70int tegra_cpu_process_id(void) 284int tegra_gpu_register_sets(void)
285{
286#ifdef CONFIG_ARCH_TEGRA_HAS_DUAL_3D
287 u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + FUSE_GPU_INFO));
288 if (reg & FUSE_GPU_INFO_MASK)
289 return 1;
290 else
291 return 2;
292#else
293 return 1;
294#endif
295}
296
297struct chip_revision {
298 enum tegra_chipid chipid;
299 unsigned int major;
300 unsigned int minor;
301 char prime;
302 enum tegra_revision revision;
303};
304
305#define CHIP_REVISION(id, m, n, p, rev) { \
306 .chipid = TEGRA_CHIPID_##id, \
307 .major = m, \
308 .minor = n, \
309 .prime = p, \
310 .revision = TEGRA_REVISION_##rev }
311
312static struct chip_revision tegra_chip_revisions[] = {
313 CHIP_REVISION(TEGRA2, 1, 2, 0, A02),
314 CHIP_REVISION(TEGRA2, 1, 3, 0, A03),
315 CHIP_REVISION(TEGRA2, 1, 3, 'p', A03p),
316 CHIP_REVISION(TEGRA2, 1, 4, 0, A04),
317 CHIP_REVISION(TEGRA2, 1, 4, 'p', A04p),
318 CHIP_REVISION(TEGRA3, 1, 1, 0, A01),
319 CHIP_REVISION(TEGRA3, 1, 2, 0, A02),
320 CHIP_REVISION(TEGRA3, 1, 3, 0, A03),
321};
322
323static enum tegra_revision tegra_decode_revision(const struct tegra_id *id)
324{
325 enum tegra_revision revision = TEGRA_REVISION_UNKNOWN;
326
327#if defined(CONFIG_TEGRA_SILICON_PLATFORM)
328 int i ;
329 char prime;
330
331 if (id->priv == NULL)
332 prime = 0;
333 else
334 prime = *(id->priv);
335
336 for (i = 0; i < ARRAY_SIZE(tegra_chip_revisions); i++) {
337 if ((id->chipid != tegra_chip_revisions[i].chipid) ||
338 (id->minor != tegra_chip_revisions[i].minor) ||
339 (id->major != tegra_chip_revisions[i].major) ||
340 (prime != tegra_chip_revisions[i].prime))
341 continue;
342
343 revision = tegra_chip_revisions[i].revision;
344 break;
345 }
346
347#elif defined(CONFIG_TEGRA_FPGA_PLATFORM)
348 if ((id->chipid & 0xf0) == TEGRA_CHIPID_TEGRA3) {
349 if ((id->major == 0) && (id->minor == 1)) {
350 unsigned int patch = id->patch & 0xF;
351 if ((id->netlist == 12) && (patch == 12))
352 revision = TEGRA_REVISION_A01;
353 else if ((id->netlist == 12) && (patch > 12))
354 revision = TEGRA_REVISION_A02;
355 else if (id->netlist > 12)
356 revision = TEGRA_REVISION_A02;
357 }
358 }
359#endif
360
361 return revision;
362}
363
364static void tegra_set_tegraid(u32 chipid,
365 u32 major, u32 minor,
366 u32 nlist, u32 patch, const char *priv)
367{
368 tegra_id.chipid = (enum tegra_chipid) chipid;
369 tegra_id.major = major;
370 tegra_id.minor = minor;
371 tegra_id.netlist = nlist;
372 tegra_id.patch = patch;
373 tegra_id.priv = (char *)priv;
374 tegra_id.revision = tegra_decode_revision(&tegra_id);
375}
376
377static void tegra_get_tegraid_from_hw(void)
71{ 378{
72 int cpu_process_id; 379 void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
73 u32 reg = fuse_readl(FUSE_SPARE_BIT); 380 void __iomem *netlist = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x860;
74 cpu_process_id = (reg >> 6) & 3; 381 u32 cid = readl(chip_id);
75 return cpu_process_id; 382 u32 nlist = readl(netlist);
383 char *priv = NULL;
384
385#ifdef CONFIG_ARCH_TEGRA_2x_SOC
386 if (get_spare_fuse(18) || get_spare_fuse(19))
387 priv = "p";
388#endif
389 tegra_set_tegraid((cid >> 8) & 0xff,
390 (cid >> 4) & 0xf,
391 (cid >> 16) & 0xf,
392 (nlist >> 0) & 0xffff,
393 (nlist >> 16) & 0xffff,
394 priv);
76} 395}
77 396
78int tegra_core_process_id(void) 397enum tegra_chipid tegra_get_chipid(void)
79{ 398{
80 int core_process_id; 399 if (tegra_id.chipid == TEGRA_CHIPID_UNKNOWN) {
81 u32 reg = fuse_readl(FUSE_SPARE_BIT); 400 /* Boot loader did not pass a valid chip ID.
82 core_process_id = (reg >> 12) & 3; 401 * Get it from hardware */
83 return core_process_id; 402 tegra_get_tegraid_from_hw();
403 }
404
405 return tegra_id.chipid;
84} 406}
407
408enum tegra_revision tegra_get_revision(void)
409{
410 if (tegra_id.chipid == TEGRA_CHIPID_UNKNOWN) {
411 /* Boot loader did not pass a valid chip ID.
412 * Get it from hardware */
413 tegra_get_tegraid_from_hw();
414 }
415
416 return tegra_id.revision;
417}
418
419static char chippriv[16]; /* Permanent buffer for private string */
420static int __init tegra_bootloader_tegraid(char *str)
421{
422 u32 id[5];
423 int i = 0;
424 char *priv = NULL;
425
426 do {
427 id[i++] = simple_strtoul(str, &str, 16);
428 } while (*str++ && i < ARRAY_SIZE(id));
429
430 if (*(str - 1) == '.') {
431 strncpy(chippriv, str, sizeof(chippriv) - 1);
432 priv = chippriv;
433 if (strlen(str) > sizeof(chippriv) - 1)
434 pr_err("### tegraid.priv in kernel arg truncated\n");
435 }
436
437 while (i < ARRAY_SIZE(id))
438 id[i++] = 0;
439
440 tegra_set_tegraid(id[0], id[1], id[2], id[3], id[4], priv);
441 return 0;
442}
443
444static unsigned int get_chip_id(char *val, struct kernel_param *kp)
445{
446 tegra_chip_id = (unsigned int)tegra_get_chipid();
447 return param_get_uint(val, kp);
448}
449static unsigned int get_chip_rev(char *val, struct kernel_param *kp)
450{
451 tegra_chip_rev = (unsigned int)tegra_get_revision();
452 return param_get_uint(val, kp);
453}
454
455module_param_call(tegra_chip_id, NULL, get_chip_id, &tegra_chip_id, 0444);
456__MODULE_PARM_TYPE(tegra_chip_id, "uint");
457module_param_call(tegra_chip_rev, NULL, get_chip_rev, &tegra_chip_rev, 0444);
458__MODULE_PARM_TYPE(tegra_chip_rev, "uint");
459
460/* tegraid=chipid.major.minor.netlist.patch[.priv] */
461early_param("tegraid", tegra_bootloader_tegraid);