brintos

brintos / linux-shallow public Read only

0
0
Text · 3.7 KiB · 97006cc Raw
169 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2019 Samsung Electronics Co., Ltd.4 *	      http://www.samsung.com/5 * Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org>6 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>7 * Author: Krzysztof Kozlowski <krzk@kernel.org>8 *9 * Samsung Exynos SoC Adaptive Supply Voltage support10 */11 12#include <linux/cpu.h>13#include <linux/device.h>14#include <linux/energy_model.h>15#include <linux/errno.h>16#include <linux/of.h>17#include <linux/pm_opp.h>18#include <linux/regmap.h>19#include <linux/soc/samsung/exynos-chipid.h>20 21#include "exynos-asv.h"22#include "exynos5422-asv.h"23 24#define MHZ 1000000U25 26static int exynos_asv_update_cpu_opps(struct exynos_asv *asv,27				      struct device *cpu)28{29	struct exynos_asv_subsys *subsys = NULL;30	struct dev_pm_opp *opp;31	unsigned int opp_freq;32	int i;33 34	for (i = 0; i < ARRAY_SIZE(asv->subsys); i++) {35		if (of_device_is_compatible(cpu->of_node,36					    asv->subsys[i].cpu_dt_compat)) {37			subsys = &asv->subsys[i];38			break;39		}40	}41	if (!subsys)42		return -EINVAL;43 44	for (i = 0; i < subsys->table.num_rows; i++) {45		unsigned int new_volt, volt;46		int ret;47 48		opp_freq = exynos_asv_opp_get_frequency(subsys, i);49 50		opp = dev_pm_opp_find_freq_exact(cpu, opp_freq * MHZ, true);51		if (IS_ERR(opp)) {52			dev_info(asv->dev, "cpu%d opp%d, freq: %u missing\n",53				 cpu->id, i, opp_freq);54 55			continue;56		}57 58		volt = dev_pm_opp_get_voltage(opp);59		new_volt = asv->opp_get_voltage(subsys, i, volt);60		dev_pm_opp_put(opp);61 62		if (new_volt == volt)63			continue;64 65		ret = dev_pm_opp_adjust_voltage(cpu, opp_freq * MHZ,66						new_volt, new_volt, new_volt);67		if (ret < 0)68			dev_err(asv->dev,69				"Failed to adjust OPP %u Hz/%u uV for cpu%d\n",70				opp_freq, new_volt, cpu->id);71		else72			dev_dbg(asv->dev,73				"Adjusted OPP %u Hz/%u -> %u uV, cpu%d\n",74				opp_freq, volt, new_volt, cpu->id);75	}76 77	return 0;78}79 80static int exynos_asv_update_opps(struct exynos_asv *asv)81{82	struct opp_table *last_opp_table = NULL;83	struct device *cpu;84	int ret, cpuid;85 86	for_each_possible_cpu(cpuid) {87		struct opp_table *opp_table;88 89		cpu = get_cpu_device(cpuid);90		if (!cpu)91			continue;92 93		opp_table = dev_pm_opp_get_opp_table(cpu);94		if (IS_ERR(opp_table))95			continue;96 97		if (!last_opp_table || opp_table != last_opp_table) {98			last_opp_table = opp_table;99 100			ret = exynos_asv_update_cpu_opps(asv, cpu);101			if (!ret) {102				/*103				 * Update EM power values since OPP104				 * voltage values may have changed.105				 */106				em_dev_update_chip_binning(cpu);107			} else {108				dev_err(asv->dev, "Couldn't udate OPPs for cpu%d\n",109					cpuid);110			}111		}112 113		dev_pm_opp_put_opp_table(opp_table);114	}115 116	return	0;117}118 119int exynos_asv_init(struct device *dev, struct regmap *regmap)120{121	int (*probe_func)(struct exynos_asv *asv);122	struct exynos_asv *asv;123	struct device *cpu_dev;124	u32 product_id = 0;125	int ret, i;126 127	asv = devm_kzalloc(dev, sizeof(*asv), GFP_KERNEL);128	if (!asv)129		return -ENOMEM;130 131	asv->chipid_regmap = regmap;132	asv->dev = dev;133	ret = regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID,134			  &product_id);135	if (ret < 0) {136		dev_err(dev, "Cannot read revision from ChipID: %d\n", ret);137		return -ENODEV;138	}139 140	switch (product_id & EXYNOS_MASK) {141	case 0xE5422000:142		probe_func = exynos5422_asv_init;143		break;144	default:145		dev_dbg(dev, "No ASV support for this SoC\n");146		devm_kfree(dev, asv);147		return 0;148	}149 150	cpu_dev = get_cpu_device(0);151	ret = dev_pm_opp_get_opp_count(cpu_dev);152	if (ret < 0)153		return -EPROBE_DEFER;154 155	ret = of_property_read_u32(dev->of_node, "samsung,asv-bin",156				   &asv->of_bin);157	if (ret < 0)158		asv->of_bin = -EINVAL;159 160	for (i = 0; i < ARRAY_SIZE(asv->subsys); i++)161		asv->subsys[i].asv = asv;162 163	ret = probe_func(asv);164	if (ret < 0)165		return ret;166 167	return exynos_asv_update_opps(asv);168}169