ath9k: Cleanup spectral scan code
[cascardo/linux.git] / drivers / cpufreq / s5pv210-cpufreq.c
1 /*
2  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
3  *              http://www.samsung.com
4  *
5  * CPU frequency scaling for S5PC110/S5PV210
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10 */
11
12 #include <linux/types.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/err.h>
16 #include <linux/clk.h>
17 #include <linux/io.h>
18 #include <linux/cpufreq.h>
19 #include <linux/reboot.h>
20 #include <linux/regulator/consumer.h>
21 #include <linux/suspend.h>
22
23 #include <mach/map.h>
24 #include <mach/regs-clock.h>
25
26 static struct clk *cpu_clk;
27 static struct clk *dmc0_clk;
28 static struct clk *dmc1_clk;
29 static DEFINE_MUTEX(set_freq_lock);
30
31 /* APLL M,P,S values for 1G/800Mhz */
32 #define APLL_VAL_1000   ((1 << 31) | (125 << 16) | (3 << 8) | 1)
33 #define APLL_VAL_800    ((1 << 31) | (100 << 16) | (3 << 8) | 1)
34
35 /* Use 800MHz when entering sleep mode */
36 #define SLEEP_FREQ      (800 * 1000)
37
38 /* Tracks if cpu freqency can be updated anymore */
39 static bool no_cpufreq_access;
40
41 /*
42  * DRAM configurations to calculate refresh counter for changing
43  * frequency of memory.
44  */
45 struct dram_conf {
46         unsigned long freq;     /* HZ */
47         unsigned long refresh;  /* DRAM refresh counter * 1000 */
48 };
49
50 /* DRAM configuration (DMC0 and DMC1) */
51 static struct dram_conf s5pv210_dram_conf[2];
52
53 enum perf_level {
54         L0, L1, L2, L3, L4,
55 };
56
57 enum s5pv210_mem_type {
58         LPDDR   = 0x1,
59         LPDDR2  = 0x2,
60         DDR2    = 0x4,
61 };
62
63 enum s5pv210_dmc_port {
64         DMC0 = 0,
65         DMC1,
66 };
67
68 static struct cpufreq_frequency_table s5pv210_freq_table[] = {
69         {L0, 1000*1000},
70         {L1, 800*1000},
71         {L2, 400*1000},
72         {L3, 200*1000},
73         {L4, 100*1000},
74         {0, CPUFREQ_TABLE_END},
75 };
76
77 static struct regulator *arm_regulator;
78 static struct regulator *int_regulator;
79
80 struct s5pv210_dvs_conf {
81         int arm_volt;   /* uV */
82         int int_volt;   /* uV */
83 };
84
85 static const int arm_volt_max = 1350000;
86 static const int int_volt_max = 1250000;
87
88 static struct s5pv210_dvs_conf dvs_conf[] = {
89         [L0] = {
90                 .arm_volt       = 1250000,
91                 .int_volt       = 1100000,
92         },
93         [L1] = {
94                 .arm_volt       = 1200000,
95                 .int_volt       = 1100000,
96         },
97         [L2] = {
98                 .arm_volt       = 1050000,
99                 .int_volt       = 1100000,
100         },
101         [L3] = {
102                 .arm_volt       = 950000,
103                 .int_volt       = 1100000,
104         },
105         [L4] = {
106                 .arm_volt       = 950000,
107                 .int_volt       = 1000000,
108         },
109 };
110
111 static u32 clkdiv_val[5][11] = {
112         /*
113          * Clock divider value for following
114          * { APLL, A2M, HCLK_MSYS, PCLK_MSYS,
115          *   HCLK_DSYS, PCLK_DSYS, HCLK_PSYS, PCLK_PSYS,
116          *   ONEDRAM, MFC, G3D }
117          */
118
119         /* L0 : [1000/200/100][166/83][133/66][200/200] */
120         {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0},
121
122         /* L1 : [800/200/100][166/83][133/66][200/200] */
123         {0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0},
124
125         /* L2 : [400/200/100][166/83][133/66][200/200] */
126         {1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
127
128         /* L3 : [200/200/100][166/83][133/66][200/200] */
129         {3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
130
131         /* L4 : [100/100/100][83/83][66/66][100/100] */
132         {7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0},
133 };
134
135 /*
136  * This function set DRAM refresh counter
137  * accoriding to operating frequency of DRAM
138  * ch: DMC port number 0 or 1
139  * freq: Operating frequency of DRAM(KHz)
140  */
141 static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
142 {
143         unsigned long tmp, tmp1;
144         void __iomem *reg = NULL;
145
146         if (ch == DMC0) {
147                 reg = (S5P_VA_DMC0 + 0x30);
148         } else if (ch == DMC1) {
149                 reg = (S5P_VA_DMC1 + 0x30);
150         } else {
151                 printk(KERN_ERR "Cannot find DMC port\n");
152                 return;
153         }
154
155         /* Find current DRAM frequency */
156         tmp = s5pv210_dram_conf[ch].freq;
157
158         do_div(tmp, freq);
159
160         tmp1 = s5pv210_dram_conf[ch].refresh;
161
162         do_div(tmp1, tmp);
163
164         __raw_writel(tmp1, reg);
165 }
166
167 static unsigned int s5pv210_getspeed(unsigned int cpu)
168 {
169         if (cpu)
170                 return 0;
171
172         return clk_get_rate(cpu_clk) / 1000;
173 }
174
175 static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
176 {
177         unsigned long reg;
178         unsigned int priv_index;
179         unsigned int pll_changing = 0;
180         unsigned int bus_speed_changing = 0;
181         unsigned int old_freq, new_freq;
182         int arm_volt, int_volt;
183         int ret = 0;
184
185         mutex_lock(&set_freq_lock);
186
187         if (no_cpufreq_access) {
188 #ifdef CONFIG_PM_VERBOSE
189                 pr_err("%s:%d denied access to %s as it is disabled"
190                                 "temporarily\n", __FILE__, __LINE__, __func__);
191 #endif
192                 ret = -EINVAL;
193                 goto exit;
194         }
195
196         old_freq = s5pv210_getspeed(0);
197         new_freq = s5pv210_freq_table[index].frequency;
198
199         /* Finding current running level index */
200         if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
201                                            old_freq, CPUFREQ_RELATION_H,
202                                            &priv_index)) {
203                 ret = -EINVAL;
204                 goto exit;
205         }
206
207         arm_volt = dvs_conf[index].arm_volt;
208         int_volt = dvs_conf[index].int_volt;
209
210         if (new_freq > old_freq) {
211                 ret = regulator_set_voltage(arm_regulator,
212                                 arm_volt, arm_volt_max);
213                 if (ret)
214                         goto exit;
215
216                 ret = regulator_set_voltage(int_regulator,
217                                 int_volt, int_volt_max);
218                 if (ret)
219                         goto exit;
220         }
221
222         /* Check if there need to change PLL */
223         if ((index == L0) || (priv_index == L0))
224                 pll_changing = 1;
225
226         /* Check if there need to change System bus clock */
227         if ((index == L4) || (priv_index == L4))
228                 bus_speed_changing = 1;
229
230         if (bus_speed_changing) {
231                 /*
232                  * Reconfigure DRAM refresh counter value for minimum
233                  * temporary clock while changing divider.
234                  * expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287
235                  */
236                 if (pll_changing)
237                         s5pv210_set_refresh(DMC1, 83000);
238                 else
239                         s5pv210_set_refresh(DMC1, 100000);
240
241                 s5pv210_set_refresh(DMC0, 83000);
242         }
243
244         /*
245          * APLL should be changed in this level
246          * APLL -> MPLL(for stable transition) -> APLL
247          * Some clock source's clock API are not prepared.
248          * Do not use clock API in below code.
249          */
250         if (pll_changing) {
251                 /*
252                  * 1. Temporary Change divider for MFC and G3D
253                  * SCLKA2M(200/1=200)->(200/4=50)Mhz
254                  */
255                 reg = __raw_readl(S5P_CLK_DIV2);
256                 reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
257                 reg |= (3 << S5P_CLKDIV2_G3D_SHIFT) |
258                         (3 << S5P_CLKDIV2_MFC_SHIFT);
259                 __raw_writel(reg, S5P_CLK_DIV2);
260
261                 /* For MFC, G3D dividing */
262                 do {
263                         reg = __raw_readl(S5P_CLKDIV_STAT0);
264                 } while (reg & ((1 << 16) | (1 << 17)));
265
266                 /*
267                  * 2. Change SCLKA2M(200Mhz)to SCLKMPLL in MFC_MUX, G3D MUX
268                  * (200/4=50)->(667/4=166)Mhz
269                  */
270                 reg = __raw_readl(S5P_CLK_SRC2);
271                 reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
272                 reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) |
273                         (1 << S5P_CLKSRC2_MFC_SHIFT);
274                 __raw_writel(reg, S5P_CLK_SRC2);
275
276                 do {
277                         reg = __raw_readl(S5P_CLKMUX_STAT1);
278                 } while (reg & ((1 << 7) | (1 << 3)));
279
280                 /*
281                  * 3. DMC1 refresh count for 133Mhz if (index == L4) is
282                  * true refresh counter is already programed in upper
283                  * code. 0x287@83Mhz
284                  */
285                 if (!bus_speed_changing)
286                         s5pv210_set_refresh(DMC1, 133000);
287
288                 /* 4. SCLKAPLL -> SCLKMPLL */
289                 reg = __raw_readl(S5P_CLK_SRC0);
290                 reg &= ~(S5P_CLKSRC0_MUX200_MASK);
291                 reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
292                 __raw_writel(reg, S5P_CLK_SRC0);
293
294                 do {
295                         reg = __raw_readl(S5P_CLKMUX_STAT0);
296                 } while (reg & (0x1 << 18));
297
298         }
299
300         /* Change divider */
301         reg = __raw_readl(S5P_CLK_DIV0);
302
303         reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK |
304                 S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK |
305                 S5P_CLKDIV0_HCLK166_MASK | S5P_CLKDIV0_PCLK83_MASK |
306                 S5P_CLKDIV0_HCLK133_MASK | S5P_CLKDIV0_PCLK66_MASK);
307
308         reg |= ((clkdiv_val[index][0] << S5P_CLKDIV0_APLL_SHIFT) |
309                 (clkdiv_val[index][1] << S5P_CLKDIV0_A2M_SHIFT) |
310                 (clkdiv_val[index][2] << S5P_CLKDIV0_HCLK200_SHIFT) |
311                 (clkdiv_val[index][3] << S5P_CLKDIV0_PCLK100_SHIFT) |
312                 (clkdiv_val[index][4] << S5P_CLKDIV0_HCLK166_SHIFT) |
313                 (clkdiv_val[index][5] << S5P_CLKDIV0_PCLK83_SHIFT) |
314                 (clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT) |
315                 (clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT));
316
317         __raw_writel(reg, S5P_CLK_DIV0);
318
319         do {
320                 reg = __raw_readl(S5P_CLKDIV_STAT0);
321         } while (reg & 0xff);
322
323         /* ARM MCS value changed */
324         reg = __raw_readl(S5P_ARM_MCS_CON);
325         reg &= ~0x3;
326         if (index >= L3)
327                 reg |= 0x3;
328         else
329                 reg |= 0x1;
330
331         __raw_writel(reg, S5P_ARM_MCS_CON);
332
333         if (pll_changing) {
334                 /* 5. Set Lock time = 30us*24Mhz = 0x2cf */
335                 __raw_writel(0x2cf, S5P_APLL_LOCK);
336
337                 /*
338                  * 6. Turn on APLL
339                  * 6-1. Set PMS values
340                  * 6-2. Wait untile the PLL is locked
341                  */
342                 if (index == L0)
343                         __raw_writel(APLL_VAL_1000, S5P_APLL_CON);
344                 else
345                         __raw_writel(APLL_VAL_800, S5P_APLL_CON);
346
347                 do {
348                         reg = __raw_readl(S5P_APLL_CON);
349                 } while (!(reg & (0x1 << 29)));
350
351                 /*
352                  * 7. Change souce clock from SCLKMPLL(667Mhz)
353                  * to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX
354                  * (667/4=166)->(200/4=50)Mhz
355                  */
356                 reg = __raw_readl(S5P_CLK_SRC2);
357                 reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
358                 reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) |
359                         (0 << S5P_CLKSRC2_MFC_SHIFT);
360                 __raw_writel(reg, S5P_CLK_SRC2);
361
362                 do {
363                         reg = __raw_readl(S5P_CLKMUX_STAT1);
364                 } while (reg & ((1 << 7) | (1 << 3)));
365
366                 /*
367                  * 8. Change divider for MFC and G3D
368                  * (200/4=50)->(200/1=200)Mhz
369                  */
370                 reg = __raw_readl(S5P_CLK_DIV2);
371                 reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
372                 reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) |
373                         (clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT);
374                 __raw_writel(reg, S5P_CLK_DIV2);
375
376                 /* For MFC, G3D dividing */
377                 do {
378                         reg = __raw_readl(S5P_CLKDIV_STAT0);
379                 } while (reg & ((1 << 16) | (1 << 17)));
380
381                 /* 9. Change MPLL to APLL in MSYS_MUX */
382                 reg = __raw_readl(S5P_CLK_SRC0);
383                 reg &= ~(S5P_CLKSRC0_MUX200_MASK);
384                 reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT);
385                 __raw_writel(reg, S5P_CLK_SRC0);
386
387                 do {
388                         reg = __raw_readl(S5P_CLKMUX_STAT0);
389                 } while (reg & (0x1 << 18));
390
391                 /*
392                  * 10. DMC1 refresh counter
393                  * L4 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c
394                  * Others : DMC1 = 200Mhz 7.8us/(1/200) = 0x618
395                  */
396                 if (!bus_speed_changing)
397                         s5pv210_set_refresh(DMC1, 200000);
398         }
399
400         /*
401          * L4 level need to change memory bus speed, hence onedram clock divier
402          * and memory refresh parameter should be changed
403          */
404         if (bus_speed_changing) {
405                 reg = __raw_readl(S5P_CLK_DIV6);
406                 reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
407                 reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
408                 __raw_writel(reg, S5P_CLK_DIV6);
409
410                 do {
411                         reg = __raw_readl(S5P_CLKDIV_STAT1);
412                 } while (reg & (1 << 15));
413
414                 /* Reconfigure DRAM refresh counter value */
415                 if (index != L4) {
416                         /*
417                          * DMC0 : 166Mhz
418                          * DMC1 : 200Mhz
419                          */
420                         s5pv210_set_refresh(DMC0, 166000);
421                         s5pv210_set_refresh(DMC1, 200000);
422                 } else {
423                         /*
424                          * DMC0 : 83Mhz
425                          * DMC1 : 100Mhz
426                          */
427                         s5pv210_set_refresh(DMC0, 83000);
428                         s5pv210_set_refresh(DMC1, 100000);
429                 }
430         }
431
432         if (new_freq < old_freq) {
433                 regulator_set_voltage(int_regulator,
434                                 int_volt, int_volt_max);
435
436                 regulator_set_voltage(arm_regulator,
437                                 arm_volt, arm_volt_max);
438         }
439
440         printk(KERN_DEBUG "Perf changed[L%d]\n", index);
441
442 exit:
443         mutex_unlock(&set_freq_lock);
444         return ret;
445 }
446
447 #ifdef CONFIG_PM
448 static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy)
449 {
450         return 0;
451 }
452
453 static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
454 {
455         return 0;
456 }
457 #endif
458
459 static int check_mem_type(void __iomem *dmc_reg)
460 {
461         unsigned long val;
462
463         val = __raw_readl(dmc_reg + 0x4);
464         val = (val & (0xf << 8));
465
466         return val >> 8;
467 }
468
469 static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
470 {
471         unsigned long mem_type;
472         int ret;
473
474         cpu_clk = clk_get(NULL, "armclk");
475         if (IS_ERR(cpu_clk))
476                 return PTR_ERR(cpu_clk);
477
478         dmc0_clk = clk_get(NULL, "sclk_dmc0");
479         if (IS_ERR(dmc0_clk)) {
480                 ret = PTR_ERR(dmc0_clk);
481                 goto out_dmc0;
482         }
483
484         dmc1_clk = clk_get(NULL, "hclk_msys");
485         if (IS_ERR(dmc1_clk)) {
486                 ret = PTR_ERR(dmc1_clk);
487                 goto out_dmc1;
488         }
489
490         if (policy->cpu != 0) {
491                 ret = -EINVAL;
492                 goto out_dmc1;
493         }
494
495         /*
496          * check_mem_type : This driver only support LPDDR & LPDDR2.
497          * other memory type is not supported.
498          */
499         mem_type = check_mem_type(S5P_VA_DMC0);
500
501         if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
502                 printk(KERN_ERR "CPUFreq doesn't support this memory type\n");
503                 ret = -EINVAL;
504                 goto out_dmc1;
505         }
506
507         /* Find current refresh counter and frequency each DMC */
508         s5pv210_dram_conf[0].refresh = (__raw_readl(S5P_VA_DMC0 + 0x30) * 1000);
509         s5pv210_dram_conf[0].freq = clk_get_rate(dmc0_clk);
510
511         s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000);
512         s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
513
514         return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
515
516 out_dmc1:
517         clk_put(dmc0_clk);
518 out_dmc0:
519         clk_put(cpu_clk);
520         return ret;
521 }
522
523 static int s5pv210_cpufreq_notifier_event(struct notifier_block *this,
524                                           unsigned long event, void *ptr)
525 {
526         int ret;
527
528         switch (event) {
529         case PM_SUSPEND_PREPARE:
530                 ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
531                 if (ret < 0)
532                         return NOTIFY_BAD;
533
534                 /* Disable updation of cpu frequency */
535                 no_cpufreq_access = true;
536                 return NOTIFY_OK;
537         case PM_POST_RESTORE:
538         case PM_POST_SUSPEND:
539                 /* Enable updation of cpu frequency */
540                 no_cpufreq_access = false;
541                 cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
542
543                 return NOTIFY_OK;
544         }
545
546         return NOTIFY_DONE;
547 }
548
549 static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
550                                                  unsigned long event, void *ptr)
551 {
552         int ret;
553
554         ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
555         if (ret < 0)
556                 return NOTIFY_BAD;
557
558         no_cpufreq_access = true;
559         return NOTIFY_DONE;
560 }
561
562 static struct cpufreq_driver s5pv210_driver = {
563         .flags          = CPUFREQ_STICKY,
564         .verify         = cpufreq_generic_frequency_table_verify,
565         .target_index   = s5pv210_target,
566         .get            = s5pv210_getspeed,
567         .init           = s5pv210_cpu_init,
568         .name           = "s5pv210",
569 #ifdef CONFIG_PM
570         .suspend        = s5pv210_cpufreq_suspend,
571         .resume         = s5pv210_cpufreq_resume,
572 #endif
573 };
574
575 static struct notifier_block s5pv210_cpufreq_notifier = {
576         .notifier_call = s5pv210_cpufreq_notifier_event,
577 };
578
579 static struct notifier_block s5pv210_cpufreq_reboot_notifier = {
580         .notifier_call = s5pv210_cpufreq_reboot_notifier_event,
581 };
582
583 static int __init s5pv210_cpufreq_init(void)
584 {
585         arm_regulator = regulator_get(NULL, "vddarm");
586         if (IS_ERR(arm_regulator)) {
587                 pr_err("failed to get regulator vddarm");
588                 return PTR_ERR(arm_regulator);
589         }
590
591         int_regulator = regulator_get(NULL, "vddint");
592         if (IS_ERR(int_regulator)) {
593                 pr_err("failed to get regulator vddint");
594                 regulator_put(arm_regulator);
595                 return PTR_ERR(int_regulator);
596         }
597
598         register_pm_notifier(&s5pv210_cpufreq_notifier);
599         register_reboot_notifier(&s5pv210_cpufreq_reboot_notifier);
600
601         return cpufreq_register_driver(&s5pv210_driver);
602 }
603
604 late_initcall(s5pv210_cpufreq_init);