blob: d99ef9e805178e31e8518ba188b1f4da9a01fd01 [file] [log] [blame]
MyungJoo Ham7b405032011-07-14 10:33:55 +09001/* 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>
Nishanth Menone4db1c72013-09-19 16:03:52 -050022#include <linux/pm_opp.h>
MyungJoo Ham7b405032011-07-14 10:33:55 +090023#include <linux/devfreq.h>
24#include <linux/platform_device.h>
25#include <linux/regulator/consumer.h>
26#include <linux/module.h>
27
Chanwoo Choiba778b32014-03-21 18:31:43 +010028#include <mach/map.h>
29
30#include "exynos_ppmu.h"
31#include "exynos4_bus.h"
32
MyungJoo Ham7b405032011-07-14 10:33:55 +090033/* Exynos4 ASV has been in the mailing list, but not upstreamed, yet. */
34#ifdef CONFIG_EXYNOS_ASV
35extern unsigned int exynos_result_of_asv;
36#endif
37
MyungJoo Ham7b405032011-07-14 10:33:55 +090038#define MAX_SAFEVOLT 1200000 /* 1.2V */
39
40enum exynos4_busf_type {
41 TYPE_BUSF_EXYNOS4210,
42 TYPE_BUSF_EXYNOS4x12,
43};
44
45/* Assume that the bus is saturated if the utilization is 40% */
46#define BUS_SATURATION_RATIO 40
47
MyungJoo Ham7b405032011-07-14 10:33:55 +090048enum busclk_level_idx {
49 LV_0 = 0,
50 LV_1,
51 LV_2,
52 LV_3,
53 LV_4,
54 _LV_END
55};
Chanwoo Choiba778b32014-03-21 18:31:43 +010056
57enum exynos_ppmu_idx {
58 PPMU_DMC0,
59 PPMU_DMC1,
60 PPMU_END,
61};
62
MyungJoo Ham7b405032011-07-14 10:33:55 +090063#define EX4210_LV_MAX LV_2
64#define EX4x12_LV_MAX LV_4
65#define EX4210_LV_NUM (LV_2 + 1)
66#define EX4x12_LV_NUM (LV_4 + 1)
67
Nishanth Menon8fa938a2013-01-18 19:52:35 +000068/**
69 * struct busfreq_opp_info - opp information for bus
70 * @rate: Frequency in hertz
71 * @volt: Voltage in microvolts corresponding to this OPP
72 */
73struct busfreq_opp_info {
74 unsigned long rate;
75 unsigned long volt;
76};
77
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +010078struct busfreq_ppmu_data {
79 struct exynos_ppmu *ppmu;
80 int ppmu_end;
81};
82
MyungJoo Ham7b405032011-07-14 10:33:55 +090083struct busfreq_data {
84 enum exynos4_busf_type type;
85 struct device *dev;
86 struct devfreq *devfreq;
87 bool disabled;
88 struct regulator *vdd_int;
89 struct regulator *vdd_mif; /* Exynos4412/4212 only */
Nishanth Menon8fa938a2013-01-18 19:52:35 +000090 struct busfreq_opp_info curr_oppinfo;
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +010091 struct busfreq_ppmu_data ppmu_data;
MyungJoo Ham7b405032011-07-14 10:33:55 +090092
93 struct notifier_block pm_notifier;
94 struct mutex lock;
95
96 /* Dividers calculated at boot/probe-time */
97 unsigned int dmc_divtable[_LV_END]; /* DMC0 */
98 unsigned int top_divtable[_LV_END];
99};
100
MyungJoo Ham7b405032011-07-14 10:33:55 +0900101/* 4210 controls clock of mif and voltage of int */
102static struct bus_opp_table exynos4210_busclk_table[] = {
103 {LV_0, 400000, 1150000},
104 {LV_1, 267000, 1050000},
105 {LV_2, 133000, 1025000},
106 {0, 0, 0},
107};
108
109/*
Sachin Kamat1d6c2c02013-11-27 14:50:26 +0530110 * MIF is the main control knob clock for Exynos4x12 MIF/INT
MyungJoo Ham7b405032011-07-14 10:33:55 +0900111 * clock and voltage of both mif/int are controlled.
112 */
113static struct bus_opp_table exynos4x12_mifclk_table[] = {
114 {LV_0, 400000, 1100000},
115 {LV_1, 267000, 1000000},
116 {LV_2, 160000, 950000},
117 {LV_3, 133000, 950000},
118 {LV_4, 100000, 950000},
119 {0, 0, 0},
120};
121
122/*
123 * INT is not the control knob of 4x12. LV_x is not meant to represent
124 * the current performance. (MIF does)
125 */
126static struct bus_opp_table exynos4x12_intclk_table[] = {
127 {LV_0, 200000, 1000000},
128 {LV_1, 160000, 950000},
129 {LV_2, 133000, 925000},
130 {LV_3, 100000, 900000},
131 {0, 0, 0},
132};
133
134/* TODO: asv volt definitions are "__initdata"? */
135/* Some chips have different operating voltages */
136static unsigned int exynos4210_asv_volt[][EX4210_LV_NUM] = {
137 {1150000, 1050000, 1050000},
138 {1125000, 1025000, 1025000},
139 {1100000, 1000000, 1000000},
140 {1075000, 975000, 975000},
141 {1050000, 950000, 950000},
142};
143
144static unsigned int exynos4x12_mif_step_50[][EX4x12_LV_NUM] = {
145 /* 400 267 160 133 100 */
146 {1050000, 950000, 900000, 900000, 900000}, /* ASV0 */
147 {1050000, 950000, 900000, 900000, 900000}, /* ASV1 */
148 {1050000, 950000, 900000, 900000, 900000}, /* ASV2 */
149 {1050000, 900000, 900000, 900000, 900000}, /* ASV3 */
150 {1050000, 900000, 900000, 900000, 850000}, /* ASV4 */
151 {1050000, 900000, 900000, 850000, 850000}, /* ASV5 */
152 {1050000, 900000, 850000, 850000, 850000}, /* ASV6 */
153 {1050000, 900000, 850000, 850000, 850000}, /* ASV7 */
154 {1050000, 900000, 850000, 850000, 850000}, /* ASV8 */
155};
156
157static unsigned int exynos4x12_int_volt[][EX4x12_LV_NUM] = {
158 /* 200 160 133 100 */
159 {1000000, 950000, 925000, 900000}, /* ASV0 */
160 {975000, 925000, 925000, 900000}, /* ASV1 */
161 {950000, 925000, 900000, 875000}, /* ASV2 */
162 {950000, 900000, 900000, 875000}, /* ASV3 */
163 {925000, 875000, 875000, 875000}, /* ASV4 */
164 {900000, 850000, 850000, 850000}, /* ASV5 */
165 {900000, 850000, 850000, 850000}, /* ASV6 */
166 {900000, 850000, 850000, 850000}, /* ASV7 */
167 {900000, 850000, 850000, 850000}, /* ASV8 */
168};
169
170/*** Clock Divider Data for Exynos4210 ***/
171static unsigned int exynos4210_clkdiv_dmc0[][8] = {
172 /*
173 * Clock divider value for following
174 * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
175 * DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
176 */
177
178 /* DMC L0: 400MHz */
179 { 3, 1, 1, 1, 1, 1, 3, 1 },
180 /* DMC L1: 266.7MHz */
181 { 4, 1, 1, 2, 1, 1, 3, 1 },
182 /* DMC L2: 133MHz */
183 { 5, 1, 1, 5, 1, 1, 3, 1 },
184};
185static unsigned int exynos4210_clkdiv_top[][5] = {
186 /*
187 * Clock divider value for following
188 * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
189 */
190 /* ACLK200 L0: 200MHz */
191 { 3, 7, 4, 5, 1 },
192 /* ACLK200 L1: 160MHz */
193 { 4, 7, 5, 6, 1 },
194 /* ACLK200 L2: 133MHz */
195 { 5, 7, 7, 7, 1 },
196};
197static unsigned int exynos4210_clkdiv_lr_bus[][2] = {
198 /*
199 * Clock divider value for following
200 * { DIVGDL/R, DIVGPL/R }
201 */
202 /* ACLK_GDL/R L1: 200MHz */
203 { 3, 1 },
204 /* ACLK_GDL/R L2: 160MHz */
205 { 4, 1 },
206 /* ACLK_GDL/R L3: 133MHz */
207 { 5, 1 },
208};
209
210/*** Clock Divider Data for Exynos4212/4412 ***/
211static unsigned int exynos4x12_clkdiv_dmc0[][6] = {
212 /*
213 * Clock divider value for following
214 * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
215 * DIVDMCP}
216 */
217
218 /* DMC L0: 400MHz */
219 {3, 1, 1, 1, 1, 1},
220 /* DMC L1: 266.7MHz */
221 {4, 1, 1, 2, 1, 1},
222 /* DMC L2: 160MHz */
223 {5, 1, 1, 4, 1, 1},
224 /* DMC L3: 133MHz */
225 {5, 1, 1, 5, 1, 1},
226 /* DMC L4: 100MHz */
227 {7, 1, 1, 7, 1, 1},
228};
229static unsigned int exynos4x12_clkdiv_dmc1[][6] = {
230 /*
231 * Clock divider value for following
232 * { G2DACP, DIVC2C, DIVC2C_ACLK }
233 */
234
235 /* DMC L0: 400MHz */
236 {3, 1, 1},
237 /* DMC L1: 266.7MHz */
238 {4, 2, 1},
239 /* DMC L2: 160MHz */
240 {5, 4, 1},
241 /* DMC L3: 133MHz */
242 {5, 5, 1},
243 /* DMC L4: 100MHz */
244 {7, 7, 1},
245};
246static unsigned int exynos4x12_clkdiv_top[][5] = {
247 /*
248 * Clock divider value for following
249 * { DIVACLK266_GPS, DIVACLK100, DIVACLK160,
250 DIVACLK133, DIVONENAND }
251 */
252
253 /* ACLK_GDL/R L0: 200MHz */
254 {2, 7, 4, 5, 1},
255 /* ACLK_GDL/R L1: 200MHz */
256 {2, 7, 4, 5, 1},
257 /* ACLK_GDL/R L2: 160MHz */
258 {4, 7, 5, 7, 1},
259 /* ACLK_GDL/R L3: 133MHz */
260 {4, 7, 5, 7, 1},
261 /* ACLK_GDL/R L4: 100MHz */
262 {7, 7, 7, 7, 1},
263};
264static unsigned int exynos4x12_clkdiv_lr_bus[][2] = {
265 /*
266 * Clock divider value for following
267 * { DIVGDL/R, DIVGPL/R }
268 */
269
270 /* ACLK_GDL/R L0: 200MHz */
271 {3, 1},
272 /* ACLK_GDL/R L1: 200MHz */
273 {3, 1},
274 /* ACLK_GDL/R L2: 160MHz */
275 {4, 1},
276 /* ACLK_GDL/R L3: 133MHz */
277 {5, 1},
278 /* ACLK_GDL/R L4: 100MHz */
279 {7, 1},
280};
281static unsigned int exynos4x12_clkdiv_sclkip[][3] = {
282 /*
283 * Clock divider value for following
284 * { DIVMFC, DIVJPEG, DIVFIMC0~3}
285 */
286
287 /* SCLK_MFC: 200MHz */
288 {3, 3, 4},
289 /* SCLK_MFC: 200MHz */
290 {3, 3, 4},
291 /* SCLK_MFC: 160MHz */
292 {4, 4, 5},
293 /* SCLK_MFC: 133MHz */
294 {5, 5, 5},
295 /* SCLK_MFC: 100MHz */
296 {7, 7, 7},
297};
298
299
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000300static int exynos4210_set_busclk(struct busfreq_data *data,
301 struct busfreq_opp_info *oppi)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900302{
303 unsigned int index;
304 unsigned int tmp;
305
306 for (index = LV_0; index < EX4210_LV_NUM; index++)
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000307 if (oppi->rate == exynos4210_busclk_table[index].clk)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900308 break;
309
310 if (index == EX4210_LV_NUM)
311 return -EINVAL;
312
313 /* Change Divider - DMC0 */
314 tmp = data->dmc_divtable[index];
315
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900316 __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900317
318 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900319 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900320 } while (tmp & 0x11111111);
321
322 /* Change Divider - TOP */
323 tmp = data->top_divtable[index];
324
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900325 __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900326
327 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900328 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900329 } while (tmp & 0x11111);
330
331 /* Change Divider - LEFTBUS */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900332 tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900333
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900334 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900335
336 tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900337 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900338 (exynos4210_clkdiv_lr_bus[index][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900339 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900340
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900341 __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900342
343 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900344 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900345 } while (tmp & 0x11);
346
347 /* Change Divider - RIGHTBUS */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900348 tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900349
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900350 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900351
352 tmp |= ((exynos4210_clkdiv_lr_bus[index][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900353 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900354 (exynos4210_clkdiv_lr_bus[index][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900355 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900356
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900357 __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900358
359 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900360 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900361 } while (tmp & 0x11);
362
363 return 0;
364}
365
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000366static int exynos4x12_set_busclk(struct busfreq_data *data,
367 struct busfreq_opp_info *oppi)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900368{
369 unsigned int index;
370 unsigned int tmp;
371
372 for (index = LV_0; index < EX4x12_LV_NUM; index++)
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000373 if (oppi->rate == exynos4x12_mifclk_table[index].clk)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900374 break;
375
376 if (index == EX4x12_LV_NUM)
377 return -EINVAL;
378
379 /* Change Divider - DMC0 */
380 tmp = data->dmc_divtable[index];
381
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900382 __raw_writel(tmp, EXYNOS4_CLKDIV_DMC0);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900383
384 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900385 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC0);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900386 } while (tmp & 0x11111111);
387
388 /* Change Divider - DMC1 */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900389 tmp = __raw_readl(EXYNOS4_CLKDIV_DMC1);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900390
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900391 tmp &= ~(EXYNOS4_CLKDIV_DMC1_G2D_ACP_MASK |
392 EXYNOS4_CLKDIV_DMC1_C2C_MASK |
393 EXYNOS4_CLKDIV_DMC1_C2CACLK_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900394
395 tmp |= ((exynos4x12_clkdiv_dmc1[index][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900396 EXYNOS4_CLKDIV_DMC1_G2D_ACP_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900397 (exynos4x12_clkdiv_dmc1[index][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900398 EXYNOS4_CLKDIV_DMC1_C2C_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900399 (exynos4x12_clkdiv_dmc1[index][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900400 EXYNOS4_CLKDIV_DMC1_C2CACLK_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900401
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900402 __raw_writel(tmp, EXYNOS4_CLKDIV_DMC1);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900403
404 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900405 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_DMC1);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900406 } while (tmp & 0x111111);
407
408 /* Change Divider - TOP */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900409 tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900410
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900411 tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK266_GPS_MASK |
412 EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
413 EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
414 EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
415 EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900416
417 tmp |= ((exynos4x12_clkdiv_top[index][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900418 EXYNOS4_CLKDIV_TOP_ACLK266_GPS_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900419 (exynos4x12_clkdiv_top[index][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900420 EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900421 (exynos4x12_clkdiv_top[index][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900422 EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900423 (exynos4x12_clkdiv_top[index][3] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900424 EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900425 (exynos4x12_clkdiv_top[index][4] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900426 EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900427
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900428 __raw_writel(tmp, EXYNOS4_CLKDIV_TOP);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900429
430 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900431 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_TOP);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900432 } while (tmp & 0x11111);
433
434 /* Change Divider - LEFTBUS */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900435 tmp = __raw_readl(EXYNOS4_CLKDIV_LEFTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900436
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900437 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900438
439 tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900440 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900441 (exynos4x12_clkdiv_lr_bus[index][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900442 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900443
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900444 __raw_writel(tmp, EXYNOS4_CLKDIV_LEFTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900445
446 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900447 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_LEFTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900448 } while (tmp & 0x11);
449
450 /* Change Divider - RIGHTBUS */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900451 tmp = __raw_readl(EXYNOS4_CLKDIV_RIGHTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900452
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900453 tmp &= ~(EXYNOS4_CLKDIV_BUS_GDLR_MASK | EXYNOS4_CLKDIV_BUS_GPLR_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900454
455 tmp |= ((exynos4x12_clkdiv_lr_bus[index][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900456 EXYNOS4_CLKDIV_BUS_GDLR_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900457 (exynos4x12_clkdiv_lr_bus[index][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900458 EXYNOS4_CLKDIV_BUS_GPLR_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900459
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900460 __raw_writel(tmp, EXYNOS4_CLKDIV_RIGHTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900461
462 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900463 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_RIGHTBUS);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900464 } while (tmp & 0x11);
465
466 /* Change Divider - MFC */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900467 tmp = __raw_readl(EXYNOS4_CLKDIV_MFC);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900468
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900469 tmp &= ~(EXYNOS4_CLKDIV_MFC_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900470
471 tmp |= ((exynos4x12_clkdiv_sclkip[index][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900472 EXYNOS4_CLKDIV_MFC_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900473
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900474 __raw_writel(tmp, EXYNOS4_CLKDIV_MFC);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900475
476 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900477 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_MFC);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900478 } while (tmp & 0x1);
479
480 /* Change Divider - JPEG */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900481 tmp = __raw_readl(EXYNOS4_CLKDIV_CAM1);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900482
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900483 tmp &= ~(EXYNOS4_CLKDIV_CAM1_JPEG_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900484
485 tmp |= ((exynos4x12_clkdiv_sclkip[index][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900486 EXYNOS4_CLKDIV_CAM1_JPEG_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900487
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900488 __raw_writel(tmp, EXYNOS4_CLKDIV_CAM1);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900489
490 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900491 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900492 } while (tmp & 0x1);
493
494 /* Change Divider - FIMC0~3 */
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900495 tmp = __raw_readl(EXYNOS4_CLKDIV_CAM);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900496
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900497 tmp &= ~(EXYNOS4_CLKDIV_CAM_FIMC0_MASK | EXYNOS4_CLKDIV_CAM_FIMC1_MASK |
498 EXYNOS4_CLKDIV_CAM_FIMC2_MASK | EXYNOS4_CLKDIV_CAM_FIMC3_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900499
500 tmp |= ((exynos4x12_clkdiv_sclkip[index][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900501 EXYNOS4_CLKDIV_CAM_FIMC0_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900502 (exynos4x12_clkdiv_sclkip[index][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900503 EXYNOS4_CLKDIV_CAM_FIMC1_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900504 (exynos4x12_clkdiv_sclkip[index][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900505 EXYNOS4_CLKDIV_CAM_FIMC2_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900506 (exynos4x12_clkdiv_sclkip[index][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900507 EXYNOS4_CLKDIV_CAM_FIMC3_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900508
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900509 __raw_writel(tmp, EXYNOS4_CLKDIV_CAM);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900510
511 do {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900512 tmp = __raw_readl(EXYNOS4_CLKDIV_STAT_CAM1);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900513 } while (tmp & 0x1111);
514
515 return 0;
516}
517
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100518static void busfreq_mon_reset(struct busfreq_ppmu_data *ppmu_data)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900519{
520 unsigned int i;
521
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100522 for (i = 0; i < ppmu_data->ppmu_end; i++) {
523 void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900524
Chanwoo Choiba778b32014-03-21 18:31:43 +0100525 /* Reset the performance and cycle counters */
526 exynos_ppmu_reset(ppmu_base);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900527
Chanwoo Choiba778b32014-03-21 18:31:43 +0100528 /* Setup count registers to monitor read/write transactions */
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100529 ppmu_data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
Chanwoo Choiba778b32014-03-21 18:31:43 +0100530 exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100531 ppmu_data->ppmu[i].event[PPMU_PMNCNT3]);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900532
Chanwoo Choiba778b32014-03-21 18:31:43 +0100533 exynos_ppmu_start(ppmu_base);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900534 }
535}
536
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100537static void exynos4_read_ppmu(struct busfreq_ppmu_data *ppmu_data)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900538{
539 int i, j;
540
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100541 for (i = 0; i < ppmu_data->ppmu_end; i++) {
542 void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900543
Chanwoo Choiba778b32014-03-21 18:31:43 +0100544 exynos_ppmu_stop(ppmu_base);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900545
546 /* Update local data from PPMU */
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100547 ppmu_data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900548
Chanwoo Choiba778b32014-03-21 18:31:43 +0100549 for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100550 if (ppmu_data->ppmu[i].event[j] == 0)
551 ppmu_data->ppmu[i].count[j] = 0;
Chanwoo Choiba778b32014-03-21 18:31:43 +0100552 else
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100553 ppmu_data->ppmu[i].count[j] =
Chanwoo Choiba778b32014-03-21 18:31:43 +0100554 exynos_ppmu_read(ppmu_base, j);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900555 }
556 }
557
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100558 busfreq_mon_reset(ppmu_data);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900559}
560
561static int exynos4x12_get_intspec(unsigned long mifclk)
562{
563 int i = 0;
564
565 while (exynos4x12_intclk_table[i].clk) {
566 if (exynos4x12_intclk_table[i].clk <= mifclk)
567 return i;
568 i++;
569 }
570
571 return -EINVAL;
572}
573
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000574static int exynos4_bus_setvolt(struct busfreq_data *data,
575 struct busfreq_opp_info *oppi,
576 struct busfreq_opp_info *oldoppi)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900577{
578 int err = 0, tmp;
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000579 unsigned long volt = oppi->volt;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900580
581 switch (data->type) {
582 case TYPE_BUSF_EXYNOS4210:
583 /* OPP represents DMC clock + INT voltage */
584 err = regulator_set_voltage(data->vdd_int, volt,
585 MAX_SAFEVOLT);
586 break;
587 case TYPE_BUSF_EXYNOS4x12:
588 /* OPP represents MIF clock + MIF voltage */
589 err = regulator_set_voltage(data->vdd_mif, volt,
590 MAX_SAFEVOLT);
591 if (err)
592 break;
593
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000594 tmp = exynos4x12_get_intspec(oppi->rate);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900595 if (tmp < 0) {
596 err = tmp;
597 regulator_set_voltage(data->vdd_mif,
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000598 oldoppi->volt,
MyungJoo Ham7b405032011-07-14 10:33:55 +0900599 MAX_SAFEVOLT);
600 break;
601 }
602 err = regulator_set_voltage(data->vdd_int,
603 exynos4x12_intclk_table[tmp].volt,
604 MAX_SAFEVOLT);
605 /* Try to recover */
606 if (err)
607 regulator_set_voltage(data->vdd_mif,
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000608 oldoppi->volt,
MyungJoo Ham7b405032011-07-14 10:33:55 +0900609 MAX_SAFEVOLT);
610 break;
611 default:
612 err = -EINVAL;
613 }
614
615 return err;
616}
617
MyungJoo Hamab5f2992012-03-16 21:54:53 +0100618static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
619 u32 flags)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900620{
621 int err = 0;
MyungJoo Hamab5f2992012-03-16 21:54:53 +0100622 struct platform_device *pdev = container_of(dev, struct platform_device,
623 dev);
624 struct busfreq_data *data = platform_get_drvdata(pdev);
Nishanth Menon47d43ba2013-09-19 16:03:51 -0500625 struct dev_pm_opp *opp;
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000626 unsigned long freq;
627 unsigned long old_freq = data->curr_oppinfo.rate;
628 struct busfreq_opp_info new_oppinfo;
MyungJoo Hamab5f2992012-03-16 21:54:53 +0100629
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000630 rcu_read_lock();
631 opp = devfreq_recommended_opp(dev, _freq, flags);
632 if (IS_ERR(opp)) {
633 rcu_read_unlock();
MyungJoo Hamab5f2992012-03-16 21:54:53 +0100634 return PTR_ERR(opp);
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000635 }
Nishanth Menon5d4879c2013-09-19 16:03:50 -0500636 new_oppinfo.rate = dev_pm_opp_get_freq(opp);
637 new_oppinfo.volt = dev_pm_opp_get_voltage(opp);
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000638 rcu_read_unlock();
639 freq = new_oppinfo.rate;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900640
641 if (old_freq == freq)
642 return 0;
643
Jiri Kosina61767722013-01-29 10:48:30 +0100644 dev_dbg(dev, "targeting %lukHz %luuV\n", freq, new_oppinfo.volt);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900645
646 mutex_lock(&data->lock);
647
648 if (data->disabled)
649 goto out;
650
651 if (old_freq < freq)
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000652 err = exynos4_bus_setvolt(data, &new_oppinfo,
653 &data->curr_oppinfo);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900654 if (err)
655 goto out;
656
657 if (old_freq != freq) {
658 switch (data->type) {
659 case TYPE_BUSF_EXYNOS4210:
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000660 err = exynos4210_set_busclk(data, &new_oppinfo);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900661 break;
662 case TYPE_BUSF_EXYNOS4x12:
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000663 err = exynos4x12_set_busclk(data, &new_oppinfo);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900664 break;
665 default:
666 err = -EINVAL;
667 }
668 }
669 if (err)
670 goto out;
671
672 if (old_freq > freq)
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000673 err = exynos4_bus_setvolt(data, &new_oppinfo,
674 &data->curr_oppinfo);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900675 if (err)
676 goto out;
677
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000678 data->curr_oppinfo = new_oppinfo;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900679out:
680 mutex_unlock(&data->lock);
681 return err;
682}
683
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100684static int exynos4_get_busier_ppmu(struct busfreq_ppmu_data *ppmu_data)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900685{
Chanwoo Choiba778b32014-03-21 18:31:43 +0100686 int i, j;
687 int busy = 0;
688 unsigned int temp = 0;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900689
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100690 for (i = 0; i < ppmu_data->ppmu_end; i++) {
Chanwoo Choiba778b32014-03-21 18:31:43 +0100691 for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100692 if (ppmu_data->ppmu[i].count[j] > temp) {
693 temp = ppmu_data->ppmu[i].count[j];
Chanwoo Choiba778b32014-03-21 18:31:43 +0100694 busy = i;
695 }
696 }
697 }
MyungJoo Ham7b405032011-07-14 10:33:55 +0900698
Chanwoo Choiba778b32014-03-21 18:31:43 +0100699 return busy;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900700}
701
702static int exynos4_bus_get_dev_status(struct device *dev,
703 struct devfreq_dev_status *stat)
704{
Axel Linf0c28b02012-01-14 16:56:43 +0800705 struct busfreq_data *data = dev_get_drvdata(dev);
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100706 struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
Chanwoo Choiba778b32014-03-21 18:31:43 +0100707 int busier;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900708
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100709 exynos4_read_ppmu(ppmu_data);
710 busier = exynos4_get_busier_ppmu(ppmu_data);
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000711 stat->current_frequency = data->curr_oppinfo.rate;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900712
MyungJoo Ham7b405032011-07-14 10:33:55 +0900713 /* Number of cycles spent on memory access */
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100714 stat->busy_time = ppmu_data->ppmu[busier].count[PPMU_PMNCNT3];
MyungJoo Ham7b405032011-07-14 10:33:55 +0900715 stat->busy_time *= 100 / BUS_SATURATION_RATIO;
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100716 stat->total_time = ppmu_data->ppmu[busier].ccnt;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900717
718 /* If the counters have overflown, retry */
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100719 if (ppmu_data->ppmu[busier].ccnt_overflow ||
720 ppmu_data->ppmu[busier].count_overflow[0])
MyungJoo Ham7b405032011-07-14 10:33:55 +0900721 return -EAGAIN;
722
723 return 0;
724}
725
MyungJoo Ham7b405032011-07-14 10:33:55 +0900726static struct devfreq_dev_profile exynos4_devfreq_profile = {
727 .initial_freq = 400000,
728 .polling_ms = 50,
729 .target = exynos4_bus_target,
730 .get_dev_status = exynos4_bus_get_dev_status,
MyungJoo Ham7b405032011-07-14 10:33:55 +0900731};
732
733static int exynos4210_init_tables(struct busfreq_data *data)
734{
735 u32 tmp;
736 int mgrp;
737 int i, err = 0;
738
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900739 tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900740 for (i = LV_0; i < EX4210_LV_NUM; i++) {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900741 tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
742 EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
743 EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
744 EXYNOS4_CLKDIV_DMC0_DMC_MASK |
745 EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
746 EXYNOS4_CLKDIV_DMC0_DMCP_MASK |
747 EXYNOS4_CLKDIV_DMC0_COPY2_MASK |
748 EXYNOS4_CLKDIV_DMC0_CORETI_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900749
750 tmp |= ((exynos4210_clkdiv_dmc0[i][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900751 EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900752 (exynos4210_clkdiv_dmc0[i][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900753 EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900754 (exynos4210_clkdiv_dmc0[i][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900755 EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900756 (exynos4210_clkdiv_dmc0[i][3] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900757 EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900758 (exynos4210_clkdiv_dmc0[i][4] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900759 EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900760 (exynos4210_clkdiv_dmc0[i][5] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900761 EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900762 (exynos4210_clkdiv_dmc0[i][6] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900763 EXYNOS4_CLKDIV_DMC0_COPY2_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900764 (exynos4210_clkdiv_dmc0[i][7] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900765 EXYNOS4_CLKDIV_DMC0_CORETI_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900766
767 data->dmc_divtable[i] = tmp;
768 }
769
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900770 tmp = __raw_readl(EXYNOS4_CLKDIV_TOP);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900771 for (i = LV_0; i < EX4210_LV_NUM; i++) {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900772 tmp &= ~(EXYNOS4_CLKDIV_TOP_ACLK200_MASK |
773 EXYNOS4_CLKDIV_TOP_ACLK100_MASK |
774 EXYNOS4_CLKDIV_TOP_ACLK160_MASK |
775 EXYNOS4_CLKDIV_TOP_ACLK133_MASK |
776 EXYNOS4_CLKDIV_TOP_ONENAND_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900777
778 tmp |= ((exynos4210_clkdiv_top[i][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900779 EXYNOS4_CLKDIV_TOP_ACLK200_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900780 (exynos4210_clkdiv_top[i][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900781 EXYNOS4_CLKDIV_TOP_ACLK100_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900782 (exynos4210_clkdiv_top[i][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900783 EXYNOS4_CLKDIV_TOP_ACLK160_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900784 (exynos4210_clkdiv_top[i][3] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900785 EXYNOS4_CLKDIV_TOP_ACLK133_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900786 (exynos4210_clkdiv_top[i][4] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900787 EXYNOS4_CLKDIV_TOP_ONENAND_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900788
789 data->top_divtable[i] = tmp;
790 }
791
792#ifdef CONFIG_EXYNOS_ASV
793 tmp = exynos4_result_of_asv;
794#else
795 tmp = 0; /* Max voltages for the reliability of the unknown */
796#endif
797
798 pr_debug("ASV Group of Exynos4 is %d\n", tmp);
799 /* Use merged grouping for voltage */
800 switch (tmp) {
801 case 0:
802 mgrp = 0;
803 break;
804 case 1:
805 case 2:
806 mgrp = 1;
807 break;
808 case 3:
809 case 4:
810 mgrp = 2;
811 break;
812 case 5:
813 case 6:
814 mgrp = 3;
815 break;
816 case 7:
817 mgrp = 4;
818 break;
819 default:
820 pr_warn("Unknown ASV Group. Use max voltage.\n");
821 mgrp = 0;
822 }
823
824 for (i = LV_0; i < EX4210_LV_NUM; i++)
825 exynos4210_busclk_table[i].volt = exynos4210_asv_volt[mgrp][i];
826
827 for (i = LV_0; i < EX4210_LV_NUM; i++) {
Nishanth Menon5d4879c2013-09-19 16:03:50 -0500828 err = dev_pm_opp_add(data->dev, exynos4210_busclk_table[i].clk,
MyungJoo Ham7b405032011-07-14 10:33:55 +0900829 exynos4210_busclk_table[i].volt);
830 if (err) {
831 dev_err(data->dev, "Cannot add opp entries.\n");
832 return err;
833 }
834 }
835
836
837 return 0;
838}
839
840static int exynos4x12_init_tables(struct busfreq_data *data)
841{
842 unsigned int i;
843 unsigned int tmp;
844 int ret;
845
846 /* Enable pause function for DREX2 DVFS */
MyungJoo Hama2b96762012-03-09 15:53:00 +0900847 tmp = __raw_readl(EXYNOS4_DMC_PAUSE_CTRL);
848 tmp |= EXYNOS4_DMC_PAUSE_ENABLE;
849 __raw_writel(tmp, EXYNOS4_DMC_PAUSE_CTRL);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900850
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900851 tmp = __raw_readl(EXYNOS4_CLKDIV_DMC0);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900852
853 for (i = 0; i < EX4x12_LV_NUM; i++) {
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900854 tmp &= ~(EXYNOS4_CLKDIV_DMC0_ACP_MASK |
855 EXYNOS4_CLKDIV_DMC0_ACPPCLK_MASK |
856 EXYNOS4_CLKDIV_DMC0_DPHY_MASK |
857 EXYNOS4_CLKDIV_DMC0_DMC_MASK |
858 EXYNOS4_CLKDIV_DMC0_DMCD_MASK |
859 EXYNOS4_CLKDIV_DMC0_DMCP_MASK);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900860
861 tmp |= ((exynos4x12_clkdiv_dmc0[i][0] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900862 EXYNOS4_CLKDIV_DMC0_ACP_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900863 (exynos4x12_clkdiv_dmc0[i][1] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900864 EXYNOS4_CLKDIV_DMC0_ACPPCLK_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900865 (exynos4x12_clkdiv_dmc0[i][2] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900866 EXYNOS4_CLKDIV_DMC0_DPHY_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900867 (exynos4x12_clkdiv_dmc0[i][3] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900868 EXYNOS4_CLKDIV_DMC0_DMC_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900869 (exynos4x12_clkdiv_dmc0[i][4] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900870 EXYNOS4_CLKDIV_DMC0_DMCD_SHIFT) |
MyungJoo Ham7b405032011-07-14 10:33:55 +0900871 (exynos4x12_clkdiv_dmc0[i][5] <<
Kukjin Kim5fcc9292012-01-22 20:46:49 +0900872 EXYNOS4_CLKDIV_DMC0_DMCP_SHIFT));
MyungJoo Ham7b405032011-07-14 10:33:55 +0900873
874 data->dmc_divtable[i] = tmp;
875 }
876
877#ifdef CONFIG_EXYNOS_ASV
878 tmp = exynos4_result_of_asv;
879#else
880 tmp = 0; /* Max voltages for the reliability of the unknown */
881#endif
882
883 if (tmp > 8)
884 tmp = 0;
885 pr_debug("ASV Group of Exynos4x12 is %d\n", tmp);
886
887 for (i = 0; i < EX4x12_LV_NUM; i++) {
888 exynos4x12_mifclk_table[i].volt =
889 exynos4x12_mif_step_50[tmp][i];
890 exynos4x12_intclk_table[i].volt =
891 exynos4x12_int_volt[tmp][i];
892 }
893
894 for (i = 0; i < EX4x12_LV_NUM; i++) {
Nishanth Menon5d4879c2013-09-19 16:03:50 -0500895 ret = dev_pm_opp_add(data->dev, exynos4x12_mifclk_table[i].clk,
MyungJoo Ham7b405032011-07-14 10:33:55 +0900896 exynos4x12_mifclk_table[i].volt);
897 if (ret) {
898 dev_err(data->dev, "Fail to add opp entries.\n");
899 return ret;
900 }
901 }
902
903 return 0;
904}
905
906static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
907 unsigned long event, void *ptr)
908{
909 struct busfreq_data *data = container_of(this, struct busfreq_data,
910 pm_notifier);
Nishanth Menon47d43ba2013-09-19 16:03:51 -0500911 struct dev_pm_opp *opp;
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000912 struct busfreq_opp_info new_oppinfo;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900913 unsigned long maxfreq = ULONG_MAX;
914 int err = 0;
915
916 switch (event) {
917 case PM_SUSPEND_PREPARE:
918 /* Set Fastest and Deactivate DVFS */
919 mutex_lock(&data->lock);
920
921 data->disabled = true;
922
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000923 rcu_read_lock();
Nishanth Menon5d4879c2013-09-19 16:03:50 -0500924 opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq);
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000925 if (IS_ERR(opp)) {
926 rcu_read_unlock();
927 dev_err(data->dev, "%s: unable to find a min freq\n",
928 __func__);
Wei Yongjun5751cdc2013-02-22 12:33:50 +0800929 mutex_unlock(&data->lock);
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000930 return PTR_ERR(opp);
931 }
Nishanth Menon5d4879c2013-09-19 16:03:50 -0500932 new_oppinfo.rate = dev_pm_opp_get_freq(opp);
933 new_oppinfo.volt = dev_pm_opp_get_voltage(opp);
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000934 rcu_read_unlock();
MyungJoo Ham7b405032011-07-14 10:33:55 +0900935
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000936 err = exynos4_bus_setvolt(data, &new_oppinfo,
937 &data->curr_oppinfo);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900938 if (err)
939 goto unlock;
940
941 switch (data->type) {
942 case TYPE_BUSF_EXYNOS4210:
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000943 err = exynos4210_set_busclk(data, &new_oppinfo);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900944 break;
945 case TYPE_BUSF_EXYNOS4x12:
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000946 err = exynos4x12_set_busclk(data, &new_oppinfo);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900947 break;
948 default:
949 err = -EINVAL;
950 }
951 if (err)
952 goto unlock;
953
Nishanth Menon8fa938a2013-01-18 19:52:35 +0000954 data->curr_oppinfo = new_oppinfo;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900955unlock:
956 mutex_unlock(&data->lock);
957 if (err)
958 return err;
959 return NOTIFY_OK;
960 case PM_POST_RESTORE:
961 case PM_POST_SUSPEND:
962 /* Reactivate */
963 mutex_lock(&data->lock);
964 data->disabled = false;
965 mutex_unlock(&data->lock);
966 return NOTIFY_OK;
967 }
968
969 return NOTIFY_DONE;
970}
971
Greg Kroah-Hartman0fe763c2012-12-21 15:14:44 -0800972static int exynos4_busfreq_probe(struct platform_device *pdev)
MyungJoo Ham7b405032011-07-14 10:33:55 +0900973{
974 struct busfreq_data *data;
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100975 struct busfreq_ppmu_data *ppmu_data;
Nishanth Menon47d43ba2013-09-19 16:03:51 -0500976 struct dev_pm_opp *opp;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900977 struct device *dev = &pdev->dev;
978 int err = 0;
979
Sachin Kamatd7895052012-08-21 15:35:32 +0530980 data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), GFP_KERNEL);
MyungJoo Ham7b405032011-07-14 10:33:55 +0900981 if (data == NULL) {
982 dev_err(dev, "Cannot allocate memory.\n");
983 return -ENOMEM;
984 }
985
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100986 ppmu_data = &data->ppmu_data;
987 ppmu_data->ppmu_end = PPMU_END;
988 ppmu_data->ppmu = devm_kzalloc(dev,
989 sizeof(struct exynos_ppmu) * PPMU_END,
990 GFP_KERNEL);
991 if (!ppmu_data->ppmu) {
992 dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
993 return -ENOMEM;
994 }
995
MyungJoo Ham7b405032011-07-14 10:33:55 +0900996 data->type = pdev->id_entry->driver_data;
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +0100997 ppmu_data->ppmu[PPMU_DMC0].hw_base = S5P_VA_DMC0;
998 ppmu_data->ppmu[PPMU_DMC1].hw_base = S5P_VA_DMC1;
MyungJoo Ham7b405032011-07-14 10:33:55 +0900999 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 }
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001014 if (err) {
1015 dev_err(dev, "Cannot initialize busfreq table %d\n",
1016 data->type);
Sachin Kamatd7895052012-08-21 15:35:32 +05301017 return err;
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001018 }
MyungJoo Ham7b405032011-07-14 10:33:55 +09001019
Sachin Kamatd7895052012-08-21 15:35:32 +05301020 data->vdd_int = devm_regulator_get(dev, "vdd_int");
MyungJoo Ham7b405032011-07-14 10:33:55 +09001021 if (IS_ERR(data->vdd_int)) {
1022 dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
Sachin Kamatd7895052012-08-21 15:35:32 +05301023 return PTR_ERR(data->vdd_int);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001024 }
1025 if (data->type == TYPE_BUSF_EXYNOS4x12) {
Sachin Kamatd7895052012-08-21 15:35:32 +05301026 data->vdd_mif = devm_regulator_get(dev, "vdd_mif");
MyungJoo Ham7b405032011-07-14 10:33:55 +09001027 if (IS_ERR(data->vdd_mif)) {
1028 dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n");
Sachin Kamatd7895052012-08-21 15:35:32 +05301029 return PTR_ERR(data->vdd_mif);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001030 }
1031 }
1032
Nishanth Menon8fa938a2013-01-18 19:52:35 +00001033 rcu_read_lock();
Nishanth Menon5d4879c2013-09-19 16:03:50 -05001034 opp = dev_pm_opp_find_freq_floor(dev,
1035 &exynos4_devfreq_profile.initial_freq);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001036 if (IS_ERR(opp)) {
Nishanth Menon8fa938a2013-01-18 19:52:35 +00001037 rcu_read_unlock();
MyungJoo Ham7b405032011-07-14 10:33:55 +09001038 dev_err(dev, "Invalid initial frequency %lu kHz.\n",
Sangho Yidce9dc32012-10-20 01:16:34 +09001039 exynos4_devfreq_profile.initial_freq);
Sachin Kamatd7895052012-08-21 15:35:32 +05301040 return PTR_ERR(opp);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001041 }
Nishanth Menon5d4879c2013-09-19 16:03:50 -05001042 data->curr_oppinfo.rate = dev_pm_opp_get_freq(opp);
1043 data->curr_oppinfo.volt = dev_pm_opp_get_voltage(opp);
Nishanth Menon8fa938a2013-01-18 19:52:35 +00001044 rcu_read_unlock();
MyungJoo Ham7b405032011-07-14 10:33:55 +09001045
1046 platform_set_drvdata(pdev, data);
1047
MyungJoo Ham7b405032011-07-14 10:33:55 +09001048 data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
Nishanth Menon1b5c1be2012-10-29 15:01:45 -05001049 "simple_ondemand", NULL);
Sachin Kamatd7895052012-08-21 15:35:32 +05301050 if (IS_ERR(data->devfreq))
1051 return PTR_ERR(data->devfreq);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001052
Chanwoo Choiba778b32014-03-21 18:31:43 +01001053 /*
1054 * Start PPMU (Performance Profiling Monitoring Unit) to check
1055 * utilization of each IP in the Exynos4 SoC.
1056 */
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +01001057 busfreq_mon_reset(ppmu_data);
Chanwoo Choiba778b32014-03-21 18:31:43 +01001058
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001059 /* Register opp_notifier for Exynos4 busfreq */
1060 err = devfreq_register_opp_notifier(dev, data->devfreq);
1061 if (err < 0) {
1062 dev_err(dev, "Failed to register opp notifier\n");
1063 goto err_notifier_opp;
1064 }
MyungJoo Ham7b405032011-07-14 10:33:55 +09001065
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001066 /* Register pm_notifier for Exynos4 busfreq */
MyungJoo Ham7b405032011-07-14 10:33:55 +09001067 err = register_pm_notifier(&data->pm_notifier);
1068 if (err) {
1069 dev_err(dev, "Failed to setup pm notifier\n");
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001070 goto err_notifier_pm;
MyungJoo Ham7b405032011-07-14 10:33:55 +09001071 }
1072
1073 return 0;
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001074
1075err_notifier_pm:
1076 devfreq_unregister_opp_notifier(dev, data->devfreq);
1077err_notifier_opp:
1078 devfreq_remove_device(data->devfreq);
1079
1080 return err;
MyungJoo Ham7b405032011-07-14 10:33:55 +09001081}
1082
Greg Kroah-Hartman0fe763c2012-12-21 15:14:44 -08001083static int exynos4_busfreq_remove(struct platform_device *pdev)
MyungJoo Ham7b405032011-07-14 10:33:55 +09001084{
1085 struct busfreq_data *data = platform_get_drvdata(pdev);
1086
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001087 /* Unregister all of notifier chain */
MyungJoo Ham7b405032011-07-14 10:33:55 +09001088 unregister_pm_notifier(&data->pm_notifier);
Chanwoo Choi45c58e92014-03-20 11:59:09 +09001089 devfreq_unregister_opp_notifier(data->dev, data->devfreq);
1090
1091 /* Remove devfreq instance */
MyungJoo Ham7b405032011-07-14 10:33:55 +09001092 devfreq_remove_device(data->devfreq);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001093
1094 return 0;
1095}
1096
Chanwoo Choi60d69772014-03-20 11:59:10 +09001097#ifdef CONFIG_PM_SLEEP
MyungJoo Ham7b405032011-07-14 10:33:55 +09001098static int exynos4_busfreq_resume(struct device *dev)
1099{
Axel Linf0c28b02012-01-14 16:56:43 +08001100 struct busfreq_data *data = dev_get_drvdata(dev);
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +01001101 struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
MyungJoo Ham7b405032011-07-14 10:33:55 +09001102
Bartlomiej Zolnierkiewiczf4145272014-03-21 18:31:44 +01001103 busfreq_mon_reset(ppmu_data);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001104 return 0;
1105}
Chanwoo Choi60d69772014-03-20 11:59:10 +09001106#endif
MyungJoo Ham7b405032011-07-14 10:33:55 +09001107
Chanwoo Choi60d69772014-03-20 11:59:10 +09001108static SIMPLE_DEV_PM_OPS(exynos4_busfreq_pm_ops, NULL, exynos4_busfreq_resume);
MyungJoo Ham7b405032011-07-14 10:33:55 +09001109
1110static const struct platform_device_id exynos4_busfreq_id[] = {
1111 { "exynos4210-busfreq", TYPE_BUSF_EXYNOS4210 },
1112 { "exynos4412-busfreq", TYPE_BUSF_EXYNOS4x12 },
1113 { "exynos4212-busfreq", TYPE_BUSF_EXYNOS4x12 },
1114 { },
1115};
1116
1117static struct platform_driver exynos4_busfreq_driver = {
1118 .probe = exynos4_busfreq_probe,
Greg Kroah-Hartman0fe763c2012-12-21 15:14:44 -08001119 .remove = exynos4_busfreq_remove,
MyungJoo Ham7b405032011-07-14 10:33:55 +09001120 .id_table = exynos4_busfreq_id,
1121 .driver = {
1122 .name = "exynos4-busfreq",
1123 .owner = THIS_MODULE,
Chanwoo Choi60d69772014-03-20 11:59:10 +09001124 .pm = &exynos4_busfreq_pm_ops,
MyungJoo Ham7b405032011-07-14 10:33:55 +09001125 },
1126};
1127
1128static int __init exynos4_busfreq_init(void)
1129{
1130 return platform_driver_register(&exynos4_busfreq_driver);
1131}
1132late_initcall(exynos4_busfreq_init);
1133
1134static void __exit exynos4_busfreq_exit(void)
1135{
1136 platform_driver_unregister(&exynos4_busfreq_driver);
1137}
1138module_exit(exynos4_busfreq_exit);
1139
1140MODULE_LICENSE("GPL");
1141MODULE_DESCRIPTION("EXYNOS4 busfreq driver with devfreq framework");
1142MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");