21224c292d7ddc719b94ee78aae34462595304f8
[linux-2.6.git] / arch / arm / mach-tegra / fuse.c
1 /*
2  * arch/arm/mach-tegra/fuse.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  * Copyright (C) 2010-2011 NVIDIA, Corp.
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/kernel.h>
22 #include <linux/io.h>
23
24 #include <mach/iomap.h>
25
26 #include "fuse.h"
27 #include "apbio.h"
28
29 #define FUSE_SKU_INFO           0x110
30 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
31 #define FUSE_UID_LOW            0x108
32 #define FUSE_UID_HIGH           0x10c
33 #define FUSE_SPARE_BIT          0x200
34 #elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
35 #define FUSE_VENDOR_CODE        0x200
36 #define FUSE_VENDOR_CODE_MASK   0xf
37 #define FUSE_FAB_CODE           0x204
38 #define FUSE_FAB_CODE_MASK      0x3f
39 #define FUSE_LOT_CODE_0         0x208
40 #define FUSE_LOT_CODE_1         0x20c
41 #define FUSE_WAFER_ID           0x210
42 #define FUSE_WAFER_ID_MASK      0x3f
43 #define FUSE_X_COORDINATE       0x214
44 #define FUSE_X_COORDINATE_MASK  0x1ff
45 #define FUSE_Y_COORDINATE       0x218
46 #define FUSE_Y_COORDINATE_MASK  0x1ff
47 #define FUSE_SPARE_BIT          0x244
48 #endif
49
50 static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
51         [TEGRA_REVISION_UNKNOWN] = "unknown",
52 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
53         [TEGRA_REVISION_A02] = "A02",
54         [TEGRA_REVISION_A03] = "A03",
55         [TEGRA_REVISION_A03p] = "A03 prime",
56 #elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
57         [TEGRA_REVISION_A01] = "A01",
58 #endif
59 };
60
61 u32 tegra_fuse_readl(unsigned long offset)
62 {
63         return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
64 }
65
66 void tegra_fuse_writel(u32 value, unsigned long offset)
67 {
68         tegra_apb_writel(value, TEGRA_FUSE_BASE + offset);
69 }
70
71 static inline bool get_spare_fuse(int bit)
72 {
73         return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
74 }
75
76 void tegra_init_fuse(void)
77 {
78         u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
79         reg |= 1 << 28;
80         writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
81         tegra_init_speedo_data();
82
83         pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
84                 tegra_revision_name[tegra_get_revision()],
85                 tegra_sku_id(), tegra_cpu_process_id(),
86                 tegra_core_process_id());
87 }
88
89 unsigned long long tegra_chip_uid(void)
90 {
91 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
92         unsigned long long lo, hi;
93
94         lo = tegra_fuse_readl(FUSE_UID_LOW);
95         hi = tegra_fuse_readl(FUSE_UID_HIGH);
96         return (hi << 32ull) | lo;
97 #else
98         u64 uid = 0ull;
99         u32 reg;
100         u32 cid;
101         u32 vendor;
102         u32 fab;
103         u32 lot;
104         u32 wafer;
105         u32 x;
106         u32 y;
107         u32 i;
108
109         /* This used to be so much easier in prior chips. Unfortunately, there
110            is no one-stop shopping for the unique id anymore. It must be
111            constructed from various bits of information burned into the fuses
112            during the manufacturing process. The 64-bit unique id is formed
113            by concatenating several bit fields. The notation used for the
114            various fields is <fieldname:size_in_bits> with the UID composed
115            thusly:
116
117             <CID:4><VENDOR:4><FAB:6><LOT:26><WAFER:6><X:9><Y:9>
118
119            Where:
120
121                 Field    Bits  Position Data
122                 -------  ----  -------- ----------------------------------------
123                 CID        4     60     Chip id (encoded as zero for T30)
124                 VENDOR     4     56     Vendor code
125                 FAB        6     50     FAB code
126                 LOT       26     24     Lot code (5-digit base-36-coded-decimal,
127                                             re-encoded to 26 bits binary)
128                 WAFER      6     18     Wafer id
129                 X          9      9     Wafer X-coordinate
130                 Y          9      0     Wafer Y-coordinate
131                 -------  ----
132                 Total     64
133         */
134
135         /* Get the chip id and encode each chip variant as a unique value. */
136         reg = readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + 0x804));
137         reg = (reg & 0xFF00) >> 8;
138
139         switch (reg) {
140         case 0x30:
141                 cid = 0;
142                 break;
143
144         default:
145                 BUG();
146                 break;
147         }
148
149         vendor = tegra_fuse_readl(FUSE_VENDOR_CODE) & FUSE_VENDOR_CODE_MASK;
150         fab = tegra_fuse_readl(FUSE_FAB_CODE) & FUSE_FAB_CODE_MASK;
151
152         /* Lot code must be re-encoded from a 5 digit base-36 'BCD' number
153            to a binary number. */
154         lot = 0;
155         reg = tegra_fuse_readl(FUSE_LOT_CODE_1) << 2;
156
157         for (i = 0; i < 5; ++i) {
158                 u32 digit = (reg & 0xFC000000) >> 26;
159                 BUG_ON(digit >= 36);
160                 lot *= 36;
161                 lot += digit;
162                 reg <<= 6;
163         }
164
165         wafer = tegra_fuse_readl(FUSE_WAFER_ID) & FUSE_WAFER_ID_MASK;
166         x = tegra_fuse_readl(FUSE_X_COORDINATE) & FUSE_X_COORDINATE_MASK;
167         y = tegra_fuse_readl(FUSE_Y_COORDINATE) & FUSE_Y_COORDINATE_MASK;
168
169         uid = ((unsigned long long)cid  << 60ull)
170             | ((unsigned long long)vendor << 56ull)
171             | ((unsigned long long)fab << 50ull)
172             | ((unsigned long long)lot << 24ull)
173             | ((unsigned long long)wafer << 18ull)
174             | ((unsigned long long)x << 9ull)
175             | ((unsigned long long)y << 0ull);
176         return uid;
177 #endif
178 }
179
180 unsigned int tegra_spare_fuse(int bit)
181 {
182         BUG_ON(bit < 0 || bit > 61);
183         return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
184 }
185
186 int tegra_sku_id(void)
187 {
188         int sku_id;
189         u32 reg = tegra_fuse_readl(FUSE_SKU_INFO);
190         sku_id = reg & 0xFF;
191         return sku_id;
192 }
193
194 enum tegra_revision tegra_get_revision(void)
195 {
196         void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
197         u32 id = readl(chip_id);
198
199         switch ((id >> 16) & 0xf) {
200 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
201         case 1:
202                 return TEGRA_REVISION_A01;
203 #endif
204         case 2:
205                 return TEGRA_REVISION_A02;
206 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
207         case 3:
208                 if (get_spare_fuse(18) || get_spare_fuse(19))
209                         return TEGRA_REVISION_A03p;
210                 else
211                         return TEGRA_REVISION_A03;
212 #endif
213         default:
214                 return TEGRA_REVISION_UNKNOWN;
215         }
216 }