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/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 busfreq_ppmu_data ppmu_data;
  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 int exynos5_int_setvolt(struct busfreq_data_int *data,
  79                                unsigned long volt)
  80{
  81        return regulator_set_voltage(data->vdd_int, volt, MAX_SAFEVOLT);
  82}
  83
  84static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
  85                              u32 flags)
  86{
  87        int err = 0;
  88        struct platform_device *pdev = container_of(dev, struct platform_device,
  89                                                    dev);
  90        struct busfreq_data_int *data = platform_get_drvdata(pdev);
  91        struct dev_pm_opp *opp;
  92        unsigned long old_freq, freq;
  93        unsigned long volt;
  94
  95        rcu_read_lock();
  96        opp = devfreq_recommended_opp(dev, _freq, flags);
  97        if (IS_ERR(opp)) {
  98                rcu_read_unlock();
  99                dev_err(dev, "%s: Invalid OPP.\n", __func__);
 100                return PTR_ERR(opp);
 101        }
 102
 103        freq = dev_pm_opp_get_freq(opp);
 104        volt = dev_pm_opp_get_voltage(opp);
 105        rcu_read_unlock();
 106
 107        old_freq = data->curr_freq;
 108
 109        if (old_freq == freq)
 110                return 0;
 111
 112        dev_dbg(dev, "targeting %lukHz %luuV\n", freq, volt);
 113
 114        mutex_lock(&data->lock);
 115
 116        if (data->disabled)
 117                goto out;
 118
 119        if (freq > exynos5_int_opp_table[0].clk)
 120                pm_qos_update_request(&data->int_req, freq * 16 / 1000);
 121        else
 122                pm_qos_update_request(&data->int_req, -1);
 123
 124        if (old_freq < freq)
 125                err = exynos5_int_setvolt(data, volt);
 126        if (err)
 127                goto out;
 128
 129        err = clk_set_rate(data->int_clk, freq * 1000);
 130
 131        if (err)
 132                goto out;
 133
 134        if (old_freq > freq)
 135                err = exynos5_int_setvolt(data, volt);
 136        if (err)
 137                goto out;
 138
 139        data->curr_freq = freq;
 140out:
 141        mutex_unlock(&data->lock);
 142        return err;
 143}
 144
 145static int exynos5_int_get_dev_status(struct device *dev,
 146                                      struct devfreq_dev_status *stat)
 147{
 148        struct platform_device *pdev = container_of(dev, struct platform_device,
 149                                                    dev);
 150        struct busfreq_data_int *data = platform_get_drvdata(pdev);
 151        struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
 152        int busier_dmc;
 153
 154        exynos_read_ppmu(ppmu_data);
 155        busier_dmc = exynos_get_busier_ppmu(ppmu_data);
 156
 157        stat->current_frequency = data->curr_freq;
 158
 159        /* Number of cycles spent on memory access */
 160        stat->busy_time = ppmu_data->ppmu[busier_dmc].count[PPMU_PMNCNT3];
 161        stat->busy_time *= 100 / INT_BUS_SATURATION_RATIO;
 162        stat->total_time = ppmu_data->ppmu[busier_dmc].ccnt;
 163
 164        return 0;
 165}
 166
 167static struct devfreq_dev_profile exynos5_devfreq_int_profile = {
 168        .initial_freq           = 160000,
 169        .polling_ms             = 100,
 170        .target                 = exynos5_busfreq_int_target,
 171        .get_dev_status         = exynos5_int_get_dev_status,
 172};
 173
 174static int exynos5250_init_int_tables(struct busfreq_data_int *data)
 175{
 176        int i, err = 0;
 177
 178        for (i = LV_0; i < _LV_END; i++) {
 179                err = dev_pm_opp_add(data->dev, exynos5_int_opp_table[i].clk,
 180                                exynos5_int_opp_table[i].volt);
 181                if (err) {
 182                        dev_err(data->dev, "Cannot add opp entries.\n");
 183                        return err;
 184                }
 185        }
 186
 187        return 0;
 188}
 189
 190static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this,
 191                unsigned long event, void *ptr)
 192{
 193        struct busfreq_data_int *data = container_of(this,
 194                                        struct busfreq_data_int, pm_notifier);
 195        struct dev_pm_opp *opp;
 196        unsigned long maxfreq = ULONG_MAX;
 197        unsigned long freq;
 198        unsigned long volt;
 199        int err = 0;
 200
 201        switch (event) {
 202        case PM_SUSPEND_PREPARE:
 203                /* Set Fastest and Deactivate DVFS */
 204                mutex_lock(&data->lock);
 205
 206                data->disabled = true;
 207
 208                rcu_read_lock();
 209                opp = dev_pm_opp_find_freq_floor(data->dev, &maxfreq);
 210                if (IS_ERR(opp)) {
 211                        rcu_read_unlock();
 212                        err = PTR_ERR(opp);
 213                        goto unlock;
 214                }
 215                freq = dev_pm_opp_get_freq(opp);
 216                volt = dev_pm_opp_get_voltage(opp);
 217                rcu_read_unlock();
 218
 219                err = exynos5_int_setvolt(data, volt);
 220                if (err)
 221                        goto unlock;
 222
 223                err = clk_set_rate(data->int_clk, freq * 1000);
 224
 225                if (err)
 226                        goto unlock;
 227
 228                data->curr_freq = freq;
 229unlock:
 230                mutex_unlock(&data->lock);
 231                if (err)
 232                        return NOTIFY_BAD;
 233                return NOTIFY_OK;
 234        case PM_POST_RESTORE:
 235        case PM_POST_SUSPEND:
 236                /* Reactivate */
 237                mutex_lock(&data->lock);
 238                data->disabled = false;
 239                mutex_unlock(&data->lock);
 240                return NOTIFY_OK;
 241        }
 242
 243        return NOTIFY_DONE;
 244}
 245
 246static int exynos5_busfreq_int_probe(struct platform_device *pdev)
 247{
 248        struct busfreq_data_int *data;
 249        struct busfreq_ppmu_data *ppmu_data;
 250        struct dev_pm_opp *opp;
 251        struct device *dev = &pdev->dev;
 252        struct device_node *np;
 253        unsigned long initial_freq;
 254        unsigned long initial_volt;
 255        int err = 0;
 256        int i;
 257
 258        data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_int),
 259                                GFP_KERNEL);
 260        if (data == NULL) {
 261                dev_err(dev, "Cannot allocate memory.\n");
 262                return -ENOMEM;
 263        }
 264
 265        ppmu_data = &data->ppmu_data;
 266        ppmu_data->ppmu_end = PPMU_END;
 267        ppmu_data->ppmu = devm_kzalloc(dev,
 268                                       sizeof(struct exynos_ppmu) * PPMU_END,
 269                                       GFP_KERNEL);
 270        if (!ppmu_data->ppmu) {
 271                dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
 272                return -ENOMEM;
 273        }
 274
 275        np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-ppmu");
 276        if (np == NULL) {
 277                pr_err("Unable to find PPMU node\n");
 278                return -ENOENT;
 279        }
 280
 281        for (i = 0; i < ppmu_data->ppmu_end; i++) {
 282                /* map PPMU memory region */
 283                ppmu_data->ppmu[i].hw_base = of_iomap(np, i);
 284                if (ppmu_data->ppmu[i].hw_base == NULL) {
 285                        dev_err(&pdev->dev, "failed to map memory region\n");
 286                        return -ENOMEM;
 287                }
 288        }
 289        data->pm_notifier.notifier_call = exynos5_busfreq_int_pm_notifier_event;
 290        data->dev = dev;
 291        mutex_init(&data->lock);
 292
 293        err = exynos5250_init_int_tables(data);
 294        if (err)
 295                return err;
 296
 297        data->vdd_int = devm_regulator_get(dev, "vdd_int");
 298        if (IS_ERR(data->vdd_int)) {
 299                dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
 300                return PTR_ERR(data->vdd_int);
 301        }
 302
 303        data->int_clk = devm_clk_get(dev, "int_clk");
 304        if (IS_ERR(data->int_clk)) {
 305                dev_err(dev, "Cannot get clock \"int_clk\"\n");
 306                return PTR_ERR(data->int_clk);
 307        }
 308
 309        rcu_read_lock();
 310        opp = dev_pm_opp_find_freq_floor(dev,
 311                        &exynos5_devfreq_int_profile.initial_freq);
 312        if (IS_ERR(opp)) {
 313                rcu_read_unlock();
 314                dev_err(dev, "Invalid initial frequency %lu kHz.\n",
 315                       exynos5_devfreq_int_profile.initial_freq);
 316                return PTR_ERR(opp);
 317        }
 318        initial_freq = dev_pm_opp_get_freq(opp);
 319        initial_volt = dev_pm_opp_get_voltage(opp);
 320        rcu_read_unlock();
 321        data->curr_freq = initial_freq;
 322
 323        err = clk_set_rate(data->int_clk, initial_freq * 1000);
 324        if (err) {
 325                dev_err(dev, "Failed to set initial frequency\n");
 326                return err;
 327        }
 328
 329        err = exynos5_int_setvolt(data, initial_volt);
 330        if (err)
 331                return err;
 332
 333        platform_set_drvdata(pdev, data);
 334
 335        busfreq_mon_reset(ppmu_data);
 336
 337        data->devfreq = devm_devfreq_add_device(dev, &exynos5_devfreq_int_profile,
 338                                           "simple_ondemand", NULL);
 339        if (IS_ERR(data->devfreq))
 340                return PTR_ERR(data->devfreq);
 341
 342        err = devm_devfreq_register_opp_notifier(dev, data->devfreq);
 343        if (err < 0) {
 344                dev_err(dev, "Failed to register opp notifier\n");
 345                return err;
 346        }
 347
 348        err = register_pm_notifier(&data->pm_notifier);
 349        if (err) {
 350                dev_err(dev, "Failed to setup pm notifier\n");
 351                return err;
 352        }
 353
 354        /* TODO: Add a new QOS class for int/mif bus */
 355        pm_qos_add_request(&data->int_req, PM_QOS_NETWORK_THROUGHPUT, -1);
 356
 357        return 0;
 358}
 359
 360static int exynos5_busfreq_int_remove(struct platform_device *pdev)
 361{
 362        struct busfreq_data_int *data = platform_get_drvdata(pdev);
 363
 364        pm_qos_remove_request(&data->int_req);
 365        unregister_pm_notifier(&data->pm_notifier);
 366
 367        return 0;
 368}
 369
 370#ifdef CONFIG_PM_SLEEP
 371static int exynos5_busfreq_int_resume(struct device *dev)
 372{
 373        struct platform_device *pdev = container_of(dev, struct platform_device,
 374                                                    dev);
 375        struct busfreq_data_int *data = platform_get_drvdata(pdev);
 376        struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
 377
 378        busfreq_mon_reset(ppmu_data);
 379        return 0;
 380}
 381static const struct dev_pm_ops exynos5_busfreq_int_pm = {
 382        .resume = exynos5_busfreq_int_resume,
 383};
 384#endif
 385static SIMPLE_DEV_PM_OPS(exynos5_busfreq_int_pm_ops, NULL,
 386                         exynos5_busfreq_int_resume);
 387
 388/* platform device pointer for exynos5 devfreq device. */
 389static struct platform_device *exynos5_devfreq_pdev;
 390
 391static struct platform_driver exynos5_busfreq_int_driver = {
 392        .probe          = exynos5_busfreq_int_probe,
 393        .remove         = exynos5_busfreq_int_remove,
 394        .driver         = {
 395                .name           = "exynos5-bus-int",
 396                .pm             = &exynos5_busfreq_int_pm_ops,
 397        },
 398};
 399
 400static int __init exynos5_busfreq_int_init(void)
 401{
 402        int ret;
 403
 404        ret = platform_driver_register(&exynos5_busfreq_int_driver);
 405        if (ret < 0)
 406                goto out;
 407
 408        exynos5_devfreq_pdev =
 409                platform_device_register_simple("exynos5-bus-int", -1, NULL, 0);
 410        if (IS_ERR(exynos5_devfreq_pdev)) {
 411                ret = PTR_ERR(exynos5_devfreq_pdev);
 412                goto out1;
 413        }
 414
 415        return 0;
 416out1:
 417        platform_driver_unregister(&exynos5_busfreq_int_driver);
 418out:
 419        return ret;
 420}
 421late_initcall(exynos5_busfreq_int_init);
 422
 423static void __exit exynos5_busfreq_int_exit(void)
 424{
 425        platform_device_unregister(exynos5_devfreq_pdev);
 426        platform_driver_unregister(&exynos5_busfreq_int_driver);
 427}
 428module_exit(exynos5_busfreq_int_exit);
 429
 430MODULE_LICENSE("GPL");
 431MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");
 432