18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Voltage regulators coupler for NVIDIA Tegra30
48c2ecf20Sopenharmony_ci * Copyright (C) 2019 GRATE-DRIVER project
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Voltage constraints borrowed from downstream kernel sources
78c2ecf20Sopenharmony_ci * Copyright (C) 2010-2011 NVIDIA Corporation
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define pr_fmt(fmt)	"tegra voltage-coupler: " fmt
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/of.h>
158c2ecf20Sopenharmony_ci#include <linux/regulator/coupler.h>
168c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
178c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <soc/tegra/fuse.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct tegra_regulator_coupler {
228c2ecf20Sopenharmony_ci	struct regulator_coupler coupler;
238c2ecf20Sopenharmony_ci	struct regulator_dev *core_rdev;
248c2ecf20Sopenharmony_ci	struct regulator_dev *cpu_rdev;
258c2ecf20Sopenharmony_ci	int core_min_uV;
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic inline struct tegra_regulator_coupler *
298c2ecf20Sopenharmony_cito_tegra_coupler(struct regulator_coupler *coupler)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	return container_of(coupler, struct tegra_regulator_coupler, coupler);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic int tegra30_core_limit(struct tegra_regulator_coupler *tegra,
358c2ecf20Sopenharmony_ci			      struct regulator_dev *core_rdev)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	int core_min_uV = 0;
388c2ecf20Sopenharmony_ci	int core_max_uV;
398c2ecf20Sopenharmony_ci	int core_cur_uV;
408c2ecf20Sopenharmony_ci	int err;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (tegra->core_min_uV > 0)
438c2ecf20Sopenharmony_ci		return tegra->core_min_uV;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	core_cur_uV = regulator_get_voltage_rdev(core_rdev);
468c2ecf20Sopenharmony_ci	if (core_cur_uV < 0)
478c2ecf20Sopenharmony_ci		return core_cur_uV;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	core_max_uV = max(core_cur_uV, 1200000);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
528c2ecf20Sopenharmony_ci	if (err)
538c2ecf20Sopenharmony_ci		return err;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	/*
568c2ecf20Sopenharmony_ci	 * Limit minimum CORE voltage to a value left from bootloader or,
578c2ecf20Sopenharmony_ci	 * if it's unreasonably low value, to the most common 1.2v or to
588c2ecf20Sopenharmony_ci	 * whatever maximum value defined via board's device-tree.
598c2ecf20Sopenharmony_ci	 */
608c2ecf20Sopenharmony_ci	tegra->core_min_uV = core_max_uV;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return tegra->core_min_uV;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int tegra30_core_cpu_limit(int cpu_uV)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	if (cpu_uV < 800000)
708c2ecf20Sopenharmony_ci		return 950000;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (cpu_uV < 900000)
738c2ecf20Sopenharmony_ci		return 1000000;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (cpu_uV < 1000000)
768c2ecf20Sopenharmony_ci		return 1100000;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (cpu_uV < 1100000)
798c2ecf20Sopenharmony_ci		return 1200000;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (cpu_uV < 1250000) {
828c2ecf20Sopenharmony_ci		switch (tegra_sku_info.cpu_speedo_id) {
838c2ecf20Sopenharmony_ci		case 0 ... 1:
848c2ecf20Sopenharmony_ci		case 4:
858c2ecf20Sopenharmony_ci		case 7 ... 8:
868c2ecf20Sopenharmony_ci			return 1200000;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		default:
898c2ecf20Sopenharmony_ci			return 1300000;
908c2ecf20Sopenharmony_ci		}
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return -EINVAL;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int tegra30_voltage_update(struct tegra_regulator_coupler *tegra,
978c2ecf20Sopenharmony_ci				  struct regulator_dev *cpu_rdev,
988c2ecf20Sopenharmony_ci				  struct regulator_dev *core_rdev)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	int core_min_uV, core_max_uV = INT_MAX;
1018c2ecf20Sopenharmony_ci	int cpu_min_uV, cpu_max_uV = INT_MAX;
1028c2ecf20Sopenharmony_ci	int cpu_min_uV_consumers = 0;
1038c2ecf20Sopenharmony_ci	int core_min_limited_uV;
1048c2ecf20Sopenharmony_ci	int core_target_uV;
1058c2ecf20Sopenharmony_ci	int cpu_target_uV;
1068c2ecf20Sopenharmony_ci	int core_max_step;
1078c2ecf20Sopenharmony_ci	int cpu_max_step;
1088c2ecf20Sopenharmony_ci	int max_spread;
1098c2ecf20Sopenharmony_ci	int core_uV;
1108c2ecf20Sopenharmony_ci	int cpu_uV;
1118c2ecf20Sopenharmony_ci	int err;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/*
1148c2ecf20Sopenharmony_ci	 * CPU voltage should not got lower than 300mV from the CORE.
1158c2ecf20Sopenharmony_ci	 * CPU voltage should stay below the CORE by 100mV+, depending
1168c2ecf20Sopenharmony_ci	 * by the CORE voltage. This applies to all Tegra30 SoC's.
1178c2ecf20Sopenharmony_ci	 */
1188c2ecf20Sopenharmony_ci	max_spread = cpu_rdev->constraints->max_spread[0];
1198c2ecf20Sopenharmony_ci	cpu_max_step = cpu_rdev->constraints->max_uV_step;
1208c2ecf20Sopenharmony_ci	core_max_step = core_rdev->constraints->max_uV_step;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (!max_spread) {
1238c2ecf20Sopenharmony_ci		pr_err_once("cpu-core max-spread is undefined in device-tree\n");
1248c2ecf20Sopenharmony_ci		max_spread = 300000;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (!cpu_max_step) {
1288c2ecf20Sopenharmony_ci		pr_err_once("cpu max-step is undefined in device-tree\n");
1298c2ecf20Sopenharmony_ci		cpu_max_step = 150000;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (!core_max_step) {
1338c2ecf20Sopenharmony_ci		pr_err_once("core max-step is undefined in device-tree\n");
1348c2ecf20Sopenharmony_ci		core_max_step = 150000;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/*
1388c2ecf20Sopenharmony_ci	 * The CORE voltage scaling is currently not hooked up in drivers,
1398c2ecf20Sopenharmony_ci	 * hence we will limit the minimum CORE voltage to a reasonable value.
1408c2ecf20Sopenharmony_ci	 * This should be good enough for the time being.
1418c2ecf20Sopenharmony_ci	 */
1428c2ecf20Sopenharmony_ci	core_min_uV = tegra30_core_limit(tegra, core_rdev);
1438c2ecf20Sopenharmony_ci	if (core_min_uV < 0)
1448c2ecf20Sopenharmony_ci		return core_min_uV;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
1478c2ecf20Sopenharmony_ci					PM_SUSPEND_ON);
1488c2ecf20Sopenharmony_ci	if (err)
1498c2ecf20Sopenharmony_ci		return err;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	core_uV = regulator_get_voltage_rdev(core_rdev);
1528c2ecf20Sopenharmony_ci	if (core_uV < 0)
1538c2ecf20Sopenharmony_ci		return core_uV;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	cpu_min_uV = core_min_uV - max_spread;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
1588c2ecf20Sopenharmony_ci					PM_SUSPEND_ON);
1598c2ecf20Sopenharmony_ci	if (err)
1608c2ecf20Sopenharmony_ci		return err;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
1638c2ecf20Sopenharmony_ci					&cpu_max_uV, PM_SUSPEND_ON);
1648c2ecf20Sopenharmony_ci	if (err)
1658c2ecf20Sopenharmony_ci		return err;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
1688c2ecf20Sopenharmony_ci	if (err)
1698c2ecf20Sopenharmony_ci		return err;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
1728c2ecf20Sopenharmony_ci	if (cpu_uV < 0)
1738c2ecf20Sopenharmony_ci		return cpu_uV;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/*
1768c2ecf20Sopenharmony_ci	 * CPU's regulator may not have any consumers, hence the voltage
1778c2ecf20Sopenharmony_ci	 * must not be changed in that case because CPU simply won't
1788c2ecf20Sopenharmony_ci	 * survive the voltage drop if it's running on a higher frequency.
1798c2ecf20Sopenharmony_ci	 */
1808c2ecf20Sopenharmony_ci	if (!cpu_min_uV_consumers)
1818c2ecf20Sopenharmony_ci		cpu_min_uV = max(cpu_uV, cpu_min_uV);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/*
1848c2ecf20Sopenharmony_ci	 * Bootloader shall set up voltages correctly, but if it
1858c2ecf20Sopenharmony_ci	 * happens that there is a violation, then try to fix it
1868c2ecf20Sopenharmony_ci	 * at first.
1878c2ecf20Sopenharmony_ci	 */
1888c2ecf20Sopenharmony_ci	core_min_limited_uV = tegra30_core_cpu_limit(cpu_uV);
1898c2ecf20Sopenharmony_ci	if (core_min_limited_uV < 0)
1908c2ecf20Sopenharmony_ci		return core_min_limited_uV;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	core_min_uV = max(core_min_uV, tegra30_core_cpu_limit(cpu_min_uV));
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
1958c2ecf20Sopenharmony_ci	if (err)
1968c2ecf20Sopenharmony_ci		return err;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (core_min_limited_uV > core_uV) {
1998c2ecf20Sopenharmony_ci		pr_err("core voltage constraint violated: %d %d %d\n",
2008c2ecf20Sopenharmony_ci		       core_uV, core_min_limited_uV, cpu_uV);
2018c2ecf20Sopenharmony_ci		goto update_core;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	while (cpu_uV != cpu_min_uV || core_uV != core_min_uV) {
2058c2ecf20Sopenharmony_ci		if (cpu_uV < cpu_min_uV) {
2068c2ecf20Sopenharmony_ci			cpu_target_uV = min(cpu_uV + cpu_max_step, cpu_min_uV);
2078c2ecf20Sopenharmony_ci		} else {
2088c2ecf20Sopenharmony_ci			cpu_target_uV = max(cpu_uV - cpu_max_step, cpu_min_uV);
2098c2ecf20Sopenharmony_ci			cpu_target_uV = max(core_uV - max_spread, cpu_target_uV);
2108c2ecf20Sopenharmony_ci		}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci		if (cpu_uV == cpu_target_uV)
2138c2ecf20Sopenharmony_ci			goto update_core;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		err = regulator_set_voltage_rdev(cpu_rdev,
2168c2ecf20Sopenharmony_ci						 cpu_target_uV,
2178c2ecf20Sopenharmony_ci						 cpu_max_uV,
2188c2ecf20Sopenharmony_ci						 PM_SUSPEND_ON);
2198c2ecf20Sopenharmony_ci		if (err)
2208c2ecf20Sopenharmony_ci			return err;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		cpu_uV = cpu_target_uV;
2238c2ecf20Sopenharmony_ciupdate_core:
2248c2ecf20Sopenharmony_ci		core_min_limited_uV = tegra30_core_cpu_limit(cpu_uV);
2258c2ecf20Sopenharmony_ci		if (core_min_limited_uV < 0)
2268c2ecf20Sopenharmony_ci			return core_min_limited_uV;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		core_target_uV = max(core_min_limited_uV, core_min_uV);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		if (core_uV < core_target_uV) {
2318c2ecf20Sopenharmony_ci			core_target_uV = min(core_target_uV, core_uV + core_max_step);
2328c2ecf20Sopenharmony_ci			core_target_uV = min(core_target_uV, cpu_uV + max_spread);
2338c2ecf20Sopenharmony_ci		} else {
2348c2ecf20Sopenharmony_ci			core_target_uV = max(core_target_uV, core_uV - core_max_step);
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci		if (core_uV == core_target_uV)
2388c2ecf20Sopenharmony_ci			continue;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		err = regulator_set_voltage_rdev(core_rdev,
2418c2ecf20Sopenharmony_ci						 core_target_uV,
2428c2ecf20Sopenharmony_ci						 core_max_uV,
2438c2ecf20Sopenharmony_ci						 PM_SUSPEND_ON);
2448c2ecf20Sopenharmony_ci		if (err)
2458c2ecf20Sopenharmony_ci			return err;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		core_uV = core_target_uV;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return 0;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler,
2548c2ecf20Sopenharmony_ci					     struct regulator_dev *rdev,
2558c2ecf20Sopenharmony_ci					     suspend_state_t state)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
2588c2ecf20Sopenharmony_ci	struct regulator_dev *core_rdev = tegra->core_rdev;
2598c2ecf20Sopenharmony_ci	struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if ((core_rdev != rdev && cpu_rdev != rdev) || state != PM_SUSPEND_ON) {
2628c2ecf20Sopenharmony_ci		pr_err("regulators are not coupled properly\n");
2638c2ecf20Sopenharmony_ci		return -EINVAL;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	return tegra30_voltage_update(tegra, cpu_rdev, core_rdev);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic int tegra30_regulator_attach(struct regulator_coupler *coupler,
2708c2ecf20Sopenharmony_ci				    struct regulator_dev *rdev)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
2738c2ecf20Sopenharmony_ci	struct device_node *np = rdev->dev.of_node;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
2768c2ecf20Sopenharmony_ci	    !tegra->core_rdev) {
2778c2ecf20Sopenharmony_ci		tegra->core_rdev = rdev;
2788c2ecf20Sopenharmony_ci		return 0;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
2828c2ecf20Sopenharmony_ci	    !tegra->cpu_rdev) {
2838c2ecf20Sopenharmony_ci		tegra->cpu_rdev = rdev;
2848c2ecf20Sopenharmony_ci		return 0;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	return -EINVAL;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int tegra30_regulator_detach(struct regulator_coupler *coupler,
2918c2ecf20Sopenharmony_ci				    struct regulator_dev *rdev)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (tegra->core_rdev == rdev) {
2968c2ecf20Sopenharmony_ci		tegra->core_rdev = NULL;
2978c2ecf20Sopenharmony_ci		return 0;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (tegra->cpu_rdev == rdev) {
3018c2ecf20Sopenharmony_ci		tegra->cpu_rdev = NULL;
3028c2ecf20Sopenharmony_ci		return 0;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return -EINVAL;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic struct tegra_regulator_coupler tegra30_coupler = {
3098c2ecf20Sopenharmony_ci	.coupler = {
3108c2ecf20Sopenharmony_ci		.attach_regulator = tegra30_regulator_attach,
3118c2ecf20Sopenharmony_ci		.detach_regulator = tegra30_regulator_detach,
3128c2ecf20Sopenharmony_ci		.balance_voltage = tegra30_regulator_balance_voltage,
3138c2ecf20Sopenharmony_ci	},
3148c2ecf20Sopenharmony_ci};
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int __init tegra_regulator_coupler_init(void)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	if (!of_machine_is_compatible("nvidia,tegra30"))
3198c2ecf20Sopenharmony_ci		return 0;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return regulator_coupler_register(&tegra30_coupler.coupler);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ciarch_initcall(tegra_regulator_coupler_init);
324