aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/soc/tegra
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 /drivers/soc/tegra
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 'drivers/soc/tegra')
-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.c110
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra124.c168
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra20.c110
-rw-r--r--drivers/soc/tegra/fuse/speedo-tegra30.c288
-rw-r--r--drivers/soc/tegra/fuse/tegra-apbmisc.c112
11 files changed, 1390 insertions, 0 deletions
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/drivers/soc/tegra/fuse/speedo-tegra114.c b/drivers/soc/tegra/fuse/speedo-tegra114.c
new file mode 100644
index 000000000000..2a6ca036f09f
--- /dev/null
+++ b/drivers/soc/tegra/fuse/speedo-tegra114.c
@@ -0,0 +1,110 @@
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/bug.h>
18#include <linux/device.h>
19#include <linux/kernel.h>
20
21#include <soc/tegra/fuse.h>
22
23#include "fuse.h"
24
25#define CORE_PROCESS_CORNERS 2
26#define CPU_PROCESS_CORNERS 2
27
28enum {
29 THRESHOLD_INDEX_0,
30 THRESHOLD_INDEX_1,
31 THRESHOLD_INDEX_COUNT,
32};
33
34static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
35 {1123, UINT_MAX},
36 {0, UINT_MAX},
37};
38
39static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
40 {1695, UINT_MAX},
41 {0, UINT_MAX},
42};
43
44static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info,
45 int *threshold)
46{
47 u32 tmp;
48 u32 sku = sku_info->sku_id;
49 enum tegra_revision rev = sku_info->revision;
50
51 switch (sku) {
52 case 0x00:
53 case 0x10:
54 case 0x05:
55 case 0x06:
56 sku_info->cpu_speedo_id = 1;
57 sku_info->soc_speedo_id = 0;
58 *threshold = THRESHOLD_INDEX_0;
59 break;
60
61 case 0x03:
62 case 0x04:
63 sku_info->cpu_speedo_id = 2;
64 sku_info->soc_speedo_id = 1;
65 *threshold = THRESHOLD_INDEX_1;
66 break;
67
68 default:
69 pr_err("Tegra Unknown SKU %d\n", sku);
70 sku_info->cpu_speedo_id = 0;
71 sku_info->soc_speedo_id = 0;
72 *threshold = THRESHOLD_INDEX_0;
73 break;
74 }
75
76 if (rev == TEGRA_REVISION_A01) {
77 tmp = tegra30_fuse_readl(0x270) << 1;
78 tmp |= tegra30_fuse_readl(0x26c);
79 if (!tmp)
80 sku_info->cpu_speedo_id = 0;
81 }
82}
83
84void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info)
85{
86 u32 cpu_speedo_val;
87 u32 core_speedo_val;
88 int threshold;
89 int i;
90
91 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
92 THRESHOLD_INDEX_COUNT);
93 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
94 THRESHOLD_INDEX_COUNT);
95
96 rev_sku_to_speedo_ids(sku_info, &threshold);
97
98 cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024;
99 core_speedo_val = tegra30_fuse_readl(0x134);
100
101 for (i = 0; i < CPU_PROCESS_CORNERS; i++)
102 if (cpu_speedo_val < cpu_process_speedos[threshold][i])
103 break;
104 sku_info->cpu_process_id = i;
105
106 for (i = 0; i < CORE_PROCESS_CORNERS; i++)
107 if (core_speedo_val < core_process_speedos[threshold][i])
108 break;
109 sku_info->core_process_id = i;
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/drivers/soc/tegra/fuse/speedo-tegra20.c b/drivers/soc/tegra/fuse/speedo-tegra20.c
new file mode 100644
index 000000000000..eff1b63f330d
--- /dev/null
+++ b/drivers/soc/tegra/fuse/speedo-tegra20.c
@@ -0,0 +1,110 @@
1/*
2 * Copyright (c) 2012-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/bug.h>
18#include <linux/device.h>
19#include <linux/kernel.h>
20
21#include <soc/tegra/fuse.h>
22
23#include "fuse.h"
24
25#define CPU_SPEEDO_LSBIT 20
26#define CPU_SPEEDO_MSBIT 29
27#define CPU_SPEEDO_REDUND_LSBIT 30
28#define CPU_SPEEDO_REDUND_MSBIT 39
29#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
30
31#define CORE_SPEEDO_LSBIT 40
32#define CORE_SPEEDO_MSBIT 47
33#define CORE_SPEEDO_REDUND_LSBIT 48
34#define CORE_SPEEDO_REDUND_MSBIT 55
35#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT)
36
37#define SPEEDO_MULT 4
38
39#define PROCESS_CORNERS_NUM 4
40
41#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2)
42#define SPEEDO_ID_SELECT_1(sku) \
43 (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
44 ((sku) != 27) && ((sku) != 28))
45
46enum {
47 SPEEDO_ID_0,
48 SPEEDO_ID_1,
49 SPEEDO_ID_2,
50 SPEEDO_ID_COUNT,
51};
52
53static const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
54 {315, 366, 420, UINT_MAX},
55 {303, 368, 419, UINT_MAX},
56 {316, 331, 383, UINT_MAX},
57};
58
59static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = {
60 {165, 195, 224, UINT_MAX},
61 {165, 195, 224, UINT_MAX},
62 {165, 195, 224, UINT_MAX},
63};
64
65void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info)
66{
67 u32 reg;
68 u32 val;
69 int i;
70
71 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT);
72 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT);
73
74 if (SPEEDO_ID_SELECT_0(sku_info->revision))
75 sku_info->soc_speedo_id = SPEEDO_ID_0;
76 else if (SPEEDO_ID_SELECT_1(sku_info->sku_id))
77 sku_info->soc_speedo_id = SPEEDO_ID_1;
78 else
79 sku_info->soc_speedo_id = SPEEDO_ID_2;
80
81 val = 0;
82 for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) {
83 reg = tegra20_spare_fuse_early(i) |
84 tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS);
85 val = (val << 1) | (reg & 0x1);
86 }
87 val = val * SPEEDO_MULT;
88 pr_debug("Tegra CPU speedo value %u\n", val);
89
90 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
91 if (val <= cpu_process_speedos[sku_info->soc_speedo_id][i])
92 break;
93 }
94 sku_info->cpu_process_id = i;
95
96 val = 0;
97 for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) {
98 reg = tegra20_spare_fuse_early(i) |
99 tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS);
100 val = (val << 1) | (reg & 0x1);
101 }
102 val = val * SPEEDO_MULT;
103 pr_debug("Core speedo value %u\n", val);
104
105 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
106 if (val <= core_process_speedos[sku_info->soc_speedo_id][i])
107 break;
108 }
109 sku_info->core_process_id = i;
110}
diff --git a/drivers/soc/tegra/fuse/speedo-tegra30.c b/drivers/soc/tegra/fuse/speedo-tegra30.c
new file mode 100644
index 000000000000..b17f0dcdfebe
--- /dev/null
+++ b/drivers/soc/tegra/fuse/speedo-tegra30.c
@@ -0,0 +1,288 @@
1/*
2 * Copyright (c) 2012-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/bug.h>
18#include <linux/device.h>
19#include <linux/kernel.h>
20
21#include <soc/tegra/fuse.h>
22
23#include "fuse.h"
24
25#define CORE_PROCESS_CORNERS 1
26#define CPU_PROCESS_CORNERS 6
27
28#define FUSE_SPEEDO_CALIB_0 0x14
29#define FUSE_PACKAGE_INFO 0XFC
30#define FUSE_TEST_PROG_VER 0X28
31
32#define G_SPEEDO_BIT_MINUS1 58
33#define G_SPEEDO_BIT_MINUS1_R 59
34#define G_SPEEDO_BIT_MINUS2 60
35#define G_SPEEDO_BIT_MINUS2_R 61
36#define LP_SPEEDO_BIT_MINUS1 62
37#define LP_SPEEDO_BIT_MINUS1_R 63
38#define LP_SPEEDO_BIT_MINUS2 64
39#define LP_SPEEDO_BIT_MINUS2_R 65
40
41enum {
42 THRESHOLD_INDEX_0,
43 THRESHOLD_INDEX_1,
44 THRESHOLD_INDEX_2,
45 THRESHOLD_INDEX_3,
46 THRESHOLD_INDEX_4,
47 THRESHOLD_INDEX_5,
48 THRESHOLD_INDEX_6,
49 THRESHOLD_INDEX_7,
50 THRESHOLD_INDEX_8,
51 THRESHOLD_INDEX_9,
52 THRESHOLD_INDEX_10,
53 THRESHOLD_INDEX_11,
54 THRESHOLD_INDEX_COUNT,
55};
56
57static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = {
58 {180},
59 {170},
60 {195},
61 {180},
62 {168},
63 {192},
64 {180},
65 {170},
66 {195},
67 {180},
68 {180},
69 {180},
70};
71
72static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
73 {306, 338, 360, 376, UINT_MAX},
74 {295, 336, 358, 375, UINT_MAX},
75 {325, 325, 358, 375, UINT_MAX},
76 {325, 325, 358, 375, UINT_MAX},
77 {292, 324, 348, 364, UINT_MAX},
78 {324, 324, 348, 364, UINT_MAX},
79 {324, 324, 348, 364, UINT_MAX},
80 {295, 336, 358, 375, UINT_MAX},
81 {358, 358, 358, 358, 397, UINT_MAX},
82 {364, 364, 364, 364, 397, UINT_MAX},
83 {295, 336, 358, 375, 391, UINT_MAX},
84 {295, 336, 358, 375, 391, UINT_MAX},
85};
86
87static int threshold_index __initdata;
88
89static void __init 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 = tegra30_fuse_readl(FUSE_SPEEDO_CALIB_0);
97
98 *speedo_lp = (reg & 0xFFFF) * 4;
99 *speedo_g = ((reg >> 16) & 0xFFFF) * 4;
100
101 ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER);
102 pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10);
103
104 if (ate_ver >= 26) {
105 bit_minus1 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1);
106 bit_minus1 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1_R);
107 bit_minus2 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2);
108 bit_minus2 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2_R);
109 *speedo_lp |= (bit_minus1 << 1) | bit_minus2;
110
111 bit_minus1 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1);
112 bit_minus1 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1_R);
113 bit_minus2 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2);
114 bit_minus2 |= tegra30_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 __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info)
123{
124 int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F;
125
126 switch (sku_info->revision) {
127 case TEGRA_REVISION_A01:
128 sku_info->cpu_speedo_id = 0;
129 sku_info->soc_speedo_id = 0;
130 threshold_index = THRESHOLD_INDEX_0;
131 break;
132 case TEGRA_REVISION_A02:
133 case TEGRA_REVISION_A03:
134 switch (sku_info->sku_id) {
135 case 0x87:
136 case 0x82:
137 sku_info->cpu_speedo_id = 1;
138 sku_info->soc_speedo_id = 1;
139 threshold_index = THRESHOLD_INDEX_1;
140 break;
141 case 0x81:
142 switch (package_id) {
143 case 1:
144 sku_info->cpu_speedo_id = 2;
145 sku_info->soc_speedo_id = 2;
146 threshold_index = THRESHOLD_INDEX_2;
147 break;
148 case 2:
149 sku_info->cpu_speedo_id = 4;
150 sku_info->soc_speedo_id = 1;
151 threshold_index = THRESHOLD_INDEX_7;
152 break;
153 default:
154 pr_err("Tegra Unknown pkg %d\n", package_id);
155 break;
156 }
157 break;
158 case 0x80:
159 switch (package_id) {
160 case 1:
161 sku_info->cpu_speedo_id = 5;
162 sku_info->soc_speedo_id = 2;
163 threshold_index = THRESHOLD_INDEX_8;
164 break;
165 case 2:
166 sku_info->cpu_speedo_id = 6;
167 sku_info->soc_speedo_id = 2;
168 threshold_index = THRESHOLD_INDEX_9;
169 break;
170 default:
171 pr_err("Tegra Unknown pkg %d\n", package_id);
172 break;
173 }
174 break;
175 case 0x83:
176 switch (package_id) {
177 case 1:
178 sku_info->cpu_speedo_id = 7;
179 sku_info->soc_speedo_id = 1;
180 threshold_index = THRESHOLD_INDEX_10;
181 break;
182 case 2:
183 sku_info->cpu_speedo_id = 3;
184 sku_info->soc_speedo_id = 2;
185 threshold_index = THRESHOLD_INDEX_3;
186 break;
187 default:
188 pr_err("Tegra Unknown pkg %d\n", package_id);
189 break;
190 }
191 break;
192 case 0x8F:
193 sku_info->cpu_speedo_id = 8;
194 sku_info->soc_speedo_id = 1;
195 threshold_index = THRESHOLD_INDEX_11;
196 break;
197 case 0x08:
198 sku_info->cpu_speedo_id = 1;
199 sku_info->soc_speedo_id = 1;
200 threshold_index = THRESHOLD_INDEX_4;
201 break;
202 case 0x02:
203 sku_info->cpu_speedo_id = 2;
204 sku_info->soc_speedo_id = 2;
205 threshold_index = THRESHOLD_INDEX_5;
206 break;
207 case 0x04:
208 sku_info->cpu_speedo_id = 3;
209 sku_info->soc_speedo_id = 2;
210 threshold_index = THRESHOLD_INDEX_6;
211 break;
212 case 0:
213 switch (package_id) {
214 case 1:
215 sku_info->cpu_speedo_id = 2;
216 sku_info->soc_speedo_id = 2;
217 threshold_index = THRESHOLD_INDEX_2;
218 break;
219 case 2:
220 sku_info->cpu_speedo_id = 3;
221 sku_info->soc_speedo_id = 2;
222 threshold_index = THRESHOLD_INDEX_3;
223 break;
224 default:
225 pr_err("Tegra Unknown pkg %d\n", package_id);
226 break;
227 }
228 break;
229 default:
230 pr_warn("Tegra Unknown SKU %d\n", sku_info->sku_id);
231 sku_info->cpu_speedo_id = 0;
232 sku_info->soc_speedo_id = 0;
233 threshold_index = THRESHOLD_INDEX_0;
234 break;
235 }
236 break;
237 default:
238 pr_warn("Tegra Unknown chip rev %d\n", sku_info->revision);
239 sku_info->cpu_speedo_id = 0;
240 sku_info->soc_speedo_id = 0;
241 threshold_index = THRESHOLD_INDEX_0;
242 break;
243 }
244}
245
246void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info)
247{
248 u32 cpu_speedo_val;
249 u32 core_speedo_val;
250 int i;
251
252 BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) !=
253 THRESHOLD_INDEX_COUNT);
254 BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) !=
255 THRESHOLD_INDEX_COUNT);
256
257
258 rev_sku_to_speedo_ids(sku_info);
259 fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val);
260 pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val);
261 pr_debug("Tegra Core speedo value %u\n", core_speedo_val);
262
263 for (i = 0; i < CPU_PROCESS_CORNERS; i++) {
264 if (cpu_speedo_val < cpu_process_speedos[threshold_index][i])
265 break;
266 }
267 sku_info->cpu_process_id = i - 1;
268
269 if (sku_info->cpu_process_id == -1) {
270 pr_warn("Tegra CPU speedo value %3d out of range",
271 cpu_speedo_val);
272 sku_info->cpu_process_id = 0;
273 sku_info->cpu_speedo_id = 1;
274 }
275
276 for (i = 0; i < CORE_PROCESS_CORNERS; i++) {
277 if (core_speedo_val < core_process_speedos[threshold_index][i])
278 break;
279 }
280 sku_info->core_process_id = i - 1;
281
282 if (sku_info->core_process_id == -1) {
283 pr_warn("Tegra CORE speedo value %3d out of range",
284 core_speedo_val);
285 sku_info->core_process_id = 0;
286 sku_info->soc_speedo_id = 1;
287 }
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}