ARM: tegra: Sort includes alphabetically
[deliverable/linux.git] / arch / arm / mach-tegra / fuse.c
CommitLineData
73625e3e
CC
1/*
2 * arch/arm/mach-tegra/fuse.c
3 *
4 * Copyright (C) 2010 Google, Inc.
7495b2eb 5 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
73625e3e
CC
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
a0524acc 21#include <linux/clk.h>
34800598 22#include <linux/export.h>
a0524acc
TR
23#include <linux/io.h>
24#include <linux/kernel.h>
3bd1ae57 25#include <linux/random.h>
306a7f91
TR
26
27#include <soc/tegra/fuse.h>
73625e3e 28
a0524acc 29#include "apbio.h"
73625e3e 30#include "fuse.h"
2be39c07 31#include "iomap.h"
73625e3e 32
3bd1ae57 33/* Tegra20 only */
73625e3e
CC
34#define FUSE_UID_LOW 0x108
35#define FUSE_UID_HIGH 0x10c
3bd1ae57
SW
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
73625e3e 46#define FUSE_SKU_INFO 0x110
1f851a26
DH
47
48#define TEGRA20_FUSE_SPARE_BIT 0x200
f8ddda71 49#define TEGRA30_FUSE_SPARE_BIT 0x244
73625e3e 50
9a1086da
OJ
51int tegra_sku_id;
52int tegra_cpu_process_id;
53int tegra_core_process_id;
4c4ad669 54int tegra_chip_id;
f8ddda71 55int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
25cd5a39 56int tegra_soc_speedo_id;
9a1086da
OJ
57enum tegra_revision tegra_revision;
58
cdcb5a07 59static struct clk *fuse_clk;
1f851a26 60static int tegra_fuse_spare_bit;
25cd5a39 61static void (*tegra_init_speedo_data)(void);
1f851a26 62
dee47183
OJ
63/* The BCT to use at boot is specified by board straps that can be read
64 * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
65 */
66int tegra_bct_strapping;
67
68#define STRAP_OPT 0x008
69#define GMI_AD0 (1 << 4)
70#define GMI_AD1 (1 << 5)
71#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
72#define RAM_CODE_SHIFT 4
73
9a1086da
OJ
74static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
75 [TEGRA_REVISION_UNKNOWN] = "unknown",
76 [TEGRA_REVISION_A01] = "A01",
77 [TEGRA_REVISION_A02] = "A02",
78 [TEGRA_REVISION_A03] = "A03",
79 [TEGRA_REVISION_A03p] = "A03 prime",
80 [TEGRA_REVISION_A04] = "A04",
81};
82
cdcb5a07
AC
83static void tegra_fuse_enable_clk(void)
84{
85 if (IS_ERR(fuse_clk))
86 fuse_clk = clk_get_sys(NULL, "fuse");
87 if (IS_ERR(fuse_clk))
88 return;
89 clk_prepare_enable(fuse_clk);
90}
91
92static void tegra_fuse_disable_clk(void)
93{
94 if (IS_ERR(fuse_clk))
95 return;
96 clk_disable_unprepare(fuse_clk);
97}
98
1f851a26 99u32 tegra_fuse_readl(unsigned long offset)
73625e3e 100{
d262f49d 101 return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
73625e3e
CC
102}
103
1f851a26 104bool tegra_spare_fuse(int bit)
73625e3e 105{
cdcb5a07
AC
106 bool ret;
107
108 tegra_fuse_enable_clk();
109
110 ret = tegra_fuse_readl(tegra_fuse_spare_bit + bit * 4);
111
112 tegra_fuse_disable_clk();
113
114 return ret;
73625e3e
CC
115}
116
35b1498a 117static enum tegra_revision tegra_get_revision(u32 id)
73625e3e 118{
9a1086da 119 u32 minor_rev = (id >> 16) & 0xf;
9a1086da
OJ
120
121 switch (minor_rev) {
122 case 1:
123 return TEGRA_REVISION_A01;
124 case 2:
125 return TEGRA_REVISION_A02;
126 case 3:
35b1498a 127 if (tegra_chip_id == TEGRA20 &&
1f851a26 128 (tegra_spare_fuse(18) || tegra_spare_fuse(19)))
9a1086da
OJ
129 return TEGRA_REVISION_A03p;
130 else
131 return TEGRA_REVISION_A03;
132 case 4:
133 return TEGRA_REVISION_A04;
134 default:
135 return TEGRA_REVISION_UNKNOWN;
136 }
73625e3e
CC
137}
138
25cd5a39
DH
139static void tegra_get_process_id(void)
140{
141 u32 reg;
142
cdcb5a07
AC
143 tegra_fuse_enable_clk();
144
25cd5a39
DH
145 reg = tegra_fuse_readl(tegra_fuse_spare_bit);
146 tegra_cpu_process_id = (reg >> 6) & 3;
147 reg = tegra_fuse_readl(tegra_fuse_spare_bit);
148 tegra_core_process_id = (reg >> 12) & 3;
cdcb5a07
AC
149
150 tegra_fuse_disable_clk();
25cd5a39
DH
151}
152
c7736edf
PG
153u32 tegra_read_chipid(void)
154{
155 return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
156}
157
3bd1ae57
SW
158static void __init tegra20_fuse_init_randomness(void)
159{
160 u32 randomness[2];
161
162 randomness[0] = tegra_fuse_readl(FUSE_UID_LOW);
163 randomness[1] = tegra_fuse_readl(FUSE_UID_HIGH);
164
165 add_device_randomness(randomness, sizeof(randomness));
166}
167
168/* Applies to Tegra30 or later */
169static void __init tegra30_fuse_init_randomness(void)
170{
171 u32 randomness[7];
172
173 randomness[0] = tegra_fuse_readl(FUSE_VENDOR_CODE);
174 randomness[1] = tegra_fuse_readl(FUSE_FAB_CODE);
175 randomness[2] = tegra_fuse_readl(FUSE_LOT_CODE_0);
176 randomness[3] = tegra_fuse_readl(FUSE_LOT_CODE_1);
177 randomness[4] = tegra_fuse_readl(FUSE_WAFER_ID);
178 randomness[5] = tegra_fuse_readl(FUSE_X_COORDINATE);
179 randomness[6] = tegra_fuse_readl(FUSE_Y_COORDINATE);
180
181 add_device_randomness(randomness, sizeof(randomness));
182}
183
5875df17 184void __init tegra_init_fuse(void)
73625e3e 185{
35b1498a 186 u32 id;
3bd1ae57 187 u32 randomness[5];
35b1498a 188
f8e798a9 189 u32 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
73625e3e 190 reg |= 1 << 28;
f8e798a9 191 writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x48));
73625e3e 192
cdcb5a07
AC
193 /*
194 * Enable FUSE clock. This needs to be hardcoded because the clock
195 * subsystem is not active during early boot.
196 */
197 reg = readl(IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
198 reg |= 1 << 7;
199 writel(reg, IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x14));
200 fuse_clk = ERR_PTR(-EINVAL);
201
9a1086da 202 reg = tegra_fuse_readl(FUSE_SKU_INFO);
3bd1ae57 203 randomness[0] = reg;
9a1086da
OJ
204 tegra_sku_id = reg & 0xFF;
205
dee47183 206 reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
3bd1ae57 207 randomness[1] = reg;
dee47183
OJ
208 tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
209
c7736edf 210 id = tegra_read_chipid();
3bd1ae57 211 randomness[2] = id;
35b1498a
PDS
212 tegra_chip_id = (id >> 8) & 0xff;
213
25cd5a39
DH
214 switch (tegra_chip_id) {
215 case TEGRA20:
f8ddda71 216 tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
25cd5a39
DH
217 tegra_init_speedo_data = &tegra20_init_speedo_data;
218 break;
f8ddda71
DH
219 case TEGRA30:
220 tegra_fuse_spare_bit = TEGRA30_FUSE_SPARE_BIT;
221 tegra_init_speedo_data = &tegra30_init_speedo_data;
222 break;
7495b2eb
DH
223 case TEGRA114:
224 tegra_init_speedo_data = &tegra114_init_speedo_data;
225 break;
25cd5a39 226 default:
f8ddda71
DH
227 pr_warn("Tegra: unknown chip id %d\n", tegra_chip_id);
228 tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT;
25cd5a39
DH
229 tegra_init_speedo_data = &tegra_get_process_id;
230 }
231
35b1498a 232 tegra_revision = tegra_get_revision(id);
25cd5a39 233 tegra_init_speedo_data();
3bd1ae57
SW
234 randomness[3] = (tegra_cpu_process_id << 16) | tegra_core_process_id;
235 randomness[4] = (tegra_cpu_speedo_id << 16) | tegra_soc_speedo_id;
236
237 add_device_randomness(randomness, sizeof(randomness));
238 switch (tegra_chip_id) {
239 case TEGRA20:
240 tegra20_fuse_init_randomness();
b988ba1b 241 break;
3bd1ae57
SW
242 case TEGRA30:
243 case TEGRA114:
244 default:
245 tegra30_fuse_init_randomness();
b988ba1b 246 break;
3bd1ae57 247 }
9a1086da
OJ
248
249 pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
35b1498a 250 tegra_revision_name[tegra_revision],
9a1086da
OJ
251 tegra_sku_id, tegra_cpu_process_id,
252 tegra_core_process_id);
73625e3e 253}
This page took 0.204374 seconds and 5 git commands to generate.