From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: linux-sh@vger.kernel.org
Subject: Re: [RFC] ARM: shmobile: minimal r8a7740 common clock framework implementation
Date: Wed, 09 Apr 2014 13:30:55 +0000 [thread overview]
Message-ID: <1934179.TFCh61MOWi@avalon> (raw)
In-Reply-To: <1397041484-12552-1-git-send-email-ulrich.hecht@gmail.com>
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/focus13901
> 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__ */
--
Regards,
Laurent Pinchart
next prev parent reply other threads:[~2014-04-09 13:30 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-09 11:04 [RFC] ARM: shmobile: minimal r8a7740 common clock framework implementation Ulrich Hecht
2014-04-09 13:30 ` Laurent Pinchart [this message]
2014-04-22 13:19 ` Ulrich Hecht
2014-04-23 13:50 ` Laurent Pinchart
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=1934179.TFCh61MOWi@avalon \
--to=laurent.pinchart@ideasonboard.com \
--cc=linux-sh@vger.kernel.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).