diff options
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_speedo.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_speedo.c | 140 |
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 */ | ||
55 | static 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 */ | ||
63 | static 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 | |||
70 | static int cpu_process_id; | ||
71 | static int core_process_id; | ||
72 | static int soc_speedo_id; | ||
73 | |||
74 | void 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 | |||
127 | int tegra_cpu_process_id(void) | ||
128 | { | ||
129 | return cpu_process_id; | ||
130 | } | ||
131 | |||
132 | int tegra_core_process_id(void) | ||
133 | { | ||
134 | return core_process_id; | ||
135 | } | ||
136 | |||
137 | int tegra_soc_speedo_id(void) | ||
138 | { | ||
139 | return soc_speedo_id; | ||
140 | } | ||