Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.14-rc4 490 lines 12 kB view raw
1/* 2 * Copyright (c) 2012 Samsung Electronics Co., Ltd. 3 * http://www.samsung.com/ 4 * 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. 8 * 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. 12 * 13 */ 14 15#include <linux/module.h> 16#include <linux/devfreq.h> 17#include <linux/io.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> 28 29#include "exynos_ppmu.h" 30 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 34 35enum int_level_idx { 36 LV_0, 37 LV_1, 38 LV_2, 39 LV_3, 40 LV_4, 41 _LV_END 42}; 43 44enum exynos_ppmu_list { 45 PPMU_RIGHT, 46 PPMU_END, 47}; 48 49struct busfreq_data_int { 50 struct device *dev; 51 struct devfreq *devfreq; 52 struct regulator *vdd_int; 53 struct exynos_ppmu ppmu[PPMU_END]; 54 unsigned long curr_freq; 55 bool disabled; 56 57 struct notifier_block pm_notifier; 58 struct mutex lock; 59 struct pm_qos_request int_req; 60 struct clk *int_clk; 61}; 62 63struct int_bus_opp_table { 64 unsigned int idx; 65 unsigned long clk; 66 unsigned long volt; 67}; 68 69static 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}, 75 {0, 0, 0}, 76}; 77 78static void busfreq_mon_reset(struct busfreq_data_int *data) 79{ 80 unsigned int i; 81 82 for (i = PPMU_RIGHT; i < PPMU_END; i++) { 83 void __iomem *ppmu_base = data->ppmu[i].hw_base; 84 85 /* Reset the performance and cycle counters */ 86 exynos_ppmu_reset(ppmu_base); 87 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]); 92 93 exynos_ppmu_start(ppmu_base); 94 } 95} 96 97static void exynos5_read_ppmu(struct busfreq_data_int *data) 98{ 99 int i, j; 100 101 for (i = PPMU_RIGHT; i < PPMU_END; i++) { 102 void __iomem *ppmu_base = data->ppmu[i].hw_base; 103 104 exynos_ppmu_stop(ppmu_base); 105 106 /* Update local data from PPMU */ 107 data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT); 108 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; 112 else 113 data->ppmu[i].count[j] = 114 exynos_ppmu_read(ppmu_base, j); 115 } 116 } 117 118 busfreq_mon_reset(data); 119} 120 121static int exynos5_int_setvolt(struct busfreq_data_int *data, 122 unsigned long volt) 123{ 124 return regulator_set_voltage(data->vdd_int, volt, MAX_SAFEVOLT); 125} 126 127static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq, 128 u32 flags) 129{ 130 int err = 0; 131 struct platform_device *pdev = container_of(dev, struct platform_device, 132 dev); 133 struct busfreq_data_int *data = platform_get_drvdata(pdev); 134 struct dev_pm_opp *opp; 135 unsigned long old_freq, freq; 136 unsigned long volt; 137 138 rcu_read_lock(); 139 opp = devfreq_recommended_opp(dev, _freq, flags); 140 if (IS_ERR(opp)) { 141 rcu_read_unlock(); 142 dev_err(dev, "%s: Invalid OPP.\n", __func__); 143 return PTR_ERR(opp); 144 } 145 146 freq = dev_pm_opp_get_freq(opp); 147 volt = dev_pm_opp_get_voltage(opp); 148 rcu_read_unlock(); 149 150 old_freq = data->curr_freq; 151 152 if (old_freq == freq) 153 return 0; 154 155 dev_dbg(dev, "targeting %lukHz %luuV\n", freq, volt); 156 157 mutex_lock(&data->lock); 158 159 if (data->disabled) 160 goto out; 161 162 if (freq > exynos5_int_opp_table[0].clk) 163 pm_qos_update_request(&data->int_req, freq * 16 / 1000); 164 else 165 pm_qos_update_request(&data->int_req, -1); 166 167 if (old_freq < freq) 168 err = exynos5_int_setvolt(data, volt); 169 if (err) 170 goto out; 171 172 err = clk_set_rate(data->int_clk, freq * 1000); 173 174 if (err) 175 goto out; 176 177 if (old_freq > freq) 178 err = exynos5_int_setvolt(data, volt); 179 if (err) 180 goto out; 181 182 data->curr_freq = freq; 183out: 184 mutex_unlock(&data->lock); 185 return err; 186} 187 188static int exynos5_get_busier_dmc(struct busfreq_data_int *data) 189{ 190 int i, j; 191 int busy = 0; 192 unsigned int temp = 0; 193 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]; 198 busy = i; 199 } 200 } 201 } 202 203 return busy; 204} 205 206static int exynos5_int_get_dev_status(struct device *dev, 207 struct devfreq_dev_status *stat) 208{ 209 struct platform_device *pdev = container_of(dev, struct platform_device, 210 dev); 211 struct busfreq_data_int *data = platform_get_drvdata(pdev); 212 int busier_dmc; 213 214 exynos5_read_ppmu(data); 215 busier_dmc = exynos5_get_busier_dmc(data); 216 217 stat->current_frequency = data->curr_freq; 218 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; 223 224 return 0; 225} 226static void exynos5_int_exit(struct device *dev) 227{ 228 struct platform_device *pdev = container_of(dev, struct platform_device, 229 dev); 230 struct busfreq_data_int *data = platform_get_drvdata(pdev); 231 232 devfreq_unregister_opp_notifier(dev, data->devfreq); 233} 234 235static struct devfreq_dev_profile exynos5_devfreq_int_profile = { 236 .initial_freq = 160000, 237 .polling_ms = 100, 238 .target = exynos5_busfreq_int_target, 239 .get_dev_status = exynos5_int_get_dev_status, 240 .exit = exynos5_int_exit, 241}; 242 243static int exynos5250_init_int_tables(struct busfreq_data_int *data) 244{ 245 int i, err = 0; 246 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); 250 if (err) { 251 dev_err(data->dev, "Cannot add opp entries.\n"); 252 return err; 253 } 254 } 255 256 return 0; 257} 258 259static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this, 260 unsigned long event, void *ptr) 261{ 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; 266 unsigned long freq; 267 unsigned long volt; 268 int err = 0; 269 270 switch (event) { 271 case PM_SUSPEND_PREPARE: 272 /* Set Fastest and Deactivate DVFS */ 273 mutex_lock(&data->lock); 274 275 data->disabled = true; 276 277 rcu_read_lock(); 278 opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq); 279 if (IS_ERR(opp)) { 280 rcu_read_unlock(); 281 err = PTR_ERR(opp); 282 goto unlock; 283 } 284 freq = dev_pm_opp_get_freq(opp); 285 volt = dev_pm_opp_get_voltage(opp); 286 rcu_read_unlock(); 287 288 err = exynos5_int_setvolt(data, volt); 289 if (err) 290 goto unlock; 291 292 err = clk_set_rate(data->int_clk, freq * 1000); 293 294 if (err) 295 goto unlock; 296 297 data->curr_freq = freq; 298unlock: 299 mutex_unlock(&data->lock); 300 if (err) 301 return NOTIFY_BAD; 302 return NOTIFY_OK; 303 case PM_POST_RESTORE: 304 case PM_POST_SUSPEND: 305 /* Reactivate */ 306 mutex_lock(&data->lock); 307 data->disabled = false; 308 mutex_unlock(&data->lock); 309 return NOTIFY_OK; 310 } 311 312 return NOTIFY_DONE; 313} 314 315static int exynos5_busfreq_int_probe(struct platform_device *pdev) 316{ 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; 323 int err = 0; 324 int i; 325 326 data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_int), 327 GFP_KERNEL); 328 if (data == NULL) { 329 dev_err(dev, "Cannot allocate memory.\n"); 330 return -ENOMEM; 331 } 332 333 np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-ppmu"); 334 if (np == NULL) { 335 pr_err("Unable to find PPMU node\n"); 336 return -ENOENT; 337 } 338 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"); 344 return -ENOMEM; 345 } 346 } 347 data->pm_notifier.notifier_call = exynos5_busfreq_int_pm_notifier_event; 348 data->dev = dev; 349 mutex_init(&data->lock); 350 351 err = exynos5250_init_int_tables(data); 352 if (err) 353 return err; 354 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); 359 } 360 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); 365 } 366 367 rcu_read_lock(); 368 opp = dev_pm_opp_find_freq_floor(dev, 369 &exynos5_devfreq_int_profile.initial_freq); 370 if (IS_ERR(opp)) { 371 rcu_read_unlock(); 372 dev_err(dev, "Invalid initial frequency %lu kHz.\n", 373 exynos5_devfreq_int_profile.initial_freq); 374 return PTR_ERR(opp); 375 } 376 initial_freq = dev_pm_opp_get_freq(opp); 377 initial_volt = dev_pm_opp_get_voltage(opp); 378 rcu_read_unlock(); 379 data->curr_freq = initial_freq; 380 381 err = clk_set_rate(data->int_clk, initial_freq * 1000); 382 if (err) { 383 dev_err(dev, "Failed to set initial frequency\n"); 384 return err; 385 } 386 387 err = exynos5_int_setvolt(data, initial_volt); 388 if (err) 389 return err; 390 391 platform_set_drvdata(pdev, data); 392 393 busfreq_mon_reset(data); 394 395 data->devfreq = devfreq_add_device(dev, &exynos5_devfreq_int_profile, 396 "simple_ondemand", NULL); 397 398 if (IS_ERR(data->devfreq)) { 399 err = PTR_ERR(data->devfreq); 400 goto err_devfreq_add; 401 } 402 403 devfreq_register_opp_notifier(dev, data->devfreq); 404 405 err = register_pm_notifier(&data->pm_notifier); 406 if (err) { 407 dev_err(dev, "Failed to setup pm notifier\n"); 408 goto err_devfreq_add; 409 } 410 411 /* TODO: Add a new QOS class for int/mif bus */ 412 pm_qos_add_request(&data->int_req, PM_QOS_NETWORK_THROUGHPUT, -1); 413 414 return 0; 415 416err_devfreq_add: 417 devfreq_remove_device(data->devfreq); 418 return err; 419} 420 421static int exynos5_busfreq_int_remove(struct platform_device *pdev) 422{ 423 struct busfreq_data_int *data = platform_get_drvdata(pdev); 424 425 pm_qos_remove_request(&data->int_req); 426 unregister_pm_notifier(&data->pm_notifier); 427 devfreq_remove_device(data->devfreq); 428 429 return 0; 430} 431 432static int exynos5_busfreq_int_resume(struct device *dev) 433{ 434 struct platform_device *pdev = container_of(dev, struct platform_device, 435 dev); 436 struct busfreq_data_int *data = platform_get_drvdata(pdev); 437 438 busfreq_mon_reset(data); 439 return 0; 440} 441 442static const struct dev_pm_ops exynos5_busfreq_int_pm = { 443 .resume = exynos5_busfreq_int_resume, 444}; 445 446/* platform device pointer for exynos5 devfreq device. */ 447static struct platform_device *exynos5_devfreq_pdev; 448 449static struct platform_driver exynos5_busfreq_int_driver = { 450 .probe = exynos5_busfreq_int_probe, 451 .remove = exynos5_busfreq_int_remove, 452 .driver = { 453 .name = "exynos5-bus-int", 454 .owner = THIS_MODULE, 455 .pm = &exynos5_busfreq_int_pm, 456 }, 457}; 458 459static int __init exynos5_busfreq_int_init(void) 460{ 461 int ret; 462 463 ret = platform_driver_register(&exynos5_busfreq_int_driver); 464 if (ret < 0) 465 goto out; 466 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); 471 goto out1; 472 } 473 474 return 0; 475out1: 476 platform_driver_unregister(&exynos5_busfreq_int_driver); 477out: 478 return ret; 479} 480late_initcall(exynos5_busfreq_int_init); 481 482static void __exit exynos5_busfreq_int_exit(void) 483{ 484 platform_device_unregister(exynos5_devfreq_pdev); 485 platform_driver_unregister(&exynos5_busfreq_int_driver); 486} 487module_exit(exynos5_busfreq_int_exit); 488 489MODULE_LICENSE("GPL"); 490MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");