* [PATCH] clk: meson: vid-pll-div: added meson_vid_pll_div_ops support to enable vid_pll_div to meet clock setting requirements, especially for late chip
@ 2023-02-23 6:27 Yu Tu
2023-02-23 10:11 ` Jerome Brunet
0 siblings, 1 reply; 3+ messages in thread
From: Yu Tu @ 2023-02-23 6:27 UTC (permalink / raw)
To: linux-clk, linux-arm-kernel, linux-amlogic, linux-kernel,
Neil Armstrong, Jerome Brunet, Kevin Hilman, Michael Turquette,
Stephen Boyd, Martin Blumenstingl
Cc: kelvin.zhang, qi.duan, Yu Tu
The previous chip only provides "ro_ops" for the vid_pll_div clock,
which is not satisfied with the operation requirements of the later
chip for this clock, so the ops that can be set for the clock is added.
Signed-off-by: Yu Tu <yu.tu@amlogic.com>
---
drivers/clk/meson/vid-pll-div.c | 59 +++++++++++++++++++++++++++++++++
drivers/clk/meson/vid-pll-div.h | 1 +
2 files changed, 60 insertions(+)
diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c
index daff235bc763..e75fa6f75efe 100644
--- a/drivers/clk/meson/vid-pll-div.c
+++ b/drivers/clk/meson/vid-pll-div.c
@@ -89,6 +89,65 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
return DIV_ROUND_UP_ULL(parent_rate * div->multiplier, div->divider);
}
+static int meson_vid_pll_div_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned long best = 0, now = 0;
+ unsigned int i, best_i = 0;
+
+ for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
+ now = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate *
+ vid_pll_div_table[i].multiplier,
+ vid_pll_div_table[i].divider);
+ if (req->rate == now) {
+ return 0;
+ } else if (abs(now - req->rate) < abs(best - req->rate)) {
+ best = now;
+ best_i = i;
+ }
+ }
+
+ if (best_i < ARRAY_SIZE(vid_pll_div_table))
+ req->rate = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate *
+ vid_pll_div_table[best_i].multiplier,
+ vid_pll_div_table[best_i].divider);
+ else
+ req->rate = meson_vid_pll_div_recalc_rate(hw, req->best_parent_rate);
+
+ return 0;
+}
+
+static int meson_vid_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_regmap *clk = to_clk_regmap(hw);
+ struct meson_vid_pll_div_data *pll_div = meson_vid_pll_div_data(clk);
+ int i;
+
+ for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
+ if (DIV_ROUND_CLOSEST_ULL(parent_rate * vid_pll_div_table[i].multiplier,
+ vid_pll_div_table[i].divider) == rate) {
+ meson_parm_write(clk->map, &pll_div->val, vid_pll_div_table[i].shift_val);
+ meson_parm_write(clk->map, &pll_div->sel, vid_pll_div_table[i].shift_sel);
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(vid_pll_div_table)) {
+ pr_debug("%s: Invalid rate value for vid_pll_div\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+const struct clk_ops meson_vid_pll_div_ops = {
+ .recalc_rate = meson_vid_pll_div_recalc_rate,
+ .determine_rate = meson_vid_pll_div_determine_rate,
+ .set_rate = meson_vid_pll_div_set_rate,
+};
+EXPORT_SYMBOL_GPL(meson_vid_pll_div_ops);
+
const struct clk_ops meson_vid_pll_div_ro_ops = {
.recalc_rate = meson_vid_pll_div_recalc_rate,
};
diff --git a/drivers/clk/meson/vid-pll-div.h b/drivers/clk/meson/vid-pll-div.h
index c0128e33ccf9..3ab729b85fde 100644
--- a/drivers/clk/meson/vid-pll-div.h
+++ b/drivers/clk/meson/vid-pll-div.h
@@ -16,5 +16,6 @@ struct meson_vid_pll_div_data {
};
extern const struct clk_ops meson_vid_pll_div_ro_ops;
+extern const struct clk_ops meson_vid_pll_div_ops;
#endif /* __MESON_VID_PLL_DIV_H */
base-commit: 8a9fbf00acfeeeaac8efab8091bb464bd71b70ea
--
2.33.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] clk: meson: vid-pll-div: added meson_vid_pll_div_ops support to enable vid_pll_div to meet clock setting requirements, especially for late chip
2023-02-23 6:27 [PATCH] clk: meson: vid-pll-div: added meson_vid_pll_div_ops support to enable vid_pll_div to meet clock setting requirements, especially for late chip Yu Tu
@ 2023-02-23 10:11 ` Jerome Brunet
2023-02-24 2:49 ` Yu Tu
0 siblings, 1 reply; 3+ messages in thread
From: Jerome Brunet @ 2023-02-23 10:11 UTC (permalink / raw)
To: Yu Tu, linux-clk, linux-arm-kernel, linux-amlogic, linux-kernel,
Neil Armstrong, Kevin Hilman, Michael Turquette, Stephen Boyd,
Martin Blumenstingl
Cc: kelvin.zhang, qi.duan
On Thu 23 Feb 2023 at 14:27, Yu Tu <yu.tu@amlogic.com> wrote:
Title is way too long, 75 char max
> The previous chip only provides "ro_ops" for the vid_pll_div clock,
The driver does. Other chip could use RW ops I suppose.
> which is not satisfied with the operation requirements of the later
> chip for this clock, so the ops that can be set for the clock is added.
>
What requirements ? What "late" chip ? all this is quite vague.
> Signed-off-by: Yu Tu <yu.tu@amlogic.com>
> ---
> drivers/clk/meson/vid-pll-div.c | 59 +++++++++++++++++++++++++++++++++
> drivers/clk/meson/vid-pll-div.h | 1 +
> 2 files changed, 60 insertions(+)
>
> diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c
> index daff235bc763..e75fa6f75efe 100644
> --- a/drivers/clk/meson/vid-pll-div.c
> +++ b/drivers/clk/meson/vid-pll-div.c
> @@ -89,6 +89,65 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
> return DIV_ROUND_UP_ULL(parent_rate * div->multiplier, div->divider);
> }
>
> +static int meson_vid_pll_div_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + unsigned long best = 0, now = 0;
> + unsigned int i, best_i = 0;
> +
> + for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
It would be nice to actually describe how this vid pll work so we can
stop using precompute "magic" values and actually use the IP to its full
capacity.
> + now = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate *
This effectively stops rate propagation. That's not how determine_rate()
call back should work. Have a look a clk-divider.c and how it calls
clk_hw_round_rate().
> + vid_pll_div_table[i].multiplier,
> + vid_pll_div_table[i].divider);
> + if (req->rate == now) {
> + return 0;
> + } else if (abs(now - req->rate) < abs(best - req->rate)) {
> + best = now;
> + best_i = i;
> + }
> + }
> +
> + if (best_i < ARRAY_SIZE(vid_pll_div_table))
> + req->rate = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate *
> + vid_pll_div_table[best_i].multiplier,
> + vid_pll_div_table[best_i].divider);
> + else
What is the point of this 'if' clause ?
It looks like the 'else' part is dead code.
> + req->rate = meson_vid_pll_div_recalc_rate(hw, req->best_parent_rate);
> +
> + return 0;
> +}
> +
> +static int meson_vid_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_regmap *clk = to_clk_regmap(hw);
> + struct meson_vid_pll_div_data *pll_div = meson_vid_pll_div_data(clk);
> + int i;
> +
> + for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
> + if (DIV_ROUND_CLOSEST_ULL(parent_rate * vid_pll_div_table[i].multiplier,
> + vid_pll_div_table[i].divider) == rate) {
This assumes the set_rate() is going to have a perfect match and
otherwise fail. You should not assume that. Have a look at clk-divider.c
for examples.
> + meson_parm_write(clk->map, &pll_div->val, vid_pll_div_table[i].shift_val);
> + meson_parm_write(clk->map, &pll_div->sel, vid_pll_div_table[i].shift_sel);
> + break;
> + }
> + }
> +
> + if (i >= ARRAY_SIZE(vid_pll_div_table)) {
> + pr_debug("%s: Invalid rate value for vid_pll_div\n", __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +const struct clk_ops meson_vid_pll_div_ops = {
> + .recalc_rate = meson_vid_pll_div_recalc_rate,
> + .determine_rate = meson_vid_pll_div_determine_rate,
> + .set_rate = meson_vid_pll_div_set_rate,
> +};
> +EXPORT_SYMBOL_GPL(meson_vid_pll_div_ops);
> +
> const struct clk_ops meson_vid_pll_div_ro_ops = {
> .recalc_rate = meson_vid_pll_div_recalc_rate,
> };
> diff --git a/drivers/clk/meson/vid-pll-div.h b/drivers/clk/meson/vid-pll-div.h
> index c0128e33ccf9..3ab729b85fde 100644
> --- a/drivers/clk/meson/vid-pll-div.h
> +++ b/drivers/clk/meson/vid-pll-div.h
> @@ -16,5 +16,6 @@ struct meson_vid_pll_div_data {
> };
>
> extern const struct clk_ops meson_vid_pll_div_ro_ops;
> +extern const struct clk_ops meson_vid_pll_div_ops;
>
> #endif /* __MESON_VID_PLL_DIV_H */
>
> base-commit: 8a9fbf00acfeeeaac8efab8091bb464bd71b70ea
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] clk: meson: vid-pll-div: added meson_vid_pll_div_ops support to enable vid_pll_div to meet clock setting requirements, especially for late chip
2023-02-23 10:11 ` Jerome Brunet
@ 2023-02-24 2:49 ` Yu Tu
0 siblings, 0 replies; 3+ messages in thread
From: Yu Tu @ 2023-02-24 2:49 UTC (permalink / raw)
To: Jerome Brunet, linux-clk, linux-arm-kernel, linux-amlogic,
linux-kernel, Neil Armstrong, Kevin Hilman, Michael Turquette,
Stephen Boyd, Martin Blumenstingl
Cc: kelvin.zhang, qi.duan
On 2023/2/23 18:11, Jerome Brunet wrote:
> [ EXTERNAL EMAIL ]
>
Hi Jerome,
>
> On Thu 23 Feb 2023 at 14:27, Yu Tu <yu.tu@amlogic.com> wrote:
>
> Title is way too long, 75 char max
I will change to "clk: meson: vid-pll-div: added meson_vid_pll_div_ops
support". I wonder if you have a better suggestion, please let me know
if you have.
>
>> The previous chip only provides "ro_ops" for the vid_pll_div clock,
>
> The driver does. Other chip could use RW ops I suppose.
Your suppose is right.
>
>> which is not satisfied with the operation requirements of the later
>> chip for this clock, so the ops that can be set for the clock is added.
>>
>
> What requirements ? What "late" chip ? all this is quite vague.
I will change to "Since the previous code only provides "ro_ops" for the
vid_pll_div clock,In fact, the clock can be set. So add "ops" that can
set the clock, especially for later chips like S4 SOC and so on."
Is that ok with you?
>
>> Signed-off-by: Yu Tu <yu.tu@amlogic.com>
>> ---
>> drivers/clk/meson/vid-pll-div.c | 59 +++++++++++++++++++++++++++++++++
>> drivers/clk/meson/vid-pll-div.h | 1 +
>> 2 files changed, 60 insertions(+)
>>
>> diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c
>> index daff235bc763..e75fa6f75efe 100644
>> --- a/drivers/clk/meson/vid-pll-div.c
>> +++ b/drivers/clk/meson/vid-pll-div.c
>> @@ -89,6 +89,65 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
>> return DIV_ROUND_UP_ULL(parent_rate * div->multiplier, div->divider);
>> }
>>
>> +static int meson_vid_pll_div_determine_rate(struct clk_hw *hw,
>> + struct clk_rate_request *req)
>> +{
>> + unsigned long best = 0, now = 0;
>> + unsigned int i, best_i = 0;
>> +
>> + for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
>
> It would be nice to actually describe how this vid pll work so we can
> stop using precompute "magic" values and actually use the IP to its full
> capacity.
Thank you for your advice. I'm going to define a macro to represent this
table size.
>
>> + now = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate *
>
> This effectively stops rate propagation. That's not how determine_rate()
> call back should work. Have a look a clk-divider.c and how it calls
> clk_hw_round_rate().
>
I understand that this should be changed to
" parent_rate = clk_hw_round_rate(req->best_parent_hw,
DIV_ROUND_CLOSEST_ULL(rate * vid_pll_div_table[i].divider,
vid_pll_div_table[i].multiplier));
now = DIV_ROUND_CLOSEST_ULL(parent_rate *
vid_pll_div_table[i].multiplier, vid_pll_div_table[i].divider);"
I don't know if it is correct, please give me a comment.
>> + vid_pll_div_table[i].multiplier,
>> + vid_pll_div_table[i].divider);
>> + if (req->rate == now) {
>> + return 0;
>> + } else if (abs(now - req->rate) < abs(best - req->rate)) {
>> + best = now;
>> + best_i = i;
>> + }
>> + }
>> +
>> + if (best_i < ARRAY_SIZE(vid_pll_div_table))
>> + req->rate = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate *
>> + vid_pll_div_table[best_i].multiplier,
>> + vid_pll_div_table[best_i].divider);
>> + else
>
> What is the point of this 'if' clause ?
> It looks like the 'else' part is dead code.
I'm going to delete these.
>
>> + req->rate = meson_vid_pll_div_recalc_rate(hw, req->best_parent_rate);
>> +
>> + return 0;
>> +}
>> +
>> +static int meson_vid_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
>> + unsigned long parent_rate)
>> +{
>> + struct clk_regmap *clk = to_clk_regmap(hw);
>> + struct meson_vid_pll_div_data *pll_div = meson_vid_pll_div_data(clk);
>> + int i;
>> +
>> + for (i = 0 ; i < ARRAY_SIZE(vid_pll_div_table) ; ++i) {
>> + if (DIV_ROUND_CLOSEST_ULL(parent_rate * vid_pll_div_table[i].multiplier,
>> + vid_pll_div_table[i].divider) == rate) {
>
> This assumes the set_rate() is going to have a perfect match and
> otherwise fail. You should not assume that. Have a look at clk-divider.c
> for examples.
Thank you for your advice. I will do a bestdiv match like the
clk-divider.c file.
>
>> + meson_parm_write(clk->map, &pll_div->val, vid_pll_div_table[i].shift_val);
>> + meson_parm_write(clk->map, &pll_div->sel, vid_pll_div_table[i].shift_sel);
>> + break;
>> + }
>> + }
>> +
>> + if (i >= ARRAY_SIZE(vid_pll_div_table)) {
>> + pr_debug("%s: Invalid rate value for vid_pll_div\n", __func__);
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +const struct clk_ops meson_vid_pll_div_ops = {
>> + .recalc_rate = meson_vid_pll_div_recalc_rate,
>> + .determine_rate = meson_vid_pll_div_determine_rate,
>> + .set_rate = meson_vid_pll_div_set_rate,
>> +};
>> +EXPORT_SYMBOL_GPL(meson_vid_pll_div_ops);
>> +
>> const struct clk_ops meson_vid_pll_div_ro_ops = {
>> .recalc_rate = meson_vid_pll_div_recalc_rate,
>> };
>> diff --git a/drivers/clk/meson/vid-pll-div.h b/drivers/clk/meson/vid-pll-div.h
>> index c0128e33ccf9..3ab729b85fde 100644
>> --- a/drivers/clk/meson/vid-pll-div.h
>> +++ b/drivers/clk/meson/vid-pll-div.h
>> @@ -16,5 +16,6 @@ struct meson_vid_pll_div_data {
>> };
>>
>> extern const struct clk_ops meson_vid_pll_div_ro_ops;
>> +extern const struct clk_ops meson_vid_pll_div_ops;
>>
>> #endif /* __MESON_VID_PLL_DIV_H */
>>
>> base-commit: 8a9fbf00acfeeeaac8efab8091bb464bd71b70ea
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-02-24 2:50 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-23 6:27 [PATCH] clk: meson: vid-pll-div: added meson_vid_pll_div_ops support to enable vid_pll_div to meet clock setting requirements, especially for late chip Yu Tu
2023-02-23 10:11 ` Jerome Brunet
2023-02-24 2:49 ` Yu Tu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox