upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / busfreq.c
1 /* linux/arch/arm/mach-s5pv310/busfreq.c
2  *
3  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com/
5  *
6  * S5PV310 - BUS clock frequency scaling support
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
15 #include <linux/types.h>
16 #include <linux/err.h>
17 #include <linux/io.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/sysfs.h>
20 #include <linux/platform_device.h>
21 #include <linux/device.h>
22 #include <linux/module.h>
23 #include <linux/cpu.h>
24 #include <linux/ktime.h>
25 #include <linux/tick.h>
26 #include <linux/kernel_stat.h>
27 #include <linux/cpufreq.h>
28 #include <linux/suspend.h>
29
30 #include <mach/ppmu.h>
31 #include <mach/map.h>
32 #include <mach/regs-clock.h>
33 #include <plat/map-s5p.h>
34 #include <mach/gpio.h>
35 #include <mach/regs-mem.h>
36 #include <mach/cpufreq.h>
37 #include <plat/gpio-cfg.h>
38 #include <asm/mach-types.h>
39 #include <mach/asv.h>
40
41 #define MAX_LOAD                100
42 #define DIVIDING_FACTOR         10000
43 #define UP_THRESHOLD_DEFAULT    17
44
45 #define BUS_SATURATION          40
46
47 static bool init_complete;
48 static unsigned up_threshold;
49 static struct regulator *int_regulator;
50 static struct s5pv310_ppmu_hw dmc[2];
51 static struct s5pv310_ppmu_hw cpu;
52 static unsigned int bus_utilization[2];
53
54 static bool halt_busfreq;
55
56 static unsigned int g_busfreq_lock_id;
57 static unsigned int g_busfreq_lock_val[DVFS_LOCK_ID_END];
58 static unsigned int g_busfreq_lock_level;
59
60 static DEFINE_MUTEX(set_bus_freq_lock);
61
62 enum busfreq_level_idx {
63         LV_0 = 0,
64         LV_1,
65         LV_2,
66         LV_END
67 };
68
69 static unsigned int p_idx;
70 static unsigned int curr_idx;
71 static unsigned int minFreq;
72
73 struct busfreq_table {
74         unsigned int idx;
75         unsigned int mem_clk;
76         unsigned int volt;
77 };
78
79 struct busfreq_clkdiv {
80         unsigned int index;
81         unsigned int clkdiv;
82 };
83
84 static struct busfreq_table s5pv310_busfreq_table[] = {
85         {LV_0, 400000, 1100000},
86         {LV_1, 267000, 1000000},
87         {LV_2, 133000, 950000},
88         {0, 0, 0},
89 };
90
91 #define ASV_GROUP       5
92 static unsigned int s5pv310_asv_volt[ASV_GROUP][LV_END] = {
93         {1150000, 1050000, 1025000},
94         {1125000, 1025000, 1000000},
95         {1100000, 1000000, 975000},
96         {1075000, 975000, 950000},
97         {1050000, 950000, 950000},
98 };
99
100 static unsigned int clkdiv_dmc0[LV_END][8] = {
101         /*
102          * Clock divider value for following
103          * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
104          *              DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
105          */
106
107         /* DMC L0: 400MHz */
108         { 3, 1, 1, 1, 1, 1, 3, 1 },
109
110         /* DMC L1: 266.7MHz */
111         { 4, 1, 1, 2, 1, 1, 3, 1 },
112
113         /* DMC L2: 133MHz */
114         { 5, 1, 1, 5, 1, 1, 3, 1 },
115 };
116
117 static unsigned int clkdiv_top[LV_END][5] = {
118         /*
119          * Clock divider value for following
120          * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
121          */
122
123         /* ACLK200 L0: 200MHz */
124         { 3, 7, 4, 5, 1 },
125
126         /* ACLK200 L1: 160MHz */
127         { 4, 7, 5, 6, 1 },
128
129         /* ACLK200 L2: 133MHz */
130         { 5, 7, 7, 7, 1 },
131 };
132
133 static unsigned int clkdiv_lr_bus[LV_END][2] = {
134         /*
135          * Clock divider value for following
136          * { DIVGDL/R, DIVGPL/R }
137          */
138
139         /* ACLK_GDL/R L1: 200MHz */
140         { 3, 1 },
141
142         /* ACLK_GDL/R L2: 160MHz */
143         { 4, 1 },
144
145         /* ACLK_GDL/R L3: 133MHz */
146         { 5, 1 },
147 };
148
149 static struct busfreq_clkdiv busfreq_dmc_divtable[] = {
150         {LV_0, 0},
151         {LV_1, 0},
152         {LV_2, 0},
153 };
154
155 static struct busfreq_clkdiv busfreq_top_divtable[] = {
156         {LV_0, 0},
157         {LV_1, 0},
158         {LV_2, 0},
159 };
160
161 static void s5pv310_set_busfreq(unsigned int div_index)
162 {
163         unsigned int tmp;
164
165         /* Change Divider - DMC0 */
166         tmp = busfreq_dmc_divtable[div_index].clkdiv;
167
168         __raw_writel(tmp, S5P_CLKDIV_DMC0);
169
170         do {
171                 tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
172         } while (tmp & 0x11111111);
173
174         /* Change Divider - TOP */
175         tmp = busfreq_top_divtable[div_index].clkdiv;
176
177         __raw_writel(tmp, S5P_CLKDIV_TOP);
178
179         do {
180                 tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
181         } while (tmp & 0x11111);
182
183         /* Change Divider - LEFTBUS */
184         tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
185
186         tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
187
188         tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
189                 (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
190
191         __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
192
193         do {
194                 tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
195         } while (tmp & 0x11);
196
197         /* Change Divider - RIGHTBUS */
198         tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
199
200         tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
201
202         tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
203                 (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
204
205         __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
206
207         do {
208                 tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
209         } while (tmp & 0x11);
210
211 }
212
213 static unsigned int calc_bus_utilization(struct s5pv310_ppmu_hw *ppmu)
214 {
215         if (ppmu->ccnt == 0) {
216                 pr_err("%s: 0 value is not permitted\n", __func__);
217                 return MAX_LOAD;
218         }
219
220         if (!(ppmu->ccnt >> 7))
221                 return (ppmu->count[0] * 100) / ppmu->ccnt;
222         else
223                 return ((ppmu->count[0] >> 7) * 100) / (ppmu->ccnt >> 7);
224
225 }
226
227 static int busfreq_target(struct busfreq_table *freq_table,
228                           unsigned int ppc_load,
229                           unsigned int ppmu_load,
230                           unsigned int pre_idx,
231                           unsigned int *index)
232 {
233         unsigned int i, target_freq, idx = 0;
234
235         if (ppc_load > 50) {
236                 pr_debug("Busfreq: Bus Load is larger than 40(%d)\n", ppc_load);
237                 ppc_load = 50;
238         }
239
240         if (pre_idx >= LV_END) {
241                 WARN(true, "Errornous value entered: %d\n", pre_idx);
242                 pre_idx = LV_END - 1;
243         }
244
245         target_freq = ppc_load * freq_table[pre_idx].mem_clk * 100
246                     / up_threshold / BUS_SATURATION;
247
248         for (i = 0; (freq_table[i].mem_clk != 0); i++) {
249                 if (freq_table[i].mem_clk >= target_freq)
250                         idx = i;
251                 else
252                         break;
253         }
254
255         if (idx > g_busfreq_lock_level) {
256                 pr_debug("LOCKED BUSFREQ %d->%d\n", idx, g_busfreq_lock_level);
257                 idx = g_busfreq_lock_level;
258         }
259
260         if (idx >= LV_END) {
261                 WARN(true, "Errornous value entered: %d\n", idx);
262                 idx = LV_END - 1;
263         }
264
265         *index = idx;
266
267         return 0;
268 }
269
270 static void busfreq_mon_reset(void)
271 {
272         unsigned int i;
273
274         for (i = 0; i < 2; i++) {
275                 s5pv310_ppc_reset(&dmc[i]);
276                 s5pv310_ppc_setevent(&dmc[i], 0x6);
277                 s5pv310_ppc_start(&dmc[i]);
278         }
279
280         s5pv310_ppmu_reset(&cpu);
281         s5pv310_ppmu_setevent(&cpu, 0x5, 0);
282         s5pv310_ppmu_setevent(&cpu, 0x6, 1);
283         s5pv310_ppmu_start(&cpu);
284
285 }
286
287 static unsigned int busfreq_monitor(void)
288 {
289         unsigned int i, index = 0, ppcload, ppmuload, ret;
290
291         for (i = 0; i < 2; i++) {
292                 s5pv310_ppc_stop(&dmc[i]);
293                 s5pv310_ppc_update(&dmc[i]);
294                 bus_utilization[i] = calc_bus_utilization(&dmc[i]);
295         }
296
297         s5pv310_ppmu_stop(&cpu);
298         s5pv310_ppmu_update(&cpu);
299
300         if (cpu.ccnt == 0)
301                 cpu.ccnt = MAX_LOAD;
302
303
304         ppcload = max(bus_utilization[0], bus_utilization[1]);
305         ppmuload = (cpu.count[0] + cpu.count[1])*100 / cpu.ccnt;
306         index = p_idx;
307
308         /* Change bus frequency */
309         ret = busfreq_target(s5pv310_busfreq_table, ppcload,
310                 ppmuload, p_idx, &index);
311         if (ret)
312                 pr_err("%s: (%d)\n", __func__, ret);
313
314         pr_debug("Bus freq(%d-%d) / ppmu %u, ppc %u\n", p_idx, index, ppmuload, ppcload);
315
316         busfreq_mon_reset();
317
318         return index;
319 }
320
321 void s5pv310_busfreq_force_notify(struct cpufreq_freqs *freq)
322 {
323         unsigned int voltage;
324
325         if (!init_complete)
326                 return;
327
328         if (halt_busfreq)
329                 return;
330
331         /* Skip reevaluating at idling */
332         if (freq->new <= 200000 && p_idx == LV_2)
333                 return;
334
335         mutex_lock(&set_bus_freq_lock);
336
337         curr_idx = busfreq_monitor();
338         voltage = s5pv310_busfreq_table[curr_idx].volt;
339         if (p_idx > curr_idx) {
340                 regulator_set_voltage(int_regulator, voltage, voltage);
341         }
342
343         if (p_idx != curr_idx)
344                 s5pv310_set_busfreq(curr_idx);
345
346         if (p_idx < curr_idx) {
347                 regulator_set_voltage(int_regulator, voltage, voltage);
348         }
349         p_idx = curr_idx;
350
351         mutex_unlock(&set_bus_freq_lock);
352 }
353
354 static int s5pv310_busfreq_notifier_event(struct notifier_block *this,
355                 unsigned long event, void *ptr)
356 {
357         unsigned int voltage;
358
359         if (!init_complete)
360                 return NOTIFY_OK;
361
362         if (halt_busfreq)
363                 return NOTIFY_OK;
364
365         switch (event) {
366         case CPUFREQ_PRECHANGE:
367                 mutex_lock(&set_bus_freq_lock);
368                 curr_idx = busfreq_monitor();
369                 mutex_unlock(&set_bus_freq_lock);
370                 break;
371         case CPUFREQ_POSTCHANGE:
372                 mutex_lock(&set_bus_freq_lock);
373                 voltage = s5pv310_busfreq_table[curr_idx].volt;
374                 if (p_idx > curr_idx) {
375                         regulator_set_voltage(int_regulator, voltage,
376                                         voltage);
377                 }
378
379                 if (p_idx != curr_idx)
380                         s5pv310_set_busfreq(curr_idx);
381
382                 if (p_idx < curr_idx) {
383                         regulator_set_voltage(int_regulator, voltage,
384                                         voltage);
385                 }
386                 p_idx = curr_idx;
387                 mutex_unlock(&set_bus_freq_lock);
388                 break;
389         case CPUFREQ_RESUMECHANGE:
390                 break;
391         default:
392                 /* ignore */
393                 break;
394         }
395
396         return NOTIFY_OK;
397 }
398
399 static struct notifier_block s5pv310_busfreq_notifier = {
400         .notifier_call = s5pv310_busfreq_notifier_event,
401 };
402
403 static int s5pv310_buspm_notifier_event(struct notifier_block *this,
404                 unsigned long event, void *ptr)
405 {
406         switch (event) {
407         case PM_RESTORE_PREPARE:
408         case PM_SUSPEND_PREPARE:
409         case PM_HIBERNATION_PREPARE:
410                 s5pv310_busfreq_lock(DVFS_LOCK_ID_PM, BUS_L0);
411                 halt_busfreq = true;
412                 return NOTIFY_OK;
413         case PM_POST_RESTORE:
414         case PM_POST_SUSPEND:
415         case PM_POST_HIBERNATION:
416                 halt_busfreq = false;
417                 busfreq_mon_reset();
418                 s5pv310_busfreq_lock_free(DVFS_LOCK_ID_PM);
419                 return NOTIFY_OK;
420         }
421         return NOTIFY_DONE;
422 }
423
424 static struct notifier_block s5pv310_buspm_notifier = {
425         .notifier_call = s5pv310_buspm_notifier_event,
426 };
427
428 int s5pv310_busfreq_lock(unsigned int nId,
429         enum busfreq_level_request busfreq_level)
430 {
431         unsigned int int_volt;
432
433         mutex_lock(&set_bus_freq_lock);
434         if (g_busfreq_lock_id & (1 << nId)) {
435                 pr_err("This device [%d] already locked busfreq\n", nId);
436                 goto err;
437         }
438         g_busfreq_lock_id |= (1 << nId);
439         g_busfreq_lock_val[nId] = busfreq_level;
440
441         if (halt_busfreq)
442                 goto err;
443
444         /* If the requested cpufreq is higher than current min frequency */
445         if (busfreq_level < g_busfreq_lock_level) {
446                 g_busfreq_lock_level = busfreq_level;
447
448                 /* Change now if the wanted freq is higher */
449                 if (busfreq_level < p_idx) {
450                         /* get the voltage value */
451                         int_volt = s5pv310_busfreq_table[busfreq_level].volt;
452                         regulator_set_voltage(int_regulator, int_volt,
453                                         int_volt);
454                         s5pv310_set_busfreq(busfreq_level);
455                 }
456         }
457 err:
458         mutex_unlock(&set_bus_freq_lock);
459         return 0;
460 }
461
462 void s5pv310_busfreq_lock_free(unsigned int nId)
463 {
464         unsigned int i;
465
466         mutex_lock(&set_bus_freq_lock);
467         g_busfreq_lock_id &= ~(1 << nId);
468         g_busfreq_lock_val[nId] = minFreq;
469         g_busfreq_lock_level = minFreq;
470
471         if (g_busfreq_lock_id) {
472                 for (i = 0; i < DVFS_LOCK_ID_END; i++) {
473                         if (g_busfreq_lock_val[i] < g_busfreq_lock_level)
474                                 g_busfreq_lock_level = g_busfreq_lock_val[i];
475                 }
476         }
477         mutex_unlock(&set_bus_freq_lock);
478 }
479
480 static void __init s5pv310_set_bus_volt(void)
481 {
482         unsigned int asv_group;
483         unsigned int i;
484
485         asv_group = exynos4_asv_group;
486
487         printk(KERN_INFO "DVFS : VDD_INT Voltage table set with %d Group\n", asv_group);
488
489         for (i = 0 ; i < LV_END ; i++) {
490                 switch (asv_group) {
491                 case 0:
492                         s5pv310_busfreq_table[i].volt =
493                                 s5pv310_asv_volt[0][i];
494                         break;
495                 case 1:
496                 case 2:
497                         s5pv310_busfreq_table[i].volt =
498                                 s5pv310_asv_volt[1][i];
499                         break;
500                 case 3:
501                 case 4:
502                         s5pv310_busfreq_table[i].volt =
503                                 s5pv310_asv_volt[2][i];
504                         break;
505                 case 5:
506                 case 6:
507                         s5pv310_busfreq_table[i].volt =
508                                 s5pv310_asv_volt[3][i];
509                         break;
510                 case 7:
511                         s5pv310_busfreq_table[i].volt =
512                                 s5pv310_asv_volt[4][i];
513                         break;
514                 }
515         }
516
517         return;
518 }
519
520 static int __init busfreq_mon_init(void)
521 {
522         unsigned int i;
523         unsigned int tmp;
524         struct cpufreq_frequency_table *table;
525
526         if (machine_is_smdkv310())
527                 return -ENODEV;
528
529         table = cpufreq_frequency_get_table(0);
530
531         if (IS_ERR_OR_NULL(table))
532                 return -ENODEV;
533
534         for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
535                 /* Donthing to do currently */
536         }
537
538         minFreq = table[i-1].frequency ;
539         g_busfreq_lock_level = minFreq;
540
541         cpu.hw_base = S5P_VA_PPMU_CPU;
542
543         dmc[DMC0].hw_base = S5P_VA_DMC0;
544         dmc[DMC1].hw_base = S5P_VA_DMC1;
545
546         p_idx = LV_0;
547         up_threshold = UP_THRESHOLD_DEFAULT;
548
549         tmp = __raw_readl(S5P_CLKDIV_DMC0);
550
551         for (i = 0; i <  LV_END; i++) {
552                 tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK |
553                         S5P_CLKDIV_DMC0_ACPPCLK_MASK |
554                         S5P_CLKDIV_DMC0_DPHY_MASK |
555                         S5P_CLKDIV_DMC0_DMC_MASK |
556                         S5P_CLKDIV_DMC0_DMCD_MASK |
557                         S5P_CLKDIV_DMC0_DMCP_MASK |
558                         S5P_CLKDIV_DMC0_COPY2_MASK |
559                         S5P_CLKDIV_DMC0_CORETI_MASK);
560
561                 tmp |= ((clkdiv_dmc0[i][0] << S5P_CLKDIV_DMC0_ACP_SHIFT) |
562                         (clkdiv_dmc0[i][1] << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
563                         (clkdiv_dmc0[i][2] << S5P_CLKDIV_DMC0_DPHY_SHIFT) |
564                         (clkdiv_dmc0[i][3] << S5P_CLKDIV_DMC0_DMC_SHIFT) |
565                         (clkdiv_dmc0[i][4] << S5P_CLKDIV_DMC0_DMCD_SHIFT) |
566                         (clkdiv_dmc0[i][5] << S5P_CLKDIV_DMC0_DMCP_SHIFT) |
567                         (clkdiv_dmc0[i][6] << S5P_CLKDIV_DMC0_COPY2_SHIFT) |
568                         (clkdiv_dmc0[i][7] << S5P_CLKDIV_DMC0_CORETI_SHIFT));
569
570                 busfreq_dmc_divtable[i].clkdiv = tmp;
571         }
572
573         tmp = __raw_readl(S5P_CLKDIV_TOP);
574
575         for (i = 0; i <  LV_END; i++) {
576                 tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK |
577                         S5P_CLKDIV_TOP_ACLK100_MASK |
578                         S5P_CLKDIV_TOP_ACLK160_MASK |
579                         S5P_CLKDIV_TOP_ACLK133_MASK |
580                         S5P_CLKDIV_TOP_ONENAND_MASK);
581
582                 tmp |= ((clkdiv_top[i][0] << S5P_CLKDIV_TOP_ACLK200_SHIFT) |
583                         (clkdiv_top[i][1] << S5P_CLKDIV_TOP_ACLK100_SHIFT) |
584                         (clkdiv_top[i][2] << S5P_CLKDIV_TOP_ACLK160_SHIFT) |
585                         (clkdiv_top[i][3] << S5P_CLKDIV_TOP_ACLK133_SHIFT) |
586                         (clkdiv_top[i][4] << S5P_CLKDIV_TOP_ONENAND_SHIFT));
587
588                 busfreq_top_divtable[i].clkdiv = tmp;
589         }
590
591         s5pv310_set_bus_volt();
592
593         int_regulator = regulator_get(NULL, "vdd_int");
594         if (IS_ERR(int_regulator)) {
595                 pr_err("failed to get resource %s\n", "vdd_int");
596                 return -ENODEV;
597         }
598         busfreq_mon_reset();
599
600         if (cpufreq_register_notifier(&s5pv310_busfreq_notifier,
601                                 CPUFREQ_TRANSITION_NOTIFIER)) {
602                 pr_err("Failed to setup cpufreq notifier\n");
603                 goto err_cpufreq;
604         }
605
606         if (register_pm_notifier(&s5pv310_buspm_notifier)) {
607                 pr_err("Failed to setup buspm notifier\n");
608                 goto err_pm;
609         }
610
611         init_complete = true;
612         return 0;
613 err_pm:
614         cpufreq_unregister_notifier(&s5pv310_busfreq_notifier,
615                                 CPUFREQ_TRANSITION_NOTIFIER);
616 err_cpufreq:
617         if (!IS_ERR(int_regulator))
618                 regulator_put(int_regulator);
619         return -ENODEV;
620 }
621 late_initcall(busfreq_mon_init);