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