[PATCH 2/2] ARM: vexpress: Initial common clock support
Jon Medhurst (Tixy)
tixy at linaro.org
Wed Jun 13 06:07:31 EDT 2012
On Fri, 2012-06-08 at 13:50 +0100, Pawel Moll wrote:
> This patch makes Versatile Express use the common clock framework
> instead of the plat-versatile implementation (which remains intact
> for mach-versatile and mach-realview sake).
>
> It defines clock provider for VE's OSCs (clock generators) and
> registers all required fixed and variable clock sources (for both
> motherboard and core tile).
>
> Signed-off-by: Pawel Moll <pawel.moll at arm.com>
Tested-by: Jon Medhurst <tixy at linaro.org>
(Tested on CA9 non-device tree and CA15-TC1 with device tree.)
> ---
> arch/arm/Kconfig | 2 +-
> arch/arm/mach-vexpress/ct-ca9x4.c | 55 +----
> arch/arm/mach-vexpress/include/mach/clkdev.h | 15 --
> arch/arm/mach-vexpress/include/mach/motherboard.h | 20 ++
> arch/arm/mach-vexpress/v2m.c | 253 +++++++++------------
> arch/arm/plat-versatile/Kconfig | 5 +
> arch/arm/plat-versatile/Makefile | 2 +-
> 7 files changed, 150 insertions(+), 202 deletions(-)
> delete mode 100644 arch/arm/mach-vexpress/include/mach/clkdev.h
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 84449dd..6f3370e 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -306,7 +306,7 @@ config ARCH_VEXPRESS
> select ARM_AMBA
> select ARM_TIMER_SP804
> select CLKDEV_LOOKUP
> - select HAVE_MACH_CLKDEV
> + select COMMON_CLK
> select GENERIC_CLOCKEVENTS
> select HAVE_CLK
> select HAVE_PATA_PLATFORM
> diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
> index 11cb248..3ef3fda 100644
> --- a/arch/arm/mach-vexpress/ct-ca9x4.c
> +++ b/arch/arm/mach-vexpress/ct-ca9x4.c
> @@ -111,48 +111,22 @@ static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
> &gpio_device,
> };
>
> +static struct v2m_osc ct_osc1 = {
> + .osc = 1,
> + .rate_min = 10000000,
> + .rate_max = 80000000,
> + .rate_default = 23750000,
> +};
>
> -static long ct_round(struct clk *clk, unsigned long rate)
> -{
> - return rate;
> -}
> -
> -static int ct_set(struct clk *clk, unsigned long rate)
> +static void __init ct_ca9x4_init_clk(void)
> {
> - u32 site = v2m_get_master_site();
> + struct clk *clk;
>
> - return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE(site) | 1, rate);
> + ct_osc1.site = v2m_get_master_site();
> + clk = v2m_osc_register("ct:osc1", &ct_osc1);
> + clk_register_clkdev(clk, NULL, "ct:clcd");
> }
>
> -static const struct clk_ops osc1_clk_ops = {
> - .round = ct_round,
> - .set = ct_set,
> -};
> -
> -static struct clk osc1_clk = {
> - .ops = &osc1_clk_ops,
> - .rate = 24000000,
> -};
> -
> -static struct clk ct_sp804_clk = {
> - .rate = 1000000,
> -};
> -
> -static struct clk_lookup lookups[] = {
> - { /* CLCD */
> - .dev_id = "ct:clcd",
> - .clk = &osc1_clk,
> - }, { /* SP804 timers */
> - .dev_id = "sp804",
> - .con_id = "ct-timer0",
> - .clk = &ct_sp804_clk,
> - }, { /* SP804 timers */
> - .dev_id = "sp804",
> - .con_id = "ct-timer1",
> - .clk = &ct_sp804_clk,
> - },
> -};
> -
> static struct resource pmu_resources[] = {
> [0] = {
> .start = IRQ_CT_CA9X4_PMU_CPU0,
> @@ -183,11 +157,6 @@ static struct platform_device pmu_device = {
> .resource = pmu_resources,
> };
>
> -static void __init ct_ca9x4_init_early(void)
> -{
> - clkdev_add_table(lookups, ARRAY_SIZE(lookups));
> -}
> -
> static void __init ct_ca9x4_init(void)
> {
> int i;
> @@ -243,8 +212,8 @@ struct ct_desc ct_ca9x4_desc __initdata = {
> .id = V2M_CT_ID_CA9,
> .name = "CA9x4",
> .map_io = ct_ca9x4_map_io,
> - .init_early = ct_ca9x4_init_early,
> .init_irq = ct_ca9x4_init_irq,
> + .init_clk = ct_ca9x4_init_clk,
> .init_tile = ct_ca9x4_init,
> #ifdef CONFIG_SMP
> .init_cpu_map = ct_ca9x4_init_cpu_map,
> diff --git a/arch/arm/mach-vexpress/include/mach/clkdev.h b/arch/arm/mach-vexpress/include/mach/clkdev.h
> deleted file mode 100644
> index 3f8307d..0000000
> --- a/arch/arm/mach-vexpress/include/mach/clkdev.h
> +++ /dev/null
> @@ -1,15 +0,0 @@
> -#ifndef __ASM_MACH_CLKDEV_H
> -#define __ASM_MACH_CLKDEV_H
> -
> -#include <plat/clock.h>
> -
> -struct clk {
> - const struct clk_ops *ops;
> - unsigned long rate;
> - const struct icst_params *params;
> -};
> -
> -#define __clk_get(clk) ({ 1; })
> -#define __clk_put(clk) do { } while (0)
> -
> -#endif
> diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h
> index f004ec9..2762263 100644
> --- a/arch/arm/mach-vexpress/include/mach/motherboard.h
> +++ b/arch/arm/mach-vexpress/include/mach/motherboard.h
> @@ -1,6 +1,8 @@
> #ifndef __MACH_MOTHERBOARD_H
> #define __MACH_MOTHERBOARD_H
>
> +#include <linux/clk-provider.h>
> +
> /*
> * Physical addresses, offset from V2M_PA_CS0-3
> */
> @@ -138,6 +140,7 @@ struct ct_desc {
> void (*map_io)(void);
> void (*init_early)(void);
> void (*init_irq)(void);
> + void (*init_clk)(void);
> void (*init_tile)(void);
> #ifdef CONFIG_SMP
> void (*init_cpu_map)(void);
> @@ -147,4 +150,21 @@ struct ct_desc {
>
> extern struct ct_desc *ct_desc;
>
> +/*
> + * OSC clock provider
> + */
> +struct v2m_osc {
> + struct clk_hw hw;
> + u8 site; /* 0 = motherboard, 1 = site 1, 2 = site 2 */
> + u8 stack; /* board stack position */
> + u16 osc;
> + unsigned long rate_min;
> + unsigned long rate_max;
> + unsigned long rate_default;
> +};
> +
> +#define to_v2m_osc(osc) container_of(osc, struct v2m_osc, hw)
> +
> +struct clk *v2m_osc_register(const char *name, struct v2m_osc *osc);
> +
> #endif
> diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
> index aa6f9a6..e1e2415 100644
> --- a/arch/arm/mach-vexpress/v2m.c
> +++ b/arch/arm/mach-vexpress/v2m.c
> @@ -16,6 +16,7 @@
> #include <linux/spinlock.h>
> #include <linux/usb/isp1760.h>
> #include <linux/clkdev.h>
> +#include <linux/clk-provider.h>
> #include <linux/mtd/physmap.h>
>
> #include <asm/arch_timer.h>
> @@ -81,16 +82,6 @@ static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
> sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
> }
>
> -static void __init v2m_timer_init(void)
> -{
> - v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
> - v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
> -}
> -
> -static struct sys_timer v2m_timer = {
> - .init = v2m_timer_init,
> -};
> -
>
> static DEFINE_SPINLOCK(v2m_cfg_lock);
>
> @@ -326,86 +317,135 @@ static struct amba_device *v2m_amba_devs[] __initdata = {
> };
>
>
> -static long v2m_osc_round(struct clk *clk, unsigned long rate)
> +static unsigned long v2m_osc_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct v2m_osc *osc = to_v2m_osc(hw);
> +
> + return !parent_rate ? osc->rate_default : parent_rate;
> +}
> +
> +static long v2m_osc_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *parent_rate)
> {
> + struct v2m_osc *osc = to_v2m_osc(hw);
> +
> + if (WARN_ON(rate < osc->rate_min))
> + rate = osc->rate_min;
> +
> + if (WARN_ON(rate > osc->rate_max))
> + rate = osc->rate_max;
> +
> return rate;
> }
>
> -static int v2m_osc1_set(struct clk *clk, unsigned long rate)
> +static int v2m_osc_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> {
> - return v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE_MB | 1, rate);
> + struct v2m_osc *osc = to_v2m_osc(hw);
> +
> + v2m_cfg_write(SYS_CFG_OSC | SYS_CFG_SITE(osc->site) |
> + SYS_CFG_STACK(osc->stack) | osc->osc, rate);
> +
> + return 0;
> }
>
> -static const struct clk_ops osc1_clk_ops = {
> - .round = v2m_osc_round,
> - .set = v2m_osc1_set,
> +static struct clk_ops v2m_osc_ops = {
> + .recalc_rate = v2m_osc_recalc_rate,
> + .round_rate = v2m_osc_round_rate,
> + .set_rate = v2m_osc_set_rate,
> };
>
> -static struct clk osc1_clk = {
> - .ops = &osc1_clk_ops,
> - .rate = 24000000,
> +struct clk * __init v2m_osc_register(const char *name, struct v2m_osc *osc)
> +{
> + struct clk_init_data init;
> +
> + WARN_ON(osc->site > 2);
> + WARN_ON(osc->stack > 15);
> + WARN_ON(osc->osc > 4095);
> +
> + init.name = name;
> + init.ops = &v2m_osc_ops;
> + init.flags = CLK_IS_ROOT;
> + init.num_parents = 0;
> +
> + osc->hw.init = &init;
> +
> + return clk_register(NULL, &osc->hw);
> +}
> +
> +static struct v2m_osc v2m_mb_osc1 = {
> + .site = SYS_CFG_SITE_MB,
> + .osc = 1,
> + .rate_min = 23750000,
> + .rate_max = 63500000,
> + .rate_default = 23750000,
> };
>
> -static struct clk osc2_clk = {
> - .rate = 24000000,
> +static const char *v2m_ref_clk_periphs[] __initconst = {
> + "mb:wdt", "1000f000.wdt", "1c0f0000.wdt", /* SP805 WDT */
> };
>
> -static struct clk v2m_sp804_clk = {
> - .rate = 1000000,
> +static const char *v2m_osc1_periphs[] __initconst = {
> + "mb:clcd", "1001f000.clcd", "1c1f0000.clcd", /* PL111 CLCD */
> };
>
> -static struct clk v2m_ref_clk = {
> - .rate = 32768,
> +static const char *v2m_osc2_periphs[] __initconst = {
> + "mb:mmci", "10005000.mmci", "1c050000.mmci", /* PL180 MMCI */
> + "mb:kmi0", "10006000.kmi", "1c060000.kmi", /* PL050 KMI0 */
> + "mb:kmi1", "10007000.kmi", "1c070000.kmi", /* PL050 KMI1 */
> + "mb:uart0", "10009000.uart", "1c090000.uart", /* PL011 UART0 */
> + "mb:uart1", "1000a000.uart", "1c0a0000.uart", /* PL011 UART1 */
> + "mb:uart2", "1000b000.uart", "1c0b0000.uart", /* PL011 UART2 */
> + "mb:uart3", "1000c000.uart", "1c0c0000.uart", /* PL011 UART3 */
> };
>
> -static struct clk dummy_apb_pclk;
> -
> -static struct clk_lookup v2m_lookups[] = {
> - { /* AMBA bus clock */
> - .con_id = "apb_pclk",
> - .clk = &dummy_apb_pclk,
> - }, { /* UART0 */
> - .dev_id = "mb:uart0",
> - .clk = &osc2_clk,
> - }, { /* UART1 */
> - .dev_id = "mb:uart1",
> - .clk = &osc2_clk,
> - }, { /* UART2 */
> - .dev_id = "mb:uart2",
> - .clk = &osc2_clk,
> - }, { /* UART3 */
> - .dev_id = "mb:uart3",
> - .clk = &osc2_clk,
> - }, { /* KMI0 */
> - .dev_id = "mb:kmi0",
> - .clk = &osc2_clk,
> - }, { /* KMI1 */
> - .dev_id = "mb:kmi1",
> - .clk = &osc2_clk,
> - }, { /* MMC0 */
> - .dev_id = "mb:mmci",
> - .clk = &osc2_clk,
> - }, { /* CLCD */
> - .dev_id = "mb:clcd",
> - .clk = &osc1_clk,
> - }, { /* SP805 WDT */
> - .dev_id = "mb:wdt",
> - .clk = &v2m_ref_clk,
> - }, { /* SP804 timers */
> - .dev_id = "sp804",
> - .con_id = "v2m-timer0",
> - .clk = &v2m_sp804_clk,
> - }, { /* SP804 timers */
> - .dev_id = "sp804",
> - .con_id = "v2m-timer1",
> - .clk = &v2m_sp804_clk,
> - },
> +static void __init v2m_clk_init(void)
> +{
> + struct clk *clk;
> + int i;
> +
> + clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
> + CLK_IS_ROOT, 0);
> + WARN_ON(clk_register_clkdev(clk, "abp_pclk", NULL));
> +
> + clk = clk_register_fixed_rate(NULL, "mb:ref_clk", NULL,
> + CLK_IS_ROOT, 32768);
> + for (i = 0; i < ARRAY_SIZE(v2m_ref_clk_periphs); i++)
> + WARN_ON(clk_register_clkdev(clk, NULL, v2m_ref_clk_periphs[i]));
> +
> + clk = clk_register_fixed_rate(NULL, "mb:sp804_clk", NULL,
> + CLK_IS_ROOT, 1000000);
> + WARN_ON(clk_register_clkdev(clk, "v2m-timer0", "sp804"));
> + WARN_ON(clk_register_clkdev(clk, "v2m-timer1", "sp804"));
> +
> + clk = v2m_osc_register("mb:osc1", &v2m_mb_osc1);
> + for (i = 0; i < ARRAY_SIZE(v2m_osc1_periphs); i++)
> + WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc1_periphs[i]));
> +
> + clk = clk_register_fixed_rate(NULL, "mb:osc2", NULL,
> + CLK_IS_ROOT, 24000000);
> + for (i = 0; i < ARRAY_SIZE(v2m_osc2_periphs); i++)
> + WARN_ON(clk_register_clkdev(clk, NULL, v2m_osc2_periphs[i]));
> +}
> +
> +static void __init v2m_timer_init(void)
> +{
> + v2m_sysctl_init(ioremap(V2M_SYSCTL, SZ_4K));
> + v2m_clk_init();
> + if (ct_desc->init_clk)
> + ct_desc->init_clk();
> + v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
> +}
> +
> +static struct sys_timer v2m_timer = {
> + .init = v2m_timer_init,
> };
>
> static void __init v2m_init_early(void)
> {
> - ct_desc->init_early();
> - clkdev_add_table(v2m_lookups, ARRAY_SIZE(v2m_lookups));
> + if (ct_desc->init_early)
> + ct_desc->init_early();
> versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
> }
>
> @@ -528,77 +568,6 @@ void __init v2m_dt_map_io(void)
> #endif
> }
>
> -static struct clk_lookup v2m_dt_lookups[] = {
> - { /* AMBA bus clock */
> - .con_id = "apb_pclk",
> - .clk = &dummy_apb_pclk,
> - }, { /* SP804 timers */
> - .dev_id = "sp804",
> - .con_id = "v2m-timer0",
> - .clk = &v2m_sp804_clk,
> - }, { /* SP804 timers */
> - .dev_id = "sp804",
> - .con_id = "v2m-timer1",
> - .clk = &v2m_sp804_clk,
> - }, { /* PL180 MMCI */
> - .dev_id = "mb:mmci", /* 10005000.mmci */
> - .clk = &osc2_clk,
> - }, { /* PL050 KMI0 */
> - .dev_id = "10006000.kmi",
> - .clk = &osc2_clk,
> - }, { /* PL050 KMI1 */
> - .dev_id = "10007000.kmi",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART0 */
> - .dev_id = "10009000.uart",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART1 */
> - .dev_id = "1000a000.uart",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART2 */
> - .dev_id = "1000b000.uart",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART3 */
> - .dev_id = "1000c000.uart",
> - .clk = &osc2_clk,
> - }, { /* SP805 WDT */
> - .dev_id = "1000f000.wdt",
> - .clk = &v2m_ref_clk,
> - }, { /* PL111 CLCD */
> - .dev_id = "1001f000.clcd",
> - .clk = &osc1_clk,
> - },
> - /* RS1 memory map */
> - { /* PL180 MMCI */
> - .dev_id = "mb:mmci", /* 1c050000.mmci */
> - .clk = &osc2_clk,
> - }, { /* PL050 KMI0 */
> - .dev_id = "1c060000.kmi",
> - .clk = &osc2_clk,
> - }, { /* PL050 KMI1 */
> - .dev_id = "1c070000.kmi",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART0 */
> - .dev_id = "1c090000.uart",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART1 */
> - .dev_id = "1c0a0000.uart",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART2 */
> - .dev_id = "1c0b0000.uart",
> - .clk = &osc2_clk,
> - }, { /* PL011 UART3 */
> - .dev_id = "1c0c0000.uart",
> - .clk = &osc2_clk,
> - }, { /* SP805 WDT */
> - .dev_id = "1c0f0000.wdt",
> - .clk = &v2m_ref_clk,
> - }, { /* PL111 CLCD */
> - .dev_id = "1c1f0000.clcd",
> - .clk = &osc1_clk,
> - },
> -};
> -
> void __init v2m_dt_init_early(void)
> {
> struct device_node *node;
> @@ -620,8 +589,6 @@ void __init v2m_dt_init_early(void)
> pr_warning("vexpress: DT HBI (%x) is not matching "
> "hardware (%x)!\n", dt_hbi, hbi);
> }
> -
> - clkdev_add_table(v2m_dt_lookups, ARRAY_SIZE(v2m_dt_lookups));
> }
>
> static struct of_device_id vexpress_irq_match[] __initdata = {
> @@ -643,6 +610,8 @@ static void __init v2m_dt_timer_init(void)
> node = of_find_compatible_node(NULL, NULL, "arm,sp810");
> v2m_sysctl_init(of_iomap(node, 0));
>
> + v2m_clk_init();
> +
> err = of_property_read_string(of_aliases, "arm,v2m_timer", &path);
> if (WARN_ON(err))
> return;
> diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig
> index 81ee7cc..4b9f4bf 100644
> --- a/arch/arm/plat-versatile/Kconfig
> +++ b/arch/arm/plat-versatile/Kconfig
> @@ -1,5 +1,10 @@
> if PLAT_VERSATILE
>
> +config PLAT_VERSATILE_CLOCK
> + bool
> + default y
> + depends on !COMMON_CLK
> +
> config PLAT_VERSATILE_CLCD
> bool
>
> diff --git a/arch/arm/plat-versatile/Makefile b/arch/arm/plat-versatile/Makefile
> index a5cb194..272769a8 100644
> --- a/arch/arm/plat-versatile/Makefile
> +++ b/arch/arm/plat-versatile/Makefile
> @@ -1,4 +1,4 @@
> -obj-y := clock.o
> +obj-$(CONFIG_PLAT_VERSATILE_CLOCK) += clock.o
> obj-$(CONFIG_PLAT_VERSATILE_CLCD) += clcd.o
> obj-$(CONFIG_PLAT_VERSATILE_FPGA_IRQ) += fpga-irq.o
> obj-$(CONFIG_PLAT_VERSATILE_LEDS) += leds.o
More information about the linux-arm-kernel
mailing list