aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/ABI/testing/sysfs-driver-tegra-fuse11
-rw-r--r--arch/arm/mach-tegra/Makefile4
-rw-r--r--arch/arm/mach-tegra/fuse.c260
-rw-r--r--arch/arm/mach-tegra/fuse.h60
-rw-r--r--arch/arm/mach-tegra/reset.c1
-rw-r--r--arch/arm/mach-tegra/tegra.c3
-rw-r--r--drivers/misc/fuse/Makefile1
-rw-r--r--drivers/soc/Makefile1
-rw-r--r--drivers/soc/tegra/Makefile1
-rw-r--r--drivers/soc/tegra/fuse/Makefile8
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c156
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra20.c142
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra30.c224
-rw-r--r--drivers/soc/tegra/fuse/fuse.h71
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra114.c (renamed from arch/arm/mach-tegra/tegra114_speedo.c)52
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra124.c168
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra20.c (renamed from arch/arm/mach-tegra/tegra20_speedo.c)41
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra30.c (renamed from arch/arm/mach-tegra/tegra30_speedo.c)172
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c112
-rw-r--r--include/soc/tegra/fuse.h20
20 files changed, 1047 insertions, 461 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-tegra-fuse b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
new file mode 100644
index 000000000000..69f5af632657
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-tegra-fuse
@@ -0,0 +1,11 @@
1What: /sys/devices/*/<our-device>/fuse
2Date: February 2014
3Contact: Peter De Schrijver <pdeschrijver@nvidia.com>
4Description: read-only access to the efuses on Tegra20, Tegra30, Tegra114
5 and Tegra124 SoC's from NVIDIA. The efuses contain write once
6 data programmed at the factory. The data is layed out in 32bit
7 words in LSB first format. Each bit represents a single value
8 as decoded from the fuse registers. Bits order/assignment
9 exactly matches the HW registers, including any unused bits.
10Users: any user space application which wants to read the efuses on
11 Tegra SoC's
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 6fbfbb77dcd9..e8601bb56f98 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -2,7 +2,6 @@ asflags-y += -march=armv7-a
2 2
3obj-y += io.o 3obj-y += io.o
4obj-y += irq.o 4obj-y += irq.o
5obj-y += fuse.o
6obj-y += pmc.o 5obj-y += pmc.o
7obj-y += flowctrl.o 6obj-y += flowctrl.o
8obj-y += powergate.o 7obj-y += powergate.o
@@ -13,13 +12,11 @@ obj-y += reset-handler.o
13obj-y += sleep.o 12obj-y += sleep.o
14obj-y += tegra.o 13obj-y += tegra.o
15obj-$(CONFIG_CPU_IDLE) += cpuidle.o 14obj-$(CONFIG_CPU_IDLE) += cpuidle.o
16obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o
17obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o 15obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-tegra20.o
18obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o 16obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pm-tegra20.o
19ifeq ($(CONFIG_CPU_IDLE),y) 17ifeq ($(CONFIG_CPU_IDLE),y)
20obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o 18obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += cpuidle-tegra20.o
21endif 19endif
22obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_speedo.o
23obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o 20obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += sleep-tegra30.o
24obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o 21obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pm-tegra30.o
25ifeq ($(CONFIG_CPU_IDLE),y) 22ifeq ($(CONFIG_CPU_IDLE),y)
@@ -28,7 +25,6 @@ endif
28obj-$(CONFIG_SMP) += platsmp.o headsmp.o 25obj-$(CONFIG_SMP) += platsmp.o headsmp.o
29obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 26obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
30 27
31obj-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114_speedo.o
32obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o 28obj-$(CONFIG_ARCH_TEGRA_114_SOC) += sleep-tegra30.o
33obj-$(CONFIG_ARCH_TEGRA_114_SOC) += pm-tegra30.o 29obj-$(CONFIG_ARCH_TEGRA_114_SOC) += pm-tegra30.o
34ifeq ($(CONFIG_CPU_IDLE),y) 30ifeq ($(CONFIG_CPU_IDLE),y)
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}
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
deleted file mode 100644
index 48a48861c19b..000000000000
--- a/arch/arm/mach-tegra/fuse.h
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 * Copyright (C) 2010 Google, Inc.
3 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
4 *
5 * Author:
6 * Colin Cross <ccross@android.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#ifndef __MACH_TEGRA_FUSE_H
20#define __MACH_TEGRA_FUSE_H
21
22#define SKU_ID_T20 8
23#define SKU_ID_T25SE 20
24#define SKU_ID_AP25 23
25#define SKU_ID_T25 24
26#define SKU_ID_AP25E 27
27#define SKU_ID_T25E 28
28
29#ifndef __ASSEMBLY__
30
31extern int tegra_sku_id;
32extern int tegra_cpu_process_id;
33extern int tegra_core_process_id;
34extern int tegra_cpu_speedo_id; /* only exist in Tegra30 and later */
35extern int tegra_soc_speedo_id;
36
37unsigned long long tegra_chip_uid(void);
38bool tegra_spare_fuse(int bit);
39u32 tegra_fuse_readl(unsigned long offset);
40
41#ifdef CONFIG_ARCH_TEGRA_2x_SOC
42void tegra20_init_speedo_data(void);
43#else
44static inline void tegra20_init_speedo_data(void) {}
45#endif
46
47#ifdef CONFIG_ARCH_TEGRA_3x_SOC
48void tegra30_init_speedo_data(void);
49#else
50static inline void tegra30_init_speedo_data(void) {}
51#endif
52
53#ifdef CONFIG_ARCH_TEGRA_114_SOC
54void tegra114_init_speedo_data(void);
55#else
56static inline void tegra114_init_speedo_data(void) {}
57#endif
58#endif /* __ASSEMBLY__ */
59
60#endif
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
index f94fdf89d457..5377495d41b8 100644
--- a/arch/arm/mach-tegra/reset.c
+++ b/arch/arm/mach-tegra/reset.c
@@ -25,7 +25,6 @@
25#include <asm/firmware.h> 25#include <asm/firmware.h>
26#include <asm/hardware/cache-l2x0.h> 26#include <asm/hardware/cache-l2x0.h>
27 27
28#include "fuse.h"
29#include "iomap.h" 28#include "iomap.h"
30#include "irammap.h" 29#include "irammap.h"
31#include "reset.h" 30#include "reset.h"
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c
index a359931c5952..c0faae8c0822 100644
--- a/arch/arm/mach-tegra/tegra.c
+++ b/arch/arm/mach-tegra/tegra.c
@@ -104,7 +104,8 @@ static void __init tegra_dt_init(void)
104 goto out; 104 goto out;
105 105
106 soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra"); 106 soc_dev_attr->family = kasprintf(GFP_KERNEL, "Tegra");
107 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d", tegra_revision); 107 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d",
108 tegra_sku_info.revision);
108 soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id()); 109 soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%u", tegra_get_chip_id());
109 110
110 soc_dev = soc_device_register(soc_dev_attr); 111 soc_dev = soc_device_register(soc_dev_attr);
diff --git a/drivers/misc/fuse/Makefile b/drivers/misc/fuse/Makefile
new file mode 100644
index 000000000000..0679c4febc89
--- /dev/null
+++ b/drivers/misc/fuse/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_ARCH_TEGRA) += tegra/
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 0f7c44793b29..3b1b95d932d1 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -3,3 +3,4 @@
3# 3#
4 4
5obj-$(CONFIG_ARCH_QCOM) += qcom/ 5obj-$(CONFIG_ARCH_QCOM) += qcom/
6obj-$(CONFIG_ARCH_TEGRA) += tegra/
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
new file mode 100644
index 000000000000..236600f91bb3
--- /dev/null
+++ b/drivers/soc/tegra/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_ARCH_TEGRA) += fuse/
diff --git a/drivers/soc/tegra/fuse/Makefile b/drivers/soc/tegra/fuse/Makefile
new file mode 100644
index 000000000000..3af357da91f3
--- /dev/null
+++ b/drivers/soc/tegra/fuse/Makefile
@@ -0,0 +1,8 @@
1obj-y += fuse-tegra.o
2obj-y += fuse-tegra30.o
3obj-y += tegra-apbmisc.o
4obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += fuse-tegra20.o
5obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += speedo-tegra20.o
6obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o
7obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o
8obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
new file mode 100644
index 000000000000..03742edcfe83
--- /dev/null
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -0,0 +1,156 @@
1/*
2 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <linux/device.h>
19#include <linux/kobject.h>
20#include <linux/kernel.h>
21#include <linux/platform_device.h>
22#include <linux/of.h>
23#include <linux/of_address.h>
24#include <linux/io.h>
25
26#include <soc/tegra/fuse.h>
27
28#include "fuse.h"
29
30static u32 (*fuse_readl)(const unsigned int offset);
31static int fuse_size;
32struct tegra_sku_info tegra_sku_info;
33
34static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
35 [TEGRA_REVISION_UNKNOWN] = "unknown",
36 [TEGRA_REVISION_A01] = "A01",
37 [TEGRA_REVISION_A02] = "A02",
38 [TEGRA_REVISION_A03] = "A03",
39 [TEGRA_REVISION_A03p] = "A03 prime",
40 [TEGRA_REVISION_A04] = "A04",
41};
42
43static u8 fuse_readb(const unsigned int offset)
44{
45 u32 val;
46
47 val = fuse_readl(round_down(offset, 4));
48 val >>= (offset % 4) * 8;
49 val &= 0xff;
50
51 return val;
52}
53
54static ssize_t fuse_read(struct file *fd, struct kobject *kobj,
55 struct bin_attribute *attr, char *buf,
56 loff_t pos, size_t size)
57{
58 int i;
59
60 if (pos < 0 || pos >= fuse_size)
61 return 0;
62
63 if (size > fuse_size - pos)
64 size = fuse_size - pos;
65
66 for (i = 0; i < size; i++)
67 buf[i] = fuse_readb(pos + i);
68
69 return i;
70}
71
72static struct bin_attribute fuse_bin_attr = {
73 .attr = { .name = "fuse", .mode = S_IRUGO, },
74 .read = fuse_read,
75};
76
77static const struct of_device_id car_match[] __initconst = {
78 { .compatible = "nvidia,tegra20-car", },
79 { .compatible = "nvidia,tegra30-car", },
80 { .compatible = "nvidia,tegra114-car", },
81 { .compatible = "nvidia,tegra124-car", },
82 {},
83};
84
85static void tegra_enable_fuse_clk(void __iomem *base)
86{
87 u32 reg;
88
89 reg = readl_relaxed(base + 0x48);
90 reg |= 1 << 28;
91 writel(reg, base + 0x48);
92
93 /*
94 * Enable FUSE clock. This needs to be hardcoded because the clock
95 * subsystem is not active during early boot.
96 */
97 reg = readl(base + 0x14);
98 reg |= 1 << 7;
99 writel(reg, base + 0x14);
100}
101
102int tegra_fuse_readl(unsigned long offset, u32 *value)
103{
104 if (!fuse_readl)
105 return -EPROBE_DEFER;
106
107 *value = fuse_readl(offset);
108
109 return 0;
110}
111EXPORT_SYMBOL(tegra_fuse_readl);
112
113int tegra_fuse_create_sysfs(struct device *dev, int size,
114 u32 (*readl)(const unsigned int offset))
115{
116 if (fuse_size)
117 return -ENODEV;
118
119 fuse_bin_attr.size = size;
120 fuse_bin_attr.read = fuse_read;
121
122 fuse_size = size;
123 fuse_readl = readl;
124
125 return device_create_bin_file(dev, &fuse_bin_attr);
126}
127
128void __init tegra_init_fuse(void)
129{
130 struct device_node *np;
131 void __iomem *car_base;
132
133 tegra_init_apbmisc();
134
135 np = of_find_matching_node(NULL, car_match);
136 car_base = of_iomap(np, 0);
137 if (car_base) {
138 tegra_enable_fuse_clk(car_base);
139 iounmap(car_base);
140 } else {
141 pr_err("Could not enable fuse clk. ioremap tegra car failed.\n");
142 return;
143 }
144
145 if (tegra_get_chip_id() == TEGRA20)
146 tegra20_init_fuse_early();
147 else
148 tegra30_init_fuse_early();
149
150 pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
151 tegra_revision_name[tegra_sku_info.revision],
152 tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id,
153 tegra_sku_info.core_process_id);
154 pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n",
155 tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id);
156}
diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c
new file mode 100644
index 000000000000..7a9d0e045490
--- /dev/null
+++ b/drivers/soc/tegra/fuse/fuse-tegra20.c
@@ -0,0 +1,142 @@
1/*
2 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Based on drivers/misc/eeprom/sunxi_sid.c
17 */
18
19#include <linux/device.h>
20#include <linux/clk.h>
21#include <linux/err.h>
22#include <linux/io.h>
23#include <linux/kernel.h>
24#include <linux/kobject.h>
25#include <linux/of_device.h>
26#include <linux/platform_device.h>
27#include <linux/random.h>
28
29#include <soc/tegra/fuse.h>
30
31#include "fuse.h"
32
33#define FUSE_BEGIN 0x100
34#define FUSE_SIZE 0x1f8
35#define FUSE_UID_LOW 0x08
36#define FUSE_UID_HIGH 0x0c
37
38static phys_addr_t fuse_phys;
39static struct clk *fuse_clk;
40static void __iomem __initdata *fuse_base;
41
42static u32 tegra20_fuse_readl(const unsigned int offset)
43{
44 int ret;
45 u32 val;
46
47 clk_prepare_enable(fuse_clk);
48
49 ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val);
50
51 clk_disable_unprepare(fuse_clk);
52
53 return (ret < 0) ? 0 : val;
54}
55
56static const struct of_device_id tegra20_fuse_of_match[] = {
57 { .compatible = "nvidia,tegra20-efuse" },
58 {},
59};
60
61static int tegra20_fuse_probe(struct platform_device *pdev)
62{
63 struct resource *res;
64
65 fuse_clk = devm_clk_get(&pdev->dev, NULL);
66 if (IS_ERR(fuse_clk)) {
67 dev_err(&pdev->dev, "missing clock");
68 return PTR_ERR(fuse_clk);
69 }
70
71 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
72 if (!res)
73 return -EINVAL;
74 fuse_phys = res->start;
75
76 if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl))
77 return -ENODEV;
78
79 dev_dbg(&pdev->dev, "loaded\n");
80
81 return 0;
82}
83
84static struct platform_driver tegra20_fuse_driver = {
85 .probe = tegra20_fuse_probe,
86 .driver = {
87 .name = "tegra20_fuse",
88 .owner = THIS_MODULE,
89 .of_match_table = tegra20_fuse_of_match,
90 }
91};
92
93static int __init tegra20_fuse_init(void)
94{
95 return platform_driver_register(&tegra20_fuse_driver);
96}
97postcore_initcall(tegra20_fuse_init);
98
99/* Early boot code. This code is called before the devices are created */
100
101u32 __init tegra20_fuse_early(const unsigned int offset)
102{
103 return readl_relaxed(fuse_base + FUSE_BEGIN + offset);
104}
105
106bool __init tegra20_spare_fuse_early(int spare_bit)
107{
108 u32 offset = spare_bit * 4;
109 bool value;
110
111 value = tegra20_fuse_early(offset + 0x100);
112
113 return value;
114}
115
116static void __init tegra20_fuse_add_randomness(void)
117{
118 u32 randomness[7];
119
120 randomness[0] = tegra_sku_info.sku_id;
121 randomness[1] = tegra_read_straps();
122 randomness[2] = tegra_read_chipid();
123 randomness[3] = tegra_sku_info.cpu_process_id << 16;
124 randomness[3] |= tegra_sku_info.core_process_id;
125 randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
126 randomness[4] |= tegra_sku_info.soc_speedo_id;
127 randomness[5] = tegra20_fuse_early(FUSE_UID_LOW);
128 randomness[6] = tegra20_fuse_early(FUSE_UID_HIGH);
129
130 add_device_randomness(randomness, sizeof(randomness));
131}
132
133void __init tegra20_init_fuse_early(void)
134{
135 fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE);
136
137 tegra_init_revision();
138 tegra20_init_speedo_data(&tegra_sku_info);
139 tegra20_fuse_add_randomness();
140
141 iounmap(fuse_base);
142}
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
new file mode 100644
index 000000000000..5999cf34ab70
--- /dev/null
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -0,0 +1,224 @@
1/*
2 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <linux/device.h>
19#include <linux/clk.h>
20#include <linux/err.h>
21#include <linux/io.h>
22#include <linux/kernel.h>
23#include <linux/of_device.h>
24#include <linux/of_address.h>
25#include <linux/platform_device.h>
26#include <linux/random.h>
27
28#include <soc/tegra/fuse.h>
29
30#include "fuse.h"
31
32#define FUSE_BEGIN 0x100
33
34/* Tegra30 and later */
35#define FUSE_VENDOR_CODE 0x100
36#define FUSE_FAB_CODE 0x104
37#define FUSE_LOT_CODE_0 0x108
38#define FUSE_LOT_CODE_1 0x10c
39#define FUSE_WAFER_ID 0x110
40#define FUSE_X_COORDINATE 0x114
41#define FUSE_Y_COORDINATE 0x118
42
43#define FUSE_HAS_REVISION_INFO BIT(0)
44
45enum speedo_idx {
46 SPEEDO_TEGRA30 = 0,
47 SPEEDO_TEGRA114,
48 SPEEDO_TEGRA124,
49};
50
51struct tegra_fuse_info {
52 int size;
53 int spare_bit;
54 enum speedo_idx speedo_idx;
55};
56
57static void __iomem *fuse_base;
58static struct clk *fuse_clk;
59static struct tegra_fuse_info *fuse_info;
60
61u32 tegra30_fuse_readl(const unsigned int offset)
62{
63 u32 val;
64
65 /*
66 * early in the boot, the fuse clock will be enabled by
67 * tegra_init_fuse()
68 */
69
70 if (fuse_clk)
71 clk_prepare_enable(fuse_clk);
72
73 val = readl_relaxed(fuse_base + FUSE_BEGIN + offset);
74
75 if (fuse_clk)
76 clk_disable_unprepare(fuse_clk);
77
78 return val;
79}
80
81static struct tegra_fuse_info tegra30_info = {
82 .size = 0x2a4,
83 .spare_bit = 0x144,
84 .speedo_idx = SPEEDO_TEGRA30,
85};
86
87static struct tegra_fuse_info tegra114_info = {
88 .size = 0x2a0,
89 .speedo_idx = SPEEDO_TEGRA114,
90};
91
92static struct tegra_fuse_info tegra124_info = {
93 .size = 0x300,
94 .speedo_idx = SPEEDO_TEGRA124,
95};
96
97static const struct of_device_id tegra30_fuse_of_match[] = {
98 { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info },
99 { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info },
100 { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info },
101 {},
102};
103
104static int tegra30_fuse_probe(struct platform_device *pdev)
105{
106 const struct of_device_id *of_dev_id;
107
108 of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev);
109 if (!of_dev_id)
110 return -ENODEV;
111
112 fuse_clk = devm_clk_get(&pdev->dev, NULL);
113 if (IS_ERR(fuse_clk)) {
114 dev_err(&pdev->dev, "missing clock");
115 return PTR_ERR(fuse_clk);
116 }
117
118 platform_set_drvdata(pdev, NULL);
119
120 if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size,
121 tegra30_fuse_readl))
122 return -ENODEV;
123
124 dev_dbg(&pdev->dev, "loaded\n");
125
126 return 0;
127}
128
129static struct platform_driver tegra30_fuse_driver = {
130 .probe = tegra30_fuse_probe,
131 .driver = {
132 .name = "tegra_fuse",
133 .owner = THIS_MODULE,
134 .of_match_table = tegra30_fuse_of_match,
135 }
136};
137
138static int __init tegra30_fuse_init(void)
139{
140 return platform_driver_register(&tegra30_fuse_driver);
141}
142postcore_initcall(tegra30_fuse_init);
143
144/* Early boot code. This code is called before the devices are created */
145
146typedef void (*speedo_f)(struct tegra_sku_info *sku_info);
147
148static speedo_f __initdata speedo_tbl[] = {
149 [SPEEDO_TEGRA30] = tegra30_init_speedo_data,
150 [SPEEDO_TEGRA114] = tegra114_init_speedo_data,
151 [SPEEDO_TEGRA124] = tegra124_init_speedo_data,
152};
153
154static void __init tegra30_fuse_add_randomness(void)
155{
156 u32 randomness[12];
157
158 randomness[0] = tegra_sku_info.sku_id;
159 randomness[1] = tegra_read_straps();
160 randomness[2] = tegra_read_chipid();
161 randomness[3] = tegra_sku_info.cpu_process_id << 16;
162 randomness[3] |= tegra_sku_info.core_process_id;
163 randomness[4] = tegra_sku_info.cpu_speedo_id << 16;
164 randomness[4] |= tegra_sku_info.soc_speedo_id;
165 randomness[5] = tegra30_fuse_readl(FUSE_VENDOR_CODE);
166 randomness[6] = tegra30_fuse_readl(FUSE_FAB_CODE);
167 randomness[7] = tegra30_fuse_readl(FUSE_LOT_CODE_0);
168 randomness[8] = tegra30_fuse_readl(FUSE_LOT_CODE_1);
169 randomness[9] = tegra30_fuse_readl(FUSE_WAFER_ID);
170 randomness[10] = tegra30_fuse_readl(FUSE_X_COORDINATE);
171 randomness[11] = tegra30_fuse_readl(FUSE_Y_COORDINATE);
172
173 add_device_randomness(randomness, sizeof(randomness));
174}
175
176static void __init legacy_fuse_init(void)
177{
178 switch (tegra_get_chip_id()) {
179 case TEGRA30:
180 fuse_info = &tegra30_info;
181 break;
182 case TEGRA114:
183 fuse_info = &tegra114_info;
184 break;
185 case TEGRA124:
186 fuse_info = &tegra124_info;
187 break;
188 default:
189 return;
190 }
191
192 fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE);
193}
194
195bool __init tegra30_spare_fuse(int spare_bit)
196{
197 u32 offset = fuse_info->spare_bit + spare_bit * 4;
198
199 return tegra30_fuse_readl(offset) & 1;
200}
201
202void __init tegra30_init_fuse_early(void)
203{
204 struct device_node *np;
205 const struct of_device_id *of_match;
206
207 np = of_find_matching_node_and_match(NULL, tegra30_fuse_of_match,
208 &of_match);
209 if (np) {
210 fuse_base = of_iomap(np, 0);
211 fuse_info = (struct tegra_fuse_info *)of_match->data;
212 } else
213 legacy_fuse_init();
214
215 if (!fuse_base) {
216 pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n",
217 tegra_get_chip_id());
218 return;
219 }
220
221 tegra_init_revision();
222 speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info);
223 tegra30_fuse_add_randomness();
224}
diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h
new file mode 100644
index 000000000000..b3442770df09
--- /dev/null
+++ b/drivers/soc/tegra/fuse/fuse.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2010 Google, Inc.
3 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
4 *
5 * Author:
6 * Colin Cross <ccross@android.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#ifndef __DRIVERS_MISC_TEGRA_FUSE_H
20#define __DRIVERS_MISC_TEGRA_FUSE_H
21
22#define TEGRA_FUSE_BASE 0x7000f800
23#define TEGRA_FUSE_SIZE 0x400
24
25int tegra_fuse_create_sysfs(struct device *dev, int size,
26 u32 (*readl)(const unsigned int offset));
27
28bool tegra30_spare_fuse(int bit);
29u32 tegra30_fuse_readl(const unsigned int offset);
30void tegra30_init_fuse_early(void);
31void tegra_init_revision(void);
32void tegra_init_apbmisc(void);
33
34#ifdef CONFIG_ARCH_TEGRA_2x_SOC
35void tegra20_init_speedo_data(struct tegra_sku_info *sku_info);
36bool tegra20_spare_fuse_early(int spare_bit);
37void tegra20_init_fuse_early(void);
38u32 tegra20_fuse_early(const unsigned int offset);
39#else
40static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info) {}
41static inline bool tegra20_spare_fuse_early(int spare_bit, void *fuse_base)
42{
43 return false;
44}
45static inline void tegra20_init_fuse_early(void);
46static inline tegra20_fuse_early(const unsigned int offset);
47{
48 return 0;
49}
50#endif
51
52
53#ifdef CONFIG_ARCH_TEGRA_3x_SOC
54void tegra30_init_speedo_data(struct tegra_sku_info *sku_info);
55#else
56static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info) {}
57#endif
58
59#ifdef CONFIG_ARCH_TEGRA_114_SOC
60void tegra114_init_speedo_data(struct tegra_sku_info *sku_info);
61#else
62static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info) {}
63#endif
64
65#ifdef CONFIG_ARCH_TEGRA_124_SOC
66void tegra124_init_speedo_data(struct tegra_sku_info *sku_info);
67#else
68static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info) {}
69#endif
70
71#endif
diff --git a/arch/arm/mach-tegra/tegra114_speedo.c b/drivers/soc/tegra/fuse/speedo-tegra114.c
index d0a6d5925f5f..2a6ca036f09f 100644
--- a/arch/arm/mach-tegra/tegra114_speedo.c
+++ b/drivers/soc/tegra/fuse/speedo-tegra114.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. 2 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify it 4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License, 5 * under the terms and conditions of the GNU General Public License,
@@ -15,14 +15,15 @@
15 */ 15 */
16 16
17#include <linux/bug.h> 17#include <linux/bug.h>
18#include <linux/device.h>
18#include <linux/kernel.h> 19#include <linux/kernel.h>
19 20
20#include <soc/tegra/fuse.h> 21#include <soc/tegra/fuse.h>
21 22
22#include "fuse.h" 23#include "fuse.h"
23 24
24#define CORE_PROCESS_CORNERS_NUM 2 25#define CORE_PROCESS_CORNERS 2
25#define CPU_PROCESS_CORNERS_NUM 2 26#define CPU_PROCESS_CORNERS 2
26 27
27enum { 28enum {
28 THRESHOLD_INDEX_0, 29 THRESHOLD_INDEX_0,
@@ -30,54 +31,57 @@ enum {
30 THRESHOLD_INDEX_COUNT, 31 THRESHOLD_INDEX_COUNT,
31}; 32};
32 33
33static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { 34static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
34 {1123, UINT_MAX}, 35 {1123, UINT_MAX},
35 {0, UINT_MAX}, 36 {0, UINT_MAX},
36}; 37};
37 38
38static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { 39static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
39 {1695, UINT_MAX}, 40 {1695, UINT_MAX},
40 {0, UINT_MAX}, 41 {0, UINT_MAX},
41}; 42};
42 43
43static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold) 44static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
45 int *threshold)
44{ 46{
45 u32 tmp; 47 u32 tmp;
48 u32 sku = sku_info->sku_id;
49 enum tegra_revision rev = sku_info->revision;
46 50
47 switch (sku) { 51 switch (sku) {
48 case 0x00: 52 case 0x00:
49 case 0x10: 53 case 0x10:
50 case 0x05: 54 case 0x05:
51 case 0x06: 55 case 0x06:
52 tegra_cpu_speedo_id = 1; 56 sku_info->cpu_speedo_id = 1;
53 tegra_soc_speedo_id = 0; 57 sku_info->soc_speedo_id = 0;
54 *threshold = THRESHOLD_INDEX_0; 58 *threshold = THRESHOLD_INDEX_0;
55 break; 59 break;
56 60
57 case 0x03: 61 case 0x03:
58 case 0x04: 62 case 0x04:
59 tegra_cpu_speedo_id = 2; 63 sku_info->cpu_speedo_id = 2;
60 tegra_soc_speedo_id = 1; 64 sku_info->soc_speedo_id = 1;
61 *threshold = THRESHOLD_INDEX_1; 65 *threshold = THRESHOLD_INDEX_1;
62 break; 66 break;
63 67
64 default: 68 default:
65 pr_err("Tegra114 Unknown SKU %d\n", sku); 69 pr_err("Tegra Unknown SKU %d\n", sku);
66 tegra_cpu_speedo_id = 0; 70 sku_info->cpu_speedo_id = 0;
67 tegra_soc_speedo_id = 0; 71 sku_info->soc_speedo_id = 0;
68 *threshold = THRESHOLD_INDEX_0; 72 *threshold = THRESHOLD_INDEX_0;
69 break; 73 break;
70 } 74 }
71 75
72 if (rev == TEGRA_REVISION_A01) { 76 if (rev == TEGRA_REVISION_A01) {
73 tmp = tegra_fuse_readl(0x270) << 1; 77 tmp = tegra30_fuse_readl(0x270) << 1;
74 tmp |= tegra_fuse_readl(0x26c); 78 tmp |= tegra30_fuse_readl(0x26c);
75 if (!tmp) 79 if (!tmp)
76 tegra_cpu_speedo_id = 0; 80 sku_info->cpu_speedo_id = 0;
77 } 81 }
78} 82}
79 83
80void tegra114_init_speedo_data(void) 84void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info)
81{ 85{
82 u32 cpu_speedo_val; 86 u32 cpu_speedo_val;
83 u32 core_speedo_val; 87 u32 core_speedo_val;
@@ -89,18 +93,18 @@ void tegra114_init_speedo_data(void)
89 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != 93 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
90 THRESHOLD_INDEX_COUNT); 94 THRESHOLD_INDEX_COUNT);
91 95
92 rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold); 96 rev_sku_to_speedo_ids(sku_info, &threshold);
93 97
94 cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024; 98 cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024;
95 core_speedo_val = tegra_fuse_readl(0x134); 99 core_speedo_val = tegra30_fuse_readl(0x134);
96 100
97 for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) 101 for (i = 0; i < CPU_PROCESS_CORNERS; i++)
98 if (cpu_speedo_val < cpu_process_speedos[threshold][i]) 102 if (cpu_speedo_val < cpu_process_speedos[threshold][i])
99 break; 103 break;
100 tegra_cpu_process_id = i; 104 sku_info->cpu_process_id = i;
101 105
102 for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) 106 for (i = 0; i < CORE_PROCESS_CORNERS; i++)
103 if (core_speedo_val < core_process_speedos[threshold][i]) 107 if (core_speedo_val < core_process_speedos[threshold][i])
104 break; 108 break;
105 tegra_core_process_id = i; 109 sku_info->core_process_id = i;
106} 110}
diff --git a/drivers/soc/tegra/fuse/speedo-tegra124.c b/drivers/soc/tegra/fuse/speedo-tegra124.c
new file mode 100644
index 000000000000..46362387d974
--- /dev/null
+++ b/drivers/soc/tegra/fuse/speedo-tegra124.c
@@ -0,0 +1,168 @@
1/*
2 * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/device.h>
18#include <linux/kernel.h>
19#include <linux/bug.h>
20
21#include <soc/tegra/fuse.h>
22
23#include "fuse.h"
24
25#define CPU_PROCESS_CORNERS 2
26#define GPU_PROCESS_CORNERS 2
27#define CORE_PROCESS_CORNERS 2
28
29#define FUSE_CPU_SPEEDO_0 0x14
30#define FUSE_CPU_SPEEDO_1 0x2c
31#define FUSE_CPU_SPEEDO_2 0x30
32#define FUSE_SOC_SPEEDO_0 0x34
33#define FUSE_SOC_SPEEDO_1 0x38
34#define FUSE_SOC_SPEEDO_2 0x3c
35#define FUSE_CPU_IDDQ 0x18
36#define FUSE_SOC_IDDQ 0x40
37#define FUSE_GPU_IDDQ 0x128
38#define FUSE_FT_REV 0x28
39
40enum {
41 THRESHOLD_INDEX_0,
42 THRESHOLD_INDEX_1,
43 THRESHOLD_INDEX_COUNT,
44};
45
46static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
47 {2190, UINT_MAX},
48 {0, UINT_MAX},
49};
50
51static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = {
52 {1965, UINT_MAX},
53 {0, UINT_MAX},
54};
55
56static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
57 {2101, UINT_MAX},
58 {0, UINT_MAX},
59};
60
61static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
62 int *threshold)
63{
64 int sku = sku_info->sku_id;
65
66 /* Assign to default */
67 sku_info->cpu_speedo_id = 0;
68 sku_info->soc_speedo_id = 0;
69 sku_info->gpu_speedo_id = 0;
70 *threshold = THRESHOLD_INDEX_0;
71
72 switch (sku) {
73 case 0x00: /* Eng sku */
74 case 0x0F:
75 case 0x23:
76 /* Using the default */
77 break;
78 case 0x83:
79 sku_info->cpu_speedo_id = 2;
80 break;
81
82 case 0x1F:
83 case 0x87:
84 case 0x27:
85 sku_info->cpu_speedo_id = 2;
86 sku_info->soc_speedo_id = 0;
87 sku_info->gpu_speedo_id = 1;
88 *threshold = THRESHOLD_INDEX_0;
89 break;
90 case 0x81:
91 case 0x21:
92 case 0x07:
93 sku_info->cpu_speedo_id = 1;
94 sku_info->soc_speedo_id = 1;
95 sku_info->gpu_speedo_id = 1;
96 *threshold = THRESHOLD_INDEX_1;
97 break;
98 case 0x49:
99 case 0x4A:
100 case 0x48:
101 sku_info->cpu_speedo_id = 4;
102 sku_info->soc_speedo_id = 2;
103 sku_info->gpu_speedo_id = 3;
104 *threshold = THRESHOLD_INDEX_1;
105 break;
106 default:
107 pr_err("Tegra Unknown SKU %d\n", sku);
108 /* Using the default for the error case */
109 break;
110 }
111}
112
113void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info)
114{
115 int i, threshold, cpu_speedo_0_value, soc_speedo_0_value;
116 int cpu_iddq_value, gpu_iddq_value, soc_iddq_value;
117
118 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
119 THRESHOLD_INDEX_COUNT);
120 BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) !=
121 THRESHOLD_INDEX_COUNT);
122 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
123 THRESHOLD_INDEX_COUNT);
124
125 cpu_speedo_0_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_0);
126
127 /* GPU Speedo is stored in CPU_SPEEDO_2 */
128 sku_info->gpu_speedo_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_2);
129
130 soc_speedo_0_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_0);
131
132 cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ);
133 soc_iddq_value = tegra30_fuse_readl(FUSE_SOC_IDDQ);
134 gpu_iddq_value = tegra30_fuse_readl(FUSE_GPU_IDDQ);
135
136 sku_info->cpu_speedo_value = cpu_speedo_0_value;
137
138 if (sku_info->cpu_speedo_value == 0) {
139 pr_warn("Tegra Warning: Speedo value not fused.\n");
140 WARN_ON(1);
141 return;
142 }
143
144 rev_sku_to_speedo_ids(sku_info, &threshold);
145
146 sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ);
147
148 for (i = 0; i < GPU_PROCESS_CORNERS; i++)
149 if (sku_info->gpu_speedo_value <
150 gpu_process_speedos[threshold][i])
151 break;
152 sku_info->gpu_process_id = i;
153
154 for (i = 0; i < CPU_PROCESS_CORNERS; i++)
155 if (sku_info->cpu_speedo_value <
156 cpu_process_speedos[threshold][i])
157 break;
158 sku_info->cpu_process_id = i;
159
160 for (i = 0; i < CORE_PROCESS_CORNERS; i++)
161 if (soc_speedo_0_value <
162 core_process_speedos[threshold][i])
163 break;
164 sku_info->core_process_id = i;
165
166 pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n",
167 sku_info->gpu_speedo_id, sku_info->gpu_speedo_value);
168}
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/drivers/soc/tegra/fuse/speedo-tegra20.c
index 2907cf8de2b1..eff1b63f330d 100644
--- a/arch/arm/mach-tegra/tegra20_speedo.c
+++ b/drivers/soc/tegra/fuse/speedo-tegra20.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 2 * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify it 4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License, 5 * under the terms and conditions of the GNU General Public License,
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include <linux/bug.h> 17#include <linux/bug.h>
18#include <linux/device.h>
18#include <linux/kernel.h> 19#include <linux/kernel.h>
19 20
20#include <soc/tegra/fuse.h> 21#include <soc/tegra/fuse.h>
@@ -49,19 +50,19 @@ enum {
49 SPEEDO_ID_COUNT, 50 SPEEDO_ID_COUNT,
50}; 51};
51 52
52static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = { 53static const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
53 {315, 366, 420, UINT_MAX}, 54 {315, 366, 420, UINT_MAX},
54 {303, 368, 419, UINT_MAX}, 55 {303, 368, 419, UINT_MAX},
55 {316, 331, 383, UINT_MAX}, 56 {316, 331, 383, UINT_MAX},
56}; 57};
57 58
58static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = { 59static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = {
59 {165, 195, 224, UINT_MAX}, 60 {165, 195, 224, UINT_MAX},
60 {165, 195, 224, UINT_MAX}, 61 {165, 195, 224, UINT_MAX},
61 {165, 195, 224, UINT_MAX}, 62 {165, 195, 224, UINT_MAX},
62}; 63};
63 64
64void tegra20_init_speedo_data(void) 65void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info)
65{ 66{
66 u32 reg; 67 u32 reg;
67 u32 val; 68 u32 val;
@@ -70,42 +71,40 @@ void tegra20_init_speedo_data(void)
70 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); 71 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT);
71 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); 72 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT);
72 73
73 if (SPEEDO_ID_SELECT_0(tegra_revision)) 74 if (SPEEDO_ID_SELECT_0(sku_info->revision))
74 tegra_soc_speedo_id = SPEEDO_ID_0; 75 sku_info->soc_speedo_id = SPEEDO_ID_0;
75 else if (SPEEDO_ID_SELECT_1(tegra_sku_id)) 76 else if (SPEEDO_ID_SELECT_1(sku_info->sku_id))
76 tegra_soc_speedo_id = SPEEDO_ID_1; 77 sku_info->soc_speedo_id = SPEEDO_ID_1;
77 else 78 else
78 tegra_soc_speedo_id = SPEEDO_ID_2; 79 sku_info->soc_speedo_id = SPEEDO_ID_2;
79 80
80 val = 0; 81 val = 0;
81 for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { 82 for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
82 reg = tegra_spare_fuse(i) | 83 reg = tegra20_spare_fuse_early(i) |
83 tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS); 84 tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS);
84 val = (val << 1) | (reg & 0x1); 85 val = (val << 1) | (reg & 0x1);
85 } 86 }
86 val = val * SPEEDO_MULT; 87 val = val * SPEEDO_MULT;
87 pr_debug("%s CPU speedo value %u\n", __func__, val); 88 pr_debug("Tegra CPU speedo value %u\n", val);
88 89
89 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { 90 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
90 if (val <= cpu_process_speedos[tegra_soc_speedo_id][i]) 91 if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i])
91 break; 92 break;
92 } 93 }
93 tegra_cpu_process_id = i; 94 sku_info->cpu_process_id = i;
94 95
95 val = 0; 96 val = 0;
96 for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { 97 for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) {
97 reg = tegra_spare_fuse(i) | 98 reg = tegra20_spare_fuse_early(i) |
98 tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS); 99 tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS);
99 val = (val << 1) | (reg & 0x1); 100 val = (val << 1) | (reg & 0x1);
100 } 101 }
101 val = val * SPEEDO_MULT; 102 val = val * SPEEDO_MULT;
102 pr_debug("%s Core speedo value %u\n", __func__, val); 103 pr_debug("Core speedo value %u\n", val);
103 104
104 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { 105 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
105 if (val <= core_process_speedos[tegra_soc_speedo_id][i]) 106 if (val <= core_process_speedos[sku_info->soc_speedo_id][i])
106 break; 107 break;
107 } 108 }
108 tegra_core_process_id = i; 109 sku_info->core_process_id = i;
109
110 pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id);
111} 110}
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/drivers/soc/tegra/fuse/speedo-tegra30.c
index 6f6102cd1e6b..b17f0dcdfebe 100644
--- a/arch/arm/mach-tegra/tegra30_speedo.c
+++ b/drivers/soc/tegra/fuse/speedo-tegra30.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 2 * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify it 4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License, 5 * under the terms and conditions of the GNU General Public License,
@@ -15,18 +15,19 @@
15 */ 15 */
16 16
17#include <linux/bug.h> 17#include <linux/bug.h>
18#include <linux/device.h>
18#include <linux/kernel.h> 19#include <linux/kernel.h>
19 20
20#include <soc/tegra/fuse.h> 21#include <soc/tegra/fuse.h>
21 22
22#include "fuse.h" 23#include "fuse.h"
23 24
24#define CORE_PROCESS_CORNERS_NUM 1 25#define CORE_PROCESS_CORNERS 1
25#define CPU_PROCESS_CORNERS_NUM 6 26#define CPU_PROCESS_CORNERS 6
26 27
27#define FUSE_SPEEDO_CALIB_0 0x114 28#define FUSE_SPEEDO_CALIB_0 0x14
28#define FUSE_PACKAGE_INFO 0X1FC 29#define FUSE_PACKAGE_INFO 0XFC
29#define FUSE_TEST_PROG_VER 0X128 30#define FUSE_TEST_PROG_VER 0X28
30 31
31#define G_SPEEDO_BIT_MINUS1 58 32#define G_SPEEDO_BIT_MINUS1 58
32#define G_SPEEDO_BIT_MINUS1_R 59 33#define G_SPEEDO_BIT_MINUS1_R 59
@@ -53,7 +54,7 @@ enum {
53 THRESHOLD_INDEX_COUNT, 54 THRESHOLD_INDEX_COUNT,
54}; 55};
55 56
56static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = { 57static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
57 {180}, 58 {180},
58 {170}, 59 {170},
59 {195}, 60 {195},
@@ -68,7 +69,7 @@ static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
68 {180}, 69 {180},
69}; 70};
70 71
71static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = { 72static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
72 {306, 338, 360, 376, UINT_MAX}, 73 {306, 338, 360, 376, UINT_MAX},
73 {295, 336, 358, 375, UINT_MAX}, 74 {295, 336, 358, 375, UINT_MAX},
74 {325, 325, 358, 375, UINT_MAX}, 75 {325, 325, 358, 375, UINT_MAX},
@@ -83,35 +84,34 @@ static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
83 {295, 336, 358, 375, 391, UINT_MAX}, 84 {295, 336, 358, 375, 391, UINT_MAX},
84}; 85};
85 86
86static int threshold_index; 87static int threshold_index __initdata;
87static int package_id;
88 88
89static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) 89static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
90{ 90{
91 u32 reg; 91 u32 reg;
92 int ate_ver; 92 int ate_ver;
93 int bit_minus1; 93 int bit_minus1;
94 int bit_minus2; 94 int bit_minus2;
95 95
96 reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0); 96 reg = tegra30_fuse_readl(FUSE_SPEEDO_CALIB_0);
97 97
98 *speedo_lp = (reg & 0xFFFF) * 4; 98 *speedo_lp = (reg & 0xFFFF) * 4;
99 *speedo_g = ((reg >> 16) & 0xFFFF) * 4; 99 *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
100 100
101 ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER); 101 ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER);
102 pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10); 102 pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10);
103 103
104 if (ate_ver >= 26) { 104 if (ate_ver >= 26) {
105 bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1); 105 bit_minus1 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1);
106 bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); 106 bit_minus1 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
107 bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2); 107 bit_minus2 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2);
108 bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); 108 bit_minus2 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
109 *speedo_lp |= (bit_minus1 << 1) | bit_minus2; 109 *speedo_lp |= (bit_minus1 << 1) | bit_minus2;
110 110
111 bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1); 111 bit_minus1 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1);
112 bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R); 112 bit_minus1 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
113 bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2); 113 bit_minus2 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2);
114 bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R); 114 bit_minus2 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2_R);
115 *speedo_g |= (bit_minus1 << 1) | bit_minus2; 115 *speedo_g |= (bit_minus1 << 1) | bit_minus2;
116 } else { 116 } else {
117 *speedo_lp |= 0x3; 117 *speedo_lp |= 0x3;
@@ -119,133 +119,131 @@ static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
119 } 119 }
120} 120}
121 121
122static void rev_sku_to_speedo_ids(int rev, int sku) 122static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info)
123{ 123{
124 switch (rev) { 124 int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
125
126 switch (sku_info->revision) {
125 case TEGRA_REVISION_A01: 127 case TEGRA_REVISION_A01:
126 tegra_cpu_speedo_id = 0; 128 sku_info->cpu_speedo_id = 0;
127 tegra_soc_speedo_id = 0; 129 sku_info->soc_speedo_id = 0;
128 threshold_index = THRESHOLD_INDEX_0; 130 threshold_index = THRESHOLD_INDEX_0;
129 break; 131 break;
130 case TEGRA_REVISION_A02: 132 case TEGRA_REVISION_A02:
131 case TEGRA_REVISION_A03: 133 case TEGRA_REVISION_A03:
132 switch (sku) { 134 switch (sku_info->sku_id) {
133 case 0x87: 135 case 0x87:
134 case 0x82: 136 case 0x82:
135 tegra_cpu_speedo_id = 1; 137 sku_info->cpu_speedo_id = 1;
136 tegra_soc_speedo_id = 1; 138 sku_info->soc_speedo_id = 1;
137 threshold_index = THRESHOLD_INDEX_1; 139 threshold_index = THRESHOLD_INDEX_1;
138 break; 140 break;
139 case 0x81: 141 case 0x81:
140 switch (package_id) { 142 switch (package_id) {
141 case 1: 143 case 1:
142 tegra_cpu_speedo_id = 2; 144 sku_info->cpu_speedo_id = 2;
143 tegra_soc_speedo_id = 2; 145 sku_info->soc_speedo_id = 2;
144 threshold_index = THRESHOLD_INDEX_2; 146 threshold_index = THRESHOLD_INDEX_2;
145 break; 147 break;
146 case 2: 148 case 2:
147 tegra_cpu_speedo_id = 4; 149 sku_info->cpu_speedo_id = 4;
148 tegra_soc_speedo_id = 1; 150 sku_info->soc_speedo_id = 1;
149 threshold_index = THRESHOLD_INDEX_7; 151 threshold_index = THRESHOLD_INDEX_7;
150 break; 152 break;
151 default: 153 default:
152 pr_err("Tegra30: Unknown pkg %d\n", package_id); 154 pr_err("Tegra Unknown pkg %d\n", package_id);
153 BUG();
154 break; 155 break;
155 } 156 }
156 break; 157 break;
157 case 0x80: 158 case 0x80:
158 switch (package_id) { 159 switch (package_id) {
159 case 1: 160 case 1:
160 tegra_cpu_speedo_id = 5; 161 sku_info->cpu_speedo_id = 5;
161 tegra_soc_speedo_id = 2; 162 sku_info->soc_speedo_id = 2;
162 threshold_index = THRESHOLD_INDEX_8; 163 threshold_index = THRESHOLD_INDEX_8;
163 break; 164 break;
164 case 2: 165 case 2:
165 tegra_cpu_speedo_id = 6; 166 sku_info->cpu_speedo_id = 6;
166 tegra_soc_speedo_id = 2; 167 sku_info->soc_speedo_id = 2;
167 threshold_index = THRESHOLD_INDEX_9; 168 threshold_index = THRESHOLD_INDEX_9;
168 break; 169 break;
169 default: 170 default:
170 pr_err("Tegra30: Unknown pkg %d\n", package_id); 171 pr_err("Tegra Unknown pkg %d\n", package_id);
171 BUG();
172 break; 172 break;
173 } 173 }
174 break; 174 break;
175 case 0x83: 175 case 0x83:
176 switch (package_id) { 176 switch (package_id) {
177 case 1: 177 case 1:
178 tegra_cpu_speedo_id = 7; 178 sku_info->cpu_speedo_id = 7;
179 tegra_soc_speedo_id = 1; 179 sku_info->soc_speedo_id = 1;
180 threshold_index = THRESHOLD_INDEX_10; 180 threshold_index = THRESHOLD_INDEX_10;
181 break; 181 break;
182 case 2: 182 case 2:
183 tegra_cpu_speedo_id = 3; 183 sku_info->cpu_speedo_id = 3;
184 tegra_soc_speedo_id = 2; 184 sku_info->soc_speedo_id = 2;
185 threshold_index = THRESHOLD_INDEX_3; 185 threshold_index = THRESHOLD_INDEX_3;
186 break; 186 break;
187 default: 187 default:
188 pr_err("Tegra30: Unknown pkg %d\n", package_id); 188 pr_err("Tegra Unknown pkg %d\n", package_id);
189 BUG();
190 break; 189 break;
191 } 190 }
192 break; 191 break;
193 case 0x8F: 192 case 0x8F:
194 tegra_cpu_speedo_id = 8; 193 sku_info->cpu_speedo_id = 8;
195 tegra_soc_speedo_id = 1; 194 sku_info->soc_speedo_id = 1;
196 threshold_index = THRESHOLD_INDEX_11; 195 threshold_index = THRESHOLD_INDEX_11;
197 break; 196 break;
198 case 0x08: 197 case 0x08:
199 tegra_cpu_speedo_id = 1; 198 sku_info->cpu_speedo_id = 1;
200 tegra_soc_speedo_id = 1; 199 sku_info->soc_speedo_id = 1;
201 threshold_index = THRESHOLD_INDEX_4; 200 threshold_index = THRESHOLD_INDEX_4;
202 break; 201 break;
203 case 0x02: 202 case 0x02:
204 tegra_cpu_speedo_id = 2; 203 sku_info->cpu_speedo_id = 2;
205 tegra_soc_speedo_id = 2; 204 sku_info->soc_speedo_id = 2;
206 threshold_index = THRESHOLD_INDEX_5; 205 threshold_index = THRESHOLD_INDEX_5;
207 break; 206 break;
208 case 0x04: 207 case 0x04:
209 tegra_cpu_speedo_id = 3; 208 sku_info->cpu_speedo_id = 3;
210 tegra_soc_speedo_id = 2; 209 sku_info->soc_speedo_id = 2;
211 threshold_index = THRESHOLD_INDEX_6; 210 threshold_index = THRESHOLD_INDEX_6;
212 break; 211 break;
213 case 0: 212 case 0:
214 switch (package_id) { 213 switch (package_id) {
215 case 1: 214 case 1:
216 tegra_cpu_speedo_id = 2; 215 sku_info->cpu_speedo_id = 2;
217 tegra_soc_speedo_id = 2; 216 sku_info->soc_speedo_id = 2;
218 threshold_index = THRESHOLD_INDEX_2; 217 threshold_index = THRESHOLD_INDEX_2;
219 break; 218 break;
220 case 2: 219 case 2:
221 tegra_cpu_speedo_id = 3; 220 sku_info->cpu_speedo_id = 3;
222 tegra_soc_speedo_id = 2; 221 sku_info->soc_speedo_id = 2;
223 threshold_index = THRESHOLD_INDEX_3; 222 threshold_index = THRESHOLD_INDEX_3;
224 break; 223 break;
225 default: 224 default:
226 pr_err("Tegra30: Unknown pkg %d\n", package_id); 225 pr_err("Tegra Unknown pkg %d\n", package_id);
227 BUG();
228 break; 226 break;
229 } 227 }
230 break; 228 break;
231 default: 229 default:
232 pr_warn("Tegra30: Unknown SKU %d\n", sku); 230 pr_warn("Tegra Unknown SKU %d\n", sku_info->sku_id);
233 tegra_cpu_speedo_id = 0; 231 sku_info->cpu_speedo_id = 0;
234 tegra_soc_speedo_id = 0; 232 sku_info->soc_speedo_id = 0;
235 threshold_index = THRESHOLD_INDEX_0; 233 threshold_index = THRESHOLD_INDEX_0;
236 break; 234 break;
237 } 235 }
238 break; 236 break;
239 default: 237 default:
240 pr_warn("Tegra30: Unknown chip rev %d\n", rev); 238 pr_warn("Tegra Unknown chip rev %d\n", sku_info->revision);
241 tegra_cpu_speedo_id = 0; 239 sku_info->cpu_speedo_id = 0;
242 tegra_soc_speedo_id = 0; 240 sku_info->soc_speedo_id = 0;
243 threshold_index = THRESHOLD_INDEX_0; 241 threshold_index = THRESHOLD_INDEX_0;
244 break; 242 break;
245 } 243 }
246} 244}
247 245
248void tegra30_init_speedo_data(void) 246void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info)
249{ 247{
250 u32 cpu_speedo_val; 248 u32 cpu_speedo_val;
251 u32 core_speedo_val; 249 u32 core_speedo_val;
@@ -256,39 +254,35 @@ void tegra30_init_speedo_data(void)
256 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != 254 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
257 THRESHOLD_INDEX_COUNT); 255 THRESHOLD_INDEX_COUNT);
258 256
259 package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
260 257
261 rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id); 258 rev_sku_to_speedo_ids(sku_info);
262 fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val); 259 fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
263 pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val); 260 pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val);
264 pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val); 261 pr_debug("Tegra Core speedo value %u\n", core_speedo_val);
265 262
266 for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) { 263 for (i = 0; i < CPU_PROCESS_CORNERS; i++) {
267 if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) 264 if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
268 break; 265 break;
269 } 266 }
270 tegra_cpu_process_id = i - 1; 267 sku_info->cpu_process_id = i - 1;
271 268
272 if (tegra_cpu_process_id == -1) { 269 if (sku_info->cpu_process_id == -1) {
273 pr_warn("Tegra30: CPU speedo value %3d out of range", 270 pr_warn("Tegra CPU speedo value %3d out of range",
274 cpu_speedo_val); 271 cpu_speedo_val);
275 tegra_cpu_process_id = 0; 272 sku_info->cpu_process_id = 0;
276 tegra_cpu_speedo_id = 1; 273 sku_info->cpu_speedo_id = 1;
277 } 274 }
278 275
279 for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) { 276 for (i = 0; i < CORE_PROCESS_CORNERS; i++) {
280 if (core_speedo_val < core_process_speedos[threshold_index][i]) 277 if (core_speedo_val < core_process_speedos[threshold_index][i])
281 break; 278 break;
282 } 279 }
283 tegra_core_process_id = i - 1; 280 sku_info->core_process_id = i - 1;
284 281
285 if (tegra_core_process_id == -1) { 282 if (sku_info->core_process_id == -1) {
286 pr_warn("Tegra30: CORE speedo value %3d out of range", 283 pr_warn("Tegra CORE speedo value %3d out of range",
287 core_speedo_val); 284 core_speedo_val);
288 tegra_core_process_id = 0; 285 sku_info->core_process_id = 0;
289 tegra_soc_speedo_id = 1; 286 sku_info->soc_speedo_id = 1;
290 } 287 }
291
292 pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
293 tegra_cpu_speedo_id, tegra_soc_speedo_id);
294} 288}
diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c
new file mode 100644
index 000000000000..bfc1d54ac4ad
--- /dev/null
+++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c
@@ -0,0 +1,112 @@
1/*
2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include <linux/kernel.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21#include <linux/io.h>
22
23#include <soc/tegra/fuse.h>
24
25#include "fuse.h"
26
27#define APBMISC_BASE 0x70000800
28#define APBMISC_SIZE 0x64
29#define FUSE_SKU_INFO 0x10
30
31static void __iomem *apbmisc_base;
32static void __iomem *strapping_base;
33
34u32 tegra_read_chipid(void)
35{
36 return readl_relaxed(apbmisc_base + 4);
37}
38
39u8 tegra_get_chip_id(void)
40{
41 u32 id = tegra_read_chipid();
42
43 return (id >> 8) & 0xff;
44}
45
46u32 tegra_read_straps(void)
47{
48 if (strapping_base)
49 return readl_relaxed(strapping_base);
50 else
51 return 0;
52}
53
54static const struct of_device_id apbmisc_match[] __initconst = {
55 { .compatible = "nvidia,tegra20-apbmisc", },
56 {},
57};
58
59void __init tegra_init_revision(void)
60{
61 u32 id, chip_id, minor_rev;
62 int rev;
63
64 id = tegra_read_chipid();
65 chip_id = (id >> 8) & 0xff;
66 minor_rev = (id >> 16) & 0xf;
67
68 switch (minor_rev) {
69 case 1:
70 rev = TEGRA_REVISION_A01;
71 break;
72 case 2:
73 rev = TEGRA_REVISION_A02;
74 break;
75 case 3:
76 if (chip_id == TEGRA20 && (tegra20_spare_fuse_early(18) ||
77 tegra20_spare_fuse_early(19)))
78 rev = TEGRA_REVISION_A03p;
79 else
80 rev = TEGRA_REVISION_A03;
81 break;
82 case 4:
83 rev = TEGRA_REVISION_A04;
84 break;
85 default:
86 rev = TEGRA_REVISION_UNKNOWN;
87 }
88
89 tegra_sku_info.revision = rev;
90
91 if (chip_id == TEGRA20)
92 tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO);
93 else
94 tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO);
95}
96
97void __init tegra_init_apbmisc(void)
98{
99 struct device_node *np;
100
101 np = of_find_matching_node(NULL, apbmisc_match);
102 apbmisc_base = of_iomap(np, 0);
103 if (!apbmisc_base) {
104 pr_warn("ioremap tegra apbmisc failed. using %08x instead\n",
105 APBMISC_BASE);
106 apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE);
107 }
108
109 strapping_base = of_iomap(np, 1);
110 if (!strapping_base)
111 pr_err("ioremap tegra strapping_base failed\n");
112}
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h
index 822eb348e107..51ac804deba5 100644
--- a/include/soc/tegra/fuse.h
+++ b/include/soc/tegra/fuse.h
@@ -22,6 +22,9 @@
22#define TEGRA114 0x35 22#define TEGRA114 0x35
23#define TEGRA124 0x40 23#define TEGRA124 0x40
24 24
25#define TEGRA_FUSE_SKU_CALIB_0 0xf0
26#define TEGRA30_FUSE_SATA_CALIB 0x124
27
25#ifndef __ASSEMBLY__ 28#ifndef __ASSEMBLY__
26 29
27u32 tegra_read_chipid(void); 30u32 tegra_read_chipid(void);
@@ -37,11 +40,26 @@ enum tegra_revision {
37 TEGRA_REVISION_MAX, 40 TEGRA_REVISION_MAX,
38}; 41};
39 42
43struct tegra_sku_info {
44 int sku_id;
45 int cpu_process_id;
46 int cpu_speedo_id;
47 int cpu_speedo_value;
48 int cpu_iddq_value;
49 int core_process_id;
50 int soc_speedo_id;
51 int gpu_speedo_id;
52 int gpu_process_id;
53 int gpu_speedo_value;
54 enum tegra_revision revision;
55};
56
40u32 tegra_read_straps(void); 57u32 tegra_read_straps(void);
41u32 tegra_read_chipid(void); 58u32 tegra_read_chipid(void);
42void tegra_init_fuse(void); 59void tegra_init_fuse(void);
60int tegra_fuse_readl(unsigned long offset, u32 *value);
43 61
44extern enum tegra_revision tegra_revision; 62extern struct tegra_sku_info tegra_sku_info;
45 63
46#if defined(CONFIG_TEGRA20_APB_DMA) 64#if defined(CONFIG_TEGRA20_APB_DMA)
47int tegra_apb_readl_using_dma(unsigned long offset, u32 *value); 65int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);