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

scmi-regulator.c (11154B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// System Control and Management Interface (SCMI) based regulator driver
      4//
      5// Copyright (C) 2020-2021 ARM Ltd.
      6//
      7// Implements a regulator driver on top of the SCMI Voltage Protocol.
      8//
      9// The ARM SCMI Protocol aims in general to hide as much as possible all the
     10// underlying operational details while providing an abstracted interface for
     11// its users to operate upon: as a consequence the resulting operational
     12// capabilities and configurability of this regulator device are much more
     13// limited than the ones usually available on a standard physical regulator.
     14//
     15// The supported SCMI regulator ops are restricted to the bare minimum:
     16//
     17//  - 'status_ops': enable/disable/is_enabled
     18//  - 'voltage_ops': get_voltage_sel/set_voltage_sel
     19//		     list_voltage/map_voltage
     20//
     21// Each SCMI regulator instance is associated, through the means of a proper DT
     22// entry description, to a specific SCMI Voltage Domain.
     23
     24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     25
     26#include <linux/linear_range.h>
     27#include <linux/module.h>
     28#include <linux/of.h>
     29#include <linux/regulator/driver.h>
     30#include <linux/regulator/machine.h>
     31#include <linux/regulator/of_regulator.h>
     32#include <linux/scmi_protocol.h>
     33#include <linux/slab.h>
     34#include <linux/types.h>
     35
     36static const struct scmi_voltage_proto_ops *voltage_ops;
     37
     38struct scmi_regulator {
     39	u32 id;
     40	struct scmi_device *sdev;
     41	struct scmi_protocol_handle *ph;
     42	struct regulator_dev *rdev;
     43	struct device_node *of_node;
     44	struct regulator_desc desc;
     45	struct regulator_config conf;
     46};
     47
     48struct scmi_regulator_info {
     49	int num_doms;
     50	struct scmi_regulator **sregv;
     51};
     52
     53static int scmi_reg_enable(struct regulator_dev *rdev)
     54{
     55	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
     56
     57	return voltage_ops->config_set(sreg->ph, sreg->id,
     58				       SCMI_VOLTAGE_ARCH_STATE_ON);
     59}
     60
     61static int scmi_reg_disable(struct regulator_dev *rdev)
     62{
     63	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
     64
     65	return voltage_ops->config_set(sreg->ph, sreg->id,
     66				       SCMI_VOLTAGE_ARCH_STATE_OFF);
     67}
     68
     69static int scmi_reg_is_enabled(struct regulator_dev *rdev)
     70{
     71	int ret;
     72	u32 config;
     73	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
     74
     75	ret = voltage_ops->config_get(sreg->ph, sreg->id, &config);
     76	if (ret) {
     77		dev_err(&sreg->sdev->dev,
     78			"Error %d reading regulator %s status.\n",
     79			ret, sreg->desc.name);
     80		return ret;
     81	}
     82
     83	return config & SCMI_VOLTAGE_ARCH_STATE_ON;
     84}
     85
     86static int scmi_reg_get_voltage_sel(struct regulator_dev *rdev)
     87{
     88	int ret;
     89	s32 volt_uV;
     90	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
     91
     92	ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV);
     93	if (ret)
     94		return ret;
     95
     96	return sreg->desc.ops->map_voltage(rdev, volt_uV, volt_uV);
     97}
     98
     99static int scmi_reg_set_voltage_sel(struct regulator_dev *rdev,
    100				    unsigned int selector)
    101{
    102	s32 volt_uV;
    103	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
    104
    105	volt_uV = sreg->desc.ops->list_voltage(rdev, selector);
    106	if (volt_uV <= 0)
    107		return -EINVAL;
    108
    109	return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV);
    110}
    111
    112static const struct regulator_ops scmi_reg_fixed_ops = {
    113	.enable = scmi_reg_enable,
    114	.disable = scmi_reg_disable,
    115	.is_enabled = scmi_reg_is_enabled,
    116};
    117
    118static const struct regulator_ops scmi_reg_linear_ops = {
    119	.enable = scmi_reg_enable,
    120	.disable = scmi_reg_disable,
    121	.is_enabled = scmi_reg_is_enabled,
    122	.get_voltage_sel = scmi_reg_get_voltage_sel,
    123	.set_voltage_sel = scmi_reg_set_voltage_sel,
    124	.list_voltage = regulator_list_voltage_linear,
    125	.map_voltage = regulator_map_voltage_linear,
    126};
    127
    128static const struct regulator_ops scmi_reg_discrete_ops = {
    129	.enable = scmi_reg_enable,
    130	.disable = scmi_reg_disable,
    131	.is_enabled = scmi_reg_is_enabled,
    132	.get_voltage_sel = scmi_reg_get_voltage_sel,
    133	.set_voltage_sel = scmi_reg_set_voltage_sel,
    134	.list_voltage = regulator_list_voltage_table,
    135	.map_voltage = regulator_map_voltage_iterate,
    136};
    137
    138static int
    139scmi_config_linear_regulator_mappings(struct scmi_regulator *sreg,
    140				      const struct scmi_voltage_info *vinfo)
    141{
    142	s32 delta_uV;
    143
    144	/*
    145	 * Note that SCMI voltage domains describable by linear ranges
    146	 * (segments) {low, high, step} are guaranteed to come in one single
    147	 * triplet by the SCMI Voltage Domain protocol support itself.
    148	 */
    149
    150	delta_uV = (vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH] -
    151			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW]);
    152
    153	/* Rule out buggy negative-intervals answers from fw */
    154	if (delta_uV < 0) {
    155		dev_err(&sreg->sdev->dev,
    156			"Invalid volt-range %d-%duV for domain %d\n",
    157			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW],
    158			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH],
    159			sreg->id);
    160		return -EINVAL;
    161	}
    162
    163	if (!delta_uV) {
    164		/* Just one fixed voltage exposed by SCMI */
    165		sreg->desc.fixed_uV =
    166			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
    167		sreg->desc.n_voltages = 1;
    168		sreg->desc.ops = &scmi_reg_fixed_ops;
    169	} else {
    170		/* One simple linear mapping. */
    171		sreg->desc.min_uV =
    172			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
    173		sreg->desc.uV_step =
    174			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_STEP];
    175		sreg->desc.linear_min_sel = 0;
    176		sreg->desc.n_voltages = (delta_uV / sreg->desc.uV_step) + 1;
    177		sreg->desc.ops = &scmi_reg_linear_ops;
    178	}
    179
    180	return 0;
    181}
    182
    183static int
    184scmi_config_discrete_regulator_mappings(struct scmi_regulator *sreg,
    185					const struct scmi_voltage_info *vinfo)
    186{
    187	/* Discrete non linear levels are mapped to volt_table */
    188	sreg->desc.n_voltages = vinfo->num_levels;
    189
    190	if (sreg->desc.n_voltages > 1) {
    191		sreg->desc.volt_table = (const unsigned int *)vinfo->levels_uv;
    192		sreg->desc.ops = &scmi_reg_discrete_ops;
    193	} else {
    194		sreg->desc.fixed_uV = vinfo->levels_uv[0];
    195		sreg->desc.ops = &scmi_reg_fixed_ops;
    196	}
    197
    198	return 0;
    199}
    200
    201static int scmi_regulator_common_init(struct scmi_regulator *sreg)
    202{
    203	int ret;
    204	struct device *dev = &sreg->sdev->dev;
    205	const struct scmi_voltage_info *vinfo;
    206
    207	vinfo = voltage_ops->info_get(sreg->ph, sreg->id);
    208	if (!vinfo) {
    209		dev_warn(dev, "Failure to get voltage domain %d\n",
    210			 sreg->id);
    211		return -ENODEV;
    212	}
    213
    214	/*
    215	 * Regulator framework does not fully support negative voltages
    216	 * so we discard any voltage domain reported as supporting negative
    217	 * voltages: as a consequence each levels_uv entry is guaranteed to
    218	 * be non-negative from here on.
    219	 */
    220	if (vinfo->negative_volts_allowed) {
    221		dev_warn(dev, "Negative voltages NOT supported...skip %s\n",
    222			 sreg->of_node->full_name);
    223		return -EOPNOTSUPP;
    224	}
    225
    226	sreg->desc.name = devm_kasprintf(dev, GFP_KERNEL, "%s", vinfo->name);
    227	if (!sreg->desc.name)
    228		return -ENOMEM;
    229
    230	sreg->desc.id = sreg->id;
    231	sreg->desc.type = REGULATOR_VOLTAGE;
    232	sreg->desc.owner = THIS_MODULE;
    233	sreg->desc.of_match_full_name = true;
    234	sreg->desc.of_match = sreg->of_node->full_name;
    235	sreg->desc.regulators_node = "regulators";
    236	if (vinfo->segmented)
    237		ret = scmi_config_linear_regulator_mappings(sreg, vinfo);
    238	else
    239		ret = scmi_config_discrete_regulator_mappings(sreg, vinfo);
    240	if (ret)
    241		return ret;
    242
    243	/*
    244	 * Using the scmi device here to have DT searched from Voltage
    245	 * protocol node down.
    246	 */
    247	sreg->conf.dev = dev;
    248
    249	/* Store for later retrieval via rdev_get_drvdata() */
    250	sreg->conf.driver_data = sreg;
    251
    252	return 0;
    253}
    254
    255static int process_scmi_regulator_of_node(struct scmi_device *sdev,
    256					  struct scmi_protocol_handle *ph,
    257					  struct device_node *np,
    258					  struct scmi_regulator_info *rinfo)
    259{
    260	u32 dom, ret;
    261
    262	ret = of_property_read_u32(np, "reg", &dom);
    263	if (ret)
    264		return ret;
    265
    266	if (dom >= rinfo->num_doms)
    267		return -ENODEV;
    268
    269	if (rinfo->sregv[dom]) {
    270		dev_err(&sdev->dev,
    271			"SCMI Voltage Domain %d already in use. Skipping: %s\n",
    272			dom, np->full_name);
    273		return -EINVAL;
    274	}
    275
    276	rinfo->sregv[dom] = devm_kzalloc(&sdev->dev,
    277					 sizeof(struct scmi_regulator),
    278					 GFP_KERNEL);
    279	if (!rinfo->sregv[dom])
    280		return -ENOMEM;
    281
    282	rinfo->sregv[dom]->id = dom;
    283	rinfo->sregv[dom]->sdev = sdev;
    284	rinfo->sregv[dom]->ph = ph;
    285
    286	/* get hold of good nodes */
    287	of_node_get(np);
    288	rinfo->sregv[dom]->of_node = np;
    289
    290	dev_dbg(&sdev->dev,
    291		"Found SCMI Regulator entry -- OF node [%d] -> %s\n",
    292		dom, np->full_name);
    293
    294	return 0;
    295}
    296
    297static int scmi_regulator_probe(struct scmi_device *sdev)
    298{
    299	int d, ret, num_doms;
    300	struct device_node *np, *child;
    301	const struct scmi_handle *handle = sdev->handle;
    302	struct scmi_regulator_info *rinfo;
    303	struct scmi_protocol_handle *ph;
    304
    305	if (!handle)
    306		return -ENODEV;
    307
    308	voltage_ops = handle->devm_protocol_get(sdev,
    309						SCMI_PROTOCOL_VOLTAGE, &ph);
    310	if (IS_ERR(voltage_ops))
    311		return PTR_ERR(voltage_ops);
    312
    313	num_doms = voltage_ops->num_domains_get(ph);
    314	if (num_doms <= 0) {
    315		if (!num_doms) {
    316			dev_err(&sdev->dev,
    317				"number of voltage domains invalid\n");
    318			num_doms = -EINVAL;
    319		} else {
    320			dev_err(&sdev->dev,
    321				"failed to get voltage domains - err:%d\n",
    322				num_doms);
    323		}
    324
    325		return num_doms;
    326	}
    327
    328	rinfo = devm_kzalloc(&sdev->dev, sizeof(*rinfo), GFP_KERNEL);
    329	if (!rinfo)
    330		return -ENOMEM;
    331
    332	/* Allocate pointers array for all possible domains */
    333	rinfo->sregv = devm_kcalloc(&sdev->dev, num_doms,
    334				    sizeof(void *), GFP_KERNEL);
    335	if (!rinfo->sregv)
    336		return -ENOMEM;
    337
    338	rinfo->num_doms = num_doms;
    339
    340	/*
    341	 * Start collecting into rinfo->sregv possibly good SCMI Regulators as
    342	 * described by a well-formed DT entry and associated with an existing
    343	 * plausible SCMI Voltage Domain number, all belonging to this SCMI
    344	 * platform instance node (handle->dev->of_node).
    345	 */
    346	np = of_find_node_by_name(handle->dev->of_node, "regulators");
    347	for_each_child_of_node(np, child) {
    348		ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
    349		/* abort on any mem issue */
    350		if (ret == -ENOMEM) {
    351			of_node_put(child);
    352			return ret;
    353		}
    354	}
    355	of_node_put(np);
    356	/*
    357	 * Register a regulator for each valid regulator-DT-entry that we
    358	 * can successfully reach via SCMI and has a valid associated voltage
    359	 * domain.
    360	 */
    361	for (d = 0; d < num_doms; d++) {
    362		struct scmi_regulator *sreg = rinfo->sregv[d];
    363
    364		/* Skip empty slots */
    365		if (!sreg)
    366			continue;
    367
    368		ret = scmi_regulator_common_init(sreg);
    369		/* Skip invalid voltage domains */
    370		if (ret)
    371			continue;
    372
    373		sreg->rdev = devm_regulator_register(&sdev->dev, &sreg->desc,
    374						     &sreg->conf);
    375		if (IS_ERR(sreg->rdev)) {
    376			sreg->rdev = NULL;
    377			continue;
    378		}
    379
    380		dev_info(&sdev->dev,
    381			 "Regulator %s registered for domain [%d]\n",
    382			 sreg->desc.name, sreg->id);
    383	}
    384
    385	dev_set_drvdata(&sdev->dev, rinfo);
    386
    387	return 0;
    388}
    389
    390static void scmi_regulator_remove(struct scmi_device *sdev)
    391{
    392	int d;
    393	struct scmi_regulator_info *rinfo;
    394
    395	rinfo = dev_get_drvdata(&sdev->dev);
    396	if (!rinfo)
    397		return;
    398
    399	for (d = 0; d < rinfo->num_doms; d++) {
    400		if (!rinfo->sregv[d])
    401			continue;
    402		of_node_put(rinfo->sregv[d]->of_node);
    403	}
    404}
    405
    406static const struct scmi_device_id scmi_regulator_id_table[] = {
    407	{ SCMI_PROTOCOL_VOLTAGE,  "regulator" },
    408	{ },
    409};
    410MODULE_DEVICE_TABLE(scmi, scmi_regulator_id_table);
    411
    412static struct scmi_driver scmi_drv = {
    413	.name		= "scmi-regulator",
    414	.probe		= scmi_regulator_probe,
    415	.remove		= scmi_regulator_remove,
    416	.id_table	= scmi_regulator_id_table,
    417};
    418
    419module_scmi_driver(scmi_drv);
    420
    421MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
    422MODULE_DESCRIPTION("ARM SCMI regulator driver");
    423MODULE_LICENSE("GPL v2");