ARM: tegra14: edp: Enable core EDP capping.
[linux-3.10.git] / arch / arm / mach-tegra / tegra14_edp.c
1 /*
2  * arch/arm/mach-tegra/tegra14_edp.c
3  *
4  * Copyright (C) 2013 NVIDIA Corporation.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/string.h>
20 #include <linux/module.h>
21 #include <linux/clk.h>
22 #include <linux/kobject.h>
23 #include <linux/err.h>
24
25 #include <mach/edp.h>
26
27 #include "clock.h"
28 #include "fuse.h"
29
30 #define CORE_MODULES_STATES 1
31 #define TEMPERATURE_RANGES 5
32 #define CAP_CLKS_NUM 2
33 #define TOTAL_CAPS (CORE_EDP_PROFILES_NUM * CORE_MODULES_STATES *\
34                         TEMPERATURE_RANGES * CAP_CLKS_NUM)
35
36 struct core_edp_entry {
37         int sku;
38         unsigned int cap_mA;
39         int mult;
40         unsigned long cap_cpu[CORE_EDP_PROFILES_NUM][
41                 CORE_MODULES_STATES][TEMPERATURE_RANGES][CAP_CLKS_NUM];
42 };
43
44 static int temperatures[] = { 50, 70, 80, 90, 100 };
45
46 #ifdef CONFIG_TEGRA_DUAL_CBUS
47 static char *cap_clks_names[] = { "edp.emc", "edp.c2bus" };
48 #else
49 static char *cap_clks_names[] = { "edp.emc", "edp.cbus" };
50 #endif
51 static struct clk *cap_clks[CAP_CLKS_NUM];
52
53 /* FIXME: Populate with correct values as per final EDP tables.
54  * Currently contains *safe* values
55  */
56 static struct core_edp_entry core_edp_table[] = {
57         {
58                 .sku            = 0x7,          /* SL440 */
59                 .cap_mA         = 3000,         /* 3A cap */
60                 .mult           = 1000000,      /* MHZ */
61                 .cap_cpu        = {
62                         /* favor emc */
63                         {       /* core modules power state 0 (all ON) */
64                                 {{ 921, 655 },
65                                  { 921, 596 },
66                                  { 921, 596 },
67                                  { 921, 596 },
68                                  { 921, 557 },
69                                 },
70                         },
71                         /* balanced profile */
72                         {       /* core modules power state 0 (all ON) */
73                                 {{ 921, 655 },
74                                  { 921, 596 },
75                                  { 921, 596 },
76                                  { 921, 596 },
77                                  { 788, 596 },
78                                 },
79                         },
80                         /* favor gpu */
81                         {       /* core modules power state 0 (all ON) */
82                                 {{ 921, 655 },
83                                  { 788, 655 },
84                                  { 921, 596 },
85                                  { 921, 596 },
86                                  { 788, 596 },
87                                 }
88                         },
89                 },
90         },
91         {
92                 .sku            = 0x3,          /* SL460 */
93                 .cap_mA         = 3000,         /* 3A cap */
94                 .mult           = 1000000,      /* MHZ */
95                 .cap_cpu        = {
96                         /* favor emc */
97                         {       /* core modules power state 0 (all ON) */
98                                 {{ 921, 672 },
99                                  { 921, 596 },
100                                  { 921, 596 },
101                                  { 921, 596 },
102                                  { 921, 557 },
103                                 },
104                         },
105                         /* balanced profile */
106                         {       /* core modules power state 0 (all ON) */
107                                 {{ 921, 672 },
108                                  { 788, 672 },
109                                  { 921, 596 },
110                                  { 921, 596 },
111                                  { 788, 596 },
112                                 },
113                         },
114                         /* favor gpu */
115                         {       /* core modules power state 0 (all ON) */
116                                 {{ 921, 672 },
117                                  { 788, 672 },
118                                  { 921, 596 },
119                                  { 921, 596 },
120                                  { 788, 596 },
121                                 }
122                         },
123                 },
124         },
125         {
126                 .sku            = 0x3,          /* SL460 */
127                 .cap_mA         = 3500,         /* 3.5A cap */
128                 .mult           = 1000000,      /* MHZ */
129                 .cap_cpu        = {
130                         /* favor emc */
131                         {       /* core modules power state 0 (all ON) */
132                                 {{ 921, 711 },
133                                  { 921, 711 },
134                                  { 921, 711 },
135                                  { 921, 672 },
136                                  { 921, 672 },
137                                 },
138                         },
139                         /* balanced profile */
140                         {       /* core modules power state 0 (all ON) */
141                                 {{ 788, 749 },
142                                  { 921, 711 },
143                                  { 921, 711 },
144                                  { 921, 672 },
145                                  { 921, 672 },
146                                 },
147                         },
148                         /* favor gpu */
149                         {       /* core modules power state 0 (all ON) */
150                                 {{ 788, 749 },
151                                  { 921, 711 },
152                                  { 921, 711 },
153                                  { 921, 672 },
154                                  { 921, 672 },
155                                 }
156                         },
157                 },
158         },
159         {
160                 .sku            = 0x3,          /* SL460 */
161                 .cap_mA         = 4000,         /* 4A cap */
162                 .mult           = 1000000,      /* MHZ */
163                 .cap_cpu        = {
164                         /* favor emc */
165                         {       /* core modules power state 0 (all ON) */
166                                 {{ 921, 749 },
167                                  { 921, 749 },
168                                  { 921, 711 },
169                                  { 921, 672 },
170                                  { 921, 672 },
171                                 },
172                         },
173                         /* balanced profile */
174                         {       /* core modules power state 0 (all ON) */
175                                 {{ 921, 749 },
176                                  { 921, 749 },
177                                  { 921, 711 },
178                                  { 921, 672 },
179                                  { 921, 672 },
180                                 },
181                         },
182                         /* favor gpu */
183                         {       /* core modules power state 0 (all ON) */
184                                 {{ 921, 749 },
185                                  { 921, 749 },
186                                  { 921, 711 },
187                                  { 921, 672 },
188                                  { 921, 672 },
189                                 }
190                         },
191                 },
192         }
193 };
194
195 static struct core_edp_entry *find_edp_entry(int sku, unsigned int regulator_mA)
196 {
197         int i;
198
199         for (i = 0; i < ARRAY_SIZE(core_edp_table); i++) {
200                 struct core_edp_entry *entry = &core_edp_table[i];
201                 if ((entry->sku == sku) && (entry->cap_mA == regulator_mA))
202                         return entry;
203         }
204         return NULL;
205 }
206
207 static unsigned long clip_cap_rate(struct clk *cap_clk, unsigned long rate)
208 {
209         unsigned long floor, ceiling;
210         struct clk *p = clk_get_parent(cap_clk);
211
212         if (!p || !p->ops || !p->ops->shared_bus_update) {
213                 WARN(1, "%s: edp cap clk %s is not a shared bus user\n",
214                         __func__, cap_clk->name);
215                 return rate;
216         }
217
218         /*
219          * Clip cap rate to shared bus possible rates (going up via shared
220          * bus * ladder since bus clocks always rounds up with resolution of
221          * at least 2kHz)
222          */
223         ceiling = clk_round_rate(p, clk_get_min_rate(p));
224         do {
225                 floor = ceiling;
226                 ceiling = clk_round_rate(p, floor + 2000);
227                 if (IS_ERR_VALUE(ceiling)) {
228                         pr_err("%s: failed to clip %lu to %s possible rates\n",
229                                __func__, rate, p->name);
230                         return rate;
231                 }
232         } while ((floor < ceiling) && (ceiling <= rate));
233
234         if (floor > rate)
235                 WARN(1, "%s: %s cap rate %lu is below %s floor %lu\n",
236                         __func__, cap_clk->name, rate, p->name, floor);
237         return floor;
238 }
239
240 int __init tegra14x_select_core_edp_table(unsigned int regulator_mA,
241                                           struct tegra_core_edp_limits *limits)
242 {
243         int i;
244         int sku = tegra_sku_id;
245         unsigned long *cap_rates;
246         struct core_edp_entry *edp_entry;
247
248         BUG_ON(ARRAY_SIZE(temperatures) != TEMPERATURE_RANGES);
249         BUG_ON(ARRAY_SIZE(cap_clks_names) != CAP_CLKS_NUM);
250
251         for (i = 0; i < CAP_CLKS_NUM; i++) {
252                 struct clk *c = tegra_get_clock_by_name(cap_clks_names[i]);
253                 if (!c) {
254                         pr_err("%s: failed to find edp cap clock %s\n",
255                                __func__, cap_clks_names[i]);
256                         return -ENODEV;
257                 }
258                 cap_clks[i] = c;
259         }
260
261         if (sku == 0x0)
262                 sku = 0x7;
263
264         if ((sku == 0x7) && (regulator_mA >= 3500)) {
265                 pr_info("%s: no core edp capping for sku %d, %d mA\n",
266                        __func__, sku, regulator_mA);
267                 return -ENODATA;
268         }
269
270         edp_entry = find_edp_entry(sku, regulator_mA);
271         if (!edp_entry) {
272                 pr_info("%s: no core edp table for sku %d, %d mA\n",
273                        __func__, sku, regulator_mA);
274                 return -ENODATA;
275         }
276
277         limits->sku = sku;
278         limits->cap_clocks = cap_clks;
279         limits->cap_clocks_num = CAP_CLKS_NUM;
280         limits->temperatures = temperatures;
281         limits->temperature_ranges = TEMPERATURE_RANGES;
282         limits->core_modules_states = CORE_MODULES_STATES;
283
284         cap_rates = &edp_entry->cap_cpu[0][0][0][0];
285         limits->cap_rates_scpu_on = cap_rates;
286         limits->cap_rates_scpu_off = cap_rates;
287         for (i = 0; i < TOTAL_CAPS; i++, cap_rates++) {
288                 unsigned long rate = *cap_rates * edp_entry->mult;
289                 *cap_rates = clip_cap_rate(cap_clks[i % CAP_CLKS_NUM], rate);
290         }
291
292         return 0;
293 }