Revert "ARM: tegra: tegratab: dummy change"
[linux-2.6.git] / drivers / edp / tegra_core_lite.c
1 /*
2  * Copyright (c) 2013, 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/clk.h>
18 #include <linux/cpu.h>
19 #include <linux/debugfs.h>
20 #include <linux/edp.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/platform_device.h>
24 #include <linux/pm_qos.h>
25 #include <linux/slab.h>
26 #include <linux/workqueue.h>
27 #include <linux/platform_data/tegra_edp.h>
28
29 struct freqcap {
30         unsigned int cpu;
31         unsigned int gpu;
32         unsigned int emc;
33 };
34
35 static unsigned int online_cpu_count;
36 static struct tegra_sysedp_corecap *cur_corecap;
37 static struct clk *emc_cap_clk;
38 static struct clk *gpu_cap_clk;
39 static struct pm_qos_request cpufreq_qos;
40 static struct tegra_sysedp_platform_data *core_platdata;
41 static struct freqcap core_policy;
42 static struct freqcap cur_caps;
43 static DEFINE_MUTEX(core_lock);
44
45 /* To save some cycles from a linear search */
46 static unsigned int cpu_lut_match(unsigned int power,
47                 struct tegra_system_edp_entry *lut, unsigned int lutlen)
48 {
49         unsigned int fv;
50         unsigned int lv;
51         unsigned int step;
52         unsigned int i;
53
54         if (lutlen == 1)
55                 return 0;
56
57         fv = lut[0].power_limit_100mW * 100;
58         lv = lut[lutlen - 1].power_limit_100mW * 100;
59         step = (lv - fv) / (lutlen - 1);
60
61         i = (power - fv + step - 1) / step;
62         i = min_t(unsigned int, i, lutlen - 1);
63         if (lut[i].power_limit_100mW * 100 >= power)
64                 return i;
65
66         /* Didn't work, search back from the end */
67         return lutlen - 1;
68 }
69
70 static unsigned int get_cpufreq_lim(unsigned int power)
71 {
72         struct tegra_system_edp_entry *p;
73         int i;
74
75         i = cpu_lut_match(power, core_platdata->cpufreq_lim,
76                         core_platdata->cpufreq_lim_size);
77         p = core_platdata->cpufreq_lim + i;
78
79         return p->freq_limits[online_cpu_count - 1];
80 }
81
82 static void pr_caps(struct freqcap *old, struct freqcap *new,
83                 unsigned int cpu_power)
84 {
85         if (!IS_ENABLED(CONFIG_DEBUG_KERNEL))
86                 return;
87
88         if (new->cpu == old->cpu &&
89                         new->gpu == old->gpu &&
90                         new->emc == old->emc)
91                 return;
92
93         pr_debug("sysedp: ncpus %u, core %5u mW," \
94                         " cpu %5u mW %u kHz, gpu %u kHz, emc %u kHz\n",
95                         online_cpu_count, cur_corecap->power,
96                         cpu_power, new->cpu, new->gpu, new->emc);
97 }
98
99 static void apply_caps(struct tegra_sysedp_devcap *devcap)
100 {
101         struct freqcap new;
102         int r;
103
104         core_policy.cpu = get_cpufreq_lim(devcap->cpu_power);
105         core_policy.gpu = devcap->gpufreq * 1000;
106         core_policy.emc = devcap->emcfreq * 1000;
107
108         new.cpu = core_policy.cpu;
109         new.gpu = core_policy.gpu;
110         new.emc = core_policy.emc;
111
112         if (new.cpu != cur_caps.cpu)
113                 pm_qos_update_request(&cpufreq_qos, new.cpu);
114
115         if (new.emc != cur_caps.emc) {
116                 r = clk_set_rate(emc_cap_clk, new.emc * 1000);
117                 WARN_ON(r);
118         }
119
120         if (new.gpu != cur_caps.gpu) {
121                 r = clk_set_rate(gpu_cap_clk, new.gpu * 1000);
122                 WARN_ON(r);
123         }
124
125         pr_caps(&cur_caps, &new, devcap->cpu_power);
126         cur_caps = new;
127 }
128
129 static void __do_cap_control(void)
130 {
131         struct tegra_sysedp_devcap *cap;
132
133         if (!cur_corecap)
134                 return;
135
136         cap = &cur_corecap->cpupri;
137         apply_caps(cap);
138 }
139
140 static void do_cap_control(void)
141 {
142         mutex_lock(&core_lock);
143         __do_cap_control();
144         mutex_unlock(&core_lock);
145 }
146
147 static void update_cur_corecap(unsigned int power)
148 {
149         struct tegra_sysedp_corecap *cap;
150         int i;
151
152         if (!core_platdata)
153                 return;
154
155         i = core_platdata->corecap_size - 1;
156         cap = core_platdata->corecap + i;
157
158         for (; i >= 0; i--, cap--) {
159                 if (cap->power <= power) {
160                         cur_corecap = cap;
161                         return;
162                 }
163         }
164
165         WARN_ON(1);
166         cur_corecap = core_platdata->corecap;
167 }
168
169 void sysedp_lite_throttle(unsigned int power)
170 {
171         mutex_lock(&core_lock);
172         update_cur_corecap(power);
173         __do_cap_control();
174         mutex_unlock(&core_lock);
175 }
176 EXPORT_SYMBOL_GPL(sysedp_lite_throttle);
177
178 static int tegra_edp_cpu_notify(struct notifier_block *nb,
179                 unsigned long action, void *data)
180 {
181         switch (action) {
182         case CPU_UP_PREPARE:
183                 online_cpu_count = num_online_cpus() + 1;
184                 break;
185         case CPU_DEAD:
186                 online_cpu_count = num_online_cpus();
187                 break;
188         default:
189                 return NOTIFY_OK;
190         }
191
192         do_cap_control();
193         return NOTIFY_OK;
194 }
195
196 static struct notifier_block tegra_edp_cpu_nb = {
197         .notifier_call = tegra_edp_cpu_notify
198 };
199
200 static __devinit int init_clks(void)
201 {
202         emc_cap_clk = clk_get_sys("battery_edp", "emc");
203         if (IS_ERR(emc_cap_clk))
204                 return -ENODEV;
205
206         gpu_cap_clk = clk_get_sys("battery_edp", "gpu");
207         if (IS_ERR(gpu_cap_clk)) {
208                 clk_put(emc_cap_clk);
209                 return -ENODEV;
210         }
211
212         return 0;
213 }
214
215 static __devinit int tegra_sysedp_lite_probe(struct platform_device *pdev)
216 {
217         int r;
218
219         if (!pdev->dev.platform_data)
220                 return -EINVAL;
221
222         online_cpu_count = num_online_cpus();
223         pm_qos_add_request(&cpufreq_qos, PM_QOS_CPU_FREQ_MAX,
224                         PM_QOS_CPU_FREQ_MAX_DEFAULT_VALUE);
225
226         r = register_cpu_notifier(&tegra_edp_cpu_nb);
227         if (r)
228                 return r;
229
230         r = init_clks();
231         if (r)
232                 return r;
233
234         mutex_lock(&core_lock);
235         core_platdata = pdev->dev.platform_data;
236         /* no limit */
237         update_cur_corecap(ULONG_MAX);
238         __do_cap_control();
239         mutex_unlock(&core_lock);
240
241         return 0;
242 }
243
244 static struct platform_driver tegra_sysedp_lite_driver = {
245         .probe = tegra_sysedp_lite_probe,
246         .driver = {
247                 .owner = THIS_MODULE,
248                 .name = "tegra_sysedp_lite"
249         }
250 };
251
252 static __init int tegra_sysedp_lite_init(void)
253 {
254         return platform_driver_register(&tegra_sysedp_lite_driver);
255 }
256 late_initcall(tegra_sysedp_lite_init);