mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 20:33:58 -04:00
Merge "PM / devfreq: icc: add support for L3 voting"
This commit is contained in:
commit
391ca3ca20
2 changed files with 111 additions and 5 deletions
|
|
@ -1,6 +1,6 @@
|
|||
// 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);
|
||||
}
|
||||
|
||||
ret = icc_set_bw(d->icc_path, Bps_to_icc(new_ab * MBYTE),
|
||||
Bps_to_icc(new_ib * MBYTE));
|
||||
dev_dbg(dev, "ICC BW: AB: %u IB: %u\n", icc_ab, icc_ib);
|
||||
|
||||
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)
|
|||
}
|
||||
}
|
||||
|
||||
ret = dev_pm_opp_of_add_table(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" },
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue