soc: rockchip: opp_select: Add struct rockchip_opp_info

Add support to get soc info and set voltage read margin.

Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Change-Id: I254a92ba124655e3efc4922a7425c1f13d384adf
This commit is contained in:
Finley Xiao
2021-12-17 10:29:59 +08:00
committed by Tao Huang
parent 8136b9a8ac
commit ddd6a0b49a
6 changed files with 192 additions and 54 deletions

View File

@@ -19,12 +19,15 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/rockchip/cpu.h>
#include <soc/rockchip/rockchip_opp_select.h>
@@ -36,6 +39,7 @@
struct cluster_info {
struct list_head list_head;
struct monitor_dev_info *mdev_info;
struct rockchip_opp_info opp_info;
cpumask_t cpus;
int scale;
};
@@ -197,34 +201,50 @@ static int rv1126_get_soc_info(struct device *dev, struct device_node *np,
return ret;
}
static const struct rockchip_opp_data px30_cpu_opp_data = {
.get_soc_info = px30_get_soc_info,
};
static const struct rockchip_opp_data rk3288_cpu_opp_data = {
.get_soc_info = rk3288_get_soc_info,
};
static const struct rockchip_opp_data rk3399_cpu_opp_data = {
.get_soc_info = rk3399_get_soc_info,
};
static const struct rockchip_opp_data rv1126_cpu_opp_data = {
.get_soc_info = rv1126_get_soc_info,
};
static const struct of_device_id rockchip_cpufreq_of_match[] = {
{
.compatible = "rockchip,px30",
.data = (void *)&px30_get_soc_info,
.data = (void *)&px30_cpu_opp_data,
},
{
.compatible = "rockchip,rk3288",
.data = (void *)&rk3288_get_soc_info,
.data = (void *)&rk3288_cpu_opp_data,
},
{
.compatible = "rockchip,rk3288w",
.data = (void *)&rk3288_get_soc_info,
.data = (void *)&rk3288_cpu_opp_data,
},
{
.compatible = "rockchip,rk3326",
.data = (void *)&px30_get_soc_info,
.data = (void *)&px30_cpu_opp_data,
},
{
.compatible = "rockchip,rk3399",
.data = (void *)&rk3399_get_soc_info,
.data = (void *)&rk3399_cpu_opp_data,
},
{
.compatible = "rockchip,rv1109",
.data = (void *)&rv1126_get_soc_info,
.data = (void *)&rv1126_cpu_opp_data,
},
{
.compatible = "rockchip,rv1126",
.data = (void *)&rv1126_get_soc_info,
.data = (void *)&rv1126_cpu_opp_data,
},
{},
};
@@ -271,10 +291,15 @@ static int cpu_opp_helper(struct dev_pm_set_opp_data *data)
struct regulator *mem_reg = data->regulators[1];
struct device *dev = data->dev;
struct clk *clk = data->clk;
struct cluster_info *cluster;
unsigned long old_freq = data->old_opp.rate;
unsigned long new_freq = data->new_opp.rate;
int ret = 0;
cluster = rockchip_cluster_info_lookup(dev->id);
if (!cluster)
return -EINVAL;
/* Scaling up? Scale voltage before frequency */
if (new_freq >= old_freq) {
ret = rockchip_cpufreq_set_volt(dev, mem_reg, new_supply_mem,
@@ -323,6 +348,7 @@ restore_voltage:
static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
{
struct rockchip_opp_info *opp_info = &cluster->opp_info;
struct opp_table *pname_table = NULL;
struct opp_table *reg_table = NULL;
struct opp_table *opp_table;
@@ -358,7 +384,17 @@ static int rockchip_cpufreq_cluster_init(int cpu, struct cluster_info *cluster)
goto np_err;
}
rockchip_get_soc_info(dev, rockchip_cpufreq_of_match, &bin, &process);
rockchip_get_opp_data(rockchip_cpufreq_of_match, opp_info);
if (opp_info->data && opp_info->data->set_read_margin) {
opp_info->grf = syscon_regmap_lookup_by_phandle(np,
"rockchip,grf");
if (IS_ERR(opp_info->grf))
opp_info->grf = NULL;
rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
&opp_info->volt_rm_tbl);
}
if (opp_info->data && opp_info->data->get_soc_info)
opp_info->data->get_soc_info(dev, np, &bin, &process);
rockchip_get_scale_volt_sel(dev, "cpu_leakage", reg_name, bin, process,
&cluster->scale, &volt_sel);
pname_table = rockchip_set_opp_prop_name(dev, process, volt_sel);

View File

@@ -67,6 +67,7 @@
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <soc/rockchip/rockchip_opp_select.h>
#if defined(CONFIG_PM)
#define KBASE_PM_RUNTIME 1
@@ -1087,6 +1088,7 @@ struct kbase_device {
struct list_head kctx_list;
struct mutex kctx_list_lock;
struct rockchip_opp_info opp_info;
#ifdef CONFIG_MALI_DEVFREQ
struct devfreq_dev_profile devfreq_profile;
struct devfreq *devfreq;

View File

@@ -467,20 +467,26 @@ out:
return ret;
}
static const struct rockchip_opp_data rk3288_gpu_opp_data = {
.get_soc_info = rk3288_get_soc_info,
};
static const struct of_device_id rockchip_mali_of_match[] = {
{
.compatible = "rockchip,rk3288",
.data = (void *)&rk3288_get_soc_info,
.data = (void *)&rk3288_gpu_opp_data,
},
{
.compatible = "rockchip,rk3288w",
.data = (void *)&rk3288_get_soc_info,
.data = (void *)&rk3288_gpu_opp_data,
},
{},
};
int kbase_platform_rk_init_opp_table(struct kbase_device *kbdev)
{
return rockchip_init_opp_table(kbdev->dev, rockchip_mali_of_match,
rockchip_get_opp_data(rockchip_mali_of_match, &kbdev->opp_info);
return rockchip_init_opp_table(kbdev->dev, &kbdev->opp_info,
"gpu_leakage", "mali");
}

View File

@@ -6,8 +6,10 @@
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/devfreq.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/soc/rockchip/pvtm.h>
@@ -813,39 +815,61 @@ void rockchip_of_get_bin_volt_sel(struct device *dev, struct device_node *np,
}
EXPORT_SYMBOL(rockchip_of_get_bin_volt_sel);
void rockchip_get_soc_info(struct device *dev,
const struct of_device_id *matches,
int *bin, int *process)
void rockchip_get_opp_data(const struct of_device_id *matches,
struct rockchip_opp_info *info)
{
const struct of_device_id *match;
struct device_node *np;
struct device_node *node;
int (*get_soc_info)(struct device *dev, struct device_node *np,
int *bin, int *process);
int ret = 0;
if (!matches)
return;
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
if (!np) {
dev_warn(dev, "OPP-v2 not supported\n");
return;
}
node = of_find_node_by_path("/");
match = of_match_node(matches, node);
if (match && match->data) {
get_soc_info = match->data;
ret = get_soc_info(dev, np, bin, process);
if (ret)
dev_err(dev, "Failed to get soc info\n");
if (match && match->data)
info->data = match->data;
of_node_put(node);
}
EXPORT_SYMBOL(rockchip_get_opp_data);
int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
char *porp_name, struct volt_rm_table **table)
{
struct volt_rm_table *rm_table;
const struct property *prop;
int count, i;
prop = of_find_property(np, porp_name, NULL);
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
count = of_property_count_u32_elems(np, porp_name);
if (count < 0)
return -EINVAL;
if (count % 2)
return -EINVAL;
rm_table = devm_kzalloc(dev, sizeof(*rm_table) * (count / 2 + 1),
GFP_KERNEL);
if (!rm_table)
return -ENOMEM;
for (i = 0; i < count / 2; i++) {
of_property_read_u32_index(np, porp_name, 2 * i,
&rm_table[i].volt);
of_property_read_u32_index(np, porp_name, 2 * i + 1,
&rm_table[i].rm);
}
of_node_put(node);
of_node_put(np);
rm_table[i].volt = 0;
rm_table[i].rm = VOLT_RM_TABLE_END;
*table = rm_table;
return 0;
}
EXPORT_SYMBOL(rockchip_get_soc_info);
EXPORT_SYMBOL(rockchip_get_volt_rm_table);
void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
char *reg_name, int bin, int process,
@@ -1118,14 +1142,13 @@ out_np:
}
EXPORT_SYMBOL(rockchip_adjust_power_scale);
int rockchip_init_opp_table(struct device *dev,
const struct of_device_id *matches,
int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,
char *lkg_name, char *reg_name)
{
struct device_node *np;
int bin = -EINVAL, process = -EINVAL;
int scale = 0, volt_sel = -EINVAL;
int ret = 0;
int ret = 0, num_clks = 0, i;
/* Get OPP descriptor node */
np = of_parse_phandle(dev->of_node, "operating-points-v2", 0);
@@ -1133,20 +1156,52 @@ int rockchip_init_opp_table(struct device *dev,
dev_dbg(dev, "Failed to find operating-points-v2\n");
return -ENOENT;
}
of_node_put(np);
if (!info)
goto next;
rockchip_get_soc_info(dev, matches, &bin, &process);
num_clks = of_clk_get_parent_count(np);
if (num_clks > 0) {
info->clks = devm_kcalloc(dev, num_clks, sizeof(*info->clks),
GFP_KERNEL);
if (!info->clks) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < num_clks; i++) {
info->clks[i].clk = of_clk_get(np, i);
if (IS_ERR(info->clks[i].clk)) {
ret = PTR_ERR(info->clks[i].clk);
dev_err(dev, "%s: failed to get clk %d\n",
np->name, i);
goto out;
}
}
info->num_clks = num_clks;
}
if (info->data && info->data->set_read_margin) {
info->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(info->grf))
info->grf = NULL;
rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin",
&info->volt_rm_tbl);
}
if (info->data && info->data->get_soc_info)
info->data->get_soc_info(dev, np, &bin, &process);
next:
rockchip_get_scale_volt_sel(dev, lkg_name, reg_name, bin, process,
&scale, &volt_sel);
rockchip_set_opp_prop_name(dev, process, volt_sel);
ret = dev_pm_opp_of_add_table(dev);
if (ret) {
dev_err(dev, "Invalid operating-points in device tree.\n");
return ret;
goto out;
}
rockchip_adjust_power_scale(dev, scale);
out:
of_node_put(np);
return 0;
return ret;
}
EXPORT_SYMBOL(rockchip_init_opp_table);

View File

@@ -984,15 +984,19 @@ static int __maybe_unused rv1126_get_soc_info(struct device *dev,
return ret;
}
static const struct rockchip_opp_data __maybe_unused rv1126_rkvenc_opp_data = {
.get_soc_info = rv1126_get_soc_info,
};
static const struct of_device_id rockchip_rkvenc_of_match[] = {
#ifdef CONFIG_CPU_RV1126
{
.compatible = "rockchip,rv1109",
.data = (void *)&rv1126_get_soc_info,
.data = (void *)&rv1126_rkvenc_opp_data,
},
{
.compatible = "rockchip,rv1126",
.data = (void *)&rv1126_get_soc_info,
.data = (void *)&rv1126_rkvenc_opp_data,
},
#endif
{},
@@ -1003,6 +1007,7 @@ static int rkvenc_devfreq_init(struct mpp_dev *mpp)
struct rkvenc_dev *enc = to_rkvenc_dev(mpp);
struct clk *clk_core = enc->core_clk_info.clk;
struct devfreq_cooling_power *venc_dcp = &venc_cooling_power_data;
struct rockchip_opp_info opp_info = {0};
int ret = 0;
if (!clk_core)
@@ -1020,8 +1025,8 @@ static int rkvenc_devfreq_init(struct mpp_dev *mpp)
return 0;
}
ret = rockchip_init_opp_table(mpp->dev, rockchip_rkvenc_of_match,
"leakage", "venc");
rockchip_get_opp_data(rockchip_rkvenc_of_match, &opp_info);
ret = rockchip_init_opp_table(mpp->dev, &opp_info, "leakage", "venc");
if (ret) {
dev_err(mpp->dev, "failed to init_opp_table\n");
return ret;

View File

@@ -6,6 +6,31 @@
#ifndef __SOC_ROCKCHIP_OPP_SELECT_H
#define __SOC_ROCKCHIP_OPP_SELECT_H
#define VOLT_RM_TABLE_END ~1
struct rockchip_opp_info;
struct volt_rm_table {
int volt;
int rm;
};
struct rockchip_opp_data {
int (*get_soc_info)(struct device *dev, struct device_node *np,
int *bin, int *process);
int (*set_read_margin)(struct device *dev,
struct rockchip_opp_info *opp_info,
unsigned long volt);
};
struct rockchip_opp_info {
const struct rockchip_opp_data *data;
struct volt_rm_table *volt_rm_tbl;
struct regmap *grf;
struct clk_bulk_data *clks;
int num_clks;
};
#if IS_ENABLED(CONFIG_ROCKCHIP_OPP)
int rockchip_of_get_leakage(struct device *dev, char *lkg_name, int *leakage);
void rockchip_of_get_lkg_sel(struct device *dev, struct device_node *np,
@@ -22,9 +47,10 @@ int rockchip_nvmem_cell_read_u8(struct device_node *np, const char *cell_id,
u8 *val);
int rockchip_nvmem_cell_read_u16(struct device_node *np, const char *cell_id,
u16 *val);
void rockchip_get_soc_info(struct device *dev,
const struct of_device_id *matches,
int *bin, int *process);
int rockchip_get_volt_rm_table(struct device *dev, struct device_node *np,
char *porp_name, struct volt_rm_table **table);
void rockchip_get_opp_data(const struct of_device_id *matches,
struct rockchip_opp_info *info);
void rockchip_get_scale_volt_sel(struct device *dev, char *lkg_name,
char *reg_name, int bin, int process,
int *scale, int *volt_sel);
@@ -32,7 +58,7 @@ struct opp_table *rockchip_set_opp_prop_name(struct device *dev, int process,
int volt_sel);
int rockchip_adjust_power_scale(struct device *dev, int scale);
int rockchip_init_opp_table(struct device *dev,
const struct of_device_id *matches,
struct rockchip_opp_info *info,
char *lkg_name, char *reg_name);
#else
static inline int rockchip_of_get_leakage(struct device *dev, char *lkg_name,
@@ -79,9 +105,17 @@ static inline int rockchip_nvmem_cell_read_u16(struct device_node *np,
return -EOPNOTSUPP;
}
static inline void rockchip_get_soc_info(struct device *dev,
const struct of_device_id *matches,
int *bin, int *process)
static inline int rockchip_get_volt_rm_table(struct device *dev,
struct device_node *np,
char *porp_name,
struct volt_rm_table **table)
{
return -EOPNOTSUPP;
}
static inline void rockchip_get_opp_data(const struct of_device_id *matches,
struct rockchip_opp_info *info)
{
}
@@ -105,7 +139,7 @@ static inline int rockchip_adjust_power_scale(struct device *dev, int scale)
}
static inline int rockchip_init_opp_table(struct device *dev,
const struct of_device_id *matches,
struct rockchip_opp_info *info,
char *lkg_name, char *reg_name)
{
return -ENOTSUPP;