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 SOC_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 
40 enum {
41 	THRESHOLD_INDEX_0,
42 	THRESHOLD_INDEX_1,
43 	THRESHOLD_INDEX_COUNT,
44 };
45 
46 static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = {
47 	{2190,	UINT_MAX},
48 	{0,	UINT_MAX},
49 };
50 
51 static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = {
52 	{1965,	UINT_MAX},
53 	{0,	UINT_MAX},
54 };
55 
56 static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = {
57 	{2101,	UINT_MAX},
58 	{0,	UINT_MAX},
59 };
60 
61 static 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 
113 void __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(soc_process_speedos) !=
123 			THRESHOLD_INDEX_COUNT);
124 
125 	cpu_speedo_0_value = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0);
126 
127 	/* GPU Speedo is stored in CPU_SPEEDO_2 */
128 	sku_info->gpu_speedo_value = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2);
129 
130 	soc_speedo_0_value = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0);
131 
132 	cpu_iddq_value = tegra_fuse_read_early(FUSE_CPU_IDDQ);
133 	soc_iddq_value = tegra_fuse_read_early(FUSE_SOC_IDDQ);
134 	gpu_iddq_value = tegra_fuse_read_early(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 = tegra_fuse_read_early(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 < SOC_PROCESS_CORNERS; i++)
161 		if (soc_speedo_0_value <
162 			soc_process_speedos[threshold][i])
163 			break;
164 	sku_info->soc_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 }
169