mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user