1 /* arch/arm/mach-rk3026/dvfs.c
\r
3 * Copyright (C) 2012 ROCKCHIP, Inc.
\r
5 * This software is licensed under the terms of the GNU General Public
\r
6 * License version 2, as published by the Free Software Foundation, and
\r
7 * may be copied, distributed, and modified under those terms.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
16 #include <linux/kernel.h>
\r
17 #include <linux/err.h>
\r
18 #include <linux/spinlock.h>
\r
19 #include <linux/list.h>
\r
20 #include <linux/slab.h>
\r
21 #include <linux/clk.h>
\r
22 #include <linux/cpufreq.h>
\r
23 #include <mach/dvfs.h>
\r
24 #include <mach/clock.h>
\r
25 #include <linux/regulator/consumer.h>
\r
26 #include <linux/delay.h>
\r
27 #include <linux/io.h>
\r
28 #include <linux/hrtimer.h>
\r
29 #include <plat/efuse.h>
\r
31 static int rk_dvfs_clk_notifier_event(struct notifier_block *this,
\r
32 unsigned long event, void *ptr)
\r
34 struct clk_notifier_data *noti_info;
\r
36 struct clk_node *dvfs_clk;
\r
37 noti_info = (struct clk_notifier_data *)ptr;
\r
38 clk = noti_info->clk;
\r
39 dvfs_clk = clk->dvfs_info;
\r
42 case CLK_PRE_RATE_CHANGE:
\r
43 DVFS_DBG("%s CLK_PRE_RATE_CHANGE\n", __func__);
\r
45 case CLK_POST_RATE_CHANGE:
\r
46 DVFS_DBG("%s CLK_POST_RATE_CHANGE\n", __func__);
\r
48 case CLK_ABORT_RATE_CHANGE:
\r
49 DVFS_DBG("%s CLK_ABORT_RATE_CHANGE\n", __func__);
\r
51 case CLK_PRE_ENABLE:
\r
52 DVFS_DBG("%s CLK_PRE_ENABLE\n", __func__);
\r
54 case CLK_POST_ENABLE:
\r
55 DVFS_DBG("%s CLK_POST_ENABLE\n", __func__);
\r
57 case CLK_ABORT_ENABLE:
\r
58 DVFS_DBG("%s CLK_ABORT_ENABLE\n", __func__);
\r
60 case CLK_PRE_DISABLE:
\r
61 DVFS_DBG("%s CLK_PRE_DISABLE\n", __func__);
\r
63 case CLK_POST_DISABLE:
\r
64 DVFS_DBG("%s CLK_POST_DISABLE\n", __func__);
\r
65 dvfs_clk->set_freq = 0;
\r
67 case CLK_ABORT_DISABLE:
\r
68 DVFS_DBG("%s CLK_ABORT_DISABLE\n", __func__);
\r
77 static struct notifier_block rk_dvfs_clk_notifier = {
\r
78 .notifier_call = rk_dvfs_clk_notifier_event,
\r
80 struct lkg_maxvolt {
\r
82 unsigned int maxvolt;
\r
86 /* avdd_com & vdd_arm separate circuit */
\r
87 static struct lkg_maxvolt lkg_volt_table[] = {
\r
88 {.leakage_level = 1, .maxvolt = 1350 * 1000},
\r
89 {.leakage_level = 3, .maxvolt = 1275 * 1000},
\r
90 {.leakage_level = 15, .maxvolt = 1200 * 1000},
\r
93 /* avdd_com & vdd_arm short circuit */
\r
94 static struct lkg_maxvolt lkg_volt_table[] = {
\r
95 {.leakage_level = 3, .maxvolt = 1350 * 1000},
\r
96 {.leakage_level = 15, .maxvolt = 1250 * 1000},
\r
99 static int leakage_level = 0;
\r
100 #define MHZ (1000 * 1000)
\r
102 // Delayline bound for nandc = 148.5MHz, Varm = Vlog = 1.00V
\r
103 #define HIGH_DELAYLINE 125
\r
104 #define LOW_DELAYLINE 125
\r
105 static u8 rk30_get_avs_val(void);
\r
106 void dvfs_adjust_table_lmtvolt(struct clk *clk, struct cpufreq_frequency_table *table)
\r
109 unsigned int maxvolt = 0;
\r
110 if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(table)) {
\r
111 DVFS_ERR("%s: clk error OR table error\n", __func__);
\r
115 leakage_level = rk_leakage_val();
\r
116 printk("DVFS MSG: %s: %s get leakage_level = %d\n", clk->name, __func__, leakage_level);
\r
117 if (leakage_level == 0) {
\r
120 * This is for delayline auto scale voltage,
\r
121 * FIXME: HIGH_DELAYLINE / LOW_DELAYLINE value maybe redefined under
\r
122 * Varm = Vlog = 1.00V.
\r
123 * Warning: this value is frequency/voltage sensitive, care
\r
124 * about Freq nandc/Volt log.
\r
128 unsigned long delayline_val = 0;
\r
129 unsigned long high_delayline = 0, low_delayline = 0;
\r
130 unsigned long rate_nandc = 0;
\r
131 rate_nandc = clk_get_rate(clk_get(NULL, "nandc")) / KHZ;
\r
132 printk("Get nandc rate = %lu KHz\n", rate_nandc);
\r
133 high_delayline = HIGH_DELAYLINE * 148500 / rate_nandc;
\r
134 low_delayline = LOW_DELAYLINE * 148500 / rate_nandc;
\r
135 delayline_val = rk30_get_avs_val();
\r
136 printk("This chip no leakage msg, use delayline instead, val = %lu.(HDL=%lu, LDL=%lu)\n",
\r
137 delayline_val, high_delayline, low_delayline);
\r
139 if (delayline_val >= high_delayline) {
\r
140 leakage_level = 4; //same as leakage_level > 4
\r
142 } else if (delayline_val <= low_delayline) {
\r
144 printk("Delayline TOO LOW, high voltage request\n");
\r
147 leakage_level = 2; //same as leakage_level = 3
\r
150 for (i = 0; i < ARRAY_SIZE(lkg_volt_table); i++) {
\r
151 if (leakage_level <= lkg_volt_table[i].leakage_level) {
\r
152 maxvolt = lkg_volt_table[i].maxvolt;
\r
157 for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
\r
158 if (table[i].index > maxvolt) {
\r
159 printk("\t\tadjust table freq=%d KHz, index=%d mV", table[i].frequency, table[i].index);
\r
160 table[i].index = maxvolt;
\r
161 printk(" to index=%d mV\n", table[i].index);
\r
167 //static struct clk_node *dvfs_clk_cpu;
\r
168 static struct vd_node vd_core;
\r
169 int dvfs_target(struct clk *clk, unsigned long rate_hz)
\r
171 struct clk_node *dvfs_clk;
\r
172 int volt_new = 0, clk_volt_store = 0;
\r
173 struct cpufreq_frequency_table clk_fv;
\r
175 unsigned long rate_new, rate_old;
\r
178 DVFS_ERR("%s is not a clk\n", __func__);
\r
181 dvfs_clk = clk_get_dvfs_info(clk);
\r
182 DVFS_DBG("enter %s: clk(%s) rate = %lu Hz\n", __func__, dvfs_clk->name, rate_hz);
\r
184 if (!dvfs_clk || dvfs_clk->vd == NULL || IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {
\r
185 DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name);
\r
189 if (dvfs_clk->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) {
\r
190 /* It means the last time set voltage error */
\r
191 ret = dvfs_reset_volt(dvfs_clk->vd);
\r
197 /* Check limit rate */
\r
198 if (rate_hz < dvfs_clk->min_rate) {
\r
199 rate_hz = dvfs_clk->min_rate;
\r
200 } else if (rate_hz > dvfs_clk->max_rate) {
\r
201 rate_hz = dvfs_clk->max_rate;
\r
204 /* need round rate */
\r
205 rate_old = clk_get_rate(clk);
\r
206 rate_new = clk_round_rate_nolock(clk, rate_hz);
\r
207 if(rate_new == rate_old)
\r
210 DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n",
\r
211 dvfs_clk->name, rate_hz, rate_new, rate_old);
\r
213 /* find the clk corresponding voltage */
\r
214 if (0 != dvfs_clk_get_ref_volt(dvfs_clk, rate_new / 1000, &clk_fv)) {
\r
215 DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n", dvfs_clk->name, rate_hz);
\r
218 clk_volt_store = dvfs_clk->set_volt;
\r
219 dvfs_clk->set_volt = clk_fv.index;
\r
220 volt_new = dvfs_vd_get_newvolt_byclk(dvfs_clk);
\r
221 DVFS_DBG("%s,%s,new rate=%lu(was=%lu),new volt=%lu,(was=%d)\n",__FUNCTION__,dvfs_clk->name,rate_new,
\r
222 rate_old,volt_new,dvfs_clk->vd->cur_volt);
\r
224 /* if up the rate */
\r
225 if (rate_new > rate_old) {
\r
226 ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);
\r
228 goto fail_roll_back;
\r
232 if (dvfs_clk->clk_dvfs_target) {
\r
233 ret = dvfs_clk->clk_dvfs_target(clk, rate_new, clk_set_rate_locked);
\r
235 ret = clk_set_rate_locked(clk, rate_new);
\r
239 DVFS_ERR("%s set rate err\n", __func__);
\r
240 goto fail_roll_back;
\r
242 dvfs_clk->set_freq = rate_new / 1000;
\r
244 DVFS_DBG("dvfs %s set rate %lu ok\n", dvfs_clk->name, clk_get_rate(clk));
\r
246 /* if down the rate */
\r
247 if (rate_new < rate_old) {
\r
248 ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);
\r
255 dvfs_clk->set_volt = clk_volt_store;
\r
261 /*****************************init**************************/
\r
263 * rate must be raising sequence
\r
265 static struct cpufreq_frequency_table cpu_dvfs_table[] = {
\r
266 // {.frequency = 48 * DVFS_KHZ, .index = 920*DVFS_MV},
\r
267 // {.frequency = 126 * DVFS_KHZ, .index = 970 * DVFS_MV},
\r
268 // {.frequency = 252 * DVFS_KHZ, .index = 1040 * DVFS_MV},
\r
269 // {.frequency = 504 * DVFS_KHZ, .index = 1050 * DVFS_MV},
\r
270 {.frequency = 816 * DVFS_KHZ, .index = 1050 * DVFS_MV},
\r
271 // {.frequency = 1008 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
272 {.frequency = CPUFREQ_TABLE_END},
\r
275 static struct cpufreq_frequency_table ddr_dvfs_table[] = {
\r
276 // {.frequency = 100 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
277 {.frequency = 200 * DVFS_KHZ, .index = 1000 * DVFS_MV},
\r
278 {.frequency = 300 * DVFS_KHZ, .index = 1050 * DVFS_MV},
\r
279 {.frequency = 400 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
280 {.frequency = 500 * DVFS_KHZ, .index = 1150 * DVFS_MV},
\r
281 {.frequency = 600 * DVFS_KHZ, .index = 1200 * DVFS_MV},
\r
282 {.frequency = CPUFREQ_TABLE_END},
\r
285 static struct cpufreq_frequency_table gpu_dvfs_table[] = {
\r
286 {.frequency = 90 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
287 {.frequency = 180 * DVFS_KHZ, .index = 1150 * DVFS_MV},
\r
288 {.frequency = 300 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
289 {.frequency = 400 * DVFS_KHZ, .index = 1150 * DVFS_MV},
\r
290 {.frequency = 500 * DVFS_KHZ, .index = 1200 * DVFS_MV},
\r
291 {.frequency = CPUFREQ_TABLE_END},
\r
294 static struct cpufreq_frequency_table peri_aclk_dvfs_table[] = {
\r
295 {.frequency = 100 * DVFS_KHZ, .index = 1000 * DVFS_MV},
\r
296 {.frequency = 200 * DVFS_KHZ, .index = 1050 * DVFS_MV},
\r
297 {.frequency = 300 * DVFS_KHZ, .index = 1070 * DVFS_MV},
\r
298 {.frequency = 500 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
299 {.frequency = CPUFREQ_TABLE_END},
\r
302 static struct cpufreq_frequency_table vpu_dvfs_table[] = {
\r
303 {.frequency = 266 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
304 {.frequency = 300 * DVFS_KHZ, .index = 1100 * DVFS_MV},
\r
305 {.frequency = 400 * DVFS_KHZ, .index = 1200 * DVFS_MV},
\r
306 {.frequency = CPUFREQ_TABLE_END},
\r
309 static struct cpufreq_frequency_table dep_cpu2core_table[] = {
\r
310 // {.frequency = 252 * DVFS_KHZ, .index = 1025 * DVFS_MV},
\r
311 // {.frequency = 504 * DVFS_KHZ, .index = 1025 * DVFS_MV},
\r
312 {.frequency = 816 * DVFS_KHZ, .index = 1050 * DVFS_MV},//logic 1.050V
\r
313 // {.frequency = 1008 * DVFS_KHZ,.index = 1050 * DVFS_MV},
\r
314 // {.frequency = 1200 * DVFS_KHZ,.index = 1050 * DVFS_MV},
\r
315 // {.frequency = 1272 * DVFS_KHZ,.index = 1050 * DVFS_MV},//logic 1.050V
\r
316 // {.frequency = 1416 * DVFS_KHZ,.index = 1100 * DVFS_MV},//logic 1.100V
\r
317 // {.frequency = 1512 * DVFS_KHZ,.index = 1125 * DVFS_MV},//logic 1.125V
\r
318 // {.frequency = 1608 * DVFS_KHZ,.index = 1175 * DVFS_MV},//logic 1.175V
\r
319 {.frequency = CPUFREQ_TABLE_END},
\r
322 static struct vd_node vd_cpu = {
\r
324 .regulator_name = "vdd_cpu",
\r
325 .volt_set_flag = DVFS_SET_VOLT_FAILURE,
\r
326 .vd_dvfs_target = dvfs_target,
\r
329 static struct vd_node vd_core = {
\r
331 .regulator_name = "vdd_core",
\r
332 .volt_set_flag = DVFS_SET_VOLT_FAILURE,
\r
333 .vd_dvfs_target = dvfs_target,
\r
336 static struct vd_node vd_rtc = {
\r
338 .regulator_name = "vdd_rtc",
\r
339 .volt_set_flag = DVFS_SET_VOLT_FAILURE,
\r
340 .vd_dvfs_target = NULL,
\r
343 static struct vd_node *rk30_vds[] = {&vd_cpu, &vd_core, &vd_rtc};
\r
345 static struct pd_node pd_a9_0 = {
\r
349 static struct pd_node pd_a9_1 = {
\r
353 static struct pd_node pd_debug = {
\r
354 .name = "pd_debug",
\r
357 static struct pd_node pd_scu = {
\r
361 static struct pd_node pd_video = {
\r
362 .name = "pd_video",
\r
365 static struct pd_node pd_vio = {
\r
369 static struct pd_node pd_gpu = {
\r
373 static struct pd_node pd_peri = {
\r
377 static struct pd_node pd_cpu = {
\r
381 static struct pd_node pd_alive = {
\r
382 .name = "pd_alive",
\r
385 static struct pd_node pd_rtc = {
\r
389 #define LOOKUP_PD(_ppd) \
\r
393 static struct pd_node_lookup rk30_pds[] = {
\r
394 LOOKUP_PD(&pd_a9_0),
\r
395 LOOKUP_PD(&pd_a9_1),
\r
396 LOOKUP_PD(&pd_debug),
\r
397 LOOKUP_PD(&pd_scu),
\r
398 LOOKUP_PD(&pd_video),
\r
399 LOOKUP_PD(&pd_vio),
\r
400 LOOKUP_PD(&pd_gpu),
\r
401 LOOKUP_PD(&pd_peri),
\r
402 LOOKUP_PD(&pd_cpu),
\r
403 LOOKUP_PD(&pd_alive),
\r
404 LOOKUP_PD(&pd_rtc),
\r
407 #define CLK_PDS(_ppd) \
\r
412 static struct pds_list cpu_pds[] = {
\r
418 static struct pds_list ddr_pds[] = {
\r
423 static struct pds_list gpu_pds[] = {
\r
428 static struct pds_list aclk_periph_pds[] = {
\r
433 static struct pds_list aclk_vepu_pds[] = {
\r
434 CLK_PDS(&pd_video),
\r
438 #define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \
\r
440 .name = _clk_name, \
\r
442 .dvfs_table = _dvfs_table, \
\r
443 .dvfs_nb = _dvfs_nb, \
\r
446 static struct clk_node rk30_clks[] = {
\r
447 RK_CLKS("cpu", cpu_pds, cpu_dvfs_table, &rk_dvfs_clk_notifier),
\r
448 RK_CLKS("ddr", ddr_pds, ddr_dvfs_table, &rk_dvfs_clk_notifier),
\r
449 RK_CLKS("gpu", gpu_pds, gpu_dvfs_table, &rk_dvfs_clk_notifier),
\r
450 RK_CLKS("aclk_vepu", aclk_vepu_pds, vpu_dvfs_table, &rk_dvfs_clk_notifier),
\r
451 //RK_CLKS("aclk_periph", aclk_periph_pds, peri_aclk_dvfs_table, &rk_dvfs_clk_notifier),
\r
454 #define RK_DEPPENDS(_clk_name, _pvd, _dep_table) \
\r
456 .clk_name = _clk_name, \
\r
458 .dep_table = _dep_table, \
\r
461 static struct depend_lookup rk30_depends[] = {
\r
462 RK_DEPPENDS("cpu", &vd_core, dep_cpu2core_table),
\r
463 //RK_DEPPENDS("gpu", &vd_cpu, NULL),
\r
464 //RK_DEPPENDS("gpu", &vd_cpu, NULL),
\r
468 static struct avs_ctr_st rk292x_avs_ctr;
\r
470 int rk292x_dvfs_init(void)
\r
473 for (i = 0; i < ARRAY_SIZE(rk30_vds); i++) {
\r
474 rk_regist_vd(rk30_vds[i]);
\r
476 for (i = 0; i < ARRAY_SIZE(rk30_pds); i++) {
\r
477 rk_regist_pd(&rk30_pds[i]);
\r
479 for (i = 0; i < ARRAY_SIZE(rk30_clks); i++) {
\r
480 rk_regist_clk(&rk30_clks[i]);
\r
482 for (i = 0; i < ARRAY_SIZE(rk30_depends); i++) {
\r
483 rk_regist_depends(&rk30_depends[i]);
\r
485 //dvfs_clk_cpu = dvfs_get_dvfs_clk_byname("cpu");
\r
486 avs_board_init(&rk292x_avs_ctr);
\r
490 /******************************rk292x avs**************************************************/
\r
492 static void __iomem *rk292x_nandc_base;
\r
493 #define nandc_readl(offset) readl_relaxed(rk292x_nandc_base + offset)
\r
494 #define nandc_writel(v, offset) do { writel_relaxed(v, rk292x_nandc_base + offset); dsb(); } while (0)
\r
495 static u8 rk292x_get_avs_val(void)
\r
497 u32 nanc_save_reg[4];
\r
498 unsigned long flags;
\r
501 if(rk292x_nandc_base == NULL)
\r
504 local_irq_save(flags);
\r
506 nanc_save_reg[0] = nandc_readl(0);
\r
507 nanc_save_reg[1] = nandc_readl(0x130);
\r
508 nanc_save_reg[2] = nandc_readl(0x134);
\r
509 nanc_save_reg[3] = nandc_readl(0x158);
\r
511 nandc_writel(nanc_save_reg[0] | 0x1 << 14, 0);
\r
512 nandc_writel(0x5, 0x130);
\r
514 /* Just break lock status */
\r
515 nandc_writel(0x1, 0x158);
\r
516 nandc_writel(0x7, 0x158);
\r
517 nandc_writel(0x21, 0x134);
\r
520 paramet = nandc_readl(0x138);
\r
521 if((paramet & 0x1))
\r
525 paramet = (paramet >> 1) & 0xff;
\r
526 nandc_writel(nanc_save_reg[0], 0);
\r
527 nandc_writel(nanc_save_reg[1], 0x130);
\r
528 nandc_writel(nanc_save_reg[2], 0x134);
\r
529 nandc_writel(nanc_save_reg[3], 0x158);
\r
531 local_irq_restore(flags);
\r
533 return (u8)paramet;
\r
537 void rk292x_avs_init(void)
\r
539 rk292x_nandc_base = ioremap(RK2928_NANDC_PHYS, RK2928_NANDC_SIZE);
\r
540 //avs_init_val_get(0,1150000,"board_init");
\r
543 static struct avs_ctr_st rk292x_avs_ctr = {
\r
544 .avs_init =rk292x_avs_init,
\r
545 .avs_get_val = rk292x_get_avs_val,
\r