diff mbox

[RFC] ARM: shmobile: minimal r8a7740 common clock framework implementation

Message ID 1397041484-12552-1-git-send-email-ulrich.hecht@gmail.com (mailing list archive)
State RFC
Headers show

Commit Message

Ulrich Hecht April 9, 2014, 11:04 a.m. UTC
Hi!

This CCF implementation brings up the timer and serial console clocks and
all direct and indirect parents. (Ethernet also happens to work because
the bootloader leaves it on.)

This is closely modeled after the r8a779x implementation, so I hope it
makes some sense. (Please ignore the build system hacks for now.)

The clock initialization call has moved from r8a7740_generic_init()/
eva_init() to r8a7740_init_delay() to make sure the flags are set correctly
before the implicit OF clock initialization happens.

I wonder if it would make sense to eliminate r8a7740_clocks_init()
entirely and put the mode switch parsing in clk-r8a7740.c...

CU
Uli
---
 arch/arm/boot/dts/r8a7740.dtsi                     |  79 ++++++++++++
 arch/arm/mach-shmobile/Kconfig                     |   2 +-
 .../board-armadillo800eva-reference.c              |  10 +-
 arch/arm/mach-shmobile/setup-r8a7740.c             |   3 +-
 drivers/clk/Makefile                               |   1 +
 drivers/clk/shmobile/Makefile                      |   2 +
 drivers/clk/shmobile/clk-r8a7740.c                 | 143 +++++++++++++++++++++
 drivers/sh/Makefile                                |   2 +-
 include/dt-bindings/clock/r8a7740-clock.h          |  61 +++++++++
 9 files changed, 297 insertions(+), 6 deletions(-)
 create mode 100644 drivers/clk/shmobile/clk-r8a7740.c
 create mode 100644 include/dt-bindings/clock/r8a7740-clock.h

Comments

Laurent Pinchart April 9, 2014, 1:30 p.m. UTC | #1
Hi Ulrich,

Thank you for the patch.

This looks pretty good overall. I've made several comments below. My biggest 
concern at the moment is that I have no clear visibility on the DT bindings 
changes that will be required when we'll extend this minimal implementation. I 
believe it would be a good idea to already implement support for additional 
clocks (as follow-up patches on top of this one) to test the bindings.

On Wednesday 09 April 2014 13:04:44 Ulrich Hecht wrote:
> Hi!
> 
> This CCF implementation brings up the timer and serial console clocks and
> all direct and indirect parents. (Ethernet also happens to work because
> the bootloader leaves it on.)
> 
> This is closely modeled after the r8a779x implementation, so I hope it
> makes some sense. (Please ignore the build system hacks for now.)
> 
> The clock initialization call has moved from r8a7740_generic_init()/
> eva_init() to r8a7740_init_delay() to make sure the flags are set correctly
> before the implicit OF clock initialization happens.
> 
> I wonder if it would make sense to eliminate r8a7740_clocks_init()
> entirely and put the mode switch parsing in clk-r8a7740.c...

Given that the goal is to get rid of arch/arm/mach-* at some point, I believe 
it would make sense to drop r8a7740_clocks_init() as there would be no place 
to call that function from. One option would be to implement a driver for the 
system controller and expose an API that the CPG driver could use to read the 
boot mode. This has been discussed recently on LAKML, see 
http://thread.gmane.org/gmane.linux.ports.arm.kernel/313696/focus=313901

> CU
> Uli
> ---
>  arch/arm/boot/dts/r8a7740.dtsi                     |  79 ++++++++++++

DT bindings documentation missing :-)

>  arch/arm/mach-shmobile/Kconfig                     |   2 +-
>  .../board-armadillo800eva-reference.c              |  10 +-
>  arch/arm/mach-shmobile/setup-r8a7740.c             |   3 +-
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/shmobile/Makefile                      |   2 +
>  drivers/clk/shmobile/clk-r8a7740.c                 | 143 ++++++++++++++++++
>  drivers/sh/Makefile                                |   2 +-
>  include/dt-bindings/clock/r8a7740-clock.h          |  61 +++++++++
>  9 files changed, 297 insertions(+), 6 deletions(-)
>  create mode 100644 drivers/clk/shmobile/clk-r8a7740.c
>  create mode 100644 include/dt-bindings/clock/r8a7740-clock.h
> 
> diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi
> index 9f65986..37babce 100644
> --- a/arch/arm/boot/dts/r8a7740.dtsi
> +++ b/arch/arm/boot/dts/r8a7740.dtsi
> @@ -10,6 +10,7 @@
> 
>  /include/ "skeleton.dtsi"
> 
> +#include <dt-bindings/clock/r8a7740-clock.h>
>  #include <dt-bindings/interrupt-controller/irq.h>
> 
>  / {
> @@ -226,4 +227,82 @@
>  		interrupts = <0 9 0x4>;
>  		status = "disabled";
>  	};
> +
> +	clocks {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		ranges;
> +
> +		/* External root clock */
> +		extalr_clk: extalr_clk {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <32768>;
> +			clock-output-names = "extalr";
> +		};
> +		extal1_clk: extal1_clk {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <25000000>;

The extal1_clk frequency is board-dependent, I would specify it in DT board 
files instead.

> +			clock-output-names = "extal1";
> +		};
> +		extal2_clk: extal2_clk {
> +			compatible = "fixed-clock";
> +			#clock-cells = <0>;
> +			clock-frequency = <48000000>;

I think (but might be wrong) that extal2 is optional. In that case maybe we 
should set the frequency to 0 here and overwrite it in DT board files for 
boards that supply the clock.

> +			clock-output-names = "extal2";
> +		};
> +		/* Special CPG clocks */
> +		cpg_clocks: cpg_clocks@e6150000 {
> +			compatible = "renesas,r8a7740-cpg-clocks";
> +			reg = <0xe6150000 0x10000>;
> +			clocks = <&extal1_clk>, <&extalr_clk>;
> +			#clock-cells = <1>;
> +			clock-output-names = "system", "pllc0", "pllc1",
> +					     "pllc2", "r";
> +		};
> +
> +		/* Variable factor clocks (DIV6) */
> +		sub_clk: sub_clk@e6150080 {
> +			compatible = "renesas,r8a7740-div6-clock", "renesas,cpg-div6-
clock";
> +			reg = <0xe6150080 4>;
> +			clocks = <&pllc1_div2_clk>;
> +			#clock-cells = <0>;
> +			clock-output-names = "sub";
> +		};

The SUB divider actually supplies two clocks, sub1 and sub2, that have the 
same frequency but can be individually enabled/disabled. Other clocks that you 
don't support yet share that characteristic, and even have sub-dividers (for 
the HDMI clocks instead). The sub clocks also have a selectable parent. Have 
you thought about how you would like to implement that ? I'm not saying it has 
to be done right now, but it might be worth giving it a try for a couple of 
clocks at least to make sure we won't have DT ABI compatibility issues in the 
future.

> +
> +		/* Fixed factor clocks */
> +		pllc1_div2_clk: pllc1_div2_clk {
> +			compatible = "fixed-factor-clock";
> +			clocks = <&cpg_clocks R8A7740_CLK_PLLC1>;
> +			#clock-cells = <0>;
> +			clock-div = <2>;
> +			clock-mult = <1>;
> +			clock-output-names = "pllc1_div2";
> +		};
> +
> +		/* Gate clocks */
> +		mstp2_clks: mstp2_clks@e6150138 {
> +			compatible = "renesas,r8a7740-mstp-clocks", "renesas,cpg-mstp-
clocks";
> +			reg = <0xe6150138 4>, <0xe6150040 4>;
> +			clocks = <&sub_clk>;
> +			#clock-cells = <1>;
> +			renesas,clock-indices = <
> +				R8A7740_CLK_SCIFA1
> +			>;
> +			clock-output-names =
> +				"scifa1";
> +		};
> +		mstp3_clks: mstp3_clks@e615013c {
> +			compatible = "renesas,r8a7740-mstp-clocks", "renesas,cpg-mstp-
clocks";
> +			reg = <0xe615013c 4>, <0xe6150048 4>;
> +			clocks = <&cpg_clocks R8A7740_CLK_R>;

The CMT1 can user either the Common Peripheral (CP) clock (the datasheet isn't 
very clear on this one though) or the RTC clock for timer operation. I wonder 
whether the main function clock wouldn't be the CP clock instead.

> +			#clock-cells = <1>;
> +			renesas,clock-indices = <
> +				R8A7740_CLK_CMT10

This should be R8A7740_CLK_CMT1.

> +			>;
> +			clock-output-names =
> +				"cmt10";

This should be "cmt1".

> +		};
> +	};
>  };

[snip]

(I'll ignore platform code for now, I believe Magnus will comment on that 
separately)

> diff --git a/drivers/clk/shmobile/clk-r8a7740.c
> b/drivers/clk/shmobile/clk-r8a7740.c new file mode 100644
> index 0000000..4d9dcba
> --- /dev/null
> +++ b/drivers/clk/shmobile/clk-r8a7740.c
> @@ -0,0 +1,143 @@
> +/*
> + * r8a7740 Core CPG Clocks
> + *
> + * Copyright (C) 2014  Ulrich Hecht
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 2 of the License.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk/shmobile.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/math64.h>

I don't think this header is needed.

> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/spinlock.h>
> +#include <mach/r8a7740.h>

If I'm not mistaken you're including mach/r8a7740.h for the MD_CK* definitions 
only. As we're trying to get rid of the mach/ headers, what about using BIT() 
directly instead ?

> +
> +struct r8a7740_cpg {
> +	struct clk_onecell_data data;
> +	spinlock_t lock;

You don't use the spinlock, let's drop it for now (as well as the 
linux/spinlock.h include above) and add it later only when needed.

> +	void __iomem *reg;
> +};
> +
> +#define CPG_FRQCRA			0
> +#define CPG_FRQCRC			0xe0
> +#define CPG_PLLC01CR			0x28

You don't use this register.

> +
> +struct cpg_pll_config {
> +};

The CPG has no PLL configuration derived from the boot mode value, you can 
drop this structure and all the related variables below.

> +
> +static u32 cpg_mode __initdata;
> +
> +static struct clk * __init
> +r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg,
> +			     const struct cpg_pll_config *config,
> +			     const char *name)
> +{
> +	const char *parent_name;
> +	unsigned int mult = 1;
> +	unsigned int div = 1;
> +
> +	if (!strcmp(name, "r")) {
> +		switch (cpg_mode & (MD_CK2 | MD_CK1)) {
> +		case MD_CK1 | MD_CK2:
> +			parent_name = of_clk_get_parent_name(np, 0);
> +			div = 2048;
> +			break;
> +		case MD_CK2:
> +			parent_name = of_clk_get_parent_name(np, 0);
> +			div = 1024;
> +			break;
> +		default:
> +			parent_name = of_clk_get_parent_name(np, 1);
> +			break;
> +		}
> +	} else if (!strcmp(name, "system")) {
> +		parent_name = of_clk_get_parent_name(np, 0);
> +		if (cpg_mode & MD_CK1)
> +			div = 2;
> +	} else if (!strcmp(name, "pllc0")) {
> +		/* PLLC0/1 are configurable multiplier clocks. Register them as
> +		 * fixed factor clocks for now as there's no generic multiplier
> +		 * clock implementation and we currently have no need to change
> +		 * the multiplier value.
> +		 */
> +		u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
> +		parent_name = "system";
> +		mult = ((value >> 24) & 0x7f) + 1;

STC is a 6-bits field if I'm not mistaken, the mask should thus be 0x3f.

> +	} else if (!strcmp(name, "pllc1")) {
> +		u32 value = clk_readl(cpg->reg + CPG_FRQCRA);
> +		parent_name = "system";
> +		mult = ((value >> 24) & 0x7f) + 1;

Same here.

> +		div = 2;
> +	} else {
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	return clk_register_fixed_factor(NULL, name, parent_name, 0,
> +					 mult, div);
> +}
> +
> +static void __init r8a7740_cpg_clocks_init(struct device_node *np)
> +{
> +	const struct cpg_pll_config *config;
> +	struct r8a7740_cpg *cpg;
> +	struct clk **clks;
> +	unsigned int i;
> +	int num_clks;
> +
> +	num_clks = of_property_count_strings(np, "clock-output-names");
> +	if (num_clks < 0) {
> +		pr_err("%s: failed to count clocks\n", __func__);
> +		return;
> +	}
> +
> +	cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
> +	clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
> +	if (cpg == NULL || clks == NULL) {
> +		/* We're leaking memory on purpose, there's no point in cleaning
> +		 * up as the system won't boot anyway.
> +		 */
> +		pr_err("%s: failed to allocate cpg\n", __func__);

kzalloc() prints an OOM message on error, there's no need to duplicate it 
here.

> +		return;
> +	}
> +
> +	spin_lock_init(&cpg->lock);
> +
> +	cpg->data.clks = clks;
> +	cpg->data.clk_num = num_clks;
> +
> +	cpg->reg = of_iomap(np, 0);
> +	if (WARN_ON(cpg->reg == NULL))
> +		return;
> +
> +	for (i = 0; i < num_clks; ++i) {
> +		const char *name;
> +		struct clk *clk;
> +
> +		of_property_read_string_index(np, "clock-output-names", i,
> +					      &name);
> +
> +		clk = r8a7740_cpg_register_clock(np, cpg, config, name);
> +
> +		if (IS_ERR(clk))
> +			pr_err("%s: failed to register %s %s clock (%ld)\n",
> +			       __func__, np->name, name, PTR_ERR(clk));
> +		else
> +			cpg->data.clks[i] = clk;
> +	}
> +
> +	of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
> +}
> +CLK_OF_DECLARE(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks",
> +	       r8a7740_cpg_clocks_init);
> +
> +void __init r8a7740_clocks_init(u32 mode)
> +{
> +	cpg_mode = mode;
> +}
> diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
> index fc67f56..4e5ccca 100644
> --- a/drivers/sh/Makefile
> +++ b/drivers/sh/Makefile
> @@ -3,7 +3,7 @@
>  #
>  obj-y	:= intc/
> 
> -obj-$(CONFIG_HAVE_CLK)		+= clk/
> +#obj-$(CONFIG_HAVE_CLK)		+= clk/

I assume this is the build system hack I should ignore :-)

>  obj-$(CONFIG_MAPLE)		+= maple/
>  obj-$(CONFIG_SUPERHYWAY)	+= superhyway/
> 
> diff --git a/include/dt-bindings/clock/r8a7740-clock.h
> b/include/dt-bindings/clock/r8a7740-clock.h new file mode 100644
> index 0000000..c71ca26
> --- /dev/null
> +++ b/include/dt-bindings/clock/r8a7740-clock.h
> @@ -0,0 +1,61 @@
> +/*
> + * Copyright 2014 Ulrich Hecht
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __DT_BINDINGS_CLOCK_R8A7740_H__
> +#define __DT_BINDINGS_CLOCK_R8A7740_H__
> +
> +/* CPG */
> +#define R8A7740_CLK_SYSTEM	0
> +#define R8A7740_CLK_PLLC0	1
> +#define R8A7740_CLK_PLLC1	2
> +#define R8A7740_CLK_PLLC2	3
> +#define R8A7740_CLK_R		4
> +
> +/* MSTP1 */
> +#define R8A7740_CLK_CEU21	28
> +#define R8A7740_CLK_CEU20	27
> +#define R8A7740_CLK_TMU0	25
> +#define R8A7740_CLK_LCDC1	17
> +#define R8A7740_CLK_IIC0	16
> +#define R8A7740_CLK_TMU1	11
> +#define R8A7740_CLK_LCDC0	0
> +
> +/* MSTP2 */
> +#define R8A7740_CLK_SCIFA6	30
> +#define R8A7740_CLK_SCIFA7	22
> +#define R8A7740_CLK_DMAC1	18
> +#define R8A7740_CLK_DMAC2	17
> +#define R8A7740_CLK_DMAC3	16
> +#define R8A7740_CLK_USBDMAC	14
> +#define R8A7740_CLK_SCIFA5	7
> +#define R8A7740_CLK_SCIFB	6
> +#define R8A7740_CLK_SCIFA0	4
> +#define R8A7740_CLK_SCIFA1	3
> +#define R8A7740_CLK_SCIFA2	2
> +#define R8A7740_CLK_SCIFA3	1
> +#define R8A7740_CLK_SCIFA4	0
> +
> +/* MSTP3 */
> +#define R8A7740_CLK_CMT10	29

This should be CMT1.

> +#define R8A7740_CLK_FSI		28
> +#define R8A7740_CLK_IIC1	23
> +#define R8A7740_CLK_USBF	20
> +#define R8A7740_CLK_SDHI0	14
> +#define R8A7740_CLK_SDHI1	13
> +#define R8A7740_CLK_MMC		12
> +#define R8A7740_CLK_GETHER	9
> +#define R8A7740_CLK_TPU0	4
> +
> +/* MSTP4 */
> +#define R8A7740_CLK_USBHOST	16

Should we call this USBH to match the datasheet ?

> +#define R8A7740_CLK_SDHI2	15
> +#define R8A7740_CLK_USBFUNC	7
> +#define R8A7740_CLK_USBPHY	6
> +
> +#endif /* __DT_BINDINGS_CLOCK_R8A7740_H__ */
Ulrich Hecht April 22, 2014, 1:19 p.m. UTC | #2
Hi!

On Wed, Apr 9, 2014 at 3:30 PM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Thank you for the patch.

And thank you for your insights.

> Given that the goal is to get rid of arch/arm/mach-* at some point, I believe
> it would make sense to drop r8a7740_clocks_init()

Further research has revealed that the mode bits of the r8a7740 cannot
be read from the inside at all, so we have to hardcode it in the board
file anyway, making r8a7740_clocks_init() unnecessary.

> The extal1_clk frequency is board-dependent, I would specify it in DT board
> files instead.
> I think (but might be wrong) that extal2 is optional. In that case maybe we
> should set the frequency to 0 here and overwrite it in DT board files for
> boards that supply the clock.

OK.

> The SUB divider actually supplies two clocks, sub1 and sub2, that have the
> same frequency but can be individually enabled/disabled.

I guess those can be treated like MSTP clocks, with sub as the parent.
I suppose there should be a generic "gated clock"...

> Other clocks that you
> don't support yet share that characteristic, and even have sub-dividers (for
> the HDMI clocks instead).

The HDMI clocks actually seem to be the only ones with that feature,
so I'd hide them in cpg_clocks together with the other weirdo stuff.
(There seem to be a lot of clocks on other SoCs as well that vaguely
resemble DIV6 clocks, but are not really compatible in a manner useful
for abstraction.)

> The sub clocks also have a selectable parent. Have
> you thought about how you would like to implement that ?

That'll be dealt with by the "renesas,src-shift" and
"renesas,src-width" properties.

> This should be R8A7740_CLK_CMT1.

OK.

>> +#include <linux/math64.h>
>
> I don't think this header is needed.

No, it isn't.

>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/spinlock.h>
>> +#include <mach/r8a7740.h>
>
> If I'm not mistaken you're including mach/r8a7740.h for the MD_CK* definitions
> only. As we're trying to get rid of the mach/ headers, what about using BIT()
> directly instead ?

OK.

>> +             u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
>> +             parent_name = "system";
>> +             mult = ((value >> 24) & 0x7f) + 1;
>
> STC is a 6-bits field if I'm not mistaken, the mask should thus be 0x3f.

My docs say that as well, but the legacy clock code doesn't agree, and
neither does reality: When I set the mask to 0x3f, the clocks are
wrong and the serial console prints a lot of garbage, so I'll leave it
as is.

>> +     cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
>> +     clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
>> +     if (cpg == NULL || clks == NULL) {
>> +             /* We're leaking memory on purpose, there's no point in cleaning
>> +              * up as the system won't boot anyway.
>> +              */
>> +             pr_err("%s: failed to allocate cpg\n", __func__);
>
> kzalloc() prints an OOM message on error, there's no need to duplicate it
> here.

OK.

>> +/* MSTP4 */
>> +#define R8A7740_CLK_USBHOST  16
>
> Should we call this USBH to match the datasheet ?

I'm not particular. :)

I'll post an updated patch next.

CU
Uli
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Laurent Pinchart April 23, 2014, 1:50 p.m. UTC | #3
Hi Ulrich,

On Tuesday 22 April 2014 15:19:15 Ulrich Hecht wrote:
> Hi!
> 
> On Wed, Apr 9, 2014 at 3:30 PM, Laurent Pinchart wrote:
> > Thank you for the patch.
> 
> And thank you for your insights.
> 
> > Given that the goal is to get rid of arch/arm/mach-* at some point, I
> > believe it would make sense to drop r8a7740_clocks_init()
> 
> Further research has revealed that the mode bits of the r8a7740 cannot
> be read from the inside at all,

Ouch. 

> so we have to hardcode it in the board file anyway, making
> r8a7740_clocks_init() unnecessary.

I've been wondering whether the driver couldn't be doing without knowledge of 
the mode pins at all. MD_CK1 seems to be needed, but let me share my reasoning 
in case I've missed something that would allow the driver to operate without 
knowing the MD_CK1 value.

MD_CK0 selects whether the board uses a direct clock input or a crystal 
oscillator. It only controls a multiplexer that routes the XTAL1 pin or the 
crystal oscillation circuit output (connected to the XTAL1 and EXTAL1 pins) to 
the system clock. It thus has no influence on the system clock frequency or 
parent, and isn't needed by the CPG driver (your patch set doesn't use the 
bit).

MD_CK2 selects whether the R clock is derived from the system clock or from 
the optional clock source connected to the EXTALR input. We could control the 
R clock parent based on the fact that the CPG DT node has or has no EXTALR 
clock parent specified.

MD_CK1 controls the XTAL1 /2 divisor. When using the restricted external clock 
frequency range, the XTAL1 frequency must be between 24MHz and 26.67MHz for 
MD_CK1 = 0 (no division), and between 48 MHz and 50 MHz for MD_CK1 = 1 (divide 
by 2). We could thus infer the MD_CK1 settings based on the external clock 
frequency. However, when using the full external clock frequency ranges, 
that's not possible anymore as the ranges overlap. I thus don't see a good way 
to avoid explicit knowledge of MD_CK1, but I might have overlooked something.

> > The extal1_clk frequency is board-dependent, I would specify it in DT
> > board files instead. I think (but might be wrong) that extal2 is optional.
> > In that case maybe we should set the frequency to 0 here and overwrite it
> > in DT board files for boards that supply the clock.
> 
> OK.
> 
> > The SUB divider actually supplies two clocks, sub1 and sub2, that have the
> > same frequency but can be individually enabled/disabled.
> 
> I guess those can be treated like MSTP clocks, with sub as the parent.
> I suppose there should be a generic "gated clock"...

There's a clk-gate driver that exports a clk_register_gate() function, you can 
use it in the SUB clock driver.

> > Other clocks that you don't support yet share that characteristic, and
> > even have sub-dividers (for the HDMI clocks instead).
> 
> The HDMI clocks actually seem to be the only ones with that feature,
> so I'd hide them in cpg_clocks together with the other weirdo stuff.
> (There seem to be a lot of clocks on other SoCs as well that vaguely
> resemble DIV6 clocks, but are not really compatible in a manner useful
> for abstraction.)

Yes, there's lot of small differences that make implementations more painful 
than they should be :-/ It's not a huge issue though, just a shame that we 
can't share more code.

> > The sub clocks also have a selectable parent. Have you thought about how
> > you would like to implement that ?
> 
> That'll be dealt with by the "renesas,src-shift" and
> "renesas,src-width" properties.
> 
> > This should be R8A7740_CLK_CMT1.
> 
> OK.
> 
> >> +#include <linux/math64.h>
> > 
> > I don't think this header is needed.
> 
> No, it isn't.
> 
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/spinlock.h>
> >> +#include <mach/r8a7740.h>
> > 
> > If I'm not mistaken you're including mach/r8a7740.h for the MD_CK*
> > definitions only. As we're trying to get rid of the mach/ headers, what
> > about using BIT() directly instead ?
> 
> OK.
> 
> >> +             u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
> >> +             parent_name = "system";
> >> +             mult = ((value >> 24) & 0x7f) + 1;
> > 
> > STC is a 6-bits field if I'm not mistaken, the mask should thus be 0x3f.
> 
> My docs say that as well, but the legacy clock code doesn't agree, and
> neither does reality: When I set the mask to 0x3f, the clocks are
> wrong and the serial console prints a lot of garbage, so I'll leave it
> as is.

Is bit 30 set then ? What about bit 31 ?

> >> +     cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
> >> +     clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
> >> +     if (cpg == NULL || clks == NULL) {
> >> +             /* We're leaking memory on purpose, there's no point in
> >> cleaning
> >> +              * up as the system won't boot anyway.
> >> +              */
> >> +             pr_err("%s: failed to allocate cpg\n", __func__);
> > 
> > kzalloc() prints an OOM message on error, there's no need to duplicate it
> > here.
> 
> OK.
> 
> >> +/* MSTP4 */
> >> +#define R8A7740_CLK_USBHOST  16
> > 
> > Should we call this USBH to match the datasheet ?
> 
> I'm not particular. :)
> 
> I'll post an updated patch next.
diff mbox

Patch

diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi
index 9f65986..37babce 100644
--- a/arch/arm/boot/dts/r8a7740.dtsi
+++ b/arch/arm/boot/dts/r8a7740.dtsi
@@ -10,6 +10,7 @@ 
 
 /include/ "skeleton.dtsi"
 
+#include <dt-bindings/clock/r8a7740-clock.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
 / {
@@ -226,4 +227,82 @@ 
 		interrupts = <0 9 0x4>;
 		status = "disabled";
 	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/* External root clock */
+		extalr_clk: extalr_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <32768>;
+			clock-output-names = "extalr";
+		};
+		extal1_clk: extal1_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <25000000>;
+			clock-output-names = "extal1";
+		};
+		extal2_clk: extal2_clk {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <48000000>;
+			clock-output-names = "extal2";
+		};
+		/* Special CPG clocks */
+		cpg_clocks: cpg_clocks@e6150000 {
+			compatible = "renesas,r8a7740-cpg-clocks";
+			reg = <0xe6150000 0x10000>;
+			clocks = <&extal1_clk>, <&extalr_clk>;
+			#clock-cells = <1>;
+			clock-output-names = "system", "pllc0", "pllc1",
+					     "pllc2", "r";
+		};
+
+		/* Variable factor clocks (DIV6) */
+		sub_clk: sub_clk@e6150080 {
+			compatible = "renesas,r8a7740-div6-clock", "renesas,cpg-div6-clock";
+			reg = <0xe6150080 4>;
+			clocks = <&pllc1_div2_clk>;
+			#clock-cells = <0>;
+			clock-output-names = "sub";
+		};
+
+		/* Fixed factor clocks */
+		pllc1_div2_clk: pllc1_div2_clk {
+			compatible = "fixed-factor-clock";
+			clocks = <&cpg_clocks R8A7740_CLK_PLLC1>;
+			#clock-cells = <0>;
+			clock-div = <2>;
+			clock-mult = <1>;
+			clock-output-names = "pllc1_div2";
+		};
+
+		/* Gate clocks */
+		mstp2_clks: mstp2_clks@e6150138 {
+			compatible = "renesas,r8a7740-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0xe6150138 4>, <0xe6150040 4>;
+			clocks = <&sub_clk>;
+			#clock-cells = <1>;
+			renesas,clock-indices = <
+				R8A7740_CLK_SCIFA1
+			>;
+			clock-output-names =
+				"scifa1";
+		};
+		mstp3_clks: mstp3_clks@e615013c {
+			compatible = "renesas,r8a7740-mstp-clocks", "renesas,cpg-mstp-clocks";
+			reg = <0xe615013c 4>, <0xe6150048 4>;
+			clocks = <&cpg_clocks R8A7740_CLK_R>;
+			#clock-cells = <1>;
+			renesas,clock-indices = <
+				R8A7740_CLK_CMT10
+			>;
+			clock-output-names =
+				"cmt10";
+		};
+	};
 };
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 75ccebf..94a3948 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -91,7 +91,7 @@  config ARCH_R8A7740
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARM_GIC
 	select CPU_V7
-	select SH_CLK_CPG
+	select COMMON_CLK
 	select RENESAS_INTC_IRQPIN
 
 config ARCH_R8A7778
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva-reference.c b/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
index 57d1a78..e725cf5 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva-reference.c
@@ -24,6 +24,7 @@ 
 #include <linux/kernel.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
+#include <mach/clock.h>
 #include <mach/common.h>
 #include <mach/r8a7740.h>
 #include <asm/mach/arch.h>
@@ -153,20 +154,23 @@  clock_error:
 		clk_put(fsibck);
 }
 
+static const struct clk_name clk_names[] __initconst = {
+	{ "cmt10", NULL, "sh_cmt.10" },
+	{ "scifa1", NULL, "sh-sci.1" },
+};
+
 /*
  * board init
  */
 static void __init eva_init(void)
 {
-	r8a7740_clock_init(MD_CK0 | MD_CK2);
-	eva_clock_init();
-
 	r8a7740_meram_workaround();
 
 #ifdef CONFIG_CACHE_L2X0
 	/* Early BRESP enable, Shared attribute override enable, 32K*8way */
 	l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff);
 #endif
+	shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false);
 
 	r8a7740_add_standard_devices_dt();
 
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 8f3c681..1bde7f7 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -887,8 +887,10 @@  void __init r8a7740_add_standard_devices_dt(void)
 	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
+extern void __init r8a7740_clocks_init(u32 mode);
 void __init r8a7740_init_delay(void)
 {
+	r8a7740_clocks_init(MD_CK0 | MD_CK2);
 	shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */
 };
 
@@ -924,7 +926,6 @@  void __init r8a7740_init_irq_of(void)
 
 static void __init r8a7740_generic_init(void)
 {
-	r8a7740_clock_init(0);
 	r8a7740_add_standard_devices_dt();
 }
 
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index a367a98..9a11312 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -39,6 +39,7 @@  obj-$(CONFIG_ARCH_MXS)			+= mxs/
 obj-$(CONFIG_COMMON_CLK_QCOM)		+= qcom/
 obj-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip/
 obj-$(CONFIG_PLAT_SAMSUNG)		+= samsung/
+obj-$(CONFIG_ARCH_R8A7740)		+= shmobile/
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= shmobile/
 obj-$(CONFIG_ARCH_SIRF)			+= sirf/
 obj-$(CONFIG_ARCH_SOCFPGA)		+= socfpga/
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 9ecef14..a6973f9 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,7 +1,9 @@ 
 obj-$(CONFIG_ARCH_EMEV2)		+= clk-emev2.o
 obj-$(CONFIG_ARCH_R8A7790)		+= clk-rcar-gen2.o
 obj-$(CONFIG_ARCH_R8A7791)		+= clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_R8A7740)		+= clk-r8a7740.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-div6.o
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)	+= clk-mstp.o
+obj-$(CONFIG_ARCH_R8A7740)	+= clk-mstp.o clk-div6.o
 # for emply built-in.o
 obj-n	:= dummy
diff --git a/drivers/clk/shmobile/clk-r8a7740.c b/drivers/clk/shmobile/clk-r8a7740.c
new file mode 100644
index 0000000..4d9dcba
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a7740.c
@@ -0,0 +1,143 @@ 
+/*
+ * r8a7740 Core CPG Clocks
+ *
+ * Copyright (C) 2014  Ulrich Hecht
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+#include <mach/r8a7740.h>
+
+struct r8a7740_cpg {
+	struct clk_onecell_data data;
+	spinlock_t lock;
+	void __iomem *reg;
+};
+
+#define CPG_FRQCRA			0
+#define CPG_FRQCRC			0xe0
+#define CPG_PLLC01CR			0x28
+
+struct cpg_pll_config {
+};
+
+static u32 cpg_mode __initdata;
+
+static struct clk * __init
+r8a7740_cpg_register_clock(struct device_node *np, struct r8a7740_cpg *cpg,
+			     const struct cpg_pll_config *config,
+			     const char *name)
+{
+	const char *parent_name;
+	unsigned int mult = 1;
+	unsigned int div = 1;
+
+	if (!strcmp(name, "r")) {
+		switch (cpg_mode & (MD_CK2 | MD_CK1)) {
+		case MD_CK1 | MD_CK2:
+			parent_name = of_clk_get_parent_name(np, 0);
+			div = 2048;
+			break;
+		case MD_CK2:
+			parent_name = of_clk_get_parent_name(np, 0);
+			div = 1024;
+			break;
+		default:
+			parent_name = of_clk_get_parent_name(np, 1);
+			break;
+		}
+	} else if (!strcmp(name, "system")) {
+		parent_name = of_clk_get_parent_name(np, 0);
+		if (cpg_mode & MD_CK1)
+			div = 2;
+	} else if (!strcmp(name, "pllc0")) {
+		/* PLLC0/1 are configurable multiplier clocks. Register them as
+		 * fixed factor clocks for now as there's no generic multiplier
+		 * clock implementation and we currently have no need to change
+		 * the multiplier value.
+		 */
+		u32 value = clk_readl(cpg->reg + CPG_FRQCRC);
+		parent_name = "system";
+		mult = ((value >> 24) & 0x7f) + 1;
+	} else if (!strcmp(name, "pllc1")) {
+		u32 value = clk_readl(cpg->reg + CPG_FRQCRA);
+		parent_name = "system";
+		mult = ((value >> 24) & 0x7f) + 1;
+		div = 2;
+	} else {
+		return ERR_PTR(-EINVAL);
+	}
+
+	return clk_register_fixed_factor(NULL, name, parent_name, 0,
+					 mult, div);
+}
+
+static void __init r8a7740_cpg_clocks_init(struct device_node *np)
+{
+	const struct cpg_pll_config *config;
+	struct r8a7740_cpg *cpg;
+	struct clk **clks;
+	unsigned int i;
+	int num_clks;
+
+	num_clks = of_property_count_strings(np, "clock-output-names");
+	if (num_clks < 0) {
+		pr_err("%s: failed to count clocks\n", __func__);
+		return;
+	}
+
+	cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+	clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL);
+	if (cpg == NULL || clks == NULL) {
+		/* We're leaking memory on purpose, there's no point in cleaning
+		 * up as the system won't boot anyway.
+		 */
+		pr_err("%s: failed to allocate cpg\n", __func__);
+		return;
+	}
+
+	spin_lock_init(&cpg->lock);
+
+	cpg->data.clks = clks;
+	cpg->data.clk_num = num_clks;
+
+	cpg->reg = of_iomap(np, 0);
+	if (WARN_ON(cpg->reg == NULL))
+		return;
+
+	for (i = 0; i < num_clks; ++i) {
+		const char *name;
+		struct clk *clk;
+
+		of_property_read_string_index(np, "clock-output-names", i,
+					      &name);
+
+		clk = r8a7740_cpg_register_clock(np, cpg, config, name);
+
+		if (IS_ERR(clk))
+			pr_err("%s: failed to register %s %s clock (%ld)\n",
+			       __func__, np->name, name, PTR_ERR(clk));
+		else
+			cpg->data.clks[i] = clk;
+	}
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(r8a7740_cpg_clks, "renesas,r8a7740-cpg-clocks",
+	       r8a7740_cpg_clocks_init);
+
+void __init r8a7740_clocks_init(u32 mode)
+{
+	cpg_mode = mode;
+}
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index fc67f56..4e5ccca 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -3,7 +3,7 @@ 
 #
 obj-y	:= intc/
 
-obj-$(CONFIG_HAVE_CLK)		+= clk/
+#obj-$(CONFIG_HAVE_CLK)		+= clk/
 obj-$(CONFIG_MAPLE)		+= maple/
 obj-$(CONFIG_SUPERHYWAY)	+= superhyway/
 
diff --git a/include/dt-bindings/clock/r8a7740-clock.h b/include/dt-bindings/clock/r8a7740-clock.h
new file mode 100644
index 0000000..c71ca26
--- /dev/null
+++ b/include/dt-bindings/clock/r8a7740-clock.h
@@ -0,0 +1,61 @@ 
+/*
+ * Copyright 2014 Ulrich Hecht
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_R8A7740_H__
+#define __DT_BINDINGS_CLOCK_R8A7740_H__
+
+/* CPG */
+#define R8A7740_CLK_SYSTEM	0
+#define R8A7740_CLK_PLLC0	1
+#define R8A7740_CLK_PLLC1	2
+#define R8A7740_CLK_PLLC2	3
+#define R8A7740_CLK_R		4
+
+/* MSTP1 */
+#define R8A7740_CLK_CEU21	28
+#define R8A7740_CLK_CEU20	27
+#define R8A7740_CLK_TMU0	25
+#define R8A7740_CLK_LCDC1	17
+#define R8A7740_CLK_IIC0	16
+#define R8A7740_CLK_TMU1	11
+#define R8A7740_CLK_LCDC0	0
+
+/* MSTP2 */
+#define R8A7740_CLK_SCIFA6	30
+#define R8A7740_CLK_SCIFA7	22
+#define R8A7740_CLK_DMAC1	18
+#define R8A7740_CLK_DMAC2	17
+#define R8A7740_CLK_DMAC3	16
+#define R8A7740_CLK_USBDMAC	14
+#define R8A7740_CLK_SCIFA5	7
+#define R8A7740_CLK_SCIFB	6
+#define R8A7740_CLK_SCIFA0	4
+#define R8A7740_CLK_SCIFA1	3
+#define R8A7740_CLK_SCIFA2	2
+#define R8A7740_CLK_SCIFA3	1
+#define R8A7740_CLK_SCIFA4	0
+
+/* MSTP3 */
+#define R8A7740_CLK_CMT10	29
+#define R8A7740_CLK_FSI		28
+#define R8A7740_CLK_IIC1	23
+#define R8A7740_CLK_USBF	20
+#define R8A7740_CLK_SDHI0	14
+#define R8A7740_CLK_SDHI1	13
+#define R8A7740_CLK_MMC		12
+#define R8A7740_CLK_GETHER	9
+#define R8A7740_CLK_TPU0	4
+
+/* MSTP4 */
+#define R8A7740_CLK_USBHOST	16
+#define R8A7740_CLK_SDHI2	15
+#define R8A7740_CLK_USBFUNC	7
+#define R8A7740_CLK_USBPHY	6
+
+#endif /* __DT_BINDINGS_CLOCK_R8A7740_H__ */