aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2015-11-05 04:29:27 -0500
committerMyungJoo Ham <myungjoo.ham@samsung.com>2016-05-02 22:20:08 -0400
commit403e0689d2a9eb33d9281db4079e964eb65ba9ef (patch)
tree793108b54d22a42f5f145a5d7d1e889f56f32c0c
parent996133119f57334c38b020dbfaaac5b5eb127e29 (diff)
PM / devfreq: exynos: Add support of bus frequency of sub-blocks using passive governor
This patch adds the support of bus frequency feature for sub-blocks which share the one power line. If each bus depends on the power line, each bus is not able to change the voltage by oneself. To optimize the power-consumption on runtime, some buses using the same power line should change the source clock and regulator at the same time. So, this patch uses the passive governor to support the bus frequency for all buses which sharing the one power line. For example, Exynos3250 include the two power line for AXI buses as following: : VDD_MIF : MIF (Memory Interface) provide the DMC (Dynamic Memory Controller) with the power (regulator). : VDD_INT : INT (Internal) provide the various sub-blocks with the power (regulator). Each bus is included in as follwoing block. In the case of VDD_MIF, only DMC bus use the power line. So, there is no any depencency between buese. But, in the case of VDD_INT, various buses share the one power line of VDD_INT. We need to make the depenency between buses. When using passive governor, there is no problem to support the bus frequency as DVFS for all buses. One bus should be operated as the parent bus device which gathering the current load of INT block and then decides the new frequency with some governors except of passive governor. After deciding the new frequency by the parent bus device, the rest bus devices will change the each source clock according to new frequency of the parent bus device. - MIF (Memory Interface) block : VDD_MIF |--- DMC - INT (Internal) block : VDD_INT |--- LEFTBUS (parent) |--- PERIL |--- MFC |--- G3D |--- RIGHTBUS |--- FSYS |--- LCD0 |--- PERIR |--- ISP |--- CAM Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> [tjakobi: Reported debugfs error during booting and cw00.choi fix it.] Reported-by: Tobias Jakobi <tjakobi@math.uni-bielefeld.de> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Acked-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
-rw-r--r--drivers/devfreq/Kconfig1
-rw-r--r--drivers/devfreq/exynos-bus.c219
2 files changed, 174 insertions, 46 deletions
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index d260cd0219f6..30e1daf1c827 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -78,6 +78,7 @@ config ARM_EXYNOS_BUS_DEVFREQ
78 bool "ARM EXYNOS Generic Memory Bus DEVFREQ Driver" 78 bool "ARM EXYNOS Generic Memory Bus DEVFREQ Driver"
79 depends on ARCH_EXYNOS 79 depends on ARCH_EXYNOS
80 select DEVFREQ_GOV_SIMPLE_ONDEMAND 80 select DEVFREQ_GOV_SIMPLE_ONDEMAND
81 select DEVFREQ_GOV_PASSIVE
81 select DEVFREQ_EVENT_EXYNOS_PPMU 82 select DEVFREQ_EVENT_EXYNOS_PPMU
82 select PM_DEVFREQ_EVENT 83 select PM_DEVFREQ_EVENT
83 select PM_OPP 84 select PM_OPP
diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c
index 137de6196af3..50fe1a16c574 100644
--- a/drivers/devfreq/exynos-bus.c
+++ b/drivers/devfreq/exynos-bus.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Generic Exynos Bus frequency driver with DEVFREQ Framework 2 * Generic Exynos Bus frequency driver with DEVFREQ Framework
3 * 3 *
4 * Copyright (c) 2015 Samsung Electronics Co., Ltd. 4 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
5 * Author : Chanwoo Choi <cw00.choi@samsung.com> 5 * Author : Chanwoo Choi <cw00.choi@samsung.com>
6 * 6 *
7 * This driver support Exynos Bus frequency feature by using 7 * This driver support Exynos Bus frequency feature by using
@@ -93,7 +93,7 @@ static int exynos_bus_get_event(struct exynos_bus *bus,
93} 93}
94 94
95/* 95/*
96 * Must necessary function for devfreq governor 96 * Must necessary function for devfreq simple-ondemand governor
97 */ 97 */
98static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags) 98static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
99{ 99{
@@ -202,59 +202,81 @@ static void exynos_bus_exit(struct device *dev)
202 regulator_disable(bus->regulator); 202 regulator_disable(bus->regulator);
203 203
204 dev_pm_opp_of_remove_table(dev); 204 dev_pm_opp_of_remove_table(dev);
205 clk_disable_unprepare(bus->clk);
205} 206}
206 207
207static int exynos_bus_parse_of(struct device_node *np, 208/*
208 struct exynos_bus *bus) 209 * Must necessary function for devfreq passive governor
210 */
211static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
212 u32 flags)
209{ 213{
210 struct device *dev = bus->dev; 214 struct exynos_bus *bus = dev_get_drvdata(dev);
211 unsigned long rate; 215 struct dev_pm_opp *new_opp;
212 int i, ret, count, size; 216 unsigned long old_freq, new_freq;
217 int ret = 0;
213 218
214 /* Get the clock to provide each bus with source clock */ 219 /* Get new opp-bus instance according to new bus clock */
215 bus->clk = devm_clk_get(dev, "bus"); 220 rcu_read_lock();
216 if (IS_ERR(bus->clk)) { 221 new_opp = devfreq_recommended_opp(dev, freq, flags);
217 dev_err(dev, "failed to get bus clock\n"); 222 if (IS_ERR(new_opp)) {
218 return PTR_ERR(bus->clk); 223 dev_err(dev, "failed to get recommended opp instance\n");
224 rcu_read_unlock();
225 return PTR_ERR(new_opp);
219 } 226 }
220 227
221 ret = clk_prepare_enable(bus->clk); 228 new_freq = dev_pm_opp_get_freq(new_opp);
222 if (ret < 0) { 229 old_freq = dev_pm_opp_get_freq(bus->curr_opp);
223 dev_err(dev, "failed to get enable clock\n"); 230 rcu_read_unlock();
224 return ret;
225 }
226 231
227 /* Get the freq/voltage OPP table to scale the bus frequency */ 232 if (old_freq == new_freq)
228 rcu_read_lock(); 233 return 0;
229 ret = dev_pm_opp_of_add_table(dev); 234
235 /* Change the frequency according to new OPP level */
236 mutex_lock(&bus->lock);
237
238 ret = clk_set_rate(bus->clk, new_freq);
230 if (ret < 0) { 239 if (ret < 0) {
231 dev_err(dev, "failed to get OPP table\n"); 240 dev_err(dev, "failed to set the clock of bus\n");
232 rcu_read_unlock(); 241 goto out;
233 goto err_clk;
234 } 242 }
235 243
236 rate = clk_get_rate(bus->clk); 244 *freq = new_freq;
237 bus->curr_opp = dev_pm_opp_find_freq_ceil(dev, &rate); 245 bus->curr_opp = new_opp;
238 if (IS_ERR(bus->curr_opp)) { 246
239 dev_err(dev, "failed to find dev_pm_opp\n"); 247 dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n",
240 rcu_read_unlock(); 248 old_freq/1000, new_freq/1000);
241 ret = PTR_ERR(bus->curr_opp); 249out:
242 goto err_opp; 250 mutex_unlock(&bus->lock);
243 } 251
244 rcu_read_unlock(); 252 return ret;
253}
254
255static void exynos_bus_passive_exit(struct device *dev)
256{
257 struct exynos_bus *bus = dev_get_drvdata(dev);
258
259 dev_pm_opp_of_remove_table(dev);
260 clk_disable_unprepare(bus->clk);
261}
262
263static int exynos_bus_parent_parse_of(struct device_node *np,
264 struct exynos_bus *bus)
265{
266 struct device *dev = bus->dev;
267 int i, ret, count, size;
245 268
246 /* Get the regulator to provide each bus with the power */ 269 /* Get the regulator to provide each bus with the power */
247 bus->regulator = devm_regulator_get(dev, "vdd"); 270 bus->regulator = devm_regulator_get(dev, "vdd");
248 if (IS_ERR(bus->regulator)) { 271 if (IS_ERR(bus->regulator)) {
249 dev_err(dev, "failed to get VDD regulator\n"); 272 dev_err(dev, "failed to get VDD regulator\n");
250 ret = PTR_ERR(bus->regulator); 273 return PTR_ERR(bus->regulator);
251 goto err_opp;
252 } 274 }
253 275
254 ret = regulator_enable(bus->regulator); 276 ret = regulator_enable(bus->regulator);
255 if (ret < 0) { 277 if (ret < 0) {
256 dev_err(dev, "failed to enable VDD regulator\n"); 278 dev_err(dev, "failed to enable VDD regulator\n");
257 goto err_opp; 279 return ret;
258 } 280 }
259 281
260 /* 282 /*
@@ -305,6 +327,51 @@ static int exynos_bus_parse_of(struct device_node *np,
305 327
306err_regulator: 328err_regulator:
307 regulator_disable(bus->regulator); 329 regulator_disable(bus->regulator);
330
331 return ret;
332}
333
334static int exynos_bus_parse_of(struct device_node *np,
335 struct exynos_bus *bus)
336{
337 struct device *dev = bus->dev;
338 unsigned long rate;
339 int ret;
340
341 /* Get the clock to provide each bus with source clock */
342 bus->clk = devm_clk_get(dev, "bus");
343 if (IS_ERR(bus->clk)) {
344 dev_err(dev, "failed to get bus clock\n");
345 return PTR_ERR(bus->clk);
346 }
347
348 ret = clk_prepare_enable(bus->clk);
349 if (ret < 0) {
350 dev_err(dev, "failed to get enable clock\n");
351 return ret;
352 }
353
354 /* Get the freq and voltage from OPP table to scale the bus freq */
355 rcu_read_lock();
356 ret = dev_pm_opp_of_add_table(dev);
357 if (ret < 0) {
358 dev_err(dev, "failed to get OPP table\n");
359 rcu_read_unlock();
360 goto err_clk;
361 }
362
363 rate = clk_get_rate(bus->clk);
364 bus->curr_opp = devfreq_recommended_opp(dev, &rate, 0);
365 if (IS_ERR(bus->curr_opp)) {
366 dev_err(dev, "failed to find dev_pm_opp\n");
367 rcu_read_unlock();
368 ret = PTR_ERR(bus->curr_opp);
369 goto err_opp;
370 }
371 rcu_read_unlock();
372
373 return 0;
374
308err_opp: 375err_opp:
309 dev_pm_opp_of_remove_table(dev); 376 dev_pm_opp_of_remove_table(dev);
310err_clk: 377err_clk:
@@ -319,8 +386,11 @@ static int exynos_bus_probe(struct platform_device *pdev)
319 struct device_node *np = dev->of_node; 386 struct device_node *np = dev->of_node;
320 struct devfreq_dev_profile *profile; 387 struct devfreq_dev_profile *profile;
321 struct devfreq_simple_ondemand_data *ondemand_data; 388 struct devfreq_simple_ondemand_data *ondemand_data;
389 struct devfreq_passive_data *passive_data;
390 struct devfreq *parent_devfreq;
322 struct exynos_bus *bus; 391 struct exynos_bus *bus;
323 int ret; 392 int ret, max_state;
393 unsigned long min_freq, max_freq;
324 394
325 if (!np) { 395 if (!np) {
326 dev_err(dev, "failed to find devicetree node\n"); 396 dev_err(dev, "failed to find devicetree node\n");
@@ -337,20 +407,33 @@ static int exynos_bus_probe(struct platform_device *pdev)
337 /* Parse the device-tree to get the resource information */ 407 /* Parse the device-tree to get the resource information */
338 ret = exynos_bus_parse_of(np, bus); 408 ret = exynos_bus_parse_of(np, bus);
339 if (ret < 0) 409 if (ret < 0)
340 return ret; 410 goto err;
341 411
342 /* Initalize the struct profile and governor data */
343 profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL); 412 profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
344 if (!profile) 413 if (!profile) {
345 return -ENOMEM; 414 ret = -ENOMEM;
415 goto err;
416 }
417
418 if (of_parse_phandle(dev->of_node, "devfreq", 0))
419 goto passive;
420 else
421 ret = exynos_bus_parent_parse_of(np, bus);
422
423 if (ret < 0)
424 goto err;
425
426 /* Initalize the struct profile and governor data for parent device */
346 profile->polling_ms = 50; 427 profile->polling_ms = 50;
347 profile->target = exynos_bus_target; 428 profile->target = exynos_bus_target;
348 profile->get_dev_status = exynos_bus_get_dev_status; 429 profile->get_dev_status = exynos_bus_get_dev_status;
349 profile->exit = exynos_bus_exit; 430 profile->exit = exynos_bus_exit;
350 431
351 ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL); 432 ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL);
352 if (!ondemand_data) 433 if (!ondemand_data) {
353 return -ENOMEM; 434 ret = -ENOMEM;
435 goto err;
436 }
354 ondemand_data->upthreshold = 40; 437 ondemand_data->upthreshold = 40;
355 ondemand_data->downdifferential = 5; 438 ondemand_data->downdifferential = 5;
356 439
@@ -359,14 +442,15 @@ static int exynos_bus_probe(struct platform_device *pdev)
359 ondemand_data); 442 ondemand_data);
360 if (IS_ERR(bus->devfreq)) { 443 if (IS_ERR(bus->devfreq)) {
361 dev_err(dev, "failed to add devfreq device\n"); 444 dev_err(dev, "failed to add devfreq device\n");
362 return PTR_ERR(bus->devfreq); 445 ret = PTR_ERR(bus->devfreq);
446 goto err;
363 } 447 }
364 448
365 /* Register opp_notifier to catch the change of OPP */ 449 /* Register opp_notifier to catch the change of OPP */
366 ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq); 450 ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq);
367 if (ret < 0) { 451 if (ret < 0) {
368 dev_err(dev, "failed to register opp notifier\n"); 452 dev_err(dev, "failed to register opp notifier\n");
369 return ret; 453 goto err;
370 } 454 }
371 455
372 /* 456 /*
@@ -376,16 +460,59 @@ static int exynos_bus_probe(struct platform_device *pdev)
376 ret = exynos_bus_enable_edev(bus); 460 ret = exynos_bus_enable_edev(bus);
377 if (ret < 0) { 461 if (ret < 0) {
378 dev_err(dev, "failed to enable devfreq-event devices\n"); 462 dev_err(dev, "failed to enable devfreq-event devices\n");
379 return ret; 463 goto err;
380 } 464 }
381 465
382 ret = exynos_bus_set_event(bus); 466 ret = exynos_bus_set_event(bus);
383 if (ret < 0) { 467 if (ret < 0) {
384 dev_err(dev, "failed to set event to devfreq-event devices\n"); 468 dev_err(dev, "failed to set event to devfreq-event devices\n");
385 return ret; 469 goto err;
386 } 470 }
387 471
472 goto out;
473passive:
474 /* Initalize the struct profile and governor data for passive device */
475 profile->target = exynos_bus_passive_target;
476 profile->exit = exynos_bus_passive_exit;
477
478 /* Get the instance of parent devfreq device */
479 parent_devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
480 if (IS_ERR(parent_devfreq)) {
481 ret = -EPROBE_DEFER;
482 goto err;
483 }
484
485 passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
486 if (!passive_data) {
487 ret = -ENOMEM;
488 goto err;
489 }
490 passive_data->parent = parent_devfreq;
491
492 /* Add devfreq device for exynos bus with passive governor */
493 bus->devfreq = devm_devfreq_add_device(dev, profile, "passive",
494 passive_data);
495 if (IS_ERR(bus->devfreq)) {
496 dev_err(dev,
497 "failed to add devfreq dev with passive governor\n");
498 ret = -EPROBE_DEFER;
499 goto err;
500 }
501
502out:
503 max_state = bus->devfreq->profile->max_state;
504 min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
505 max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
506 pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",
507 dev_name(dev), min_freq, max_freq);
508
388 return 0; 509 return 0;
510
511err:
512 dev_pm_opp_of_remove_table(dev);
513 clk_disable_unprepare(bus->clk);
514
515 return ret;
389} 516}
390 517
391#ifdef CONFIG_PM_SLEEP 518#ifdef CONFIG_PM_SLEEP