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/pm_opp.h>
19 #include <linux/slab.h>
20 #include <linux/suspend.h>
21 #include <linux/clk.h>
22 #include <linux/delay.h>
23 #include <linux/platform_device.h>
24 #include <linux/pm_qos.h>
25 #include <linux/regulator/consumer.h>
26 #include <linux/of_address.h>
27 #include <linux/of_platform.h>
29 #include "exynos_ppmu.h"
31 #define MAX_SAFEVOLT 1100000 /* 1.10V */
32 /* Assume that the bus is saturated if the utilization is 25% */
33 #define INT_BUS_SATURATION_RATIO 25
44 enum exynos_ppmu_list
{
49 struct busfreq_data_int
{
51 struct devfreq
*devfreq
;
52 struct regulator
*vdd_int
;
53 struct exynos_ppmu ppmu
[PPMU_END
];
54 unsigned long curr_freq
;
57 struct notifier_block pm_notifier
;
59 struct pm_qos_request int_req
;
63 struct int_bus_opp_table
{
69 static struct int_bus_opp_table exynos5_int_opp_table
[] = {
70 {LV_0
, 266000, 1025000},
71 {LV_1
, 200000, 1025000},
72 {LV_2
, 160000, 1025000},
73 {LV_3
, 133000, 1025000},
74 {LV_4
, 100000, 1025000},
78 static void busfreq_mon_reset(struct busfreq_data_int
*data
)
82 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
83 void __iomem
*ppmu_base
= data
->ppmu
[i
].hw_base
;
85 /* Reset the performance and cycle counters */
86 exynos_ppmu_reset(ppmu_base
);
88 /* Setup count registers to monitor read/write transactions */
89 data
->ppmu
[i
].event
[PPMU_PMNCNT3
] = RDWR_DATA_COUNT
;
90 exynos_ppmu_setevent(ppmu_base
, PPMU_PMNCNT3
,
91 data
->ppmu
[i
].event
[PPMU_PMNCNT3
]);
93 exynos_ppmu_start(ppmu_base
);
97 static void exynos5_read_ppmu(struct busfreq_data_int
*data
)
101 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
102 void __iomem
*ppmu_base
= data
->ppmu
[i
].hw_base
;
104 exynos_ppmu_stop(ppmu_base
);
106 /* Update local data from PPMU */
107 data
->ppmu
[i
].ccnt
= __raw_readl(ppmu_base
+ PPMU_CCNT
);
109 for (j
= PPMU_PMNCNT0
; j
< PPMU_PMNCNT_MAX
; j
++) {
110 if (data
->ppmu
[i
].event
[j
] == 0)
111 data
->ppmu
[i
].count
[j
] = 0;
113 data
->ppmu
[i
].count
[j
] =
114 exynos_ppmu_read(ppmu_base
, j
);
118 busfreq_mon_reset(data
);
121 static int exynos5_int_setvolt(struct busfreq_data_int
*data
,
124 return regulator_set_voltage(data
->vdd_int
, volt
, MAX_SAFEVOLT
);
127 static int exynos5_busfreq_int_target(struct device
*dev
, unsigned long *_freq
,
131 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
133 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
134 struct dev_pm_opp
*opp
;
135 unsigned long old_freq
, freq
;
139 opp
= devfreq_recommended_opp(dev
, _freq
, flags
);
142 dev_err(dev
, "%s: Invalid OPP.\n", __func__
);
146 freq
= dev_pm_opp_get_freq(opp
);
147 volt
= dev_pm_opp_get_voltage(opp
);
150 old_freq
= data
->curr_freq
;
152 if (old_freq
== freq
)
155 dev_dbg(dev
, "targeting %lukHz %luuV\n", freq
, volt
);
157 mutex_lock(&data
->lock
);
162 if (freq
> exynos5_int_opp_table
[0].clk
)
163 pm_qos_update_request(&data
->int_req
, freq
* 16 / 1000);
165 pm_qos_update_request(&data
->int_req
, -1);
168 err
= exynos5_int_setvolt(data
, volt
);
172 err
= clk_set_rate(data
->int_clk
, freq
* 1000);
178 err
= exynos5_int_setvolt(data
, volt
);
182 data
->curr_freq
= freq
;
184 mutex_unlock(&data
->lock
);
188 static int exynos5_get_busier_dmc(struct busfreq_data_int
*data
)
192 unsigned int temp
= 0;
194 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
195 for (j
= PPMU_PMNCNT0
; j
< PPMU_PMNCNT_MAX
; j
++) {
196 if (data
->ppmu
[i
].count
[j
] > temp
) {
197 temp
= data
->ppmu
[i
].count
[j
];
206 static int exynos5_int_get_dev_status(struct device
*dev
,
207 struct devfreq_dev_status
*stat
)
209 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
211 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
214 exynos5_read_ppmu(data
);
215 busier_dmc
= exynos5_get_busier_dmc(data
);
217 stat
->current_frequency
= data
->curr_freq
;
219 /* Number of cycles spent on memory access */
220 stat
->busy_time
= data
->ppmu
[busier_dmc
].count
[PPMU_PMNCNT3
];
221 stat
->busy_time
*= 100 / INT_BUS_SATURATION_RATIO
;
222 stat
->total_time
= data
->ppmu
[busier_dmc
].ccnt
;
226 static void exynos5_int_exit(struct device
*dev
)
228 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
230 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
232 devfreq_unregister_opp_notifier(dev
, data
->devfreq
);
235 static struct devfreq_dev_profile exynos5_devfreq_int_profile
= {
236 .initial_freq
= 160000,
238 .target
= exynos5_busfreq_int_target
,
239 .get_dev_status
= exynos5_int_get_dev_status
,
240 .exit
= exynos5_int_exit
,
243 static int exynos5250_init_int_tables(struct busfreq_data_int
*data
)
247 for (i
= LV_0
; i
< _LV_END
; i
++) {
248 err
= dev_pm_opp_add(data
->dev
, exynos5_int_opp_table
[i
].clk
,
249 exynos5_int_opp_table
[i
].volt
);
251 dev_err(data
->dev
, "Cannot add opp entries.\n");
259 static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block
*this,
260 unsigned long event
, void *ptr
)
262 struct busfreq_data_int
*data
= container_of(this,
263 struct busfreq_data_int
, pm_notifier
);
264 struct dev_pm_opp
*opp
;
265 unsigned long maxfreq
= ULONG_MAX
;
271 case PM_SUSPEND_PREPARE
:
272 /* Set Fastest and Deactivate DVFS */
273 mutex_lock(&data
->lock
);
275 data
->disabled
= true;
278 opp
= dev_pm_opp_find_freq_floor(data
->dev
, &maxfreq
);
284 freq
= dev_pm_opp_get_freq(opp
);
285 volt
= dev_pm_opp_get_voltage(opp
);
288 err
= exynos5_int_setvolt(data
, volt
);
292 err
= clk_set_rate(data
->int_clk
, freq
* 1000);
297 data
->curr_freq
= freq
;
299 mutex_unlock(&data
->lock
);
303 case PM_POST_RESTORE
:
304 case PM_POST_SUSPEND
:
306 mutex_lock(&data
->lock
);
307 data
->disabled
= false;
308 mutex_unlock(&data
->lock
);
315 static int exynos5_busfreq_int_probe(struct platform_device
*pdev
)
317 struct busfreq_data_int
*data
;
318 struct dev_pm_opp
*opp
;
319 struct device
*dev
= &pdev
->dev
;
320 struct device_node
*np
;
321 unsigned long initial_freq
;
322 unsigned long initial_volt
;
326 data
= devm_kzalloc(&pdev
->dev
, sizeof(struct busfreq_data_int
),
329 dev_err(dev
, "Cannot allocate memory.\n");
333 np
= of_find_compatible_node(NULL
, NULL
, "samsung,exynos5250-ppmu");
335 pr_err("Unable to find PPMU node\n");
339 for (i
= PPMU_RIGHT
; i
< PPMU_END
; i
++) {
340 /* map PPMU memory region */
341 data
->ppmu
[i
].hw_base
= of_iomap(np
, i
);
342 if (data
->ppmu
[i
].hw_base
== NULL
) {
343 dev_err(&pdev
->dev
, "failed to map memory region\n");
347 data
->pm_notifier
.notifier_call
= exynos5_busfreq_int_pm_notifier_event
;
349 mutex_init(&data
->lock
);
351 err
= exynos5250_init_int_tables(data
);
355 data
->vdd_int
= devm_regulator_get(dev
, "vdd_int");
356 if (IS_ERR(data
->vdd_int
)) {
357 dev_err(dev
, "Cannot get the regulator \"vdd_int\"\n");
358 return PTR_ERR(data
->vdd_int
);
361 data
->int_clk
= devm_clk_get(dev
, "int_clk");
362 if (IS_ERR(data
->int_clk
)) {
363 dev_err(dev
, "Cannot get clock \"int_clk\"\n");
364 return PTR_ERR(data
->int_clk
);
368 opp
= dev_pm_opp_find_freq_floor(dev
,
369 &exynos5_devfreq_int_profile
.initial_freq
);
372 dev_err(dev
, "Invalid initial frequency %lu kHz.\n",
373 exynos5_devfreq_int_profile
.initial_freq
);
376 initial_freq
= dev_pm_opp_get_freq(opp
);
377 initial_volt
= dev_pm_opp_get_voltage(opp
);
379 data
->curr_freq
= initial_freq
;
381 err
= clk_set_rate(data
->int_clk
, initial_freq
* 1000);
383 dev_err(dev
, "Failed to set initial frequency\n");
387 err
= exynos5_int_setvolt(data
, initial_volt
);
391 platform_set_drvdata(pdev
, data
);
393 busfreq_mon_reset(data
);
395 data
->devfreq
= devfreq_add_device(dev
, &exynos5_devfreq_int_profile
,
396 "simple_ondemand", NULL
);
398 if (IS_ERR(data
->devfreq
)) {
399 err
= PTR_ERR(data
->devfreq
);
400 goto err_devfreq_add
;
403 devfreq_register_opp_notifier(dev
, data
->devfreq
);
405 err
= register_pm_notifier(&data
->pm_notifier
);
407 dev_err(dev
, "Failed to setup pm notifier\n");
408 goto err_devfreq_add
;
411 /* TODO: Add a new QOS class for int/mif bus */
412 pm_qos_add_request(&data
->int_req
, PM_QOS_NETWORK_THROUGHPUT
, -1);
417 devfreq_remove_device(data
->devfreq
);
421 static int exynos5_busfreq_int_remove(struct platform_device
*pdev
)
423 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
425 pm_qos_remove_request(&data
->int_req
);
426 unregister_pm_notifier(&data
->pm_notifier
);
427 devfreq_remove_device(data
->devfreq
);
432 static int exynos5_busfreq_int_resume(struct device
*dev
)
434 struct platform_device
*pdev
= container_of(dev
, struct platform_device
,
436 struct busfreq_data_int
*data
= platform_get_drvdata(pdev
);
438 busfreq_mon_reset(data
);
442 static const struct dev_pm_ops exynos5_busfreq_int_pm
= {
443 .resume
= exynos5_busfreq_int_resume
,
446 /* platform device pointer for exynos5 devfreq device. */
447 static struct platform_device
*exynos5_devfreq_pdev
;
449 static struct platform_driver exynos5_busfreq_int_driver
= {
450 .probe
= exynos5_busfreq_int_probe
,
451 .remove
= exynos5_busfreq_int_remove
,
453 .name
= "exynos5-bus-int",
454 .owner
= THIS_MODULE
,
455 .pm
= &exynos5_busfreq_int_pm
,
459 static int __init
exynos5_busfreq_int_init(void)
463 ret
= platform_driver_register(&exynos5_busfreq_int_driver
);
467 exynos5_devfreq_pdev
=
468 platform_device_register_simple("exynos5-bus-int", -1, NULL
, 0);
469 if (IS_ERR(exynos5_devfreq_pdev
)) {
470 ret
= PTR_ERR(exynos5_devfreq_pdev
);
476 platform_driver_unregister(&exynos5_busfreq_int_driver
);
480 late_initcall(exynos5_busfreq_int_init
);
482 static void __exit
exynos5_busfreq_int_exit(void)
484 platform_device_unregister(exynos5_devfreq_pdev
);
485 platform_driver_unregister(&exynos5_busfreq_int_driver
);
487 module_exit(exynos5_busfreq_int_exit
);
489 MODULE_LICENSE("GPL");
490 MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");