linux/drivers/devfreq/exynos-bus.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Generic Exynos Bus frequency driver with DEVFREQ Framework
   4 *
   5 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
   6 * Author : Chanwoo Choi <cw00.choi@samsung.com>
   7 *
   8 * This driver support Exynos Bus frequency feature by using
   9 * DEVFREQ framework and is based on drivers/devfreq/exynos/exynos4_bus.c.
  10 */
  11
  12#include <linux/clk.h>
  13#include <linux/devfreq.h>
  14#include <linux/devfreq-event.h>
  15#include <linux/device.h>
  16#include <linux/export.h>
  17#include <linux/module.h>
  18#include <linux/of.h>
  19#include <linux/pm_opp.h>
  20#include <linux/platform_device.h>
  21#include <linux/regulator/consumer.h>
  22
  23#define DEFAULT_SATURATION_RATIO        40
  24
  25struct exynos_bus {
  26        struct device *dev;
  27
  28        struct devfreq *devfreq;
  29        struct devfreq_event_dev **edev;
  30        unsigned int edev_count;
  31        struct mutex lock;
  32
  33        unsigned long curr_freq;
  34
  35        struct opp_table *opp_table;
  36        struct clk *clk;
  37        unsigned int ratio;
  38};
  39
  40/*
  41 * Control the devfreq-event device to get the current state of bus
  42 */
  43#define exynos_bus_ops_edev(ops)                                \
  44static int exynos_bus_##ops(struct exynos_bus *bus)             \
  45{                                                               \
  46        int i, ret;                                             \
  47                                                                \
  48        for (i = 0; i < bus->edev_count; i++) {                 \
  49                if (!bus->edev[i])                              \
  50                        continue;                               \
  51                ret = devfreq_event_##ops(bus->edev[i]);        \
  52                if (ret < 0)                                    \
  53                        return ret;                             \
  54        }                                                       \
  55                                                                \
  56        return 0;                                               \
  57}
  58exynos_bus_ops_edev(enable_edev);
  59exynos_bus_ops_edev(disable_edev);
  60exynos_bus_ops_edev(set_event);
  61
  62static int exynos_bus_get_event(struct exynos_bus *bus,
  63                                struct devfreq_event_data *edata)
  64{
  65        struct devfreq_event_data event_data;
  66        unsigned long load_count = 0, total_count = 0;
  67        int i, ret = 0;
  68
  69        for (i = 0; i < bus->edev_count; i++) {
  70                if (!bus->edev[i])
  71                        continue;
  72
  73                ret = devfreq_event_get_event(bus->edev[i], &event_data);
  74                if (ret < 0)
  75                        return ret;
  76
  77                if (i == 0 || event_data.load_count > load_count) {
  78                        load_count = event_data.load_count;
  79                        total_count = event_data.total_count;
  80                }
  81        }
  82
  83        edata->load_count = load_count;
  84        edata->total_count = total_count;
  85
  86        return ret;
  87}
  88
  89/*
  90 * devfreq function for both simple-ondemand and passive governor
  91 */
  92static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
  93{
  94        struct exynos_bus *bus = dev_get_drvdata(dev);
  95        struct dev_pm_opp *new_opp;
  96        int ret = 0;
  97
  98        /* Get correct frequency for bus. */
  99        new_opp = devfreq_recommended_opp(dev, freq, flags);
 100        if (IS_ERR(new_opp)) {
 101                dev_err(dev, "failed to get recommended opp instance\n");
 102                return PTR_ERR(new_opp);
 103        }
 104
 105        dev_pm_opp_put(new_opp);
 106
 107        /* Change voltage and frequency according to new OPP level */
 108        mutex_lock(&bus->lock);
 109        ret = dev_pm_opp_set_rate(dev, *freq);
 110        if (!ret)
 111                bus->curr_freq = *freq;
 112
 113        mutex_unlock(&bus->lock);
 114
 115        return ret;
 116}
 117
 118static int exynos_bus_get_dev_status(struct device *dev,
 119                                     struct devfreq_dev_status *stat)
 120{
 121        struct exynos_bus *bus = dev_get_drvdata(dev);
 122        struct devfreq_event_data edata;
 123        int ret;
 124
 125        stat->current_frequency = bus->curr_freq;
 126
 127        ret = exynos_bus_get_event(bus, &edata);
 128        if (ret < 0) {
 129                dev_err(dev, "failed to get event from devfreq-event devices\n");
 130                stat->total_time = stat->busy_time = 0;
 131                goto err;
 132        }
 133
 134        stat->busy_time = (edata.load_count * 100) / bus->ratio;
 135        stat->total_time = edata.total_count;
 136
 137        dev_dbg(dev, "Usage of devfreq-event : %lu/%lu\n", stat->busy_time,
 138                                                        stat->total_time);
 139
 140err:
 141        ret = exynos_bus_set_event(bus);
 142        if (ret < 0) {
 143                dev_err(dev, "failed to set event to devfreq-event devices\n");
 144                return ret;
 145        }
 146
 147        return ret;
 148}
 149
 150static void exynos_bus_exit(struct device *dev)
 151{
 152        struct exynos_bus *bus = dev_get_drvdata(dev);
 153        int ret;
 154
 155        ret = exynos_bus_disable_edev(bus);
 156        if (ret < 0)
 157                dev_warn(dev, "failed to disable the devfreq-event devices\n");
 158
 159        dev_pm_opp_of_remove_table(dev);
 160        clk_disable_unprepare(bus->clk);
 161        if (bus->opp_table) {
 162                dev_pm_opp_put_regulators(bus->opp_table);
 163                bus->opp_table = NULL;
 164        }
 165}
 166
 167static void exynos_bus_passive_exit(struct device *dev)
 168{
 169        struct exynos_bus *bus = dev_get_drvdata(dev);
 170
 171        dev_pm_opp_of_remove_table(dev);
 172        clk_disable_unprepare(bus->clk);
 173}
 174
 175static int exynos_bus_parent_parse_of(struct device_node *np,
 176                                        struct exynos_bus *bus)
 177{
 178        struct device *dev = bus->dev;
 179        struct opp_table *opp_table;
 180        const char *vdd = "vdd";
 181        int i, ret, count, size;
 182
 183        opp_table = dev_pm_opp_set_regulators(dev, &vdd, 1);
 184        if (IS_ERR(opp_table)) {
 185                ret = PTR_ERR(opp_table);
 186                dev_err(dev, "failed to set regulators %d\n", ret);
 187                return ret;
 188        }
 189
 190        bus->opp_table = opp_table;
 191
 192        /*
 193         * Get the devfreq-event devices to get the current utilization of
 194         * buses. This raw data will be used in devfreq ondemand governor.
 195         */
 196        count = devfreq_event_get_edev_count(dev);
 197        if (count < 0) {
 198                dev_err(dev, "failed to get the count of devfreq-event dev\n");
 199                ret = count;
 200                goto err_regulator;
 201        }
 202        bus->edev_count = count;
 203
 204        size = sizeof(*bus->edev) * count;
 205        bus->edev = devm_kzalloc(dev, size, GFP_KERNEL);
 206        if (!bus->edev) {
 207                ret = -ENOMEM;
 208                goto err_regulator;
 209        }
 210
 211        for (i = 0; i < count; i++) {
 212                bus->edev[i] = devfreq_event_get_edev_by_phandle(dev, i);
 213                if (IS_ERR(bus->edev[i])) {
 214                        ret = -EPROBE_DEFER;
 215                        goto err_regulator;
 216                }
 217        }
 218
 219        /*
 220         * Optionally, Get the saturation ratio according to Exynos SoC
 221         * When measuring the utilization of each AXI bus with devfreq-event
 222         * devices, the measured real cycle might be much lower than the
 223         * total cycle of bus during sampling rate. In result, the devfreq
 224         * simple-ondemand governor might not decide to change the current
 225         * frequency due to too utilization (= real cycle/total cycle).
 226         * So, this property is used to adjust the utilization when calculating
 227         * the busy_time in exynos_bus_get_dev_status().
 228         */
 229        if (of_property_read_u32(np, "exynos,saturation-ratio", &bus->ratio))
 230                bus->ratio = DEFAULT_SATURATION_RATIO;
 231
 232        return 0;
 233
 234err_regulator:
 235        dev_pm_opp_put_regulators(bus->opp_table);
 236        bus->opp_table = NULL;
 237
 238        return ret;
 239}
 240
 241static int exynos_bus_parse_of(struct device_node *np,
 242                              struct exynos_bus *bus)
 243{
 244        struct device *dev = bus->dev;
 245        struct dev_pm_opp *opp;
 246        unsigned long rate;
 247        int ret;
 248
 249        /* Get the clock to provide each bus with source clock */
 250        bus->clk = devm_clk_get(dev, "bus");
 251        if (IS_ERR(bus->clk)) {
 252                dev_err(dev, "failed to get bus clock\n");
 253                return PTR_ERR(bus->clk);
 254        }
 255
 256        ret = clk_prepare_enable(bus->clk);
 257        if (ret < 0) {
 258                dev_err(dev, "failed to get enable clock\n");
 259                return ret;
 260        }
 261
 262        /* Get the freq and voltage from OPP table to scale the bus freq */
 263        ret = dev_pm_opp_of_add_table(dev);
 264        if (ret < 0) {
 265                dev_err(dev, "failed to get OPP table\n");
 266                goto err_clk;
 267        }
 268
 269        rate = clk_get_rate(bus->clk);
 270
 271        opp = devfreq_recommended_opp(dev, &rate, 0);
 272        if (IS_ERR(opp)) {
 273                dev_err(dev, "failed to find dev_pm_opp\n");
 274                ret = PTR_ERR(opp);
 275                goto err_opp;
 276        }
 277        bus->curr_freq = dev_pm_opp_get_freq(opp);
 278        dev_pm_opp_put(opp);
 279
 280        return 0;
 281
 282err_opp:
 283        dev_pm_opp_of_remove_table(dev);
 284err_clk:
 285        clk_disable_unprepare(bus->clk);
 286
 287        return ret;
 288}
 289
 290static int exynos_bus_profile_init(struct exynos_bus *bus,
 291                                   struct devfreq_dev_profile *profile)
 292{
 293        struct device *dev = bus->dev;
 294        struct devfreq_simple_ondemand_data *ondemand_data;
 295        int ret;
 296
 297        /* Initialize the struct profile and governor data for parent device */
 298        profile->polling_ms = 50;
 299        profile->target = exynos_bus_target;
 300        profile->get_dev_status = exynos_bus_get_dev_status;
 301        profile->exit = exynos_bus_exit;
 302
 303        ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL);
 304        if (!ondemand_data)
 305                return -ENOMEM;
 306
 307        ondemand_data->upthreshold = 40;
 308        ondemand_data->downdifferential = 5;
 309
 310        /* Add devfreq device to monitor and handle the exynos bus */
 311        bus->devfreq = devm_devfreq_add_device(dev, profile,
 312                                                DEVFREQ_GOV_SIMPLE_ONDEMAND,
 313                                                ondemand_data);
 314        if (IS_ERR(bus->devfreq)) {
 315                dev_err(dev, "failed to add devfreq device\n");
 316                return PTR_ERR(bus->devfreq);
 317        }
 318
 319        /* Register opp_notifier to catch the change of OPP  */
 320        ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq);
 321        if (ret < 0) {
 322                dev_err(dev, "failed to register opp notifier\n");
 323                return ret;
 324        }
 325
 326        /*
 327         * Enable devfreq-event to get raw data which is used to determine
 328         * current bus load.
 329         */
 330        ret = exynos_bus_enable_edev(bus);
 331        if (ret < 0) {
 332                dev_err(dev, "failed to enable devfreq-event devices\n");
 333                return ret;
 334        }
 335
 336        ret = exynos_bus_set_event(bus);
 337        if (ret < 0) {
 338                dev_err(dev, "failed to set event to devfreq-event devices\n");
 339                goto err_edev;
 340        }
 341
 342        return 0;
 343
 344err_edev:
 345        if (exynos_bus_disable_edev(bus))
 346                dev_warn(dev, "failed to disable the devfreq-event devices\n");
 347
 348        return ret;
 349}
 350
 351static int exynos_bus_profile_init_passive(struct exynos_bus *bus,
 352                                           struct devfreq_dev_profile *profile)
 353{
 354        struct device *dev = bus->dev;
 355        struct devfreq_passive_data *passive_data;
 356        struct devfreq *parent_devfreq;
 357
 358        /* Initialize the struct profile and governor data for passive device */
 359        profile->target = exynos_bus_target;
 360        profile->exit = exynos_bus_passive_exit;
 361
 362        /* Get the instance of parent devfreq device */
 363        parent_devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
 364        if (IS_ERR(parent_devfreq))
 365                return -EPROBE_DEFER;
 366
 367        passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
 368        if (!passive_data)
 369                return -ENOMEM;
 370
 371        passive_data->parent = parent_devfreq;
 372
 373        /* Add devfreq device for exynos bus with passive governor */
 374        bus->devfreq = devm_devfreq_add_device(dev, profile, DEVFREQ_GOV_PASSIVE,
 375                                                passive_data);
 376        if (IS_ERR(bus->devfreq)) {
 377                dev_err(dev,
 378                        "failed to add devfreq dev with passive governor\n");
 379                return PTR_ERR(bus->devfreq);
 380        }
 381
 382        return 0;
 383}
 384
 385static int exynos_bus_probe(struct platform_device *pdev)
 386{
 387        struct device *dev = &pdev->dev;
 388        struct device_node *np = dev->of_node, *node;
 389        struct devfreq_dev_profile *profile;
 390        struct exynos_bus *bus;
 391        int ret, max_state;
 392        unsigned long min_freq, max_freq;
 393        bool passive = false;
 394
 395        if (!np) {
 396                dev_err(dev, "failed to find devicetree node\n");
 397                return -EINVAL;
 398        }
 399
 400        bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
 401        if (!bus)
 402                return -ENOMEM;
 403        mutex_init(&bus->lock);
 404        bus->dev = &pdev->dev;
 405        platform_set_drvdata(pdev, bus);
 406
 407        profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
 408        if (!profile)
 409                return -ENOMEM;
 410
 411        node = of_parse_phandle(dev->of_node, "devfreq", 0);
 412        if (node) {
 413                of_node_put(node);
 414                passive = true;
 415        } else {
 416                ret = exynos_bus_parent_parse_of(np, bus);
 417                if (ret < 0)
 418                        return ret;
 419        }
 420
 421        /* Parse the device-tree to get the resource information */
 422        ret = exynos_bus_parse_of(np, bus);
 423        if (ret < 0)
 424                goto err_reg;
 425
 426        if (passive)
 427                ret = exynos_bus_profile_init_passive(bus, profile);
 428        else
 429                ret = exynos_bus_profile_init(bus, profile);
 430
 431        if (ret < 0)
 432                goto err;
 433
 434        max_state = bus->devfreq->profile->max_state;
 435        min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
 436        max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
 437        pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",
 438                        dev_name(dev), min_freq, max_freq);
 439
 440        return 0;
 441
 442err:
 443        dev_pm_opp_of_remove_table(dev);
 444        clk_disable_unprepare(bus->clk);
 445err_reg:
 446        if (!passive) {
 447                dev_pm_opp_put_regulators(bus->opp_table);
 448                bus->opp_table = NULL;
 449        }
 450
 451        return ret;
 452}
 453
 454static void exynos_bus_shutdown(struct platform_device *pdev)
 455{
 456        struct exynos_bus *bus = dev_get_drvdata(&pdev->dev);
 457
 458        devfreq_suspend_device(bus->devfreq);
 459}
 460
 461#ifdef CONFIG_PM_SLEEP
 462static int exynos_bus_resume(struct device *dev)
 463{
 464        struct exynos_bus *bus = dev_get_drvdata(dev);
 465        int ret;
 466
 467        ret = exynos_bus_enable_edev(bus);
 468        if (ret < 0) {
 469                dev_err(dev, "failed to enable the devfreq-event devices\n");
 470                return ret;
 471        }
 472
 473        return 0;
 474}
 475
 476static int exynos_bus_suspend(struct device *dev)
 477{
 478        struct exynos_bus *bus = dev_get_drvdata(dev);
 479        int ret;
 480
 481        ret = exynos_bus_disable_edev(bus);
 482        if (ret < 0) {
 483                dev_err(dev, "failed to disable the devfreq-event devices\n");
 484                return ret;
 485        }
 486
 487        return 0;
 488}
 489#endif
 490
 491static const struct dev_pm_ops exynos_bus_pm = {
 492        SET_SYSTEM_SLEEP_PM_OPS(exynos_bus_suspend, exynos_bus_resume)
 493};
 494
 495static const struct of_device_id exynos_bus_of_match[] = {
 496        { .compatible = "samsung,exynos-bus", },
 497        { /* sentinel */ },
 498};
 499MODULE_DEVICE_TABLE(of, exynos_bus_of_match);
 500
 501static struct platform_driver exynos_bus_platdrv = {
 502        .probe          = exynos_bus_probe,
 503        .shutdown       = exynos_bus_shutdown,
 504        .driver = {
 505                .name   = "exynos-bus",
 506                .pm     = &exynos_bus_pm,
 507                .of_match_table = of_match_ptr(exynos_bus_of_match),
 508        },
 509};
 510module_platform_driver(exynos_bus_platdrv);
 511
 512MODULE_DESCRIPTION("Generic Exynos Bus frequency driver");
 513MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
 514MODULE_LICENSE("GPL v2");
 515