Commit c88a4c79 authored by Peng Fan's avatar Peng Fan Committed by Shawn Guo

clk: imx: pfdv2: determine best parent rate

pfdv2 is only used in i.MX7ULP. To get best pfd output, the i.MX7ULP
Datasheet defines two best PLL rate and pfd frac.

Per Datasheel
All PLLs on i.MX 7ULP either have VCO base frequency of
480 MHz or 528 MHz. So when determine best rate, we also
determine best parent rate which could match the requirement.

For some reason the current parent might not be 480MHz or 528MHz,
so we still take current parent rate as a choice.

And we also enable flag CLK_SET_RATE_PARENT to let parent rate
to be configured.
Signed-off-by: default avatarPeng Fan <peng.fan@nxp.com>
Signed-off-by: default avatarShawn Guo <shawnguo@kernel.org>
parent 8ffe9c7b
...@@ -101,24 +101,40 @@ static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw, ...@@ -101,24 +101,40 @@ static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw,
static int clk_pfdv2_determine_rate(struct clk_hw *hw, static int clk_pfdv2_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req) struct clk_rate_request *req)
{ {
u64 tmp = req->best_parent_rate; unsigned long parent_rates[] = {
u64 rate = req->rate; 480000000,
528000000,
req->best_parent_rate
};
unsigned long best_rate = -1UL, rate = req->rate;
unsigned long best_parent_rate = req->best_parent_rate;
u64 tmp;
u8 frac; u8 frac;
int i;
for (i = 0; i < ARRAY_SIZE(parent_rates); i++) {
tmp = parent_rates[i];
tmp = tmp * 18 + rate / 2;
do_div(tmp, rate);
frac = tmp;
if (frac < 12)
frac = 12;
else if (frac > 35)
frac = 35;
tmp = parent_rates[i];
tmp *= 18;
do_div(tmp, frac);
if (abs(tmp - req->rate) < abs(best_rate - req->rate)) {
best_rate = tmp;
best_parent_rate = parent_rates[i];
}
}
tmp = tmp * 18 + rate / 2; req->best_parent_rate = best_parent_rate;
do_div(tmp, rate); req->rate = best_rate;
frac = tmp;
if (frac < 12)
frac = 12;
else if (frac > 35)
frac = 35;
tmp = req->best_parent_rate;
tmp *= 18;
do_div(tmp, frac);
req->rate = tmp;
return 0; return 0;
} }
...@@ -198,7 +214,7 @@ struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name, ...@@ -198,7 +214,7 @@ struct clk_hw *imx_clk_hw_pfdv2(const char *name, const char *parent_name,
init.ops = &clk_pfdv2_ops; init.ops = &clk_pfdv2_ops;
init.parent_names = &parent_name; init.parent_names = &parent_name;
init.num_parents = 1; init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE; init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT;
pfd->hw.init = &init; pfd->hw.init = &init;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment