diff --git a/drivers/soc/rockchip/rockchip_opp_select.c b/drivers/soc/rockchip/rockchip_opp_select.c index a81c4eedbb75..aa01c1c234ee 100644 --- a/drivers/soc/rockchip/rockchip_opp_select.c +++ b/drivers/soc/rockchip/rockchip_opp_select.c @@ -1164,6 +1164,69 @@ int rockchip_get_read_margin(struct device *dev, } EXPORT_SYMBOL(rockchip_get_read_margin); +int rockchip_set_read_margin(struct device *dev, + struct rockchip_opp_info *opp_info, u32 rm, + bool is_set_rm) +{ + if (!is_set_rm || !opp_info) + return 0; + if (!opp_info || !opp_info->volt_rm_tbl) + return 0; + if (!opp_info->data || !opp_info->data->set_read_margin) + return 0; + if (rm == opp_info->current_rm) + return 0; + + return opp_info->data->set_read_margin(dev, opp_info, rm); +} +EXPORT_SYMBOL(rockchip_set_read_margin); + +int rockchip_set_intermediate_rate(struct device *dev, + struct rockchip_opp_info *opp_info, + struct clk *clk, unsigned long old_freq, + unsigned long new_freq, bool is_scaling_up, + bool is_set_clk) +{ + if (!is_set_clk) + return 0; + if (!opp_info || !opp_info->volt_rm_tbl) + return 0; + if (!opp_info->data || !opp_info->data->set_read_margin) + return 0; + if (opp_info->target_rm == opp_info->current_rm) + return 0; + /* + * There is no need to set intermediate rate if the new voltage + * and the current voltage are high voltage. + */ + if ((opp_info->target_rm < opp_info->low_rm) && + (opp_info->current_rm < opp_info->low_rm)) + return 0; + + if (is_scaling_up) { + /* + * If scaling up and the current frequency is less than + * or equal to intermediate threshold frequency, there is + * no need to set intermediate rate. + */ + if (opp_info->intermediate_threshold_freq && + old_freq <= opp_info->intermediate_threshold_freq) + return 0; + return clk_set_rate(clk, new_freq | OPP_SCALING_UP_INTER); + } + /* + * If scaling down and the new frequency is less than or equal to + * intermediate threshold frequency , there is no need to set + * intermediate rate and set the new frequency directly. + */ + if (opp_info->intermediate_threshold_freq && + new_freq <= opp_info->intermediate_threshold_freq) + return clk_set_rate(clk, new_freq); + + return clk_set_rate(clk, new_freq | OPP_SCALING_DOWN_INTER); +} +EXPORT_SYMBOL(rockchip_set_intermediate_rate); + int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info, char *lkg_name, char *reg_name) { @@ -1171,6 +1234,7 @@ int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info, int bin = -EINVAL, process = -EINVAL; int scale = 0, volt_sel = -EINVAL; int ret = 0, num_clks = 0, i; + u32 freq; /* Get OPP descriptor node */ np = of_parse_phandle(dev->of_node, "operating-points-v2", 0); @@ -1207,6 +1271,11 @@ int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info, info->grf = NULL; rockchip_get_volt_rm_table(dev, np, "volt-mem-read-margin", &info->volt_rm_tbl); + of_property_read_u32(np, "low-volt-mem-read-margin", + &info->low_rm); + if (!of_property_read_u32(np, "intermediate-threshold-freq", + &freq)) + info->intermediate_threshold_freq = freq * 1000; } if (info->data && info->data->get_soc_info) info->data->get_soc_info(dev, np, &bin, &process); diff --git a/include/soc/rockchip/rockchip_opp_select.h b/include/soc/rockchip/rockchip_opp_select.h index 99c846dc4ff8..b2ea9b07cdd3 100644 --- a/include/soc/rockchip/rockchip_opp_select.h +++ b/include/soc/rockchip/rockchip_opp_select.h @@ -8,6 +8,12 @@ #define VOLT_RM_TABLE_END ~1 +#define OPP_INTERMEDIATE_MASK 0x3f +#define OPP_INTERMEDIATE_RATE 0x01 +#define OPP_SCALING_UP_RATE 0x02 +#define OPP_SCALING_UP_INTER (OPP_INTERMEDIATE_RATE | OPP_SCALING_UP_RATE) +#define OPP_SCALING_DOWN_INTER OPP_INTERMEDIATE_RATE + struct rockchip_opp_info; struct volt_rm_table { @@ -30,7 +36,11 @@ struct rockchip_opp_info { struct regmap *dsu_grf; struct clk_bulk_data *clks; struct clk *scmi_clk; + /* The threshold frequency for set intermediate rate */ + unsigned long intermediate_threshold_freq; int num_clks; + /* The read margin for low voltage */ + u32 low_rm; u32 current_rm; u32 target_rm; }; @@ -64,6 +74,14 @@ int rockchip_adjust_power_scale(struct device *dev, int scale); int rockchip_get_read_margin(struct device *dev, struct rockchip_opp_info *opp_info, unsigned long volt, u32 *target_rm); +int rockchip_set_read_margin(struct device *dev, + struct rockchip_opp_info *opp_info, u32 rm, + bool is_set_rm); +int rockchip_set_intermediate_rate(struct device *dev, + struct rockchip_opp_info *opp_info, + struct clk *clk, unsigned long old_freq, + unsigned long new_freq, bool is_scaling_up, + bool is_set_clk); int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info, char *lkg_name, char *reg_name); @@ -151,6 +169,22 @@ static inline int rockchip_get_read_margin(struct device *dev, { return -EOPNOTSUPP; } +static inline int rockchip_set_read_margin(struct device *dev, + struct rockchip_opp_info *opp_info, + u32 rm, bool is_set_rm) +{ + return -EOPNOTSUPP; +} + +static inline int +rockchip_set_intermediate_rate(struct device *dev, + struct rockchip_opp_info *opp_info, + struct clk *clk, unsigned long old_freq, + unsigned long new_freq, bool is_scaling_up, + bool is_set_clk) +{ + return -EOPNOTSUPP; +} static inline int rockchip_init_opp_table(struct device *dev, struct rockchip_opp_info *info,