diff options
author | Danny Huang <dahuang@nvidia.com> | 2012-11-15 02:42:33 -0500 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2012-11-15 16:34:20 -0500 |
commit | 25cd5a391478b1e29ef7de172b3bd612159a07cc (patch) | |
tree | 3dd124908a55cba2427cf0b7a6c1637c14ce8d81 | |
parent | 1f851a262baf7cbd4096d4d279c73cb697021773 (diff) |
ARM: tegra: Add speedo-based process identification
Detect CPU and core process ID by checking speedo corner tables.
This can provide a more accurate process ID.
Signed-off-by: Danny Huang <dahuang@nvidia.com>
[swarren s/Tegra2/Tegra20/ in log print]
Signed-off-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/fuse.c | 31 | ||||
-rw-r--r-- | arch/arm/mach-tegra/fuse.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra20_speedo.c | 109 |
4 files changed, 140 insertions, 8 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 9aa653b3eb32..07ed4bdaba3a 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile | |||
@@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o | |||
12 | obj-$(CONFIG_CPU_IDLE) += sleep.o | 12 | obj-$(CONFIG_CPU_IDLE) += sleep.o |
13 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o | 13 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks.o |
14 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o | 14 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_clocks_data.o |
15 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20_speedo.o | ||
15 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o | 16 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o |
16 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t20.o | 17 | obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += sleep-t20.o |
17 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o | 18 | obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o |
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index bd19c2f53a97..9fd02c50ae29 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c | |||
@@ -35,9 +35,11 @@ int tegra_sku_id; | |||
35 | int tegra_cpu_process_id; | 35 | int tegra_cpu_process_id; |
36 | int tegra_core_process_id; | 36 | int tegra_core_process_id; |
37 | int tegra_chip_id; | 37 | int tegra_chip_id; |
38 | int tegra_soc_speedo_id; | ||
38 | enum tegra_revision tegra_revision; | 39 | enum tegra_revision tegra_revision; |
39 | 40 | ||
40 | static int tegra_fuse_spare_bit; | 41 | static int tegra_fuse_spare_bit; |
42 | static void (*tegra_init_speedo_data)(void); | ||
41 | 43 | ||
42 | /* The BCT to use at boot is specified by board straps that can be read | 44 | /* The BCT to use at boot is specified by board straps that can be read |
43 | * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. | 45 | * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs. |
@@ -91,6 +93,16 @@ static enum tegra_revision tegra_get_revision(u32 id) | |||
91 | } | 93 | } |
92 | } | 94 | } |
93 | 95 | ||
96 | static void tegra_get_process_id(void) | ||
97 | { | ||
98 | u32 reg; | ||
99 | |||
100 | reg = tegra_fuse_readl(tegra_fuse_spare_bit); | ||
101 | tegra_cpu_process_id = (reg >> 6) & 3; | ||
102 | reg = tegra_fuse_readl(tegra_fuse_spare_bit); | ||
103 | tegra_core_process_id = (reg >> 12) & 3; | ||
104 | } | ||
105 | |||
94 | void tegra_init_fuse(void) | 106 | void tegra_init_fuse(void) |
95 | { | 107 | { |
96 | u32 id; | 108 | u32 id; |
@@ -102,21 +114,24 @@ void tegra_init_fuse(void) | |||
102 | reg = tegra_fuse_readl(FUSE_SKU_INFO); | 114 | reg = tegra_fuse_readl(FUSE_SKU_INFO); |
103 | tegra_sku_id = reg & 0xFF; | 115 | tegra_sku_id = reg & 0xFF; |
104 | 116 | ||
105 | tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; | ||
106 | |||
107 | reg = tegra_fuse_readl(tegra_fuse_spare_bit); | ||
108 | tegra_cpu_process_id = (reg >> 6) & 3; | ||
109 | |||
110 | reg = tegra_fuse_readl(tegra_fuse_spare_bit); | ||
111 | tegra_core_process_id = (reg >> 12) & 3; | ||
112 | |||
113 | reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); | 117 | reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT); |
114 | tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; | 118 | tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT; |
115 | 119 | ||
116 | id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); | 120 | id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804); |
117 | tegra_chip_id = (id >> 8) & 0xff; | 121 | tegra_chip_id = (id >> 8) & 0xff; |
118 | 122 | ||
123 | tegra_fuse_spare_bit = TEGRA20_FUSE_SPARE_BIT; | ||
124 | |||
125 | switch (tegra_chip_id) { | ||
126 | case TEGRA20: | ||
127 | tegra_init_speedo_data = &tegra20_init_speedo_data; | ||
128 | break; | ||
129 | default: | ||
130 | tegra_init_speedo_data = &tegra_get_process_id; | ||
131 | } | ||
132 | |||
119 | tegra_revision = tegra_get_revision(id); | 133 | tegra_revision = tegra_get_revision(id); |
134 | tegra_init_speedo_data(); | ||
120 | 135 | ||
121 | pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", | 136 | pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", |
122 | tegra_revision_name[tegra_revision], | 137 | tegra_revision_name[tegra_revision], |
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h index aef12231e559..7347c8818937 100644 --- a/arch/arm/mach-tegra/fuse.h +++ b/arch/arm/mach-tegra/fuse.h | |||
@@ -42,6 +42,7 @@ extern int tegra_sku_id; | |||
42 | extern int tegra_cpu_process_id; | 42 | extern int tegra_cpu_process_id; |
43 | extern int tegra_core_process_id; | 43 | extern int tegra_core_process_id; |
44 | extern int tegra_chip_id; | 44 | extern int tegra_chip_id; |
45 | extern int tegra_soc_speedo_id; | ||
45 | extern enum tegra_revision tegra_revision; | 46 | extern enum tegra_revision tegra_revision; |
46 | 47 | ||
47 | extern int tegra_bct_strapping; | 48 | extern int tegra_bct_strapping; |
@@ -51,4 +52,10 @@ void tegra_init_fuse(void); | |||
51 | bool tegra_spare_fuse(int bit); | 52 | bool tegra_spare_fuse(int bit); |
52 | u32 tegra_fuse_readl(unsigned long offset); | 53 | u32 tegra_fuse_readl(unsigned long offset); |
53 | 54 | ||
55 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
56 | void tegra20_init_speedo_data(void); | ||
57 | #else | ||
58 | static inline void tegra20_init_speedo_data(void) {} | ||
59 | #endif | ||
60 | |||
54 | #endif | 61 | #endif |
diff --git a/arch/arm/mach-tegra/tegra20_speedo.c b/arch/arm/mach-tegra/tegra20_speedo.c new file mode 100644 index 000000000000..fa6eb570623f --- /dev/null +++ b/arch/arm/mach-tegra/tegra20_speedo.c | |||
@@ -0,0 +1,109 @@ | |||
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/kernel.h> | ||
18 | #include <linux/bug.h> | ||
19 | |||
20 | #include "fuse.h" | ||
21 | |||
22 | #define CPU_SPEEDO_LSBIT 20 | ||
23 | #define CPU_SPEEDO_MSBIT 29 | ||
24 | #define CPU_SPEEDO_REDUND_LSBIT 30 | ||
25 | #define CPU_SPEEDO_REDUND_MSBIT 39 | ||
26 | #define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) | ||
27 | |||
28 | #define CORE_SPEEDO_LSBIT 40 | ||
29 | #define CORE_SPEEDO_MSBIT 47 | ||
30 | #define CORE_SPEEDO_REDUND_LSBIT 48 | ||
31 | #define CORE_SPEEDO_REDUND_MSBIT 55 | ||
32 | #define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) | ||
33 | |||
34 | #define SPEEDO_MULT 4 | ||
35 | |||
36 | #define PROCESS_CORNERS_NUM 4 | ||
37 | |||
38 | #define SPEEDO_ID_SELECT_0(rev) ((rev) <= 2) | ||
39 | #define SPEEDO_ID_SELECT_1(sku) \ | ||
40 | (((sku) != 20) && ((sku) != 23) && ((sku) != 24) && \ | ||
41 | ((sku) != 27) && ((sku) != 28)) | ||
42 | |||
43 | enum { | ||
44 | SPEEDO_ID_0, | ||
45 | SPEEDO_ID_1, | ||
46 | SPEEDO_ID_2, | ||
47 | SPEEDO_ID_COUNT, | ||
48 | }; | ||
49 | |||
50 | static const u32 cpu_process_speedos[][PROCESS_CORNERS_NUM] = { | ||
51 | {315, 366, 420, UINT_MAX}, | ||
52 | {303, 368, 419, UINT_MAX}, | ||
53 | {316, 331, 383, UINT_MAX}, | ||
54 | }; | ||
55 | |||
56 | static const u32 core_process_speedos[][PROCESS_CORNERS_NUM] = { | ||
57 | {165, 195, 224, UINT_MAX}, | ||
58 | {165, 195, 224, UINT_MAX}, | ||
59 | {165, 195, 224, UINT_MAX}, | ||
60 | }; | ||
61 | |||
62 | void tegra20_init_speedo_data(void) | ||
63 | { | ||
64 | u32 reg; | ||
65 | u32 val; | ||
66 | int i; | ||
67 | |||
68 | BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); | ||
69 | BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); | ||
70 | |||
71 | if (SPEEDO_ID_SELECT_0(tegra_revision)) | ||
72 | tegra_soc_speedo_id = SPEEDO_ID_0; | ||
73 | else if (SPEEDO_ID_SELECT_1(tegra_sku_id)) | ||
74 | tegra_soc_speedo_id = SPEEDO_ID_1; | ||
75 | else | ||
76 | tegra_soc_speedo_id = SPEEDO_ID_2; | ||
77 | |||
78 | val = 0; | ||
79 | for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { | ||
80 | reg = tegra_spare_fuse(i) | | ||
81 | tegra_spare_fuse(i + CPU_SPEEDO_REDUND_OFFS); | ||
82 | val = (val << 1) | (reg & 0x1); | ||
83 | } | ||
84 | val = val * SPEEDO_MULT; | ||
85 | pr_debug("%s CPU speedo value %u\n", __func__, val); | ||
86 | |||
87 | for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { | ||
88 | if (val <= cpu_process_speedos[tegra_soc_speedo_id][i]) | ||
89 | break; | ||
90 | } | ||
91 | tegra_cpu_process_id = i; | ||
92 | |||
93 | val = 0; | ||
94 | for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { | ||
95 | reg = tegra_spare_fuse(i) | | ||
96 | tegra_spare_fuse(i + CORE_SPEEDO_REDUND_OFFS); | ||
97 | val = (val << 1) | (reg & 0x1); | ||
98 | } | ||
99 | val = val * SPEEDO_MULT; | ||
100 | pr_debug("%s Core speedo value %u\n", __func__, val); | ||
101 | |||
102 | for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { | ||
103 | if (val <= core_process_speedos[tegra_soc_speedo_id][i]) | ||
104 | break; | ||
105 | } | ||
106 | tegra_core_process_id = i; | ||
107 | |||
108 | pr_info("Tegra20 Soc Speedo ID %d", tegra_soc_speedo_id); | ||
109 | } | ||