All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tomasz Figa <tomasz.figa@gmail.com>
To: Vikas Sajjan <vikas.sajjan@linaro.org>
Cc: yadi.brar01@gmail.com, linux-samsung-soc@vger.kernel.org,
	dianders@chromium.org, linux-arm-kernel@lists.infradead.org,
	kgene.kim@samsung.com, mturquette@linaro.org,
	thomas.abraham@linaro.org
Subject: Re: [RESEND PATCH 3/5] clk: samsung: Add set_rate() clk_ops for PLL35xx
Date: Sat, 25 May 2013 00:19:11 +0200	[thread overview]
Message-ID: <2621811.AH1nnyyD7h@flatron> (raw)
In-Reply-To: <1369391478-7665-4-git-send-email-vikas.sajjan@linaro.org>

Hi,

On Friday 24 of May 2013 16:01:16 Vikas Sajjan wrote:
> From: Yadwinder Singh Brar <yadi.brar@samsung.com>
> 
> Adds set_rate() and round_rate() clk_ops for PLL35xx
> 
> The round_rate() implemenation as of now is dummy, it returns the same
> rate which is passed as input.
> 
> Signed-off-by: Yadwinder Singh Brar <yadi.brar@samsung.com>
> ---
>  drivers/clk/samsung/clk-pll.c |   95
> ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94
> insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/samsung/clk-pll.c
> b/drivers/clk/samsung/clk-pll.c index b8c0260..291cc9e 100644
> --- a/drivers/clk/samsung/clk-pll.c
> +++ b/drivers/clk/samsung/clk-pll.c
> @@ -11,6 +11,7 @@
> 
>  #include <linux/errno.h>
>  #include <linux/sort.h>
> +#include <linux/bsearch.h>
>  #include "clk.h"
>  #include "clk-pll.h"
> 
> @@ -36,6 +37,21 @@ static int samsung_compare_rate(const void *_a, const
> void *_b) return a->rate - b->rate;
>  }
> 
> +static struct samsung_pll_rate_table *samsung_get_pll_settings(
> +				struct samsung_clk_pll *pll, unsigned long 
rate)
> +{
> +	struct samsung_pll_rate_table req_rate, *tmp;
> +
> +	req_rate.rate = rate;
> +	tmp = bsearch(&req_rate, pll->rate_table, pll->rate_count,
> +			sizeof(struct samsung_pll_rate_table),
> +			samsung_compare_rate);

Binary search over < 10 entries? Isn't it a bit of overkill?

> +	if (tmp)
> +		return tmp;
> +
> +	return NULL;
> +}
> +
>  /*
>   * PLL35xx Clock Type
>   */
> @@ -46,9 +62,15 @@ static int samsung_compare_rate(const void *_a, const
> void *_b) #define PLL35XX_MDIV_MASK       (0x3FF)
>  #define PLL35XX_PDIV_MASK       (0x3F)
>  #define PLL35XX_SDIV_MASK       (0x7)
> +#define PLL35XX_LOCK_STAT_MASK  (0x1)
>  #define PLL35XX_MDIV_SHIFT      (16)
>  #define PLL35XX_PDIV_SHIFT      (8)
>  #define PLL35XX_SDIV_SHIFT      (0)
> +#define PLL35XX_LOCK_STAT_SHIFT (29)
> +
> +#define PLL35XX_MDIV(_tmp) ((_tmp) & (PLL35XX_MDIV_MASK <<
> PLL35XX_MDIV_SHIFT)) +#define PLL35XX_PDIV(_tmp) ((_tmp) &
> (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT)) +#define PLL35XX_SDIV(_tmp)
> ((_tmp) & (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT))
> 
>  static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
>  				unsigned long parent_rate)
> @@ -68,8 +90,76 @@ static unsigned long
> samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned
> long)fvco;
>  }
> 
> -static const struct clk_ops samsung_pll35xx_clk_ops = {
> +static inline bool samsung_pll35xx_mp_change(u32 mdiv, u32 pdiv, u32
> pll_con) +{
> +	if ((mdiv != PLL35XX_MDIV(pll_con)) || (pdiv !=
> PLL35XX_PDIV(pll_con))) +		return 1;
> +	else
> +		return 0;
> +}
> +
> +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long
> drate, +					unsigned long prate)
> +{
> +	struct samsung_clk_pll *pll = to_clk_pll(hw);
> +	struct samsung_pll_rate_table *rate;
> +
> +	u32 tmp, mdiv, pdiv, sdiv;
> +
> +	/* Get required rate settings from table */
> +	rate = samsung_get_pll_settings(pll, drate);
> +	if (!rate) {
> +		pr_err("%s: Invalid rate : %lu for pll clk %s\n", 
__func__,
> +			drate, __clk_get_name(hw->clk));
> +		return -EINVAL;
> +	}
> +
> +	mdiv = PLL35XX_MDIV(rate->pll_con0);
> +	pdiv = PLL35XX_PDIV(rate->pll_con0);
> +	sdiv = PLL35XX_SDIV(rate->pll_con0);

You wouldn't need to use those macros if all coefficients were stored as 
separate fields in the struct.

> +
> +	tmp = pll_readl(pll, PLL35XX_CON0_OFFSET);
> +
> +	if (!(samsung_pll35xx_mp_change(mdiv, pdiv, tmp))) {
> +		/* If only s change, change just s value only*/
> +		tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
> +		tmp |= sdiv;

This line is correct, but it looks like it wasn't, because:
a) the name suggests that it contains the raw value of S coefficient
b) it's real value is hidden between a macro, name of which suggests the 
same as in a) as well.

This makes the code hard to read.

> +		pll_writel(pll, tmp, PLL35XX_CON0_OFFSET);
> +	} else {
> +		/* Set PLL lock time.
> +		   Maximum lock time can be 270 * PDIV cycles */
> +		pll_writel(pll, (pdiv >> PLL35XX_PDIV_SHIFT) * 270,
> +				PLL35XX_LOCK_OFFSET);

Hmm, magic constant in the code? Shouldn't it be defined as a macro?

> +
> +		/* Change PLL PMS values */
> +		tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
> +				(PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) 
|
> +				(PLL35XX_SDIV_MASK << 
PLL35XX_SDIV_SHIFT));
> +		tmp |= mdiv | pdiv | sdiv;

This looks strange as well, even if it's correct.

> +		pll_writel(pll, tmp, PLL35XX_CON0_OFFSET);
> +
> +		/* wait_lock_time */
> +		do {
> +			cpu_relax();
> +			tmp = pll_readl(pll, PLL35XX_CON0_OFFSET);
> +		} while (!(tmp & (PLL35XX_LOCK_STAT_MASK
> +				<< PLL35XX_LOCK_STAT_SHIFT)));
> +	}
> +
> +	return 0;
> +}
> +
> +static long samsung_pll35xx_round_rate(struct clk_hw *hw,
> +			unsigned long drate, unsigned long *prate)
> +{
> +	/* Clock framework cries without this, so implemented dummy */

This is completely wrong. Have you tested this code or read how Common 
Clock Framework works?

clk_set_rate() first calls ->round_rate() to get a rate supported by the 
clock that is nearest and not higher than requested rate and only then it 
calls ->set_rate() with the rate returned by ->round_rate().

So the round_rate() callback must return the highest supported rate with 
parent clock at prate and not higher than drate.

> +	return drate;
> +}
> +
> +static struct clk_ops samsung_pll35xx_clk_ops = {
>  	.recalc_rate = samsung_pll35xx_recalc_rate,
> +	.round_rate = samsung_pll35xx_round_rate,
> +	.set_rate = samsung_pll35xx_set_rate,
>  };
> 
>  struct clk * __init samsung_clk_register_pll35xx(const char *name,
> @@ -102,6 +192,9 @@ struct clk * __init
> samsung_clk_register_pll35xx(const char *name, sort(pll->rate_table,
> pll->rate_count,
>  			sizeof(struct samsung_pll_rate_table),
>  			samsung_compare_rate, NULL);
> +	} else {
> +		samsung_pll35xx_clk_ops.round_rate = NULL;
> +		samsung_pll35xx_clk_ops.set_rate = NULL;

This is completely wrong. You are changing a static structure that is used 
for all instances of PLL35xx, not only the one being registered at the 
moment.

Best regards,
Tomasz

>  	}
> 
>  	clk = clk_register(NULL, &pll->hw);

WARNING: multiple messages have this Message-ID (diff)
From: tomasz.figa@gmail.com (Tomasz Figa)
To: linux-arm-kernel@lists.infradead.org
Subject: [RESEND PATCH 3/5] clk: samsung: Add set_rate() clk_ops for PLL35xx
Date: Sat, 25 May 2013 00:19:11 +0200	[thread overview]
Message-ID: <2621811.AH1nnyyD7h@flatron> (raw)
In-Reply-To: <1369391478-7665-4-git-send-email-vikas.sajjan@linaro.org>

Hi,

On Friday 24 of May 2013 16:01:16 Vikas Sajjan wrote:
> From: Yadwinder Singh Brar <yadi.brar@samsung.com>
> 
> Adds set_rate() and round_rate() clk_ops for PLL35xx
> 
> The round_rate() implemenation as of now is dummy, it returns the same
> rate which is passed as input.
> 
> Signed-off-by: Yadwinder Singh Brar <yadi.brar@samsung.com>
> ---
>  drivers/clk/samsung/clk-pll.c |   95
> ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94
> insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/samsung/clk-pll.c
> b/drivers/clk/samsung/clk-pll.c index b8c0260..291cc9e 100644
> --- a/drivers/clk/samsung/clk-pll.c
> +++ b/drivers/clk/samsung/clk-pll.c
> @@ -11,6 +11,7 @@
> 
>  #include <linux/errno.h>
>  #include <linux/sort.h>
> +#include <linux/bsearch.h>
>  #include "clk.h"
>  #include "clk-pll.h"
> 
> @@ -36,6 +37,21 @@ static int samsung_compare_rate(const void *_a, const
> void *_b) return a->rate - b->rate;
>  }
> 
> +static struct samsung_pll_rate_table *samsung_get_pll_settings(
> +				struct samsung_clk_pll *pll, unsigned long 
rate)
> +{
> +	struct samsung_pll_rate_table req_rate, *tmp;
> +
> +	req_rate.rate = rate;
> +	tmp = bsearch(&req_rate, pll->rate_table, pll->rate_count,
> +			sizeof(struct samsung_pll_rate_table),
> +			samsung_compare_rate);

Binary search over < 10 entries? Isn't it a bit of overkill?

> +	if (tmp)
> +		return tmp;
> +
> +	return NULL;
> +}
> +
>  /*
>   * PLL35xx Clock Type
>   */
> @@ -46,9 +62,15 @@ static int samsung_compare_rate(const void *_a, const
> void *_b) #define PLL35XX_MDIV_MASK       (0x3FF)
>  #define PLL35XX_PDIV_MASK       (0x3F)
>  #define PLL35XX_SDIV_MASK       (0x7)
> +#define PLL35XX_LOCK_STAT_MASK  (0x1)
>  #define PLL35XX_MDIV_SHIFT      (16)
>  #define PLL35XX_PDIV_SHIFT      (8)
>  #define PLL35XX_SDIV_SHIFT      (0)
> +#define PLL35XX_LOCK_STAT_SHIFT (29)
> +
> +#define PLL35XX_MDIV(_tmp) ((_tmp) & (PLL35XX_MDIV_MASK <<
> PLL35XX_MDIV_SHIFT)) +#define PLL35XX_PDIV(_tmp) ((_tmp) &
> (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT)) +#define PLL35XX_SDIV(_tmp)
> ((_tmp) & (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT))
> 
>  static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
>  				unsigned long parent_rate)
> @@ -68,8 +90,76 @@ static unsigned long
> samsung_pll35xx_recalc_rate(struct clk_hw *hw, return (unsigned
> long)fvco;
>  }
> 
> -static const struct clk_ops samsung_pll35xx_clk_ops = {
> +static inline bool samsung_pll35xx_mp_change(u32 mdiv, u32 pdiv, u32
> pll_con) +{
> +	if ((mdiv != PLL35XX_MDIV(pll_con)) || (pdiv !=
> PLL35XX_PDIV(pll_con))) +		return 1;
> +	else
> +		return 0;
> +}
> +
> +static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long
> drate, +					unsigned long prate)
> +{
> +	struct samsung_clk_pll *pll = to_clk_pll(hw);
> +	struct samsung_pll_rate_table *rate;
> +
> +	u32 tmp, mdiv, pdiv, sdiv;
> +
> +	/* Get required rate settings from table */
> +	rate = samsung_get_pll_settings(pll, drate);
> +	if (!rate) {
> +		pr_err("%s: Invalid rate : %lu for pll clk %s\n", 
__func__,
> +			drate, __clk_get_name(hw->clk));
> +		return -EINVAL;
> +	}
> +
> +	mdiv = PLL35XX_MDIV(rate->pll_con0);
> +	pdiv = PLL35XX_PDIV(rate->pll_con0);
> +	sdiv = PLL35XX_SDIV(rate->pll_con0);

You wouldn't need to use those macros if all coefficients were stored as 
separate fields in the struct.

> +
> +	tmp = pll_readl(pll, PLL35XX_CON0_OFFSET);
> +
> +	if (!(samsung_pll35xx_mp_change(mdiv, pdiv, tmp))) {
> +		/* If only s change, change just s value only*/
> +		tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
> +		tmp |= sdiv;

This line is correct, but it looks like it wasn't, because:
a) the name suggests that it contains the raw value of S coefficient
b) it's real value is hidden between a macro, name of which suggests the 
same as in a) as well.

This makes the code hard to read.

> +		pll_writel(pll, tmp, PLL35XX_CON0_OFFSET);
> +	} else {
> +		/* Set PLL lock time.
> +		   Maximum lock time can be 270 * PDIV cycles */
> +		pll_writel(pll, (pdiv >> PLL35XX_PDIV_SHIFT) * 270,
> +				PLL35XX_LOCK_OFFSET);

Hmm, magic constant in the code? Shouldn't it be defined as a macro?

> +
> +		/* Change PLL PMS values */
> +		tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
> +				(PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) 
|
> +				(PLL35XX_SDIV_MASK << 
PLL35XX_SDIV_SHIFT));
> +		tmp |= mdiv | pdiv | sdiv;

This looks strange as well, even if it's correct.

> +		pll_writel(pll, tmp, PLL35XX_CON0_OFFSET);
> +
> +		/* wait_lock_time */
> +		do {
> +			cpu_relax();
> +			tmp = pll_readl(pll, PLL35XX_CON0_OFFSET);
> +		} while (!(tmp & (PLL35XX_LOCK_STAT_MASK
> +				<< PLL35XX_LOCK_STAT_SHIFT)));
> +	}
> +
> +	return 0;
> +}
> +
> +static long samsung_pll35xx_round_rate(struct clk_hw *hw,
> +			unsigned long drate, unsigned long *prate)
> +{
> +	/* Clock framework cries without this, so implemented dummy */

This is completely wrong. Have you tested this code or read how Common 
Clock Framework works?

clk_set_rate() first calls ->round_rate() to get a rate supported by the 
clock that is nearest and not higher than requested rate and only then it 
calls ->set_rate() with the rate returned by ->round_rate().

So the round_rate() callback must return the highest supported rate with 
parent clock at prate and not higher than drate.

> +	return drate;
> +}
> +
> +static struct clk_ops samsung_pll35xx_clk_ops = {
>  	.recalc_rate = samsung_pll35xx_recalc_rate,
> +	.round_rate = samsung_pll35xx_round_rate,
> +	.set_rate = samsung_pll35xx_set_rate,
>  };
> 
>  struct clk * __init samsung_clk_register_pll35xx(const char *name,
> @@ -102,6 +192,9 @@ struct clk * __init
> samsung_clk_register_pll35xx(const char *name, sort(pll->rate_table,
> pll->rate_count,
>  			sizeof(struct samsung_pll_rate_table),
>  			samsung_compare_rate, NULL);
> +	} else {
> +		samsung_pll35xx_clk_ops.round_rate = NULL;
> +		samsung_pll35xx_clk_ops.set_rate = NULL;

This is completely wrong. You are changing a static structure that is used 
for all instances of PLL35xx, not only the one being registered at the 
moment.

Best regards,
Tomasz

>  	}
> 
>  	clk = clk_register(NULL, &pll->hw);

  reply	other threads:[~2013-05-24 22:19 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-05-24 10:31 [RESEND PATCH 0/5] Add generic set_rate clk_ops for PLL35XX and PLL36XX for samsung SoCs Vikas Sajjan
2013-05-24 10:31 ` Vikas Sajjan
2013-05-24 10:31 ` [RESEND PATCH 1/5] clk: samsung: Use clk->base instead of directly using clk->con0 for PLL3xxx Vikas Sajjan
2013-05-24 10:31   ` Vikas Sajjan
2013-05-24 21:55   ` Tomasz Figa
2013-05-24 21:55     ` Tomasz Figa
2013-05-24 10:31 ` [RESEND PATCH 2/5] clk: samsung: Add support to register rate_table " Vikas Sajjan
2013-05-24 10:31   ` Vikas Sajjan
2013-05-24 22:04   ` Tomasz Figa
2013-05-24 22:04     ` Tomasz Figa
2013-05-27  6:35     ` Yadwinder Singh Brar
2013-05-27  6:35       ` Yadwinder Singh Brar
2013-05-24 10:31 ` [RESEND PATCH 3/5] clk: samsung: Add set_rate() clk_ops for PLL35xx Vikas Sajjan
2013-05-24 10:31   ` Vikas Sajjan
2013-05-24 22:19   ` Tomasz Figa [this message]
2013-05-24 22:19     ` Tomasz Figa
2013-05-27  6:36     ` Yadwinder Singh Brar
2013-05-27  6:36       ` Yadwinder Singh Brar
2013-05-24 10:31 ` [RESEND PATCH 4/5] clk: samsung: Add set_rate() clk_ops for PLL36xx Vikas Sajjan
2013-05-24 10:31   ` Vikas Sajjan
2013-05-24 22:20   ` Tomasz Figa
2013-05-24 22:20     ` Tomasz Figa
2013-05-24 10:31 ` [RESEND PATCH 5/5] clk: samsung: Add EPLL and VPLL freq table for exynos5250 SoC Vikas Sajjan
2013-05-24 10:31   ` Vikas Sajjan
  -- strict thread matches above, loose matches on Subject: below --
2013-05-24  5:55 [RESEND PATCH 0/5] Add generic set_rate clk_ops for PLL35XX and PLL36XX for samsung SoCs Vikas Sajjan
2013-05-24  5:55 ` [RESEND PATCH 3/5] clk: samsung: Add set_rate() clk_ops for PLL35xx Vikas Sajjan

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=2621811.AH1nnyyD7h@flatron \
    --to=tomasz.figa@gmail.com \
    --cc=dianders@chromium.org \
    --cc=kgene.kim@samsung.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=mturquette@linaro.org \
    --cc=thomas.abraham@linaro.org \
    --cc=vikas.sajjan@linaro.org \
    --cc=yadi.brar01@gmail.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.