diff mbox

[03/10] arm: zynq: Move timer to generic location

Message ID 1364219596-4954-3-git-send-email-michal.simek@xilinx.com (mailing list archive)
State New, archived
Headers show

Commit Message

Michal Simek March 25, 2013, 1:53 p.m. UTC
Move zynq timer out of mach folder to generic location.

Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
Arnd: This is the last patch as we discuss about moving
this timer to generic location.

It depends on ARCH_ZYNQ as Tegra and others.
It should be ok to use it or we can use different name if you like.
---
 arch/arm/mach-zynq/Makefile      |    2 +-
 arch/arm/mach-zynq/timer.c       |  430 --------------------------------------
 drivers/clocksource/Makefile     |    1 +
 drivers/clocksource/zynq_timer.c |  430 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 432 insertions(+), 431 deletions(-)
 delete mode 100644 arch/arm/mach-zynq/timer.c
 create mode 100644 drivers/clocksource/zynq_timer.c

Comments

Steffen Trumtrar March 25, 2013, 4:01 p.m. UTC | #1
Hi Michal!

On Mon, Mar 25, 2013 at 02:53:09PM +0100, Michal Simek wrote:
> Move zynq timer out of mach folder to generic location.
> 
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
> Arnd: This is the last patch as we discuss about moving
> this timer to generic location.
> 
> It depends on ARCH_ZYNQ as Tegra and others.
> It should be ok to use it or we can use different name if you like.
> ---

Moving out of mach-zynq is good, because this is a
	Cadence Rev06 Triple Timer Counter (see Zynq-7000 TRM page 25)
Which leads me to a proposed rename to: cadence_timer.c or something like that.
And the fn-names should be changed accordingly while at it.

>  arch/arm/mach-zynq/Makefile      |    2 +-
>  arch/arm/mach-zynq/timer.c       |  430 --------------------------------------
>  drivers/clocksource/Makefile     |    1 +
>  drivers/clocksource/zynq_timer.c |  430 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 432 insertions(+), 431 deletions(-)
>  delete mode 100644 arch/arm/mach-zynq/timer.c
>  create mode 100644 drivers/clocksource/zynq_timer.c
> 
> diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
> index 397268c..320faed 100644
> --- a/arch/arm/mach-zynq/Makefile
> +++ b/arch/arm/mach-zynq/Makefile
> @@ -3,4 +3,4 @@
>  #
>  
>  # Common support
> -obj-y				:= common.o timer.o
> +obj-y				:= common.o
> diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c
> deleted file mode 100644
> index 3b1faed..0000000
> --- a/arch/arm/mach-zynq/timer.c
> +++ /dev/null
> @@ -1,430 +0,0 @@
> -/*
> - * This file contains driver for the Xilinx PS Timer Counter IP.
> - *
> - *  Copyright (C) 2011 Xilinx
> - *
> - * based on arch/mips/kernel/time.c timer driver
> - *
> - * This software is licensed under the terms of the GNU General Public
> - * License version 2, as published by the Free Software Foundation, and
> - * may be copied, distributed, and modified under those terms.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> - * GNU General Public License for more details.
> - */
> -
> -#include <linux/clk.h>
> -#include <linux/interrupt.h>
> -#include <linux/clockchips.h>
> -#include <linux/of_address.h>
> -#include <linux/of_irq.h>
> -#include <linux/slab.h>
> -#include <linux/clk-provider.h>
> -
> -/*
> - * This driver configures the 2 16-bit count-up timers as follows:
> - *
> - * T1: Timer 1, clocksource for generic timekeeping
> - * T2: Timer 2, clockevent source for hrtimers
> - * T3: Timer 3, <unused>
> - *
> - * The input frequency to the timer module for emulation is 2.5MHz which is
> - * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
> - * the timers are clocked at 78.125KHz (12.8 us resolution).
> -
> - * The input frequency to the timer module in silicon is configurable and
> - * obtained from device tree. The pre-scaler of 32 is used.
> - */
> -
> -/*
> - * Timer Register Offset Definitions of Timer 1, Increment base address by 4
> - * and use same offsets for Timer 2
> - */
> -#define XTTCPS_CLK_CNTRL_OFFSET		0x00 /* Clock Control Reg, RW */
> -#define XTTCPS_CNT_CNTRL_OFFSET		0x0C /* Counter Control Reg, RW */
> -#define XTTCPS_COUNT_VAL_OFFSET		0x18 /* Counter Value Reg, RO */
> -#define XTTCPS_INTR_VAL_OFFSET		0x24 /* Interval Count Reg, RW */
> -#define XTTCPS_ISR_OFFSET		0x54 /* Interrupt Status Reg, RO */
> -#define XTTCPS_IER_OFFSET		0x60 /* Interrupt Enable Reg, RW */
> -
> -#define XTTCPS_CNT_CNTRL_DISABLE_MASK	0x1
> -
> -/*
> - * Setup the timers to use pre-scaling, using a fixed value for now that will
> - * work across most input frequency, but it may need to be more dynamic
> - */
> -#define PRESCALE_EXPONENT	11	/* 2 ^ PRESCALE_EXPONENT = PRESCALE */
> -#define PRESCALE		2048	/* The exponent must match this */
> -#define CLK_CNTRL_PRESCALE	((PRESCALE_EXPONENT - 1) << 1)
> -#define CLK_CNTRL_PRESCALE_EN	1
> -#define CNT_CNTRL_RESET		(1 << 4)
> -
> -/**
> - * struct xttcps_timer - This definition defines local timer structure
> - *
> - * @base_addr:	Base address of timer
> - * @clk:	Associated clock source
> - * @clk_rate_change_nb	Notifier block for clock rate changes
> - */
> -struct xttcps_timer {
> -	void __iomem *base_addr;
> -	struct clk *clk;
> -	struct notifier_block clk_rate_change_nb;
> -};
> -
> -#define to_xttcps_timer(x) \
> -		container_of(x, struct xttcps_timer, clk_rate_change_nb)
> -
> -struct xttcps_timer_clocksource {
> -	struct xttcps_timer	xttc;
> -	struct clocksource	cs;
> -};
> -
> -#define to_xttcps_timer_clksrc(x) \
> -		container_of(x, struct xttcps_timer_clocksource, cs)
> -
> -struct xttcps_timer_clockevent {
> -	struct xttcps_timer		xttc;
> -	struct clock_event_device	ce;
> -};
> -
> -#define to_xttcps_timer_clkevent(x) \
> -		container_of(x, struct xttcps_timer_clockevent, ce)
> -
> -/**
> - * xttcps_set_interval - Set the timer interval value
> - *
> - * @timer:	Pointer to the timer instance
> - * @cycles:	Timer interval ticks
> - **/
> -static void xttcps_set_interval(struct xttcps_timer *timer,
> -					unsigned long cycles)
> -{
> -	u32 ctrl_reg;
> -
> -	/* Disable the counter, set the counter value  and re-enable counter */
> -	ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> -	ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
> -	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> -
> -	__raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET);
> -
> -	/*
> -	 * Reset the counter (0x10) so that it starts from 0, one-shot
> -	 * mode makes this needed for timing to be right.
> -	 */
> -	ctrl_reg |= CNT_CNTRL_RESET;
> -	ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
> -	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> -}
> -
> -/**
> - * xttcps_clock_event_interrupt - Clock event timer interrupt handler
> - *
> - * @irq:	IRQ number of the Timer
> - * @dev_id:	void pointer to the xttcps_timer instance
> - *
> - * returns: Always IRQ_HANDLED - success
> - **/
> -static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id)
> -{
> -	struct xttcps_timer_clockevent *xttce = dev_id;
> -	struct xttcps_timer *timer = &xttce->xttc;
> -
> -	/* Acknowledge the interrupt and call event handler */
> -	__raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET);
> -
> -	xttce->ce.event_handler(&xttce->ce);
> -
> -	return IRQ_HANDLED;
> -}
> -
> -/**
> - * __xttc_clocksource_read - Reads the timer counter register
> - *
> - * returns: Current timer counter register value
> - **/
> -static cycle_t __xttc_clocksource_read(struct clocksource *cs)
> -{
> -	struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc;
> -
> -	return (cycle_t)__raw_readl(timer->base_addr +
> -				XTTCPS_COUNT_VAL_OFFSET);
> -}
> -
> -/**
> - * xttcps_set_next_event - Sets the time interval for next event
> - *
> - * @cycles:	Timer interval ticks
> - * @evt:	Address of clock event instance
> - *
> - * returns: Always 0 - success
> - **/
> -static int xttcps_set_next_event(unsigned long cycles,
> -					struct clock_event_device *evt)
> -{
> -	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
> -	struct xttcps_timer *timer = &xttce->xttc;
> -
> -	xttcps_set_interval(timer, cycles);
> -	return 0;
> -}
> -
> -/**
> - * xttcps_set_mode - Sets the mode of timer
> - *
> - * @mode:	Mode to be set
> - * @evt:	Address of clock event instance
> - **/
> -static void xttcps_set_mode(enum clock_event_mode mode,
> -					struct clock_event_device *evt)
> -{
> -	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
> -	struct xttcps_timer *timer = &xttce->xttc;
> -	u32 ctrl_reg;
> -
> -	switch (mode) {
> -	case CLOCK_EVT_MODE_PERIODIC:
> -		xttcps_set_interval(timer,
> -				DIV_ROUND_CLOSEST(clk_get_rate(xttce->xttc.clk),
> -					PRESCALE * HZ));
> -		break;
> -	case CLOCK_EVT_MODE_ONESHOT:
> -	case CLOCK_EVT_MODE_UNUSED:
> -	case CLOCK_EVT_MODE_SHUTDOWN:
> -		ctrl_reg = __raw_readl(timer->base_addr +
> -					XTTCPS_CNT_CNTRL_OFFSET);
> -		ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
> -		__raw_writel(ctrl_reg,
> -				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> -		break;
> -	case CLOCK_EVT_MODE_RESUME:
> -		ctrl_reg = __raw_readl(timer->base_addr +
> -					XTTCPS_CNT_CNTRL_OFFSET);
> -		ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
> -		__raw_writel(ctrl_reg,
> -				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> -		break;
> -	}
> -}
> -
> -static int xttcps_rate_change_clocksource_cb(struct notifier_block *nb,
> -		unsigned long event, void *data)
> -{
> -	struct clk_notifier_data *ndata = data;
> -	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
> -	struct xttcps_timer_clocksource *xttccs = container_of(xttcps,
> -			struct xttcps_timer_clocksource, xttc);
> -
> -	switch (event) {
> -	case POST_RATE_CHANGE:
> -		/*
> -		 * Do whatever is necessare to maintain a proper time base
> -		 *
> -		 * I cannot find a way to adjust the currently used clocksource
> -		 * to the new frequency. __clocksource_updatefreq_hz() sounds
> -		 * good, but does not work. Not sure what's that missing.
> -		 *
> -		 * This approach works, but triggers two clocksource switches.
> -		 * The first after unregister to clocksource jiffies. And
> -		 * another one after the register to the newly registered timer.
> -		 *
> -		 * Alternatively we could 'waste' another HW timer to ping pong
> -		 * between clock sources. That would also use one register and
> -		 * one unregister call, but only trigger one clocksource switch
> -		 * for the cost of another HW timer used by the OS.
> -		 */
> -		clocksource_unregister(&xttccs->cs);
> -		clocksource_register_hz(&xttccs->cs,
> -				ndata->new_rate / PRESCALE);
> -		/* fall through */
> -	case PRE_RATE_CHANGE:
> -	case ABORT_RATE_CHANGE:
> -	default:
> -		return NOTIFY_DONE;
> -	}
> -}
> -
> -static void __init zynq_ttc_setup_clocksource(struct clk *clk,
> -							void __iomem *base)
> -{
> -	struct xttcps_timer_clocksource *ttccs;
> -	int err;
> -
> -	ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
> -	if (WARN_ON(!ttccs))
> -		return;
> -
> -	ttccs->xttc.clk = clk;
> -
> -	err = clk_prepare_enable(ttccs->xttc.clk);
> -	if (WARN_ON(err))
> -		return;
> -
> -	ttccs->xttc.clk_rate_change_nb.notifier_call =
> -		xttcps_rate_change_clocksource_cb;
> -	ttccs->xttc.clk_rate_change_nb.next = NULL;
> -	if (clk_notifier_register(ttccs->xttc.clk,
> -				&ttccs->xttc.clk_rate_change_nb))
> -		pr_warn("Unable to register clock notifier.\n");
> -
> -	ttccs->xttc.base_addr = base;
> -	ttccs->cs.name = "xttcps_clocksource";
> -	ttccs->cs.rating = 200;
> -	ttccs->cs.read = __xttc_clocksource_read;
> -	ttccs->cs.mask = CLOCKSOURCE_MASK(16);
> -	ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
> -
> -	/*
> -	 * Setup the clock source counter to be an incrementing counter
> -	 * with no interrupt and it rolls over at 0xFFFF. Pre-scale
> -	 * it by 32 also. Let it start running now.
> -	 */
> -	__raw_writel(0x0,  ttccs->xttc.base_addr + XTTCPS_IER_OFFSET);
> -	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
> -		     ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
> -	__raw_writel(CNT_CNTRL_RESET,
> -		     ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> -
> -	err = clocksource_register_hz(&ttccs->cs,
> -			clk_get_rate(ttccs->xttc.clk) / PRESCALE);
> -	if (WARN_ON(err))
> -		return;
> -
> -}
> -
> -static int xttcps_rate_change_clockevent_cb(struct notifier_block *nb,
> -		unsigned long event, void *data)
> -{
> -	struct clk_notifier_data *ndata = data;
> -	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
> -	struct xttcps_timer_clockevent *xttcce = container_of(xttcps,
> -			struct xttcps_timer_clockevent, xttc);
> -
> -	switch (event) {
> -	case POST_RATE_CHANGE:
> -	{
> -		unsigned long flags;
> -
> -		/*
> -		 * clockevents_update_freq should be called with IRQ disabled on
> -		 * the CPU the timer provides events for. The timer we use is
> -		 * common to both CPUs, not sure if we need to run on both
> -		 * cores.
> -		 */
> -		local_irq_save(flags);
> -		clockevents_update_freq(&xttcce->ce,
> -				ndata->new_rate / PRESCALE);
> -		local_irq_restore(flags);
> -
> -		/* fall through */
> -	}
> -	case PRE_RATE_CHANGE:
> -	case ABORT_RATE_CHANGE:
> -	default:
> -		return NOTIFY_DONE;
> -	}
> -}
> -
> -static void __init zynq_ttc_setup_clockevent(struct clk *clk,
> -						void __iomem *base, u32 irq)
> -{
> -	struct xttcps_timer_clockevent *ttcce;
> -	int err;
> -
> -	ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
> -	if (WARN_ON(!ttcce))
> -		return;
> -
> -	ttcce->xttc.clk = clk;
> -
> -	err = clk_prepare_enable(ttcce->xttc.clk);
> -	if (WARN_ON(err))
> -		return;
> -
> -	ttcce->xttc.clk_rate_change_nb.notifier_call =
> -		xttcps_rate_change_clockevent_cb;
> -	ttcce->xttc.clk_rate_change_nb.next = NULL;
> -	if (clk_notifier_register(ttcce->xttc.clk,
> -				&ttcce->xttc.clk_rate_change_nb))
> -		pr_warn("Unable to register clock notifier.\n");
> -
> -	ttcce->xttc.base_addr = base;
> -	ttcce->ce.name = "xttcps_clockevent";
> -	ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
> -	ttcce->ce.set_next_event = xttcps_set_next_event;
> -	ttcce->ce.set_mode = xttcps_set_mode;
> -	ttcce->ce.rating = 200;
> -	ttcce->ce.irq = irq;
> -	ttcce->ce.cpumask = cpu_possible_mask;
> -
> -	/*
> -	 * Setup the clock event timer to be an interval timer which
> -	 * is prescaled by 32 using the interval interrupt. Leave it
> -	 * disabled for now.
> -	 */
> -	__raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> -	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
> -		     ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
> -	__raw_writel(0x1,  ttcce->xttc.base_addr + XTTCPS_IER_OFFSET);
> -
> -	err = request_irq(irq, xttcps_clock_event_interrupt,
> -			  IRQF_DISABLED | IRQF_TIMER,
> -			  ttcce->ce.name, ttcce);
> -	if (WARN_ON(err))
> -		return;
> -
> -	clockevents_config_and_register(&ttcce->ce,
> -			clk_get_rate(ttcce->xttc.clk) / PRESCALE, 1, 0xfffe);
> -}
> -
> -/**
> - * xttcps_timer_init - Initialize the timer
> - *
> - * Initializes the timer hardware and register the clock source and clock event
> - * timers with Linux kernal timer framework
> - */
> -static void __init xttcps_timer_init(struct device_node *timer)
> -{
> -	unsigned int irq;
> -	void __iomem *timer_baseaddr;
> -	struct clk *clk;
> -	static int initialized;
> -
> -	if (initialized)
> -		return;
> -
> -	initialized = 1;
> -
> -	/*
> -	 * Get the 1st Triple Timer Counter (TTC) block from the device tree
> -	 * and use it. Note that the event timer uses the interrupt and it's the
> -	 * 2nd TTC hence the irq_of_parse_and_map(,1)
> -	 */
> -	timer_baseaddr = of_iomap(timer, 0);
> -	if (!timer_baseaddr) {
> -		pr_err("ERROR: invalid timer base address\n");
> -		BUG();
> -	}
> -
> -	irq = irq_of_parse_and_map(timer, 1);
> -	if (irq <= 0) {
> -		pr_err("ERROR: invalid interrupt number\n");
> -		BUG();
> -	}
> -
> -	clk = of_clk_get_by_name(timer, "cpu_1x");
> -	if (IS_ERR(clk)) {
> -		pr_err("ERROR: timer input clock not found\n");
> -		BUG();
> -	}
> -
> -	zynq_ttc_setup_clocksource(clk, timer_baseaddr);
> -	zynq_ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
> -
> -	pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
> -}
> -
> -CLOCKSOURCE_OF_DECLARE(zynq, "xlnx,ttc", xttcps_timer_init);
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 4d8283a..665af7f 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
>  obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o
>  obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o
>  obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o
> +obj-$(CONFIG_ARCH_ZYNQ)		+= zynq_timer.o
>  
>  obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
>  obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
> diff --git a/drivers/clocksource/zynq_timer.c b/drivers/clocksource/zynq_timer.c
> new file mode 100644
> index 0000000..3b1faed
> --- /dev/null
> +++ b/drivers/clocksource/zynq_timer.c
> @@ -0,0 +1,430 @@
> +/*
> + * This file contains driver for the Xilinx PS Timer Counter IP.
> + *
> + *  Copyright (C) 2011 Xilinx
> + *
> + * based on arch/mips/kernel/time.c timer driver
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/clockchips.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +#include <linux/clk-provider.h>
> +
> +/*
> + * This driver configures the 2 16-bit count-up timers as follows:
> + *
> + * T1: Timer 1, clocksource for generic timekeeping
> + * T2: Timer 2, clockevent source for hrtimers
> + * T3: Timer 3, <unused>
> + *
> + * The input frequency to the timer module for emulation is 2.5MHz which is
> + * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
> + * the timers are clocked at 78.125KHz (12.8 us resolution).
> +
> + * The input frequency to the timer module in silicon is configurable and
> + * obtained from device tree. The pre-scaler of 32 is used.
> + */
> +
> +/*
> + * Timer Register Offset Definitions of Timer 1, Increment base address by 4
> + * and use same offsets for Timer 2
> + */
> +#define XTTCPS_CLK_CNTRL_OFFSET		0x00 /* Clock Control Reg, RW */
> +#define XTTCPS_CNT_CNTRL_OFFSET		0x0C /* Counter Control Reg, RW */
> +#define XTTCPS_COUNT_VAL_OFFSET		0x18 /* Counter Value Reg, RO */
> +#define XTTCPS_INTR_VAL_OFFSET		0x24 /* Interval Count Reg, RW */
> +#define XTTCPS_ISR_OFFSET		0x54 /* Interrupt Status Reg, RO */
> +#define XTTCPS_IER_OFFSET		0x60 /* Interrupt Enable Reg, RW */
> +
> +#define XTTCPS_CNT_CNTRL_DISABLE_MASK	0x1
> +
> +/*
> + * Setup the timers to use pre-scaling, using a fixed value for now that will
> + * work across most input frequency, but it may need to be more dynamic
> + */
> +#define PRESCALE_EXPONENT	11	/* 2 ^ PRESCALE_EXPONENT = PRESCALE */
> +#define PRESCALE		2048	/* The exponent must match this */
> +#define CLK_CNTRL_PRESCALE	((PRESCALE_EXPONENT - 1) << 1)
> +#define CLK_CNTRL_PRESCALE_EN	1
> +#define CNT_CNTRL_RESET		(1 << 4)
> +
> +/**
> + * struct xttcps_timer - This definition defines local timer structure
> + *
> + * @base_addr:	Base address of timer
> + * @clk:	Associated clock source
> + * @clk_rate_change_nb	Notifier block for clock rate changes
> + */
> +struct xttcps_timer {
> +	void __iomem *base_addr;
> +	struct clk *clk;
> +	struct notifier_block clk_rate_change_nb;
> +};
> +
> +#define to_xttcps_timer(x) \
> +		container_of(x, struct xttcps_timer, clk_rate_change_nb)
> +
> +struct xttcps_timer_clocksource {
> +	struct xttcps_timer	xttc;
> +	struct clocksource	cs;
> +};
> +
> +#define to_xttcps_timer_clksrc(x) \
> +		container_of(x, struct xttcps_timer_clocksource, cs)
> +
> +struct xttcps_timer_clockevent {
> +	struct xttcps_timer		xttc;
> +	struct clock_event_device	ce;
> +};
> +
> +#define to_xttcps_timer_clkevent(x) \
> +		container_of(x, struct xttcps_timer_clockevent, ce)
> +
> +/**
> + * xttcps_set_interval - Set the timer interval value
> + *
> + * @timer:	Pointer to the timer instance
> + * @cycles:	Timer interval ticks
> + **/
> +static void xttcps_set_interval(struct xttcps_timer *timer,
> +					unsigned long cycles)
> +{
> +	u32 ctrl_reg;
> +
> +	/* Disable the counter, set the counter value  and re-enable counter */
> +	ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> +	ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
> +	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> +
> +	__raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET);
> +
> +	/*
> +	 * Reset the counter (0x10) so that it starts from 0, one-shot
> +	 * mode makes this needed for timing to be right.
> +	 */
> +	ctrl_reg |= CNT_CNTRL_RESET;
> +	ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
> +	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> +}
> +
> +/**
> + * xttcps_clock_event_interrupt - Clock event timer interrupt handler
> + *
> + * @irq:	IRQ number of the Timer
> + * @dev_id:	void pointer to the xttcps_timer instance
> + *
> + * returns: Always IRQ_HANDLED - success
> + **/
> +static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id)
> +{
> +	struct xttcps_timer_clockevent *xttce = dev_id;
> +	struct xttcps_timer *timer = &xttce->xttc;
> +
> +	/* Acknowledge the interrupt and call event handler */
> +	__raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET);
> +
> +	xttce->ce.event_handler(&xttce->ce);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/**
> + * __xttc_clocksource_read - Reads the timer counter register
> + *
> + * returns: Current timer counter register value
> + **/
> +static cycle_t __xttc_clocksource_read(struct clocksource *cs)
> +{
> +	struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc;
> +
> +	return (cycle_t)__raw_readl(timer->base_addr +
> +				XTTCPS_COUNT_VAL_OFFSET);
> +}
> +
> +/**
> + * xttcps_set_next_event - Sets the time interval for next event
> + *
> + * @cycles:	Timer interval ticks
> + * @evt:	Address of clock event instance
> + *
> + * returns: Always 0 - success
> + **/
> +static int xttcps_set_next_event(unsigned long cycles,
> +					struct clock_event_device *evt)
> +{
> +	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
> +	struct xttcps_timer *timer = &xttce->xttc;
> +
> +	xttcps_set_interval(timer, cycles);
> +	return 0;
> +}
> +
> +/**
> + * xttcps_set_mode - Sets the mode of timer
> + *
> + * @mode:	Mode to be set
> + * @evt:	Address of clock event instance
> + **/
> +static void xttcps_set_mode(enum clock_event_mode mode,
> +					struct clock_event_device *evt)
> +{
> +	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
> +	struct xttcps_timer *timer = &xttce->xttc;
> +	u32 ctrl_reg;
> +
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		xttcps_set_interval(timer,
> +				DIV_ROUND_CLOSEST(clk_get_rate(xttce->xttc.clk),
> +					PRESCALE * HZ));
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +		ctrl_reg = __raw_readl(timer->base_addr +
> +					XTTCPS_CNT_CNTRL_OFFSET);
> +		ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
> +		__raw_writel(ctrl_reg,
> +				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> +		break;
> +	case CLOCK_EVT_MODE_RESUME:
> +		ctrl_reg = __raw_readl(timer->base_addr +
> +					XTTCPS_CNT_CNTRL_OFFSET);
> +		ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
> +		__raw_writel(ctrl_reg,
> +				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> +		break;
> +	}
> +}
> +
> +static int xttcps_rate_change_clocksource_cb(struct notifier_block *nb,
> +		unsigned long event, void *data)
> +{
> +	struct clk_notifier_data *ndata = data;
> +	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
> +	struct xttcps_timer_clocksource *xttccs = container_of(xttcps,
> +			struct xttcps_timer_clocksource, xttc);
> +
> +	switch (event) {
> +	case POST_RATE_CHANGE:
> +		/*
> +		 * Do whatever is necessare to maintain a proper time base
------------------------------------------^ little typo

> +		 *
> +		 * I cannot find a way to adjust the currently used clocksource
> +		 * to the new frequency. __clocksource_updatefreq_hz() sounds
> +		 * good, but does not work. Not sure what's that missing.
> +		 *
> +		 * This approach works, but triggers two clocksource switches.
> +		 * The first after unregister to clocksource jiffies. And
> +		 * another one after the register to the newly registered timer.
> +		 *
> +		 * Alternatively we could 'waste' another HW timer to ping pong
> +		 * between clock sources. That would also use one register and
> +		 * one unregister call, but only trigger one clocksource switch
> +		 * for the cost of another HW timer used by the OS.
> +		 */
> +		clocksource_unregister(&xttccs->cs);
> +		clocksource_register_hz(&xttccs->cs,
> +				ndata->new_rate / PRESCALE);
> +		/* fall through */
> +	case PRE_RATE_CHANGE:
> +	case ABORT_RATE_CHANGE:
> +	default:
> +		return NOTIFY_DONE;
> +	}
> +}
> +
> +static void __init zynq_ttc_setup_clocksource(struct clk *clk,
> +							void __iomem *base)
> +{
> +	struct xttcps_timer_clocksource *ttccs;
> +	int err;
> +
> +	ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
> +	if (WARN_ON(!ttccs))
> +		return;
> +
> +	ttccs->xttc.clk = clk;
> +
> +	err = clk_prepare_enable(ttccs->xttc.clk);
> +	if (WARN_ON(err))
> +		return;

I think you are losing memory here...

> +
> +	ttccs->xttc.clk_rate_change_nb.notifier_call =
> +		xttcps_rate_change_clocksource_cb;
> +	ttccs->xttc.clk_rate_change_nb.next = NULL;
> +	if (clk_notifier_register(ttccs->xttc.clk,
> +				&ttccs->xttc.clk_rate_change_nb))
> +		pr_warn("Unable to register clock notifier.\n");
> +
> +	ttccs->xttc.base_addr = base;
> +	ttccs->cs.name = "xttcps_clocksource";
> +	ttccs->cs.rating = 200;
> +	ttccs->cs.read = __xttc_clocksource_read;
> +	ttccs->cs.mask = CLOCKSOURCE_MASK(16);
> +	ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
> +
> +	/*
> +	 * Setup the clock source counter to be an incrementing counter
> +	 * with no interrupt and it rolls over at 0xFFFF. Pre-scale
> +	 * it by 32 also. Let it start running now.
> +	 */
> +	__raw_writel(0x0,  ttccs->xttc.base_addr + XTTCPS_IER_OFFSET);
> +	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
> +		     ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
> +	__raw_writel(CNT_CNTRL_RESET,
> +		     ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> +
> +	err = clocksource_register_hz(&ttccs->cs,
> +			clk_get_rate(ttccs->xttc.clk) / PRESCALE);
> +	if (WARN_ON(err))
> +		return;
... and here and below in zynq_ttc_setup_clockevent the same.
> +
> +}
> +
> +static int xttcps_rate_change_clockevent_cb(struct notifier_block *nb,
> +		unsigned long event, void *data)
> +{
> +	struct clk_notifier_data *ndata = data;
> +	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
> +	struct xttcps_timer_clockevent *xttcce = container_of(xttcps,
> +			struct xttcps_timer_clockevent, xttc);
> +
> +	switch (event) {
> +	case POST_RATE_CHANGE:
> +	{
> +		unsigned long flags;
> +
> +		/*
> +		 * clockevents_update_freq should be called with IRQ disabled on
> +		 * the CPU the timer provides events for. The timer we use is
> +		 * common to both CPUs, not sure if we need to run on both
> +		 * cores.
> +		 */
> +		local_irq_save(flags);
> +		clockevents_update_freq(&xttcce->ce,
> +				ndata->new_rate / PRESCALE);
> +		local_irq_restore(flags);
> +
> +		/* fall through */
> +	}
> +	case PRE_RATE_CHANGE:
> +	case ABORT_RATE_CHANGE:
> +	default:
> +		return NOTIFY_DONE;
> +	}
> +}
> +
> +static void __init zynq_ttc_setup_clockevent(struct clk *clk,
> +						void __iomem *base, u32 irq)
> +{
> +	struct xttcps_timer_clockevent *ttcce;
> +	int err;
> +
> +	ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
> +	if (WARN_ON(!ttcce))
> +		return;
> +
> +	ttcce->xttc.clk = clk;
> +
> +	err = clk_prepare_enable(ttcce->xttc.clk);
> +	if (WARN_ON(err))
> +		return;
> +
> +	ttcce->xttc.clk_rate_change_nb.notifier_call =
> +		xttcps_rate_change_clockevent_cb;
> +	ttcce->xttc.clk_rate_change_nb.next = NULL;
> +	if (clk_notifier_register(ttcce->xttc.clk,
> +				&ttcce->xttc.clk_rate_change_nb))
> +		pr_warn("Unable to register clock notifier.\n");
> +
> +	ttcce->xttc.base_addr = base;
> +	ttcce->ce.name = "xttcps_clockevent";
> +	ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
> +	ttcce->ce.set_next_event = xttcps_set_next_event;
> +	ttcce->ce.set_mode = xttcps_set_mode;
> +	ttcce->ce.rating = 200;
> +	ttcce->ce.irq = irq;
> +	ttcce->ce.cpumask = cpu_possible_mask;
> +
> +	/*
> +	 * Setup the clock event timer to be an interval timer which
> +	 * is prescaled by 32 using the interval interrupt. Leave it
> +	 * disabled for now.
> +	 */
> +	__raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
> +	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
> +		     ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
> +	__raw_writel(0x1,  ttcce->xttc.base_addr + XTTCPS_IER_OFFSET);
> +
> +	err = request_irq(irq, xttcps_clock_event_interrupt,
> +			  IRQF_DISABLED | IRQF_TIMER,
> +			  ttcce->ce.name, ttcce);
> +	if (WARN_ON(err))
> +		return;
> +
> +	clockevents_config_and_register(&ttcce->ce,
> +			clk_get_rate(ttcce->xttc.clk) / PRESCALE, 1, 0xfffe);
> +}
> +
> +/**
> + * xttcps_timer_init - Initialize the timer
> + *
> + * Initializes the timer hardware and register the clock source and clock event
> + * timers with Linux kernal timer framework
> + */
> +static void __init xttcps_timer_init(struct device_node *timer)
> +{
> +	unsigned int irq;
> +	void __iomem *timer_baseaddr;
> +	struct clk *clk;
> +	static int initialized;
> +
> +	if (initialized)
> +		return;
> +
> +	initialized = 1;
> +
??? This looks very strange ???
I think this should be handled in a different manner.
> +	/*
> +	 * Get the 1st Triple Timer Counter (TTC) block from the device tree
> +	 * and use it. Note that the event timer uses the interrupt and it's the
> +	 * 2nd TTC hence the irq_of_parse_and_map(,1)
> +	 */
> +	timer_baseaddr = of_iomap(timer, 0);
> +	if (!timer_baseaddr) {
> +		pr_err("ERROR: invalid timer base address\n");
> +		BUG();
> +	}
> +
> +	irq = irq_of_parse_and_map(timer, 1);
> +	if (irq <= 0) {
> +		pr_err("ERROR: invalid interrupt number\n");
> +		BUG();
> +	}
> +
> +	clk = of_clk_get_by_name(timer, "cpu_1x");
> +	if (IS_ERR(clk)) {
> +		pr_err("ERROR: timer input clock not found\n");
> +		BUG();
> +	}
> +
> +	zynq_ttc_setup_clocksource(clk, timer_baseaddr);
> +	zynq_ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
> +
> +	pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
> +}
> +
> +CLOCKSOURCE_OF_DECLARE(zynq, "xlnx,ttc", xttcps_timer_init);

What if do not want to use the ttc as clocksource and therefore don't want it
enabled? I still have the smp_twd which I might prefere.

Regards,
Steffen
Michal Simek March 25, 2013, 4:24 p.m. UTC | #2
2013/3/25 Steffen Trumtrar <s.trumtrar@pengutronix.de>:
> Hi Michal!
>
> On Mon, Mar 25, 2013 at 02:53:09PM +0100, Michal Simek wrote:
>> Move zynq timer out of mach folder to generic location.
>>
>> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>> ---
>> Arnd: This is the last patch as we discuss about moving
>> this timer to generic location.
>>
>> It depends on ARCH_ZYNQ as Tegra and others.
>> It should be ok to use it or we can use different name if you like.
>> ---
>
> Moving out of mach-zynq is good, because this is a
>         Cadence Rev06 Triple Timer Counter (see Zynq-7000 TRM page 25)
> Which leads me to a proposed rename to: cadence_timer.c or something like that.
> And the fn-names should be changed accordingly while at it.

Agree. Let me do one middle patch which will just remove all zynq reference
before we can move it to generic location.


>>  arch/arm/mach-zynq/Makefile      |    2 +-
>>  arch/arm/mach-zynq/timer.c       |  430 --------------------------------------
>>  drivers/clocksource/Makefile     |    1 +
>>  drivers/clocksource/zynq_timer.c |  430 ++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 432 insertions(+), 431 deletions(-)
>>  delete mode 100644 arch/arm/mach-zynq/timer.c
>>  create mode 100644 drivers/clocksource/zynq_timer.c
>>
>> diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
>> index 397268c..320faed 100644
>> --- a/arch/arm/mach-zynq/Makefile
>> +++ b/arch/arm/mach-zynq/Makefile
>> @@ -3,4 +3,4 @@
>>  #
>>
>>  # Common support
>> -obj-y                                := common.o timer.o
>> +obj-y                                := common.o
>> diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c
>> deleted file mode 100644
>> index 3b1faed..0000000
>> --- a/arch/arm/mach-zynq/timer.c
>> +++ /dev/null
>> @@ -1,430 +0,0 @@
>> -/*
>> - * This file contains driver for the Xilinx PS Timer Counter IP.
>> - *
>> - *  Copyright (C) 2011 Xilinx
>> - *
>> - * based on arch/mips/kernel/time.c timer driver
>> - *
>> - * This software is licensed under the terms of the GNU General Public
>> - * License version 2, as published by the Free Software Foundation, and
>> - * may be copied, distributed, and modified under those terms.
>> - *
>> - * This program is distributed in the hope that it will be useful,
>> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> - * GNU General Public License for more details.
>> - */
>> -
>> -#include <linux/clk.h>
>> -#include <linux/interrupt.h>
>> -#include <linux/clockchips.h>
>> -#include <linux/of_address.h>
>> -#include <linux/of_irq.h>
>> -#include <linux/slab.h>
>> -#include <linux/clk-provider.h>
>> -
>> -/*
>> - * This driver configures the 2 16-bit count-up timers as follows:
>> - *
>> - * T1: Timer 1, clocksource for generic timekeeping
>> - * T2: Timer 2, clockevent source for hrtimers
>> - * T3: Timer 3, <unused>
>> - *
>> - * The input frequency to the timer module for emulation is 2.5MHz which is
>> - * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
>> - * the timers are clocked at 78.125KHz (12.8 us resolution).
>> -
>> - * The input frequency to the timer module in silicon is configurable and
>> - * obtained from device tree. The pre-scaler of 32 is used.
>> - */
>> -
>> -/*
>> - * Timer Register Offset Definitions of Timer 1, Increment base address by 4
>> - * and use same offsets for Timer 2
>> - */
>> -#define XTTCPS_CLK_CNTRL_OFFSET              0x00 /* Clock Control Reg, RW */
>> -#define XTTCPS_CNT_CNTRL_OFFSET              0x0C /* Counter Control Reg, RW */
>> -#define XTTCPS_COUNT_VAL_OFFSET              0x18 /* Counter Value Reg, RO */
>> -#define XTTCPS_INTR_VAL_OFFSET               0x24 /* Interval Count Reg, RW */
>> -#define XTTCPS_ISR_OFFSET            0x54 /* Interrupt Status Reg, RO */
>> -#define XTTCPS_IER_OFFSET            0x60 /* Interrupt Enable Reg, RW */
>> -
>> -#define XTTCPS_CNT_CNTRL_DISABLE_MASK        0x1
>> -
>> -/*
>> - * Setup the timers to use pre-scaling, using a fixed value for now that will
>> - * work across most input frequency, but it may need to be more dynamic
>> - */
>> -#define PRESCALE_EXPONENT    11      /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
>> -#define PRESCALE             2048    /* The exponent must match this */
>> -#define CLK_CNTRL_PRESCALE   ((PRESCALE_EXPONENT - 1) << 1)
>> -#define CLK_CNTRL_PRESCALE_EN        1
>> -#define CNT_CNTRL_RESET              (1 << 4)
>> -
>> -/**
>> - * struct xttcps_timer - This definition defines local timer structure
>> - *
>> - * @base_addr:       Base address of timer
>> - * @clk:     Associated clock source
>> - * @clk_rate_change_nb       Notifier block for clock rate changes
>> - */
>> -struct xttcps_timer {
>> -     void __iomem *base_addr;
>> -     struct clk *clk;
>> -     struct notifier_block clk_rate_change_nb;
>> -};
>> -
>> -#define to_xttcps_timer(x) \
>> -             container_of(x, struct xttcps_timer, clk_rate_change_nb)
>> -
>> -struct xttcps_timer_clocksource {
>> -     struct xttcps_timer     xttc;
>> -     struct clocksource      cs;
>> -};
>> -
>> -#define to_xttcps_timer_clksrc(x) \
>> -             container_of(x, struct xttcps_timer_clocksource, cs)
>> -
>> -struct xttcps_timer_clockevent {
>> -     struct xttcps_timer             xttc;
>> -     struct clock_event_device       ce;
>> -};
>> -
>> -#define to_xttcps_timer_clkevent(x) \
>> -             container_of(x, struct xttcps_timer_clockevent, ce)
>> -
>> -/**
>> - * xttcps_set_interval - Set the timer interval value
>> - *
>> - * @timer:   Pointer to the timer instance
>> - * @cycles:  Timer interval ticks
>> - **/
>> -static void xttcps_set_interval(struct xttcps_timer *timer,
>> -                                     unsigned long cycles)
>> -{
>> -     u32 ctrl_reg;
>> -
>> -     /* Disable the counter, set the counter value  and re-enable counter */
>> -     ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> -     ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> -     __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> -
>> -     __raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET);
>> -
>> -     /*
>> -      * Reset the counter (0x10) so that it starts from 0, one-shot
>> -      * mode makes this needed for timing to be right.
>> -      */
>> -     ctrl_reg |= CNT_CNTRL_RESET;
>> -     ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> -     __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> -}
>> -
>> -/**
>> - * xttcps_clock_event_interrupt - Clock event timer interrupt handler
>> - *
>> - * @irq:     IRQ number of the Timer
>> - * @dev_id:  void pointer to the xttcps_timer instance
>> - *
>> - * returns: Always IRQ_HANDLED - success
>> - **/
>> -static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id)
>> -{
>> -     struct xttcps_timer_clockevent *xttce = dev_id;
>> -     struct xttcps_timer *timer = &xttce->xttc;
>> -
>> -     /* Acknowledge the interrupt and call event handler */
>> -     __raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET);
>> -
>> -     xttce->ce.event_handler(&xttce->ce);
>> -
>> -     return IRQ_HANDLED;
>> -}
>> -
>> -/**
>> - * __xttc_clocksource_read - Reads the timer counter register
>> - *
>> - * returns: Current timer counter register value
>> - **/
>> -static cycle_t __xttc_clocksource_read(struct clocksource *cs)
>> -{
>> -     struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc;
>> -
>> -     return (cycle_t)__raw_readl(timer->base_addr +
>> -                             XTTCPS_COUNT_VAL_OFFSET);
>> -}
>> -
>> -/**
>> - * xttcps_set_next_event - Sets the time interval for next event
>> - *
>> - * @cycles:  Timer interval ticks
>> - * @evt:     Address of clock event instance
>> - *
>> - * returns: Always 0 - success
>> - **/
>> -static int xttcps_set_next_event(unsigned long cycles,
>> -                                     struct clock_event_device *evt)
>> -{
>> -     struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
>> -     struct xttcps_timer *timer = &xttce->xttc;
>> -
>> -     xttcps_set_interval(timer, cycles);
>> -     return 0;
>> -}
>> -
>> -/**
>> - * xttcps_set_mode - Sets the mode of timer
>> - *
>> - * @mode:    Mode to be set
>> - * @evt:     Address of clock event instance
>> - **/
>> -static void xttcps_set_mode(enum clock_event_mode mode,
>> -                                     struct clock_event_device *evt)
>> -{
>> -     struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
>> -     struct xttcps_timer *timer = &xttce->xttc;
>> -     u32 ctrl_reg;
>> -
>> -     switch (mode) {
>> -     case CLOCK_EVT_MODE_PERIODIC:
>> -             xttcps_set_interval(timer,
>> -                             DIV_ROUND_CLOSEST(clk_get_rate(xttce->xttc.clk),
>> -                                     PRESCALE * HZ));
>> -             break;
>> -     case CLOCK_EVT_MODE_ONESHOT:
>> -     case CLOCK_EVT_MODE_UNUSED:
>> -     case CLOCK_EVT_MODE_SHUTDOWN:
>> -             ctrl_reg = __raw_readl(timer->base_addr +
>> -                                     XTTCPS_CNT_CNTRL_OFFSET);
>> -             ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> -             __raw_writel(ctrl_reg,
>> -                             timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> -             break;
>> -     case CLOCK_EVT_MODE_RESUME:
>> -             ctrl_reg = __raw_readl(timer->base_addr +
>> -                                     XTTCPS_CNT_CNTRL_OFFSET);
>> -             ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> -             __raw_writel(ctrl_reg,
>> -                             timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> -             break;
>> -     }
>> -}
>> -
>> -static int xttcps_rate_change_clocksource_cb(struct notifier_block *nb,
>> -             unsigned long event, void *data)
>> -{
>> -     struct clk_notifier_data *ndata = data;
>> -     struct xttcps_timer *xttcps = to_xttcps_timer(nb);
>> -     struct xttcps_timer_clocksource *xttccs = container_of(xttcps,
>> -                     struct xttcps_timer_clocksource, xttc);
>> -
>> -     switch (event) {
>> -     case POST_RATE_CHANGE:
>> -             /*
>> -              * Do whatever is necessare to maintain a proper time base
>> -              *
>> -              * I cannot find a way to adjust the currently used clocksource
>> -              * to the new frequency. __clocksource_updatefreq_hz() sounds
>> -              * good, but does not work. Not sure what's that missing.
>> -              *
>> -              * This approach works, but triggers two clocksource switches.
>> -              * The first after unregister to clocksource jiffies. And
>> -              * another one after the register to the newly registered timer.
>> -              *
>> -              * Alternatively we could 'waste' another HW timer to ping pong
>> -              * between clock sources. That would also use one register and
>> -              * one unregister call, but only trigger one clocksource switch
>> -              * for the cost of another HW timer used by the OS.
>> -              */
>> -             clocksource_unregister(&xttccs->cs);
>> -             clocksource_register_hz(&xttccs->cs,
>> -                             ndata->new_rate / PRESCALE);
>> -             /* fall through */
>> -     case PRE_RATE_CHANGE:
>> -     case ABORT_RATE_CHANGE:
>> -     default:
>> -             return NOTIFY_DONE;
>> -     }
>> -}
>> -
>> -static void __init zynq_ttc_setup_clocksource(struct clk *clk,
>> -                                                     void __iomem *base)
>> -{
>> -     struct xttcps_timer_clocksource *ttccs;
>> -     int err;
>> -
>> -     ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
>> -     if (WARN_ON(!ttccs))
>> -             return;
>> -
>> -     ttccs->xttc.clk = clk;
>> -
>> -     err = clk_prepare_enable(ttccs->xttc.clk);
>> -     if (WARN_ON(err))
>> -             return;
>> -
>> -     ttccs->xttc.clk_rate_change_nb.notifier_call =
>> -             xttcps_rate_change_clocksource_cb;
>> -     ttccs->xttc.clk_rate_change_nb.next = NULL;
>> -     if (clk_notifier_register(ttccs->xttc.clk,
>> -                             &ttccs->xttc.clk_rate_change_nb))
>> -             pr_warn("Unable to register clock notifier.\n");
>> -
>> -     ttccs->xttc.base_addr = base;
>> -     ttccs->cs.name = "xttcps_clocksource";
>> -     ttccs->cs.rating = 200;
>> -     ttccs->cs.read = __xttc_clocksource_read;
>> -     ttccs->cs.mask = CLOCKSOURCE_MASK(16);
>> -     ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
>> -
>> -     /*
>> -      * Setup the clock source counter to be an incrementing counter
>> -      * with no interrupt and it rolls over at 0xFFFF. Pre-scale
>> -      * it by 32 also. Let it start running now.
>> -      */
>> -     __raw_writel(0x0,  ttccs->xttc.base_addr + XTTCPS_IER_OFFSET);
>> -     __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
>> -                  ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
>> -     __raw_writel(CNT_CNTRL_RESET,
>> -                  ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> -
>> -     err = clocksource_register_hz(&ttccs->cs,
>> -                     clk_get_rate(ttccs->xttc.clk) / PRESCALE);
>> -     if (WARN_ON(err))
>> -             return;
>> -
>> -}
>> -
>> -static int xttcps_rate_change_clockevent_cb(struct notifier_block *nb,
>> -             unsigned long event, void *data)
>> -{
>> -     struct clk_notifier_data *ndata = data;
>> -     struct xttcps_timer *xttcps = to_xttcps_timer(nb);
>> -     struct xttcps_timer_clockevent *xttcce = container_of(xttcps,
>> -                     struct xttcps_timer_clockevent, xttc);
>> -
>> -     switch (event) {
>> -     case POST_RATE_CHANGE:
>> -     {
>> -             unsigned long flags;
>> -
>> -             /*
>> -              * clockevents_update_freq should be called with IRQ disabled on
>> -              * the CPU the timer provides events for. The timer we use is
>> -              * common to both CPUs, not sure if we need to run on both
>> -              * cores.
>> -              */
>> -             local_irq_save(flags);
>> -             clockevents_update_freq(&xttcce->ce,
>> -                             ndata->new_rate / PRESCALE);
>> -             local_irq_restore(flags);
>> -
>> -             /* fall through */
>> -     }
>> -     case PRE_RATE_CHANGE:
>> -     case ABORT_RATE_CHANGE:
>> -     default:
>> -             return NOTIFY_DONE;
>> -     }
>> -}
>> -
>> -static void __init zynq_ttc_setup_clockevent(struct clk *clk,
>> -                                             void __iomem *base, u32 irq)
>> -{
>> -     struct xttcps_timer_clockevent *ttcce;
>> -     int err;
>> -
>> -     ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
>> -     if (WARN_ON(!ttcce))
>> -             return;
>> -
>> -     ttcce->xttc.clk = clk;
>> -
>> -     err = clk_prepare_enable(ttcce->xttc.clk);
>> -     if (WARN_ON(err))
>> -             return;
>> -
>> -     ttcce->xttc.clk_rate_change_nb.notifier_call =
>> -             xttcps_rate_change_clockevent_cb;
>> -     ttcce->xttc.clk_rate_change_nb.next = NULL;
>> -     if (clk_notifier_register(ttcce->xttc.clk,
>> -                             &ttcce->xttc.clk_rate_change_nb))
>> -             pr_warn("Unable to register clock notifier.\n");
>> -
>> -     ttcce->xttc.base_addr = base;
>> -     ttcce->ce.name = "xttcps_clockevent";
>> -     ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
>> -     ttcce->ce.set_next_event = xttcps_set_next_event;
>> -     ttcce->ce.set_mode = xttcps_set_mode;
>> -     ttcce->ce.rating = 200;
>> -     ttcce->ce.irq = irq;
>> -     ttcce->ce.cpumask = cpu_possible_mask;
>> -
>> -     /*
>> -      * Setup the clock event timer to be an interval timer which
>> -      * is prescaled by 32 using the interval interrupt. Leave it
>> -      * disabled for now.
>> -      */
>> -     __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> -     __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
>> -                  ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
>> -     __raw_writel(0x1,  ttcce->xttc.base_addr + XTTCPS_IER_OFFSET);
>> -
>> -     err = request_irq(irq, xttcps_clock_event_interrupt,
>> -                       IRQF_DISABLED | IRQF_TIMER,
>> -                       ttcce->ce.name, ttcce);
>> -     if (WARN_ON(err))
>> -             return;
>> -
>> -     clockevents_config_and_register(&ttcce->ce,
>> -                     clk_get_rate(ttcce->xttc.clk) / PRESCALE, 1, 0xfffe);
>> -}
>> -
>> -/**
>> - * xttcps_timer_init - Initialize the timer
>> - *
>> - * Initializes the timer hardware and register the clock source and clock event
>> - * timers with Linux kernal timer framework
>> - */
>> -static void __init xttcps_timer_init(struct device_node *timer)
>> -{
>> -     unsigned int irq;
>> -     void __iomem *timer_baseaddr;
>> -     struct clk *clk;
>> -     static int initialized;
>> -
>> -     if (initialized)
>> -             return;
>> -
>> -     initialized = 1;
>> -
>> -     /*
>> -      * Get the 1st Triple Timer Counter (TTC) block from the device tree
>> -      * and use it. Note that the event timer uses the interrupt and it's the
>> -      * 2nd TTC hence the irq_of_parse_and_map(,1)
>> -      */
>> -     timer_baseaddr = of_iomap(timer, 0);
>> -     if (!timer_baseaddr) {
>> -             pr_err("ERROR: invalid timer base address\n");
>> -             BUG();
>> -     }
>> -
>> -     irq = irq_of_parse_and_map(timer, 1);
>> -     if (irq <= 0) {
>> -             pr_err("ERROR: invalid interrupt number\n");
>> -             BUG();
>> -     }
>> -
>> -     clk = of_clk_get_by_name(timer, "cpu_1x");
>> -     if (IS_ERR(clk)) {
>> -             pr_err("ERROR: timer input clock not found\n");
>> -             BUG();
>> -     }
>> -
>> -     zynq_ttc_setup_clocksource(clk, timer_baseaddr);
>> -     zynq_ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
>> -
>> -     pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
>> -}
>> -
>> -CLOCKSOURCE_OF_DECLARE(zynq, "xlnx,ttc", xttcps_timer_init);
>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
>> index 4d8283a..665af7f 100644
>> --- a/drivers/clocksource/Makefile
>> +++ b/drivers/clocksource/Makefile
>> @@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_BCM2835)  += bcm2835_timer.o
>>  obj-$(CONFIG_SUNXI_TIMER)    += sunxi_timer.o
>>  obj-$(CONFIG_ARCH_TEGRA)     += tegra20_timer.o
>>  obj-$(CONFIG_VT8500_TIMER)   += vt8500_timer.o
>> +obj-$(CONFIG_ARCH_ZYNQ)              += zynq_timer.o
>>
>>  obj-$(CONFIG_ARM_ARCH_TIMER)         += arm_arch_timer.o
>>  obj-$(CONFIG_CLKSRC_METAG_GENERIC)   += metag_generic.o
>> diff --git a/drivers/clocksource/zynq_timer.c b/drivers/clocksource/zynq_timer.c
>> new file mode 100644
>> index 0000000..3b1faed
>> --- /dev/null
>> +++ b/drivers/clocksource/zynq_timer.c
>> @@ -0,0 +1,430 @@
>> +/*
>> + * This file contains driver for the Xilinx PS Timer Counter IP.
>> + *
>> + *  Copyright (C) 2011 Xilinx
>> + *
>> + * based on arch/mips/kernel/time.c timer driver
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/clockchips.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/slab.h>
>> +#include <linux/clk-provider.h>
>> +
>> +/*
>> + * This driver configures the 2 16-bit count-up timers as follows:
>> + *
>> + * T1: Timer 1, clocksource for generic timekeeping
>> + * T2: Timer 2, clockevent source for hrtimers
>> + * T3: Timer 3, <unused>
>> + *
>> + * The input frequency to the timer module for emulation is 2.5MHz which is
>> + * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
>> + * the timers are clocked at 78.125KHz (12.8 us resolution).
>> +
>> + * The input frequency to the timer module in silicon is configurable and
>> + * obtained from device tree. The pre-scaler of 32 is used.
>> + */
>> +
>> +/*
>> + * Timer Register Offset Definitions of Timer 1, Increment base address by 4
>> + * and use same offsets for Timer 2
>> + */
>> +#define XTTCPS_CLK_CNTRL_OFFSET              0x00 /* Clock Control Reg, RW */
>> +#define XTTCPS_CNT_CNTRL_OFFSET              0x0C /* Counter Control Reg, RW */
>> +#define XTTCPS_COUNT_VAL_OFFSET              0x18 /* Counter Value Reg, RO */
>> +#define XTTCPS_INTR_VAL_OFFSET               0x24 /* Interval Count Reg, RW */
>> +#define XTTCPS_ISR_OFFSET            0x54 /* Interrupt Status Reg, RO */
>> +#define XTTCPS_IER_OFFSET            0x60 /* Interrupt Enable Reg, RW */
>> +
>> +#define XTTCPS_CNT_CNTRL_DISABLE_MASK        0x1
>> +
>> +/*
>> + * Setup the timers to use pre-scaling, using a fixed value for now that will
>> + * work across most input frequency, but it may need to be more dynamic
>> + */
>> +#define PRESCALE_EXPONENT    11      /* 2 ^ PRESCALE_EXPONENT = PRESCALE */
>> +#define PRESCALE             2048    /* The exponent must match this */
>> +#define CLK_CNTRL_PRESCALE   ((PRESCALE_EXPONENT - 1) << 1)
>> +#define CLK_CNTRL_PRESCALE_EN        1
>> +#define CNT_CNTRL_RESET              (1 << 4)
>> +
>> +/**
>> + * struct xttcps_timer - This definition defines local timer structure
>> + *
>> + * @base_addr:       Base address of timer
>> + * @clk:     Associated clock source
>> + * @clk_rate_change_nb       Notifier block for clock rate changes
>> + */
>> +struct xttcps_timer {
>> +     void __iomem *base_addr;
>> +     struct clk *clk;
>> +     struct notifier_block clk_rate_change_nb;
>> +};
>> +
>> +#define to_xttcps_timer(x) \
>> +             container_of(x, struct xttcps_timer, clk_rate_change_nb)
>> +
>> +struct xttcps_timer_clocksource {
>> +     struct xttcps_timer     xttc;
>> +     struct clocksource      cs;
>> +};
>> +
>> +#define to_xttcps_timer_clksrc(x) \
>> +             container_of(x, struct xttcps_timer_clocksource, cs)
>> +
>> +struct xttcps_timer_clockevent {
>> +     struct xttcps_timer             xttc;
>> +     struct clock_event_device       ce;
>> +};
>> +
>> +#define to_xttcps_timer_clkevent(x) \
>> +             container_of(x, struct xttcps_timer_clockevent, ce)
>> +
>> +/**
>> + * xttcps_set_interval - Set the timer interval value
>> + *
>> + * @timer:   Pointer to the timer instance
>> + * @cycles:  Timer interval ticks
>> + **/
>> +static void xttcps_set_interval(struct xttcps_timer *timer,
>> +                                     unsigned long cycles)
>> +{
>> +     u32 ctrl_reg;
>> +
>> +     /* Disable the counter, set the counter value  and re-enable counter */
>> +     ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> +     ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> +     __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> +
>> +     __raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET);
>> +
>> +     /*
>> +      * Reset the counter (0x10) so that it starts from 0, one-shot
>> +      * mode makes this needed for timing to be right.
>> +      */
>> +     ctrl_reg |= CNT_CNTRL_RESET;
>> +     ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> +     __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> +}
>> +
>> +/**
>> + * xttcps_clock_event_interrupt - Clock event timer interrupt handler
>> + *
>> + * @irq:     IRQ number of the Timer
>> + * @dev_id:  void pointer to the xttcps_timer instance
>> + *
>> + * returns: Always IRQ_HANDLED - success
>> + **/
>> +static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id)
>> +{
>> +     struct xttcps_timer_clockevent *xttce = dev_id;
>> +     struct xttcps_timer *timer = &xttce->xttc;
>> +
>> +     /* Acknowledge the interrupt and call event handler */
>> +     __raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET);
>> +
>> +     xttce->ce.event_handler(&xttce->ce);
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +/**
>> + * __xttc_clocksource_read - Reads the timer counter register
>> + *
>> + * returns: Current timer counter register value
>> + **/
>> +static cycle_t __xttc_clocksource_read(struct clocksource *cs)
>> +{
>> +     struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc;
>> +
>> +     return (cycle_t)__raw_readl(timer->base_addr +
>> +                             XTTCPS_COUNT_VAL_OFFSET);
>> +}
>> +
>> +/**
>> + * xttcps_set_next_event - Sets the time interval for next event
>> + *
>> + * @cycles:  Timer interval ticks
>> + * @evt:     Address of clock event instance
>> + *
>> + * returns: Always 0 - success
>> + **/
>> +static int xttcps_set_next_event(unsigned long cycles,
>> +                                     struct clock_event_device *evt)
>> +{
>> +     struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
>> +     struct xttcps_timer *timer = &xttce->xttc;
>> +
>> +     xttcps_set_interval(timer, cycles);
>> +     return 0;
>> +}
>> +
>> +/**
>> + * xttcps_set_mode - Sets the mode of timer
>> + *
>> + * @mode:    Mode to be set
>> + * @evt:     Address of clock event instance
>> + **/
>> +static void xttcps_set_mode(enum clock_event_mode mode,
>> +                                     struct clock_event_device *evt)
>> +{
>> +     struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
>> +     struct xttcps_timer *timer = &xttce->xttc;
>> +     u32 ctrl_reg;
>> +
>> +     switch (mode) {
>> +     case CLOCK_EVT_MODE_PERIODIC:
>> +             xttcps_set_interval(timer,
>> +                             DIV_ROUND_CLOSEST(clk_get_rate(xttce->xttc.clk),
>> +                                     PRESCALE * HZ));
>> +             break;
>> +     case CLOCK_EVT_MODE_ONESHOT:
>> +     case CLOCK_EVT_MODE_UNUSED:
>> +     case CLOCK_EVT_MODE_SHUTDOWN:
>> +             ctrl_reg = __raw_readl(timer->base_addr +
>> +                                     XTTCPS_CNT_CNTRL_OFFSET);
>> +             ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> +             __raw_writel(ctrl_reg,
>> +                             timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> +             break;
>> +     case CLOCK_EVT_MODE_RESUME:
>> +             ctrl_reg = __raw_readl(timer->base_addr +
>> +                                     XTTCPS_CNT_CNTRL_OFFSET);
>> +             ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
>> +             __raw_writel(ctrl_reg,
>> +                             timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> +             break;
>> +     }
>> +}
>> +
>> +static int xttcps_rate_change_clocksource_cb(struct notifier_block *nb,
>> +             unsigned long event, void *data)
>> +{
>> +     struct clk_notifier_data *ndata = data;
>> +     struct xttcps_timer *xttcps = to_xttcps_timer(nb);
>> +     struct xttcps_timer_clocksource *xttccs = container_of(xttcps,
>> +                     struct xttcps_timer_clocksource, xttc);
>> +
>> +     switch (event) {
>> +     case POST_RATE_CHANGE:
>> +             /*
>> +              * Do whatever is necessare to maintain a proper time base
> ------------------------------------------^ little typo
>
>> +              *
>> +              * I cannot find a way to adjust the currently used clocksource
>> +              * to the new frequency. __clocksource_updatefreq_hz() sounds
>> +              * good, but does not work. Not sure what's that missing.
>> +              *
>> +              * This approach works, but triggers two clocksource switches.
>> +              * The first after unregister to clocksource jiffies. And
>> +              * another one after the register to the newly registered timer.
>> +              *
>> +              * Alternatively we could 'waste' another HW timer to ping pong
>> +              * between clock sources. That would also use one register and
>> +              * one unregister call, but only trigger one clocksource switch
>> +              * for the cost of another HW timer used by the OS.
>> +              */
>> +             clocksource_unregister(&xttccs->cs);
>> +             clocksource_register_hz(&xttccs->cs,
>> +                             ndata->new_rate / PRESCALE);
>> +             /* fall through */
>> +     case PRE_RATE_CHANGE:
>> +     case ABORT_RATE_CHANGE:
>> +     default:
>> +             return NOTIFY_DONE;
>> +     }
>> +}
>> +
>> +static void __init zynq_ttc_setup_clocksource(struct clk *clk,
>> +                                                     void __iomem *base)
>> +{
>> +     struct xttcps_timer_clocksource *ttccs;
>> +     int err;
>> +
>> +     ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
>> +     if (WARN_ON(!ttccs))
>> +             return;
>> +
>> +     ttccs->xttc.clk = clk;
>> +
>> +     err = clk_prepare_enable(ttccs->xttc.clk);
>> +     if (WARN_ON(err))
>> +             return;
>
> I think you are losing memory here...

right. Let's free that memory. I have pinged Soren to look if we can handle
clock better.
Till now this is only one timer in the system we have used.
Look below.

>
>> +
>> +     ttccs->xttc.clk_rate_change_nb.notifier_call =
>> +             xttcps_rate_change_clocksource_cb;
>> +     ttccs->xttc.clk_rate_change_nb.next = NULL;
>> +     if (clk_notifier_register(ttccs->xttc.clk,
>> +                             &ttccs->xttc.clk_rate_change_nb))
>> +             pr_warn("Unable to register clock notifier.\n");
>> +
>> +     ttccs->xttc.base_addr = base;
>> +     ttccs->cs.name = "xttcps_clocksource";
>> +     ttccs->cs.rating = 200;
>> +     ttccs->cs.read = __xttc_clocksource_read;
>> +     ttccs->cs.mask = CLOCKSOURCE_MASK(16);
>> +     ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
>> +
>> +     /*
>> +      * Setup the clock source counter to be an incrementing counter
>> +      * with no interrupt and it rolls over at 0xFFFF. Pre-scale
>> +      * it by 32 also. Let it start running now.
>> +      */
>> +     __raw_writel(0x0,  ttccs->xttc.base_addr + XTTCPS_IER_OFFSET);
>> +     __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
>> +                  ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
>> +     __raw_writel(CNT_CNTRL_RESET,
>> +                  ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> +
>> +     err = clocksource_register_hz(&ttccs->cs,
>> +                     clk_get_rate(ttccs->xttc.clk) / PRESCALE);
>> +     if (WARN_ON(err))
>> +             return;
> ... and here and below in zynq_ttc_setup_clockevent the same.

yep

>> +
>> +}
>> +
>> +static int xttcps_rate_change_clockevent_cb(struct notifier_block *nb,
>> +             unsigned long event, void *data)
>> +{
>> +     struct clk_notifier_data *ndata = data;
>> +     struct xttcps_timer *xttcps = to_xttcps_timer(nb);
>> +     struct xttcps_timer_clockevent *xttcce = container_of(xttcps,
>> +                     struct xttcps_timer_clockevent, xttc);
>> +
>> +     switch (event) {
>> +     case POST_RATE_CHANGE:
>> +     {
>> +             unsigned long flags;
>> +
>> +             /*
>> +              * clockevents_update_freq should be called with IRQ disabled on
>> +              * the CPU the timer provides events for. The timer we use is
>> +              * common to both CPUs, not sure if we need to run on both
>> +              * cores.
>> +              */
>> +             local_irq_save(flags);
>> +             clockevents_update_freq(&xttcce->ce,
>> +                             ndata->new_rate / PRESCALE);
>> +             local_irq_restore(flags);
>> +
>> +             /* fall through */
>> +     }
>> +     case PRE_RATE_CHANGE:
>> +     case ABORT_RATE_CHANGE:
>> +     default:
>> +             return NOTIFY_DONE;
>> +     }
>> +}
>> +
>> +static void __init zynq_ttc_setup_clockevent(struct clk *clk,
>> +                                             void __iomem *base, u32 irq)
>> +{
>> +     struct xttcps_timer_clockevent *ttcce;
>> +     int err;
>> +
>> +     ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
>> +     if (WARN_ON(!ttcce))
>> +             return;
>> +
>> +     ttcce->xttc.clk = clk;
>> +
>> +     err = clk_prepare_enable(ttcce->xttc.clk);
>> +     if (WARN_ON(err))
>> +             return;
>> +
>> +     ttcce->xttc.clk_rate_change_nb.notifier_call =
>> +             xttcps_rate_change_clockevent_cb;
>> +     ttcce->xttc.clk_rate_change_nb.next = NULL;
>> +     if (clk_notifier_register(ttcce->xttc.clk,
>> +                             &ttcce->xttc.clk_rate_change_nb))
>> +             pr_warn("Unable to register clock notifier.\n");
>> +
>> +     ttcce->xttc.base_addr = base;
>> +     ttcce->ce.name = "xttcps_clockevent";
>> +     ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
>> +     ttcce->ce.set_next_event = xttcps_set_next_event;
>> +     ttcce->ce.set_mode = xttcps_set_mode;
>> +     ttcce->ce.rating = 200;
>> +     ttcce->ce.irq = irq;
>> +     ttcce->ce.cpumask = cpu_possible_mask;
>> +
>> +     /*
>> +      * Setup the clock event timer to be an interval timer which
>> +      * is prescaled by 32 using the interval interrupt. Leave it
>> +      * disabled for now.
>> +      */
>> +     __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
>> +     __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
>> +                  ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
>> +     __raw_writel(0x1,  ttcce->xttc.base_addr + XTTCPS_IER_OFFSET);
>> +
>> +     err = request_irq(irq, xttcps_clock_event_interrupt,
>> +                       IRQF_DISABLED | IRQF_TIMER,
>> +                       ttcce->ce.name, ttcce);
>> +     if (WARN_ON(err))
>> +             return;
>> +
>> +     clockevents_config_and_register(&ttcce->ce,
>> +                     clk_get_rate(ttcce->xttc.clk) / PRESCALE, 1, 0xfffe);
>> +}
>> +
>> +/**
>> + * xttcps_timer_init - Initialize the timer
>> + *
>> + * Initializes the timer hardware and register the clock source and clock event
>> + * timers with Linux kernal timer framework
>> + */
>> +static void __init xttcps_timer_init(struct device_node *timer)
>> +{
>> +     unsigned int irq;
>> +     void __iomem *timer_baseaddr;
>> +     struct clk *clk;
>> +     static int initialized;
>> +
>> +     if (initialized)
>> +             return;
>> +
>> +     initialized = 1;
>> +
> ??? This looks very strange ???
> I think this should be handled in a different manner.

Feel free to propose better solution. Because there are two ttc in the
system and the first
is taken, second shouldn't be initialized as clocksource or clockevent.

>> +     /*
>> +      * Get the 1st Triple Timer Counter (TTC) block from the device tree
>> +      * and use it. Note that the event timer uses the interrupt and it's the
>> +      * 2nd TTC hence the irq_of_parse_and_map(,1)
>> +      */
>> +     timer_baseaddr = of_iomap(timer, 0);
>> +     if (!timer_baseaddr) {
>> +             pr_err("ERROR: invalid timer base address\n");
>> +             BUG();
>> +     }
>> +
>> +     irq = irq_of_parse_and_map(timer, 1);
>> +     if (irq <= 0) {
>> +             pr_err("ERROR: invalid interrupt number\n");
>> +             BUG();
>> +     }
>> +
>> +     clk = of_clk_get_by_name(timer, "cpu_1x");
>> +     if (IS_ERR(clk)) {
>> +             pr_err("ERROR: timer input clock not found\n");
>> +             BUG();
>> +     }
>> +
>> +     zynq_ttc_setup_clocksource(clk, timer_baseaddr);
>> +     zynq_ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
>> +
>> +     pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
>> +}
>> +
>> +CLOCKSOURCE_OF_DECLARE(zynq, "xlnx,ttc", xttcps_timer_init);
>
> What if do not want to use the ttc as clocksource and therefore don't want it
> enabled? I still have the smp_twd which I might prefere.

Renaming this to cadence name we will have to change dt name to more generic
one cdns,ttc? Also we should probably add it to Kconfig.

IRC: If there is not compatible string kernel will try to find out
different one.
If you find some of them the more precise one is used. It is quite long time
I was playing with it.

Thanks,
Michal
diff mbox

Patch

diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
index 397268c..320faed 100644
--- a/arch/arm/mach-zynq/Makefile
+++ b/arch/arm/mach-zynq/Makefile
@@ -3,4 +3,4 @@ 
 #
 
 # Common support
-obj-y				:= common.o timer.o
+obj-y				:= common.o
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c
deleted file mode 100644
index 3b1faed..0000000
--- a/arch/arm/mach-zynq/timer.c
+++ /dev/null
@@ -1,430 +0,0 @@ 
-/*
- * This file contains driver for the Xilinx PS Timer Counter IP.
- *
- *  Copyright (C) 2011 Xilinx
- *
- * based on arch/mips/kernel/time.c timer driver
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/slab.h>
-#include <linux/clk-provider.h>
-
-/*
- * This driver configures the 2 16-bit count-up timers as follows:
- *
- * T1: Timer 1, clocksource for generic timekeeping
- * T2: Timer 2, clockevent source for hrtimers
- * T3: Timer 3, <unused>
- *
- * The input frequency to the timer module for emulation is 2.5MHz which is
- * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
- * the timers are clocked at 78.125KHz (12.8 us resolution).
-
- * The input frequency to the timer module in silicon is configurable and
- * obtained from device tree. The pre-scaler of 32 is used.
- */
-
-/*
- * Timer Register Offset Definitions of Timer 1, Increment base address by 4
- * and use same offsets for Timer 2
- */
-#define XTTCPS_CLK_CNTRL_OFFSET		0x00 /* Clock Control Reg, RW */
-#define XTTCPS_CNT_CNTRL_OFFSET		0x0C /* Counter Control Reg, RW */
-#define XTTCPS_COUNT_VAL_OFFSET		0x18 /* Counter Value Reg, RO */
-#define XTTCPS_INTR_VAL_OFFSET		0x24 /* Interval Count Reg, RW */
-#define XTTCPS_ISR_OFFSET		0x54 /* Interrupt Status Reg, RO */
-#define XTTCPS_IER_OFFSET		0x60 /* Interrupt Enable Reg, RW */
-
-#define XTTCPS_CNT_CNTRL_DISABLE_MASK	0x1
-
-/*
- * Setup the timers to use pre-scaling, using a fixed value for now that will
- * work across most input frequency, but it may need to be more dynamic
- */
-#define PRESCALE_EXPONENT	11	/* 2 ^ PRESCALE_EXPONENT = PRESCALE */
-#define PRESCALE		2048	/* The exponent must match this */
-#define CLK_CNTRL_PRESCALE	((PRESCALE_EXPONENT - 1) << 1)
-#define CLK_CNTRL_PRESCALE_EN	1
-#define CNT_CNTRL_RESET		(1 << 4)
-
-/**
- * struct xttcps_timer - This definition defines local timer structure
- *
- * @base_addr:	Base address of timer
- * @clk:	Associated clock source
- * @clk_rate_change_nb	Notifier block for clock rate changes
- */
-struct xttcps_timer {
-	void __iomem *base_addr;
-	struct clk *clk;
-	struct notifier_block clk_rate_change_nb;
-};
-
-#define to_xttcps_timer(x) \
-		container_of(x, struct xttcps_timer, clk_rate_change_nb)
-
-struct xttcps_timer_clocksource {
-	struct xttcps_timer	xttc;
-	struct clocksource	cs;
-};
-
-#define to_xttcps_timer_clksrc(x) \
-		container_of(x, struct xttcps_timer_clocksource, cs)
-
-struct xttcps_timer_clockevent {
-	struct xttcps_timer		xttc;
-	struct clock_event_device	ce;
-};
-
-#define to_xttcps_timer_clkevent(x) \
-		container_of(x, struct xttcps_timer_clockevent, ce)
-
-/**
- * xttcps_set_interval - Set the timer interval value
- *
- * @timer:	Pointer to the timer instance
- * @cycles:	Timer interval ticks
- **/
-static void xttcps_set_interval(struct xttcps_timer *timer,
-					unsigned long cycles)
-{
-	u32 ctrl_reg;
-
-	/* Disable the counter, set the counter value  and re-enable counter */
-	ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
-	ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
-	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
-
-	__raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET);
-
-	/*
-	 * Reset the counter (0x10) so that it starts from 0, one-shot
-	 * mode makes this needed for timing to be right.
-	 */
-	ctrl_reg |= CNT_CNTRL_RESET;
-	ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
-	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
-}
-
-/**
- * xttcps_clock_event_interrupt - Clock event timer interrupt handler
- *
- * @irq:	IRQ number of the Timer
- * @dev_id:	void pointer to the xttcps_timer instance
- *
- * returns: Always IRQ_HANDLED - success
- **/
-static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id)
-{
-	struct xttcps_timer_clockevent *xttce = dev_id;
-	struct xttcps_timer *timer = &xttce->xttc;
-
-	/* Acknowledge the interrupt and call event handler */
-	__raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET);
-
-	xttce->ce.event_handler(&xttce->ce);
-
-	return IRQ_HANDLED;
-}
-
-/**
- * __xttc_clocksource_read - Reads the timer counter register
- *
- * returns: Current timer counter register value
- **/
-static cycle_t __xttc_clocksource_read(struct clocksource *cs)
-{
-	struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc;
-
-	return (cycle_t)__raw_readl(timer->base_addr +
-				XTTCPS_COUNT_VAL_OFFSET);
-}
-
-/**
- * xttcps_set_next_event - Sets the time interval for next event
- *
- * @cycles:	Timer interval ticks
- * @evt:	Address of clock event instance
- *
- * returns: Always 0 - success
- **/
-static int xttcps_set_next_event(unsigned long cycles,
-					struct clock_event_device *evt)
-{
-	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
-	struct xttcps_timer *timer = &xttce->xttc;
-
-	xttcps_set_interval(timer, cycles);
-	return 0;
-}
-
-/**
- * xttcps_set_mode - Sets the mode of timer
- *
- * @mode:	Mode to be set
- * @evt:	Address of clock event instance
- **/
-static void xttcps_set_mode(enum clock_event_mode mode,
-					struct clock_event_device *evt)
-{
-	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
-	struct xttcps_timer *timer = &xttce->xttc;
-	u32 ctrl_reg;
-
-	switch (mode) {
-	case CLOCK_EVT_MODE_PERIODIC:
-		xttcps_set_interval(timer,
-				DIV_ROUND_CLOSEST(clk_get_rate(xttce->xttc.clk),
-					PRESCALE * HZ));
-		break;
-	case CLOCK_EVT_MODE_ONESHOT:
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_SHUTDOWN:
-		ctrl_reg = __raw_readl(timer->base_addr +
-					XTTCPS_CNT_CNTRL_OFFSET);
-		ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
-		__raw_writel(ctrl_reg,
-				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
-		break;
-	case CLOCK_EVT_MODE_RESUME:
-		ctrl_reg = __raw_readl(timer->base_addr +
-					XTTCPS_CNT_CNTRL_OFFSET);
-		ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
-		__raw_writel(ctrl_reg,
-				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
-		break;
-	}
-}
-
-static int xttcps_rate_change_clocksource_cb(struct notifier_block *nb,
-		unsigned long event, void *data)
-{
-	struct clk_notifier_data *ndata = data;
-	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
-	struct xttcps_timer_clocksource *xttccs = container_of(xttcps,
-			struct xttcps_timer_clocksource, xttc);
-
-	switch (event) {
-	case POST_RATE_CHANGE:
-		/*
-		 * Do whatever is necessare to maintain a proper time base
-		 *
-		 * I cannot find a way to adjust the currently used clocksource
-		 * to the new frequency. __clocksource_updatefreq_hz() sounds
-		 * good, but does not work. Not sure what's that missing.
-		 *
-		 * This approach works, but triggers two clocksource switches.
-		 * The first after unregister to clocksource jiffies. And
-		 * another one after the register to the newly registered timer.
-		 *
-		 * Alternatively we could 'waste' another HW timer to ping pong
-		 * between clock sources. That would also use one register and
-		 * one unregister call, but only trigger one clocksource switch
-		 * for the cost of another HW timer used by the OS.
-		 */
-		clocksource_unregister(&xttccs->cs);
-		clocksource_register_hz(&xttccs->cs,
-				ndata->new_rate / PRESCALE);
-		/* fall through */
-	case PRE_RATE_CHANGE:
-	case ABORT_RATE_CHANGE:
-	default:
-		return NOTIFY_DONE;
-	}
-}
-
-static void __init zynq_ttc_setup_clocksource(struct clk *clk,
-							void __iomem *base)
-{
-	struct xttcps_timer_clocksource *ttccs;
-	int err;
-
-	ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
-	if (WARN_ON(!ttccs))
-		return;
-
-	ttccs->xttc.clk = clk;
-
-	err = clk_prepare_enable(ttccs->xttc.clk);
-	if (WARN_ON(err))
-		return;
-
-	ttccs->xttc.clk_rate_change_nb.notifier_call =
-		xttcps_rate_change_clocksource_cb;
-	ttccs->xttc.clk_rate_change_nb.next = NULL;
-	if (clk_notifier_register(ttccs->xttc.clk,
-				&ttccs->xttc.clk_rate_change_nb))
-		pr_warn("Unable to register clock notifier.\n");
-
-	ttccs->xttc.base_addr = base;
-	ttccs->cs.name = "xttcps_clocksource";
-	ttccs->cs.rating = 200;
-	ttccs->cs.read = __xttc_clocksource_read;
-	ttccs->cs.mask = CLOCKSOURCE_MASK(16);
-	ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-
-	/*
-	 * Setup the clock source counter to be an incrementing counter
-	 * with no interrupt and it rolls over at 0xFFFF. Pre-scale
-	 * it by 32 also. Let it start running now.
-	 */
-	__raw_writel(0x0,  ttccs->xttc.base_addr + XTTCPS_IER_OFFSET);
-	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
-		     ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
-	__raw_writel(CNT_CNTRL_RESET,
-		     ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
-
-	err = clocksource_register_hz(&ttccs->cs,
-			clk_get_rate(ttccs->xttc.clk) / PRESCALE);
-	if (WARN_ON(err))
-		return;
-
-}
-
-static int xttcps_rate_change_clockevent_cb(struct notifier_block *nb,
-		unsigned long event, void *data)
-{
-	struct clk_notifier_data *ndata = data;
-	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
-	struct xttcps_timer_clockevent *xttcce = container_of(xttcps,
-			struct xttcps_timer_clockevent, xttc);
-
-	switch (event) {
-	case POST_RATE_CHANGE:
-	{
-		unsigned long flags;
-
-		/*
-		 * clockevents_update_freq should be called with IRQ disabled on
-		 * the CPU the timer provides events for. The timer we use is
-		 * common to both CPUs, not sure if we need to run on both
-		 * cores.
-		 */
-		local_irq_save(flags);
-		clockevents_update_freq(&xttcce->ce,
-				ndata->new_rate / PRESCALE);
-		local_irq_restore(flags);
-
-		/* fall through */
-	}
-	case PRE_RATE_CHANGE:
-	case ABORT_RATE_CHANGE:
-	default:
-		return NOTIFY_DONE;
-	}
-}
-
-static void __init zynq_ttc_setup_clockevent(struct clk *clk,
-						void __iomem *base, u32 irq)
-{
-	struct xttcps_timer_clockevent *ttcce;
-	int err;
-
-	ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
-	if (WARN_ON(!ttcce))
-		return;
-
-	ttcce->xttc.clk = clk;
-
-	err = clk_prepare_enable(ttcce->xttc.clk);
-	if (WARN_ON(err))
-		return;
-
-	ttcce->xttc.clk_rate_change_nb.notifier_call =
-		xttcps_rate_change_clockevent_cb;
-	ttcce->xttc.clk_rate_change_nb.next = NULL;
-	if (clk_notifier_register(ttcce->xttc.clk,
-				&ttcce->xttc.clk_rate_change_nb))
-		pr_warn("Unable to register clock notifier.\n");
-
-	ttcce->xttc.base_addr = base;
-	ttcce->ce.name = "xttcps_clockevent";
-	ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
-	ttcce->ce.set_next_event = xttcps_set_next_event;
-	ttcce->ce.set_mode = xttcps_set_mode;
-	ttcce->ce.rating = 200;
-	ttcce->ce.irq = irq;
-	ttcce->ce.cpumask = cpu_possible_mask;
-
-	/*
-	 * Setup the clock event timer to be an interval timer which
-	 * is prescaled by 32 using the interval interrupt. Leave it
-	 * disabled for now.
-	 */
-	__raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
-	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
-		     ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
-	__raw_writel(0x1,  ttcce->xttc.base_addr + XTTCPS_IER_OFFSET);
-
-	err = request_irq(irq, xttcps_clock_event_interrupt,
-			  IRQF_DISABLED | IRQF_TIMER,
-			  ttcce->ce.name, ttcce);
-	if (WARN_ON(err))
-		return;
-
-	clockevents_config_and_register(&ttcce->ce,
-			clk_get_rate(ttcce->xttc.clk) / PRESCALE, 1, 0xfffe);
-}
-
-/**
- * xttcps_timer_init - Initialize the timer
- *
- * Initializes the timer hardware and register the clock source and clock event
- * timers with Linux kernal timer framework
- */
-static void __init xttcps_timer_init(struct device_node *timer)
-{
-	unsigned int irq;
-	void __iomem *timer_baseaddr;
-	struct clk *clk;
-	static int initialized;
-
-	if (initialized)
-		return;
-
-	initialized = 1;
-
-	/*
-	 * Get the 1st Triple Timer Counter (TTC) block from the device tree
-	 * and use it. Note that the event timer uses the interrupt and it's the
-	 * 2nd TTC hence the irq_of_parse_and_map(,1)
-	 */
-	timer_baseaddr = of_iomap(timer, 0);
-	if (!timer_baseaddr) {
-		pr_err("ERROR: invalid timer base address\n");
-		BUG();
-	}
-
-	irq = irq_of_parse_and_map(timer, 1);
-	if (irq <= 0) {
-		pr_err("ERROR: invalid interrupt number\n");
-		BUG();
-	}
-
-	clk = of_clk_get_by_name(timer, "cpu_1x");
-	if (IS_ERR(clk)) {
-		pr_err("ERROR: timer input clock not found\n");
-		BUG();
-	}
-
-	zynq_ttc_setup_clocksource(clk, timer_baseaddr);
-	zynq_ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
-
-	pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
-}
-
-CLOCKSOURCE_OF_DECLARE(zynq, "xlnx,ttc", xttcps_timer_init);
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 4d8283a..665af7f 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -19,6 +19,7 @@  obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835_timer.o
 obj-$(CONFIG_SUNXI_TIMER)	+= sunxi_timer.o
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra20_timer.o
 obj-$(CONFIG_VT8500_TIMER)	+= vt8500_timer.o
+obj-$(CONFIG_ARCH_ZYNQ)		+= zynq_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
diff --git a/drivers/clocksource/zynq_timer.c b/drivers/clocksource/zynq_timer.c
new file mode 100644
index 0000000..3b1faed
--- /dev/null
+++ b/drivers/clocksource/zynq_timer.c
@@ -0,0 +1,430 @@ 
+/*
+ * This file contains driver for the Xilinx PS Timer Counter IP.
+ *
+ *  Copyright (C) 2011 Xilinx
+ *
+ * based on arch/mips/kernel/time.c timer driver
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+
+/*
+ * This driver configures the 2 16-bit count-up timers as follows:
+ *
+ * T1: Timer 1, clocksource for generic timekeeping
+ * T2: Timer 2, clockevent source for hrtimers
+ * T3: Timer 3, <unused>
+ *
+ * The input frequency to the timer module for emulation is 2.5MHz which is
+ * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32,
+ * the timers are clocked at 78.125KHz (12.8 us resolution).
+
+ * The input frequency to the timer module in silicon is configurable and
+ * obtained from device tree. The pre-scaler of 32 is used.
+ */
+
+/*
+ * Timer Register Offset Definitions of Timer 1, Increment base address by 4
+ * and use same offsets for Timer 2
+ */
+#define XTTCPS_CLK_CNTRL_OFFSET		0x00 /* Clock Control Reg, RW */
+#define XTTCPS_CNT_CNTRL_OFFSET		0x0C /* Counter Control Reg, RW */
+#define XTTCPS_COUNT_VAL_OFFSET		0x18 /* Counter Value Reg, RO */
+#define XTTCPS_INTR_VAL_OFFSET		0x24 /* Interval Count Reg, RW */
+#define XTTCPS_ISR_OFFSET		0x54 /* Interrupt Status Reg, RO */
+#define XTTCPS_IER_OFFSET		0x60 /* Interrupt Enable Reg, RW */
+
+#define XTTCPS_CNT_CNTRL_DISABLE_MASK	0x1
+
+/*
+ * Setup the timers to use pre-scaling, using a fixed value for now that will
+ * work across most input frequency, but it may need to be more dynamic
+ */
+#define PRESCALE_EXPONENT	11	/* 2 ^ PRESCALE_EXPONENT = PRESCALE */
+#define PRESCALE		2048	/* The exponent must match this */
+#define CLK_CNTRL_PRESCALE	((PRESCALE_EXPONENT - 1) << 1)
+#define CLK_CNTRL_PRESCALE_EN	1
+#define CNT_CNTRL_RESET		(1 << 4)
+
+/**
+ * struct xttcps_timer - This definition defines local timer structure
+ *
+ * @base_addr:	Base address of timer
+ * @clk:	Associated clock source
+ * @clk_rate_change_nb	Notifier block for clock rate changes
+ */
+struct xttcps_timer {
+	void __iomem *base_addr;
+	struct clk *clk;
+	struct notifier_block clk_rate_change_nb;
+};
+
+#define to_xttcps_timer(x) \
+		container_of(x, struct xttcps_timer, clk_rate_change_nb)
+
+struct xttcps_timer_clocksource {
+	struct xttcps_timer	xttc;
+	struct clocksource	cs;
+};
+
+#define to_xttcps_timer_clksrc(x) \
+		container_of(x, struct xttcps_timer_clocksource, cs)
+
+struct xttcps_timer_clockevent {
+	struct xttcps_timer		xttc;
+	struct clock_event_device	ce;
+};
+
+#define to_xttcps_timer_clkevent(x) \
+		container_of(x, struct xttcps_timer_clockevent, ce)
+
+/**
+ * xttcps_set_interval - Set the timer interval value
+ *
+ * @timer:	Pointer to the timer instance
+ * @cycles:	Timer interval ticks
+ **/
+static void xttcps_set_interval(struct xttcps_timer *timer,
+					unsigned long cycles)
+{
+	u32 ctrl_reg;
+
+	/* Disable the counter, set the counter value  and re-enable counter */
+	ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+	ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
+	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+
+	__raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET);
+
+	/*
+	 * Reset the counter (0x10) so that it starts from 0, one-shot
+	 * mode makes this needed for timing to be right.
+	 */
+	ctrl_reg |= CNT_CNTRL_RESET;
+	ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
+	__raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+}
+
+/**
+ * xttcps_clock_event_interrupt - Clock event timer interrupt handler
+ *
+ * @irq:	IRQ number of the Timer
+ * @dev_id:	void pointer to the xttcps_timer instance
+ *
+ * returns: Always IRQ_HANDLED - success
+ **/
+static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id)
+{
+	struct xttcps_timer_clockevent *xttce = dev_id;
+	struct xttcps_timer *timer = &xttce->xttc;
+
+	/* Acknowledge the interrupt and call event handler */
+	__raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET);
+
+	xttce->ce.event_handler(&xttce->ce);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * __xttc_clocksource_read - Reads the timer counter register
+ *
+ * returns: Current timer counter register value
+ **/
+static cycle_t __xttc_clocksource_read(struct clocksource *cs)
+{
+	struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc;
+
+	return (cycle_t)__raw_readl(timer->base_addr +
+				XTTCPS_COUNT_VAL_OFFSET);
+}
+
+/**
+ * xttcps_set_next_event - Sets the time interval for next event
+ *
+ * @cycles:	Timer interval ticks
+ * @evt:	Address of clock event instance
+ *
+ * returns: Always 0 - success
+ **/
+static int xttcps_set_next_event(unsigned long cycles,
+					struct clock_event_device *evt)
+{
+	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
+	struct xttcps_timer *timer = &xttce->xttc;
+
+	xttcps_set_interval(timer, cycles);
+	return 0;
+}
+
+/**
+ * xttcps_set_mode - Sets the mode of timer
+ *
+ * @mode:	Mode to be set
+ * @evt:	Address of clock event instance
+ **/
+static void xttcps_set_mode(enum clock_event_mode mode,
+					struct clock_event_device *evt)
+{
+	struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt);
+	struct xttcps_timer *timer = &xttce->xttc;
+	u32 ctrl_reg;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		xttcps_set_interval(timer,
+				DIV_ROUND_CLOSEST(clk_get_rate(xttce->xttc.clk),
+					PRESCALE * HZ));
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		ctrl_reg = __raw_readl(timer->base_addr +
+					XTTCPS_CNT_CNTRL_OFFSET);
+		ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK;
+		__raw_writel(ctrl_reg,
+				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		ctrl_reg = __raw_readl(timer->base_addr +
+					XTTCPS_CNT_CNTRL_OFFSET);
+		ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK;
+		__raw_writel(ctrl_reg,
+				timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+		break;
+	}
+}
+
+static int xttcps_rate_change_clocksource_cb(struct notifier_block *nb,
+		unsigned long event, void *data)
+{
+	struct clk_notifier_data *ndata = data;
+	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
+	struct xttcps_timer_clocksource *xttccs = container_of(xttcps,
+			struct xttcps_timer_clocksource, xttc);
+
+	switch (event) {
+	case POST_RATE_CHANGE:
+		/*
+		 * Do whatever is necessare to maintain a proper time base
+		 *
+		 * I cannot find a way to adjust the currently used clocksource
+		 * to the new frequency. __clocksource_updatefreq_hz() sounds
+		 * good, but does not work. Not sure what's that missing.
+		 *
+		 * This approach works, but triggers two clocksource switches.
+		 * The first after unregister to clocksource jiffies. And
+		 * another one after the register to the newly registered timer.
+		 *
+		 * Alternatively we could 'waste' another HW timer to ping pong
+		 * between clock sources. That would also use one register and
+		 * one unregister call, but only trigger one clocksource switch
+		 * for the cost of another HW timer used by the OS.
+		 */
+		clocksource_unregister(&xttccs->cs);
+		clocksource_register_hz(&xttccs->cs,
+				ndata->new_rate / PRESCALE);
+		/* fall through */
+	case PRE_RATE_CHANGE:
+	case ABORT_RATE_CHANGE:
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static void __init zynq_ttc_setup_clocksource(struct clk *clk,
+							void __iomem *base)
+{
+	struct xttcps_timer_clocksource *ttccs;
+	int err;
+
+	ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL);
+	if (WARN_ON(!ttccs))
+		return;
+
+	ttccs->xttc.clk = clk;
+
+	err = clk_prepare_enable(ttccs->xttc.clk);
+	if (WARN_ON(err))
+		return;
+
+	ttccs->xttc.clk_rate_change_nb.notifier_call =
+		xttcps_rate_change_clocksource_cb;
+	ttccs->xttc.clk_rate_change_nb.next = NULL;
+	if (clk_notifier_register(ttccs->xttc.clk,
+				&ttccs->xttc.clk_rate_change_nb))
+		pr_warn("Unable to register clock notifier.\n");
+
+	ttccs->xttc.base_addr = base;
+	ttccs->cs.name = "xttcps_clocksource";
+	ttccs->cs.rating = 200;
+	ttccs->cs.read = __xttc_clocksource_read;
+	ttccs->cs.mask = CLOCKSOURCE_MASK(16);
+	ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+	/*
+	 * Setup the clock source counter to be an incrementing counter
+	 * with no interrupt and it rolls over at 0xFFFF. Pre-scale
+	 * it by 32 also. Let it start running now.
+	 */
+	__raw_writel(0x0,  ttccs->xttc.base_addr + XTTCPS_IER_OFFSET);
+	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
+		     ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
+	__raw_writel(CNT_CNTRL_RESET,
+		     ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+
+	err = clocksource_register_hz(&ttccs->cs,
+			clk_get_rate(ttccs->xttc.clk) / PRESCALE);
+	if (WARN_ON(err))
+		return;
+
+}
+
+static int xttcps_rate_change_clockevent_cb(struct notifier_block *nb,
+		unsigned long event, void *data)
+{
+	struct clk_notifier_data *ndata = data;
+	struct xttcps_timer *xttcps = to_xttcps_timer(nb);
+	struct xttcps_timer_clockevent *xttcce = container_of(xttcps,
+			struct xttcps_timer_clockevent, xttc);
+
+	switch (event) {
+	case POST_RATE_CHANGE:
+	{
+		unsigned long flags;
+
+		/*
+		 * clockevents_update_freq should be called with IRQ disabled on
+		 * the CPU the timer provides events for. The timer we use is
+		 * common to both CPUs, not sure if we need to run on both
+		 * cores.
+		 */
+		local_irq_save(flags);
+		clockevents_update_freq(&xttcce->ce,
+				ndata->new_rate / PRESCALE);
+		local_irq_restore(flags);
+
+		/* fall through */
+	}
+	case PRE_RATE_CHANGE:
+	case ABORT_RATE_CHANGE:
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static void __init zynq_ttc_setup_clockevent(struct clk *clk,
+						void __iomem *base, u32 irq)
+{
+	struct xttcps_timer_clockevent *ttcce;
+	int err;
+
+	ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL);
+	if (WARN_ON(!ttcce))
+		return;
+
+	ttcce->xttc.clk = clk;
+
+	err = clk_prepare_enable(ttcce->xttc.clk);
+	if (WARN_ON(err))
+		return;
+
+	ttcce->xttc.clk_rate_change_nb.notifier_call =
+		xttcps_rate_change_clockevent_cb;
+	ttcce->xttc.clk_rate_change_nb.next = NULL;
+	if (clk_notifier_register(ttcce->xttc.clk,
+				&ttcce->xttc.clk_rate_change_nb))
+		pr_warn("Unable to register clock notifier.\n");
+
+	ttcce->xttc.base_addr = base;
+	ttcce->ce.name = "xttcps_clockevent";
+	ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	ttcce->ce.set_next_event = xttcps_set_next_event;
+	ttcce->ce.set_mode = xttcps_set_mode;
+	ttcce->ce.rating = 200;
+	ttcce->ce.irq = irq;
+	ttcce->ce.cpumask = cpu_possible_mask;
+
+	/*
+	 * Setup the clock event timer to be an interval timer which
+	 * is prescaled by 32 using the interval interrupt. Leave it
+	 * disabled for now.
+	 */
+	__raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET);
+	__raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN,
+		     ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET);
+	__raw_writel(0x1,  ttcce->xttc.base_addr + XTTCPS_IER_OFFSET);
+
+	err = request_irq(irq, xttcps_clock_event_interrupt,
+			  IRQF_DISABLED | IRQF_TIMER,
+			  ttcce->ce.name, ttcce);
+	if (WARN_ON(err))
+		return;
+
+	clockevents_config_and_register(&ttcce->ce,
+			clk_get_rate(ttcce->xttc.clk) / PRESCALE, 1, 0xfffe);
+}
+
+/**
+ * xttcps_timer_init - Initialize the timer
+ *
+ * Initializes the timer hardware and register the clock source and clock event
+ * timers with Linux kernal timer framework
+ */
+static void __init xttcps_timer_init(struct device_node *timer)
+{
+	unsigned int irq;
+	void __iomem *timer_baseaddr;
+	struct clk *clk;
+	static int initialized;
+
+	if (initialized)
+		return;
+
+	initialized = 1;
+
+	/*
+	 * Get the 1st Triple Timer Counter (TTC) block from the device tree
+	 * and use it. Note that the event timer uses the interrupt and it's the
+	 * 2nd TTC hence the irq_of_parse_and_map(,1)
+	 */
+	timer_baseaddr = of_iomap(timer, 0);
+	if (!timer_baseaddr) {
+		pr_err("ERROR: invalid timer base address\n");
+		BUG();
+	}
+
+	irq = irq_of_parse_and_map(timer, 1);
+	if (irq <= 0) {
+		pr_err("ERROR: invalid interrupt number\n");
+		BUG();
+	}
+
+	clk = of_clk_get_by_name(timer, "cpu_1x");
+	if (IS_ERR(clk)) {
+		pr_err("ERROR: timer input clock not found\n");
+		BUG();
+	}
+
+	zynq_ttc_setup_clocksource(clk, timer_baseaddr);
+	zynq_ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
+
+	pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
+}
+
+CLOCKSOURCE_OF_DECLARE(zynq, "xlnx,ttc", xttcps_timer_init);