aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/tegra2_speedo.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_speedo.c')
-rw-r--r--arch/arm/mach-tegra/tegra2_speedo.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/tegra2_speedo.c b/arch/arm/mach-tegra/tegra2_speedo.c
new file mode 100644
index 00000000000..1e5fa26a5c4
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_speedo.c
@@ -0,0 +1,140 @@
1/*
2 * arch/arm/mach-tegra/tegra2_speedo.c
3 *
4 * Copyright (c) 2010, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/io.h>
23#include <linux/err.h>
24
25#include <mach/iomap.h>
26
27#include "fuse.h"
28
29#define CPU_SPEEDO_LSBIT 20
30#define CPU_SPEEDO_MSBIT 29
31#define CPU_SPEEDO_REDUND_LSBIT 30
32#define CPU_SPEEDO_REDUND_MSBIT 39
33#define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT)
34
35#define CORE_SPEEDO_LSBIT 40
36#define CORE_SPEEDO_MSBIT 47
37#define CORE_SPEEDO_REDUND_LSBIT 48
38#define CORE_SPEEDO_REDUND_MSBIT 55
39#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT)
40
41#define SPEEDO_MULT 4
42
43#define CHIP_ID 0x804
44#define CHIP_MINOR_SHIFT 16
45#define CHIP_MINOR_MASK (0xF << CHIP_MINOR_SHIFT)
46
47#define PROCESS_CORNERS_NUM 4
48
49#define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2)
50#define SPEEDO_ID_SELECT_1(sku) \
51 (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \
52 ((sku) != 27) && ((sku) != 28))
53
54/* Maximum speedo levels for each CPU process corner */
55static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = {
56/* proc_id 0 1 2 3 */
57 {315, 366, 420, UINT_MAX}, /* speedo_id 0 */
58 {303, 368, 419, UINT_MAX}, /* speedo_id 1 */
59 {316, 331, 383, UINT_MAX}, /* speedo_id 2 */
60};
61
62/* Maximum speedo levels for each core process corner */
63static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = {
64/* proc_id 0 1 2 3 */
65 {165, 195, 224, UINT_MAX}, /* speedo_id 0 */
66 {165, 195, 224, UINT_MAX}, /* speedo_id 1 */
67 {165, 195, 224, UINT_MAX}, /* speedo_id 2 */
68};
69
70static int cpu_process_id;
71static int core_process_id;
72static int soc_speedo_id;
73
74void tegra_init_speedo_data(void)
75{
76 u32 reg, val;
77 int i, bit, rev;
78 int sku = tegra_sku_id();
79 void __iomem *apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
80
81 reg = readl(apb_misc + CHIP_ID);
82 rev = (reg & CHIP_MINOR_MASK) >> CHIP_MINOR_SHIFT;
83 if (SPEEDO_ID_SELECT_0(rev))
84 soc_speedo_id = 0;
85 else if (SPEEDO_ID_SELECT_1(sku))
86 soc_speedo_id = 1;
87 else
88 soc_speedo_id = 2;
89 BUG_ON(soc_speedo_id >= ARRAY_SIZE(cpu_process_speedos));
90 BUG_ON(soc_speedo_id >= ARRAY_SIZE(core_process_speedos));
91
92 val = 0;
93 for (bit = CPU_SPEEDO_MSBIT; bit >= CPU_SPEEDO_LSBIT; bit--) {
94 reg = tegra_spare_fuse(bit) |
95 tegra_spare_fuse(bit + CPU_SPEEDO_REDUND_OFFS);
96 val = (val << 1) | (reg & 0x1);
97 }
98 val = val * SPEEDO_MULT;
99 pr_debug("%s CPU speedo level %u\n", __func__, val);
100
101 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
102 if (val <= cpu_process_speedos[soc_speedo_id][i])
103 break;
104 }
105 cpu_process_id = i;
106
107 val = 0;
108 for (bit = CORE_SPEEDO_MSBIT; bit >= CORE_SPEEDO_LSBIT; bit--) {
109 reg = tegra_spare_fuse(bit) |
110 tegra_spare_fuse(bit + CORE_SPEEDO_REDUND_OFFS);
111 val = (val << 1) | (reg & 0x1);
112 }
113 val = val * SPEEDO_MULT;
114 pr_debug("%s Core speedo level %u\n", __func__, val);
115
116 for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) {
117 if (val <= core_process_speedos[soc_speedo_id][i])
118 break;
119 }
120 core_process_id = i;
121
122 pr_info("Tegra SKU: %d Rev: A%.2d CPU Process: %d Core Process: %d"
123 " Speedo ID: %d\n", sku, rev, cpu_process_id, core_process_id,
124 soc_speedo_id);
125}
126
127int tegra_cpu_process_id(void)
128{
129 return cpu_process_id;
130}
131
132int tegra_core_process_id(void)
133{
134 return core_process_id;
135}
136
137int tegra_soc_speedo_id(void)
138{
139 return soc_speedo_id;
140}