linux/drivers/devfreq/exynos/exynos5_bus.c
<<
>>
Prefs
   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");
 504