Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6acb90f authored by Vikram Mulukutla's avatar Vikram Mulukutla Committed by David Collins
Browse files

qcom: clock-cpu-8994: Populate absolute voltages in CPU-device OPP tables



Previously, the MSM8994 CPU clock driver populated the
two CPR regulator devices (one per CPU power rail) with
OPP tables containing frequency to corner mappings. The
CPR regulator driver will now populate its own devices
with corner to voltage mappings. If those OPP tables are
present, populate the CPU devices with frequency to voltage
mappings.

Change-Id: Iebbb0a03040686566dd2c65ecb8248869e1359f5
Signed-off-by: default avatarVikram Mulukutla <markivx@codeaurora.org>
parent 768b0343
Loading
Loading
Loading
Loading
+129 −16
Original line number Diff line number Diff line
@@ -1178,11 +1178,39 @@ static void perform_v1_fixup(void)
	__cpu_mux_set_sel(&a53_lf_mux, 1);
}

static int add_opp(struct clk *c, struct device *dev, unsigned long max_rate)
static long corner_to_voltage(unsigned long corner, struct device *dev)
{
	struct opp *oppl;
	long uv;

	rcu_read_lock();
	oppl = dev_pm_opp_find_freq_exact(dev, corner, true);
	rcu_read_unlock();
	if (IS_ERR_OR_NULL(oppl))
		return -EINVAL;

	rcu_read_lock();
	uv = dev_pm_opp_get_voltage(oppl);
	rcu_read_unlock();

	return uv;
}

static int add_opp(struct clk *c, struct device *cpudev, struct device *vregdev,
			unsigned long max_rate)
{
	unsigned long rate = 0;
	int level;
	long ret;
	long ret, uv, corner;
	bool use_voltages = false;
	struct opp *oppl;

	rcu_read_lock();
	/* Check if the regulator driver has already populated OPP tables */
	oppl = dev_pm_opp_find_freq_exact(vregdev, 2, true);
	rcu_read_unlock();
	if (!IS_ERR_OR_NULL(oppl))
		use_voltages = true;

	while (1) {
		ret = clk_round_rate(c, rate + 1);
@@ -1196,11 +1224,43 @@ static int add_opp(struct clk *c, struct device *dev, unsigned long max_rate)
			pr_warn("clock-cpu: no uv for %lu.\n", rate);
			return -EINVAL;
		}
		ret = dev_pm_opp_add(dev, rate, c->vdd_class->vdd_uv[level]);
		uv = corner = c->vdd_class->vdd_uv[level];
		/*
		 * If corner to voltage mapping is available, populate the OPP
		 * table with the voltages rather than corners.
		 */
		if (use_voltages) {
			uv = corner_to_voltage(corner, vregdev);
			if (uv < 0) {
				pr_warn("clock-cpu: no uv for corner %lu\n",
					 corner);
				return uv;
			}
			ret = dev_pm_opp_add(cpudev, rate, uv);
			if (ret) {
				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
					 rate);
				return ret;
			}
		} else {
			/*
			 * Populate both CPU and regulator devices with the
			 * freq-to-corner OPP table to maintain backward
			 * compatibility.
			 */
			ret = dev_pm_opp_add(cpudev, rate, corner);
			if (ret) {
				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
					rate);
				return ret;
			}
			ret = dev_pm_opp_add(vregdev, rate, corner);
			if (ret) {
			pr_warn("clock-cpu: failed to add OPP for %lu\n", rate);
				pr_warn("clock-cpu: couldn't add OPP for %lu\n",
					rate);
				return ret;
			}
		}
		if (rate >= max_rate)
			break;
	}
@@ -1208,20 +1268,52 @@ static int add_opp(struct clk *c, struct device *dev, unsigned long max_rate)
	return 0;
}

static void print_opp_table(int a53_cpu, int a57_cpu)
{
	struct opp *oppfmax, *oppfmin;
	unsigned long apc0_fmax = a53_clk.c.fmax[a53_clk.c.num_fmax - 1];
	unsigned long apc1_fmax = a57_clk.c.fmax[a57_clk.c.num_fmax - 1];
	unsigned long apc0_fmin = a53_clk.c.fmax[1];
	unsigned long apc1_fmin = a57_clk.c.fmax[1];

	rcu_read_lock();
	oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a53_cpu), apc0_fmax,
					     true);
	oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a53_cpu), apc0_fmin,
					     true);
	/*
	 * One time information during boot. Important to know that this looks
	 * sane since it can eventually make its way to the scheduler.
	 */
	pr_info("clock_cpu: a53: OPP voltage for %lu: %ld\n", apc0_fmin,
		dev_pm_opp_get_voltage(oppfmin));
	pr_info("clock_cpu: a53: OPP voltage for %lu: %ld\n", apc0_fmax,
		dev_pm_opp_get_voltage(oppfmax));

	oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(a57_cpu), apc1_fmax,
					     true);
	oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(a57_cpu), apc1_fmin,
					     true);
	pr_info("clock_cpu: a57: OPP voltage for %lu: %lu\n", apc1_fmin,
		dev_pm_opp_get_voltage(oppfmin));
	pr_info("clock_cpu: a57: OPP voltage for %lu: %lu\n", apc1_fmax,
		dev_pm_opp_get_voltage(oppfmax));
	rcu_read_unlock();
}

static void populate_opp_table(struct platform_device *pdev)
{
	struct platform_device *apc0_dev, *apc1_dev;
	struct device_node *apc0_node, *apc1_node;
	unsigned long apc0_fmax, apc1_fmax;
	int cpu, a53_cpu, a57_cpu;

	apc0_node = of_parse_phandle(pdev->dev.of_node, "vdd-a53-supply", 0);
	apc1_node = of_parse_phandle(pdev->dev.of_node, "vdd-a57-supply", 0);

	if (!apc0_node) {
		pr_err("can't find the apc0 dt node.\n");
		return;
	}

	if (!apc1_node) {
		pr_err("can't find the apc1 dt node.\n");
		return;
@@ -1229,12 +1321,10 @@ static void populate_opp_table(struct platform_device *pdev)

	apc0_dev = of_find_device_by_node(apc0_node);
	apc1_dev = of_find_device_by_node(apc1_node);

	if (!apc0_dev) {
		pr_err("can't find the apc0 device node.\n");
		return;
	}

	if (!apc1_dev) {
		pr_err("can't find the apc1 device node.\n");
		return;
@@ -1243,16 +1333,30 @@ static void populate_opp_table(struct platform_device *pdev)
	apc0_fmax = a53_clk.c.fmax[a53_clk.c.num_fmax - 1];
	apc1_fmax = a57_clk.c.fmax[a57_clk.c.num_fmax - 1];

	WARN(add_opp(&a53_clk.c, &apc0_dev->dev, apc0_fmax),
	for_each_possible_cpu(cpu) {
		if (logical_cpu_to_clk(cpu) == &a53_clk.c) {
			a53_cpu = cpu;
			WARN(add_opp(&a53_clk.c, get_cpu_device(cpu),
				     &apc0_dev->dev, apc0_fmax),
				     "Failed to add OPP levels for A53\n");
	WARN(add_opp(&a57_clk.c, &apc1_dev->dev, apc1_fmax),
		}
		if (logical_cpu_to_clk(cpu) == &a57_clk.c) {
			a57_cpu = cpu;
			WARN(add_opp(&a57_clk.c, get_cpu_device(cpu),
				     &apc1_dev->dev, apc1_fmax),
				     "Failed to add OPP levels for A57\n");
		}
	}

	/* One time print during bootup */
	pr_info("clock-cpu-8994: OPP tables populated.\n");
	pr_info("clock-cpu-8994: OPP tables populated (cpu %d and %d)",
		a53_cpu, a57_cpu);

	print_opp_table(a53_cpu, a57_cpu);
}

static int a57speedbin;
struct platform_device *cpu_clock_8994_dev;

static int cpu_clock_8994_driver_probe(struct platform_device *pdev)
{
@@ -1264,6 +1368,7 @@ static int cpu_clock_8994_driver_probe(struct platform_device *pdev)
	char a57speedbinstr[] = "qcom,a57-speedbinXX-vXX";

	v2 = msm8994_v2;
	cpu_clock_8994_dev = pdev;

	a53_pll0_main.c.flags = CLKFLAG_NO_RATE_CACHE;
	a57_pll0_main.c.flags = CLKFLAG_NO_RATE_CACHE;
@@ -1395,7 +1500,6 @@ static int cpu_clock_8994_driver_probe(struct platform_device *pdev)
		clk_set_rate(&cci_clk.c, 300000000);
	}

	populate_opp_table(pdev);

	put_online_cpus();

@@ -1417,6 +1521,15 @@ static struct platform_driver cpu_clock_8994_driver = {
	},
};

/* CPU devices are not currently available in arch_initcall */
static int __init cpu_clock_8994_init_opp(void)
{
	if (cpu_clock_8994_dev)
		populate_opp_table(cpu_clock_8994_dev);
	return 0;
}
module_init(cpu_clock_8994_init_opp);

static int __init cpu_clock_8994_init(void)
{
	return platform_driver_register(&cpu_clock_8994_driver);