aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorPeter De Schrijver <pdeschrijver@nvidia.com>2014-06-12 11:36:37 -0400
committerThierry Reding <treding@nvidia.com>2014-07-17 08:36:01 -0400
commit783c8f4c84451bc444e314a71b447239c6ef6fd9 (patch)
treeccf8ed545ac850e06d3e781a99769bd0ea43c597 /arch/arm
parent35874f3617b38e0c1f72163407c41d554a8f5939 (diff)
soc/tegra: Add efuse driver for Tegra
Implement fuse driver for Tegra20, Tegra30, Tegra114 and Tegra124. This replaces functionality previously provided in arch/arm/mach-tegra, which is removed in this patch. While at it, move the only user of the global tegra_revision variable over to tegra_sku_info.revision and export tegra_fuse_readl() to allow drivers to read calibration fuses. Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'arch/arm')
-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--arch/arm/mach-tegra/tegra114_speedo.c106
-rw-r--r--arch/arm/mach-tegra/tegra20_speedo.c111
-rw-r--r--arch/arm/mach-tegra/tegra30_speedo.c294
8 files changed, 2 insertions, 837 deletions
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/arch/arm/mach-tegra/tegra114_speedo.c b/arch/arm/mach-tegra/tegra114_speedo.c
deleted file mode 100644
index d0a6d5925f5f..000000000000
--- a/arch/arm/mach-tegra/tegra114_speedo.c
+++ /dev/null
@@ -1,106 +0,0 @@
1/*
2 * Copyright (c) 2013, 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/bug.h>
18#include <linux/kernel.h>
19
20#include <soc/tegra/fuse.h>
21
22#include "fuse.h"
23
24#define CORE_PROCESS_CORNERS_NUM 2
25#define CPU_PROCESS_CORNERS_NUM 2
26
27enum {
28 THRESHOLD_INDEX_0,
29 THRESHOLD_INDEX_1,
30 THRESHOLD_INDEX_COUNT,
31};
32
33static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
34 {1123, UINT_MAX},
35 {0, UINT_MAX},
36};
37
38static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
39 {1695, UINT_MAX},
40 {0, UINT_MAX},
41};
42
43static void rev_sku_to_speedo_ids(int rev, int sku, int *threshold)
44{
45 u32 tmp;
46
47 switch (sku) {
48 case 0x00:
49 case 0x10:
50 case 0x05:
51 case 0x06:
52 tegra_cpu_speedo_id = 1;
53 tegra_soc_speedo_id = 0;
54 *threshold = THRESHOLD_INDEX_0;
55 break;
56
57 case 0x03:
58 case 0x04:
59 tegra_cpu_speedo_id = 2;
60 tegra_soc_speedo_id = 1;
61 *threshold = THRESHOLD_INDEX_1;
62 break;
63
64 default:
65 pr_err("Tegra114 Unknown SKU %d\n", sku);
66 tegra_cpu_speedo_id = 0;
67 tegra_soc_speedo_id = 0;
68 *threshold = THRESHOLD_INDEX_0;
69 break;
70 }
71
72 if (rev == TEGRA_REVISION_A01) {
73 tmp = tegra_fuse_readl(0x270) << 1;
74 tmp |= tegra_fuse_readl(0x26c);
75 if (!tmp)
76 tegra_cpu_speedo_id = 0;
77 }
78}
79
80void tegra114_init_speedo_data(void)
81{
82 u32 cpu_speedo_val;
83 u32 core_speedo_val;
84 int threshold;
85 int i;
86
87 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
88 THRESHOLD_INDEX_COUNT);
89 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
90 THRESHOLD_INDEX_COUNT);
91
92 rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id, &threshold);
93
94 cpu_speedo_val = tegra_fuse_readl(0x12c) + 1024;
95 core_speedo_val = tegra_fuse_readl(0x134);
96
97 for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++)
98 if (cpu_speedo_val < cpu_process_speedos[threshold][i])
99 break;
100 tegra_cpu_process_id = i;
101
102 for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++)
103 if (core_speedo_val < core_process_speedos[threshold][i])
104 break;
105 tegra_core_process_id = i;
106}
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c
deleted file mode 100644
index 2907cf8de2b1..000000000000
--- a/arch/arm/mach-tegra/tegra20_speedo.c
+++ /dev/null
@@ -1,111 +0,0 @@
1/*
2 * Copyright (c) 2012, 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/bug.h>
18#include <linux/kernel.h>
19
20#include <soc/tegra/fuse.h>
21
22#include "fuse.h"
23
24#define CPU_SPEEDO_LSBIT 20
25#define CPU_SPEEDO_MSBIT 29
26#define CPU_SPEEDO_REDUND_LSBIT 30
27#define CPU_SPEEDO_REDUND_MSBIT 39
28#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
29
30#define CORE_SPEEDO_LSBIT 40
31#define CORE_SPEEDO_MSBIT 47
32#define CORE_SPEEDO_REDUND_LSBIT 48
33#define CORE_SPEEDO_REDUND_MSBIT 55
34#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT)
35
36#define SPEEDO_MULT 4
37
38#define PROCESS_CORNERS_NUM 4
39
40#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2)
41#define SPEEDO_ID_SELECT_1(sku) \
42 (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
43 ((sku) != 27) && ((sku) != 28))
44
45enum {
46 SPEEDO_ID_0,
47 SPEEDO_ID_1,
48 SPEEDO_ID_2,
49 SPEEDO_ID_COUNT,
50};
51
52static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
53 {315, 366, 420, UINT_MAX},
54 {303, 368, 419, UINT_MAX},
55 {316, 331, 383, UINT_MAX},
56};
57
58static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
59 {165, 195, 224, UINT_MAX},
60 {165, 195, 224, UINT_MAX},
61 {165, 195, 224, UINT_MAX},
62};
63
64void tegra20_init_speedo_data(void)
65{
66 u32 reg;
67 u32 val;
68 int i;
69
70 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT);
71 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT);
72
73 if (SPEEDO_ID_SELECT_0(tegra_revision))
74 tegra_soc_speedo_id = SPEEDO_ID_0;
75 else if (SPEEDO_ID_SELECT_1(tegra_sku_id))
76 tegra_soc_speedo_id = SPEEDO_ID_1;
77 else
78 tegra_soc_speedo_id = SPEEDO_ID_2;
79
80 val = 0;
81 for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
82 reg = tegra_spare_fuse(i) |
83 tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS);
84 val = (val << 1) | (reg & 0x1);
85 }
86 val = val * SPEEDO_MULT;
87 pr_debug("%s CPU speedo value %u\n", __func__, val);
88
89 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
90 if (val <= cpu_process_speedos[tegra_soc_speedo_id][i])
91 break;
92 }
93 tegra_cpu_process_id = i;
94
95 val = 0;
96 for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) {
97 reg = tegra_spare_fuse(i) |
98 tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS);
99 val = (val << 1) | (reg & 0x1);
100 }
101 val = val * SPEEDO_MULT;
102 pr_debug("%s Core speedo value %u\n", __func__, val);
103
104 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
105 if (val <= core_process_speedos[tegra_soc_speedo_id][i])
106 break;
107 }
108 tegra_core_process_id = i;
109
110 pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id);
111}
diff --git a/arch/arm/mach-tegra/tegra30_speedo.c b/arch/arm/mach-tegra/tegra30_speedo.c
deleted file mode 100644
index 6f6102cd1e6b..000000000000
--- a/arch/arm/mach-tegra/tegra30_speedo.c
+++ /dev/null
@@ -1,294 +0,0 @@
1/*
2 * Copyright (c) 2012, 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/bug.h>
18#include <linux/kernel.h>
19
20#include <soc/tegra/fuse.h>
21
22#include "fuse.h"
23
24#define CORE_PROCESS_CORNERS_NUM 1
25#define CPU_PROCESS_CORNERS_NUM 6
26
27#define FUSE_SPEEDO_CALIB_0 0x114
28#define FUSE_PACKAGE_INFO 0X1FC
29#define FUSE_TEST_PROG_VER 0X128
30
31#define G_SPEEDO_BIT_MINUS1 58
32#define G_SPEEDO_BIT_MINUS1_R 59
33#define G_SPEEDO_BIT_MINUS2 60
34#define G_SPEEDO_BIT_MINUS2_R 61
35#define LP_SPEEDO_BIT_MINUS1 62
36#define LP_SPEEDO_BIT_MINUS1_R 63
37#define LP_SPEEDO_BIT_MINUS2 64
38#define LP_SPEEDO_BIT_MINUS2_R 65
39
40enum {
41 THRESHOLD_INDEX_0,
42 THRESHOLD_INDEX_1,
43 THRESHOLD_INDEX_2,
44 THRESHOLD_INDEX_3,
45 THRESHOLD_INDEX_4,
46 THRESHOLD_INDEX_5,
47 THRESHOLD_INDEX_6,
48 THRESHOLD_INDEX_7,
49 THRESHOLD_INDEX_8,
50 THRESHOLD_INDEX_9,
51 THRESHOLD_INDEX_10,
52 THRESHOLD_INDEX_11,
53 THRESHOLD_INDEX_COUNT,
54};
55
56static const u32 core_process_speedos[][CORE_PROCESS_CORNERS_NUM] = {
57 {180},
58 {170},
59 {195},
60 {180},
61 {168},
62 {192},
63 {180},
64 {170},
65 {195},
66 {180},
67 {180},
68 {180},
69};
70
71static const u32 cpu_process_speedos[][CPU_PROCESS_CORNERS_NUM] = {
72 {306, 338, 360, 376, UINT_MAX},
73 {295, 336, 358, 375, UINT_MAX},
74 {325, 325, 358, 375, UINT_MAX},
75 {325, 325, 358, 375, UINT_MAX},
76 {292, 324, 348, 364, UINT_MAX},
77 {324, 324, 348, 364, UINT_MAX},
78 {324, 324, 348, 364, UINT_MAX},
79 {295, 336, 358, 375, UINT_MAX},
80 {358, 358, 358, 358, 397, UINT_MAX},
81 {364, 364, 364, 364, 397, UINT_MAX},
82 {295, 336, 358, 375, 391, UINT_MAX},
83 {295, 336, 358, 375, 391, UINT_MAX},
84};
85
86static int threshold_index;
87static int package_id;
88
89static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
90{
91 u32 reg;
92 int ate_ver;
93 int bit_minus1;
94 int bit_minus2;
95
96 reg = tegra_fuse_readl(FUSE_SPEEDO_CALIB_0);
97
98 *speedo_lp = (reg & 0xFFFF) * 4;
99 *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
100
101 ate_ver = tegra_fuse_readl(FUSE_TEST_PROG_VER);
102 pr_info("%s: ATE prog ver %d.%d\n", __func__, ate_ver/10, ate_ver%10);
103
104 if (ate_ver >= 26) {
105 bit_minus1 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1);
106 bit_minus1 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
107 bit_minus2 = tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2);
108 bit_minus2 |= tegra_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
109 *speedo_lp |= (bit_minus1 << 1) | bit_minus2;
110
111 bit_minus1 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS1);
112 bit_minus1 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
113 bit_minus2 = tegra_spare_fuse(G_SPEEDO_BIT_MINUS2);
114 bit_minus2 |= tegra_spare_fuse(G_SPEEDO_BIT_MINUS2_R);
115 *speedo_g |= (bit_minus1 << 1) | bit_minus2;
116 } else {
117 *speedo_lp |= 0x3;
118 *speedo_g |= 0x3;
119 }
120}
121
122static void rev_sku_to_speedo_ids(int rev, int sku)
123{
124 switch (rev) {
125 case TEGRA_REVISION_A01:
126 tegra_cpu_speedo_id = 0;
127 tegra_soc_speedo_id = 0;
128 threshold_index = THRESHOLD_INDEX_0;
129 break;
130 case TEGRA_REVISION_A02:
131 case TEGRA_REVISION_A03:
132 switch (sku) {
133 case 0x87:
134 case 0x82:
135 tegra_cpu_speedo_id = 1;
136 tegra_soc_speedo_id = 1;
137 threshold_index = THRESHOLD_INDEX_1;
138 break;
139 case 0x81:
140 switch (package_id) {
141 case 1:
142 tegra_cpu_speedo_id = 2;
143 tegra_soc_speedo_id = 2;
144 threshold_index = THRESHOLD_INDEX_2;
145 break;
146 case 2:
147 tegra_cpu_speedo_id = 4;
148 tegra_soc_speedo_id = 1;
149 threshold_index = THRESHOLD_INDEX_7;
150 break;
151 default:
152 pr_err("Tegra30: Unknown pkg %d\n", package_id);
153 BUG();
154 break;
155 }
156 break;
157 case 0x80:
158 switch (package_id) {
159 case 1:
160 tegra_cpu_speedo_id = 5;
161 tegra_soc_speedo_id = 2;
162 threshold_index = THRESHOLD_INDEX_8;
163 break;
164 case 2:
165 tegra_cpu_speedo_id = 6;
166 tegra_soc_speedo_id = 2;
167 threshold_index = THRESHOLD_INDEX_9;
168 break;
169 default:
170 pr_err("Tegra30: Unknown pkg %d\n", package_id);
171 BUG();
172 break;
173 }
174 break;
175 case 0x83:
176 switch (package_id) {
177 case 1:
178 tegra_cpu_speedo_id = 7;
179 tegra_soc_speedo_id = 1;
180 threshold_index = THRESHOLD_INDEX_10;
181 break;
182 case 2:
183 tegra_cpu_speedo_id = 3;
184 tegra_soc_speedo_id = 2;
185 threshold_index = THRESHOLD_INDEX_3;
186 break;
187 default:
188 pr_err("Tegra30: Unknown pkg %d\n", package_id);
189 BUG();
190 break;
191 }
192 break;
193 case 0x8F:
194 tegra_cpu_speedo_id = 8;
195 tegra_soc_speedo_id = 1;
196 threshold_index = THRESHOLD_INDEX_11;
197 break;
198 case 0x08:
199 tegra_cpu_speedo_id = 1;
200 tegra_soc_speedo_id = 1;
201 threshold_index = THRESHOLD_INDEX_4;
202 break;
203 case 0x02:
204 tegra_cpu_speedo_id = 2;
205 tegra_soc_speedo_id = 2;
206 threshold_index = THRESHOLD_INDEX_5;
207 break;
208 case 0x04:
209 tegra_cpu_speedo_id = 3;
210 tegra_soc_speedo_id = 2;
211 threshold_index = THRESHOLD_INDEX_6;
212 break;
213 case 0:
214 switch (package_id) {
215 case 1:
216 tegra_cpu_speedo_id = 2;
217 tegra_soc_speedo_id = 2;
218 threshold_index = THRESHOLD_INDEX_2;
219 break;
220 case 2:
221 tegra_cpu_speedo_id = 3;
222 tegra_soc_speedo_id = 2;
223 threshold_index = THRESHOLD_INDEX_3;
224 break;
225 default:
226 pr_err("Tegra30: Unknown pkg %d\n", package_id);
227 BUG();
228 break;
229 }
230 break;
231 default:
232 pr_warn("Tegra30: Unknown SKU %d\n", sku);
233 tegra_cpu_speedo_id = 0;
234 tegra_soc_speedo_id = 0;
235 threshold_index = THRESHOLD_INDEX_0;
236 break;
237 }
238 break;
239 default:
240 pr_warn("Tegra30: Unknown chip rev %d\n", rev);
241 tegra_cpu_speedo_id = 0;
242 tegra_soc_speedo_id = 0;
243 threshold_index = THRESHOLD_INDEX_0;
244 break;
245 }
246}
247
248void tegra30_init_speedo_data(void)
249{
250 u32 cpu_speedo_val;
251 u32 core_speedo_val;
252 int i;
253
254 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
255 THRESHOLD_INDEX_COUNT);
256 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
257 THRESHOLD_INDEX_COUNT);
258
259 package_id = tegra_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
260
261 rev_sku_to_speedo_ids(tegra_revision, tegra_sku_id);
262 fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
263 pr_debug("%s CPU speedo value %u\n", __func__, cpu_speedo_val);
264 pr_debug("%s Core speedo value %u\n", __func__, core_speedo_val);
265
266 for (i = 0; i < CPU_PROCESS_CORNERS_NUM; i++) {
267 if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
268 break;
269 }
270 tegra_cpu_process_id = i - 1;
271
272 if (tegra_cpu_process_id == -1) {
273 pr_warn("Tegra30: CPU speedo value %3d out of range",
274 cpu_speedo_val);
275 tegra_cpu_process_id = 0;
276 tegra_cpu_speedo_id = 1;
277 }
278
279 for (i = 0; i < CORE_PROCESS_CORNERS_NUM; i++) {
280 if (core_speedo_val < core_process_speedos[threshold_index][i])
281 break;
282 }
283 tegra_core_process_id = i - 1;
284
285 if (tegra_core_process_id == -1) {
286 pr_warn("Tegra30: CORE speedo value %3d out of range",
287 core_speedo_val);
288 tegra_core_process_id = 0;
289 tegra_soc_speedo_id = 1;
290 }
291
292 pr_info("Tegra30: CPU Speedo ID %d, Soc Speedo ID %d",
293 tegra_cpu_speedo_id, tegra_soc_speedo_id);
294}