linux/drivers/opp/ti-opp-supply.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/
   4 *      Nishanth Menon <nm@ti.com>
   5 *      Dave Gerlach <d-gerlach@ti.com>
   6 *
   7 * TI OPP supply driver that provides override into the regulator control
   8 * for generic opp core to handle devices with ABB regulator and/or
   9 * SmartReflex Class0.
  10 */
  11#include <linux/clk.h>
  12#include <linux/cpufreq.h>
  13#include <linux/device.h>
  14#include <linux/io.h>
  15#include <linux/module.h>
  16#include <linux/notifier.h>
  17#include <linux/of_device.h>
  18#include <linux/of.h>
  19#include <linux/platform_device.h>
  20#include <linux/pm_opp.h>
  21#include <linux/regulator/consumer.h>
  22#include <linux/slab.h>
  23
  24/**
  25 * struct ti_opp_supply_optimum_voltage_table - optimized voltage table
  26 * @reference_uv:       reference voltage (usually Nominal voltage)
  27 * @optimized_uv:       Optimized voltage from efuse
  28 */
  29struct ti_opp_supply_optimum_voltage_table {
  30        unsigned int reference_uv;
  31        unsigned int optimized_uv;
  32};
  33
  34/**
  35 * struct ti_opp_supply_data - OMAP specific opp supply data
  36 * @vdd_table:  Optimized voltage mapping table
  37 * @num_vdd_table: number of entries in vdd_table
  38 * @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the supply
  39 */
  40struct ti_opp_supply_data {
  41        struct ti_opp_supply_optimum_voltage_table *vdd_table;
  42        u32 num_vdd_table;
  43        u32 vdd_absolute_max_voltage_uv;
  44};
  45
  46static struct ti_opp_supply_data opp_data;
  47
  48/**
  49 * struct ti_opp_supply_of_data - device tree match data
  50 * @flags:      specific type of opp supply
  51 * @efuse_voltage_mask: mask required for efuse register representing voltage
  52 * @efuse_voltage_uv: Are the efuse entries in micro-volts? if not, assume
  53 *              milli-volts.
  54 */
  55struct ti_opp_supply_of_data {
  56#define OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE    BIT(1)
  57#define OPPDM_HAS_NO_ABB                        BIT(2)
  58        const u8 flags;
  59        const u32 efuse_voltage_mask;
  60        const bool efuse_voltage_uv;
  61};
  62
  63/**
  64 * _store_optimized_voltages() - store optimized voltages
  65 * @dev:        ti opp supply device for which we need to store info
  66 * @data:       data specific to the device
  67 *
  68 * Picks up efuse based optimized voltages for VDD unique per device and
  69 * stores it in internal data structure for use during transition requests.
  70 *
  71 * Return: If successful, 0, else appropriate error value.
  72 */
  73static int _store_optimized_voltages(struct device *dev,
  74                                     struct ti_opp_supply_data *data)
  75{
  76        void __iomem *base;
  77        struct property *prop;
  78        struct resource *res;
  79        const __be32 *val;
  80        int proplen, i;
  81        int ret = 0;
  82        struct ti_opp_supply_optimum_voltage_table *table;
  83        const struct ti_opp_supply_of_data *of_data = dev_get_drvdata(dev);
  84
  85        /* pick up Efuse based voltages */
  86        res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
  87        if (!res) {
  88                dev_err(dev, "Unable to get IO resource\n");
  89                ret = -ENODEV;
  90                goto out_map;
  91        }
  92
  93        base = ioremap_nocache(res->start, resource_size(res));
  94        if (!base) {
  95                dev_err(dev, "Unable to map Efuse registers\n");
  96                ret = -ENOMEM;
  97                goto out_map;
  98        }
  99
 100        /* Fetch efuse-settings. */
 101        prop = of_find_property(dev->of_node, "ti,efuse-settings", NULL);
 102        if (!prop) {
 103                dev_err(dev, "No 'ti,efuse-settings' property found\n");
 104                ret = -EINVAL;
 105                goto out;
 106        }
 107
 108        proplen = prop->length / sizeof(int);
 109        data->num_vdd_table = proplen / 2;
 110        /* Verify for corrupted OPP entries in dt */
 111        if (data->num_vdd_table * 2 * sizeof(int) != prop->length) {
 112                dev_err(dev, "Invalid 'ti,efuse-settings'\n");
 113                ret = -EINVAL;
 114                goto out;
 115        }
 116
 117        ret = of_property_read_u32(dev->of_node, "ti,absolute-max-voltage-uv",
 118                                   &data->vdd_absolute_max_voltage_uv);
 119        if (ret) {
 120                dev_err(dev, "ti,absolute-max-voltage-uv is missing\n");
 121                ret = -EINVAL;
 122                goto out;
 123        }
 124
 125        table = kcalloc(data->num_vdd_table, sizeof(*data->vdd_table),
 126                        GFP_KERNEL);
 127        if (!table) {
 128                ret = -ENOMEM;
 129                goto out;
 130        }
 131        data->vdd_table = table;
 132
 133        val = prop->value;
 134        for (i = 0; i < data->num_vdd_table; i++, table++) {
 135                u32 efuse_offset;
 136                u32 tmp;
 137
 138                table->reference_uv = be32_to_cpup(val++);
 139                efuse_offset = be32_to_cpup(val++);
 140
 141                tmp = readl(base + efuse_offset);
 142                tmp &= of_data->efuse_voltage_mask;
 143                tmp >>= __ffs(of_data->efuse_voltage_mask);
 144
 145                table->optimized_uv = of_data->efuse_voltage_uv ? tmp :
 146                                        tmp * 1000;
 147
 148                dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d vset=%d\n",
 149                        i, efuse_offset, table->reference_uv,
 150                        table->optimized_uv);
 151
 152                /*
 153                 * Some older samples might not have optimized efuse
 154                 * Use reference voltage for those - just add debug message
 155                 * for them.
 156                 */
 157                if (!table->optimized_uv) {
 158                        dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d:vset0\n",
 159                                i, efuse_offset, table->reference_uv);
 160                        table->optimized_uv = table->reference_uv;
 161                }
 162        }
 163out:
 164        iounmap(base);
 165out_map:
 166        return ret;
 167}
 168
 169/**
 170 * _free_optimized_voltages() - free resources for optvoltages
 171 * @dev:        device for which we need to free info
 172 * @data:       data specific to the device
 173 */
 174static void _free_optimized_voltages(struct device *dev,
 175                                     struct ti_opp_supply_data *data)
 176{
 177        kfree(data->vdd_table);
 178        data->vdd_table = NULL;
 179        data->num_vdd_table = 0;
 180}
 181
 182/**
 183 * _get_optimal_vdd_voltage() - Finds optimal voltage for the supply
 184 * @dev:        device for which we need to find info
 185 * @data:       data specific to the device
 186 * @reference_uv:       reference voltage (OPP voltage) for which we need value
 187 *
 188 * Return: if a match is found, return optimized voltage, else return
 189 * reference_uv, also return reference_uv if no optimization is needed.
 190 */
 191static int _get_optimal_vdd_voltage(struct device *dev,
 192                                    struct ti_opp_supply_data *data,
 193                                    int reference_uv)
 194{
 195        int i;
 196        struct ti_opp_supply_optimum_voltage_table *table;
 197
 198        if (!data->num_vdd_table)
 199                return reference_uv;
 200
 201        table = data->vdd_table;
 202        if (!table)
 203                return -EINVAL;
 204
 205        /* Find a exact match - this list is usually very small */
 206        for (i = 0; i < data->num_vdd_table; i++, table++)
 207                if (table->reference_uv == reference_uv)
 208                        return table->optimized_uv;
 209
 210        /* IF things are screwed up, we'd make a mess on console.. ratelimit */
 211        dev_err_ratelimited(dev, "%s: Failed optimized voltage match for %d\n",
 212                            __func__, reference_uv);
 213        return reference_uv;
 214}
 215
 216static int _opp_set_voltage(struct device *dev,
 217                            struct dev_pm_opp_supply *supply,
 218                            int new_target_uv, struct regulator *reg,
 219                            char *reg_name)
 220{
 221        int ret;
 222        unsigned long vdd_uv, uv_max;
 223
 224        if (new_target_uv)
 225                vdd_uv = new_target_uv;
 226        else
 227                vdd_uv = supply->u_volt;
 228
 229        /*
 230         * If we do have an absolute max voltage specified, then we should
 231         * use that voltage instead to allow for cases where the voltage rails
 232         * are ganged (example if we set the max for an opp as 1.12v, and
 233         * the absolute max is 1.5v, for another rail to get 1.25v, it cannot
 234         * be achieved if the regulator is constrainted to max of 1.12v, even
 235         * if it can function at 1.25v
 236         */
 237        if (opp_data.vdd_absolute_max_voltage_uv)
 238                uv_max = opp_data.vdd_absolute_max_voltage_uv;
 239        else
 240                uv_max = supply->u_volt_max;
 241
 242        if (vdd_uv > uv_max ||
 243            vdd_uv < supply->u_volt_min ||
 244            supply->u_volt_min > uv_max) {
 245                dev_warn(dev,
 246                         "Invalid range voltages [Min:%lu target:%lu Max:%lu]\n",
 247                         supply->u_volt_min, vdd_uv, uv_max);
 248                return -EINVAL;
 249        }
 250
 251        dev_dbg(dev, "%s scaling to %luuV[min %luuV max %luuV]\n", reg_name,
 252                vdd_uv, supply->u_volt_min,
 253                uv_max);
 254
 255        ret = regulator_set_voltage_triplet(reg,
 256                                            supply->u_volt_min,
 257                                            vdd_uv,
 258                                            uv_max);
 259        if (ret) {
 260                dev_err(dev, "%s failed for %luuV[min %luuV max %luuV]\n",
 261                        reg_name, vdd_uv, supply->u_volt_min,
 262                        uv_max);
 263                return ret;
 264        }
 265
 266        return 0;
 267}
 268
 269/**
 270 * ti_opp_supply_set_opp() - do the opp supply transition
 271 * @data:       information on regulators and new and old opps provided by
 272 *              opp core to use in transition
 273 *
 274 * Return: If successful, 0, else appropriate error value.
 275 */
 276static int ti_opp_supply_set_opp(struct dev_pm_set_opp_data *data)
 277{
 278        struct dev_pm_opp_supply *old_supply_vdd = &data->old_opp.supplies[0];
 279        struct dev_pm_opp_supply *old_supply_vbb = &data->old_opp.supplies[1];
 280        struct dev_pm_opp_supply *new_supply_vdd = &data->new_opp.supplies[0];
 281        struct dev_pm_opp_supply *new_supply_vbb = &data->new_opp.supplies[1];
 282        struct device *dev = data->dev;
 283        unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
 284        struct clk *clk = data->clk;
 285        struct regulator *vdd_reg = data->regulators[0];
 286        struct regulator *vbb_reg = data->regulators[1];
 287        int vdd_uv;
 288        int ret;
 289
 290        vdd_uv = _get_optimal_vdd_voltage(dev, &opp_data,
 291                                          new_supply_vdd->u_volt);
 292
 293        if (new_supply_vdd->u_volt_min < vdd_uv)
 294                new_supply_vdd->u_volt_min = vdd_uv;
 295
 296        /* Scaling up? Scale voltage before frequency */
 297        if (freq > old_freq) {
 298                ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
 299                                       "vdd");
 300                if (ret)
 301                        goto restore_voltage;
 302
 303                ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
 304                if (ret)
 305                        goto restore_voltage;
 306        }
 307
 308        /* Change frequency */
 309        dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
 310                __func__, old_freq, freq);
 311
 312        ret = clk_set_rate(clk, freq);
 313        if (ret) {
 314                dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
 315                        ret);
 316                goto restore_voltage;
 317        }
 318
 319        /* Scaling down? Scale voltage after frequency */
 320        if (freq < old_freq) {
 321                ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
 322                if (ret)
 323                        goto restore_freq;
 324
 325                ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
 326                                       "vdd");
 327                if (ret)
 328                        goto restore_freq;
 329        }
 330
 331        return 0;
 332
 333restore_freq:
 334        ret = clk_set_rate(clk, old_freq);
 335        if (ret)
 336                dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
 337                        __func__, old_freq);
 338restore_voltage:
 339        /* This shouldn't harm even if the voltages weren't updated earlier */
 340        if (old_supply_vdd->u_volt) {
 341                ret = _opp_set_voltage(dev, old_supply_vbb, 0, vbb_reg, "vbb");
 342                if (ret)
 343                        return ret;
 344
 345                ret = _opp_set_voltage(dev, old_supply_vdd, 0, vdd_reg,
 346                                       "vdd");
 347                if (ret)
 348                        return ret;
 349        }
 350
 351        return ret;
 352}
 353
 354static const struct ti_opp_supply_of_data omap_generic_of_data = {
 355};
 356
 357static const struct ti_opp_supply_of_data omap_omap5_of_data = {
 358        .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE,
 359        .efuse_voltage_mask = 0xFFF,
 360        .efuse_voltage_uv = false,
 361};
 362
 363static const struct ti_opp_supply_of_data omap_omap5core_of_data = {
 364        .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE | OPPDM_HAS_NO_ABB,
 365        .efuse_voltage_mask = 0xFFF,
 366        .efuse_voltage_uv = false,
 367};
 368
 369static const struct of_device_id ti_opp_supply_of_match[] = {
 370        {.compatible = "ti,omap-opp-supply", .data = &omap_generic_of_data},
 371        {.compatible = "ti,omap5-opp-supply", .data = &omap_omap5_of_data},
 372        {.compatible = "ti,omap5-core-opp-supply",
 373         .data = &omap_omap5core_of_data},
 374        {},
 375};
 376MODULE_DEVICE_TABLE(of, ti_opp_supply_of_match);
 377
 378static int ti_opp_supply_probe(struct platform_device *pdev)
 379{
 380        struct device *dev = &pdev->dev;
 381        struct device *cpu_dev = get_cpu_device(0);
 382        const struct of_device_id *match;
 383        const struct ti_opp_supply_of_data *of_data;
 384        int ret = 0;
 385
 386        match = of_match_device(ti_opp_supply_of_match, dev);
 387        if (!match) {
 388                /* We do not expect this to happen */
 389                dev_err(dev, "%s: Unable to match device\n", __func__);
 390                return -ENODEV;
 391        }
 392        if (!match->data) {
 393                /* Again, unlikely.. but mistakes do happen */
 394                dev_err(dev, "%s: Bad data in match\n", __func__);
 395                return -EINVAL;
 396        }
 397        of_data = match->data;
 398
 399        dev_set_drvdata(dev, (void *)of_data);
 400
 401        /* If we need optimized voltage */
 402        if (of_data->flags & OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE) {
 403                ret = _store_optimized_voltages(dev, &opp_data);
 404                if (ret)
 405                        return ret;
 406        }
 407
 408        ret = PTR_ERR_OR_ZERO(dev_pm_opp_register_set_opp_helper(cpu_dev,
 409                                                                 ti_opp_supply_set_opp));
 410        if (ret)
 411                _free_optimized_voltages(dev, &opp_data);
 412
 413        return ret;
 414}
 415
 416static struct platform_driver ti_opp_supply_driver = {
 417        .probe = ti_opp_supply_probe,
 418        .driver = {
 419                   .name = "ti_opp_supply",
 420                   .of_match_table = of_match_ptr(ti_opp_supply_of_match),
 421                   },
 422};
 423module_platform_driver(ti_opp_supply_driver);
 424
 425MODULE_DESCRIPTION("Texas Instruments OMAP OPP Supply driver");
 426MODULE_AUTHOR("Texas Instruments Inc.");
 427MODULE_LICENSE("GPL v2");
 428