devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lukasz Majewski <l.majewski@samsung.com>
To: Thomas Abraham <ta.omasab@gmail.com>
Cc: linux-samsung-soc@vger.kernel.org, cpufreq@vger.kernel.org,
	devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	t.figa@samsung.com, kgene.kim@samsung.com,
	viresh.kumar@linaro.org, shawn.guo@linaro.org,
	thomas.ab@samsung.com, Lukasz Majewski <l.majewski@majess.pl>
Subject: Re: [PATCH 3/6] clk: samsung: register cpu clock provider for exynos4210 SoC
Date: Fri, 10 Jan 2014 13:04:24 +0100	[thread overview]
Message-ID: <20140110130424.6aa78438@amdc2363> (raw)
In-Reply-To: <1389283165-17708-4-git-send-email-thomas.ab@samsung.com>

Hi Thomas,

> Add a new clock provider for ARM clock domain. This clock provider
> is composed of multiple components which include mux_core, div_core,
> div_core2, div_corem0, div_corem1, div_periph, div_atb, div_pclk_dbg,
> div_copy and div_hpm. This composition of mutiple components into
> a single clock provider helps with faster completion of CPU clock
> speed switching during DVFS operations.
> 
> Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> ---
>  drivers/clk/samsung/clk-exynos4.c |   96
> ++++++++++++++++++++++++++++++++++++- 1 files changed, 95
> insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/clk/samsung/clk-exynos4.c
> b/drivers/clk/samsung/clk-exynos4.c index d967571..4bf2f93 100644
> --- a/drivers/clk/samsung/clk-exynos4.c
> +++ b/drivers/clk/samsung/clk-exynos4.c
> @@ -108,8 +108,11 @@
>  #define APLL_CON0		0x14100
>  #define E4210_MPLL_CON0		0x14108
>  #define SRC_CPU			0x14200
> +#define STAT_CPU		0x14400
>  #define DIV_CPU0		0x14500
>  #define DIV_CPU1		0x14504
> +#define DIV_STAT_CPU0		0x14600
> +#define DIV_STAT_CPU1		0x14604
>  #define GATE_SCLK_CPU		0x14800
>  #define GATE_IP_CPU		0x14900
>  #define E4X12_DIV_ISP0		0x18300
> @@ -289,7 +292,7 @@ static unsigned long exynos4_clk_regs[]
> __initdata = { };
>  
>  /* list of all parent clock list */
> -PNAME(mout_apll_p)	= { "fin_pll", "fout_apll", };
> +PNAME(mout_apll_p)	= { "fin_pll", "fout_apll1", };
>  PNAME(mout_mpll_p)	= { "fin_pll", "fout_mpll", };
>  PNAME(mout_epll_p)	= { "fin_pll", "fout_epll", };
>  PNAME(mout_vpllsrc_p)	= { "fin_pll", "sclk_hdmi24m", };
> @@ -306,6 +309,7 @@ PNAME(mout_onenand_p)  = {"aclk133", "aclk160", };
>  PNAME(mout_onenand1_p) = {"mout_onenand", "sclk_vpll", };
>  
>  /* Exynos 4210-specific parent groups */
> +PNAME(armclk_p) = { "fout_apll", };

Here you only give no parent clock, but at samsung_coreclk_register()
it is expected to provide list of parents.

>  PNAME(sclk_vpll_p4210)	= { "mout_vpllsrc", "fout_vpll", };
>  PNAME(mout_core_p4210)	= { "mout_apll", "sclk_mpll", };
>  PNAME(sclk_ampll_p4210)	= { "sclk_mpll", "sclk_apll", };
> @@ -1089,6 +1093,92 @@ static struct samsung_pll_clock
> exynos4x12_plls[nr_plls] __initdata = { VPLL_LOCK, VPLL_CON0, NULL),
>  };
>  
> +#define EXYNOS4210_DIV_CPU0(apll, pclk_dbg, atb, periph, corem1,
> corem0) \
> +		((apll << 24) | (pclk_dbg << 20) | (atb << 16) | \
> +		(periph << 12) | (corem1 << 8) | (corem0 << 4))
> +#define EXYNOS4210_DIV_CPU1(hpm, copy)	\
> +		((hpm << 4) | (copy << 0))
> +static const unsigned long exynos4210_armclk_data[][2] = {
> +	{ EXYNOS4210_DIV_CPU0(7, 1, 4, 3, 7, 3),
> EXYNOS4210_DIV_CPU1(0, 5), },
> +	{ EXYNOS4210_DIV_CPU0(7, 1, 4, 3, 7, 3),
> EXYNOS4210_DIV_CPU1(0, 4), },
> +	{ EXYNOS4210_DIV_CPU0(7, 1, 3, 3, 7, 3),
> EXYNOS4210_DIV_CPU1(0, 3), },
> +	{ EXYNOS4210_DIV_CPU0(7, 1, 3, 3, 7, 3),
> EXYNOS4210_DIV_CPU1(0, 3), },
> +	{ EXYNOS4210_DIV_CPU0(7, 1, 3, 3, 7, 3),
> EXYNOS4210_DIV_CPU1(0, 3), },
> +	{ EXYNOS4210_DIV_CPU0(0, 1, 3, 1, 3, 1),
> EXYNOS4210_DIV_CPU1(0, 3), }, +};
> +

What do you think about adding those parameters (like CPU dividers) as
an attribute to /cpus/cpu@0 node?

> +static const unsigned long exynos4210_armclk_freqs[] = {
> +	1200000 , 1000000, 800000, 500000, 400000, 200000,
> +};

Those freq's are going to be defined at /cpus/cpu@0 at operating-points
attribute (or if possible took from cpufreq_frequency table).

> +
> +static const struct samsung_core_clock_freq_table
> exyno4210_armclk_table = {
> +	.freq		= exynos4210_armclk_freqs,
> +	.freq_count	= ARRAY_SIZE(exynos4210_armclk_freqs),
> +	.data		= (void *)exynos4210_armclk_data,
> +};
> +
> +static int exynos4210_armclk_set_rate(struct clk_hw *hw, unsigned
> long drate,
> +					unsigned long prate)
> +{
> +	struct samsung_core_clock *armclk;
> +	const struct samsung_core_clock_freq_table *freq_tbl;
> +	unsigned long *freq_data;
> +	unsigned long mux_reg, idx;
> +	void __iomem *base;
> +
> +	if (drate == prate)
> +		return 0;
> +
> +	armclk = container_of(hw, struct samsung_core_clock, hw);
> +	freq_tbl = armclk->freq_table;
> +	freq_data = (unsigned long *)freq_tbl->data;
> +	base = armclk->ctrl_base;
> +
> +	for (idx = 0; idx < freq_tbl->freq_count; idx++, freq_data
> += 2)
> +		if ((freq_tbl->freq[idx] * 1000) == drate)
> +			break;
> +
> +	if (!armclk->fout_pll)
> +		armclk->fout_pll = __clk_lookup("fout_apll");\
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^[*]
	
I'm a bit confused here for two reasons. Please correct me if I'm wrong.

1. You go into this ->set_rate() because of calling clk_set_rate at
"arm_clk" clock (numbered as 12 at clk-exynos4.c) at cpufreq-cpu0.c

In a Exynos4210 we have:
XXTI-> APLL -> fout_apll -> mout_apll -> mout_core -> div_core
-> div_core2 -> arm_clk

In the code you call directly the fout_apll which changes
frequency. Then the change shall be propagated to all registered
clocks.
I think, that DIV and DIV1 shall be reduced before PLL change [*],
to reflect the changes at CCF.	


> +
> +	if (drate < prate) {
> +		mux_reg = readl(base + SRC_CPU);
> +		writel(mux_reg | (1 << 16), base + SRC_CPU);
> +		while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +			;
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [**]

2. I think, the above shall be done in a following way:

	clk_set_parent(mout_core, mout_mpll);
	clk_set_rate(armclk->fout_pll, drate);
	clk_set_parent(mout_core, mout_apll);

The direct write to registers [**] doesn't look compliant to CCF.


I'd rather thought about using "mout_core" instead of "arm_clk". Then we
would get access to the parent directly:

	struct clk *parent = clk_get_parent(hw->clk);

so we set the parents explicitly (at clk registration) and call
->recalc_rate for clocks which are lower in the tree (like "div_core",
"div_core2").

> +		clk_set_rate(armclk->fout_pll, drate);
> +	}
> +
> +	writel(freq_data[0], base + DIV_CPU0);
> +	while (readl(base + DIV_STAT_CPU0) != 0)
> +		;
> +	writel(freq_data[1], base + DIV_CPU1);
> +	while (readl(base + DIV_STAT_CPU1) != 0)
> +		;
> +
> +	if (drate > prate) {
> +		mux_reg = readl(base + SRC_CPU);
> +		writel(mux_reg | (1 << 16), base + SRC_CPU);
> +		while (((readl(base + STAT_CPU) >> 16) & 0x7) != 2)
> +			;
> +
> +		clk_set_rate(armclk->fout_pll, drate);
> +	}
> +
> +	mux_reg = readl(base + SRC_CPU);
> +	writel(mux_reg & ~(1 << 16), base + SRC_CPU);
> +	while (((readl(base + STAT_CPU) >> 16) & 0x7) != 1)
> +			;
> +	return 0;
> +}
> +
> +static const struct clk_ops exynos4210_armclk_clk_ops = {
> +	.recalc_rate = samsung_core_clock_recalc_rate,
> +	.round_rate = samsung_core_clk_round_rate,
> +	.set_rate = exynos4210_armclk_set_rate,
> +};
> +
>  /* register exynos4 clocks */
>  static void __init exynos4_clk_init(struct device_node *np,
>  				    enum exynos4_soc exynos4_soc,
> @@ -1164,6 +1254,10 @@ static void __init exynos4_clk_init(struct
> device_node *np, ARRAY_SIZE(exynos4210_gate_clks));
>  		samsung_clk_register_alias(exynos4210_aliases,
>  			ARRAY_SIZE(exynos4210_aliases));
> +		samsung_coreclk_register("armclk", armclk_p,
> +			ARRAY_SIZE(armclk_p), "fout_apll",
> +			&exynos4210_armclk_clk_ops, arm_clk,
> +			&exyno4210_armclk_table);
>  	} else {
>  		samsung_clk_register_mux(exynos4x12_mux_clks,
>  			ARRAY_SIZE(exynos4x12_mux_clks));



-- 
Best regards,

Lukasz Majewski

Samsung R&D Institute Poland (SRPOL) | Linux Platform Group

  reply	other threads:[~2014-01-10 12:04 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-01-09 15:59 [PATCH 0/6] cpufreq: use cpufreq-cpu0 driver for exynos4210 based platforms Thomas Abraham
2014-01-09 15:59 ` [PATCH 1/6] cpufreq: cpufreq-cpu0: allow optional safe voltage during frequency transitions Thomas Abraham
2014-01-10 12:03   ` Lukasz Majewski
2014-01-12 13:39   ` Tomasz Figa
2014-01-13  3:14   ` Shawn Guo
2014-01-13 14:21     ` Thomas Abraham
2014-01-13 14:28       ` Shawn Guo
2014-01-09 15:59 ` [PATCH 2/6] clk: samsung: add infrastructure to register CPU clocks Thomas Abraham
2014-01-10 12:04   ` Lukasz Majewski
2014-01-10 12:19     ` Thomas Abraham
2014-01-10 13:25       ` Lukasz Majewski
2014-01-11  4:43         ` Thomas Abraham
2014-01-12  1:47           ` Tomasz Figa
2014-01-12  8:04             ` Lukasz Majewski
2014-01-13 13:15             ` Thomas Abraham
2014-01-09 15:59 ` [PATCH 3/6] clk: samsung: register cpu clock provider for exynos4210 SoC Thomas Abraham
2014-01-10 12:04   ` Lukasz Majewski [this message]
2014-01-10 12:37     ` Thomas Abraham
2014-01-10 14:18       ` Lukasz Majewski
2014-01-11  5:25         ` Thomas Abraham
2014-01-12  2:19           ` Tomasz Figa
2014-01-12  8:23             ` Lukasz Majewski
2014-01-12 12:05               ` Tomasz Figa
2014-01-12 12:41                 ` Lukasz Majewski
2014-01-12 12:58                   ` Tomasz Figa
2014-01-13 14:12                     ` Thomas Abraham
2014-01-13 14:07             ` Thomas Abraham
2014-01-09 15:59 ` [PATCH 4/6] cpufreq: exynos: remove Exynos4210 specific cpufreq driver support Thomas Abraham
2014-01-10 10:20   ` Lukasz Majewski
2014-01-09 15:59 ` [PATCH 5/6] arm: exynos4-dt: statically add platform device for cpufreq-cpu0 platform driver Thomas Abraham
2014-01-10 10:23   ` Lukasz Majewski
2014-01-13  3:17   ` Shawn Guo
2014-01-09 15:59 ` [PATCH 6/6] arm: dts: add cpu nodes for Exynos4210 SoC Thomas Abraham
2014-01-10 10:32   ` Lukasz Majewski
2014-01-10 12:06     ` Thomas Abraham
2014-01-10 10:32 ` [PATCH 0/6] cpufreq: use cpufreq-cpu0 driver for exynos4210 based platforms Lukasz Majewski
2014-01-10 11:59   ` Thomas Abraham
2014-01-12  2:26     ` Tomasz Figa
2014-01-13 14:27       ` Thomas Abraham

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=20140110130424.6aa78438@amdc2363 \
    --to=l.majewski@samsung.com \
    --cc=cpufreq@vger.kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=kgene.kim@samsung.com \
    --cc=l.majewski@majess.pl \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=shawn.guo@linaro.org \
    --cc=t.figa@samsung.com \
    --cc=ta.omasab@gmail.com \
    --cc=thomas.ab@samsung.com \
    --cc=viresh.kumar@linaro.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).