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

Commit 391ca3ca authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "PM / devfreq: icc: add support for L3 voting"

parents 716d4016 6540cafe
Loading
Loading
Loading
Loading
+108 −5
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2013-2014, 2018, 2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2014, 2018-2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) "devfreq-icc: " fmt
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_address.h>
#include <trace/events/power.h>
#include <linux/platform_device.h>
#include <linux/interconnect.h>
@@ -33,22 +34,33 @@ struct dev_data {
	u32				cur_ab;
	u32				cur_ib;
	unsigned long			gov_ab;
	bool				is_l3;
	struct devfreq			*df;
	struct devfreq_dev_profile	dp;
};

#define MAX_L3_ENTRIES	40U
static unsigned long	l3_freqs[MAX_L3_ENTRIES];
static			DEFINE_MUTEX(l3_freqs_lock);
static bool		use_cached_l3_freqs;

static int set_bw(struct device *dev, u32 new_ib, u32 new_ab)
{
	struct dev_data *d = dev_get_drvdata(dev);
	int ret;
	u32 icc_ib = new_ib, icc_ab = new_ab;

	if (d->cur_ib == new_ib && d->cur_ab == new_ab)
		return 0;

	dev_dbg(dev, "BW MBps: AB: %d IB: %d\n", new_ab, new_ib);
	if (!d->is_l3) {
		icc_ib = Bps_to_icc(new_ib * MBYTE);
		icc_ab = Bps_to_icc(new_ab * MBYTE);
	}

	dev_dbg(dev, "ICC BW: AB: %u IB: %u\n", icc_ab, icc_ib);

	ret = icc_set_bw(d->icc_path, Bps_to_icc(new_ab * MBYTE),
				Bps_to_icc(new_ib * MBYTE));
	ret = icc_set_bw(d->icc_path, icc_ab, icc_ib);
	if (ret < 0) {
		dev_err(dev, "icc set bandwidth request failed (%d)\n", ret);
	} else {
@@ -80,6 +92,83 @@ static int icc_get_dev_status(struct device *dev,
	return 0;
}

#define INIT_HZ			300000000UL
#define XO_HZ			19200000UL
#define FTBL_ROW_SIZE		4
#define SRC_MASK		GENMASK(31, 30)
#define SRC_SHIFT		30
#define MULT_MASK		GENMASK(7, 0)

static int populate_l3_opp_table(struct device *dev)
{
	int idx, ret;
	u32 data, src, mult, i;
	unsigned long freq, prev_freq = 0;
	struct resource res;
	void __iomem *ftbl_base;
	unsigned int ftbl_row_size = FTBL_ROW_SIZE;

	idx = of_property_match_string(dev->of_node, "reg-names", "ftbl-base");
	if (idx < 0) {
		dev_err(dev, "Unable to find ftbl-base: %d\n", idx);
		return -EINVAL;
	}

	ret = of_address_to_resource(dev->of_node, idx, &res);
	if (ret < 0) {
		dev_err(dev, "Unable to get resource from address: %d\n", ret);
		return -EINVAL;
	}

	ftbl_base = devm_ioremap(dev, res.start, resource_size(&res));
	if (!ftbl_base) {
		dev_err(dev, "Unable to map ftbl-base!\n");
		return -ENOMEM;
	}

	of_property_read_u32(dev->of_node, "qcom,ftbl-row-size",
						&ftbl_row_size);

	for (i = 0; i < MAX_L3_ENTRIES; i++) {
		data = readl_relaxed(ftbl_base + i * ftbl_row_size);
		src = ((data & SRC_MASK) >> SRC_SHIFT);
		mult = (data & MULT_MASK);
		freq = src ? XO_HZ * mult : INIT_HZ;

		/* Two of the same frequencies means end of table */
		if (i > 0 && prev_freq == freq)
			break;

		dev_pm_opp_add(dev, freq, 0);
		l3_freqs[i] = freq;
		prev_freq = freq;
	}

	devm_iounmap(dev, ftbl_base);
	use_cached_l3_freqs = true;

	return 0;
}

static int copy_l3_opp_table(struct device *dev)
{
	int idx;

	for (idx = 0; idx < MAX_L3_ENTRIES; idx++) {
		if (l3_freqs[idx])
			dev_pm_opp_add(dev, l3_freqs[idx], 0);
		else
			break;
	}

	if (!idx) {
		dev_err(dev, "No L3 frequencies copied for device!\n");
		return -EINVAL;
	}

	return 0;
}

#define PROP_ACTIVE	"qcom,active-only"
#define ACTIVE_ONLY_TAG	0x3

@@ -111,7 +200,20 @@ int devfreq_add_icc(struct device *dev)
		}
	}

	if (of_device_is_compatible(dev->of_node, "qcom,devfreq-icc-l3")) {
		mutex_lock(&l3_freqs_lock);
		if (use_cached_l3_freqs) {
			mutex_unlock(&l3_freqs_lock);
			ret = copy_l3_opp_table(dev);
		} else {
			ret = populate_l3_opp_table(dev);
			mutex_unlock(&l3_freqs_lock);
		}
		d->is_l3 = true;
	} else {
		ret = dev_pm_opp_of_add_table(dev);
		d->is_l3 = false;
	}
	if (ret < 0)
		dev_err(dev, "Couldn't parse OPP table:%d\n", ret);

@@ -172,6 +274,7 @@ static int devfreq_icc_remove(struct platform_device *pdev)
}

static const struct of_device_id devfreq_icc_match_table[] = {
	{ .compatible = "qcom,devfreq-icc-l3" },
	{ .compatible = "qcom,devfreq-icc-llcc" },
	{ .compatible = "qcom,devfreq-icc-ddr" },
	{ .compatible = "qcom,devfreq-icc" },
+3 −0
Original line number Diff line number Diff line
@@ -489,6 +489,9 @@ static struct memlat_node *register_common(struct device *dev,
	if (hw->get_child_of_node)
		of_node = hw->get_child_of_node(dev);

	if (of_parse_phandle(of_node, "qcom,core-dev-table", 0))
		of_node = of_parse_phandle(of_node, "qcom,core-dev-table", 0);

	hw->freq_map = init_core_dev_map(dev, of_node, "qcom,core-dev-table");

	if (!hw->freq_map) {