2 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com/
5 * EXYNOS5 INT clock frequency scaling support using DEVFREQ framework
6 * Based on work done by Jonghwan Choi <jhbird.choi@samsung.com>
7 * Support for only EXYNOS5250 is present.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
15 #include <linux/module.h>
16 #include <linux/devfreq.h>
18 #include <linux/opp.h>
19 #include <linux/slab.h>
20 #include <linux/suspend.h>
21 #include <linux/opp.h>
22 #include <linux/clk.h>
23 #include <linux/delay.h>
24 #include <linux/platform_device.h>
25 #include <linux/pm_qos.h>
26 #include <linux/regulator/consumer.h>
27 #include <linux/of_address.h>
28 #include <linux/of_platform.h>
30 #include "exynos_ppmu.h"
32 #define MAX_SAFEVOLT 1100000 /* 1.10V */
33 /* Assume that the bus is saturated if the utilization is 25% */
34 #define INT_BUS_SATURATION_RATIO 25
45 enum exynos_ppmu_list
{
50 struct busfreq_data_int
{
52 struct devfreq
*devfreq
;
53 struct regulator
*vdd_int
;
54 struct exynos_ppmu ppmu
[PPMU_END
];
55 unsigned long curr_freq
;
58 struct notifier_block pm_notifier
;
60 struct pm_qos_request int_req
;
64 struct int_bus_opp_table
{
70 static struct int_bus_opp_table exynos5_int_opp_table
[] = {
71 {LV_0
, 266000, 1025000},
72 {LV_1
, 200000, 1025000},
73 {LV_2
, 160000, 1025000},
74 {LV_3
, 133000, 1025000},
75 {LV_4
, 100000, 1025000},
79 static void busfreq_mon_reset(struct busfreq_data_int
*data
)
83 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
84 void __iomem
*ppmu_base
= data
->ppmu
[i
].hw_base
;
86 /* Reset the performance and cycle counters */
87 exynos_ppmu_reset(ppmu_base
);
89 /* Setup count registers to monitor read/write transactions */
90 data
->ppmu
[i
].event
[PPMU_PMNCNT3
] = RDWR_DATA_COUNT
;
91 exynos_ppmu_setevent(ppmu_base
, PPMU_PMNCNT3
,
92 data
->ppmu
[i
].event
[PPMU_PMNCNT3
]);
94 exynos_ppmu_start(ppmu_base
);
98 static void exynos5_read_ppmu(struct busfreq_data_int
*data
)
102 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
103 void __iomem
*ppmu_base
= data
->ppmu
[i
].hw_base
;
105 exynos_ppmu_stop(ppmu_base
);
107 /* Update local data from PPMU */
108 data
->ppmu
[i
].ccnt
= __raw_readl(ppmu_base
+ PPMU_CCNT
);
110 for (j
= PPMU_PMNCNT0
; j
< PPMU_PMNCNT_MAX
; j
++) {
111 if (data
->ppmu
[i
].event
[j
] == 0)
112 data
->ppmu
[i
].count
[j
] = 0;
114 data
->ppmu
[i
].count
[j
] =
115 exynos_ppmu_read(ppmu_base
, j
);
119 busfreq_mon_reset(data
);
122 static int exynos5_int_setvolt(struct busfreq_data_int
*data
,
125 return regulator_set_voltage(data
->vdd_int
, volt
, MAX_SAFEVOLT
);
128 static int exynos5_busfreq_int_target(struct device
*dev
, unsigned long *_freq
,
132 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
134 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
136 unsigned long old_freq
, freq
;
140 opp
= devfreq_recommended_opp(dev
, _freq
, flags
);
143 dev_err(dev
, "%s: Invalid OPP.\n", __func__
);
147 freq
= opp_get_freq(opp
);
148 volt
= opp_get_voltage(opp
);
151 old_freq
= data
->curr_freq
;
153 if (old_freq
== freq
)
156 dev_dbg(dev
, "targetting %lukHz %luuV\n", freq
, volt
);
158 mutex_lock(&data
->lock
);
163 if (freq
> exynos5_int_opp_table
[0].clk
)
164 pm_qos_update_request(&data
->int_req
, freq
* 16 / 1000);
166 pm_qos_update_request(&data
->int_req
, -1);
169 err
= exynos5_int_setvolt(data
, volt
);
173 err
= clk_set_rate(data
->int_clk
, freq
* 1000);
179 err
= exynos5_int_setvolt(data
, volt
);
183 data
->curr_freq
= freq
;
185 mutex_unlock(&data
->lock
);
189 static int exynos5_get_busier_dmc(struct busfreq_data_int
*data
)
193 unsigned int temp
= 0;
195 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
196 for (j
= PPMU_PMNCNT0
; j
< PPMU_PMNCNT_MAX
; j
++) {
197 if (data
->ppmu
[i
].count
[j
] > temp
) {
198 temp
= data
->ppmu
[i
].count
[j
];
207 static int exynos5_int_get_dev_status(struct device
*dev
,
208 struct devfreq_dev_status
*stat
)
210 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
212 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
215 exynos5_read_ppmu(data
);
216 busier_dmc
= exynos5_get_busier_dmc(data
);
218 stat
->current_frequency
= data
->curr_freq
;
220 /* Number of cycles spent on memory access */
221 stat
->busy_time
= data
->ppmu
[busier_dmc
].count
[PPMU_PMNCNT3
];
222 stat
->busy_time
*= 100 / INT_BUS_SATURATION_RATIO
;
223 stat
->total_time
= data
->ppmu
[busier_dmc
].ccnt
;
227 static void exynos5_int_exit(struct device
*dev
)
229 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
231 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
233 devfreq_unregister_opp_notifier(dev
, data
->devfreq
);
236 static struct devfreq_dev_profile exynos5_devfreq_int_profile
= {
237 .initial_freq
= 160000,
239 .target
= exynos5_busfreq_int_target
,
240 .get_dev_status
= exynos5_int_get_dev_status
,
241 .exit
= exynos5_int_exit
,
244 static int exynos5250_init_int_tables(struct busfreq_data_int
*data
)
248 for (i
= LV_0
; i
< _LV_END
; i
++) {
249 err
= opp_add(data
->dev
, exynos5_int_opp_table
[i
].clk
,
250 exynos5_int_opp_table
[i
].volt
);
252 dev_err(data
->dev
, "Cannot add opp entries.\n");
260 static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block
*this,
261 unsigned long event
, void *ptr
)
263 struct busfreq_data_int
*data
= container_of(this,
264 struct busfreq_data_int
, pm_notifier
);
266 unsigned long maxfreq
= ULONG_MAX
;
272 case PM_SUSPEND_PREPARE
:
273 /* Set Fastest and Deactivate DVFS */
274 mutex_lock(&data
->lock
);
276 data
->disabled
= true;
279 opp
= opp_find_freq_floor(data
->dev
, &maxfreq
);
285 freq
= opp_get_freq(opp
);
286 volt
= opp_get_voltage(opp
);
289 err
= exynos5_int_setvolt(data
, volt
);
293 err
= clk_set_rate(data
->int_clk
, freq
* 1000);
298 data
->curr_freq
= freq
;
300 mutex_unlock(&data
->lock
);
304 case PM_POST_RESTORE
:
305 case PM_POST_SUSPEND
:
307 mutex_lock(&data
->lock
);
308 data
->disabled
= false;
309 mutex_unlock(&data
->lock
);
316 static int exynos5_busfreq_int_probe(struct platform_device
*pdev
)
318 struct busfreq_data_int
*data
;
320 struct device
*dev
= &pdev
->dev
;
321 struct device_node
*np
;
322 unsigned long initial_freq
;
323 unsigned long initial_volt
;
327 data
= devm_kzalloc(&pdev
->dev
, sizeof(struct busfreq_data_int
),
330 dev_err(dev
, "Cannot allocate memory.\n");
334 np
= of_find_compatible_node(NULL
, NULL
, "samsung,exynos5250-ppmu");
336 pr_err("Unable to find PPMU node\n");
340 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
341 /* map PPMU memory region */
342 data
->ppmu
[i
].hw_base
= of_iomap(np
, i
);
343 if (data
->ppmu
[i
].hw_base
== NULL
) {
344 dev_err(&pdev
->dev
, "failed to map memory region\n");
348 data
->pm_notifier
.notifier_call
= exynos5_busfreq_int_pm_notifier_event
;
350 mutex_init(&data
->lock
);
352 err
= exynos5250_init_int_tables(data
);
356 data
->vdd_int
= regulator_get(dev
, "vdd_int");
357 if (IS_ERR(data
->vdd_int
)) {
358 dev_err(dev
, "Cannot get the regulator \"vdd_int\"\n");
359 err
= PTR_ERR(data
->vdd_int
);
363 data
->int_clk
= clk_get(dev
, "int_clk");
364 if (IS_ERR(data
->int_clk
)) {
365 dev_err(dev
, "Cannot get clock \"int_clk\"\n");
366 err
= PTR_ERR(data
->int_clk
);
371 opp
= opp_find_freq_floor(dev
,
372 &exynos5_devfreq_int_profile
.initial_freq
);
375 dev_err(dev
, "Invalid initial frequency %lu kHz.\n",
376 exynos5_devfreq_int_profile
.initial_freq
);
380 initial_freq
= opp_get_freq(opp
);
381 initial_volt
= opp_get_voltage(opp
);
383 data
->curr_freq
= initial_freq
;
385 err
= clk_set_rate(data
->int_clk
, initial_freq
* 1000);
387 dev_err(dev
, "Failed to set initial frequency\n");
391 err
= exynos5_int_setvolt(data
, initial_volt
);
395 platform_set_drvdata(pdev
, data
);
397 busfreq_mon_reset(data
);
399 data
->devfreq
= devfreq_add_device(dev
, &exynos5_devfreq_int_profile
,
400 "simple_ondemand", NULL
);
402 if (IS_ERR(data
->devfreq
)) {
403 err
= PTR_ERR(data
->devfreq
);
404 goto err_devfreq_add
;
407 devfreq_register_opp_notifier(dev
, data
->devfreq
);
409 err
= register_pm_notifier(&data
->pm_notifier
);
411 dev_err(dev
, "Failed to setup pm notifier\n");
412 goto err_devfreq_add
;
415 /* TODO: Add a new QOS class for int/mif bus */
416 pm_qos_add_request(&data
->int_req
, PM_QOS_NETWORK_THROUGHPUT
, -1);
421 devfreq_remove_device(data
->devfreq
);
422 platform_set_drvdata(pdev
, NULL
);
424 clk_put(data
->int_clk
);
426 regulator_put(data
->vdd_int
);
431 static int exynos5_busfreq_int_remove(struct platform_device
*pdev
)
433 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
435 pm_qos_remove_request(&data
->int_req
);
436 unregister_pm_notifier(&data
->pm_notifier
);
437 devfreq_remove_device(data
->devfreq
);
438 regulator_put(data
->vdd_int
);
439 clk_put(data
->int_clk
);
440 platform_set_drvdata(pdev
, NULL
);
445 static int exynos5_busfreq_int_resume(struct device
*dev
)
447 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
449 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
451 busfreq_mon_reset(data
);
455 static const struct dev_pm_ops exynos5_busfreq_int_pm
= {
456 .resume
= exynos5_busfreq_int_resume
,
459 /* platform device pointer for exynos5 devfreq device. */
460 static struct platform_device
*exynos5_devfreq_pdev
;
462 static struct platform_driver exynos5_busfreq_int_driver
= {
463 .probe
= exynos5_busfreq_int_probe
,
464 .remove
= exynos5_busfreq_int_remove
,
466 .name
= "exynos5-bus-int",
467 .owner
= THIS_MODULE
,
468 .pm
= &exynos5_busfreq_int_pm
,
472 static int __init
exynos5_busfreq_int_init(void)
476 ret
= platform_driver_register(&exynos5_busfreq_int_driver
);
480 exynos5_devfreq_pdev
=
481 platform_device_register_simple("exynos5-bus-int", -1, NULL
, 0);
482 if (IS_ERR_OR_NULL(exynos5_devfreq_pdev
)) {
483 ret
= PTR_ERR(exynos5_devfreq_pdev
);
489 platform_driver_unregister(&exynos5_busfreq_int_driver
);
493 late_initcall(exynos5_busfreq_int_init
);
495 static void __exit
exynos5_busfreq_int_exit(void)
497 platform_device_unregister(exynos5_devfreq_pdev
);
498 platform_driver_unregister(&exynos5_busfreq_int_driver
);
500 module_exit(exynos5_busfreq_int_exit
);
502 MODULE_LICENSE("GPL");
503 MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");