arm: tegra: refactor edp parameters init
[linux-3.10.git] / arch / arm / mach-tegra / tegra11_edp.c
1 /*
2  * arch/arm/mach-tegra/tegra11_edp.c
3  *
4  * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/init.h>
21 #include <linux/string.h>
22 #include <linux/module.h>
23 #include <linux/clk.h>
24 #include <linux/kobject.h>
25 #include <linux/err.h>
26
27 #include <mach/edp.h>
28
29 #include "clock.h"
30 #include "fuse.h"
31
32 #define CORE_MODULES_STATES 1
33 #define TEMPERATURE_RANGES 4
34 #define CAP_CLKS_NUM 2
35 #define TOTAL_CAPS (CORE_EDP_PROFILES_NUM * CORE_MODULES_STATES *\
36                         TEMPERATURE_RANGES * CAP_CLKS_NUM)
37
38 struct core_edp_entry {
39         int sku;
40         unsigned int cap_mA;
41         int mult;
42         unsigned long cap_scpu_on[CORE_EDP_PROFILES_NUM][
43                 CORE_MODULES_STATES][TEMPERATURE_RANGES][CAP_CLKS_NUM];
44         unsigned long cap_scpu_off[CORE_EDP_PROFILES_NUM][
45                 CORE_MODULES_STATES][TEMPERATURE_RANGES][CAP_CLKS_NUM];
46 };
47
48 static int temperatures[] = { 50, 70, 90, 105 };
49
50 #ifdef CONFIG_TEGRA_DUAL_CBUS
51 static char *cap_clks_names[] = { "edp.emc", "edp.c2bus" };
52 #else
53 static char *cap_clks_names[] = { "edp.emc", "edp.cbus" };
54 #endif
55 static struct clk *cap_clks[CAP_CLKS_NUM];
56
57 static struct core_edp_entry core_edp_table[] = {
58         {
59                 .sku            = 0x3,          /* SKU = 4 - T40X */
60                 .cap_mA         = 6000,         /* 6A cap */
61                 .mult           = 1000000,      /* MHZ */
62                 .cap_scpu_on    = {
63                         /* favor emc */
64                         {       /* core modules power state 0 (all ON) */
65                                 {{ 924, 636 },
66                                  { 924, 612 },
67                                  { 924, 564 },
68                                  { 924, 480 },
69                                 },
70                         },
71                         /* balanced profile */
72                         {       /* core modules power state 0 (all ON) */
73                                 {{ 792, 636 },
74                                  { 792, 636 },
75                                  { 792, 636 },
76                                  { 792, 552 },
77                                 },
78                         },
79                         /* favor gpu */
80                         {       /* core modules power state 0 (all ON) */
81                                 {{ 624, 672 },
82                                  { 624, 672 },
83                                  { 528, 672 },
84                                  { 408, 672 },
85                                 }
86                         },
87                 },
88                 .cap_scpu_off   = {
89                         /* favor emc */
90                         {       /* core modules power state 0 (all ON) */
91                                 {{1066, 700 },
92                                  { 924, 648 },
93                                  { 924, 636 },
94                                  { 924, 588 },
95                                 },
96                         },
97                         /* balanced profile */
98                         {       /* core modules power state 0 (all ON) */
99                                 {{1066, 700 },
100                                  { 792, 672 },
101                                  { 792, 672 },
102                                  { 792, 624 },
103                                 },
104                         },
105                         /* favor gpu */
106                         {       /* core modules power state 0 (all ON) */
107                                 {{1066, 700 },
108                                  { 792, 672 },
109                                  { 792, 672 },
110                                  { 624, 672 },
111                                 }
112                         },
113                 },
114         },
115 };
116
117 #ifdef CONFIG_TEGRA_EDP_LIMITS
118 #define LEAKAGE_CONSTS_IJK_COMMON                                       \
119         {                                                               \
120                 /* i = 0 */                                             \
121                 { {  -42746668,   -5458429,   164998,  -1711, },        \
122                   {  178262421,   13375684,  -411791,   4590, },        \
123                   { -228866784,  -10482993,   331248,  -4062, },        \
124                   {   94301550,    2618719,   -85983,   1193, },        \
125                 },                                                      \
126                 /* i = 1 */                                             \
127                 { { -256611791,   49677413, -1655785,  14917, },        \
128                   {  584675433, -132620939,  4541560, -41812, },        \
129                   { -398106336,  115987156, -4102328,  38737, },        \
130                   {   68897184,  -33030745,  1217839, -11801, },        \
131                 },                                                      \
132                 /* i = 2 */                                             \
133                 { {  186324676,  -36019083,  1177969, -10669, },        \
134                   { -439237936,   98429131, -3276444,  30301, },        \
135                   {  315060898,  -88635036,  3004777, -28474, },        \
136                   {  -60854399,   26267188,  -907121,   8844, },        \
137                 },                                                      \
138                 /* i = 3 */                                             \
139                 { {  -35432997,    6154621,  -202200,   1830, },        \
140                   {   87402153,  -16908683,   565152,  -5220, },        \
141                   {  -67775314,   15326770,  -521221,   4927, },        \
142                   {   15618709,   -4576116,   158401,  -1538, },        \
143                 },                                                      \
144         }
145
146 #define LEAKAGE_PARAMS_COMMON_PART                                      \
147         .dyn_scaled         = 1000000,                                  \
148         .dyn_consts_n       = { 1091747, 2035205, 2978661, 3922119 },   \
149         .consts_scaled      = 1000000,                                  \
150         .leakage_consts_n   = {  538991,  752463,  959441, 1150000 },   \
151         .ijk_scaled         = 100000,                                   \
152         .volt_temp_cap      = { 70, 1300 },                             \
153         .leakage_consts_ijk = LEAKAGE_CONSTS_IJK_COMMON
154
155 static struct tegra_edp_cpu_leakage_params t11x_leakage_params[] = {
156         {
157                 .cpu_speedo_id      = 0, /* A01 CPU */
158                 LEAKAGE_PARAMS_COMMON_PART,
159         },
160         {
161                 .cpu_speedo_id      = 1, /* A01P+ CPU */
162                 .safety_cap         = { 1810500, 1810500, 1606500, 1606500 },
163                 LEAKAGE_PARAMS_COMMON_PART,
164         },
165         {
166                 .cpu_speedo_id      = 2, /* A01P+ fast CPU */
167                 .safety_cap         = { 1912500, 1912500, 1912500, 1912500 },
168                 LEAKAGE_PARAMS_COMMON_PART,
169         },
170 };
171
172 struct tegra_edp_cpu_leakage_params *tegra11x_get_leakage_params(int index,
173                                                         unsigned int *sz)
174 {
175         BUG_ON(index >= ARRAY_SIZE(t11x_leakage_params));
176         if (sz)
177                 *sz = ARRAY_SIZE(t11x_leakage_params);
178         return &t11x_leakage_params[index];
179 }
180 #endif
181
182 static struct core_edp_entry *find_edp_entry(int sku, unsigned int regulator_mA)
183 {
184         int i;
185
186         for (i = 0; i < ARRAY_SIZE(core_edp_table); i++) {
187                 struct core_edp_entry *entry = &core_edp_table[i];
188                 if ((entry->sku == sku) && (entry->cap_mA == regulator_mA))
189                         return entry;
190         }
191         return NULL;
192 }
193
194 static unsigned long clip_cap_rate(struct clk *cap_clk, unsigned long rate)
195 {
196         unsigned long floor, ceiling;
197         struct clk *p = clk_get_parent(cap_clk);
198
199         if (!p || !p->ops || !p->ops->shared_bus_update) {
200                 WARN(1, "%s: edp cap clk %s is not a shared bus user\n",
201                         __func__, cap_clk->name);
202                 return rate;
203         }
204
205         /*
206          * Clip cap rate to shared bus possible rates (going up via shared
207          * bus * ladder since bus clocks always rounds up with resolution of
208          * at least 2kHz)
209          */
210         ceiling = clk_round_rate(p, clk_get_min_rate(p));
211         do {
212                 floor = ceiling;
213                 ceiling = clk_round_rate(p, floor + 2000);
214                 if (IS_ERR_VALUE(ceiling)) {
215                         pr_err("%s: failed to clip %lu to %s possible rates\n",
216                                __func__, rate, p->name);
217                         return rate;
218                 }
219         } while ((floor < ceiling) && (ceiling <= rate));
220
221         if (floor > rate)
222                 WARN(1, "%s: %s cap rate %lu is below %s floor %lu\n",
223                         __func__, cap_clk->name, rate, p->name, floor);
224         return floor;
225 }
226
227 int __init tegra11x_select_core_edp_table(unsigned int regulator_mA,
228                                           struct tegra_core_edp_limits *limits)
229 {
230         int i;
231         int sku = tegra_sku_id;
232         unsigned long *cap_rates;
233         struct core_edp_entry *edp_entry;
234
235         BUG_ON(ARRAY_SIZE(temperatures) != TEMPERATURE_RANGES);
236         BUG_ON(ARRAY_SIZE(cap_clks_names) != CAP_CLKS_NUM);
237         for (i = 0; i < CAP_CLKS_NUM; i++) {
238                 struct clk *c = tegra_get_clock_by_name(cap_clks_names[i]);
239                 if (!c) {
240                         pr_err("%s: failed to find edp cap clock %s\n",
241                                __func__, cap_clks_names[i]);
242                         return -ENODEV;
243                 }
244                 cap_clks[i] = c;
245         }
246
247         edp_entry = find_edp_entry(sku, regulator_mA);
248         if (!edp_entry) {
249                 pr_info("%s: no core edp table for sku %d, %d mA\n",
250                        __func__, sku, regulator_mA);
251                 return -ENODATA;
252         }
253
254         limits->sku = sku;
255         limits->cap_clocks = cap_clks;
256         limits->cap_clocks_num = CAP_CLKS_NUM;
257         limits->temperatures = temperatures;
258         limits->temperature_ranges = TEMPERATURE_RANGES;
259         limits->core_modules_states = CORE_MODULES_STATES;
260
261         cap_rates = &edp_entry->cap_scpu_on[0][0][0][0];
262         limits->cap_rates_scpu_on = cap_rates;
263         for (i = 0; i < TOTAL_CAPS; i++, cap_rates++) {
264                 unsigned long rate = *cap_rates * edp_entry->mult;
265                 *cap_rates = clip_cap_rate(cap_clks[i % CAP_CLKS_NUM], rate);
266         }
267
268         cap_rates = &edp_entry->cap_scpu_off[0][0][0][0];
269         limits->cap_rates_scpu_off = cap_rates;
270         for (i = 0; i < TOTAL_CAPS; i++, cap_rates++) {
271                 unsigned long rate = *cap_rates * edp_entry->mult;
272                 *cap_rates = clip_cap_rate(cap_clks[i % CAP_CLKS_NUM], rate);
273         }
274
275         return 0;
276 }