cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ti-opp-supply.c (12012B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2016-2017 Texas Instruments Incorporated - https://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(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");