Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2016-2017 Texas Instruments Incorporated - https://www.ti.com/
0004  *  Nishanth Menon <nm@ti.com>
0005  *  Dave Gerlach <d-gerlach@ti.com>
0006  *
0007  * TI OPP supply driver that provides override into the regulator control
0008  * for generic opp core to handle devices with ABB regulator and/or
0009  * SmartReflex Class0.
0010  */
0011 #include <linux/clk.h>
0012 #include <linux/cpufreq.h>
0013 #include <linux/device.h>
0014 #include <linux/io.h>
0015 #include <linux/module.h>
0016 #include <linux/notifier.h>
0017 #include <linux/of_device.h>
0018 #include <linux/of.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/pm_opp.h>
0021 #include <linux/regulator/consumer.h>
0022 #include <linux/slab.h>
0023 
0024 /**
0025  * struct ti_opp_supply_optimum_voltage_table - optimized voltage table
0026  * @reference_uv:   reference voltage (usually Nominal voltage)
0027  * @optimized_uv:   Optimized voltage from efuse
0028  */
0029 struct ti_opp_supply_optimum_voltage_table {
0030     unsigned int reference_uv;
0031     unsigned int optimized_uv;
0032 };
0033 
0034 /**
0035  * struct ti_opp_supply_data - OMAP specific opp supply data
0036  * @vdd_table:  Optimized voltage mapping table
0037  * @num_vdd_table: number of entries in vdd_table
0038  * @vdd_absolute_max_voltage_uv: absolute maximum voltage in UV for the supply
0039  * @old_supplies: Placeholder for supplies information for old OPP.
0040  * @new_supplies: Placeholder for supplies information for new OPP.
0041  */
0042 struct ti_opp_supply_data {
0043     struct ti_opp_supply_optimum_voltage_table *vdd_table;
0044     u32 num_vdd_table;
0045     u32 vdd_absolute_max_voltage_uv;
0046     struct dev_pm_opp_supply old_supplies[2];
0047     struct dev_pm_opp_supply new_supplies[2];
0048 };
0049 
0050 static struct ti_opp_supply_data opp_data;
0051 
0052 /**
0053  * struct ti_opp_supply_of_data - device tree match data
0054  * @flags:  specific type of opp supply
0055  * @efuse_voltage_mask: mask required for efuse register representing voltage
0056  * @efuse_voltage_uv: Are the efuse entries in micro-volts? if not, assume
0057  *      milli-volts.
0058  */
0059 struct ti_opp_supply_of_data {
0060 #define OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE    BIT(1)
0061 #define OPPDM_HAS_NO_ABB            BIT(2)
0062     const u8 flags;
0063     const u32 efuse_voltage_mask;
0064     const bool efuse_voltage_uv;
0065 };
0066 
0067 /**
0068  * _store_optimized_voltages() - store optimized voltages
0069  * @dev:    ti opp supply device for which we need to store info
0070  * @data:   data specific to the device
0071  *
0072  * Picks up efuse based optimized voltages for VDD unique per device and
0073  * stores it in internal data structure for use during transition requests.
0074  *
0075  * Return: If successful, 0, else appropriate error value.
0076  */
0077 static int _store_optimized_voltages(struct device *dev,
0078                      struct ti_opp_supply_data *data)
0079 {
0080     void __iomem *base;
0081     struct property *prop;
0082     struct resource *res;
0083     const __be32 *val;
0084     int proplen, i;
0085     int ret = 0;
0086     struct ti_opp_supply_optimum_voltage_table *table;
0087     const struct ti_opp_supply_of_data *of_data = dev_get_drvdata(dev);
0088 
0089     /* pick up Efuse based voltages */
0090     res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
0091     if (!res) {
0092         dev_err(dev, "Unable to get IO resource\n");
0093         ret = -ENODEV;
0094         goto out_map;
0095     }
0096 
0097     base = ioremap(res->start, resource_size(res));
0098     if (!base) {
0099         dev_err(dev, "Unable to map Efuse registers\n");
0100         ret = -ENOMEM;
0101         goto out_map;
0102     }
0103 
0104     /* Fetch efuse-settings. */
0105     prop = of_find_property(dev->of_node, "ti,efuse-settings", NULL);
0106     if (!prop) {
0107         dev_err(dev, "No 'ti,efuse-settings' property found\n");
0108         ret = -EINVAL;
0109         goto out;
0110     }
0111 
0112     proplen = prop->length / sizeof(int);
0113     data->num_vdd_table = proplen / 2;
0114     /* Verify for corrupted OPP entries in dt */
0115     if (data->num_vdd_table * 2 * sizeof(int) != prop->length) {
0116         dev_err(dev, "Invalid 'ti,efuse-settings'\n");
0117         ret = -EINVAL;
0118         goto out;
0119     }
0120 
0121     ret = of_property_read_u32(dev->of_node, "ti,absolute-max-voltage-uv",
0122                    &data->vdd_absolute_max_voltage_uv);
0123     if (ret) {
0124         dev_err(dev, "ti,absolute-max-voltage-uv is missing\n");
0125         ret = -EINVAL;
0126         goto out;
0127     }
0128 
0129     table = kcalloc(data->num_vdd_table, sizeof(*data->vdd_table),
0130             GFP_KERNEL);
0131     if (!table) {
0132         ret = -ENOMEM;
0133         goto out;
0134     }
0135     data->vdd_table = table;
0136 
0137     val = prop->value;
0138     for (i = 0; i < data->num_vdd_table; i++, table++) {
0139         u32 efuse_offset;
0140         u32 tmp;
0141 
0142         table->reference_uv = be32_to_cpup(val++);
0143         efuse_offset = be32_to_cpup(val++);
0144 
0145         tmp = readl(base + efuse_offset);
0146         tmp &= of_data->efuse_voltage_mask;
0147         tmp >>= __ffs(of_data->efuse_voltage_mask);
0148 
0149         table->optimized_uv = of_data->efuse_voltage_uv ? tmp :
0150                     tmp * 1000;
0151 
0152         dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d vset=%d\n",
0153             i, efuse_offset, table->reference_uv,
0154             table->optimized_uv);
0155 
0156         /*
0157          * Some older samples might not have optimized efuse
0158          * Use reference voltage for those - just add debug message
0159          * for them.
0160          */
0161         if (!table->optimized_uv) {
0162             dev_dbg(dev, "[%d] efuse=0x%08x volt_table=%d:vset0\n",
0163                 i, efuse_offset, table->reference_uv);
0164             table->optimized_uv = table->reference_uv;
0165         }
0166     }
0167 out:
0168     iounmap(base);
0169 out_map:
0170     return ret;
0171 }
0172 
0173 /**
0174  * _free_optimized_voltages() - free resources for optvoltages
0175  * @dev:    device for which we need to free info
0176  * @data:   data specific to the device
0177  */
0178 static void _free_optimized_voltages(struct device *dev,
0179                      struct ti_opp_supply_data *data)
0180 {
0181     kfree(data->vdd_table);
0182     data->vdd_table = NULL;
0183     data->num_vdd_table = 0;
0184 }
0185 
0186 /**
0187  * _get_optimal_vdd_voltage() - Finds optimal voltage for the supply
0188  * @dev:    device for which we need to find info
0189  * @data:   data specific to the device
0190  * @reference_uv:   reference voltage (OPP voltage) for which we need value
0191  *
0192  * Return: if a match is found, return optimized voltage, else return
0193  * reference_uv, also return reference_uv if no optimization is needed.
0194  */
0195 static int _get_optimal_vdd_voltage(struct device *dev,
0196                     struct ti_opp_supply_data *data,
0197                     int reference_uv)
0198 {
0199     int i;
0200     struct ti_opp_supply_optimum_voltage_table *table;
0201 
0202     if (!data->num_vdd_table)
0203         return reference_uv;
0204 
0205     table = data->vdd_table;
0206     if (!table)
0207         return -EINVAL;
0208 
0209     /* Find a exact match - this list is usually very small */
0210     for (i = 0; i < data->num_vdd_table; i++, table++)
0211         if (table->reference_uv == reference_uv)
0212             return table->optimized_uv;
0213 
0214     /* IF things are screwed up, we'd make a mess on console.. ratelimit */
0215     dev_err_ratelimited(dev, "%s: Failed optimized voltage match for %d\n",
0216                 __func__, reference_uv);
0217     return reference_uv;
0218 }
0219 
0220 static int _opp_set_voltage(struct device *dev,
0221                 struct dev_pm_opp_supply *supply,
0222                 int new_target_uv, struct regulator *reg,
0223                 char *reg_name)
0224 {
0225     int ret;
0226     unsigned long vdd_uv, uv_max;
0227 
0228     if (new_target_uv)
0229         vdd_uv = new_target_uv;
0230     else
0231         vdd_uv = supply->u_volt;
0232 
0233     /*
0234      * If we do have an absolute max voltage specified, then we should
0235      * use that voltage instead to allow for cases where the voltage rails
0236      * are ganged (example if we set the max for an opp as 1.12v, and
0237      * the absolute max is 1.5v, for another rail to get 1.25v, it cannot
0238      * be achieved if the regulator is constrainted to max of 1.12v, even
0239      * if it can function at 1.25v
0240      */
0241     if (opp_data.vdd_absolute_max_voltage_uv)
0242         uv_max = opp_data.vdd_absolute_max_voltage_uv;
0243     else
0244         uv_max = supply->u_volt_max;
0245 
0246     if (vdd_uv > uv_max ||
0247         vdd_uv < supply->u_volt_min ||
0248         supply->u_volt_min > uv_max) {
0249         dev_warn(dev,
0250              "Invalid range voltages [Min:%lu target:%lu Max:%lu]\n",
0251              supply->u_volt_min, vdd_uv, uv_max);
0252         return -EINVAL;
0253     }
0254 
0255     dev_dbg(dev, "%s scaling to %luuV[min %luuV max %luuV]\n", reg_name,
0256         vdd_uv, supply->u_volt_min,
0257         uv_max);
0258 
0259     ret = regulator_set_voltage_triplet(reg,
0260                         supply->u_volt_min,
0261                         vdd_uv,
0262                         uv_max);
0263     if (ret) {
0264         dev_err(dev, "%s failed for %luuV[min %luuV max %luuV]\n",
0265             reg_name, vdd_uv, supply->u_volt_min,
0266             uv_max);
0267         return ret;
0268     }
0269 
0270     return 0;
0271 }
0272 
0273 /* Do the opp supply transition */
0274 static int ti_opp_config_regulators(struct device *dev,
0275             struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp,
0276             struct regulator **regulators, unsigned int count)
0277 {
0278     struct dev_pm_opp_supply *old_supply_vdd = &opp_data.old_supplies[0];
0279     struct dev_pm_opp_supply *old_supply_vbb = &opp_data.old_supplies[1];
0280     struct dev_pm_opp_supply *new_supply_vdd = &opp_data.new_supplies[0];
0281     struct dev_pm_opp_supply *new_supply_vbb = &opp_data.new_supplies[1];
0282     struct regulator *vdd_reg = regulators[0];
0283     struct regulator *vbb_reg = regulators[1];
0284     unsigned long old_freq, freq;
0285     int vdd_uv;
0286     int ret;
0287 
0288     /* We must have two regulators here */
0289     WARN_ON(count != 2);
0290 
0291     /* Fetch supplies and freq information from OPP core */
0292     ret = dev_pm_opp_get_supplies(new_opp, opp_data.new_supplies);
0293     WARN_ON(ret);
0294 
0295     old_freq = dev_pm_opp_get_freq(old_opp);
0296     freq = dev_pm_opp_get_freq(new_opp);
0297     WARN_ON(!old_freq || !freq);
0298 
0299     vdd_uv = _get_optimal_vdd_voltage(dev, &opp_data,
0300                       new_supply_vdd->u_volt);
0301 
0302     if (new_supply_vdd->u_volt_min < vdd_uv)
0303         new_supply_vdd->u_volt_min = vdd_uv;
0304 
0305     /* Scaling up? Scale voltage before frequency */
0306     if (freq > old_freq) {
0307         ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
0308                        "vdd");
0309         if (ret)
0310             goto restore_voltage;
0311 
0312         ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
0313         if (ret)
0314             goto restore_voltage;
0315     } else {
0316         ret = _opp_set_voltage(dev, new_supply_vbb, 0, vbb_reg, "vbb");
0317         if (ret)
0318             goto restore_voltage;
0319 
0320         ret = _opp_set_voltage(dev, new_supply_vdd, vdd_uv, vdd_reg,
0321                        "vdd");
0322         if (ret)
0323             goto restore_voltage;
0324     }
0325 
0326     return 0;
0327 
0328 restore_voltage:
0329     /* Fetch old supplies information only if required */
0330     ret = dev_pm_opp_get_supplies(old_opp, opp_data.old_supplies);
0331     WARN_ON(ret);
0332 
0333     /* This shouldn't harm even if the voltages weren't updated earlier */
0334     if (old_supply_vdd->u_volt) {
0335         ret = _opp_set_voltage(dev, old_supply_vbb, 0, vbb_reg, "vbb");
0336         if (ret)
0337             return ret;
0338 
0339         ret = _opp_set_voltage(dev, old_supply_vdd, 0, vdd_reg,
0340                        "vdd");
0341         if (ret)
0342             return ret;
0343     }
0344 
0345     return ret;
0346 }
0347 
0348 static const struct ti_opp_supply_of_data omap_generic_of_data = {
0349 };
0350 
0351 static const struct ti_opp_supply_of_data omap_omap5_of_data = {
0352     .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE,
0353     .efuse_voltage_mask = 0xFFF,
0354     .efuse_voltage_uv = false,
0355 };
0356 
0357 static const struct ti_opp_supply_of_data omap_omap5core_of_data = {
0358     .flags = OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE | OPPDM_HAS_NO_ABB,
0359     .efuse_voltage_mask = 0xFFF,
0360     .efuse_voltage_uv = false,
0361 };
0362 
0363 static const struct of_device_id ti_opp_supply_of_match[] = {
0364     {.compatible = "ti,omap-opp-supply", .data = &omap_generic_of_data},
0365     {.compatible = "ti,omap5-opp-supply", .data = &omap_omap5_of_data},
0366     {.compatible = "ti,omap5-core-opp-supply",
0367      .data = &omap_omap5core_of_data},
0368     {},
0369 };
0370 MODULE_DEVICE_TABLE(of, ti_opp_supply_of_match);
0371 
0372 static int ti_opp_supply_probe(struct platform_device *pdev)
0373 {
0374     struct device *dev = &pdev->dev;
0375     struct device *cpu_dev = get_cpu_device(0);
0376     const struct of_device_id *match;
0377     const struct ti_opp_supply_of_data *of_data;
0378     int ret = 0;
0379 
0380     match = of_match_device(ti_opp_supply_of_match, dev);
0381     if (!match) {
0382         /* We do not expect this to happen */
0383         dev_err(dev, "%s: Unable to match device\n", __func__);
0384         return -ENODEV;
0385     }
0386     if (!match->data) {
0387         /* Again, unlikely.. but mistakes do happen */
0388         dev_err(dev, "%s: Bad data in match\n", __func__);
0389         return -EINVAL;
0390     }
0391     of_data = match->data;
0392 
0393     dev_set_drvdata(dev, (void *)of_data);
0394 
0395     /* If we need optimized voltage */
0396     if (of_data->flags & OPPDM_EFUSE_CLASS0_OPTIMIZED_VOLTAGE) {
0397         ret = _store_optimized_voltages(dev, &opp_data);
0398         if (ret)
0399             return ret;
0400     }
0401 
0402     ret = dev_pm_opp_set_config_regulators(cpu_dev, ti_opp_config_regulators);
0403     if (ret < 0)
0404         _free_optimized_voltages(dev, &opp_data);
0405 
0406     return ret;
0407 }
0408 
0409 static struct platform_driver ti_opp_supply_driver = {
0410     .probe = ti_opp_supply_probe,
0411     .driver = {
0412            .name = "ti_opp_supply",
0413            .of_match_table = of_match_ptr(ti_opp_supply_of_match),
0414            },
0415 };
0416 module_platform_driver(ti_opp_supply_driver);
0417 
0418 MODULE_DESCRIPTION("Texas Instruments OMAP OPP Supply driver");
0419 MODULE_AUTHOR("Texas Instruments Inc.");
0420 MODULE_LICENSE("GPL v2");