All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] [ARM] [S3C64XX] Add support for hr timer
@ 2009-11-11  5:41 aditya.ps
  0 siblings, 0 replies; 6+ messages in thread
From: aditya.ps @ 2009-11-11  5:41 UTC (permalink / raw)
  To: linux-samsung-soc; +Cc: aditya

From: aditya <aditya.ps@samsung.com>

This patch add support for the S3C64XX hr timer.

Signed-off-by: Aditya Pratap Sharma <aditya.ps@samsung.com>
---
 arch/arm/mach-s3c6410/Kconfig               |    2 +
 arch/arm/plat-s3c/Makefile                  |   10 +
 arch/arm/plat-s3c/hr-time.c                 |  301 +++++++++++++++++++++++++++
 arch/arm/plat-s3c/include/plat/regs-timer.h |   11 +
 4 files changed, 324 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s3c/hr-time.c

diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
index f9d0f09..29cfd0c 100644
--- a/arch/arm/mach-s3c6410/Kconfig
+++ b/arch/arm/mach-s3c6410/Kconfig
@@ -11,6 +11,8 @@ config CPU_S3C6410
 	bool
 	select CPU_S3C6400_INIT
 	select CPU_S3C6400_CLOCK
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
 	help
 	  Enable S3C6410 CPU support
 
diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
index 3c09109..6c612aa 100644
--- a/arch/arm/plat-s3c/Makefile
+++ b/arch/arm/plat-s3c/Makefile
@@ -12,7 +12,17 @@ obj-				:=
 # Core support for all Samsung SoCs
 
 obj-y				+=  init.o
+ifdef CONFIG_NO_HZ
+obj-y				+= hr-time.o
+else
+
+ifndef CONFIG_HIGH_RES_TIMERS
 obj-y				+= time.o
+else
+obj-y				+= hr-time.o
+endif
+
+endif
 obj-y				+= clock.o
 obj-y				+= pwm-clock.o
 obj-y				+= gpio.o
diff --git a/arch/arm/plat-s3c/hr-time.c b/arch/arm/plat-s3c/hr-time.c
new file mode 100644
index 0000000..76fd91f
--- /dev/null
+++ b/arch/arm/plat-s3c/hr-time.c
@@ -0,0 +1,301 @@
+/*
+ * linux/arch/arm/plat-s3c/hr-time.c
+ *
+ * S3C6410 high resolution Timers
+ *
+ * Copyright (c) 2006 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-irq.h>
+#include <mach/tick.h>
+#include <plat/regs-timer.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+
+static void s3c64xx_timer_setup(void);
+
+static inline void s3c64xx_tick_set_autoreset(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon |= (S3C2410_TCON_T4RELOAD);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static inline void s3c64xx_tick_remove_autoreset(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon &= ~(S3C2410_TCON_T4RELOAD);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s3c64xx_tick_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcfg1;
+	unsigned long tcfg0;
+	unsigned long tcstat;
+
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcfg1 = __raw_readl(S3C2410_TCFG1);
+	tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
+	tcstat |=  S3C_TINT_CSTAT_T4INTEN;
+	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
+	__raw_writel(load_val - 1, S3C2410_TCNTB(4));
+
+	tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
+	tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
+
+	tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+	tcfg0 |= (0) << S3C2410_TCFG_PRESCALER1_SHIFT;
+
+	__raw_writel(tcfg1, S3C2410_TCFG1);
+	__raw_writel(tcfg0, S3C2410_TCFG0);
+
+	tcon &= ~(S3C2410_TCON_T4START|S3C2410_TCON_T4MANUALUPD
+					|S3C2410_TCON_T4RELOAD);
+	tcon |= S3C2410_TCON_T4MANUALUPD;
+	if (autoreset)
+		tcon |= S3C2410_TCON_T4RELOAD;
+	__raw_writel(tcon, S3C2410_TCON);
+
+	/* start the timer running */
+	tcon |= S3C2410_TCON_T4START;
+	tcon &= ~S3C2410_TCON_T4MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static inline void s3c64xx_tick_timer_stop(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon &= ~(S3C2410_TCON_T4START);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s3c64xx_sched_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcfg1;
+	unsigned long tcfg0;
+	unsigned long tcstat;
+
+	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
+	tcstat |=  S3C_TINT_CSTAT_T2INTEN;
+	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
+
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcfg1 = __raw_readl(S3C2410_TCFG1);
+	tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+	__raw_writel(load_val - 1, S3C2410_TCNTB(2));
+	__raw_writel(load_val - 1, S3C2410_TCMPB(2));
+
+	tcon &= ~(S3C2410_TCON_T2RELOAD|(!S3C2410_TCON_T2INVERT)
+			|S3C2410_TCON_T2MANUALUPD|S3C2410_TCON_T2START);
+	if (autoreset)
+		tcon |= S3C2410_TCON_T2RELOAD;
+	tcon |= S3C2410_TCON_T2MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+
+	/* start the timer running */
+	tcon |= S3C2410_TCON_T2START;
+	tcon &= ~S3C2410_TCON_T2MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * PWM timer 4 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static int s3c64xx_tick_set_next_event(unsigned long cycles,
+				   struct clock_event_device *evt)
+{
+	s3c64xx_tick_timer_start(cycles, 0);
+	return 0;
+}
+static void s3c64xx_tick_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		s3c64xx_tick_set_autoreset();
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		s3c64xx_tick_timer_stop();
+		s3c64xx_tick_remove_autoreset();
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		s3c64xx_timer_setup();
+		break;
+	}
+}
+
+static struct clock_event_device tick_tmr = {
+	.name		= "pwm_timer4",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_next_event	= s3c64xx_tick_set_next_event,
+	.set_mode	= s3c64xx_tick_set_mode,
+};
+
+irqreturn_t s3c64xx_tick_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &tick_tmr;
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction s3c64xx_tick_timer_irq = {
+	.name		= "pwm_timer4",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= s3c64xx_tick_timer_interrupt,
+};
+
+static void __init s3c64xx_init_dynamic_tick_timer(unsigned long rate)
+{
+	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
+	tick_tmr.mult = div_sc(rate, NSEC_PER_SEC, tick_tmr.shift);
+	tick_tmr.max_delta_ns = clockevent_delta2ns(-1, &tick_tmr);
+	tick_tmr.min_delta_ns = clockevent_delta2ns(1, &tick_tmr);
+
+	tick_tmr.cpumask = get_cpu_mask(0);
+	clockevents_register_device(&tick_tmr);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * PWM timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
+ */
+static unsigned long s3c64xx_mpu_timer2_overflows;
+
+irqreturn_t s3c64xx_mpu_timer2_interrupt(int irq, void *dev_id)
+{
+	s3c64xx_mpu_timer2_overflows++;
+	return IRQ_HANDLED;
+}
+
+struct irqaction s3c64xx_timer2_irq = {
+	.name		= "pwm_timer2",
+	.flags		= IRQF_DISABLED ,
+	.handler	= s3c64xx_mpu_timer2_interrupt,
+};
+
+
+/* Read timer 2 Count Observation Register */
+static cycle_t s3c64xx_sched_timer_read(struct clocksource *cs)
+{
+	return (cycle_t)~__raw_readl(S3C_TIMERREG(0x2c));
+}
+
+struct clocksource clocksource_s3c64xx = {
+	.name		= "clock_source_timer2",
+	.rating		= 300,
+	.read		= s3c64xx_sched_timer_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s3c64xx_init_clocksource(unsigned long rate)
+{
+	clocksource_s3c64xx.mult
+		= clocksource_khz2mult(rate/1000, clocksource_s3c64xx.shift);
+	s3c64xx_sched_timer_start(~0, 1);
+
+	if (clocksource_register(&clocksource_s3c64xx))
+		printk(KERN_ERR "%s: can't register clocksource\n",
+			clocksource_s3c64xx.name);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  Tick Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void s3c64xx_dynamic_timer_setup(void)
+{
+	struct clk	*ck_ref = clk_get(NULL, "timers");
+	unsigned long	rate;
+
+	if (IS_ERR(ck_ref))
+		panic("failed to get clock for system timer");
+
+	rate = clk_get_rate(ck_ref);
+	clk_put(ck_ref);
+
+	s3c64xx_init_dynamic_tick_timer(rate);
+	s3c64xx_init_clocksource(rate);
+}
+
+static void s3c64xx_timer_setup(void)
+{
+	struct clk	*ck_ref = clk_get(NULL, "timers");
+	unsigned long	rate;
+
+	if (IS_ERR(ck_ref))
+		panic("failed to get clock for system timer");
+
+	rate = clk_get_rate(ck_ref);
+	clk_put(ck_ref);
+	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
+	s3c64xx_sched_timer_start(~0, 1);
+}
+
+
+static void __init s3c64xx_dynamic_timer_init(void)
+{
+	s3c64xx_dynamic_timer_setup();
+	setup_irq(IRQ_TIMER2, &s3c64xx_timer2_irq);
+	setup_irq(IRQ_TIMER4, &s3c64xx_tick_timer_irq);
+}
+
+
+struct sys_timer s3c24xx_timer = {
+	.init		= s3c64xx_dynamic_timer_init,
+};
+
diff --git a/arch/arm/plat-s3c/include/plat/regs-timer.h b/arch/arm/plat-s3c/include/plat/regs-timer.h
index d097d92..e9994db 100644
--- a/arch/arm/plat-s3c/include/plat/regs-timer.h
+++ b/arch/arm/plat-s3c/include/plat/regs-timer.h
@@ -117,6 +117,17 @@
 #define S3C2410_TCON_T0INVERT	  (1<<2)
 #define S3C2410_TCON_T0MANUALUPD  (1<<1)
 #define S3C2410_TCON_T0START	  (1<<0)
+/* Interrupt Control and Status register*/
+#define S3C_TINT_CSTAT_T4INT	(1<<9)
+#define S3C_TINT_CSTAT_T3INT	(1<<8)
+#define S3C_TINT_CSTAT_T2INT	(1<<7)
+#define S3C_TINT_CSTAT_T1INT	(1<<6)
+#define S3C_TINT_CSTAT_T0INT	(1<<5)
+#define S3C_TINT_CSTAT_T4INTEN	(1<<4)
+#define S3C_TINT_CSTAT_T3INTEN	(1<<3)
+#define S3C_TINT_CSTAT_T2INTEN	(1<<2)
+#define S3C_TINT_CSTAT_T1INTEN	(1<<1)
+#define S3C_TINT_CSTAT_T0INTEN	(1<<0)
 
 #endif /*  __ASM_ARCH_REGS_TIMER_H */
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH] [ARM] [S3C64XX] Add support for hr timer
  2009-12-01  8:39 aditya
@ 2010-01-08  5:47 ` Ben Dooks
  0 siblings, 0 replies; 6+ messages in thread
From: Ben Dooks @ 2010-01-08  5:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 01, 2009 at 05:39:55PM +0900, aditya wrote:
> This patch add support for the S3C64XX hr timer.

would be nicer to use high resolution instead of hr in this text.
 
> Signed-off-by: Aditya Pratap Sharma <aditya.ps@samsung.com>
> ---
>  arch/arm/mach-s3c6410/Kconfig               |    2 +
>  arch/arm/plat-s3c/Makefile                  |   10 +
>  arch/arm/plat-s3c/hr-time.c                 |  301 +++++++++++++++++++++++++++
>  arch/arm/plat-s3c/include/plat/regs-timer.h |   11 +
>  4 files changed, 324 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-s3c/hr-time.c
> 
> diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
> index f9d0f09..29cfd0c 100644
> --- a/arch/arm/mach-s3c6410/Kconfig
> +++ b/arch/arm/mach-s3c6410/Kconfig
> @@ -11,6 +11,8 @@ config CPU_S3C6410
>  	bool
>  	select CPU_S3C6400_INIT
>  	select CPU_S3C6400_CLOCK
> +	select GENERIC_TIME
> +	select GENERIC_CLOCKEVENTS
>  	help
>  	  Enable S3C6410 CPU support
>  
> diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
> index 3c09109..6c612aa 100644
> --- a/arch/arm/plat-s3c/Makefile
> +++ b/arch/arm/plat-s3c/Makefile
> @@ -12,7 +12,17 @@ obj-				:=
>  # Core support for all Samsung SoCs
>  
>  obj-y				+=  init.o
> +ifdef CONFIG_NO_HZ
> +obj-y				+= hr-time.o
> +else
> +
> +ifndef CONFIG_HIGH_RES_TIMERS
>  obj-y				+= time.o
> +else
> +obj-y				+= hr-time.o
> +endif
> +
> +endif
>  obj-y				+= clock.o
>  obj-y				+= pwm-clock.o
>  obj-y				+= gpio.o

It would be nicer to allow both to be compiled in depending on what the
board files want to use.

> diff --git a/arch/arm/plat-s3c/hr-time.c b/arch/arm/plat-s3c/hr-time.c
> new file mode 100644
> index 0000000..76fd91f
> --- /dev/null
> +++ b/arch/arm/plat-s3c/hr-time.c
> @@ -0,0 +1,301 @@
> +/*
> + * linux/arch/arm/plat-s3c/hr-time.c
> + *
> + * S3C6410 high resolution Timers
> + *
> + * Copyright (c) 2006 Samsung Electronics
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/sched.h>
> +#include <linux/spinlock.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/clocksource.h>
> +#include <linux/clockchips.h>
> +#include <linux/io.h>
> +#include <linux/leds.h>

is <linux/leds.h> needed here?

> +#include <asm/system.h>
> +#include <asm/irq.h>
> +#include <asm/mach/irq.h>
> +#include <asm/mach/time.h>
> +#include <asm/mach-types.h>

do you really need mach-types.h? I now the old code
for the s3c2410 needed it for machine_is_xxx() but we've learned quite
a bit since that time.

there are also a lot of asm files being pulled in as well.

> +#include <mach/hardware.h>
> +#include <mach/map.h>
> +#include <mach/regs-irq.h>
> +#include <mach/tick.h>
> +#include <plat/regs-timer.h>
> +#include <plat/clock.h>
> +#include <plat/cpu.h>

some spacing in between the include files would make it neater and in
my opinion neater too.

> +
> +static void s3c64xx_timer_setup(void);
> +
> +static inline void s3c64xx_tick_set_autoreset(void)
> +{
> +	unsigned long tcon;
> +	tcon  = __raw_readl(S3C2410_TCON);
> +	tcon |= (S3C2410_TCON_T4RELOAD);
> +	__raw_writel(tcon, S3C2410_TCON);
> +}
> +
> +static inline void s3c64xx_tick_remove_autoreset(void)
> +{
> +	unsigned long tcon;
> +	tcon  = __raw_readl(S3C2410_TCON);
> +	tcon &= ~(S3C2410_TCON_T4RELOAD);
> +	__raw_writel(tcon, S3C2410_TCON);
> +}
> +
> +static void s3c64xx_tick_timer_start(unsigned long load_val,
> +					int autoreset)
> +{
> +	unsigned long tcon;
> +	unsigned long tcfg1;
> +	unsigned long tcfg0;
> +	unsigned long tcstat;
> +
> +	tcon  = __raw_readl(S3C2410_TCON);
> +	tcfg1 = __raw_readl(S3C2410_TCFG1);
> +	tcfg0 = __raw_readl(S3C2410_TCFG0);
> +
> +	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
> +	tcstat |=  S3C_TINT_CSTAT_T4INTEN;
> +	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
> +	__raw_writel(load_val - 1, S3C2410_TCNTB(4));

could the interrupt support for the pwm-timer clocks be used here?
 
are these protected against access from multiple sources, as the pwm
timer interrpt code might touch these too.

thirdly, you don't mask the interrupt status and thus may end up acknowleding
an extant interrupt.

> +	tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
> +	tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
> +
> +	tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
> +	tcfg0 |= (0) << S3C2410_TCFG_PRESCALER1_SHIFT;
> +
> +	__raw_writel(tcfg1, S3C2410_TCFG1);
> +	__raw_writel(tcfg0, S3C2410_TCFG0);
> +
> +	tcon &= ~(S3C2410_TCON_T4START|S3C2410_TCON_T4MANUALUPD
> +					|S3C2410_TCON_T4RELOAD);
> +	tcon |= S3C2410_TCON_T4MANUALUPD;
> +	if (autoreset)
> +		tcon |= S3C2410_TCON_T4RELOAD;
> +	__raw_writel(tcon, S3C2410_TCON);
> +
> +	/* start the timer running */
> +	tcon |= S3C2410_TCON_T4START;
> +	tcon &= ~S3C2410_TCON_T4MANUALUPD;
> +	__raw_writel(tcon, S3C2410_TCON);
> +}
> +
> +static inline void s3c64xx_tick_timer_stop(void)
> +{
> +	unsigned long tcon;
> +	tcon  = __raw_readl(S3C2410_TCON);
> +	tcon &= ~(S3C2410_TCON_T4START);
> +	__raw_writel(tcon, S3C2410_TCON);
> +}
> +
> +static void s3c64xx_sched_timer_start(unsigned long load_val,
> +					int autoreset)
> +{
> +	unsigned long tcon;
> +	unsigned long tcfg1;
> +	unsigned long tcfg0;
> +	unsigned long tcstat;
> +
> +	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
> +	tcstat |=  S3C_TINT_CSTAT_T2INTEN;
> +	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
> +
> +	tcon  = __raw_readl(S3C2410_TCON);
> +	tcfg1 = __raw_readl(S3C2410_TCFG1);
> +	tcfg0 = __raw_readl(S3C2410_TCFG0);
> +
> +	__raw_writel(load_val - 1, S3C2410_TCNTB(2));
> +	__raw_writel(load_val - 1, S3C2410_TCMPB(2));
> +
> +	tcon &= ~(S3C2410_TCON_T2RELOAD|(!S3C2410_TCON_T2INVERT)
> +			|S3C2410_TCON_T2MANUALUPD|S3C2410_TCON_T2START);
> +	if (autoreset)
> +		tcon |= S3C2410_TCON_T2RELOAD;
> +	tcon |= S3C2410_TCON_T2MANUALUPD;
> +	__raw_writel(tcon, S3C2410_TCON);
> +
> +	/* start the timer running */
> +	tcon |= S3C2410_TCON_T2START;
> +	tcon &= ~S3C2410_TCON_T2MANUALUPD;
> +	__raw_writel(tcon, S3C2410_TCON);
> +}
> +
> +/*
> + * ---------------------------------------------------------------------------
> + * PWM timer 4 ... count down to zero, interrupt, reload
> + * ---------------------------------------------------------------------------
> + */
> +static int s3c64xx_tick_set_next_event(unsigned long cycles,
> +				   struct clock_event_device *evt)
> +{
> +	s3c64xx_tick_timer_start(cycles, 0);
> +	return 0;
> +}
> +static void s3c64xx_tick_set_mode(enum clock_event_mode mode,
> +			      struct clock_event_device *evt)
> +{
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		s3c64xx_tick_set_autoreset();
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +		s3c64xx_tick_timer_stop();
> +		s3c64xx_tick_remove_autoreset();
> +		break;
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +		break;
> +	case CLOCK_EVT_MODE_RESUME:
> +		s3c64xx_timer_setup();
> +		break;
> +	}
> +}
> +
> +static struct clock_event_device tick_tmr = {
> +	.name		= "pwm_timer4",
> +	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +	.shift		= 32,
> +	.set_next_event	= s3c64xx_tick_set_next_event,
> +	.set_mode	= s3c64xx_tick_set_mode,
> +};
> +
> +irqreturn_t s3c64xx_tick_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *evt = &tick_tmr;
> +	evt->event_handler(evt);
> +	return IRQ_HANDLED;
> +}
> +
> +static struct irqaction s3c64xx_tick_timer_irq = {
> +	.name		= "pwm_timer4",
> +	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
> +	.handler	= s3c64xx_tick_timer_interrupt,
> +};
> +
> +static void __init s3c64xx_init_dynamic_tick_timer(unsigned long rate)
> +{
> +	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
> +	tick_tmr.mult = div_sc(rate, NSEC_PER_SEC, tick_tmr.shift);
> +	tick_tmr.max_delta_ns = clockevent_delta2ns(-1, &tick_tmr);
> +	tick_tmr.min_delta_ns = clockevent_delta2ns(1, &tick_tmr);
> +
> +	tick_tmr.cpumask = get_cpu_mask(0);
> +	clockevents_register_device(&tick_tmr);
> +}
> +
> +/*
> + * ---------------------------------------------------------------------------
> + * PWM timer 2 ... free running 32-bit clock source and scheduler clock
> + * ---------------------------------------------------------------------------
> + */
> +static unsigned long s3c64xx_mpu_timer2_overflows;
> +
> +irqreturn_t s3c64xx_mpu_timer2_interrupt(int irq, void *dev_id)
> +{
> +	s3c64xx_mpu_timer2_overflows++;
> +	return IRQ_HANDLED;
> +}
> +
> +struct irqaction s3c64xx_timer2_irq = {
> +	.name		= "pwm_timer2",
> +	.flags		= IRQF_DISABLED ,
> +	.handler	= s3c64xx_mpu_timer2_interrupt,
> +};
> +
> +
> +/* Read timer 2 Count Observation Register */
> +static cycle_t s3c64xx_sched_timer_read(struct clocksource *cs)
> +{
> +	return (cycle_t)~__raw_readl(S3C_TIMERREG(0x2c));
> +}
> +
> +struct clocksource clocksource_s3c64xx = {
> +	.name		= "clock_source_timer2",
> +	.rating		= 300,
> +	.read		= s3c64xx_sched_timer_read,
> +	.mask		= CLOCKSOURCE_MASK(32),
> +	.shift		= 20,
> +	.flags		= CLOCK_SOURCE_IS_CONTINUOUS ,
> +};
> +
> +static void __init s3c64xx_init_clocksource(unsigned long rate)
> +{
> +	clocksource_s3c64xx.mult
> +		= clocksource_khz2mult(rate/1000, clocksource_s3c64xx.shift);
> +	s3c64xx_sched_timer_start(~0, 1);
> +
> +	if (clocksource_register(&clocksource_s3c64xx))
> +		printk(KERN_ERR "%s: can't register clocksource\n",
> +			clocksource_s3c64xx.name);
> +}
> +
> +/*
> + * ---------------------------------------------------------------------------
> + *  Tick Timer initialization
> + * ---------------------------------------------------------------------------
> + */
> +static void s3c64xx_dynamic_timer_setup(void)
> +{
> +	struct clk	*ck_ref = clk_get(NULL, "timers");
> +	unsigned long	rate;
> +
> +	if (IS_ERR(ck_ref))
> +		panic("failed to get clock for system timer");
> +
> +	rate = clk_get_rate(ck_ref);
> +	clk_put(ck_ref);
> +
> +	s3c64xx_init_dynamic_tick_timer(rate);
> +	s3c64xx_init_clocksource(rate);
> +}
> +
> +static void s3c64xx_timer_setup(void)
> +{
> +	struct clk	*ck_ref = clk_get(NULL, "timers");
> +	unsigned long	rate;
> +
> +	if (IS_ERR(ck_ref))
> +		panic("failed to get clock for system timer");
> +
> +	rate = clk_get_rate(ck_ref);
> +	clk_put(ck_ref);
> +	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
> +	s3c64xx_sched_timer_start(~0, 1);
> +}
> +
> +
> +static void __init s3c64xx_dynamic_timer_init(void)
> +{
> +	s3c64xx_dynamic_timer_setup();
> +	setup_irq(IRQ_TIMER2, &s3c64xx_timer2_irq);
> +	setup_irq(IRQ_TIMER4, &s3c64xx_tick_timer_irq);
> +}
> +
> +
> +struct sys_timer s3c24xx_timer = {
> +	.init		= s3c64xx_dynamic_timer_init,
> +};

If we want both timer and highres timer support, this will need to
get renamed.

> diff --git a/arch/arm/plat-s3c/include/plat/regs-timer.h b/arch/arm/plat-s3c/include/plat/regs-timer.h
> index d097d92..e9994db 100644
> --- a/arch/arm/plat-s3c/include/plat/regs-timer.h
> +++ b/arch/arm/plat-s3c/include/plat/regs-timer.h
> @@ -117,6 +117,17 @@
>  #define S3C2410_TCON_T0INVERT	  (1<<2)
>  #define S3C2410_TCON_T0MANUALUPD  (1<<1)
>  #define S3C2410_TCON_T0START	  (1<<0)
> +/* Interrupt Control and Status register*/
> +#define S3C_TINT_CSTAT_T4INT	(1<<9)
> +#define S3C_TINT_CSTAT_T3INT	(1<<8)
> +#define S3C_TINT_CSTAT_T2INT	(1<<7)
> +#define S3C_TINT_CSTAT_T1INT	(1<<6)
> +#define S3C_TINT_CSTAT_T0INT	(1<<5)
> +#define S3C_TINT_CSTAT_T4INTEN	(1<<4)
> +#define S3C_TINT_CSTAT_T3INTEN	(1<<3)
> +#define S3C_TINT_CSTAT_T2INTEN	(1<<2)
> +#define S3C_TINT_CSTAT_T1INTEN	(1<<1)
> +#define S3C_TINT_CSTAT_T0INTEN	(1<<0)
>  
>  #endif /*  __ASM_ARCH_REGS_TIMER_H */

how about defining the following:

#define S3C_TINT_CTSTA_INTEN(x)	(1 << (x))
#define S3C_TINT_CSTAT_INT(x)	(1 << ((x) + 5))

-- 
Ben

Q:      What's a light-year?
A:      One-third less calories than a regular year.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] [ARM] [S3C64XX] Add support for hr timer
@ 2009-12-01  8:39 aditya
  2010-01-08  5:47 ` Ben Dooks
  0 siblings, 1 reply; 6+ messages in thread
From: aditya @ 2009-12-01  8:39 UTC (permalink / raw)
  To: linux-arm-kernel

This patch add support for the S3C64XX hr timer.

Signed-off-by: Aditya Pratap Sharma <aditya.ps@samsung.com>
---
 arch/arm/mach-s3c6410/Kconfig               |    2 +
 arch/arm/plat-s3c/Makefile                  |   10 +
 arch/arm/plat-s3c/hr-time.c                 |  301 +++++++++++++++++++++++++++
 arch/arm/plat-s3c/include/plat/regs-timer.h |   11 +
 4 files changed, 324 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s3c/hr-time.c

diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
index f9d0f09..29cfd0c 100644
--- a/arch/arm/mach-s3c6410/Kconfig
+++ b/arch/arm/mach-s3c6410/Kconfig
@@ -11,6 +11,8 @@ config CPU_S3C6410
 	bool
 	select CPU_S3C6400_INIT
 	select CPU_S3C6400_CLOCK
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
 	help
 	  Enable S3C6410 CPU support
 
diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
index 3c09109..6c612aa 100644
--- a/arch/arm/plat-s3c/Makefile
+++ b/arch/arm/plat-s3c/Makefile
@@ -12,7 +12,17 @@ obj-				:=
 # Core support for all Samsung SoCs
 
 obj-y				+=  init.o
+ifdef CONFIG_NO_HZ
+obj-y				+= hr-time.o
+else
+
+ifndef CONFIG_HIGH_RES_TIMERS
 obj-y				+= time.o
+else
+obj-y				+= hr-time.o
+endif
+
+endif
 obj-y				+= clock.o
 obj-y				+= pwm-clock.o
 obj-y				+= gpio.o
diff --git a/arch/arm/plat-s3c/hr-time.c b/arch/arm/plat-s3c/hr-time.c
new file mode 100644
index 0000000..76fd91f
--- /dev/null
+++ b/arch/arm/plat-s3c/hr-time.c
@@ -0,0 +1,301 @@
+/*
+ * linux/arch/arm/plat-s3c/hr-time.c
+ *
+ * S3C6410 high resolution Timers
+ *
+ * Copyright (c) 2006 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-irq.h>
+#include <mach/tick.h>
+#include <plat/regs-timer.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+
+static void s3c64xx_timer_setup(void);
+
+static inline void s3c64xx_tick_set_autoreset(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon |= (S3C2410_TCON_T4RELOAD);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static inline void s3c64xx_tick_remove_autoreset(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon &= ~(S3C2410_TCON_T4RELOAD);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s3c64xx_tick_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcfg1;
+	unsigned long tcfg0;
+	unsigned long tcstat;
+
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcfg1 = __raw_readl(S3C2410_TCFG1);
+	tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
+	tcstat |=  S3C_TINT_CSTAT_T4INTEN;
+	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
+	__raw_writel(load_val - 1, S3C2410_TCNTB(4));
+
+	tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
+	tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
+
+	tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+	tcfg0 |= (0) << S3C2410_TCFG_PRESCALER1_SHIFT;
+
+	__raw_writel(tcfg1, S3C2410_TCFG1);
+	__raw_writel(tcfg0, S3C2410_TCFG0);
+
+	tcon &= ~(S3C2410_TCON_T4START|S3C2410_TCON_T4MANUALUPD
+					|S3C2410_TCON_T4RELOAD);
+	tcon |= S3C2410_TCON_T4MANUALUPD;
+	if (autoreset)
+		tcon |= S3C2410_TCON_T4RELOAD;
+	__raw_writel(tcon, S3C2410_TCON);
+
+	/* start the timer running */
+	tcon |= S3C2410_TCON_T4START;
+	tcon &= ~S3C2410_TCON_T4MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static inline void s3c64xx_tick_timer_stop(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon &= ~(S3C2410_TCON_T4START);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s3c64xx_sched_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcfg1;
+	unsigned long tcfg0;
+	unsigned long tcstat;
+
+	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
+	tcstat |=  S3C_TINT_CSTAT_T2INTEN;
+	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
+
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcfg1 = __raw_readl(S3C2410_TCFG1);
+	tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+	__raw_writel(load_val - 1, S3C2410_TCNTB(2));
+	__raw_writel(load_val - 1, S3C2410_TCMPB(2));
+
+	tcon &= ~(S3C2410_TCON_T2RELOAD|(!S3C2410_TCON_T2INVERT)
+			|S3C2410_TCON_T2MANUALUPD|S3C2410_TCON_T2START);
+	if (autoreset)
+		tcon |= S3C2410_TCON_T2RELOAD;
+	tcon |= S3C2410_TCON_T2MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+
+	/* start the timer running */
+	tcon |= S3C2410_TCON_T2START;
+	tcon &= ~S3C2410_TCON_T2MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * PWM timer 4 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static int s3c64xx_tick_set_next_event(unsigned long cycles,
+				   struct clock_event_device *evt)
+{
+	s3c64xx_tick_timer_start(cycles, 0);
+	return 0;
+}
+static void s3c64xx_tick_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		s3c64xx_tick_set_autoreset();
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		s3c64xx_tick_timer_stop();
+		s3c64xx_tick_remove_autoreset();
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		s3c64xx_timer_setup();
+		break;
+	}
+}
+
+static struct clock_event_device tick_tmr = {
+	.name		= "pwm_timer4",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_next_event	= s3c64xx_tick_set_next_event,
+	.set_mode	= s3c64xx_tick_set_mode,
+};
+
+irqreturn_t s3c64xx_tick_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &tick_tmr;
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction s3c64xx_tick_timer_irq = {
+	.name		= "pwm_timer4",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= s3c64xx_tick_timer_interrupt,
+};
+
+static void __init s3c64xx_init_dynamic_tick_timer(unsigned long rate)
+{
+	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
+	tick_tmr.mult = div_sc(rate, NSEC_PER_SEC, tick_tmr.shift);
+	tick_tmr.max_delta_ns = clockevent_delta2ns(-1, &tick_tmr);
+	tick_tmr.min_delta_ns = clockevent_delta2ns(1, &tick_tmr);
+
+	tick_tmr.cpumask = get_cpu_mask(0);
+	clockevents_register_device(&tick_tmr);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * PWM timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
+ */
+static unsigned long s3c64xx_mpu_timer2_overflows;
+
+irqreturn_t s3c64xx_mpu_timer2_interrupt(int irq, void *dev_id)
+{
+	s3c64xx_mpu_timer2_overflows++;
+	return IRQ_HANDLED;
+}
+
+struct irqaction s3c64xx_timer2_irq = {
+	.name		= "pwm_timer2",
+	.flags		= IRQF_DISABLED ,
+	.handler	= s3c64xx_mpu_timer2_interrupt,
+};
+
+
+/* Read timer 2 Count Observation Register */
+static cycle_t s3c64xx_sched_timer_read(struct clocksource *cs)
+{
+	return (cycle_t)~__raw_readl(S3C_TIMERREG(0x2c));
+}
+
+struct clocksource clocksource_s3c64xx = {
+	.name		= "clock_source_timer2",
+	.rating		= 300,
+	.read		= s3c64xx_sched_timer_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s3c64xx_init_clocksource(unsigned long rate)
+{
+	clocksource_s3c64xx.mult
+		= clocksource_khz2mult(rate/1000, clocksource_s3c64xx.shift);
+	s3c64xx_sched_timer_start(~0, 1);
+
+	if (clocksource_register(&clocksource_s3c64xx))
+		printk(KERN_ERR "%s: can't register clocksource\n",
+			clocksource_s3c64xx.name);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  Tick Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void s3c64xx_dynamic_timer_setup(void)
+{
+	struct clk	*ck_ref = clk_get(NULL, "timers");
+	unsigned long	rate;
+
+	if (IS_ERR(ck_ref))
+		panic("failed to get clock for system timer");
+
+	rate = clk_get_rate(ck_ref);
+	clk_put(ck_ref);
+
+	s3c64xx_init_dynamic_tick_timer(rate);
+	s3c64xx_init_clocksource(rate);
+}
+
+static void s3c64xx_timer_setup(void)
+{
+	struct clk	*ck_ref = clk_get(NULL, "timers");
+	unsigned long	rate;
+
+	if (IS_ERR(ck_ref))
+		panic("failed to get clock for system timer");
+
+	rate = clk_get_rate(ck_ref);
+	clk_put(ck_ref);
+	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
+	s3c64xx_sched_timer_start(~0, 1);
+}
+
+
+static void __init s3c64xx_dynamic_timer_init(void)
+{
+	s3c64xx_dynamic_timer_setup();
+	setup_irq(IRQ_TIMER2, &s3c64xx_timer2_irq);
+	setup_irq(IRQ_TIMER4, &s3c64xx_tick_timer_irq);
+}
+
+
+struct sys_timer s3c24xx_timer = {
+	.init		= s3c64xx_dynamic_timer_init,
+};
+
diff --git a/arch/arm/plat-s3c/include/plat/regs-timer.h b/arch/arm/plat-s3c/include/plat/regs-timer.h
index d097d92..e9994db 100644
--- a/arch/arm/plat-s3c/include/plat/regs-timer.h
+++ b/arch/arm/plat-s3c/include/plat/regs-timer.h
@@ -117,6 +117,17 @@
 #define S3C2410_TCON_T0INVERT	  (1<<2)
 #define S3C2410_TCON_T0MANUALUPD  (1<<1)
 #define S3C2410_TCON_T0START	  (1<<0)
+/* Interrupt Control and Status register*/
+#define S3C_TINT_CSTAT_T4INT	(1<<9)
+#define S3C_TINT_CSTAT_T3INT	(1<<8)
+#define S3C_TINT_CSTAT_T2INT	(1<<7)
+#define S3C_TINT_CSTAT_T1INT	(1<<6)
+#define S3C_TINT_CSTAT_T0INT	(1<<5)
+#define S3C_TINT_CSTAT_T4INTEN	(1<<4)
+#define S3C_TINT_CSTAT_T3INTEN	(1<<3)
+#define S3C_TINT_CSTAT_T2INTEN	(1<<2)
+#define S3C_TINT_CSTAT_T1INTEN	(1<<1)
+#define S3C_TINT_CSTAT_T0INTEN	(1<<0)
 
 #endif /*  __ASM_ARCH_REGS_TIMER_H */
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] [ARM] [S3C64XX] Add support for hr timer
  2009-11-06  5:58 ` Harald Welte
@ 2009-11-11  5:38   ` Aditya Sharma
  0 siblings, 0 replies; 6+ messages in thread
From: Aditya Sharma @ 2009-11-11  5:38 UTC (permalink / raw)
  To: Harald Welte; +Cc: linux-samsung-soc

Hi Harald,

On Fri, Nov 6, 2009 at 2:58 PM, Harald Welte <laforge@gnumonks.org> wrote:
> Hi Aditya,
>
> thanks for your [first] patch :)
>
> On Fri, Nov 06, 2009 at 09:45:45AM +0900, aditya.ps@samsung.com wrote:
>> +
>> +choice
>> +     prompt "OS Timer support"
>> +     depends on PLAT_S3C64XX
>> +     default DYNAMIC_TIMER
>> +
>> +config FIXED_TIMER
>> +     bool "Fixed Tick timer"
>> +
>> +config DYNAMIC_TIMER
>> +     bool "Tickless and HR Timer"
>> +     select GENERIC_TIME
>> +     select GENERIC_CLOCKEVENTS
>
> I think those should probably be prefixed with S3C_ as the Kconfig namespace
> is global.  Like with symbol names, we should not use generic names unless
> we are implementing generic code.
>
>>  obj-y                                +=  init.o
>> +ifdef CONFIG_NO_HZ
>> +obj-y                                += hr-time.o
>> +else
>> +
>> +ifndef CONFIG_HIGH_RES_TIMERS
>>  obj-y                                += time.o
>> +else
>> +obj-y                                += hr-time.o
>> +endif
>
> Mh.  This means the actual timer code depends only on CONFIG_NO_HZ and
> CONFIG_HIGH_RES_TIMERS.
>
> The two Kconfig choices FIXED_TIMER and DYNAMIC_TIMER are not really used
> anywhere.
>
> At last to me, it is unclear how this all works together. I think the choices
> are either
>
> 1) you build the timer code solely on core kernel configuration options like
>   GENERIC_TIME, GENERIC_CLOCKEVENTS, HIGH_RES_TIMERS, NO_HZ or the like
>

Yes, selected the GENERIC_TIME, GENERIC_CLOCKEVENTS during machine
configuration.

> or
>
> 2) you have a private (s3c-specific) Kconfig option to select it.  In this case,
>   dependent options need to be selected (like you do).  But then, the Makefile
>   should still reflect the s3c-specific Kconfig.
>
> Mixing both does not really seem to make sense to me.
>
> So as I can see, there are the three following possible cases:
>
> a) the regular/old timer code is used.  No high-res and no tickless.
>
> b) the high-resolution timer is used but not tickless (NO_HZ not set)
>
> c) the high-resolution timer are used tickless.
>
> If you configure+build yoru code, each of those three options has to work
> as expected.
>
>> +static struct clock_event_device clockevent_tick_timer = {
>> +     .name           = "pwm_timer4",
>> +     .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
>> +     .shift          = 32,
>> +     .set_next_event = s3c64xx_tick_set_next_event,
>> +     .set_mode       = s3c64xx_tick_set_mode,
>> +};
>
> if you give this static variable a shorter name, (like clkevt_tick_tmr or even
> only tick_timer), then you can probably avoid some line wraps further down the
> code:
>
>> +     clockevent_tick_timer.mult = div_sc(rate, NSEC_PER_SEC,
>> +                                         clockevent_tick_timer.shift);
>> +     clockevent_tick_timer.max_delta_ns =
>> +             clockevent_delta2ns(-1, &clockevent_tick_timer);
>> +     clockevent_tick_timer.min_delta_ns =
>> +             clockevent_delta2ns(1, &clockevent_tick_timer);
>
> Also, we typically don't define a static string and then printk'
>
>> +     static char err[] __initdata = KERN_ERR
>> +                     "%s: can't register clocksource!\n";
>> +             printk(err, clocksource_s3c64xx.name);
>
> why not simply
>                printk(KERN_ERR "%s: can't register clocksource\n",
>                        clocksource_s3c64xx.name);
>

i have made these changes in the new patch.

>> +     if (IS_ERR(ck_ref))
>> +             panic("failed to get clock for system timer");
>
> here we panic.  Is this failure really more severe than the failure above
> where we simply printk(KERN_ERR) ?
>
> Yes, I think if we can't get the clocks for the system timer, then we should
> panic since the kernel will not be able to function.  But is failing the
> clocksource registration any less severe? (this is a real question, you
> probably know better than I do)
>
> Regards,
>        Harald
> --
> - Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
> ============================================================================
> "Privacy in residential applications is a desirable marketing option."
>                                                  (ETSI EN 300 175-7 Ch. A6)
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Thanks and best regards
Aditya

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] [ARM] [S3C64XX] Add support for hr timer
  2009-11-06  0:45 aditya.ps
@ 2009-11-06  5:58 ` Harald Welte
  2009-11-11  5:38   ` Aditya Sharma
  0 siblings, 1 reply; 6+ messages in thread
From: Harald Welte @ 2009-11-06  5:58 UTC (permalink / raw)
  To: aditya.ps; +Cc: linux-samsung-soc

Hi Aditya,

thanks for your [first] patch :)

On Fri, Nov 06, 2009 at 09:45:45AM +0900, aditya.ps@samsung.com wrote:
> +
> +choice
> +	prompt "OS Timer support"
> +	depends on PLAT_S3C64XX
> +	default DYNAMIC_TIMER
> +
> +config FIXED_TIMER
> +	bool "Fixed Tick timer"
> +
> +config DYNAMIC_TIMER
> +	bool "Tickless and HR Timer"
> +	select GENERIC_TIME
> +	select GENERIC_CLOCKEVENTS

I think those should probably be prefixed with S3C_ as the Kconfig namespace
is global.  Like with symbol names, we should not use generic names unless
we are implementing generic code.

>  obj-y				+=  init.o
> +ifdef CONFIG_NO_HZ
> +obj-y				+= hr-time.o
> +else
> +
> +ifndef CONFIG_HIGH_RES_TIMERS
>  obj-y				+= time.o
> +else
> +obj-y				+= hr-time.o
> +endif

Mh.  This means the actual timer code depends only on CONFIG_NO_HZ and
CONFIG_HIGH_RES_TIMERS.

The two Kconfig choices FIXED_TIMER and DYNAMIC_TIMER are not really used
anywhere.

At last to me, it is unclear how this all works together. I think the choices
are either

1) you build the timer code solely on core kernel configuration options like
   GENERIC_TIME, GENERIC_CLOCKEVENTS, HIGH_RES_TIMERS, NO_HZ or the like

or

2) you have a private (s3c-specific) Kconfig option to select it.  In this case,
   dependent options need to be selected (like you do).  But then, the Makefile
   should still reflect the s3c-specific Kconfig.

Mixing both does not really seem to make sense to me.

So as I can see, there are the three following possible cases:

a) the regular/old timer code is used.  No high-res and no tickless.

b) the high-resolution timer is used but not tickless (NO_HZ not set)

c) the high-resolution timer are used tickless.

If you configure+build yoru code, each of those three options has to work
as expected.  

> +static struct clock_event_device clockevent_tick_timer = {
> +	.name		= "pwm_timer4",
> +	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +	.shift		= 32,
> +	.set_next_event	= s3c64xx_tick_set_next_event,
> +	.set_mode	= s3c64xx_tick_set_mode,
> +};

if you give this static variable a shorter name, (like clkevt_tick_tmr or even
only tick_timer), then you can probably avoid some line wraps further down the
code:

> +	clockevent_tick_timer.mult = div_sc(rate, NSEC_PER_SEC,
> +					    clockevent_tick_timer.shift);
> +	clockevent_tick_timer.max_delta_ns =
> +		clockevent_delta2ns(-1, &clockevent_tick_timer);
> +	clockevent_tick_timer.min_delta_ns =
> +		clockevent_delta2ns(1, &clockevent_tick_timer);

Also, we typically don't define a static string and then printk'

> +	static char err[] __initdata = KERN_ERR
> +			"%s: can't register clocksource!\n";
> +		printk(err, clocksource_s3c64xx.name);

why not simply 
		printk(KERN_ERR "%s: can't register clocksource\n",
			clocksource_s3c64xx.name);

> +	if (IS_ERR(ck_ref))
> +		panic("failed to get clock for system timer");

here we panic.  Is this failure really more severe than the failure above
where we simply printk(KERN_ERR) ?

Yes, I think if we can't get the clocks for the system timer, then we should
panic since the kernel will not be able to function.  But is failing the
clocksource registration any less severe? (this is a real question, you
probably know better than I do)

Regards,
	Harald
-- 
- Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] [ARM] [S3C64XX] Add support for hr timer
@ 2009-11-06  0:45 aditya.ps
  2009-11-06  5:58 ` Harald Welte
  0 siblings, 1 reply; 6+ messages in thread
From: aditya.ps @ 2009-11-06  0:45 UTC (permalink / raw)
  To: linux-samsung-soc; +Cc: aditya

From: aditya <aditya.ps@samsung.com>

This patch add support for the S3C64XX hr timer (tick timer and sched timer).

Signed-off-by: Aditya Pratap Sharma <aditya.ps@samsung.com>
---
 arch/arm/plat-s3c/Kconfig                   |   18 ++
 arch/arm/plat-s3c/Makefile                  |   10 +
 arch/arm/plat-s3c/hr-time.c                 |  305 +++++++++++++++++++++++++++
 arch/arm/plat-s3c/include/plat/regs-timer.h |   11 +
 4 files changed, 344 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s3c/hr-time.c

diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
index 8931c5f..6568c21 100644
--- a/arch/arm/plat-s3c/Kconfig
+++ b/arch/arm/plat-s3c/Kconfig
@@ -203,4 +203,22 @@ config S3C_DEV_NAND
 	help
 	  Compile in platform device definition for NAND controller
 
+#option for OS tick timer (fixed/dynamic)
+
+choice
+	prompt "OS Timer support"
+	depends on PLAT_S3C64XX
+	default DYNAMIC_TIMER
+
+config FIXED_TIMER
+	bool "Fixed Tick timer"
+
+config DYNAMIC_TIMER
+	bool "Tickless and HR Timer"
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+
+endchoice
+
+
 endif
diff --git a/arch/arm/plat-s3c/Makefile b/arch/arm/plat-s3c/Makefile
index 3c09109..6c612aa 100644
--- a/arch/arm/plat-s3c/Makefile
+++ b/arch/arm/plat-s3c/Makefile
@@ -12,7 +12,17 @@ obj-				:=
 # Core support for all Samsung SoCs
 
 obj-y				+=  init.o
+ifdef CONFIG_NO_HZ
+obj-y				+= hr-time.o
+else
+
+ifndef CONFIG_HIGH_RES_TIMERS
 obj-y				+= time.o
+else
+obj-y				+= hr-time.o
+endif
+
+endif
 obj-y				+= clock.o
 obj-y				+= pwm-clock.o
 obj-y				+= gpio.o
diff --git a/arch/arm/plat-s3c/hr-time.c b/arch/arm/plat-s3c/hr-time.c
new file mode 100644
index 0000000..10cd159
--- /dev/null
+++ b/arch/arm/plat-s3c/hr-time.c
@@ -0,0 +1,305 @@
+/*
+ * linux/arch/arm/plat-s3c/hr-time.c
+ *
+ * S3C6410 high resolution Timers
+ *
+ * Copyright (c) 2006 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-irq.h>
+#include <mach/tick.h>
+#include <plat/regs-timer.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+
+static void s3c64xx_timer_setup(void);
+
+static inline void s3c64xx_tick_set_autoreset(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon |= (S3C2410_TCON_T4RELOAD);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static inline void s3c64xx_tick_remove_autoreset(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon &= ~(S3C2410_TCON_T4RELOAD);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s3c64xx_tick_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcfg1;
+	unsigned long tcfg0;
+	unsigned long tcstat;
+
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcfg1 = __raw_readl(S3C2410_TCFG1);
+	tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
+	tcstat |=  S3C_TINT_CSTAT_T4INTEN;
+	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
+	__raw_writel(load_val - 1, S3C2410_TCNTB(4));
+
+	tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
+	tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
+
+	tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+	tcfg0 |= (0) << S3C2410_TCFG_PRESCALER1_SHIFT;
+
+	__raw_writel(tcfg1, S3C2410_TCFG1);
+	__raw_writel(tcfg0, S3C2410_TCFG0);
+
+	tcon &= ~(S3C2410_TCON_T4START|S3C2410_TCON_T4MANUALUPD
+					|S3C2410_TCON_T4RELOAD);
+	tcon |= S3C2410_TCON_T4MANUALUPD;
+	if (autoreset)
+		tcon |= S3C2410_TCON_T4RELOAD;
+	__raw_writel(tcon, S3C2410_TCON);
+
+	/* start the timer running */
+	tcon |= S3C2410_TCON_T4START;
+	tcon &= ~S3C2410_TCON_T4MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static inline void s3c64xx_tick_timer_stop(void)
+{
+	unsigned long tcon;
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcon &= ~(S3C2410_TCON_T4START);
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+static void s3c64xx_sched_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcfg1;
+	unsigned long tcfg0;
+	unsigned long tcstat;
+
+	tcstat = __raw_readl(S3C64XX_TINT_CSTAT);
+	tcstat |=  S3C_TINT_CSTAT_T2INTEN;
+	__raw_writel(tcstat, S3C64XX_TINT_CSTAT);
+
+	tcon  = __raw_readl(S3C2410_TCON);
+	tcfg1 = __raw_readl(S3C2410_TCFG1);
+	tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+	__raw_writel(load_val - 1, S3C2410_TCNTB(2));
+	__raw_writel(load_val - 1, S3C2410_TCMPB(2));
+
+	tcon &= ~(S3C2410_TCON_T2RELOAD|(!S3C2410_TCON_T2INVERT)
+			|S3C2410_TCON_T2MANUALUPD|S3C2410_TCON_T2START);
+	if (autoreset)
+		tcon |= S3C2410_TCON_T2RELOAD;
+	tcon |= S3C2410_TCON_T2MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+
+	/* start the timer running */
+	tcon |= S3C2410_TCON_T2START;
+	tcon &= ~S3C2410_TCON_T2MANUALUPD;
+	__raw_writel(tcon, S3C2410_TCON);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * PWM timer 4 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static int s3c64xx_tick_set_next_event(unsigned long cycles,
+				   struct clock_event_device *evt)
+{
+	s3c64xx_tick_timer_start(cycles, 0);
+	return 0;
+}
+static void s3c64xx_tick_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		s3c64xx_tick_set_autoreset();
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		s3c64xx_tick_timer_stop();
+		s3c64xx_tick_remove_autoreset();
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		s3c64xx_timer_setup();
+		break;
+	}
+}
+
+static struct clock_event_device clockevent_tick_timer = {
+	.name		= "pwm_timer4",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_next_event	= s3c64xx_tick_set_next_event,
+	.set_mode	= s3c64xx_tick_set_mode,
+};
+
+irqreturn_t s3c64xx_tick_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &clockevent_tick_timer;
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction s3c64xx_tick_timer_irq = {
+	.name		= "pwm_timer4",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= s3c64xx_tick_timer_interrupt,
+};
+
+static void __init s3c64xx_init_dynamic_tick_timer(unsigned long rate)
+{
+	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
+	clockevent_tick_timer.mult = div_sc(rate, NSEC_PER_SEC,
+					    clockevent_tick_timer.shift);
+	clockevent_tick_timer.max_delta_ns =
+		clockevent_delta2ns(-1, &clockevent_tick_timer);
+	clockevent_tick_timer.min_delta_ns =
+		clockevent_delta2ns(1, &clockevent_tick_timer);
+
+	clockevent_tick_timer.cpumask = get_cpu_mask(0);
+	clockevents_register_device(&clockevent_tick_timer);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * PWM timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
+ */
+static unsigned long s3c64xx_mpu_timer2_overflows;
+
+irqreturn_t s3c64xx_mpu_timer2_interrupt(int irq, void *dev_id)
+{
+	s3c64xx_mpu_timer2_overflows++;
+	return IRQ_HANDLED;
+}
+
+struct irqaction s3c64xx_timer2_irq = {
+	.name		= "pwm_timer2",
+	.flags		= IRQF_DISABLED ,
+	.handler	= s3c64xx_mpu_timer2_interrupt,
+};
+
+
+/* Read timer 2 Count Observation Register */
+static cycle_t s3c64xx_sched_timer_read(struct clocksource *cs)
+{
+	return (cycle_t)~__raw_readl(S3C_TIMERREG(0x2c));
+}
+
+struct clocksource clocksource_s3c64xx = {
+	.name		= "clock_source_timer2",
+	.rating		= 300,
+	.read		= s3c64xx_sched_timer_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS ,
+};
+
+static void __init s3c64xx_init_clocksource(unsigned long rate)
+{
+	static char err[] __initdata = KERN_ERR
+			"%s: can't register clocksource!\n";
+	clocksource_s3c64xx.mult
+		= clocksource_khz2mult(rate/1000, clocksource_s3c64xx.shift);
+	s3c64xx_sched_timer_start(~0, 1);
+
+	if (clocksource_register(&clocksource_s3c64xx))
+		printk(err, clocksource_s3c64xx.name);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ *  Tick Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void s3c64xx_dynamic_timer_setup(void)
+{
+	struct clk	*ck_ref = clk_get(NULL, "timers");
+	unsigned long	rate;
+
+	if (IS_ERR(ck_ref))
+		panic("failed to get clock for system timer");
+
+	rate = clk_get_rate(ck_ref);
+	clk_put(ck_ref);
+
+	s3c64xx_init_dynamic_tick_timer(rate);
+	s3c64xx_init_clocksource(rate);
+}
+
+static void s3c64xx_timer_setup(void)
+{
+	struct clk	*ck_ref = clk_get(NULL, "timers");
+	unsigned long	rate;
+
+	if (IS_ERR(ck_ref))
+		panic("failed to get clock for system timer");
+
+	rate = clk_get_rate(ck_ref);
+	clk_put(ck_ref);
+	s3c64xx_tick_timer_start((rate / HZ) - 1, 1);
+	s3c64xx_sched_timer_start(~0, 1);
+}
+
+
+static void __init s3c64xx_dynamic_timer_init(void)
+{
+	s3c64xx_dynamic_timer_setup();
+	setup_irq(IRQ_TIMER2, &s3c64xx_timer2_irq);
+	setup_irq(IRQ_TIMER4, &s3c64xx_tick_timer_irq);
+}
+
+
+struct sys_timer s3c24xx_timer = {
+	.init		= s3c64xx_dynamic_timer_init,
+};
+
diff --git a/arch/arm/plat-s3c/include/plat/regs-timer.h b/arch/arm/plat-s3c/include/plat/regs-timer.h
index d097d92..e9994db 100644
--- a/arch/arm/plat-s3c/include/plat/regs-timer.h
+++ b/arch/arm/plat-s3c/include/plat/regs-timer.h
@@ -117,6 +117,17 @@
 #define S3C2410_TCON_T0INVERT	  (1<<2)
 #define S3C2410_TCON_T0MANUALUPD  (1<<1)
 #define S3C2410_TCON_T0START	  (1<<0)
+/* Interrupt Control and Status register*/
+#define S3C_TINT_CSTAT_T4INT	(1<<9)
+#define S3C_TINT_CSTAT_T3INT	(1<<8)
+#define S3C_TINT_CSTAT_T2INT	(1<<7)
+#define S3C_TINT_CSTAT_T1INT	(1<<6)
+#define S3C_TINT_CSTAT_T0INT	(1<<5)
+#define S3C_TINT_CSTAT_T4INTEN	(1<<4)
+#define S3C_TINT_CSTAT_T3INTEN	(1<<3)
+#define S3C_TINT_CSTAT_T2INTEN	(1<<2)
+#define S3C_TINT_CSTAT_T1INTEN	(1<<1)
+#define S3C_TINT_CSTAT_T0INTEN	(1<<0)
 
 #endif /*  __ASM_ARCH_REGS_TIMER_H */
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-01-08  5:47 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-11  5:41 [PATCH] [ARM] [S3C64XX] Add support for hr timer aditya.ps
  -- strict thread matches above, loose matches on Subject: below --
2009-12-01  8:39 aditya
2010-01-08  5:47 ` Ben Dooks
2009-11-06  0:45 aditya.ps
2009-11-06  5:58 ` Harald Welte
2009-11-11  5:38   ` Aditya Sharma

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.