[PATCH 1/7] clk: mvebu: add mvebu core clocks.

Gregory CLEMENT gregory.clement at free-electrons.com
Fri Nov 16 07:52:44 EST 2012


Hi Andrew,

On 11/15/2012 10:28 PM, Andrew Lunn wrote:
> From: Sebastian Hesselbarth <sebastian.hesselbarth at gmail.com>
> 
> This driver allows to provide DT clocks for core clocks found on
> Marvell Kirkwood, Dove & 370/XP SoCs. The core clock frequencies and
> ratios are determined by decoding the Sample-At-Reset registers.
> 
> Although technically correct, using a divider of 0 will lead to
> div_by_zero panic. Let's use a ratio of 0/1 instead to fail later
> with a zero clock.
> 
> Signed-off-by: Gregory CLEMENT <gregory.clement at free-electrons.com>
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth at gmail.com>
> Signed-off-by: Andrew Lunn <andrew at lunn.ch>
> ---
>  .../devicetree/bindings/clock/mvebu-core-clock.txt |   47 ++
>  drivers/clk/Kconfig                                |    2 +
>  drivers/clk/Makefile                               |    1 +
>  drivers/clk/mvebu/Kconfig                          |    3 +
>  drivers/clk/mvebu/Makefile                         |    1 +
>  drivers/clk/mvebu/clk-core.c                       |  675 ++++++++++++++++++++
>  drivers/clk/mvebu/clk-core.h                       |   18 +
>  drivers/clk/mvebu/clk.c                            |   23 +
>  include/linux/clk/mvebu.h                          |   22 +
>  9 files changed, 792 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
>  create mode 100644 drivers/clk/mvebu/Kconfig
>  create mode 100644 drivers/clk/mvebu/Makefile
>  create mode 100644 drivers/clk/mvebu/clk-core.c
>  create mode 100644 drivers/clk/mvebu/clk-core.h
>  create mode 100644 drivers/clk/mvebu/clk.c
>  create mode 100644 include/linux/clk/mvebu.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
> new file mode 100644
> index 0000000..84cfae7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
> @@ -0,0 +1,47 @@
> +* Core Clock bindings for Marvell MVEBU SoCs
> +
> +Marvell MVEBU SoCs usually allow to determine core clock frequencies by
> +reading the Sample-At-Reset (SAR) register. The core clock consumer should
> +specify the desired clock by having the clock ID in its "clocks" phandle cell.
> +
> +The following is a list of provided IDs and clock names on Kirkwood and Dove:
> + 0 = tclk   (Internal Bus clock)
> + 1 = cpuclk (CPU0 clock)
> + 2 = l2clk  (L2 Cache clock derived from CPU0 clock)
> + 3 = ddrclk (DDR controller clock derived from CPU0 clock)
> +
> +The following is a list of provided IDs and clock names on 370/XP:

You should call them Aramda 370 and Aramda XP. You do this modification
in the 2nd patch but it should be squashed in this patch.

> + 0 = tclk    (Internal Bus clock)
> + 1 = cpuclk  (CPU clock)
> + 2 = nbclk   (L2 Cache clock)
> + 3 = hclk    (DRAM control clock)
> + 4 = dramclk (DDR clock)
> +
> +Required properties:
> +- compatible : shall be one of the following:
> +	"marvell,dove-core-clocks" - for Dove SoC core clocks
> +	"marvell,kirkwood-core-clocks" - for Kirkwood SoC (except mv88f6180)
> +	"marvell,mv88f6180-core-clocks" - for Kirkwood MV88f6180 SoC
> +	"marvell,370-core-clocks" - For 370 SoC core clocks
> +	"marvell,xp-core-clocks" - For XP SoC core clocks

Same here.

> +- reg : shall be the register address of the Sample-At-Reset (SAR) register
> +- #clock-cells : from common clock binding; shall be set to 1
> +
> +Optional properties:
> +- clock-output-names : from common clock binding; allows overwrite default clock
> +	output names ("tclk", "cpuclk", "l2clk", "ddrclk")
> +
> +Example:
> +
> +core_clk: core-clocks at d0214 {
> +	compatible = "marvell,dove-core-clocks";
> +	reg = <0xd0214 0x4>;
> +	#clock-cells = <1>;
> +};
> +
> +spi0: spi at 10600 {
> +	compatible = "marvell,orion-spi";
> +	/* ... */
> +	/* get tclk from core clock provider */
> +	clocks = <&core_clk 0>;
> +};
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index bace9e9..60427c0 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -54,3 +54,5 @@ config COMMON_CLK_MAX77686
>  	  This driver supports Maxim 77686 crystal oscillator clock. 
>  
>  endmenu
> +
> +source "drivers/clk/mvebu/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 71a25b9..d0a14ae 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_PLAT_SPEAR)	+= spear/
>  obj-$(CONFIG_ARCH_U300)		+= clk-u300.o
>  obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
>  obj-$(CONFIG_ARCH_PRIMA2)	+= clk-prima2.o
> +obj-$(CONFIG_PLAT_ORION)	+= mvebu/
>  ifeq ($(CONFIG_COMMON_CLK), y)
>  obj-$(CONFIG_ARCH_MMP)		+= mmp/
>  endif
> diff --git a/drivers/clk/mvebu/Kconfig b/drivers/clk/mvebu/Kconfig
> new file mode 100644
> index 0000000..fd7bf97
> --- /dev/null
> +++ b/drivers/clk/mvebu/Kconfig
> @@ -0,0 +1,3 @@
> +config MVEBU_CLK_CORE
> +       bool
> +
> diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
> new file mode 100644
> index 0000000..de1d961
> --- /dev/null
> +++ b/drivers/clk/mvebu/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_MVEBU_CLK_CORE) 	+= clk.o clk-core.o
> diff --git a/drivers/clk/mvebu/clk-core.c b/drivers/clk/mvebu/clk-core.c
> new file mode 100644
> index 0000000..26ba835
> --- /dev/null
> +++ b/drivers/clk/mvebu/clk-core.c
> @@ -0,0 +1,675 @@
> +/*
> + * Marvell EBU clock core handling defined at reset
> + *
> + * Copyright (C) 2012 Marvell
> + *
> + * Gregory CLEMENT <gregory.clement at free-electrons.com>
> + * Sebastian Hesselbarth <sebastian.hesselbarth at gmail.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +#include <linux/kernel.h>
> +#include <linux/clk.h>
> +#include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of_address.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include "clk-core.h"
> +
> +struct core_ratio {
> +	int id;
> +	const char *name;
> +};
> +
> +struct core_clocks {
> +	u32 (*get_tclk_freq)(void __iomem *sar);
> +	u32 (*get_cpu_freq)(void __iomem *sar);
> +	void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div);
> +	const struct core_ratio *ratios;
> +	int num_ratios;
> +};
> +
> +static struct clk_onecell_data clk_data;
> +
> +static void __init mvebu_clk_core_setup(struct device_node *np,
> +				 struct core_clocks *coreclk)
> +{
> +	const char *tclk_name = "tclk";
> +	const char *cpuclk_name = "cpuclk";
> +	void __iomem *base;
> +	unsigned long rate;
> +	int n;
> +
> +	base = of_iomap(np, 0);
> +	if (WARN_ON(!base))
> +		return;
> +
> +	/*
> +	 * Allocate struct for TCLK, cpu clk, and core ratio clocks
> +	 */
> +	clk_data.clk_num = 2 + coreclk->num_ratios;
> +	clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *),
> +				GFP_KERNEL);
> +	if (WARN_ON(!clk_data.clks))
> +		return;
> +
> +	/*
> +	 * Register TCLK
> +	 */
> +	of_property_read_string_index(np, "clock-output-names", 0,
> +				      &tclk_name);
> +	rate = coreclk->get_tclk_freq(base);
> +	clk_data.clks[0] = clk_register_fixed_rate(NULL, tclk_name, NULL,
> +						   CLK_IS_ROOT, rate);
> +	WARN_ON(IS_ERR(clk_data.clks[0]));
> +
> +	/*
> +	 * Register CPU clock
> +	 */
> +	of_property_read_string_index(np, "clock-output-names", 1,
> +				      &cpuclk_name);
> +	rate = coreclk->get_cpu_freq(base);
> +	clk_data.clks[1] = clk_register_fixed_rate(NULL, cpuclk_name, NULL,
> +						   CLK_IS_ROOT, rate);
> +	WARN_ON(IS_ERR(clk_data.clks[1]));
> +
> +	/*
> +	 * Register fixed-factor clocks derived from CPU clock
> +	 */
> +	for (n = 0; n < coreclk->num_ratios; n++) {
> +		const char *rclk_name = coreclk->ratios[n].name;
> +		int mult, div;
> +
> +		of_property_read_string_index(np, "clock-output-names",
> +					      2+n, &rclk_name);
> +		coreclk->get_clk_ratio(base, coreclk->ratios[n].id,
> +				       &mult, &div);
> +		clk_data.clks[2+n] = clk_register_fixed_factor(NULL, rclk_name,
> +				       cpuclk_name, 0, mult, div);
> +		WARN_ON(IS_ERR(clk_data.clks[2+n]));
> +	};
> +
> +	/*
> +	 * SAR register isn't needed anymore
> +	 */
> +	iounmap(base);
> +
> +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> +}
> +
> +#ifdef CONFIG_MACH_ARMADA_370_XP
> +/*
> + * 370/XP Sample At Reset is a 64 bit bitfiled split in two register

Add "Armada" in front of 370/XP please.

> + * of 32 bits
> + */
> +
> +#define SARL				    0	/* Low part [0:31] */
> +#define	    SARL_AXP_PCLK_FREQ_OPT	    21
> +#define	    SARL_AXP_PCLK_FREQ_OPT_MASK	    0x7
> +#define	    SARL_A370_PCLK_FREQ_OPT	    11
> +#define	    SARL_A370_PCLK_FREQ_OPT_MASK    0xF
> +#define	    SARL_AXP_FAB_FREQ_OPT	    24
> +#define	    SARL_AXP_FAB_FREQ_OPT_MASK	    0xF
> +#define	    SARL_A370_FAB_FREQ_OPT	    15
> +#define	    SARL_A370_FAB_FREQ_OPT_MASK	    0x1F
> +#define	    SARL_A370_TCLK_FREQ_OPT	    20
> +#define	    SARL_A370_TCLK_FREQ_OPT_MASK    0x1
> +#define SARH				    4	/* High part [32:63] */
> +#define	    SARH_AXP_PCLK_FREQ_OPT	    (52-32)
> +#define	    SARH_AXP_PCLK_FREQ_OPT_MASK	    0x1
> +#define	    SARH_AXP_PCLK_FREQ_OPT_SHIFT    3
> +#define	    SARH_AXP_FAB_FREQ_OPT	    (51-32)
> +#define	    SARH_AXP_FAB_FREQ_OPT_MASK	    0x1
> +#define	    SARH_AXP_FAB_FREQ_OPT_SHIFT	    4
> +
> +static const u32 __initconst a370_tclk_frequencies[] = {

In all other part in the kernel the relatives functions to
Armada 370 or Armada XP are suffixed by armada_370 or armada_xp.
Could we do the same here for being consistent?
It will help when one wants to grep code relative to the armada
370 or the armada XP.


> +	16600000,
> +	20000000,
> +};
> +
> +static u32 __init a370_get_tclk_freq(void __iomem *sar)
Same here.

> +{
> +	u8 tclk_freq_select = 0;
> +
> +	tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) &
> +			    SARL_A370_TCLK_FREQ_OPT_MASK);
> +	return a370_tclk_frequencies[tclk_freq_select];
> +}
> +
> +static const u32 __initconst a370_cpu_frequencies[] = {
> +	400000000,
> +	533000000,
> +	667000000,
> +	800000000,
> +	1000000000,
> +	1067000000,
> +	1200000000,
> +};
> +
> +static u32 __init a370_get_cpu_freq(void __iomem *sar)
> +{
> +	u32 cpu_freq;
> +	u8 cpu_freq_select = 0;
> +
> +	cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
> +			   SARL_A370_PCLK_FREQ_OPT_MASK);
> +	if (cpu_freq_select > ARRAY_SIZE(a370_cpu_frequencies)) {
> +		pr_err("CPU freq select unsuported %d\n", cpu_freq_select);
> +		cpu_freq = 0;
> +	} else
> +		cpu_freq = a370_cpu_frequencies[cpu_freq_select];
> +
> +	return cpu_freq;
> +}
> +
> +enum { A370_XP_NBCLK, A370_XP_HCLK, A370_XP_DRAMCLK };
> +
> +static const struct core_ratio __initconst a370_xp_core_ratios[] = {
> +	{ .id = A370_XP_NBCLK,	 .name = "nbclk" },
> +	{ .id = A370_XP_HCLK,	 .name = "hclk" },
> +	{ .id = A370_XP_DRAMCLK, .name = "dramclk" },
> +};
> +
> +static const int __initconst a370_xp_nbclk_ratios[32][2] = {
> +	{0, 1}, {1, 2}, {2, 2}, {2, 2},
> +	{1, 2}, {1, 2}, {1, 1}, {2, 3},
> +	{0, 1}, {1, 2}, {2, 4}, {0, 1},
> +	{1, 2}, {0, 1}, {0, 1}, {2, 2},
> +	{0, 1}, {0, 1}, {0, 1}, {1, 1},
> +	{2, 3}, {0, 1}, {0, 1}, {0, 1},
> +	{0, 1}, {0, 1}, {0, 1}, {1, 1},
> +	{0, 1}, {0, 1}, {0, 1}, {0, 1},
> +};
> +
> +static const int __initconst a370_xp_hclk_ratios[32][2] = {
> +	{0, 1}, {1, 2}, {2, 6}, {2, 3},
> +	{1, 3}, {1, 4}, {1, 2}, {2, 6},
> +	{0, 1}, {1, 6}, {2, 10}, {0, 1},
> +	{1, 4}, {0, 1}, {0, 1}, {2, 5},
> +	{0, 1}, {0, 1}, {0, 1}, {1, 2},
> +	{2, 6}, {0, 1}, {0, 1}, {0, 1},
> +	{0, 1}, {0, 1}, {0, 1}, {1, 1},
> +	{0, 1}, {0, 1}, {0, 1}, {0, 1},
> +};
> +
> +static const int __initconst a370_xp_dramclk_ratios[32][2] = {
> +	{0, 1}, {1, 2}, {2, 3}, {2, 3},
> +	{1, 3}, {1, 2}, {1, 2}, {2, 6},
> +	{0, 1}, {1, 3}, {2, 5}, {0, 1},
> +	{1, 4}, {0, 1}, {0, 1}, {2, 5},
> +	{0, 1}, {0, 1}, {0, 1}, {1, 1},
> +	{2, 3}, {0, 1}, {0, 1}, {0, 1},
> +	{0, 1}, {0, 1}, {0, 1}, {1, 1},
> +	{0, 1}, {0, 1}, {0, 1}, {0, 1},
> +};
> +
> +static void __init a370_xp_get_clk_ratio(u32 opt,
> +	void __iomem *sar, int id, int *mult, int *div)
> +{
> +	switch (id) {
> +	case A370_XP_NBCLK:
> +		*mult = a370_xp_nbclk_ratios[opt][0];
> +		*div = a370_xp_nbclk_ratios[opt][1];
> +		break;
> +	case A370_XP_HCLK:
> +		*mult = a370_xp_hclk_ratios[opt][0];
> +		*div = a370_xp_hclk_ratios[opt][1];
> +		break;
> +	case A370_XP_DRAMCLK:
> +		*mult = a370_xp_dramclk_ratios[opt][0];
> +		*div = a370_xp_dramclk_ratios[opt][1];
> +		break;
> +	}
> +}
> +
> +static void __init a370_get_clk_ratio(
> +	void __iomem *sar, int id, int *mult, int *div)
> +{
> +	u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
> +		SARL_A370_FAB_FREQ_OPT_MASK);
> +
> +	a370_xp_get_clk_ratio(opt, sar, id, mult, div);
> +}
> +
> +
> +static const struct core_clocks a370_core_clocks = {
> +	.get_tclk_freq = a370_get_tclk_freq,
> +	.get_cpu_freq = a370_get_cpu_freq,
> +	.get_clk_ratio = a370_get_clk_ratio,
> +	.ratios = a370_xp_core_ratios,
> +	.num_ratios = ARRAY_SIZE(a370_xp_core_ratios),
> +};
> +
> +static const u32 __initconst xp_cpu_frequencies[] = {

And for Armada XP even the 'a' disappeared!

Gregory



More information about the linux-arm-kernel mailing list