mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
PM / devfreq: icc: add support for L3 BW devices
Add support for L3 bandwidth devices that vote in units of MBPS. This includes creating OPP tables in units of MBPS as well as requiring that these devices define a width in DT which is used to convert the votes to Hz before submitting them to the L3 provider. Change-Id: I47a569f76b9e57caac57788592784921c689505b Signed-off-by: Amir Vajid <[email protected]>
This commit is contained in:
parent
e1bdeb4100
commit
7e0c383b72
1 changed files with 61 additions and 14 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-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "devfreq-icc: " fmt
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <trace/events/power.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interconnect.h>
|
||||
|
|
@ -28,13 +29,27 @@
|
|||
|
||||
/* Has to be ULL to prevent overflow where this macro is used. */
|
||||
#define MBYTE (1ULL << 20)
|
||||
#define HZ_TO_MBPS(hz, w) (mult_frac(w, hz, MBYTE))
|
||||
#define MBPS_TO_HZ(mbps, w) (mult_frac(mbps, MBYTE, w))
|
||||
|
||||
enum dev_type {
|
||||
STD_MBPS_DEV,
|
||||
L3_HZ_DEV,
|
||||
L3_MBPS_DEV,
|
||||
NUM_DEV_TYPES
|
||||
};
|
||||
|
||||
struct devfreq_icc_spec {
|
||||
enum dev_type type;
|
||||
};
|
||||
|
||||
struct dev_data {
|
||||
struct icc_path *icc_path;
|
||||
u32 cur_ab;
|
||||
u32 cur_ib;
|
||||
unsigned long gov_ab;
|
||||
bool is_l3;
|
||||
const struct devfreq_icc_spec *spec;
|
||||
unsigned int width;
|
||||
struct devfreq *df;
|
||||
struct devfreq_dev_profile dp;
|
||||
};
|
||||
|
|
@ -53,7 +68,10 @@ static int set_bw(struct device *dev, u32 new_ib, u32 new_ab)
|
|||
if (d->cur_ib == new_ib && d->cur_ab == new_ab)
|
||||
return 0;
|
||||
|
||||
if (!d->is_l3) {
|
||||
if (d->spec->type == L3_MBPS_DEV) {
|
||||
icc_ib = MBPS_TO_HZ(new_ib, d->width);
|
||||
icc_ab = MBPS_TO_HZ(new_ab, d->width);
|
||||
} else if (d->spec->type == STD_MBPS_DEV) {
|
||||
icc_ib = Bps_to_icc(new_ib * MBYTE);
|
||||
icc_ab = Bps_to_icc(new_ab * MBYTE);
|
||||
}
|
||||
|
|
@ -101,6 +119,7 @@ static int icc_get_dev_status(struct device *dev,
|
|||
|
||||
static int populate_l3_opp_table(struct device *dev)
|
||||
{
|
||||
struct dev_data *d = dev_get_drvdata(dev);
|
||||
int idx, ret;
|
||||
u32 data, src, mult, i;
|
||||
unsigned long freq, prev_freq = 0;
|
||||
|
|
@ -139,7 +158,10 @@ static int populate_l3_opp_table(struct device *dev)
|
|||
if (i > 0 && prev_freq == freq)
|
||||
break;
|
||||
|
||||
dev_pm_opp_add(dev, freq, 0);
|
||||
if (d->spec->type == L3_MBPS_DEV)
|
||||
dev_pm_opp_add(dev, HZ_TO_MBPS(freq, d->width), 0);
|
||||
else
|
||||
dev_pm_opp_add(dev, freq, 0);
|
||||
l3_freqs[i] = freq;
|
||||
prev_freq = freq;
|
||||
}
|
||||
|
|
@ -152,13 +174,18 @@ static int populate_l3_opp_table(struct device *dev)
|
|||
|
||||
static int copy_l3_opp_table(struct device *dev)
|
||||
{
|
||||
struct dev_data *d = dev_get_drvdata(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
|
||||
if (!l3_freqs[idx])
|
||||
break;
|
||||
|
||||
if (d->spec->type == L3_MBPS_DEV)
|
||||
dev_pm_opp_add(dev,
|
||||
HZ_TO_MBPS(l3_freqs[idx], d->width), 0);
|
||||
else
|
||||
dev_pm_opp_add(dev, l3_freqs[idx], 0);
|
||||
}
|
||||
|
||||
if (!idx) {
|
||||
|
|
@ -186,6 +213,12 @@ int devfreq_add_icc(struct device *dev)
|
|||
return -ENOMEM;
|
||||
dev_set_drvdata(dev, d);
|
||||
|
||||
d->spec = of_device_get_match_data(dev);
|
||||
if (!d->spec) {
|
||||
dev_err(dev, "Unknown device type!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
p = &d->dp;
|
||||
p->polling_ms = 50;
|
||||
p->target = icc_target;
|
||||
|
|
@ -200,7 +233,16 @@ int devfreq_add_icc(struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(dev->of_node, "qcom,devfreq-icc-l3")) {
|
||||
if (d->spec->type == L3_MBPS_DEV) {
|
||||
ret = of_property_read_u32(dev->of_node, "qcom,bus-width",
|
||||
&d->width);
|
||||
if (ret < 0 || !d->width) {
|
||||
dev_err(dev, "Missing or invalid bus-width: %d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (d->spec->type == L3_HZ_DEV || d->spec->type == L3_MBPS_DEV) {
|
||||
mutex_lock(&l3_freqs_lock);
|
||||
if (use_cached_l3_freqs) {
|
||||
mutex_unlock(&l3_freqs_lock);
|
||||
|
|
@ -209,10 +251,8 @@ int devfreq_add_icc(struct device *dev)
|
|||
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);
|
||||
|
|
@ -273,11 +313,18 @@ static int devfreq_icc_remove(struct platform_device *pdev)
|
|||
return devfreq_remove_icc(&pdev->dev);
|
||||
}
|
||||
|
||||
static const struct devfreq_icc_spec spec[] = {
|
||||
[0] = { STD_MBPS_DEV },
|
||||
[1] = { L3_HZ_DEV },
|
||||
[2] = { L3_MBPS_DEV },
|
||||
};
|
||||
|
||||
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" },
|
||||
{ .compatible = "qcom,devfreq-icc-l3bw", .data = &spec[2] },
|
||||
{ .compatible = "qcom,devfreq-icc-l3", .data = &spec[1] },
|
||||
{ .compatible = "qcom,devfreq-icc-llcc", .data = &spec[0] },
|
||||
{ .compatible = "qcom,devfreq-icc-ddr", .data = &spec[0] },
|
||||
{ .compatible = "qcom,devfreq-icc", .data = &spec[0] },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue