ARM: tegra11: power: Integrate core EDP 6A limit table
[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 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 4
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_scpu_on[CORE_EDP_PROFILES_NUM][
41                 CORE_MODULES_STATES][TEMPERATURE_RANGES][CAP_CLKS_NUM];
42         unsigned long cap_scpu_off[CORE_EDP_PROFILES_NUM][
43                 CORE_MODULES_STATES][TEMPERATURE_RANGES][CAP_CLKS_NUM];
44 };
45
46 static int temperatures[] = { 50, 70, 90, 105 };
47
48 #ifdef CONFIG_TEGRA_DUAL_CBUS
49 static char *cap_clks_names[] = { "edp.emc", "edp.c2bus" };
50 #else
51 static char *cap_clks_names[] = { "edp.emc", "edp.cbus" };
52 #endif
53 static struct clk *cap_clks[CAP_CLKS_NUM];
54
55 static struct core_edp_entry core_edp_table[] = {
56         {
57                 .sku            = 0x4,          /* SKU = 4 - T40T */
58                 .cap_mA         = 6000,         /* 6A cap */
59                 .mult           = 1000000,      /* MHZ */
60                 .cap_scpu_on    = {
61                         /* favor emc */
62                         {       /* core modules power state 0 (all ON) */
63                                 {{ 924, 672 },
64                                  { 924, 600 },
65                                  { 924, 564 },
66                                  { 924, 492 },
67                                 },
68                         },
69                         /* balanced profile */
70                         {       /* core modules power state 0 (all ON) */
71                                 {{ 924, 672 },
72                                  { 792, 600 },
73                                  { 792, 600 },
74                                  { 792, 564 },
75                                 },
76                         },
77                         /* favor gpu */
78                         {       /* core modules power state 0 (all ON) */
79                                 {{ 924, 672 },
80                                  { 624, 672 },
81                                  { 624, 672 },
82                                  { 624, 672 },
83                                 }
84                         },
85                 },
86                 .cap_scpu_off   = {
87                         /* favor emc */
88                         {       /* core modules power state 0 (all ON) */
89                                 {{ 924, 672 },
90                                  { 924, 600 },
91                                  { 924, 600 },
92                                  { 924, 564 },
93                                 },
94                         },
95                         /* balanced profile */
96                         {       /* core modules power state 0 (all ON) */
97                                 {{ 924, 672 },
98                                  { 792, 672 },
99                                  { 792, 672 },
100                                  { 792, 600 },
101                                 },
102                         },
103                         /* favor gpu */
104                         {       /* core modules power state 0 (all ON) */
105                                 {{ 924, 672 },
106                                  { 792, 672 },
107                                  { 792, 672 },
108                                  { 624, 672 },
109                                 }
110                         },
111                 },
112         },
113 };
114
115 static struct core_edp_entry *find_edp_entry(int sku, unsigned int regulator_mA)
116 {
117         int i;
118
119         for (i = 0; i < ARRAY_SIZE(core_edp_table); i++) {
120                 struct core_edp_entry *entry = &core_edp_table[i];
121                 if ((entry->sku == sku) && (entry->cap_mA == regulator_mA))
122                         return entry;
123         }
124         return NULL;
125 }
126
127 static unsigned long clip_cap_rate(struct clk *cap_clk, unsigned long rate)
128 {
129         unsigned long floor, ceiling;
130         struct clk *p = clk_get_parent(cap_clk);
131
132         if (!p || !p->ops || !p->ops->shared_bus_update) {
133                 WARN(1, "%s: edp cap clk %s is not a shared bus user\n",
134                         __func__, cap_clk->name);
135                 return rate;
136         }
137
138         /*
139          * Clip cap rate to shared bus possible rates (going up via shared
140          * bus * ladder since bus clocks always rounds up with resolution of
141          * at least 2kHz)
142          */
143         ceiling = clk_round_rate(p, clk_get_min_rate(p));
144         do {
145                 floor = ceiling;
146                 ceiling = clk_round_rate(p, floor + 2000);
147                 if (IS_ERR_VALUE(ceiling)) {
148                         pr_err("%s: failed to clip %lu to %s possible rates\n",
149                                __func__, rate, p->name);
150                         return rate;
151                 }
152         } while ((floor < ceiling) && (ceiling <= rate));
153
154         if (floor > rate)
155                 WARN(1, "%s: %s cap rate %lu is below %s floor %lu\n",
156                         __func__, cap_clk->name, rate, p->name, floor);
157         return floor;
158 }
159
160 int __init tegra11x_select_core_edp_table(unsigned int regulator_mA,
161                                           struct tegra_core_edp_limits *limits)
162 {
163         int i;
164         int sku = tegra_sku_id;
165         unsigned long *cap_rates;
166         struct core_edp_entry *edp_entry;
167
168         BUG_ON(ARRAY_SIZE(temperatures) != TEMPERATURE_RANGES);
169         BUG_ON(ARRAY_SIZE(cap_clks_names) != CAP_CLKS_NUM);
170         for (i = 0; i < CAP_CLKS_NUM; i++) {
171                 struct clk *c = tegra_get_clock_by_name(cap_clks_names[i]);
172                 if (!c) {
173                         pr_err("%s: failed to find edp cap clock %s\n",
174                                __func__, cap_clks_names[i]);
175                         return -ENODEV;
176                 }
177                 cap_clks[i] = c;
178         }
179
180         edp_entry = find_edp_entry(sku, regulator_mA);
181         if (!edp_entry) {
182                 pr_err("%s: failed to find edp entry for sku %d, %d mA\n",
183                        __func__, sku, regulator_mA);
184                 return -ENODATA;
185         }
186
187         limits->sku = sku;
188         limits->cap_clocks = cap_clks;
189         limits->cap_clocks_num = CAP_CLKS_NUM;
190         limits->temperatures = temperatures;
191         limits->temperature_ranges = TEMPERATURE_RANGES;
192         limits->core_modules_states = CORE_MODULES_STATES;
193
194         cap_rates = &edp_entry->cap_scpu_on[0][0][0][0];
195         limits->cap_rates_scpu_on = cap_rates;
196         for (i = 0; i < TOTAL_CAPS; i++, cap_rates++) {
197                 unsigned long rate = *cap_rates * edp_entry->mult;
198                 *cap_rates = clip_cap_rate(cap_clks[i % CAP_CLKS_NUM], rate);
199         }
200
201         cap_rates = &edp_entry->cap_scpu_off[0][0][0][0];
202         limits->cap_rates_scpu_off = cap_rates;
203         for (i = 0; i < TOTAL_CAPS; i++, cap_rates++) {
204                 unsigned long rate = *cap_rates * edp_entry->mult;
205                 *cap_rates = clip_cap_rate(cap_clks[i % CAP_CLKS_NUM], rate);
206         }
207
208         return 0;
209 }