diff --git a/drivers/cpufreq/rockchip-cpufreq.c b/drivers/cpufreq/rockchip-cpufreq.c index d31f8d46eaea..71a1f08f3748 100644 --- a/drivers/cpufreq/rockchip-cpufreq.c +++ b/drivers/cpufreq/rockchip-cpufreq.c @@ -19,12 +19,15 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -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); diff --git a/drivers/gpu/arm/midgard/mali_kbase_defs.h b/drivers/gpu/arm/midgard/mali_kbase_defs.h index b35cade71391..f8a6f33df2da 100644 --- a/drivers/gpu/arm/midgard/mali_kbase_defs.h +++ b/drivers/gpu/arm/midgard/mali_kbase_defs.h @@ -67,6 +67,7 @@ #include #include +#include #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; diff --git a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c index 9c71a78f95d7..8ad910c1256f 100644 --- a/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c +++ b/drivers/gpu/arm/midgard/platform/rk/mali_kbase_config_rk.c @@ -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"); } diff --git a/drivers/soc/rockchip/rockchip_opp_select.c b/drivers/soc/rockchip/rockchip_opp_select.c index 1520e2f96ea6..6bc917b56fbc 100644 --- a/drivers/soc/rockchip/rockchip_opp_select.c +++ b/drivers/soc/rockchip/rockchip_opp_select.c @@ -6,8 +6,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -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); diff --git a/drivers/video/rockchip/mpp/mpp_rkvenc.c b/drivers/video/rockchip/mpp/mpp_rkvenc.c index 50a72b84abdf..5f4925e11677 100644 --- a/drivers/video/rockchip/mpp/mpp_rkvenc.c +++ b/drivers/video/rockchip/mpp/mpp_rkvenc.c @@ -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; diff --git a/include/soc/rockchip/rockchip_opp_select.h b/include/soc/rockchip/rockchip_opp_select.h index e31c36c7f506..3ae160cfb08b 100644 --- a/include/soc/rockchip/rockchip_opp_select.h +++ b/include/soc/rockchip/rockchip_opp_select.h @@ -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;