Message ID | 18a3bc0c5b371deec5c4bbe6ceacf8afcf0bc640.1693996662.git.quic_varada@quicinc.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | viresh kumar |
Headers | show |
Series | Enable cpufreq for IPQ5332 & IPQ9574 | expand |
On 7.09.2023 07:21, Varadarajan Narayanan wrote: > Stromer plus APSS PLL does not support dynamic frequency scaling. > To switch between frequencies, we have to shut down the PLL, > configure the L and ALPHA values and turn on again. So introduce the > separate set of ops for Stromer Plus PLL. > > Signed-off-by: Kathiravan T <quic_kathirav@quicinc.com> > Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com> > --- [...] > + > + /* Wait five micro seconds or more */ > + udelay(5); > + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, > + PLL_RESET_N); > + > + /* The lock time should be less than 50 micro seconds worst case */ > + udelay(50); https://www.kernel.org/doc/Documentation/timers/timers-howto.txt > + > + ret = wait_for_pll_enable_lock(pll); > + if (ret) { > + pr_err("alpha pll running in 800 MHz with source GPLL0\n"); > + return ret; > + } Would that not be SoC-specific information? Konrad
On Thu, 7 Sept 2023 at 08:22, Varadarajan Narayanan <quic_varada@quicinc.com> wrote: > > Stromer plus APSS PLL does not support dynamic frequency scaling. > To switch between frequencies, we have to shut down the PLL, > configure the L and ALPHA values and turn on again. So introduce the > separate set of ops for Stromer Plus PLL. > > Signed-off-by: Kathiravan T <quic_kathirav@quicinc.com> > Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com> > --- > drivers/clk/qcom/clk-alpha-pll.c | 68 ++++++++++++++++++++++++++++++++++++++++ > drivers/clk/qcom/clk-alpha-pll.h | 1 + > 2 files changed, 69 insertions(+) > > diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c > index e4ef645..2ef81f7 100644 > --- a/drivers/clk/qcom/clk-alpha-pll.c > +++ b/drivers/clk/qcom/clk-alpha-pll.c > @@ -2479,3 +2479,71 @@ const struct clk_ops clk_alpha_pll_stromer_ops = { > .set_rate = clk_alpha_pll_stromer_set_rate, > }; > EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops); > + > +static int clk_alpha_pll_stromer_plus_determine_rate(struct clk_hw *hw, > + struct clk_rate_request *req) > +{ > + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); > + u32 l, alpha_width = pll_alpha_width(pll); > + u64 a; > + > + req->rate = alpha_pll_round_rate(req->rate, req->best_parent_rate, &l, > + &a, alpha_width); > + return 0; > +} What is the plL_alpha_width on stromer_plus? Does clk_alpha_pll_stromer_determine_rate() work for you? > + > +static int clk_alpha_pll_stromer_plus_set_rate(struct clk_hw *hw, > + unsigned long rate, > + unsigned long prate) > +{ > + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); > + u32 l, alpha_width = pll_alpha_width(pll); > + int ret; > + u64 a; > + > + rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); > + > + regmap_write(pll->clkr.regmap, PLL_MODE(pll), 0); > + > + /* Delay of 2 output clock ticks required until output is disabled */ > + udelay(1); > + > + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); > + > + if (alpha_width > ALPHA_BITWIDTH) > + a <<= alpha_width - ALPHA_BITWIDTH; > + > + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); > + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), > + a >> ALPHA_BITWIDTH); > + > + regmap_write(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL); > + > + /* Wait five micro seconds or more */ > + udelay(5); > + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, > + PLL_RESET_N); > + > + /* The lock time should be less than 50 micro seconds worst case */ > + udelay(50); > + > + ret = wait_for_pll_enable_lock(pll); > + if (ret) { > + pr_err("alpha pll running in 800 MHz with source GPLL0\n"); > + return ret; > + } > + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, > + PLL_OUTCTRL); > + > + return 0; > +} > + > +const struct clk_ops clk_alpha_pll_stromer_plus_ops = { > + .enable = clk_alpha_pll_enable, > + .disable = clk_alpha_pll_disable, > + .is_enabled = clk_alpha_pll_is_enabled, > + .recalc_rate = clk_alpha_pll_recalc_rate, > + .determine_rate = clk_alpha_pll_stromer_plus_determine_rate, > + .set_rate = clk_alpha_pll_stromer_plus_set_rate, > +}; > +EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_plus_ops); > diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h > index e4bd863..903fbab 100644 > --- a/drivers/clk/qcom/clk-alpha-pll.h > +++ b/drivers/clk/qcom/clk-alpha-pll.h > @@ -152,6 +152,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_ops; > extern const struct clk_ops clk_alpha_pll_huayra_ops; > extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; > extern const struct clk_ops clk_alpha_pll_stromer_ops; > +extern const struct clk_ops clk_alpha_pll_stromer_plus_ops; > > extern const struct clk_ops clk_alpha_pll_fabia_ops; > extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; > -- > 2.7.4 >
On Thu, Sep 07, 2023 at 04:39:33PM +0300, Dmitry Baryshkov wrote: > On Thu, 7 Sept 2023 at 08:22, Varadarajan Narayanan > <quic_varada@quicinc.com> wrote: > > > > Stromer plus APSS PLL does not support dynamic frequency scaling. > > To switch between frequencies, we have to shut down the PLL, > > configure the L and ALPHA values and turn on again. So introduce the > > separate set of ops for Stromer Plus PLL. > > > > Signed-off-by: Kathiravan T <quic_kathirav@quicinc.com> > > Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com> > > --- > > drivers/clk/qcom/clk-alpha-pll.c | 68 ++++++++++++++++++++++++++++++++++++++++ > > drivers/clk/qcom/clk-alpha-pll.h | 1 + > > 2 files changed, 69 insertions(+) > > > > diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c > > index e4ef645..2ef81f7 100644 > > --- a/drivers/clk/qcom/clk-alpha-pll.c > > +++ b/drivers/clk/qcom/clk-alpha-pll.c > > @@ -2479,3 +2479,71 @@ const struct clk_ops clk_alpha_pll_stromer_ops = { > > .set_rate = clk_alpha_pll_stromer_set_rate, > > }; > > EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops); > > + > > +static int clk_alpha_pll_stromer_plus_determine_rate(struct clk_hw *hw, > > + struct clk_rate_request *req) > > +{ > > + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); > > + u32 l, alpha_width = pll_alpha_width(pll); > > + u64 a; > > + > > + req->rate = alpha_pll_round_rate(req->rate, req->best_parent_rate, &l, > > + &a, alpha_width); > > + return 0; > > +} > > What is the plL_alpha_width on stromer_plus? Does > clk_alpha_pll_stromer_determine_rate() work for you? pll_alpha_width is 4. I tested with clk_alpha_pll_stromer_determine_rate() and it works. Will change and post a new version. Thanks Varada > > + > > +static int clk_alpha_pll_stromer_plus_set_rate(struct clk_hw *hw, > > + unsigned long rate, > > + unsigned long prate) > > +{ > > + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); > > + u32 l, alpha_width = pll_alpha_width(pll); > > + int ret; > > + u64 a; > > + > > + rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); > > + > > + regmap_write(pll->clkr.regmap, PLL_MODE(pll), 0); > > + > > + /* Delay of 2 output clock ticks required until output is disabled */ > > + udelay(1); > > + > > + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); > > + > > + if (alpha_width > ALPHA_BITWIDTH) > > + a <<= alpha_width - ALPHA_BITWIDTH; > > + > > + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); > > + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), > > + a >> ALPHA_BITWIDTH); > > + > > + regmap_write(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL); > > + > > + /* Wait five micro seconds or more */ > > + udelay(5); > > + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, > > + PLL_RESET_N); > > + > > + /* The lock time should be less than 50 micro seconds worst case */ > > + udelay(50); > > + > > + ret = wait_for_pll_enable_lock(pll); > > + if (ret) { > > + pr_err("alpha pll running in 800 MHz with source GPLL0\n"); > > + return ret; > > + } > > + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, > > + PLL_OUTCTRL); > > + > > + return 0; > > +} > > + > > +const struct clk_ops clk_alpha_pll_stromer_plus_ops = { > > + .enable = clk_alpha_pll_enable, > > + .disable = clk_alpha_pll_disable, > > + .is_enabled = clk_alpha_pll_is_enabled, > > + .recalc_rate = clk_alpha_pll_recalc_rate, > > + .determine_rate = clk_alpha_pll_stromer_plus_determine_rate, > > + .set_rate = clk_alpha_pll_stromer_plus_set_rate, > > +}; > > +EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_plus_ops); > > diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h > > index e4bd863..903fbab 100644 > > --- a/drivers/clk/qcom/clk-alpha-pll.h > > +++ b/drivers/clk/qcom/clk-alpha-pll.h > > @@ -152,6 +152,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_ops; > > extern const struct clk_ops clk_alpha_pll_huayra_ops; > > extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; > > extern const struct clk_ops clk_alpha_pll_stromer_ops; > > +extern const struct clk_ops clk_alpha_pll_stromer_plus_ops; > > > > extern const struct clk_ops clk_alpha_pll_fabia_ops; > > extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; > > -- > > 2.7.4 > > > > > -- > With best wishes > Dmitry
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index e4ef645..2ef81f7 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -2479,3 +2479,71 @@ const struct clk_ops clk_alpha_pll_stromer_ops = { .set_rate = clk_alpha_pll_stromer_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops); + +static int clk_alpha_pll_stromer_plus_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, alpha_width = pll_alpha_width(pll); + u64 a; + + req->rate = alpha_pll_round_rate(req->rate, req->best_parent_rate, &l, + &a, alpha_width); + return 0; +} + +static int clk_alpha_pll_stromer_plus_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, alpha_width = pll_alpha_width(pll); + int ret; + u64 a; + + rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); + + regmap_write(pll->clkr.regmap, PLL_MODE(pll), 0); + + /* Delay of 2 output clock ticks required until output is disabled */ + udelay(1); + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + + if (alpha_width > ALPHA_BITWIDTH) + a <<= alpha_width - ALPHA_BITWIDTH; + + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), + a >> ALPHA_BITWIDTH); + + regmap_write(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL); + + /* Wait five micro seconds or more */ + udelay(5); + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, + PLL_RESET_N); + + /* The lock time should be less than 50 micro seconds worst case */ + udelay(50); + + ret = wait_for_pll_enable_lock(pll); + if (ret) { + pr_err("alpha pll running in 800 MHz with source GPLL0\n"); + return ret; + } + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, + PLL_OUTCTRL); + + return 0; +} + +const struct clk_ops clk_alpha_pll_stromer_plus_ops = { + .enable = clk_alpha_pll_enable, + .disable = clk_alpha_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, + .recalc_rate = clk_alpha_pll_recalc_rate, + .determine_rate = clk_alpha_pll_stromer_plus_determine_rate, + .set_rate = clk_alpha_pll_stromer_plus_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_plus_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index e4bd863..903fbab 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -152,6 +152,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_ops; extern const struct clk_ops clk_alpha_pll_huayra_ops; extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; extern const struct clk_ops clk_alpha_pll_stromer_ops; +extern const struct clk_ops clk_alpha_pll_stromer_plus_ops; extern const struct clk_ops clk_alpha_pll_fabia_ops; extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops;