All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Heiko Stübner" <heiko@sntech.de>
To: Sebastian Reichel <sebastian.reichel@collabora.com>,
	Nicolas Dufresne <nicolas.dufresne@collabora.com>
Cc: Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Linus Walleij <linus.walleij@linaro.org>,
	Bartosz Golaszewski <brgl@bgdev.pl>,
	Adrian Hunter <adrian.hunter@intel.com>,
	Ulf Hansson <ulf.hansson@linaro.org>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>,
	linux-clk@vger.kernel.org, linux-mmc@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-rockchip@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, kernel@lists.collabora.co.uk,
	Elaine Zhang <zhangqing@rock-chips.com>,
	kernel@collabora.com
Subject: Re: [PATCHv1 03/19] clk: rockchip: add pll type for RK3588
Date: Sat, 30 Apr 2022 02:02:11 +0200	[thread overview]
Message-ID: <2180345.iZASKD2KPV@diego> (raw)
In-Reply-To: <05f60b83065a7e39c04f71c6b769a205e1953f41.camel@collabora.com>

Am Mittwoch, 27. April 2022, 15:36:17 CEST schrieb Nicolas Dufresne:
> Le vendredi 22 avril 2022 à 19:09 +0200, Sebastian Reichel a écrit :
> > From: Elaine Zhang <zhangqing@rock-chips.com>
> > 
> > Add RK3588 PLL support including calculation of PLL parameters
> > for arbitrary frequencies.
> > 
> > Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> > [rebase and partially rewrite code]
> > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> > ---
> >  drivers/clk/rockchip/clk-pll.c | 287 ++++++++++++++++++++++++++++++++-
> >  drivers/clk/rockchip/clk.h     |  18 +++
> >  2 files changed, 304 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
> > index f7827b3b7fc1..010e47eb51b8 100644
> > --- a/drivers/clk/rockchip/clk-pll.c
> > +++ b/drivers/clk/rockchip/clk-pll.c
> > @@ -15,6 +15,7 @@
> >  #include <linux/iopoll.h>
> >  #include <linux/regmap.h>
> >  #include <linux/clk.h>
> > +#include <linux/units.h>
> >  #include "clk.h"
> >  
> >  #define PLL_MODE_MASK		0x3
> > @@ -47,6 +48,67 @@ struct rockchip_clk_pll {
> >  #define to_rockchip_clk_pll_nb(nb) \
> >  			container_of(nb, struct rockchip_clk_pll, clk_nb)
> >  
> > +static int
> > +rockchip_rk3588_get_pll_settings(struct rockchip_clk_pll *pll,
> > +				 unsigned long fin_hz,
> > +				 unsigned long fout_hz,
> > +				 struct rockchip_pll_rate_table *rate_table)
> > +{
> > +	u64 fvco_min = 2250 * HZ_PER_MHZ, fvco_max = 4500 * HZ_PER_MHZ;
> > +	u64 fout_min = 37 * HZ_PER_MHZ, fout_max = 4500 * HZ_PER_MHZ;
> > +	u32 p, m, s;
> > +	u64 fvco, fref, fout, ffrac;
> > +
> > +	if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
> > +		return -EINVAL;
> > +
> > +	if (fout_hz > fout_max || fout_hz < fout_min)
> > +		return -EINVAL;
> > +
> > +	if (fin_hz / HZ_PER_MHZ * HZ_PER_MHZ == fin_hz &&
> > +	    fout_hz / HZ_PER_MHZ * HZ_PER_MHZ == fout_hz) {
> > +		for (s = 0; s <= 6; s++) {
> > +			fvco = fout_hz << s;
> > +			if (fvco < fvco_min || fvco > fvco_max)
> > +				continue;
> > +			for (p = 2; p <= 4; p++) {
> > +				for (m = 64; m <= 1023; m++) {
> > +					if (fvco == m * fin_hz / p) {
> > +						rate_table->p = p;
> > +						rate_table->m = m;
> > +						rate_table->s = s;
> > +						rate_table->k = 0;
> > +						return 0;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	} else {
> > +		fout = (fout_hz / HZ_PER_MHZ) * HZ_PER_MHZ;
> > +		ffrac = (fout_hz % HZ_PER_MHZ);
> > +		for (s = 0; s <= 6; s++) {
> > +			fvco = fout << s;
> > +			if (fvco < fvco_min || fvco > fvco_max)
> > +				continue;
> > +			for (p = 1; p <= 4; p++) {
> > +				for (m = 64; m <= 1023; m++) {
> > +					if (fvco == m * fin_hz / p) {
> > +						rate_table->p = p;
> > +						rate_table->m = m;
> > +						rate_table->s = s;
> > +						fref = fin_hz / p;
> > +						fout = (ffrac << s) * 65535;
> > +						rate_table->k = fout / fref;
> > +						return 0;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +
> >  static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
> >  			    struct rockchip_clk_pll *pll, unsigned long rate)
> >  {
> > @@ -68,6 +130,14 @@ static long rockchip_pll_round_rate(struct clk_hw *hw,
> >  	const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
> >  	int i;
> >  
> > +	if (pll->type == pll_rk3588 || pll->type == pll_rk3588_core) {
> > +		long parent_rate = prate ? *prate : 24 * HZ_PER_MHZ;
> > +		struct rockchip_pll_rate_table pll_settings;
> > +
> > +		if (rockchip_rk3588_get_pll_settings(pll, parent_rate, drate, &pll_settings) >= 0)
> > +			return pll_settings.rate;
> > +	}
> > +
> 
> I was reading some of previous backlog on why these formula have never been
> mainlines [0]. It looks like so far the statu quo was adopted. But if that was
> to change, I think this implementation is not aligned with the intent. If my
> understanding is right, the rate_table[] (if it exists) should be looked up
> first and the formula use as a fallback.

real life products like the Chromebooks using rk3288 and rk3399 had
a lot of fun with PLL rates (jitter and whatnot) and even had the underlying
parameters of some rates changed (same rate but using different parameters
to achive it) to reduce effects.

When doing this rate-table + dynamic calculation you never really know
which one will be taken I guess. When you hit the exact rate as in the
table you might get an optimized one but when round-rate ends up like 1kHz
above, you would then get a non-optimized calculated one.

So I'm personally really in favor of just sticking with a curated rate-table.


Heiko



> [0] https://patchwork.kernel.org/project/linux-rockchip/patch/1470144852-20708-1-git-send-email-zhengxing@rock-chips.com/#19548765
> 
> >  	/* Assumming rate_table is in descending order */
> >  	for (i = 0; i < pll->rate_count; i++) {
> >  		if (drate >= rate_table[i].rate)
> > @@ -842,6 +912,212 @@ static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
> >  	.init = rockchip_rk3399_pll_init,
> >  };
> >  
> > +/**
> > + * PLL used in RK3588
> > + */
> > +
> > +#define RK3588_PLLCON(i)               (i * 0x4)
> > +#define RK3588_PLLCON0_M_MASK          0x3ff
> > +#define RK3588_PLLCON0_M_SHIFT         0
> > +#define RK3588_PLLCON1_P_MASK          0x3f
> > +#define RK3588_PLLCON1_P_SHIFT         0
> > +#define RK3588_PLLCON1_S_MASK          0x7
> > +#define RK3588_PLLCON1_S_SHIFT         6
> > +#define RK3588_PLLCON2_K_MASK          0xffff
> > +#define RK3588_PLLCON2_K_SHIFT         0
> > +#define RK3588_PLLCON1_PWRDOWN         BIT(13)
> > +#define RK3588_PLLCON6_LOCK_STATUS     BIT(15)
> > +
> > +static int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll)
> > +{
> > +	u32 pllcon;
> > +	int ret;
> > +
> > +	/*
> > +	 * Lock time typical 250, max 500 input clock cycles @24MHz
> > +	 * So define a very safe maximum of 1000us, meaning 24000 cycles.
> > +	 */
> > +	ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6),
> > +					 pllcon,
> > +					 pllcon & RK3588_PLLCON6_LOCK_STATUS,
> > +					 0, 1000);
> > +	if (ret)
> > +		pr_err("%s: timeout waiting for pll to lock\n", __func__);
> > +
> > +	return ret;
> > +}
> > +
> > +static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll,
> > +					   struct rockchip_pll_rate_table *rate)
> > +{
> > +	u32 pllcon;
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0));
> > +	rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT) & RK3588_PLLCON0_M_MASK);
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
> > +	rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) & RK3588_PLLCON1_P_MASK);
> > +	rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) & RK3588_PLLCON1_S_MASK);
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2));
> > +	rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT) & RK3588_PLLCON2_K_MASK);
> > +}
> > +
> > +static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	struct rockchip_pll_rate_table cur;
> > +	u64 rate64 = prate, postdiv;
> > +
> > +	rockchip_rk3588_pll_get_params(pll, &cur);
> > +
> > +	rate64 *= cur.m;
> > +	do_div(rate64, cur.p);
> > +
> > +	if (cur.k) {
> > +		/* fractional mode */
> > +		u64 frac_rate64 = prate * cur.k;
> > +
> > +		postdiv = cur.p * 65535;
> > +		do_div(frac_rate64, postdiv);
> > +		rate64 += frac_rate64;
> > +	}
> > +	rate64 = rate64 >> cur.s;
> > +
> > +	return (unsigned long)rate64;
> > +}
> > +
> > +static int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll,
> > +					  const struct rockchip_pll_rate_table *rate)
> > +{
> > +	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
> > +	struct clk_mux *pll_mux = &pll->pll_mux;
> > +	struct rockchip_pll_rate_table cur;
> > +	int rate_change_remuxed = 0;
> > +	int cur_parent;
> > +	int ret;
> > +
> > +	pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n",
> > +		 __func__, rate->rate, rate->p, rate->m, rate->s, rate->k);
> > +
> > +	rockchip_rk3588_pll_get_params(pll, &cur);
> > +	cur.rate = 0;
> > +
> > +	if (pll->type == pll_rk3588) {
> > +		cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
> > +		if (cur_parent == PLL_MODE_NORM) {
> > +			pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
> > +			rate_change_remuxed = 1;
> > +		}
> > +	}
> > +
> > +	/* set pll power down */
> > +	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN,
> > +			     RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3399_PLLCON(1));
> > +
> > +	/* update pll values */
> > +	writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK, RK3588_PLLCON0_M_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(0));
> > +
> > +	writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK, RK3588_PLLCON1_P_SHIFT) |
> > +		       HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK, RK3588_PLLCON1_S_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(1));
> > +
> > +	writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK, RK3588_PLLCON2_K_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(2));
> > +
> > +	/* set pll power up */
> > +	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +
> > +	/* wait for the pll to lock */
> > +	ret = rockchip_rk3588_pll_wait_lock(pll);
> > +	if (ret) {
> > +		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
> > +			__func__);
> > +		rockchip_rk3588_pll_set_params(pll, &cur);
> > +	}
> > +
> > +	if ((pll->type == pll_rk3588) && rate_change_remuxed)
> > +		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
> > +
> > +	return ret;
> > +}
> > +
> > +static int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate,
> > +					unsigned long prate)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	struct rockchip_pll_rate_table rate;
> > +	unsigned long old_rate = rockchip_rk3588_pll_recalc_rate(hw, prate);
> > +
> > +	pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
> > +		 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
> > +
> > +	if (rockchip_rk3588_get_pll_settings(pll, prate, drate, &rate) < 0) {
> > +		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
> > +		       drate, __clk_get_name(hw->clk));
> > +		return -EINVAL;
> > +	}
> > +
> > +	return rockchip_rk3588_pll_set_params(pll, &rate);
> > +}
> > +
> > +static int rockchip_rk3588_pll_enable(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +	rockchip_rk3588_pll_wait_lock(pll);
> > +
> > +	return 0;
> > +}
> > +
> > +static void rockchip_rk3588_pll_disable(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +}
> > +
> > +static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1));
> > +
> > +	return !(pllcon & RK3588_PLLCON1_PWRDOWN);
> > +}
> > +
> > +static int rockchip_rk3588_pll_init(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
> > +		return 0;
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = {
> > +	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
> > +	.enable = rockchip_rk3588_pll_enable,
> > +	.disable = rockchip_rk3588_pll_disable,
> > +	.is_enabled = rockchip_rk3588_pll_is_enabled,
> > +};
> > +
> > +static const struct clk_ops rockchip_rk3588_pll_clk_ops = {
> > +	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
> > +	.round_rate = rockchip_pll_round_rate,
> > +	.set_rate = rockchip_rk3588_pll_set_rate,
> > +	.enable = rockchip_rk3588_pll_enable,
> > +	.disable = rockchip_rk3588_pll_disable,
> > +	.is_enabled = rockchip_rk3588_pll_is_enabled,
> > +	.init = rockchip_rk3588_pll_init,
> > +};
> > +
> >  /*
> >   * Common registering of pll clocks
> >   */
> > @@ -890,7 +1166,8 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
> >  	if (pll_type == pll_rk3036 ||
> >  	    pll_type == pll_rk3066 ||
> >  	    pll_type == pll_rk3328 ||
> > -	    pll_type == pll_rk3399)
> > +	    pll_type == pll_rk3399 ||
> > +	    pll_type == pll_rk3588)
> >  		pll_mux->flags |= CLK_MUX_HIWORD_MASK;
> >  
> >  	/* the actual muxing is xin24m, pll-output, xin32k */
> > @@ -957,6 +1234,14 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
> >  		else
> >  			init.ops = &rockchip_rk3399_pll_clk_ops;
> >  		break;
> > +	case pll_rk3588:
> > +	case pll_rk3588_core:
> > +		if (!pll->rate_table)
> > +			init.ops = &rockchip_rk3588_pll_clk_norate_ops;
> > +		else
> > +			init.ops = &rockchip_rk3588_pll_clk_ops;
> > +		init.flags = flags;
> > +		break;
> >  	default:
> >  		pr_warn("%s: Unknown pll type for pll clk %s\n",
> >  			__func__, name);
> > diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
> > index 6aece7f07a7d..bf7c8d082fde 100644
> > --- a/drivers/clk/rockchip/clk.h
> > +++ b/drivers/clk/rockchip/clk.h
> > @@ -221,6 +221,8 @@ enum rockchip_pll_type {
> >  	pll_rk3066,
> >  	pll_rk3328,
> >  	pll_rk3399,
> > +	pll_rk3588,
> > +	pll_rk3588_core,
> >  };
> >  
> >  #define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,	\
> > @@ -253,6 +255,15 @@ enum rockchip_pll_type {
> >  	.nb = _nb,						\
> >  }
> >  
> > +#define RK3588_PLL_RATE(_rate, _p, _m, _s, _k)			\
> > +{								\
> > +	.rate   = _rate##U,					\
> > +	.p = _p,						\
> > +	.m = _m,						\
> > +	.s = _s,						\
> > +	.k = _k,						\
> > +}
> > +
> >  /**
> >   * struct rockchip_clk_provider - information about clock provider
> >   * @reg_base: virtual address for the register base.
> > @@ -288,6 +299,13 @@ struct rockchip_pll_rate_table {
> >  			unsigned int dsmpd;
> >  			unsigned int frac;
> >  		};
> > +		struct {
> > +			/* for RK3588 */
> > +			unsigned int m;
> > +			unsigned int p;
> > +			unsigned int s;
> > +			unsigned int k;
> > +		};
> >  	};
> >  };
> >  
> 
> 





WARNING: multiple messages have this Message-ID (diff)
From: "Heiko Stübner" <heiko@sntech.de>
To: Sebastian Reichel <sebastian.reichel@collabora.com>,
	Nicolas Dufresne <nicolas.dufresne@collabora.com>
Cc: Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Linus Walleij <linus.walleij@linaro.org>,
	Bartosz Golaszewski <brgl@bgdev.pl>,
	Adrian Hunter <adrian.hunter@intel.com>,
	Ulf Hansson <ulf.hansson@linaro.org>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>,
	linux-clk@vger.kernel.org, linux-mmc@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-rockchip@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, kernel@lists.collabora.co.uk,
	Elaine Zhang <zhangqing@rock-chips.com>,
	kernel@collabora.com
Subject: Re: [PATCHv1 03/19] clk: rockchip: add pll type for RK3588
Date: Sat, 30 Apr 2022 02:02:11 +0200	[thread overview]
Message-ID: <2180345.iZASKD2KPV@diego> (raw)
In-Reply-To: <05f60b83065a7e39c04f71c6b769a205e1953f41.camel@collabora.com>

Am Mittwoch, 27. April 2022, 15:36:17 CEST schrieb Nicolas Dufresne:
> Le vendredi 22 avril 2022 à 19:09 +0200, Sebastian Reichel a écrit :
> > From: Elaine Zhang <zhangqing@rock-chips.com>
> > 
> > Add RK3588 PLL support including calculation of PLL parameters
> > for arbitrary frequencies.
> > 
> > Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> > [rebase and partially rewrite code]
> > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> > ---
> >  drivers/clk/rockchip/clk-pll.c | 287 ++++++++++++++++++++++++++++++++-
> >  drivers/clk/rockchip/clk.h     |  18 +++
> >  2 files changed, 304 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
> > index f7827b3b7fc1..010e47eb51b8 100644
> > --- a/drivers/clk/rockchip/clk-pll.c
> > +++ b/drivers/clk/rockchip/clk-pll.c
> > @@ -15,6 +15,7 @@
> >  #include <linux/iopoll.h>
> >  #include <linux/regmap.h>
> >  #include <linux/clk.h>
> > +#include <linux/units.h>
> >  #include "clk.h"
> >  
> >  #define PLL_MODE_MASK		0x3
> > @@ -47,6 +48,67 @@ struct rockchip_clk_pll {
> >  #define to_rockchip_clk_pll_nb(nb) \
> >  			container_of(nb, struct rockchip_clk_pll, clk_nb)
> >  
> > +static int
> > +rockchip_rk3588_get_pll_settings(struct rockchip_clk_pll *pll,
> > +				 unsigned long fin_hz,
> > +				 unsigned long fout_hz,
> > +				 struct rockchip_pll_rate_table *rate_table)
> > +{
> > +	u64 fvco_min = 2250 * HZ_PER_MHZ, fvco_max = 4500 * HZ_PER_MHZ;
> > +	u64 fout_min = 37 * HZ_PER_MHZ, fout_max = 4500 * HZ_PER_MHZ;
> > +	u32 p, m, s;
> > +	u64 fvco, fref, fout, ffrac;
> > +
> > +	if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
> > +		return -EINVAL;
> > +
> > +	if (fout_hz > fout_max || fout_hz < fout_min)
> > +		return -EINVAL;
> > +
> > +	if (fin_hz / HZ_PER_MHZ * HZ_PER_MHZ == fin_hz &&
> > +	    fout_hz / HZ_PER_MHZ * HZ_PER_MHZ == fout_hz) {
> > +		for (s = 0; s <= 6; s++) {
> > +			fvco = fout_hz << s;
> > +			if (fvco < fvco_min || fvco > fvco_max)
> > +				continue;
> > +			for (p = 2; p <= 4; p++) {
> > +				for (m = 64; m <= 1023; m++) {
> > +					if (fvco == m * fin_hz / p) {
> > +						rate_table->p = p;
> > +						rate_table->m = m;
> > +						rate_table->s = s;
> > +						rate_table->k = 0;
> > +						return 0;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	} else {
> > +		fout = (fout_hz / HZ_PER_MHZ) * HZ_PER_MHZ;
> > +		ffrac = (fout_hz % HZ_PER_MHZ);
> > +		for (s = 0; s <= 6; s++) {
> > +			fvco = fout << s;
> > +			if (fvco < fvco_min || fvco > fvco_max)
> > +				continue;
> > +			for (p = 1; p <= 4; p++) {
> > +				for (m = 64; m <= 1023; m++) {
> > +					if (fvco == m * fin_hz / p) {
> > +						rate_table->p = p;
> > +						rate_table->m = m;
> > +						rate_table->s = s;
> > +						fref = fin_hz / p;
> > +						fout = (ffrac << s) * 65535;
> > +						rate_table->k = fout / fref;
> > +						return 0;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +
> >  static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
> >  			    struct rockchip_clk_pll *pll, unsigned long rate)
> >  {
> > @@ -68,6 +130,14 @@ static long rockchip_pll_round_rate(struct clk_hw *hw,
> >  	const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
> >  	int i;
> >  
> > +	if (pll->type == pll_rk3588 || pll->type == pll_rk3588_core) {
> > +		long parent_rate = prate ? *prate : 24 * HZ_PER_MHZ;
> > +		struct rockchip_pll_rate_table pll_settings;
> > +
> > +		if (rockchip_rk3588_get_pll_settings(pll, parent_rate, drate, &pll_settings) >= 0)
> > +			return pll_settings.rate;
> > +	}
> > +
> 
> I was reading some of previous backlog on why these formula have never been
> mainlines [0]. It looks like so far the statu quo was adopted. But if that was
> to change, I think this implementation is not aligned with the intent. If my
> understanding is right, the rate_table[] (if it exists) should be looked up
> first and the formula use as a fallback.

real life products like the Chromebooks using rk3288 and rk3399 had
a lot of fun with PLL rates (jitter and whatnot) and even had the underlying
parameters of some rates changed (same rate but using different parameters
to achive it) to reduce effects.

When doing this rate-table + dynamic calculation you never really know
which one will be taken I guess. When you hit the exact rate as in the
table you might get an optimized one but when round-rate ends up like 1kHz
above, you would then get a non-optimized calculated one.

So I'm personally really in favor of just sticking with a curated rate-table.


Heiko



> [0] https://patchwork.kernel.org/project/linux-rockchip/patch/1470144852-20708-1-git-send-email-zhengxing@rock-chips.com/#19548765
> 
> >  	/* Assumming rate_table is in descending order */
> >  	for (i = 0; i < pll->rate_count; i++) {
> >  		if (drate >= rate_table[i].rate)
> > @@ -842,6 +912,212 @@ static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
> >  	.init = rockchip_rk3399_pll_init,
> >  };
> >  
> > +/**
> > + * PLL used in RK3588
> > + */
> > +
> > +#define RK3588_PLLCON(i)               (i * 0x4)
> > +#define RK3588_PLLCON0_M_MASK          0x3ff
> > +#define RK3588_PLLCON0_M_SHIFT         0
> > +#define RK3588_PLLCON1_P_MASK          0x3f
> > +#define RK3588_PLLCON1_P_SHIFT         0
> > +#define RK3588_PLLCON1_S_MASK          0x7
> > +#define RK3588_PLLCON1_S_SHIFT         6
> > +#define RK3588_PLLCON2_K_MASK          0xffff
> > +#define RK3588_PLLCON2_K_SHIFT         0
> > +#define RK3588_PLLCON1_PWRDOWN         BIT(13)
> > +#define RK3588_PLLCON6_LOCK_STATUS     BIT(15)
> > +
> > +static int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll)
> > +{
> > +	u32 pllcon;
> > +	int ret;
> > +
> > +	/*
> > +	 * Lock time typical 250, max 500 input clock cycles @24MHz
> > +	 * So define a very safe maximum of 1000us, meaning 24000 cycles.
> > +	 */
> > +	ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6),
> > +					 pllcon,
> > +					 pllcon & RK3588_PLLCON6_LOCK_STATUS,
> > +					 0, 1000);
> > +	if (ret)
> > +		pr_err("%s: timeout waiting for pll to lock\n", __func__);
> > +
> > +	return ret;
> > +}
> > +
> > +static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll,
> > +					   struct rockchip_pll_rate_table *rate)
> > +{
> > +	u32 pllcon;
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0));
> > +	rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT) & RK3588_PLLCON0_M_MASK);
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
> > +	rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) & RK3588_PLLCON1_P_MASK);
> > +	rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) & RK3588_PLLCON1_S_MASK);
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2));
> > +	rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT) & RK3588_PLLCON2_K_MASK);
> > +}
> > +
> > +static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	struct rockchip_pll_rate_table cur;
> > +	u64 rate64 = prate, postdiv;
> > +
> > +	rockchip_rk3588_pll_get_params(pll, &cur);
> > +
> > +	rate64 *= cur.m;
> > +	do_div(rate64, cur.p);
> > +
> > +	if (cur.k) {
> > +		/* fractional mode */
> > +		u64 frac_rate64 = prate * cur.k;
> > +
> > +		postdiv = cur.p * 65535;
> > +		do_div(frac_rate64, postdiv);
> > +		rate64 += frac_rate64;
> > +	}
> > +	rate64 = rate64 >> cur.s;
> > +
> > +	return (unsigned long)rate64;
> > +}
> > +
> > +static int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll,
> > +					  const struct rockchip_pll_rate_table *rate)
> > +{
> > +	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
> > +	struct clk_mux *pll_mux = &pll->pll_mux;
> > +	struct rockchip_pll_rate_table cur;
> > +	int rate_change_remuxed = 0;
> > +	int cur_parent;
> > +	int ret;
> > +
> > +	pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n",
> > +		 __func__, rate->rate, rate->p, rate->m, rate->s, rate->k);
> > +
> > +	rockchip_rk3588_pll_get_params(pll, &cur);
> > +	cur.rate = 0;
> > +
> > +	if (pll->type == pll_rk3588) {
> > +		cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
> > +		if (cur_parent == PLL_MODE_NORM) {
> > +			pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
> > +			rate_change_remuxed = 1;
> > +		}
> > +	}
> > +
> > +	/* set pll power down */
> > +	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN,
> > +			     RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3399_PLLCON(1));
> > +
> > +	/* update pll values */
> > +	writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK, RK3588_PLLCON0_M_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(0));
> > +
> > +	writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK, RK3588_PLLCON1_P_SHIFT) |
> > +		       HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK, RK3588_PLLCON1_S_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(1));
> > +
> > +	writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK, RK3588_PLLCON2_K_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(2));
> > +
> > +	/* set pll power up */
> > +	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +
> > +	/* wait for the pll to lock */
> > +	ret = rockchip_rk3588_pll_wait_lock(pll);
> > +	if (ret) {
> > +		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
> > +			__func__);
> > +		rockchip_rk3588_pll_set_params(pll, &cur);
> > +	}
> > +
> > +	if ((pll->type == pll_rk3588) && rate_change_remuxed)
> > +		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
> > +
> > +	return ret;
> > +}
> > +
> > +static int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate,
> > +					unsigned long prate)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	struct rockchip_pll_rate_table rate;
> > +	unsigned long old_rate = rockchip_rk3588_pll_recalc_rate(hw, prate);
> > +
> > +	pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
> > +		 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
> > +
> > +	if (rockchip_rk3588_get_pll_settings(pll, prate, drate, &rate) < 0) {
> > +		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
> > +		       drate, __clk_get_name(hw->clk));
> > +		return -EINVAL;
> > +	}
> > +
> > +	return rockchip_rk3588_pll_set_params(pll, &rate);
> > +}
> > +
> > +static int rockchip_rk3588_pll_enable(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +	rockchip_rk3588_pll_wait_lock(pll);
> > +
> > +	return 0;
> > +}
> > +
> > +static void rockchip_rk3588_pll_disable(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +}
> > +
> > +static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1));
> > +
> > +	return !(pllcon & RK3588_PLLCON1_PWRDOWN);
> > +}
> > +
> > +static int rockchip_rk3588_pll_init(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
> > +		return 0;
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = {
> > +	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
> > +	.enable = rockchip_rk3588_pll_enable,
> > +	.disable = rockchip_rk3588_pll_disable,
> > +	.is_enabled = rockchip_rk3588_pll_is_enabled,
> > +};
> > +
> > +static const struct clk_ops rockchip_rk3588_pll_clk_ops = {
> > +	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
> > +	.round_rate = rockchip_pll_round_rate,
> > +	.set_rate = rockchip_rk3588_pll_set_rate,
> > +	.enable = rockchip_rk3588_pll_enable,
> > +	.disable = rockchip_rk3588_pll_disable,
> > +	.is_enabled = rockchip_rk3588_pll_is_enabled,
> > +	.init = rockchip_rk3588_pll_init,
> > +};
> > +
> >  /*
> >   * Common registering of pll clocks
> >   */
> > @@ -890,7 +1166,8 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
> >  	if (pll_type == pll_rk3036 ||
> >  	    pll_type == pll_rk3066 ||
> >  	    pll_type == pll_rk3328 ||
> > -	    pll_type == pll_rk3399)
> > +	    pll_type == pll_rk3399 ||
> > +	    pll_type == pll_rk3588)
> >  		pll_mux->flags |= CLK_MUX_HIWORD_MASK;
> >  
> >  	/* the actual muxing is xin24m, pll-output, xin32k */
> > @@ -957,6 +1234,14 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
> >  		else
> >  			init.ops = &rockchip_rk3399_pll_clk_ops;
> >  		break;
> > +	case pll_rk3588:
> > +	case pll_rk3588_core:
> > +		if (!pll->rate_table)
> > +			init.ops = &rockchip_rk3588_pll_clk_norate_ops;
> > +		else
> > +			init.ops = &rockchip_rk3588_pll_clk_ops;
> > +		init.flags = flags;
> > +		break;
> >  	default:
> >  		pr_warn("%s: Unknown pll type for pll clk %s\n",
> >  			__func__, name);
> > diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
> > index 6aece7f07a7d..bf7c8d082fde 100644
> > --- a/drivers/clk/rockchip/clk.h
> > +++ b/drivers/clk/rockchip/clk.h
> > @@ -221,6 +221,8 @@ enum rockchip_pll_type {
> >  	pll_rk3066,
> >  	pll_rk3328,
> >  	pll_rk3399,
> > +	pll_rk3588,
> > +	pll_rk3588_core,
> >  };
> >  
> >  #define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,	\
> > @@ -253,6 +255,15 @@ enum rockchip_pll_type {
> >  	.nb = _nb,						\
> >  }
> >  
> > +#define RK3588_PLL_RATE(_rate, _p, _m, _s, _k)			\
> > +{								\
> > +	.rate   = _rate##U,					\
> > +	.p = _p,						\
> > +	.m = _m,						\
> > +	.s = _s,						\
> > +	.k = _k,						\
> > +}
> > +
> >  /**
> >   * struct rockchip_clk_provider - information about clock provider
> >   * @reg_base: virtual address for the register base.
> > @@ -288,6 +299,13 @@ struct rockchip_pll_rate_table {
> >  			unsigned int dsmpd;
> >  			unsigned int frac;
> >  		};
> > +		struct {
> > +			/* for RK3588 */
> > +			unsigned int m;
> > +			unsigned int p;
> > +			unsigned int s;
> > +			unsigned int k;
> > +		};
> >  	};
> >  };
> >  
> 
> 





_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip

WARNING: multiple messages have this Message-ID (diff)
From: "Heiko Stübner" <heiko@sntech.de>
To: Sebastian Reichel <sebastian.reichel@collabora.com>,
	Nicolas Dufresne <nicolas.dufresne@collabora.com>
Cc: Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Linus Walleij <linus.walleij@linaro.org>,
	Bartosz Golaszewski <brgl@bgdev.pl>,
	Adrian Hunter <adrian.hunter@intel.com>,
	Ulf Hansson <ulf.hansson@linaro.org>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	Michael Turquette <mturquette@baylibre.com>,
	Stephen Boyd <sboyd@kernel.org>,
	linux-clk@vger.kernel.org, linux-mmc@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-rockchip@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, kernel@lists.collabora.co.uk,
	Elaine Zhang <zhangqing@rock-chips.com>,
	kernel@collabora.com
Subject: Re: [PATCHv1 03/19] clk: rockchip: add pll type for RK3588
Date: Sat, 30 Apr 2022 02:02:11 +0200	[thread overview]
Message-ID: <2180345.iZASKD2KPV@diego> (raw)
In-Reply-To: <05f60b83065a7e39c04f71c6b769a205e1953f41.camel@collabora.com>

Am Mittwoch, 27. April 2022, 15:36:17 CEST schrieb Nicolas Dufresne:
> Le vendredi 22 avril 2022 à 19:09 +0200, Sebastian Reichel a écrit :
> > From: Elaine Zhang <zhangqing@rock-chips.com>
> > 
> > Add RK3588 PLL support including calculation of PLL parameters
> > for arbitrary frequencies.
> > 
> > Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> > [rebase and partially rewrite code]
> > Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> > ---
> >  drivers/clk/rockchip/clk-pll.c | 287 ++++++++++++++++++++++++++++++++-
> >  drivers/clk/rockchip/clk.h     |  18 +++
> >  2 files changed, 304 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
> > index f7827b3b7fc1..010e47eb51b8 100644
> > --- a/drivers/clk/rockchip/clk-pll.c
> > +++ b/drivers/clk/rockchip/clk-pll.c
> > @@ -15,6 +15,7 @@
> >  #include <linux/iopoll.h>
> >  #include <linux/regmap.h>
> >  #include <linux/clk.h>
> > +#include <linux/units.h>
> >  #include "clk.h"
> >  
> >  #define PLL_MODE_MASK		0x3
> > @@ -47,6 +48,67 @@ struct rockchip_clk_pll {
> >  #define to_rockchip_clk_pll_nb(nb) \
> >  			container_of(nb, struct rockchip_clk_pll, clk_nb)
> >  
> > +static int
> > +rockchip_rk3588_get_pll_settings(struct rockchip_clk_pll *pll,
> > +				 unsigned long fin_hz,
> > +				 unsigned long fout_hz,
> > +				 struct rockchip_pll_rate_table *rate_table)
> > +{
> > +	u64 fvco_min = 2250 * HZ_PER_MHZ, fvco_max = 4500 * HZ_PER_MHZ;
> > +	u64 fout_min = 37 * HZ_PER_MHZ, fout_max = 4500 * HZ_PER_MHZ;
> > +	u32 p, m, s;
> > +	u64 fvco, fref, fout, ffrac;
> > +
> > +	if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz)
> > +		return -EINVAL;
> > +
> > +	if (fout_hz > fout_max || fout_hz < fout_min)
> > +		return -EINVAL;
> > +
> > +	if (fin_hz / HZ_PER_MHZ * HZ_PER_MHZ == fin_hz &&
> > +	    fout_hz / HZ_PER_MHZ * HZ_PER_MHZ == fout_hz) {
> > +		for (s = 0; s <= 6; s++) {
> > +			fvco = fout_hz << s;
> > +			if (fvco < fvco_min || fvco > fvco_max)
> > +				continue;
> > +			for (p = 2; p <= 4; p++) {
> > +				for (m = 64; m <= 1023; m++) {
> > +					if (fvco == m * fin_hz / p) {
> > +						rate_table->p = p;
> > +						rate_table->m = m;
> > +						rate_table->s = s;
> > +						rate_table->k = 0;
> > +						return 0;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	} else {
> > +		fout = (fout_hz / HZ_PER_MHZ) * HZ_PER_MHZ;
> > +		ffrac = (fout_hz % HZ_PER_MHZ);
> > +		for (s = 0; s <= 6; s++) {
> > +			fvco = fout << s;
> > +			if (fvco < fvco_min || fvco > fvco_max)
> > +				continue;
> > +			for (p = 1; p <= 4; p++) {
> > +				for (m = 64; m <= 1023; m++) {
> > +					if (fvco == m * fin_hz / p) {
> > +						rate_table->p = p;
> > +						rate_table->m = m;
> > +						rate_table->s = s;
> > +						fref = fin_hz / p;
> > +						fout = (ffrac << s) * 65535;
> > +						rate_table->k = fout / fref;
> > +						return 0;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	return -EINVAL;
> > +}
> > +
> >  static const struct rockchip_pll_rate_table *rockchip_get_pll_settings(
> >  			    struct rockchip_clk_pll *pll, unsigned long rate)
> >  {
> > @@ -68,6 +130,14 @@ static long rockchip_pll_round_rate(struct clk_hw *hw,
> >  	const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
> >  	int i;
> >  
> > +	if (pll->type == pll_rk3588 || pll->type == pll_rk3588_core) {
> > +		long parent_rate = prate ? *prate : 24 * HZ_PER_MHZ;
> > +		struct rockchip_pll_rate_table pll_settings;
> > +
> > +		if (rockchip_rk3588_get_pll_settings(pll, parent_rate, drate, &pll_settings) >= 0)
> > +			return pll_settings.rate;
> > +	}
> > +
> 
> I was reading some of previous backlog on why these formula have never been
> mainlines [0]. It looks like so far the statu quo was adopted. But if that was
> to change, I think this implementation is not aligned with the intent. If my
> understanding is right, the rate_table[] (if it exists) should be looked up
> first and the formula use as a fallback.

real life products like the Chromebooks using rk3288 and rk3399 had
a lot of fun with PLL rates (jitter and whatnot) and even had the underlying
parameters of some rates changed (same rate but using different parameters
to achive it) to reduce effects.

When doing this rate-table + dynamic calculation you never really know
which one will be taken I guess. When you hit the exact rate as in the
table you might get an optimized one but when round-rate ends up like 1kHz
above, you would then get a non-optimized calculated one.

So I'm personally really in favor of just sticking with a curated rate-table.


Heiko



> [0] https://patchwork.kernel.org/project/linux-rockchip/patch/1470144852-20708-1-git-send-email-zhengxing@rock-chips.com/#19548765
> 
> >  	/* Assumming rate_table is in descending order */
> >  	for (i = 0; i < pll->rate_count; i++) {
> >  		if (drate >= rate_table[i].rate)
> > @@ -842,6 +912,212 @@ static const struct clk_ops rockchip_rk3399_pll_clk_ops = {
> >  	.init = rockchip_rk3399_pll_init,
> >  };
> >  
> > +/**
> > + * PLL used in RK3588
> > + */
> > +
> > +#define RK3588_PLLCON(i)               (i * 0x4)
> > +#define RK3588_PLLCON0_M_MASK          0x3ff
> > +#define RK3588_PLLCON0_M_SHIFT         0
> > +#define RK3588_PLLCON1_P_MASK          0x3f
> > +#define RK3588_PLLCON1_P_SHIFT         0
> > +#define RK3588_PLLCON1_S_MASK          0x7
> > +#define RK3588_PLLCON1_S_SHIFT         6
> > +#define RK3588_PLLCON2_K_MASK          0xffff
> > +#define RK3588_PLLCON2_K_SHIFT         0
> > +#define RK3588_PLLCON1_PWRDOWN         BIT(13)
> > +#define RK3588_PLLCON6_LOCK_STATUS     BIT(15)
> > +
> > +static int rockchip_rk3588_pll_wait_lock(struct rockchip_clk_pll *pll)
> > +{
> > +	u32 pllcon;
> > +	int ret;
> > +
> > +	/*
> > +	 * Lock time typical 250, max 500 input clock cycles @24MHz
> > +	 * So define a very safe maximum of 1000us, meaning 24000 cycles.
> > +	 */
> > +	ret = readl_relaxed_poll_timeout(pll->reg_base + RK3588_PLLCON(6),
> > +					 pllcon,
> > +					 pllcon & RK3588_PLLCON6_LOCK_STATUS,
> > +					 0, 1000);
> > +	if (ret)
> > +		pr_err("%s: timeout waiting for pll to lock\n", __func__);
> > +
> > +	return ret;
> > +}
> > +
> > +static void rockchip_rk3588_pll_get_params(struct rockchip_clk_pll *pll,
> > +					   struct rockchip_pll_rate_table *rate)
> > +{
> > +	u32 pllcon;
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(0));
> > +	rate->m = ((pllcon >> RK3588_PLLCON0_M_SHIFT) & RK3588_PLLCON0_M_MASK);
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1));
> > +	rate->p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) & RK3588_PLLCON1_P_MASK);
> > +	rate->s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) & RK3588_PLLCON1_S_MASK);
> > +
> > +	pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(2));
> > +	rate->k = ((pllcon >> RK3588_PLLCON2_K_SHIFT) & RK3588_PLLCON2_K_MASK);
> > +}
> > +
> > +static unsigned long rockchip_rk3588_pll_recalc_rate(struct clk_hw *hw, unsigned long prate)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	struct rockchip_pll_rate_table cur;
> > +	u64 rate64 = prate, postdiv;
> > +
> > +	rockchip_rk3588_pll_get_params(pll, &cur);
> > +
> > +	rate64 *= cur.m;
> > +	do_div(rate64, cur.p);
> > +
> > +	if (cur.k) {
> > +		/* fractional mode */
> > +		u64 frac_rate64 = prate * cur.k;
> > +
> > +		postdiv = cur.p * 65535;
> > +		do_div(frac_rate64, postdiv);
> > +		rate64 += frac_rate64;
> > +	}
> > +	rate64 = rate64 >> cur.s;
> > +
> > +	return (unsigned long)rate64;
> > +}
> > +
> > +static int rockchip_rk3588_pll_set_params(struct rockchip_clk_pll *pll,
> > +					  const struct rockchip_pll_rate_table *rate)
> > +{
> > +	const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
> > +	struct clk_mux *pll_mux = &pll->pll_mux;
> > +	struct rockchip_pll_rate_table cur;
> > +	int rate_change_remuxed = 0;
> > +	int cur_parent;
> > +	int ret;
> > +
> > +	pr_debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n",
> > +		 __func__, rate->rate, rate->p, rate->m, rate->s, rate->k);
> > +
> > +	rockchip_rk3588_pll_get_params(pll, &cur);
> > +	cur.rate = 0;
> > +
> > +	if (pll->type == pll_rk3588) {
> > +		cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
> > +		if (cur_parent == PLL_MODE_NORM) {
> > +			pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
> > +			rate_change_remuxed = 1;
> > +		}
> > +	}
> > +
> > +	/* set pll power down */
> > +	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN,
> > +			     RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3399_PLLCON(1));
> > +
> > +	/* update pll values */
> > +	writel_relaxed(HIWORD_UPDATE(rate->m, RK3588_PLLCON0_M_MASK, RK3588_PLLCON0_M_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(0));
> > +
> > +	writel_relaxed(HIWORD_UPDATE(rate->p, RK3588_PLLCON1_P_MASK, RK3588_PLLCON1_P_SHIFT) |
> > +		       HIWORD_UPDATE(rate->s, RK3588_PLLCON1_S_MASK, RK3588_PLLCON1_S_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(1));
> > +
> > +	writel_relaxed(HIWORD_UPDATE(rate->k, RK3588_PLLCON2_K_MASK, RK3588_PLLCON2_K_SHIFT),
> > +		       pll->reg_base + RK3399_PLLCON(2));
> > +
> > +	/* set pll power up */
> > +	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +
> > +	/* wait for the pll to lock */
> > +	ret = rockchip_rk3588_pll_wait_lock(pll);
> > +	if (ret) {
> > +		pr_warn("%s: pll update unsuccessful, trying to restore old params\n",
> > +			__func__);
> > +		rockchip_rk3588_pll_set_params(pll, &cur);
> > +	}
> > +
> > +	if ((pll->type == pll_rk3588) && rate_change_remuxed)
> > +		pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
> > +
> > +	return ret;
> > +}
> > +
> > +static int rockchip_rk3588_pll_set_rate(struct clk_hw *hw, unsigned long drate,
> > +					unsigned long prate)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	struct rockchip_pll_rate_table rate;
> > +	unsigned long old_rate = rockchip_rk3588_pll_recalc_rate(hw, prate);
> > +
> > +	pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
> > +		 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
> > +
> > +	if (rockchip_rk3588_get_pll_settings(pll, prate, drate, &rate) < 0) {
> > +		pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
> > +		       drate, __clk_get_name(hw->clk));
> > +		return -EINVAL;
> > +	}
> > +
> > +	return rockchip_rk3588_pll_set_params(pll, &rate);
> > +}
> > +
> > +static int rockchip_rk3588_pll_enable(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	writel(HIWORD_UPDATE(0, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +	rockchip_rk3588_pll_wait_lock(pll);
> > +
> > +	return 0;
> > +}
> > +
> > +static void rockchip_rk3588_pll_disable(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	writel(HIWORD_UPDATE(RK3588_PLLCON1_PWRDOWN, RK3588_PLLCON1_PWRDOWN, 0),
> > +	       pll->reg_base + RK3588_PLLCON(1));
> > +}
> > +
> > +static int rockchip_rk3588_pll_is_enabled(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +	u32 pllcon = readl(pll->reg_base + RK3588_PLLCON(1));
> > +
> > +	return !(pllcon & RK3588_PLLCON1_PWRDOWN);
> > +}
> > +
> > +static int rockchip_rk3588_pll_init(struct clk_hw *hw)
> > +{
> > +	struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
> > +
> > +	if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
> > +		return 0;
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct clk_ops rockchip_rk3588_pll_clk_norate_ops = {
> > +	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
> > +	.enable = rockchip_rk3588_pll_enable,
> > +	.disable = rockchip_rk3588_pll_disable,
> > +	.is_enabled = rockchip_rk3588_pll_is_enabled,
> > +};
> > +
> > +static const struct clk_ops rockchip_rk3588_pll_clk_ops = {
> > +	.recalc_rate = rockchip_rk3588_pll_recalc_rate,
> > +	.round_rate = rockchip_pll_round_rate,
> > +	.set_rate = rockchip_rk3588_pll_set_rate,
> > +	.enable = rockchip_rk3588_pll_enable,
> > +	.disable = rockchip_rk3588_pll_disable,
> > +	.is_enabled = rockchip_rk3588_pll_is_enabled,
> > +	.init = rockchip_rk3588_pll_init,
> > +};
> > +
> >  /*
> >   * Common registering of pll clocks
> >   */
> > @@ -890,7 +1166,8 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
> >  	if (pll_type == pll_rk3036 ||
> >  	    pll_type == pll_rk3066 ||
> >  	    pll_type == pll_rk3328 ||
> > -	    pll_type == pll_rk3399)
> > +	    pll_type == pll_rk3399 ||
> > +	    pll_type == pll_rk3588)
> >  		pll_mux->flags |= CLK_MUX_HIWORD_MASK;
> >  
> >  	/* the actual muxing is xin24m, pll-output, xin32k */
> > @@ -957,6 +1234,14 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
> >  		else
> >  			init.ops = &rockchip_rk3399_pll_clk_ops;
> >  		break;
> > +	case pll_rk3588:
> > +	case pll_rk3588_core:
> > +		if (!pll->rate_table)
> > +			init.ops = &rockchip_rk3588_pll_clk_norate_ops;
> > +		else
> > +			init.ops = &rockchip_rk3588_pll_clk_ops;
> > +		init.flags = flags;
> > +		break;
> >  	default:
> >  		pr_warn("%s: Unknown pll type for pll clk %s\n",
> >  			__func__, name);
> > diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
> > index 6aece7f07a7d..bf7c8d082fde 100644
> > --- a/drivers/clk/rockchip/clk.h
> > +++ b/drivers/clk/rockchip/clk.h
> > @@ -221,6 +221,8 @@ enum rockchip_pll_type {
> >  	pll_rk3066,
> >  	pll_rk3328,
> >  	pll_rk3399,
> > +	pll_rk3588,
> > +	pll_rk3588_core,
> >  };
> >  
> >  #define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,	\
> > @@ -253,6 +255,15 @@ enum rockchip_pll_type {
> >  	.nb = _nb,						\
> >  }
> >  
> > +#define RK3588_PLL_RATE(_rate, _p, _m, _s, _k)			\
> > +{								\
> > +	.rate   = _rate##U,					\
> > +	.p = _p,						\
> > +	.m = _m,						\
> > +	.s = _s,						\
> > +	.k = _k,						\
> > +}
> > +
> >  /**
> >   * struct rockchip_clk_provider - information about clock provider
> >   * @reg_base: virtual address for the register base.
> > @@ -288,6 +299,13 @@ struct rockchip_pll_rate_table {
> >  			unsigned int dsmpd;
> >  			unsigned int frac;
> >  		};
> > +		struct {
> > +			/* for RK3588 */
> > +			unsigned int m;
> > +			unsigned int p;
> > +			unsigned int s;
> > +			unsigned int k;
> > +		};
> >  	};
> >  };
> >  
> 
> 





_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2022-04-30  0:02 UTC|newest]

Thread overview: 146+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-22 17:09 [PATCHv1 00/19] Basic RK3588 Support Sebastian Reichel
2022-04-22 17:09 ` Sebastian Reichel
2022-04-22 17:09 ` Sebastian Reichel
2022-04-22 17:09 ` [PATCHv1 01/19] dt-binding: clock: Document rockchip,rk3588-cru bindings Sebastian Reichel
2022-04-22 17:09   ` [PATCHv1 01/19] dt-binding: clock: Document rockchip, rk3588-cru bindings Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-23 10:01   ` [PATCHv1 01/19] dt-binding: clock: Document rockchip,rk3588-cru bindings Krzysztof Kozlowski
2022-04-23 10:01     ` Krzysztof Kozlowski
2022-04-23 10:01     ` Krzysztof Kozlowski
2022-04-22 17:09 ` [PATCHv1 02/19] clk: rockchip: add register offset of the cores select parent Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09 ` [PATCHv1 03/19] clk: rockchip: add pll type for RK3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-27 13:36   ` Nicolas Dufresne
2022-04-27 13:36     ` Nicolas Dufresne
2022-04-27 13:36     ` Nicolas Dufresne
2022-04-30  0:02     ` Heiko Stübner [this message]
2022-04-30  0:02       ` Heiko Stübner
2022-04-30  0:02       ` Heiko Stübner
2022-04-29  1:56   ` kernel test robot
2022-04-29  1:56     ` kernel test robot
2022-04-29  1:56     ` kernel test robot
2022-04-22 17:09 ` [PATCHv1 04/19] clk: rockchip: clk-cpu: add mux setting for cpu change frequency Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09 ` [PATCHv1 05/19] clk: rockchip: add dt-binding header for rk3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-05-02 22:15   ` Rob Herring
2022-05-02 22:15     ` Rob Herring
2022-05-02 22:15     ` Rob Herring
2022-04-22 17:09 ` [PATCHv1 06/19] clk: rockchip: Add clock controller for the RK3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-29 19:31   ` kernel test robot
2022-04-29 19:31     ` kernel test robot
2022-04-29 19:31     ` kernel test robot
2022-04-22 17:09 ` [PATCHv1 07/19] dt-bindings: mmc: sdhci-of-dwcmhsc: Add rk3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-23 10:01   ` Krzysztof Kozlowski
2022-04-23 10:01     ` Krzysztof Kozlowski
2022-04-23 10:01     ` Krzysztof Kozlowski
2022-05-04 10:37   ` Ulf Hansson
2022-05-04 10:37     ` Ulf Hansson
2022-05-04 10:37     ` Ulf Hansson
2022-04-22 17:09 ` [PATCHv1 08/19] mmc: sdhci-of-dwcmshc: add reset call back for rockchip Socs Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-23 10:32   ` Dmitry Osipenko
2022-04-23 10:32     ` Dmitry Osipenko
2022-04-23 10:32     ` Dmitry Osipenko
2022-04-27  7:50   ` Adrian Hunter
2022-04-27  7:50     ` Adrian Hunter
2022-04-27  7:50     ` Adrian Hunter
2022-04-22 17:09 ` [PATCHv1 09/19] mmc: sdhci-of-dwcmshc: rename rk3568 to rk35xx Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-27  7:51   ` Adrian Hunter
2022-04-27  7:51     ` Adrian Hunter
2022-04-27  7:51     ` Adrian Hunter
2022-04-22 17:09 ` [PATCHv1 10/19] mmc: sdhci-of-dwcmshc: add support for rk3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-27  7:51   ` Adrian Hunter
2022-04-27  7:51     ` Adrian Hunter
2022-04-27  7:51     ` Adrian Hunter
2022-04-22 17:09 ` [PATCHv1 11/19] dt-bindings: pinctrl: rockchip: add rk3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-23 10:02   ` Krzysztof Kozlowski
2022-04-23 10:02     ` Krzysztof Kozlowski
2022-04-23 10:02     ` Krzysztof Kozlowski
2022-04-22 17:09 ` [PATCHv1 12/19] pinctrl/rockchip: add error handling for pull/drive register getters Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 20:50   ` Heiko Stuebner
2022-04-22 20:50     ` Heiko Stuebner
2022-04-22 20:50     ` Heiko Stuebner
2022-04-28 22:54   ` Linus Walleij
2022-04-28 22:54     ` Linus Walleij
2022-04-28 22:54     ` Linus Walleij
2022-04-22 17:09 ` [PATCHv1 13/19] pinctrl/rockchip: add rk3588 support Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-28 22:55   ` Linus Walleij
2022-04-28 22:55     ` Linus Walleij
2022-04-28 22:55     ` Linus Walleij
2022-04-30 14:12     ` Heiko Stuebner
2022-04-30 14:12       ` Heiko Stuebner
2022-04-30 14:12       ` Heiko Stuebner
2022-04-22 17:09 ` [PATCHv1 14/19] gpio: rockchip: add support for rk3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 20:35   ` Linus Walleij
2022-04-22 20:35     ` Linus Walleij
2022-04-22 20:35     ` Linus Walleij
2022-04-22 17:09 ` [PATCHv1 15/19] dt-bindings: serial: snps-dw-apb-uart: Add Rockchip RK3588 Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-23 10:02   ` Krzysztof Kozlowski
2022-04-23 10:02     ` Krzysztof Kozlowski
2022-04-23 10:02     ` Krzysztof Kozlowski
2022-04-22 17:09 ` [PATCHv1 16/19] dt-bindings: soc: rockchip: add initial rk3588 syscon compatibles Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-23 10:03   ` Krzysztof Kozlowski
2022-04-23 10:03     ` Krzysztof Kozlowski
2022-04-23 10:03     ` Krzysztof Kozlowski
2022-04-22 17:09 ` [PATCHv1 17/19] arm64: dts: rockchip: Add rk3588s pinctrl data Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 20:45   ` Linus Walleij
2022-04-22 20:45     ` Linus Walleij
2022-04-22 20:45     ` Linus Walleij
2022-04-22 17:09 ` [PATCHv1 18/19] arm64: dts: rockchip: Add base DT for rk3588 SoC Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 18:16   ` Robin Murphy
2022-04-22 18:16     ` Robin Murphy
2022-04-22 18:16     ` Robin Murphy
2022-04-25 18:14     ` Sebastian Reichel
2022-04-25 18:14       ` Sebastian Reichel
2022-04-25 18:14       ` Sebastian Reichel
2022-04-25 19:37       ` Peter Geis
2022-04-25 19:37         ` Peter Geis
2022-04-25 19:37         ` Peter Geis
2022-04-23 10:07   ` Krzysztof Kozlowski
2022-04-23 10:07     ` Krzysztof Kozlowski
2022-04-23 10:07     ` Krzysztof Kozlowski
2022-05-02 22:20   ` Rob Herring
2022-05-02 22:20     ` Rob Herring
2022-05-02 22:20     ` Rob Herring
2022-04-22 17:09 ` [PATCHv1 19/19] arm64: dts: rockchip: Add rk3588-evb1 board Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-22 17:09   ` Sebastian Reichel
2022-04-23 10:09   ` Krzysztof Kozlowski
2022-04-23 10:09     ` Krzysztof Kozlowski
2022-04-23 10:09     ` Krzysztof Kozlowski
2022-04-25 19:44     ` Rob Herring
2022-04-25 19:44       ` Rob Herring
2022-04-25 19:44       ` Rob Herring
2022-04-22 20:44 ` [PATCHv1 00/19] Basic RK3588 Support Linus Walleij
2022-04-22 20:44   ` Linus Walleij
2022-04-22 20:44   ` Linus Walleij

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2180345.iZASKD2KPV@diego \
    --to=heiko@sntech.de \
    --cc=adrian.hunter@intel.com \
    --cc=brgl@bgdev.pl \
    --cc=devicetree@vger.kernel.org \
    --cc=kernel@collabora.com \
    --cc=kernel@lists.collabora.co.uk \
    --cc=krzk+dt@kernel.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=mturquette@baylibre.com \
    --cc=nicolas.dufresne@collabora.com \
    --cc=p.zabel@pengutronix.de \
    --cc=robh+dt@kernel.org \
    --cc=sboyd@kernel.org \
    --cc=sebastian.reichel@collabora.com \
    --cc=ulf.hansson@linaro.org \
    --cc=zhangqing@rock-chips.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.