diff mbox

clk: convert ARM RealView to common clk

Message ID 1344270728-7550-1-git-send-email-linus.walleij@stericsson.com (mailing list archive)
State New, archived
Headers show

Commit Message

Linus Walleij Aug. 6, 2012, 4:32 p.m. UTC
From: Linus Walleij <linus.walleij@linaro.org>

This converts the ARM RealView machine over to using the common
clock. The approach is similar to the one used for the Integrator,
and we're reusing the ICST wrapper code.

We have to put the clock intialization in the timer init function
for the clocks to be available when initializing the timer,
keeping them in early_init() is too early for the common clk.

Since we now have to go down and compile drivers/clk/versatile
a CONFIG_COMMON_CLK_VERSATILE symbol has been added so the proper
code gets compiled into the kernel for either machine. A leftover
CLK_VERSATILE in the Integrator Kconfig was fixed up to use
the new symbol as well.

Tested on ARM RealView PB1176.

Cc: Pawel Moll <pawel.moll@arm.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/Kconfig                             |   7 +-
 arch/arm/mach-realview/core.c                | 106 -------------------------
 arch/arm/mach-realview/include/mach/clkdev.h |  16 ----
 arch/arm/mach-realview/realview_eb.c         |   2 +
 arch/arm/mach-realview/realview_pb1176.c     |   2 +
 arch/arm/mach-realview/realview_pb11mp.c     |   2 +
 arch/arm/mach-realview/realview_pba8.c       |   2 +
 arch/arm/mach-realview/realview_pbx.c        |   2 +
 drivers/clk/Kconfig                          |   7 ++
 drivers/clk/Makefile                         |   2 +-
 drivers/clk/versatile/Makefile               |   1 +
 drivers/clk/versatile/clk-realview.c         | 114 +++++++++++++++++++++++++++
 include/linux/platform_data/clk-realview.h   |   1 +
 13 files changed, 137 insertions(+), 127 deletions(-)
 delete mode 100644 arch/arm/mach-realview/include/mach/clkdev.h
 create mode 100644 drivers/clk/versatile/clk-realview.c
 create mode 100644 include/linux/platform_data/clk-realview.h

Comments

Pawel Moll Aug. 8, 2012, 11:48 a.m. UTC | #1
On Mon, 2012-08-06 at 17:32 +0100, Linus Walleij wrote:
> This converts the ARM RealView machine over to using the common
> clock. The approach is similar to the one used for the Integrator,
> and we're reusing the ICST wrapper code.

I've just tried it with v3.6-rc1 and an EB Model and I get this:

------------[ cut here ]------------
WARNING: at /home/pawmol01/src/kernel.org/linux/kernel/timer.c:1076 del_timer_sync+0x34/0x5c()
Modules linked in:
[<c0014054>] (unwind_backtrace+0x0/0xe0) from [<c001ca3c>] (warn_slowpath_common+0x4c/0x64)
[<c001ca3c>] (warn_slowpath_common+0x4c/0x64) from [<c001ca6c>] (warn_slowpath_null+0x18/0x1c)
[<c001ca6c>] (warn_slowpath_null+0x18/0x1c) from [<c00285b8>] (del_timer_sync+0x34/0x5c)
[<c00285b8>] (del_timer_sync+0x34/0x5c) from [<c01d57e4>] (led_set_brightness+0x14/0x4c)
[<c01d57e4>] (led_set_brightness+0x14/0x4c) from [<c01d6270>] (led_trigger_event+0x30/0x70)
[<c01d6270>] (led_trigger_event+0x30/0x70) from [<c01c7ee8>] (mmc_request_done+0x68/0x90)
[<c01c7ee8>] (mmc_request_done+0x68/0x90) from [<c01d5770>] (mmci_irq+0x274/0x2d4)
[<c01d5770>] (mmci_irq+0x274/0x2d4) from [<c005a090>] (handle_irq_event_percpu+0x2c/0x170)
[<c005a090>] (handle_irq_event_percpu+0x2c/0x170) from [<c005a22c>] (handle_irq_event+0x58/0x78)
[<c005a22c>] (handle_irq_event+0x58/0x78) from [<c005ce68>] (handle_fasteoi_irq+0xcc/0x13c)
[<c005ce68>] (handle_fasteoi_irq+0xcc/0x13c) from [<c0059ae8>] (generic_handle_irq+0x20/0x30)
[<c0059ae8>] (generic_handle_irq+0x20/0x30) from [<c000eafc>] (handle_IRQ+0x78/0xb8)
[<c000eafc>] (handle_IRQ+0x78/0xb8) from [<c0008468>] (gic_handle_irq+0x3c/0x60)
[<c0008468>] (gic_handle_irq+0x3c/0x60) from [<c000d820>] (__irq_svc+0x40/0x54)
Exception stack(0xcf83be20 to 0xcf83be68)
be20: cfbfd26c 60000013 00130013 00000000 cf83be84 cfbfd000 00000000 cf83be94
be40: cf83beb8 c01c989c 00000000 00000000 00000000 cf83be68 c01c7f80 c02aaac0
be60: 40000013 ffffffff
[<c000d820>] (__irq_svc+0x40/0x54) from [<c02aaac0>] (_raw_spin_unlock_irqrestore+0x2c/0x30)
[<c02aaac0>] (_raw_spin_unlock_irqrestore+0x2c/0x30) from [<c01c7f80>] (mmc_wait_for_req_done+0x70/0x74)
[<c01c7f80>] (mmc_wait_for_req_done+0x70/0x74) from [<c01c83b8>] (mmc_wait_for_cmd+0x64/0x74)        
[<c01c83b8>] (mmc_wait_for_cmd+0x64/0x74) from [<c01cfcfc>] (mmc_send_io_op_cond+0x58/0xc4)
[<c01cfcfc>] (mmc_send_io_op_cond+0x58/0xc4) from [<c01cf8b0>] (mmc_attach_sdio+0x3c/0x304)
[<c01cf8b0>] (mmc_attach_sdio+0x3c/0x304) from [<c01c9ab0>] (mmc_rescan+0x214/0x290)
[<c01c9ab0>] (mmc_rescan+0x214/0x290) from [<c00328f4>] (process_one_work+0x240/0x3b8)
[<c00328f4>] (process_one_work+0x240/0x3b8) from [<c0032d70>] (worker_thread+0x2d8/0x434)
[<c0032d70>] (worker_thread+0x2d8/0x434) from [<c00373b0>] (kthread+0x84/0x94)
[<c00373b0>] (kthread+0x84/0x94) from [<c000ed44>] (kernel_thread_exit+0x0/0x8)
---[ end trace 93fc2bf490575317 ]---

I'm not sure who's fault it is (may be mine), will try to figure out
what is going on...

Cheers!

Pawe?
Pawel Moll Aug. 8, 2012, 11:52 a.m. UTC | #2
On Wed, 2012-08-08 at 12:48 +0100, Pawel Moll wrote:
> On Mon, 2012-08-06 at 17:32 +0100, Linus Walleij wrote:
> > This converts the ARM RealView machine over to using the common
> > clock. The approach is similar to the one used for the Integrator,
> > and we're reusing the ICST wrapper code.
> 
> I've just tried it with v3.6-rc1 and an EB Model and I get this:
> 
> ------------[ cut here ]------------
> WARNING: at /home/pawmol01/src/kernel.org/linux/kernel/timer.c:1076 del_timer_sync+0x34/0x5c()

Err. Ignore that. The same happens without your patch :-)

Will try with 3.5.

Pawe?
Linus Walleij Aug. 8, 2012, 11:55 a.m. UTC | #3
On Wed, Aug 8, 2012 at 1:52 PM, Pawel Moll <pawel.moll@arm.com> wrote:

>> ------------[ cut here ]------------
>> WARNING: at /home/pawmol01/src/kernel.org/linux/kernel/timer.c:1076 del_timer_sync+0x34/0x5c()
>
> Err. Ignore that. The same happens without your patch :-)
>
> Will try with 3.5.

Hm it boots like a charm on PB1176, what's so very different about the EB?

Oh well. Are you maintaining RealView EB, BTW?

Yours,
Linus Walleij
Pawel Moll Aug. 8, 2012, 1:06 p.m. UTC | #4
On Wed, 2012-08-08 at 12:55 +0100, Linus Walleij wrote:
> On Wed, Aug 8, 2012 at 1:52 PM, Pawel Moll <pawel.moll@arm.com> wrote:
> 
> >> ------------[ cut here ]------------
> >> WARNING: at /home/pawmol01/src/kernel.org/linux/kernel/timer.c:1076 del_timer_sync+0x34/0x5c()
> >
> > Err. Ignore that. The same happens without your patch :-)
> >
> > Will try with 3.5.
> 
> Hm it boots like a charm on PB1176, what's so very different about the EB?

It's configuration difference, I guess. You may try enabling
CONFIG_LEDS_TRIGGERS (not that it makes much sense on Realview) if you
want to see the same effect :-)

It seems that a0193cbee0809d65362a0767b2d50306b145b2f5 "leds: use
led_set_brightness in led_trigger_event" causes a problem when
led_trigger_event() is called from an interrupt context. I'll let the
LEDS people know.

> Oh well. Are you maintaining RealView EB, BTW?

Not really. At least I didn't have any reason to do this so far. And the
only Realview platforms I'm really interested in are the EB models. DT
for Realview is on my todo list, but with really low priority (around
"most likely will never happen").

Anyway, after testing your change on EB model:

Acked-by: Pawel Moll <pawel.moll@arm.com>

Cheers!

Pawe?
Linus Walleij Aug. 16, 2012, 12:56 p.m. UTC | #5
On Mon, Aug 6, 2012 at 6:32 PM, Linus Walleij
<linus.walleij@stericsson.com> wrote:

> This converts the ARM RealView machine over to using the common
> clock. The approach is similar to the one used for the Integrator,
> and we're reusing the ICST wrapper code.

Mike have you had time to look at this? I got Pawel's ACK in the thread.

Yours,
Linus Walleij
Linus Walleij Aug. 22, 2012, 12:09 p.m. UTC | #6
On Thu, Aug 16, 2012 at 2:56 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Mon, Aug 6, 2012 at 6:32 PM, Linus Walleij
> <linus.walleij@stericsson.com> wrote:
>
>> This converts the ARM RealView machine over to using the common
>> clock. The approach is similar to the one used for the Integrator,
>> and we're reusing the ICST wrapper code.
>
> Mike have you had time to look at this? I got Pawel's ACK in the thread.

Ping again on this, if it's OK it would be great to get some rotation in
-next for this patch.

Yours,
Linus Walleij
Mike Turquette Aug. 24, 2012, 11:51 p.m. UTC | #7
Quoting Linus Walleij (2012-08-22 05:09:30)
> On Thu, Aug 16, 2012 at 2:56 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
> > On Mon, Aug 6, 2012 at 6:32 PM, Linus Walleij
> > <linus.walleij@stericsson.com> wrote:
> >
> >> This converts the ARM RealView machine over to using the common
> >> clock. The approach is similar to the one used for the Integrator,
> >> and we're reusing the ICST wrapper code.
> >
> > Mike have you had time to look at this? I got Pawel's ACK in the thread.
> 
> Ping again on this, if it's OK it would be great to get some rotation in
> -next for this patch.
> 

Hi Linus,

Apologies for the delayed response.  I've been AWOL on clk patches since
the 3.5 release.

I've taken this into clk-next which will be published (based on 3.6-rc3)
this evening.

Regards,
Mike

> Yours,
> Linus Walleij
Pawel Moll Aug. 30, 2012, 12:33 p.m. UTC | #8
Hi Linus,

I'm working on moving the VE clocking into driver/clk on top of your
Realview change, and just spotted one minor issue...

On Mon, 2012-08-06 at 17:32 +0100, Linus Walleij wrote:
> From: Linus Walleij <linus.walleij@linaro.org>
> 
> This converts the ARM RealView machine over to using the common
> clock. The approach is similar to the one used for the Integrator,
> and we're reusing the ICST wrapper code.
[...]
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 7f0b5ca..89b726d 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -40,4 +40,11 @@ config COMMON_CLK_WM831X
>            Supports the clocking subsystem of the WM831x/2x series of
>           PMICs from Wolfson Microlectronics.
> 
> +config COMMON_CLK_VERSATILE
> +       tristate "Clock driver for ARM Reference designs"

It can't really be a "tristate", can it? To my mind there is no way of
making it a module, so a "bool" seems more appropriate?

> +       depends on ARCH_INTEGRATOR || ARCH_REALVIEW
> +       ---help---
> +          Supports clocking on ARM Reference designs Integrator/AP,
> +         Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
> +
>  endmenu

Cheers!

Pawe?
Linus Walleij Aug. 30, 2012, 5:24 p.m. UTC | #9
On Thu, Aug 30, 2012 at 5:33 AM, Pawel Moll <pawel.moll@arm.com> wrote:
[Me]
>> +config COMMON_CLK_VERSATILE
>> +       tristate "Clock driver for ARM Reference designs"
>
> It can't really be a "tristate", can it? To my mind there is no way of
> making it a module, so a "bool" seems more appropriate?

You're right, I'll send a small fixup patch to Mike.

Yours,
Linus Walleij
diff mbox

Patch

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e91c7cd..530630c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -279,7 +279,7 @@  config ARCH_INTEGRATOR
 	select ARM_AMBA
 	select ARCH_HAS_CPUFREQ
 	select COMMON_CLK
-	select CLK_VERSATILE
+	select COMMON_CLK_VERSATILE
 	select HAVE_TCM
 	select ICST
 	select GENERIC_CLOCKEVENTS
@@ -295,13 +295,12 @@  config ARCH_INTEGRATOR
 config ARCH_REALVIEW
 	bool "ARM Ltd. RealView family"
 	select ARM_AMBA
-	select CLKDEV_LOOKUP
-	select HAVE_MACH_CLKDEV
+	select COMMON_CLK
+	select COMMON_CLK_VERSATILE
 	select ICST
 	select GENERIC_CLOCKEVENTS
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select PLAT_VERSATILE
-	select PLAT_VERSATILE_CLOCK
 	select PLAT_VERSATILE_CLCD
 	select ARM_TIMER_SP804
 	select GPIO_PL061 if GPIOLIB
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 45868bb..ff007d1 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -30,7 +30,6 @@ 
 #include <linux/ata_platform.h>
 #include <linux/amba/mmci.h>
 #include <linux/gfp.h>
-#include <linux/clkdev.h>
 #include <linux/mtd/physmap.h>
 
 #include <mach/hardware.h>
@@ -226,115 +225,10 @@  struct mmci_platform_data realview_mmc1_plat_data = {
 	.cd_invert	= true,
 };
 
-/*
- * Clock handling
- */
-static const struct icst_params realview_oscvco_params = {
-	.ref		= 24000000,
-	.vco_max	= ICST307_VCO_MAX,
-	.vco_min	= ICST307_VCO_MIN,
-	.vd_min		= 4 + 8,
-	.vd_max		= 511 + 8,
-	.rd_min		= 1 + 2,
-	.rd_max		= 127 + 2,
-	.s2div		= icst307_s2div,
-	.idx2s		= icst307_idx2s,
-};
-
-static void realview_oscvco_set(struct clk *clk, struct icst_vco vco)
-{
-	void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET;
-	u32 val;
-
-	val = readl(clk->vcoreg) & ~0x7ffff;
-	val |= vco.v | (vco.r << 9) | (vco.s << 16);
-
-	writel(0xa05f, sys_lock);
-	writel(val, clk->vcoreg);
-	writel(0, sys_lock);
-}
-
-static const struct clk_ops oscvco_clk_ops = {
-	.round	= icst_clk_round,
-	.set	= icst_clk_set,
-	.setvco	= realview_oscvco_set,
-};
-
-static struct clk oscvco_clk = {
-	.ops	= &oscvco_clk_ops,
-	.params	= &realview_oscvco_params,
-};
-
-/*
- * These are fixed clocks.
- */
-static struct clk ref24_clk = {
-	.rate	= 24000000,
-};
-
-static struct clk sp804_clk = {
-	.rate	= 1000000,
-};
-
-static struct clk dummy_apb_pclk;
-
-static struct clk_lookup lookups[] = {
-	{	/* Bus clock */
-		.con_id		= "apb_pclk",
-		.clk		= &dummy_apb_pclk,
-	}, {	/* UART0 */
-		.dev_id		= "dev:uart0",
-		.clk		= &ref24_clk,
-	}, {	/* UART1 */
-		.dev_id		= "dev:uart1",
-		.clk		= &ref24_clk,
-	}, {	/* UART2 */
-		.dev_id		= "dev:uart2",
-		.clk		= &ref24_clk,
-	}, {	/* UART3 */
-		.dev_id		= "fpga:uart3",
-		.clk		= &ref24_clk,
-	}, {	/* UART3 is on the dev chip in PB1176 */
-		.dev_id		= "dev:uart3",
-		.clk		= &ref24_clk,
-	}, {	/* UART4 only exists in PB1176 */
-		.dev_id		= "fpga:uart4",
-		.clk		= &ref24_clk,
-	}, {	/* KMI0 */
-		.dev_id		= "fpga:kmi0",
-		.clk		= &ref24_clk,
-	}, {	/* KMI1 */
-		.dev_id		= "fpga:kmi1",
-		.clk		= &ref24_clk,
-	}, {	/* MMC0 */
-		.dev_id		= "fpga:mmc0",
-		.clk		= &ref24_clk,
-	}, {	/* CLCD is in the PB1176 and EB DevChip */
-		.dev_id		= "dev:clcd",
-		.clk		= &oscvco_clk,
-	}, {	/* PB:CLCD */
-		.dev_id		= "issp:clcd",
-		.clk		= &oscvco_clk,
-	}, {	/* SSP */
-		.dev_id		= "dev:ssp0",
-		.clk		= &ref24_clk,
-	}, {	/* SP804 timers */
-		.dev_id		= "sp804",
-		.clk		= &sp804_clk,
-	},
-};
-
 void __init realview_init_early(void)
 {
 	void __iomem *sys = __io_address(REALVIEW_SYS_BASE);
 
-	if (machine_is_realview_pb1176())
-		oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC0_OFFSET;
-	else
-		oscvco_clk.vcoreg = sys + REALVIEW_SYS_OSC4_OFFSET;
-
-	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
 	versatile_sched_clock_init(sys + REALVIEW_SYS_24MHz_OFFSET, 24000000);
 }
 
diff --git a/arch/arm/mach-realview/include/mach/clkdev.h b/arch/arm/mach-realview/include/mach/clkdev.h
deleted file mode 100644
index e58d077..0000000
--- a/arch/arm/mach-realview/include/mach/clkdev.h
+++ /dev/null
@@ -1,16 +0,0 @@ 
-#ifndef __ASM_MACH_CLKDEV_H
-#define __ASM_MACH_CLKDEV_H
-
-#include <plat/clock.h>
-
-struct clk {
-	unsigned long		rate;
-	const struct clk_ops	*ops;
-	const struct icst_params *params;
-	void __iomem		*vcoreg;
-};
-
-#define __clk_get(clk) ({ 1; })
-#define __clk_put(clk) do { } while (0)
-
-#endif
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index baf382c..a33e33b 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -27,6 +27,7 @@ 
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -414,6 +415,7 @@  static void __init realview_eb_timer_init(void)
 	else
 		timer_irq = IRQ_EB_TIMER0_1;
 
+	realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
 	realview_timer_init(timer_irq);
 	realview_eb_twd_init();
 }
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index b1d7caf..f0298cb 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -29,6 +29,7 @@ 
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -326,6 +327,7 @@  static void __init realview_pb1176_timer_init(void)
 	timer2_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PB1176_TIMER2_3_BASE) + 0x20;
 
+	realview_clk_init(__io_address(REALVIEW_SYS_BASE), true);
 	realview_timer_init(IRQ_DC1176_TIMER0);
 }
 
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index a98c536..1f019f7 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -27,6 +27,7 @@ 
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -312,6 +313,7 @@  static void __init realview_pb11mp_timer_init(void)
 	timer2_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
 
+	realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
 	realview_timer_init(IRQ_TC11MP_TIMER0_1);
 	realview_pb11mp_twd_init();
 }
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index 5965017..5032775 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -27,6 +27,7 @@ 
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <asm/irq.h>
 #include <asm/leds.h>
@@ -261,6 +262,7 @@  static void __init realview_pba8_timer_init(void)
 	timer2_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE) + 0x20;
 
+	realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
 	realview_timer_init(IRQ_PBA8_TIMER0_1);
 }
 
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 3f2f605..de64ba0 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -26,6 +26,7 @@ 
 #include <linux/amba/mmci.h>
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
+#include <linux/platform_data/clk-realview.h>
 
 #include <asm/irq.h>
 #include <asm/leds.h>
@@ -320,6 +321,7 @@  static void __init realview_pbx_timer_init(void)
 	timer2_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE);
 	timer3_va_base = __io_address(REALVIEW_PBX_TIMER2_3_BASE) + 0x20;
 
+	realview_clk_init(__io_address(REALVIEW_SYS_BASE), false);
 	realview_timer_init(IRQ_PBX_TIMER0_1);
 	realview_pbx_twd_init();
 }
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 7f0b5ca..89b726d 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -40,4 +40,11 @@  config COMMON_CLK_WM831X
           Supports the clocking subsystem of the WM831x/2x series of
 	  PMICs from Wolfson Microlectronics.
 
+config COMMON_CLK_VERSATILE
+	tristate "Clock driver for ARM Reference designs"
+	depends on ARCH_INTEGRATOR || ARCH_REALVIEW
+	---help---
+          Supports clocking on ARM Reference designs Integrator/AP,
+	  Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
+
 endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5869ea3..cfa7eeb 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,7 +9,7 @@  obj-$(CONFIG_ARCH_MXS)		+= mxs/
 obj-$(CONFIG_ARCH_SOCFPGA)	+= socfpga/
 obj-$(CONFIG_PLAT_SPEAR)	+= spear/
 obj-$(CONFIG_ARCH_U300)		+= clk-u300.o
-obj-$(CONFIG_ARCH_INTEGRATOR)	+= versatile/
+obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
 
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index 50cf6a2..c0a0f64 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -1,3 +1,4 @@ 
 # Makefile for Versatile-specific clocks
 obj-$(CONFIG_ICST)		+= clk-icst.o
 obj-$(CONFIG_ARCH_INTEGRATOR)	+= clk-integrator.o
+obj-$(CONFIG_ARCH_REALVIEW)	+= clk-realview.o
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c
new file mode 100644
index 0000000..e21a99c
--- /dev/null
+++ b/drivers/clk/versatile/clk-realview.c
@@ -0,0 +1,114 @@ 
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#include "clk-icst.h"
+
+/*
+ * Implementation of the ARM RealView clock trees.
+ */
+
+static void __iomem *sys_lock;
+static void __iomem *sys_vcoreg;
+
+/**
+ * realview_oscvco_get() - get ICST OSC settings for the RealView
+ */
+static struct icst_vco realview_oscvco_get(void)
+{
+	u32 val;
+	struct icst_vco vco;
+
+	val = readl(sys_vcoreg);
+	vco.v = val & 0x1ff;
+	vco.r = (val >> 9) & 0x7f;
+	vco.s = (val >> 16) & 03;
+	return vco;
+}
+
+static void realview_oscvco_set(struct icst_vco vco)
+{
+	u32 val;
+
+	val = readl(sys_vcoreg) & ~0x7ffff;
+	val |= vco.v | (vco.r << 9) | (vco.s << 16);
+
+	/* This magic unlocks the CM VCO so it can be controlled */
+	writel(0xa05f, sys_lock);
+	writel(val, sys_vcoreg);
+	/* This locks the CM again */
+	writel(0, sys_lock);
+}
+
+static const struct icst_params realview_oscvco_params = {
+	.ref		= 24000000,
+	.vco_max	= ICST307_VCO_MAX,
+	.vco_min	= ICST307_VCO_MIN,
+	.vd_min		= 4 + 8,
+	.vd_max		= 511 + 8,
+	.rd_min		= 1 + 2,
+	.rd_max		= 127 + 2,
+	.s2div		= icst307_s2div,
+	.idx2s		= icst307_idx2s,
+};
+
+static const struct clk_icst_desc __initdata realview_icst_desc = {
+	.params = &realview_oscvco_params,
+	.getvco = realview_oscvco_get,
+	.setvco = realview_oscvco_set,
+};
+
+/*
+ * realview_clk_init() - set up the RealView clock tree
+ */
+void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
+{
+	struct clk *clk;
+
+	sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
+	if (is_pb1176)
+		sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
+	else
+		sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;
+
+
+	/* APB clock dummy */
+	clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
+	clk_register_clkdev(clk, "apb_pclk", NULL);
+
+	/* 24 MHz clock */
+	clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT,
+				24000000);
+	clk_register_clkdev(clk, NULL, "dev:uart0");
+	clk_register_clkdev(clk, NULL, "dev:uart1");
+	clk_register_clkdev(clk, NULL, "dev:uart2");
+	clk_register_clkdev(clk, NULL, "fpga:kmi0");
+	clk_register_clkdev(clk, NULL, "fpga:kmi1");
+	clk_register_clkdev(clk, NULL, "fpga:mmc0");
+	clk_register_clkdev(clk, NULL, "dev:ssp0");
+	if (is_pb1176) {
+		/*
+		 * UART3 is on the dev chip in PB1176
+		 * UART4 only exists in PB1176
+		 */
+		clk_register_clkdev(clk, NULL, "dev:uart3");
+		clk_register_clkdev(clk, NULL, "dev:uart4");
+	} else
+		clk_register_clkdev(clk, NULL, "fpga:uart3");
+
+
+	/* 1 MHz clock */
+	clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT,
+				      1000000);
+	clk_register_clkdev(clk, NULL, "sp804");
+
+	/* ICST VCO clock */
+	clk = icst_clk_register(NULL, &realview_icst_desc);
+	clk_register_clkdev(clk, NULL, "dev:clcd");
+	clk_register_clkdev(clk, NULL, "issp:clcd");
+}
diff --git a/include/linux/platform_data/clk-realview.h b/include/linux/platform_data/clk-realview.h
new file mode 100644
index 0000000..2e426a7
--- /dev/null
+++ b/include/linux/platform_data/clk-realview.h
@@ -0,0 +1 @@ 
+void realview_clk_init(void __iomem *sysbase, bool is_pb1176);