aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq
diff options
context:
space:
mode:
authorMyungJoo Ham <myungjoo.ham@samsung.com>2011-07-13 21:33:55 -0400
committerMyungJoo Ham <myungjoo.ham@samsung.com>2011-12-20 00:08:08 -0500
commit7b4050381127ae11fcfc74a106d715a5fbbf888a (patch)
tree9f3b90d254776e92bf69a1be658198ad34ac7651 /drivers/devfreq
parent390f998509bf049019df0b078c0a6606e0d57fb4 (diff)
PM/Devfreq: Add Exynos4-bus device DVFS driver for Exynos4210/4212/4412.
Exynos4-bus device devfreq driver add DVFS capability for Exynos4210/4212/4412-Bus (memory). The driver monitors PPMU counters of memory controllers and adjusts operating frequencies and voltages with OPP. For Exynos4210, vdd_int is controlled. For exynos4412/4212, vdd_mif and vdd_int are controlled. Dependency (CONFIG_EXYNOS_ASV): Exynos4 ASV driver has been posted in the mailing list; however, it si not yet upstreamed. Although the current revision of Exynos4 ASV patch does not contain "CONFIG_EXYNOS_ASV", we have added the symbol to hide the dependent from compilers for now. As soon as Exynos4 ASV drivers are merged, the #ifdef statement will be removed or the name will be changed. However, enabling ASV is essential in most Exynos4 chips to reduce the power consumption of Exynos4210 because without ASV, this Devfreq driver assumes the worst case scenario, which consumes more power. Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> --- Changes from v1 - Support 4212 and 4412 as well as 4210.
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/Kconfig13
-rw-r--r--drivers/devfreq/Makefile3
-rw-r--r--drivers/devfreq/exynos4_bus.c1135
3 files changed, 1151 insertions, 0 deletions
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 8f0491037080..464fa2147dfb 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -65,4 +65,17 @@ config DEVFREQ_GOV_USERSPACE
65 65
66comment "DEVFREQ Drivers" 66comment "DEVFREQ Drivers"
67 67
68config ARM_EXYNOS4_BUS_DEVFREQ
69 bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
70 depends on CPU_EXYNOS4210 || CPU_EXYNOS4212 || CPU_EXYNOS4412
71 select ARCH_HAS_OPP
72 select DEVFREQ_GOV_SIMPLE_ONDEMAND
73 help
74 This adds the DEVFREQ driver for Exynos4210 memory bus (vdd_int)
75 and Exynos4212/4412 memory interface and bus (vdd_mif + vdd_int).
76 It reads PPMU counters of memory controllers and adjusts
77 the operating frequencies and voltages with OPP support.
78 To operate with optimal voltages, ASV support is required
79 (CONFIG_EXYNOS_ASV).
80
68endif # PM_DEVFREQ 81endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 4564a89e970a..8c464234f7e7 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -3,3 +3,6 @@ obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o
3obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o 3obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o
4obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o 4obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
5obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o 5obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
6
7# DEVFREQ Drivers
8obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o
diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c
new file mode 100644
index 000000000000..6460577d6701
--- /dev/null
+++ b/drivers/devfreq/exynos4_bus.c
@@ -0,0 +1,1135 @@
1/* drivers/devfreq/exynos4210_memorybus.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 * MyungJoo Ham <myungjoo.ham@samsung.com>
6 *
7 * EXYNOS4 - Memory/Bus clock frequency scaling support in DEVFREQ framework
8 * This version supports EXYNOS4210 only. This changes bus frequencies
9 * and vddint voltages. Exynos4412/4212 should be able to be supported
10 * with minor modifications.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 */
17
18#include <linux/io.h>
19#include <linux/slab.h>
20#include <linux/mutex.h>
21#include <linux/suspend.h>
22#include <linux/opp.h>
23#include <linux/devfreq.h>
24#include <linux/platform_device.h>
25#include <linux/regulator/consumer.h>
26#include <linux/module.h>
27
28/* Exynos4 ASV has been in the mailing list, but not upstreamed, yet. */
29#ifdef CONFIG_EXYNOS_ASV
30extern unsigned int exynos_result_of_asv;
31#endif
32
33#include <mach/regs-clock.h>
34
35#include <plat/map-s5p.h>
36
37#define MAX_SAFEVOLT 1200000 /* 1.2V */
38
39enum exynos4_busf_type {
40 TYPE_BUSF_EXYNOS4210,
41 TYPE_BUSF_EXYNOS4x12,
42};
43
44/* Assume that the bus is saturated if the utilization is 40% */
45#define BUS_SATURATION_RATIO 40
46
47enum ppmu_counter {
48 PPMU_PMNCNT0 = 0,
49 PPMU_PMCCNT1,
50 PPMU_PMNCNT2,
51 PPMU_PMNCNT3,
52 PPMU_PMNCNT_MAX,
53};
54struct exynos4_ppmu {
55 void __iomem *hw_base;
56 unsigned int ccnt;
57 unsigned int event;
58 unsigned int count[PPMU_PMNCNT_MAX];
59 bool ccnt_overflow;
60 bool count_overflow[PPMU_PMNCNT_MAX];
61};
62
63enum busclk_level_idx {
64 LV_0 = 0,
65 LV_1,
66 LV_2,
67 LV_3,
68 LV_4,
69 _LV_END
70};
71#define EX4210_LV_MAX LV_2
72#define EX4x12_LV_MAX LV_4
73#define EX4210_LV_NUM (LV_2 + 1)
74#define EX4x12_LV_NUM (LV_4 + 1)
75
76struct busfreq_data {
77 enum exynos4_busf_type type;
78 struct device *dev;
79 struct devfreq *devfreq;
80 bool disabled;
81 struct regulator *vdd_int;
82 struct regulator *vdd_mif; /* Exynos4412/4212 only */
83 struct opp *curr_opp;
84 struct exynos4_ppmu dmc[2];
85
86 struct notifier_block pm_notifier;
87 struct mutex lock;
88
89 /* Dividers calculated at boot/probe-time */
90 unsigned int dmc_divtable[_LV_END]; /* DMC0 */
91 unsigned int top_divtable[_LV_END];
92};
93
94struct bus_opp_table {
95 unsigned int idx;
96 unsigned long clk;
97 unsigned long volt;
98};
99
100/* 4210 controls clock of mif and voltage of int */
101static struct bus_opp_table exynos4210_busclk_table[] = {
102 {LV_0, 400000, 1150000},
103 {LV_1, 267000, 1050000},
104 {LV_2, 133000, 1025000},
105 {0, 0, 0},
106};
107
108/*
109 * MIF is the main control knob clock for exynox4x12 MIF/INT
110 * clock and voltage of both mif/int are controlled.
111 */
112static struct bus_opp_table exynos4x12_mifclk_table[] = {
113 {LV_0, 400000, 1100000},
114 {LV_1, 267000, 1000000},
115 {LV_2, 160000, 950000},
116 {LV_3, 133000, 950000},
117 {LV_4, 100000, 950000},
118 {0, 0, 0},
119};
120
121/*
122 * INT is not the control knob of 4x12. LV_x is not meant to represent
123 * the current performance. (MIF does)
124 */
125static struct bus_opp_table exynos4x12_intclk_table[] = {
126 {LV_0, 200000, 1000000},
127 {LV_1, 160000, 950000},
128 {LV_2, 133000, 925000},
129 {LV_3, 100000, 900000},
130 {0, 0, 0},
131};
132
133/* TODO: asv volt definitions are "__initdata"? */
134/* Some chips have different operating voltages */
135static unsigned int exynos4210_asv_volt[][EX4210_LV_NUM] = {
136 {1150000, 1050000, 1050000},
137 {1125000, 1025000, 1025000},
138 {1100000, 1000000, 1000000},
139 {1075000, 975000, 975000},
140 {1050000, 950000, 950000},
141};
142
143static unsigned int exynos4x12_mif_step_50[][EX4x12_LV_NUM] = {
144 /* 400 267 160 133 100 */
145 {1050000, 950000, 900000, 900000, 900000}, /* ASV0 */
146 {1050000, 950000, 900000, 900000, 900000}, /* ASV1 */
147 {1050000, 950000, 900000, 900000, 900000}, /* ASV2 */
148 {1050000, 900000, 900000, 900000, 900000}, /* ASV3 */
149 {1050000, 900000, 900000, 900000, 850000}, /* ASV4 */
150 {1050000, 900000, 900000, 850000, 850000}, /* ASV5 */
151 {1050000, 900000, 850000, 850000, 850000}, /* ASV6 */
152 {1050000, 900000, 850000, 850000, 850000}, /* ASV7 */
153 {1050000, 900000, 850000, 850000, 850000}, /* ASV8 */
154};
155
156static unsigned int exynos4x12_int_volt[][EX4x12_LV_NUM] = {
157 /* 200 160 133 100 */
158 {1000000, 950000, 925000, 900000}, /* ASV0 */
159 {975000, 925000, 925000, 900000}, /* ASV1 */
160 {950000, 925000, 900000, 875000}, /* ASV2 */
161 {950000, 900000, 900000, 875000}, /* ASV3 */
162 {925000, 875000, 875000, 875000}, /* ASV4 */
163 {900000, 850000, 850000, 850000}, /* ASV5 */
164 {900000, 850000, 850000, 850000}, /* ASV6 */
165 {900000, 850000, 850000, 850000}, /* ASV7 */
166 {900000, 850000, 850000, 850000}, /* ASV8 */
167};
168
169/*** Clock Divider Data for Exynos4210 ***/
170static unsigned int exynos4210_clkdiv_dmc0[][8] = {
171 /*
172 * Clock divider value for following
173 * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
174 * DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
175 */
176
177 /* DMC L0: 400MHz */
178 { 3, 1, 1, 1, 1, 1, 3, 1 },
179 /* DMC L1: 266.7MHz */
180 { 4, 1, 1, 2, 1, 1, 3, 1 },
181 /* DMC L2: 133MHz */
182 { 5, 1, 1, 5, 1, 1, 3, 1 },
183};
184static unsigned int exynos4210_clkdiv_top[][5] = {
185 /*
186 * Clock divider value for following
187 * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
188 */
189 /* ACLK200 L0: 200MHz */
190 { 3, 7, 4, 5, 1 },
191 /* ACLK200 L1: 160MHz */
192 { 4, 7, 5, 6, 1 },
193 /* ACLK200 L2: 133MHz */
194 { 5, 7, 7, 7, 1 },
195};
196static unsigned int exynos4210_clkdiv_lr_bus[][2] = {
197 /*
198 * Clock divider value for following
199 * { DIVGDL/R, DIVGPL/R }
200 */
201 /* ACLK_GDL/R L1: 200MHz */
202 { 3, 1 },
203 /* ACLK_GDL/R L2: 160MHz */
204 { 4, 1 },
205 /* ACLK_GDL/R L3: 133MHz */
206 { 5, 1 },
207};
208
209/*** Clock Divider Data for Exynos4212/4412 ***/
210static unsigned int exynos4x12_clkdiv_dmc0[][6] = {
211 /*
212 * Clock divider value for following
213 * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
214 * DIVDMCP}
215 */
216
217 /* DMC L0: 400MHz */
218 {3, 1, 1, 1, 1, 1},
219 /* DMC L1: 266.7MHz */
220 {4, 1, 1, 2, 1, 1},
221 /* DMC L2: 160MHz */
222 {5, 1, 1, 4, 1, 1},
223 /* DMC L3: 133MHz */
224 {5, 1, 1, 5, 1, 1},
225 /* DMC L4: 100MHz */
226 {7, 1, 1, 7, 1, 1},
227};
228static unsigned int exynos4x12_clkdiv_dmc1[][6] = {
229 /*
230 * Clock divider value for following
231 * { G2DACP, DIVC2C, DIVC2C_ACLK }
232 */
233
234 /* DMC L0: 400MHz */
235 {3, 1, 1},
236 /* DMC L1: 266.7MHz */
237 {4, 2, 1},
238 /* DMC L2: 160MHz */
239 {5, 4, 1},
240 /* DMC L3: 133MHz */
241 {5, 5, 1},
242 /* DMC L4: 100MHz */
243 {7, 7, 1},
244};
245static unsigned int exynos4x12_clkdiv_top[][5] = {
246 /*
247 * Clock divider value for following
248 * { DIVACLK266_GPS, DIVACLK100, DIVACLK160,
249 DIVACLK133, DIVONENAND }
250 */
251
252 /* ACLK_GDL/R L0: 200MHz */
253 {2, 7, 4, 5, 1},
254 /* ACLK_GDL/R L1: 200MHz */
255 {2, 7, 4, 5, 1},
256 /* ACLK_GDL/R L2: 160MHz */
257 {4, 7, 5, 7, 1},
258 /* ACLK_GDL/R L3: 133MHz */
259 {4, 7, 5, 7, 1},
260 /* ACLK_GDL/R L4: 100MHz */
261 {7, 7, 7, 7, 1},
262};
263static unsigned int exynos4x12_clkdiv_lr_bus[][2] = {
264 /*
265 * Clock divider value for following
266 * { DIVGDL/R, DIVGPL/R }
267 */
268
269 /* ACLK_GDL/R L0: 200MHz */
270 {3, 1},
271 /* ACLK_GDL/R L1: 200MHz */
272 {3, 1},
273 /* ACLK_GDL/R L2: 160MHz */
274 {4, 1},
275 /* ACLK_GDL/R L3: 133MHz */
276 {5, 1},
277 /* ACLK_GDL/R L4: 100MHz */
278 {7, 1},
279};
280static unsigned int exynos4x12_clkdiv_sclkip[][3] = {
281 /*
282 * Clock divider value for following
283 * { DIVMFC, DIVJPEG, DIVFIMC0~3}
284 */
285
286 /* SCLK_MFC: 200MHz */
287 {3, 3, 4},
288 /* SCLK_MFC: 200MHz */
289 {3, 3, 4},
290 /* SCLK_MFC: 160MHz */
291 {4, 4, 5},
292 /* SCLK_MFC: 133MHz */
293 {5, 5, 5},
294 /* SCLK_MFC: 100MHz */
295 {7, 7, 7},
296};
297
298
299static int exynos4210_set_busclk(struct busfreq_data *data, struct opp *opp)
300{
301 unsigned int index;
302 unsigned int tmp;
303
304 for (index = LV_0; index < EX4210_LV_NUM; index++)
305 if (opp_get_freq(opp) == exynos4210_busclk_table[index].clk)
306 break;
307
308 if (index == EX4210_LV_NUM)
309 return -EINVAL;
310
311 /* Change Divider - DMC0 */
312 tmp = data->dmc_divtable[index];
313
314 __raw_writel(tmp, S5P_CLKDIV_DMC0);
315
316 do {
317 tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
318 } while (tmp & 0x11111111);
319
320 /* Change Divider - TOP */
321 tmp = data->top_divtable[index];
322
323 __raw_writel(tmp, S5P_CLKDIV_TOP);
324
325 do {
326 tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
327 } while (tmp & 0x11111);
328
329 /* Change Divider - LEFTBUS */
330 tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
331
332 tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
333
334 tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
335 S5P_CLKDIV_BUS_GDLR_SHIFT) |
336 (exynos4210_clkdiv_lr_bus[index][1] <<
337 S5P_CLKDIV_BUS_GPLR_SHIFT));
338
339 __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
340
341 do {
342 tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
343 } while (tmp & 0x11);
344
345 /* Change Divider - RIGHTBUS */
346 tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
347
348 tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
349
350 tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
351 S5P_CLKDIV_BUS_GDLR_SHIFT) |
352 (exynos4210_clkdiv_lr_bus[index][1] <<
353 S5P_CLKDIV_BUS_GPLR_SHIFT));
354
355 __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
356
357 do {
358 tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
359 } while (tmp & 0x11);
360
361 return 0;
362}
363
364static int exynos4x12_set_busclk(struct busfreq_data *data, struct opp *opp)
365{
366 unsigned int index;
367 unsigned int tmp;
368
369 for (index = LV_0; index < EX4x12_LV_NUM; index++)
370 if (opp_get_freq(opp) == exynos4x12_mifclk_table[index].clk)
371 break;
372
373 if (index == EX4x12_LV_NUM)
374 return -EINVAL;
375
376 /* Change Divider - DMC0 */
377 tmp = data->dmc_divtable[index];
378
379 __raw_writel(tmp, S5P_CLKDIV_DMC0);
380
381 do {
382 tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
383 } while (tmp & 0x11111111);
384
385 /* Change Divider - DMC1 */
386 tmp = __raw_readl(S5P_CLKDIV_DMC1);
387
388 tmp &= ~(S5P_CLKDIV_DMC1_G2D_ACP_MASK |
389 S5P_CLKDIV_DMC1_C2C_MASK |
390 S5P_CLKDIV_DMC1_C2CACLK_MASK);
391
392 tmp |= ((exynos4x12_clkdiv_dmc1[index][0] <<
393 S5P_CLKDIV_DMC1_G2D_ACP_SHIFT) |
394 (exynos4x12_clkdiv_dmc1[index][1] <<
395 S5P_CLKDIV_DMC1_C2C_SHIFT) |
396 (exynos4x12_clkdiv_dmc1[index][2] <<
397 S5P_CLKDIV_DMC1_C2CACLK_SHIFT));
398
399 __raw_writel(tmp, S5P_CLKDIV_DMC1);
400
401 do {
402 tmp = __raw_readl(S5P_CLKDIV_STAT_DMC1);
403 } while (tmp & 0x111111);
404
405 /* Change Divider - TOP */
406 tmp = __raw_readl(S5P_CLKDIV_TOP);
407
408 tmp &= ~(S5P_CLKDIV_TOP_ACLK266_GPS_MASK |
409 S5P_CLKDIV_TOP_ACLK100_MASK |
410 S5P_CLKDIV_TOP_ACLK160_MASK |
411 S5P_CLKDIV_TOP_ACLK133_MASK |
412 S5P_CLKDIV_TOP_ONENAND_MASK);
413
414 tmp |= ((exynos4x12_clkdiv_top[index][0] <<
415 S5P_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
416 (exynos4x12_clkdiv_top[index][1] <<
417 S5P_CLKDIV_TOP_ACLK100_SHIFT) |
418 (exynos4x12_clkdiv_top[index][2] <<
419 S5P_CLKDIV_TOP_ACLK160_SHIFT) |
420 (exynos4x12_clkdiv_top[index][3] <<
421 S5P_CLKDIV_TOP_ACLK133_SHIFT) |
422 (exynos4x12_clkdiv_top[index][4] <<
423 S5P_CLKDIV_TOP_ONENAND_SHIFT));
424
425 __raw_writel(tmp, S5P_CLKDIV_TOP);
426
427 do {
428 tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
429 } while (tmp & 0x11111);
430
431 /* Change Divider - LEFTBUS */
432 tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
433
434 tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
435
436 tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
437 S5P_CLKDIV_BUS_GDLR_SHIFT) |
438 (exynos4x12_clkdiv_lr_bus[index][1] <<
439 S5P_CLKDIV_BUS_GPLR_SHIFT));
440
441 __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
442
443 do {
444 tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
445 } while (tmp & 0x11);
446
447 /* Change Divider - RIGHTBUS */
448 tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
449
450 tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
451
452 tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
453 S5P_CLKDIV_BUS_GDLR_SHIFT) |
454 (exynos4x12_clkdiv_lr_bus[index][1] <<
455 S5P_CLKDIV_BUS_GPLR_SHIFT));
456
457 __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
458
459 do {
460 tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
461 } while (tmp & 0x11);
462
463 /* Change Divider - MFC */
464 tmp = __raw_readl(S5P_CLKDIV_MFC);
465
466 tmp &= ~(S5P_CLKDIV_MFC_MASK);
467
468 tmp |= ((exynos4x12_clkdiv_sclkip[index][0] <<
469 S5P_CLKDIV_MFC_SHIFT));
470
471 __raw_writel(tmp, S5P_CLKDIV_MFC);
472
473 do {
474 tmp = __raw_readl(S5P_CLKDIV_STAT_MFC);
475 } while (tmp & 0x1);
476
477 /* Change Divider - JPEG */
478 tmp = __raw_readl(S5P_CLKDIV_CAM1);
479
480 tmp &= ~(S5P_CLKDIV_CAM1_JPEG_MASK);
481
482 tmp |= ((exynos4x12_clkdiv_sclkip[index][1] <<
483 S5P_CLKDIV_CAM1_JPEG_SHIFT));
484
485 __raw_writel(tmp, S5P_CLKDIV_CAM1);
486
487 do {
488 tmp = __raw_readl(S5P_CLKDIV_STAT_CAM1);
489 } while (tmp & 0x1);
490
491 /* Change Divider - FIMC0~3 */
492 tmp = __raw_readl(S5P_CLKDIV_CAM);
493
494 tmp &= ~(S5P_CLKDIV_CAM_FIMC0_MASK | S5P_CLKDIV_CAM_FIMC1_MASK |
495 S5P_CLKDIV_CAM_FIMC2_MASK | S5P_CLKDIV_CAM_FIMC3_MASK);
496
497 tmp |= ((exynos4x12_clkdiv_sclkip[index][2] <<
498 S5P_CLKDIV_CAM_FIMC0_SHIFT) |
499 (exynos4x12_clkdiv_sclkip[index][2] <<
500 S5P_CLKDIV_CAM_FIMC1_SHIFT) |
501 (exynos4x12_clkdiv_sclkip[index][2] <<
502 S5P_CLKDIV_CAM_FIMC2_SHIFT) |
503 (exynos4x12_clkdiv_sclkip[index][2] <<
504 S5P_CLKDIV_CAM_FIMC3_SHIFT));
505
506 __raw_writel(tmp, S5P_CLKDIV_CAM);
507
508 do {
509 tmp = __raw_readl(S5P_CLKDIV_STAT_CAM1);
510 } while (tmp & 0x1111);
511
512 return 0;
513}
514
515
516static void busfreq_mon_reset(struct busfreq_data *data)
517{
518 unsigned int i;
519
520 for (i = 0; i < 2; i++) {
521 void __iomem *ppmu_base = data->dmc[i].hw_base;
522
523 /* Reset PPMU */
524 __raw_writel(0x8000000f, ppmu_base + 0xf010);
525 __raw_writel(0x8000000f, ppmu_base + 0xf050);
526 __raw_writel(0x6, ppmu_base + 0xf000);
527 __raw_writel(0x0, ppmu_base + 0xf100);
528
529 /* Set PPMU Event */
530 data->dmc[i].event = 0x6;
531 __raw_writel(((data->dmc[i].event << 12) | 0x1),
532 ppmu_base + 0xfc);
533
534 /* Start PPMU */
535 __raw_writel(0x1, ppmu_base + 0xf000);
536 }
537}
538
539static void exynos4_read_ppmu(struct busfreq_data *data)
540{
541 int i, j;
542
543 for (i = 0; i < 2; i++) {
544 void __iomem *ppmu_base = data->dmc[i].hw_base;
545 u32 overflow;
546
547 /* Stop PPMU */
548 __raw_writel(0x0, ppmu_base + 0xf000);
549
550 /* Update local data from PPMU */
551 overflow = __raw_readl(ppmu_base + 0xf050);
552
553 data->dmc[i].ccnt = __raw_readl(ppmu_base + 0xf100);
554 data->dmc[i].ccnt_overflow = overflow & (1 << 31);
555
556 for (j = 0; j < PPMU_PMNCNT_MAX; j++) {
557 data->dmc[i].count[j] = __raw_readl(
558 ppmu_base + (0xf110 + (0x10 * j)));
559 data->dmc[i].count_overflow[j] = overflow & (1 << j);
560 }
561 }
562
563 busfreq_mon_reset(data);
564}
565
566static int exynos4x12_get_intspec(unsigned long mifclk)
567{
568 int i = 0;
569
570 while (exynos4x12_intclk_table[i].clk) {
571 if (exynos4x12_intclk_table[i].clk <= mifclk)
572 return i;
573 i++;
574 }
575
576 return -EINVAL;
577}
578
579static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp,
580 struct opp *oldopp)
581{
582 int err = 0, tmp;
583 unsigned long volt = opp_get_voltage(opp);
584
585 switch (data->type) {
586 case TYPE_BUSF_EXYNOS4210:
587 /* OPP represents DMC clock + INT voltage */
588 err = regulator_set_voltage(data->vdd_int, volt,
589 MAX_SAFEVOLT);
590 break;
591 case TYPE_BUSF_EXYNOS4x12:
592 /* OPP represents MIF clock + MIF voltage */
593 err = regulator_set_voltage(data->vdd_mif, volt,
594 MAX_SAFEVOLT);
595 if (err)
596 break;
597
598 tmp = exynos4x12_get_intspec(opp_get_freq(opp));
599 if (tmp < 0) {
600 err = tmp;
601 regulator_set_voltage(data->vdd_mif,
602 opp_get_voltage(oldopp),
603 MAX_SAFEVOLT);
604 break;
605 }
606 err = regulator_set_voltage(data->vdd_int,
607 exynos4x12_intclk_table[tmp].volt,
608 MAX_SAFEVOLT);
609 /* Try to recover */
610 if (err)
611 regulator_set_voltage(data->vdd_mif,
612 opp_get_voltage(oldopp),
613 MAX_SAFEVOLT);
614 break;
615 default:
616 err = -EINVAL;
617 }
618
619 return err;
620}
621
622static int exynos4_bus_target(struct device *dev, unsigned long *_freq)
623{
624 int err = 0;
625 struct platform_device *pdev = container_of(dev, struct platform_device,
626 dev);
627 struct busfreq_data *data = platform_get_drvdata(pdev);
628 struct opp *opp = devfreq_recommended_opp(dev, _freq);
629 unsigned long old_freq = opp_get_freq(data->curr_opp);
630 unsigned long freq = opp_get_freq(opp);
631
632 if (old_freq == freq)
633 return 0;
634
635 dev_dbg(dev, "targetting %lukHz %luuV\n", freq, opp_get_voltage(opp));
636
637 mutex_lock(&data->lock);
638
639 if (data->disabled)
640 goto out;
641
642 if (old_freq < freq)
643 err = exynos4_bus_setvolt(data, opp, data->curr_opp);
644 if (err)
645 goto out;
646
647 if (old_freq != freq) {
648 switch (data->type) {
649 case TYPE_BUSF_EXYNOS4210:
650 err = exynos4210_set_busclk(data, opp);
651 break;
652 case TYPE_BUSF_EXYNOS4x12:
653 err = exynos4x12_set_busclk(data, opp);
654 break;
655 default:
656 err = -EINVAL;
657 }
658 }
659 if (err)
660 goto out;
661
662 if (old_freq > freq)
663 err = exynos4_bus_setvolt(data, opp, data->curr_opp);
664 if (err)
665 goto out;
666
667 data->curr_opp = opp;
668out:
669 mutex_unlock(&data->lock);
670 return err;
671}
672
673static int exynos4_get_busier_dmc(struct busfreq_data *data)
674{
675 u64 p0 = data->dmc[0].count[0];
676 u64 p1 = data->dmc[1].count[0];
677
678 p0 *= data->dmc[1].ccnt;
679 p1 *= data->dmc[0].ccnt;
680
681 if (data->dmc[1].ccnt == 0)
682 return 0;
683
684 if (p0 > p1)
685 return 0;
686 return 1;
687}
688
689static int exynos4_bus_get_dev_status(struct device *dev,
690 struct devfreq_dev_status *stat)
691{
692 struct platform_device *pdev = container_of(dev, struct platform_device,
693 dev);
694 struct busfreq_data *data = platform_get_drvdata(pdev);
695 int busier_dmc;
696 int cycles_x2 = 2; /* 2 x cycles */
697 void __iomem *addr;
698 u32 timing;
699 u32 memctrl;
700
701 exynos4_read_ppmu(data);
702 busier_dmc = exynos4_get_busier_dmc(data);
703 stat->current_frequency = opp_get_freq(data->curr_opp);
704
705 if (busier_dmc)
706 addr = S5P_VA_DMC1;
707 else
708 addr = S5P_VA_DMC0;
709
710 memctrl = __raw_readl(addr + 0x04); /* one of DDR2/3/LPDDR2 */
711 timing = __raw_readl(addr + 0x38); /* CL or WL/RL values */
712
713 switch ((memctrl >> 8) & 0xf) {
714 case 0x4: /* DDR2 */
715 cycles_x2 = ((timing >> 16) & 0xf) * 2;
716 break;
717 case 0x5: /* LPDDR2 */
718 case 0x6: /* DDR3 */
719 cycles_x2 = ((timing >> 8) & 0xf) + ((timing >> 0) & 0xf);
720 break;
721 default:
722 pr_err("%s: Unknown Memory Type(%d).\n", __func__,
723 (memctrl >> 8) & 0xf);
724 return -EINVAL;
725 }
726
727 /* Number of cycles spent on memory access */
728 stat->busy_time = data->dmc[busier_dmc].count[0] / 2 * (cycles_x2 + 2);
729 stat->busy_time *= 100 / BUS_SATURATION_RATIO;
730 stat->total_time = data->dmc[busier_dmc].ccnt;
731
732 /* If the counters have overflown, retry */
733 if (data->dmc[busier_dmc].ccnt_overflow ||
734 data->dmc[busier_dmc].count_overflow[0])
735 return -EAGAIN;
736
737 return 0;
738}
739
740static void exynos4_bus_exit(struct device *dev)
741{
742 struct platform_device *pdev = container_of(dev, struct platform_device,
743 dev);
744 struct busfreq_data *data = platform_get_drvdata(pdev);
745
746 devfreq_unregister_opp_notifier(dev, data->devfreq);
747}
748
749static struct devfreq_dev_profile exynos4_devfreq_profile = {
750 .initial_freq = 400000,
751 .polling_ms = 50,
752 .target = exynos4_bus_target,
753 .get_dev_status = exynos4_bus_get_dev_status,
754 .exit = exynos4_bus_exit,
755};
756
757static int exynos4210_init_tables(struct busfreq_data *data)
758{
759 u32 tmp;
760 int mgrp;
761 int i, err = 0;
762
763 tmp = __raw_readl(S5P_CLKDIV_DMC0);
764 for (i = LV_0; i < EX4210_LV_NUM; i++) {
765 tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK |
766 S5P_CLKDIV_DMC0_ACPPCLK_MASK |
767 S5P_CLKDIV_DMC0_DPHY_MASK |
768 S5P_CLKDIV_DMC0_DMC_MASK |
769 S5P_CLKDIV_DMC0_DMCD_MASK |
770 S5P_CLKDIV_DMC0_DMCP_MASK |
771 S5P_CLKDIV_DMC0_COPY2_MASK |
772 S5P_CLKDIV_DMC0_CORETI_MASK);
773
774 tmp |= ((exynos4210_clkdiv_dmc0[i][0] <<
775 S5P_CLKDIV_DMC0_ACP_SHIFT) |
776 (exynos4210_clkdiv_dmc0[i][1] <<
777 S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
778 (exynos4210_clkdiv_dmc0[i][2] <<
779 S5P_CLKDIV_DMC0_DPHY_SHIFT) |
780 (exynos4210_clkdiv_dmc0[i][3] <<
781 S5P_CLKDIV_DMC0_DMC_SHIFT) |
782 (exynos4210_clkdiv_dmc0[i][4] <<
783 S5P_CLKDIV_DMC0_DMCD_SHIFT) |
784 (exynos4210_clkdiv_dmc0[i][5] <<
785 S5P_CLKDIV_DMC0_DMCP_SHIFT) |
786 (exynos4210_clkdiv_dmc0[i][6] <<
787 S5P_CLKDIV_DMC0_COPY2_SHIFT) |
788 (exynos4210_clkdiv_dmc0[i][7] <<
789 S5P_CLKDIV_DMC0_CORETI_SHIFT));
790
791 data->dmc_divtable[i] = tmp;
792 }
793
794 tmp = __raw_readl(S5P_CLKDIV_TOP);
795 for (i = LV_0; i < EX4210_LV_NUM; i++) {
796 tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK |
797 S5P_CLKDIV_TOP_ACLK100_MASK |
798 S5P_CLKDIV_TOP_ACLK160_MASK |
799 S5P_CLKDIV_TOP_ACLK133_MASK |
800 S5P_CLKDIV_TOP_ONENAND_MASK);
801
802 tmp |= ((exynos4210_clkdiv_top[i][0] <<
803 S5P_CLKDIV_TOP_ACLK200_SHIFT) |
804 (exynos4210_clkdiv_top[i][1] <<
805 S5P_CLKDIV_TOP_ACLK100_SHIFT) |
806 (exynos4210_clkdiv_top[i][2] <<
807 S5P_CLKDIV_TOP_ACLK160_SHIFT) |
808 (exynos4210_clkdiv_top[i][3] <<
809 S5P_CLKDIV_TOP_ACLK133_SHIFT) |
810 (exynos4210_clkdiv_top[i][4] <<
811 S5P_CLKDIV_TOP_ONENAND_SHIFT));
812
813 data->top_divtable[i] = tmp;
814 }
815
816#ifdef CONFIG_EXYNOS_ASV
817 tmp = exynos4_result_of_asv;
818#else
819 tmp = 0; /* Max voltages for the reliability of the unknown */
820#endif
821
822 pr_debug("ASV Group of Exynos4 is %d\n", tmp);
823 /* Use merged grouping for voltage */
824 switch (tmp) {
825 case 0:
826 mgrp = 0;
827 break;
828 case 1:
829 case 2:
830 mgrp = 1;
831 break;
832 case 3:
833 case 4:
834 mgrp = 2;
835 break;
836 case 5:
837 case 6:
838 mgrp = 3;
839 break;
840 case 7:
841 mgrp = 4;
842 break;
843 default:
844 pr_warn("Unknown ASV Group. Use max voltage.\n");
845 mgrp = 0;
846 }
847
848 for (i = LV_0; i < EX4210_LV_NUM; i++)
849 exynos4210_busclk_table[i].volt = exynos4210_asv_volt[mgrp][i];
850
851 for (i = LV_0; i < EX4210_LV_NUM; i++) {
852 err = opp_add(data->dev, exynos4210_busclk_table[i].clk,
853 exynos4210_busclk_table[i].volt);
854 if (err) {
855 dev_err(data->dev, "Cannot add opp entries.\n");
856 return err;
857 }
858 }
859
860
861 return 0;
862}
863
864static int exynos4x12_init_tables(struct busfreq_data *data)
865{
866 unsigned int i;
867 unsigned int tmp;
868 int ret;
869
870 /* Enable pause function for DREX2 DVFS */
871 tmp = __raw_readl(S5P_DMC_PAUSE_CTRL);
872 tmp |= DMC_PAUSE_ENABLE;
873 __raw_writel(tmp, S5P_DMC_PAUSE_CTRL);
874
875 tmp = __raw_readl(S5P_CLKDIV_DMC0);
876
877 for (i = 0; i < EX4x12_LV_NUM; i++) {
878 tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK |
879 S5P_CLKDIV_DMC0_ACPPCLK_MASK |
880 S5P_CLKDIV_DMC0_DPHY_MASK |
881 S5P_CLKDIV_DMC0_DMC_MASK |
882 S5P_CLKDIV_DMC0_DMCD_MASK |
883 S5P_CLKDIV_DMC0_DMCP_MASK);
884
885 tmp |= ((exynos4x12_clkdiv_dmc0[i][0] <<
886 S5P_CLKDIV_DMC0_ACP_SHIFT) |
887 (exynos4x12_clkdiv_dmc0[i][1] <<
888 S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
889 (exynos4x12_clkdiv_dmc0[i][2] <<
890 S5P_CLKDIV_DMC0_DPHY_SHIFT) |
891 (exynos4x12_clkdiv_dmc0[i][3] <<
892 S5P_CLKDIV_DMC0_DMC_SHIFT) |
893 (exynos4x12_clkdiv_dmc0[i][4] <<
894 S5P_CLKDIV_DMC0_DMCD_SHIFT) |
895 (exynos4x12_clkdiv_dmc0[i][5] <<
896 S5P_CLKDIV_DMC0_DMCP_SHIFT));
897
898 data->dmc_divtable[i] = tmp;
899 }
900
901#ifdef CONFIG_EXYNOS_ASV
902 tmp = exynos4_result_of_asv;
903#else
904 tmp = 0; /* Max voltages for the reliability of the unknown */
905#endif
906
907 if (tmp > 8)
908 tmp = 0;
909 pr_debug("ASV Group of Exynos4x12 is %d\n", tmp);
910
911 for (i = 0; i < EX4x12_LV_NUM; i++) {
912 exynos4x12_mifclk_table[i].volt =
913 exynos4x12_mif_step_50[tmp][i];
914 exynos4x12_intclk_table[i].volt =
915 exynos4x12_int_volt[tmp][i];
916 }
917
918 for (i = 0; i < EX4x12_LV_NUM; i++) {
919 ret = opp_add(data->dev, exynos4x12_mifclk_table[i].clk,
920 exynos4x12_mifclk_table[i].volt);
921 if (ret) {
922 dev_err(data->dev, "Fail to add opp entries.\n");
923 return ret;
924 }
925 }
926
927 return 0;
928}
929
930static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
931 unsigned long event, void *ptr)
932{
933 struct busfreq_data *data = container_of(this, struct busfreq_data,
934 pm_notifier);
935 struct opp *opp;
936 unsigned long maxfreq = ULONG_MAX;
937 int err = 0;
938
939 switch (event) {
940 case PM_SUSPEND_PREPARE:
941 /* Set Fastest and Deactivate DVFS */
942 mutex_lock(&data->lock);
943
944 data->disabled = true;
945
946 opp = opp_find_freq_floor(data->dev, &maxfreq);
947
948 err = exynos4_bus_setvolt(data, opp, data->curr_opp);
949 if (err)
950 goto unlock;
951
952 switch (data->type) {
953 case TYPE_BUSF_EXYNOS4210:
954 err = exynos4210_set_busclk(data, opp);
955 break;
956 case TYPE_BUSF_EXYNOS4x12:
957 err = exynos4x12_set_busclk(data, opp);
958 break;
959 default:
960 err = -EINVAL;
961 }
962 if (err)
963 goto unlock;
964
965 data->curr_opp = opp;
966unlock:
967 mutex_unlock(&data->lock);
968 if (err)
969 return err;
970 return NOTIFY_OK;
971 case PM_POST_RESTORE:
972 case PM_POST_SUSPEND:
973 /* Reactivate */
974 mutex_lock(&data->lock);
975 data->disabled = false;
976 mutex_unlock(&data->lock);
977 return NOTIFY_OK;
978 }
979
980 return NOTIFY_DONE;
981}
982
983static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
984{
985 struct busfreq_data *data;
986 struct opp *opp;
987 struct device *dev = &pdev->dev;
988 int err = 0;
989
990 data = kzalloc(sizeof(struct busfreq_data), GFP_KERNEL);
991 if (data == NULL) {
992 dev_err(dev, "Cannot allocate memory.\n");
993 return -ENOMEM;
994 }
995
996 data->type = pdev->id_entry->driver_data;
997 data->dmc[0].hw_base = S5P_VA_DMC0;
998 data->dmc[1].hw_base = S5P_VA_DMC1;
999 data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event;
1000 data->dev = dev;
1001 mutex_init(&data->lock);
1002
1003 switch (data->type) {
1004 case TYPE_BUSF_EXYNOS4210:
1005 err = exynos4210_init_tables(data);
1006 break;
1007 case TYPE_BUSF_EXYNOS4x12:
1008 err = exynos4x12_init_tables(data);
1009 break;
1010 default:
1011 dev_err(dev, "Cannot determine the device id %d\n", data->type);
1012 err = -EINVAL;
1013 }
1014 if (err)
1015 goto err_regulator;
1016
1017 data->vdd_int = regulator_get(dev, "vdd_int");
1018 if (IS_ERR(data->vdd_int)) {
1019 dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
1020 err = PTR_ERR(data->vdd_int);
1021 goto err_regulator;
1022 }
1023 if (data->type == TYPE_BUSF_EXYNOS4x12) {
1024 data->vdd_mif = regulator_get(dev, "vdd_mif");
1025 if (IS_ERR(data->vdd_mif)) {
1026 dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
1027 err = PTR_ERR(data->vdd_mif);
1028 regulator_put(data->vdd_int);
1029 goto err_regulator;
1030
1031 }
1032 }
1033
1034 opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq);
1035 if (IS_ERR(opp)) {
1036 dev_err(dev, "Invalid initial frequency %lu kHz.\n",
1037 exynos4_devfreq_profile.initial_freq);
1038 err = PTR_ERR(opp);
1039 goto err_opp_add;
1040 }
1041 data->curr_opp = opp;
1042
1043 platform_set_drvdata(pdev, data);
1044
1045 busfreq_mon_reset(data);
1046
1047 data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
1048 &devfreq_simple_ondemand, NULL);
1049 if (IS_ERR(data->devfreq)) {
1050 err = PTR_ERR(data->devfreq);
1051 goto err_opp_add;
1052 }
1053
1054 devfreq_register_opp_notifier(dev, data->devfreq);
1055
1056 err = register_pm_notifier(&data->pm_notifier);
1057 if (err) {
1058 dev_err(dev, "Failed to setup pm notifier\n");
1059 goto err_devfreq_add;
1060 }
1061
1062 return 0;
1063err_devfreq_add:
1064 devfreq_remove_device(data->devfreq);
1065err_opp_add:
1066 if (data->vdd_mif)
1067 regulator_put(data->vdd_mif);
1068 regulator_put(data->vdd_int);
1069err_regulator:
1070 kfree(data);
1071 return err;
1072}
1073
1074static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
1075{
1076 struct busfreq_data *data = platform_get_drvdata(pdev);
1077
1078 unregister_pm_notifier(&data->pm_notifier);
1079 devfreq_remove_device(data->devfreq);
1080 regulator_put(data->vdd_int);
1081 if (data->vdd_mif)
1082 regulator_put(data->vdd_mif);
1083 kfree(data);
1084
1085 return 0;
1086}
1087
1088static int exynos4_busfreq_resume(struct device *dev)
1089{
1090 struct platform_device *pdev = container_of(dev, struct platform_device,
1091 dev);
1092 struct busfreq_data *data = platform_get_drvdata(pdev);
1093
1094 busfreq_mon_reset(data);
1095 return 0;
1096}
1097
1098static const struct dev_pm_ops exynos4_busfreq_pm = {
1099 .resume = exynos4_busfreq_resume,
1100};
1101
1102static const struct platform_device_id exynos4_busfreq_id[] = {
1103 { "exynos4210-busfreq", TYPE_BUSF_EXYNOS4210 },
1104 { "exynos4412-busfreq", TYPE_BUSF_EXYNOS4x12 },
1105 { "exynos4212-busfreq", TYPE_BUSF_EXYNOS4x12 },
1106 { },
1107};
1108
1109static struct platform_driver exynos4_busfreq_driver = {
1110 .probe = exynos4_busfreq_probe,
1111 .remove = __devexit_p(exynos4_busfreq_remove),
1112 .id_table = exynos4_busfreq_id,
1113 .driver = {
1114 .name = "exynos4-busfreq",
1115 .owner = THIS_MODULE,
1116 .pm = &exynos4_busfreq_pm,
1117 },
1118};
1119
1120static int __init exynos4_busfreq_init(void)
1121{
1122 return platform_driver_register(&exynos4_busfreq_driver);
1123}
1124late_initcall(exynos4_busfreq_init);
1125
1126static void __exit exynos4_busfreq_exit(void)
1127{
1128 platform_driver_unregister(&exynos4_busfreq_driver);
1129}
1130module_exit(exynos4_busfreq_exit);
1131
1132MODULE_LICENSE("GPL");
1133MODULE_DESCRIPTION("EXYNOS4 busfreq driver with devfreq framework");
1134MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
1135MODULE_ALIAS("exynos4-busfreq");