linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH]HRT support in Samsung S5P Platform
@ 2010-07-19  6:54 MADHAV SINGHCHAUHAN
  2010-07-21  0:36 ` Ben Dooks
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: MADHAV SINGHCHAUHAN @ 2010-07-19  6:54 UTC (permalink / raw)
  To: linux-arm-kernel

From: Madhav Singh <singh.madhav@samsung.com>
Date: Mon, 19 Jul 2010 10:51:01 +0530
Subject: [PATCH] HRT support in Samsung Tree
This patch implements HRT support for Samsung plat-s5p.
RTC has been used as CLOCKEVENT and SYSTIMER as CLOCKSOURCE.

Signed-off-by: Madhav Chauhan <singh.madhav@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv210/Kconfig                   |    9 +
 arch/arm/mach-s5pv210/include/mach/map.h        |    4 +
 arch/arm/plat-s5p/clock.c                       |   15 +
 arch/arm/plat-s5p/cpu.c                         |    8 +
 arch/arm/plat-s5p/hr-time-rtc.c                 |  470 +++++++++++++++++++++++
 arch/arm/plat-s5p/include/plat/regs-sys-timer.h |   63 +++
 arch/arm/plat-samsung/include/plat/map-base.h   |    2 +
 7 files changed, 571 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s5p/hr-time-rtc.c
 create mode 100644 arch/arm/plat-s5p/include/plat/regs-sys-timer.h

diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 631019a..9d8698e 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -101,4 +101,13 @@ config MACH_SMDKC110
 	  Machine support for Samsung SMDKC110
 	  S5PC110(MCP) is one of package option of S5PV210
 
+config MACH_S5PV210_HRT
+        bool "HRtimer and Dynamic Tick support"
+        select GENERIC_TIME
+        select GENERIC_CLOCKEVENTS
+        select HIGH_RES_TIMERS
+        default n
+        help
+          Support for HRtimer and Dynamic Tick system using RTC and SYSTEM timer
+
 endif
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index 17687f0..fd8e504 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -42,6 +42,10 @@
 #define S5P_PA_TIMER		S5PV210_PA_TIMER
 
 #define S5PV210_PA_SYSTIMER	(0xE2600000)
+/*For RTC*/
+#define S5PC11X_PA_RTC		(0xE2800000)
+#define S3C_PA_RTC		S5PC11X_PA_RTC
+
 
 #define S5PV210_PA_WATCHDOG	(0xE2700000)
 
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index b5e2552..1e2a6f4 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -89,6 +89,19 @@ struct clk clk_arm = {
 	.ctrlbit	= 0,
 };
 
+/*For HRT*/
+struct clk clk_ext_xtal_rtc = {
+	.name		= "XrtcXTI",
+	.id		= -1,
+	.rate           = 32768,
+};
+
+struct clk clk_ext_xtal_usb = {
+	.name		= "XusbXTI",
+	.id		= -1,
+	.rate		= 24000000,
+};
+
 /* Possible clock sources for APLL Mux */
 static struct clk *clk_src_apll_list[] = {
 	[0] = &clk_fin_apll,
@@ -149,6 +162,8 @@ static struct clk *s5p_clks[] __initdata = {
 	&clk_arm,
 	&clk_vpll,
 	&clk_xusbxti,
+	&clk_ext_xtal_usb,
+	&clk_ext_xtal_rtc,
 };
 
 void __init s5p_register_clocks(unsigned long xtal_freq)
diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c
index 75cb8c3..83ae862 100644
--- a/arch/arm/plat-s5p/cpu.c
+++ b/arch/arm/plat-s5p/cpu.c
@@ -104,6 +104,14 @@ static struct map_desc s5p_iodesc[] __initdata = {
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
 	},
+#if defined(CONFIG_MACH_S5PV210_HRT)
+	{
+		.virtual        = (unsigned long)S3C_VA_RTC,
+		.pfn            = __phys_to_pfn(S3C_PA_RTC),
+		.length         = SZ_4K,
+		.type           = MT_DEVICE,
+	},
+#endif
 };
 
 /* read cpu identification code */
diff --git a/arch/arm/plat-s5p/hr-time-rtc.c b/arch/arm/plat-s5p/hr-time-rtc.c
new file mode 100644
index 0000000..8decf4e
--- /dev/null
+++ b/arch/arm/plat-s5p/hr-time-rtc.c
@@ -0,0 +1,470 @@
+/*
+ * linux/arch/arm/plat-s5p/hr-time-rtc.c
+ *
+ * S5PC11X Timers
+ *
+ * Copyright (c) 2006 Samsung Electronics
+ * Copyright (c) 2010 Samsung Electronics Madhav Chauhan <singh.madhav@samsung.com>
+ *
+ *
+ * S5PC11X (and compatible) HRT support using RTC and SYSTEM TIMER
+ *
+ * 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 <asm/system.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <plat/regs-rtc.h>
+#include <plat/regs-sys-timer.h>
+#include <mach/regs-irq.h>
+#include <mach/tick.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+/*For SCHED_CLOCK*/
+static unsigned long long time_stamp;
+static unsigned long long s5pc11x_sched_timer_overflows;
+static unsigned long long old_overflows;
+static cycle_t last_ticks;
+
+/* Sched timer interrupt is not processed right after
+ * timer counter expired
+ */
+static unsigned int pending_irq;
+
+/* sched_timer_running
+ * 0 : sched timer stopped or not initialized
+ * 1 : sched timer started
+ */
+static unsigned int sched_timer_running;
+
+void __iomem *rtc_base =	S3C_VA_RTC;
+static struct clk *clk_event;
+static struct clk *clk_sched;
+static int tick_timer_mode;	/* 0: oneshot, 1: autoreload */
+
+#define RTC_CLOCK		(32768)
+#define RTC_DEFAULT_TICK	((RTC_CLOCK / HZ) - 1)
+
+/*
+ * Helper functions
+ * s5pc11x_systimer_read() : Read from System timer register
+ * s5pc11x_systimer_write(): Write to System timer register
+ *
+ */
+static unsigned int s5pc11x_systimer_read(unsigned int *reg_offset)
+{
+	return __raw_readl(reg_offset);
+}
+
+static unsigned int s5pc11x_systimer_write(unsigned int *reg_offset,
+					unsigned int value)
+{
+	unsigned int temp_regs;
+
+	__raw_writel(value, reg_offset);
+
+	if (reg_offset == S3C_SYSTIMER_TCON) {
+		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
+				S3C_SYSTIMER_INT_TCON));
+		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
+		temp_regs |= S3C_SYSTIMER_INT_TCON;
+		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
+
+	} else if (reg_offset == S3C_SYSTIMER_ICNTB) {
+		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
+				S3C_SYSTIMER_INT_ICNTB));
+		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
+		temp_regs |= S3C_SYSTIMER_INT_ICNTB;
+		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
+
+	} else if (reg_offset == S3C_SYSTIMER_TCNTB) {
+		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
+				S3C_SYSTIMER_INT_TCNTB));
+		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
+		temp_regs |= S3C_SYSTIMER_INT_TCNTB;
+		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
+	}
+
+	return 0;
+}
+
+static void s5pc11x_rtc_set_tick(int enabled)
+{
+	unsigned int tmp;
+
+	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) & ~S3C_RTCCON_TICEN;
+	if (enabled)
+		tmp |= S3C_RTCCON_TICEN;
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+}
+
+static void s5pc11x_tick_timer_setup(void);
+
+static void s5pc11x_tick_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned int tmp;
+
+	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
+		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+
+	__raw_writel(load_val, rtc_base + S3C2410_TICNT);
+
+	tmp |= S3C_RTCCON_TICEN;
+
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+}
+
+static  void s5pc11x_tick_timer_stop(void)
+{
+	unsigned int tmp;
+
+	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
+		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
+
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+
+}
+
+static void s5pc11x_sched_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcnt;
+	unsigned long tcfg;
+
+	/* clock configuration setting and enable */
+	struct clk *clk;
+
+	tcnt = TICK_MAX;  /* default value for tcnt */
+
+	/* initialize system timer clock */
+	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
+
+	tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
+	tcfg |= S3C_SYSTIMER_TCLK_USB;
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
+
+	/* TCFG must not be changed at run-time.
+	 * If you want to change TCFG, stop timer(TCON[0] = 0)
+	 */
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, 0);
+
+	/* read the current timer configuration bits */
+	tcon = s5pc11x_systimer_read(S3C_SYSTIMER_TCON);
+	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
+
+	clk = clk_get(NULL, "systimer");
+	if (IS_ERR(clk))
+		panic("failed to get clock[%s] for system timer", "systimer");
+
+	clk_enable(clk);
+
+	clk_put(clk);
+
+	tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
+	tcfg |= S3C_SYSTIMER_TCLK_USB;
+	tcfg &= ~S3C_SYSTIMER_PRESCALER_MASK;
+
+	/* check to see if timer is within 16bit range... */
+	if (tcnt > TICK_MAX) {
+		panic("setup_timer: cannot configure timer!");
+		return;
+	}
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCNTB, tcnt);
+
+	/* set timer con */
+	tcon =  S3C_SYSTIMER_INT_AUTO | S3C_SYSTIMER_START |
+			S3C_SYSTIMER_AUTO_RELOAD;
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
+
+	tcon |= S3C_SYSTIMER_INT_START;
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
+
+	/* Interrupt Start and Enable */
+	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT,
+				(S3C_SYSTIMER_INT_ICNTEIE |
+					S3C_SYSTIMER_INT_EN));
+	sched_timer_running = 1;
+}
+
+/*
+ * RTC tick : count down to zero, interrupt, reload
+ */
+static int s5pc11x_tick_set_next_event(unsigned long cycles,
+				   struct clock_event_device *evt)
+{
+	if  (cycles == 0)	/* Should be larger than 0 */
+		cycles = 1;
+	s5pc11x_tick_timer_start(cycles, 0);
+	return 0;
+}
+
+static void s5pc11x_tick_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		tick_timer_mode = 1;
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		s5pc11x_tick_timer_stop();
+		tick_timer_mode = 0;
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		/* Sched timer stopped */
+		sched_timer_running = 0;
+		/* Reset sched_clock variables after sleep/wakeup */
+		last_ticks = 0;
+		s5pc11x_sched_timer_overflows = 0;
+		old_overflows = 0;
+		pending_irq = 0;
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		s5pc11x_tick_timer_setup();
+		s5pc11x_sched_timer_start(~0, 1);
+		break;
+	}
+}
+
+static struct clock_event_device clockevent_tick_timer = {
+	.name		= "S5PC110 event timer",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_next_event	= s5pc11x_tick_set_next_event,
+	.set_mode	= s5pc11x_tick_set_mode,
+};
+
+irqreturn_t s5pc11x_tick_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &clockevent_tick_timer;
+
+	__raw_writel(S3C_INTP_TIC, rtc_base + S3C_INTP);
+	/* In case of oneshot mode */
+	if (tick_timer_mode == 0)
+		s5pc11x_tick_timer_stop();
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction s5pc11x_tick_timer_irq = {
+	.name		= "rtc-tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= s5pc11x_tick_timer_interrupt,
+};
+
+static void  s5pc11x_init_dynamic_tick_timer(unsigned long rate)
+{
+	tick_timer_mode = 1;
+
+	s5pc11x_tick_timer_stop();
+
+	s5pc11x_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 = cpumask_of(0);
+	clockevents_register_device(&clockevent_tick_timer);
+
+	printk(KERN_INFO "mult[%u]\n", clockevent_tick_timer.mult);
+	printk(KERN_INFO "max_delta_ns[%u]\n", clockevent_tick_timer.max_delta_ns);
+	printk(KERN_INFO "min_delta_ns[%u]\n", clockevent_tick_timer.min_delta_ns);
+	printk(KERN_INFO "rate[%lu]\n", rate);
+	printk(KERN_INFO "HZ[%d]\n", HZ);
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * SYSTEM TIMER ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
+ */
+irqreturn_t s5pc11x_sched_timer_interrupt(int irq, void *dev_id)
+{
+	volatile unsigned int temp_cstat;
+
+	temp_cstat = s5pc11x_systimer_read(S3C_SYSTIMER_INT_CSTAT);
+	temp_cstat |= S3C_SYSTIMER_INT_STATS;
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT, temp_cstat);
+
+	if (unlikely(pending_irq))
+		pending_irq = 0;
+	else
+		s5pc11x_sched_timer_overflows++;
+
+	return IRQ_HANDLED;
+}
+
+struct irqaction s5pc11x_systimer_irq = {
+	.name		= "System timer",
+	.flags		= IRQF_DISABLED ,
+	.handler	= s5pc11x_sched_timer_interrupt,
+};
+
+
+static cycle_t s5pc11x_sched_timer_read(void)
+{
+	return (cycle_t)~__raw_readl(S3C_SYSTIMER_TCNTO);
+}
+
+struct clocksource clocksource_s5pc11x = {
+	.name		= "clock_source_systimer",
+	.rating		= 300,
+	.read		= s5pc11x_sched_timer_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void s5pc11x_init_clocksource(unsigned long rate)
+{
+	static char err[] __initdata = KERN_ERR
+			"%s: can't register clocksource!\n";
+
+	clocksource_s5pc11x.mult
+		= clocksource_khz2mult(rate/1000, clocksource_s5pc11x.shift);
+
+
+	s5pc11x_sched_timer_start(~0, 1);
+
+	if (clocksource_register(&clocksource_s5pc11x))
+		printk(err, clocksource_s5pc11x.name);
+}
+
+/*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+	unsigned long irq_flags;
+	cycle_t ticks, elapsed_ticks = 0;
+	unsigned long long increment = 0;
+	unsigned int overflow_cnt = 0;
+
+	local_irq_save(irq_flags);
+
+	if (likely(sched_timer_running)) {
+		overflow_cnt = (s5pc11x_sched_timer_overflows - old_overflows);
+
+		ticks = s5pc11x_sched_timer_read();
+
+		if (overflow_cnt) {
+			increment = (overflow_cnt - 1) *
+					(clocksource_cyc2ns(clocksource_s5pc11x.mask,
+					clocksource_s5pc11x.mult, clocksource_s5pc11x.shift));
+			elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks;
+		} else {
+			if (unlikely(last_ticks > ticks)) {
+				pending_irq = 1;
+				elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks;
+				s5pc11x_sched_timer_overflows++;
+			} else {
+				elapsed_ticks = (ticks - last_ticks);
+			}
+		}
+
+		time_stamp += (clocksource_cyc2ns(elapsed_ticks, clocksource_s5pc11x.mult, clocksource_s5pc11x.shift) + increment);
+
+		old_overflows = s5pc11x_sched_timer_overflows;
+		last_ticks = ticks;
+	}
+	local_irq_restore(irq_flags);
+
+	return time_stamp;
+}
+
+/*
+ *  Event/Sched Timer initialization
+ */
+static void s5pc11x_timer_setup(void)
+{
+	unsigned long rate;
+	/* Setup event timer using XrtcXTI */
+	if (clk_event == NULL)
+		clk_event = clk_get(NULL, "XrtcXTI");
+	if (IS_ERR(clk_event))
+		panic("failed to get clock for event timer");
+	rate = clk_get_rate(clk_event);
+	s5pc11x_init_dynamic_tick_timer(rate);
+
+	/* Setup sched-timer using XusbXTI */
+	if (clk_sched == NULL)
+		clk_sched = clk_get(NULL, "XusbXTI");
+	if (IS_ERR(clk_sched))
+		panic("failed to get clock for sched-timer");
+	rate = clk_get_rate(clk_sched);
+	s5pc11x_init_clocksource(rate);
+}
+
+static void s5pc11x_tick_timer_setup(void)
+{
+	unsigned long rate;
+
+	rate = clk_get_rate(clk_event);
+	s5pc11x_tick_timer_start((rate / HZ) - 1, 1);
+}
+
+static void __init s5pc11x_timer_init(void)
+{
+	/* Initialize variables before starting each timers */
+	last_ticks = 0;
+	s5pc11x_sched_timer_overflows = 0;
+	old_overflows = 0;
+	time_stamp = 0;
+	sched_timer_running = 0;
+	pending_irq = 0;
+	s5pc11x_timer_setup();
+	setup_irq(IRQ_RTC_TIC, &s5pc11x_tick_timer_irq);
+	setup_irq(IRQ_SYSTIMER, &s5pc11x_systimer_irq);
+}
+
+
+struct sys_timer s3c24xx_timer = {
+	.init		= s5pc11x_timer_init,
+};
+
diff --git a/arch/arm/plat-s5p/include/plat/regs-sys-timer.h b/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
new file mode 100644
index 0000000..75e6267
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
@@ -0,0 +1,63 @@
+/* arch/arm/plat-s5pc1xx/include/plat/regs-sys-timer.h
+ *
+ * Copyright (c) 2008 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S5PC1XX System Timer configuration
+*/
+
+#ifndef __ASM_ARCH_REGS_SYS_TIMER_H
+#define __ASM_ARCH_REGS_SYS_TIMER_H
+
+#define S3C_SYSTIMERREG(x)		(S5P_VA_SYSTIMER + (x))
+
+#define S3C_SYSTIMER_TCFG		S3C_SYSTIMERREG(0x00)
+#define S3C_SYSTIMER_TCON		S3C_SYSTIMERREG(0x04)
+#define S3C_SYSTIMER_TCNTB		S3C_SYSTIMERREG(0x08)
+#define S3C_SYSTIMER_TCNTO		S3C_SYSTIMERREG(0x0c)
+
+#define S3C_SYSTIMER_TFCNTB		S3C_SYSTIMERREG(0x10)
+#define S3C_SYSTIMER_ICNTB		S3C_SYSTIMERREG(0x18)
+#define S3C_SYSTIMER_ICNTO		S3C_SYSTIMERREG(0x1c)
+#define S3C_SYSTIMER_INT_CSTAT	S3C_SYSTIMERREG(0x20)
+
+/* Value for TCFG */
+#define S3C_SYSTIMER_TCLK_MASK		(3<<12)
+#define S3C_SYSTIMER_TCLK_XXTI		(0<<12)
+#define S3C_SYSTIMER_TCLK_RTC		(1<<12)
+#define S3C_SYSTIMER_TCLK_USB		(2<<12)
+#define S3C_SYSTIMER_TCLK_PCLK		(3<<12)
+
+#define S3C_SYSTIMER_DIV_MASK		(7<<8)
+#define S3C_SYSTIMER_DIV_1		(0<<8)
+#define S3C_SYSTIMER_DIV_2		(1<<8)
+#define S3C_SYSTIMER_DIV_4		(2<<8)
+#define S3C_SYSTIMER_DIV_8		(3<<8)
+#define S3C_SYSTIMER_DIV_16		(4<<8)
+
+#define S3C_SYSTIMER_TARGET_HZ		200
+#define S3C_SYSTIMER_PRESCALER		5
+#define S3C_SYSTIMER_PRESCALER_MASK	(0x3f<<0)
+
+/* value for TCON */
+#define S3C_SYSTIMER_INT_AUTO		(1<<5)
+#define S3C_SYSTIMER_INT_IMM		(1<<4)
+#define S3C_SYSTIMER_INT_START		(1<<3)
+#define S3C_SYSTIMER_AUTO_RELOAD	(1<<2)
+#define S3C_SYSTIMER_IMM_UPDATE		(1<<1)
+#define S3C_SYSTIMER_START		(1<<0)
+
+/* Value for INT_CSTAT */
+#define S3C_SYSTIMER_INT_IWIE		(1<<9)
+#define S3C_SYSTIMER_INT_TWIE		(1<<10)
+#define S3C_SYSTIMER_INT_ICNTEIE	(1<<6)
+#define S3C_SYSTIMER_INT_TCON		(1<<5)
+#define S3C_SYSTIMER_INT_ICNTB		(1<<4)
+#define S3C_SYSTIMER_INT_TCNTB		(1<<2)
+#define S3C_SYSTIMER_INT_STATS		(1<<1)
+#define S3C_SYSTIMER_INT_EN		(1<<0)
+
+#endif /*  __ASM_ARCH_REGS_TIMER_H */
diff --git a/arch/arm/plat-samsung/include/plat/map-base.h b/arch/arm/plat-samsung/include/plat/map-base.h
index 250be31..ff766d9 100644
--- a/arch/arm/plat-samsung/include/plat/map-base.h
+++ b/arch/arm/plat-samsung/include/plat/map-base.h
@@ -36,6 +36,8 @@
 #define S3C_VA_TIMER	S3C_ADDR(0x00300000)	/* timer block */
 #define S3C_VA_WATCHDOG	S3C_ADDR(0x00400000)	/* watchdog */
 #define S3C_VA_UART	S3C_ADDR(0x01000000)	/* UART */
+/*For RTC*/
+#define S3C_VA_RTC	S3C_ADDR(0x00c00000)
 
 /* This is used for the CPU specific mappings that may be needed, so that
  * they do not need to directly used S3C_ADDR() and thus make it easier to
-- 
1.6.0.4

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

* [PATCH]HRT support in Samsung S5P Platform
  2010-07-19  6:54 MADHAV SINGHCHAUHAN
@ 2010-07-21  0:36 ` Ben Dooks
  2010-07-21 12:06 ` Kukjin Kim
  2010-07-22  7:55 ` Russell King - ARM Linux
  2 siblings, 0 replies; 7+ messages in thread
From: Ben Dooks @ 2010-07-21  0:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/19/10 07:54, MADHAV SINGHCHAUHAN wrote:
> From: Madhav Singh<singh.madhav@samsung.com>
> Date: Mon, 19 Jul 2010 10:51:01 +0530
> Subject: [PATCH] HRT support in Samsung Tree
> This patch implements HRT support for Samsung plat-s5p.
> RTC has been used as CLOCKEVENT and SYSTIMER as CLOCKSOURCE.
>
> Signed-off-by: Madhav Chauhan<singh.madhav@samsung.com>
> Signed-off-by: Kyungmin Park<kyungmin.park@samsung.com>
> ---
>   arch/arm/mach-s5pv210/Kconfig                   |    9 +
>   arch/arm/mach-s5pv210/include/mach/map.h        |    4 +
>   arch/arm/plat-s5p/clock.c                       |   15 +
>   arch/arm/plat-s5p/cpu.c                         |    8 +
>   arch/arm/plat-s5p/hr-time-rtc.c                 |  470 +++++++++++++++++++++++
>   arch/arm/plat-s5p/include/plat/regs-sys-timer.h |   63 +++
>   arch/arm/plat-samsung/include/plat/map-base.h   |    2 +
>   7 files changed, 571 insertions(+), 0 deletions(-)
>   create mode 100644 arch/arm/plat-s5p/hr-time-rtc.c
>   create mode 100644 arch/arm/plat-s5p/include/plat/regs-sys-timer.h
>
> diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
> index 631019a..9d8698e 100644
> --- a/arch/arm/mach-s5pv210/Kconfig
> +++ b/arch/arm/mach-s5pv210/Kconfig
> @@ -101,4 +101,13 @@ config MACH_SMDKC110
>   	  Machine support for Samsung SMDKC110
>   	  S5PC110(MCP) is one of package option of S5PV210
>
> +config MACH_S5PV210_HRT
> +        bool "HRtimer and Dynamic Tick support"
> +        select GENERIC_TIME
> +        select GENERIC_CLOCKEVENTS
> +        select HIGH_RES_TIMERS
> +        default n
> +        help
> +          Support for HRtimer and Dynamic Tick system using RTC and SYSTEM timer
> +
>   endif
> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
> index 17687f0..fd8e504 100644
> --- a/arch/arm/mach-s5pv210/include/mach/map.h
> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
> @@ -42,6 +42,10 @@
>   #define S5P_PA_TIMER		S5PV210_PA_TIMER
>
>   #define S5PV210_PA_SYSTIMER	(0xE2600000)
> +/*For RTC*/
> +#define S5PC11X_PA_RTC		(0xE2800000)
> +#define S3C_PA_RTC		S5PC11X_PA_RTC
> +
>
>   #define S5PV210_PA_WATCHDOG	(0xE2700000)
>
> diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
> index b5e2552..1e2a6f4 100644
> --- a/arch/arm/plat-s5p/clock.c
> +++ b/arch/arm/plat-s5p/clock.c
> @@ -89,6 +89,19 @@ struct clk clk_arm = {
>   	.ctrlbit	= 0,
>   };
>
> +/*For HRT*/
> +struct clk clk_ext_xtal_rtc = {
> +	.name		= "XrtcXTI",
> +	.id		= -1,
> +	.rate           = 32768,
> +};
> +
> +struct clk clk_ext_xtal_usb = {
> +	.name		= "XusbXTI",
> +	.id		= -1,
> +	.rate		= 24000000,
> +};
> +
>   /* Possible clock sources for APLL Mux */
>   static struct clk *clk_src_apll_list[] = {
>   	[0] =&clk_fin_apll,
> @@ -149,6 +162,8 @@ static struct clk *s5p_clks[] __initdata = {
>   	&clk_arm,
>   	&clk_vpll,
>   	&clk_xusbxti,
> +	&clk_ext_xtal_usb,
> +	&clk_ext_xtal_rtc,

I think you've invented clk_ext_xtal_usb  which is already being used
to feed the usb phyd.

Do we need the XrtcXTI as iirc, this has to be 32.768KHz?

>   };
>
>   void __init s5p_register_clocks(unsigned long xtal_freq)
> diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c
> index 75cb8c3..83ae862 100644
> --- a/arch/arm/plat-s5p/cpu.c
> +++ b/arch/arm/plat-s5p/cpu.c
> @@ -104,6 +104,14 @@ static struct map_desc s5p_iodesc[] __initdata = {
>   		.length		= SZ_4K,
>   		.type		= MT_DEVICE,
>   	},
> +#if defined(CONFIG_MACH_S5PV210_HRT)
> +	{
> +		.virtual        = (unsigned long)S3C_VA_RTC,
> +		.pfn            = __phys_to_pfn(S3C_PA_RTC),
> +		.length         = SZ_4K,
> +		.type           = MT_DEVICE,
> +	},
> +#endif
>   };
>
>   /* read cpu identification code */
> diff --git a/arch/arm/plat-s5p/hr-time-rtc.c b/arch/arm/plat-s5p/hr-time-rtc.c
> new file mode 100644
> index 0000000..8decf4e
> --- /dev/null
> +++ b/arch/arm/plat-s5p/hr-time-rtc.c
> @@ -0,0 +1,470 @@
> +/*
> + * linux/arch/arm/plat-s5p/hr-time-rtc.c
> + *
> + * S5PC11X Timers
> + *
> + * Copyright (c) 2006 Samsung Electronics
> + * Copyright (c) 2010 Samsung Electronics Madhav Chauhan<singh.madhav@samsung.com>
> + *
> + *
> + * S5PC11X (and compatible) HRT support using RTC and SYSTEM TIMER
> + *
> + * 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<asm/system.h>
> +#include<mach/hardware.h>
> +#include<asm/irq.h>
> +#include<asm/mach/irq.h>
> +#include<asm/mach/time.h>
> +#include<asm/mach-types.h>
> +#include<mach/map.h>
> +#include<plat/regs-timer.h>
> +#include<plat/regs-rtc.h>
> +#include<plat/regs-sys-timer.h>
> +#include<mach/regs-irq.h>
> +#include<mach/tick.h>
> +#include<plat/clock.h>
> +#include<plat/cpu.h>
> +
> +/*For SCHED_CLOCK*/
> +static unsigned long long time_stamp;
> +static unsigned long long s5pc11x_sched_timer_overflows;
> +static unsigned long long old_overflows;
> +static cycle_t last_ticks;
> +
> +/* Sched timer interrupt is not processed right after
> + * timer counter expired
> + */
> +static unsigned int pending_irq;
> +
> +/* sched_timer_running
> + * 0 : sched timer stopped or not initialized
> + * 1 : sched timer started
> + */
> +static unsigned int sched_timer_running;
> +
> +void __iomem *rtc_base =	S3C_VA_RTC;
> +static struct clk *clk_event;
> +static struct clk *clk_sched;
> +static int tick_timer_mode;	/* 0: oneshot, 1: autoreload */
> +
> +#define RTC_CLOCK		(32768)
> +#define RTC_DEFAULT_TICK	((RTC_CLOCK / HZ) - 1)
> +
> +/*
> + * Helper functions
> + * s5pc11x_systimer_read() : Read from System timer register
> + * s5pc11x_systimer_write(): Write to System timer register
> + *
> + */
> +static unsigned int s5pc11x_systimer_read(unsigned int *reg_offset)
> +{
> +	return __raw_readl(reg_offset);
> +}
> +
> +static unsigned int s5pc11x_systimer_write(unsigned int *reg_offset,
> +					unsigned int value)
> +{
> +	unsigned int temp_regs;
> +
> +	__raw_writel(value, reg_offset);
> +
> +	if (reg_offset == S3C_SYSTIMER_TCON) {
> +		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT)&
> +				S3C_SYSTIMER_INT_TCON));
> +		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
> +		temp_regs |= S3C_SYSTIMER_INT_TCON;
> +		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
> +
> +	} else if (reg_offset == S3C_SYSTIMER_ICNTB) {
> +		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT)&
> +				S3C_SYSTIMER_INT_ICNTB));
> +		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
> +		temp_regs |= S3C_SYSTIMER_INT_ICNTB;
> +		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
> +
> +	} else if (reg_offset == S3C_SYSTIMER_TCNTB) {
> +		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT)&
> +				S3C_SYSTIMER_INT_TCNTB));
> +		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
> +		temp_regs |= S3C_SYSTIMER_INT_TCNTB;
> +		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
> +	}
> +
> +	return 0;
> +}
> +
> +static void s5pc11x_rtc_set_tick(int enabled)
> +{
> +	unsigned int tmp;
> +
> +	tmp = __raw_readl(rtc_base + S3C2410_RTCCON)&  ~S3C_RTCCON_TICEN;
> +	if (enabled)
> +		tmp |= S3C_RTCCON_TICEN;
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +}
> +
> +static void s5pc11x_tick_timer_setup(void);
> +
> +static void s5pc11x_tick_timer_start(unsigned long load_val,
> +					int autoreset)
> +{
> +	unsigned int tmp;
> +
> +	tmp = __raw_readl(rtc_base + S3C2410_RTCCON)&
> +		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +
> +	__raw_writel(load_val, rtc_base + S3C2410_TICNT);
> +
> +	tmp |= S3C_RTCCON_TICEN;
> +
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +}
> +
> +static  void s5pc11x_tick_timer_stop(void)
> +{
> +	unsigned int tmp;
> +
> +	tmp = __raw_readl(rtc_base + S3C2410_RTCCON)&
> +		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
> +
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +
> +}

Will have to think about the cross usage against the
rtc driver.

> +static void s5pc11x_sched_timer_start(unsigned long load_val,
> +					int autoreset)
> +{
> +	unsigned long tcon;
> +	unsigned long tcnt;
> +	unsigned long tcfg;
> +
> +	/* clock configuration setting and enable */
> +	struct clk *clk;
> +
> +	tcnt = TICK_MAX;  /* default value for tcnt */
> +
> +	/* initialize system timer clock */
> +	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
> +
> +	tcfg&= ~S3C_SYSTIMER_TCLK_MASK;
> +	tcfg |= S3C_SYSTIMER_TCLK_USB;
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
> +
> +	/* TCFG must not be changed at run-time.
> +	 * If you want to change TCFG, stop timer(TCON[0] = 0)
> +	 */
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, 0);
> +
> +	/* read the current timer configuration bits */
> +	tcon = s5pc11x_systimer_read(S3C_SYSTIMER_TCON);
> +	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
> +
> +	clk = clk_get(NULL, "systimer");
> +	if (IS_ERR(clk))
> +		panic("failed to get clock[%s] for system timer", "systimer");
> +
> +	clk_enable(clk);
> +
> +	clk_put(clk);
> +
> +	tcfg&= ~S3C_SYSTIMER_TCLK_MASK;
> +	tcfg |= S3C_SYSTIMER_TCLK_USB;
> +	tcfg&= ~S3C_SYSTIMER_PRESCALER_MASK;
> +
> +	/* check to see if timer is within 16bit range... */
> +	if (tcnt>  TICK_MAX) {
> +		panic("setup_timer: cannot configure timer!");
> +		return;
> +	}
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCNTB, tcnt);
> +
> +	/* set timer con */
> +	tcon =  S3C_SYSTIMER_INT_AUTO | S3C_SYSTIMER_START |
> +			S3C_SYSTIMER_AUTO_RELOAD;
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
> +
> +	tcon |= S3C_SYSTIMER_INT_START;
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
> +
> +	/* Interrupt Start and Enable */
> +	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT,
> +				(S3C_SYSTIMER_INT_ICNTEIE |
> +					S3C_SYSTIMER_INT_EN));
> +	sched_timer_running = 1;
> +}
> +
> +/*
> + * RTC tick : count down to zero, interrupt, reload
> + */
> +static int s5pc11x_tick_set_next_event(unsigned long cycles,
> +				   struct clock_event_device *evt)
> +{
> +	if  (cycles == 0)	/* Should be larger than 0 */
> +		cycles = 1;
> +	s5pc11x_tick_timer_start(cycles, 0);
> +	return 0;
> +}
> +
> +static void s5pc11x_tick_set_mode(enum clock_event_mode mode,
> +			      struct clock_event_device *evt)
> +{
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		tick_timer_mode = 1;
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +		s5pc11x_tick_timer_stop();
> +		tick_timer_mode = 0;
> +		break;
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +		/* Sched timer stopped */
> +		sched_timer_running = 0;
> +		/* Reset sched_clock variables after sleep/wakeup */
> +		last_ticks = 0;
> +		s5pc11x_sched_timer_overflows = 0;
> +		old_overflows = 0;
> +		pending_irq = 0;
> +		break;
> +	case CLOCK_EVT_MODE_RESUME:
> +		s5pc11x_tick_timer_setup();
> +		s5pc11x_sched_timer_start(~0, 1);
> +		break;
> +	}
> +}
> +
> +static struct clock_event_device clockevent_tick_timer = {
> +	.name		= "S5PC110 event timer",
> +	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> +	.shift		= 32,
> +	.set_next_event	= s5pc11x_tick_set_next_event,
> +	.set_mode	= s5pc11x_tick_set_mode,
> +};
> +
> +irqreturn_t s5pc11x_tick_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *evt =&clockevent_tick_timer;
> +
> +	__raw_writel(S3C_INTP_TIC, rtc_base + S3C_INTP);
> +	/* In case of oneshot mode */
> +	if (tick_timer_mode == 0)
> +		s5pc11x_tick_timer_stop();
> +
> +	evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static struct irqaction s5pc11x_tick_timer_irq = {
> +	.name		= "rtc-tick",
> +	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
> +	.handler	= s5pc11x_tick_timer_interrupt,
> +};
> +
> +static void  s5pc11x_init_dynamic_tick_timer(unsigned long rate)
> +{
> +	tick_timer_mode = 1;
> +
> +	s5pc11x_tick_timer_stop();
> +
> +	s5pc11x_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 = cpumask_of(0);
> +	clockevents_register_device(&clockevent_tick_timer);
> +
> +	printk(KERN_INFO "mult[%u]\n", clockevent_tick_timer.mult);
> +	printk(KERN_INFO "max_delta_ns[%u]\n", clockevent_tick_timer.max_delta_ns);
> +	printk(KERN_INFO "min_delta_ns[%u]\n", clockevent_tick_timer.min_delta_ns);
> +	printk(KERN_INFO "rate[%lu]\n", rate);
> +	printk(KERN_INFO "HZ[%d]\n", HZ);
> +}
> +
> +
> +/*
> + * ---------------------------------------------------------------------------
> + * SYSTEM TIMER ... free running 32-bit clock source and scheduler clock
> + * ---------------------------------------------------------------------------
> + */
> +irqreturn_t s5pc11x_sched_timer_interrupt(int irq, void *dev_id)
> +{
> +	volatile unsigned int temp_cstat;
> +
> +	temp_cstat = s5pc11x_systimer_read(S3C_SYSTIMER_INT_CSTAT);
> +	temp_cstat |= S3C_SYSTIMER_INT_STATS;
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT, temp_cstat);
> +
> +	if (unlikely(pending_irq))
> +		pending_irq = 0;
> +	else
> +		s5pc11x_sched_timer_overflows++;
> +
> +	return IRQ_HANDLED;
> +}
> +
> +struct irqaction s5pc11x_systimer_irq = {
> +	.name		= "System timer",
> +	.flags		= IRQF_DISABLED ,
> +	.handler	= s5pc11x_sched_timer_interrupt,
> +};
> +
> +
> +static cycle_t s5pc11x_sched_timer_read(void)
> +{
> +	return (cycle_t)~__raw_readl(S3C_SYSTIMER_TCNTO);
> +}
> +
> +struct clocksource clocksource_s5pc11x = {
> +	.name		= "clock_source_systimer",
> +	.rating		= 300,
> +	.read		= s5pc11x_sched_timer_read,
> +	.mask		= CLOCKSOURCE_MASK(32),
> +	.shift		= 20,
> +	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> +};
> +
> +static void s5pc11x_init_clocksource(unsigned long rate)
> +{
> +	static char err[] __initdata = KERN_ERR
> +			"%s: can't register clocksource!\n";

yuck

> +	clocksource_s5pc11x.mult
> +		= clocksource_khz2mult(rate/1000, clocksource_s5pc11x.shift);
> +
> +
> +	s5pc11x_sched_timer_start(~0, 1);
> +
> +	if (clocksource_register(&clocksource_s5pc11x))
> +		printk(err, clocksource_s5pc11x.name);
> +}
> +
> +/*
> + * Returns current time from boot in nsecs. It's OK for this to wrap
> + * around for now, as it's just a relative time stamp.
> + */
> +unsigned long long sched_clock(void)
> +{
> +	unsigned long irq_flags;
> +	cycle_t ticks, elapsed_ticks = 0;
> +	unsigned long long increment = 0;
> +	unsigned int overflow_cnt = 0;
> +
> +	local_irq_save(irq_flags);
> +
> +	if (likely(sched_timer_running)) {
> +		overflow_cnt = (s5pc11x_sched_timer_overflows - old_overflows);
> +
> +		ticks = s5pc11x_sched_timer_read();
> +
> +		if (overflow_cnt) {
> +			increment = (overflow_cnt - 1) *
> +					(clocksource_cyc2ns(clocksource_s5pc11x.mask,
> +					clocksource_s5pc11x.mult, clocksource_s5pc11x.shift));
> +			elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks;
> +		} else {
> +			if (unlikely(last_ticks>  ticks)) {
> +				pending_irq = 1;
> +				elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks;
> +				s5pc11x_sched_timer_overflows++;
> +			} else {
> +				elapsed_ticks = (ticks - last_ticks);
> +			}
> +		}
> +
> +		time_stamp += (clocksource_cyc2ns(elapsed_ticks, clocksource_s5pc11x.mult, clocksource_s5pc11x.shift) + increment);
> +
> +		old_overflows = s5pc11x_sched_timer_overflows;
> +		last_ticks = ticks;
> +	}
> +	local_irq_restore(irq_flags);
> +
> +	return time_stamp;
> +}
> +
> +/*
> + *  Event/Sched Timer initialization
> + */
> +static void s5pc11x_timer_setup(void)
> +{
> +	unsigned long rate;
> +	/* Setup event timer using XrtcXTI */
> +	if (clk_event == NULL)
> +		clk_event = clk_get(NULL, "XrtcXTI");
> +	if (IS_ERR(clk_event))
> +		panic("failed to get clock for event timer");
> +	rate = clk_get_rate(clk_event);
> +	s5pc11x_init_dynamic_tick_timer(rate);
> +
> +	/* Setup sched-timer using XusbXTI */
> +	if (clk_sched == NULL)
> +		clk_sched = clk_get(NULL, "XusbXTI");
> +	if (IS_ERR(clk_sched))
> +		panic("failed to get clock for sched-timer");
> +	rate = clk_get_rate(clk_sched);
> +	s5pc11x_init_clocksource(rate);
> +}
> +
> +static void s5pc11x_tick_timer_setup(void)
> +{
> +	unsigned long rate;
> +
> +	rate = clk_get_rate(clk_event);
> +	s5pc11x_tick_timer_start((rate / HZ) - 1, 1);
> +}
> +
> +static void __init s5pc11x_timer_init(void)
> +{
> +	/* Initialize variables before starting each timers */
> +	last_ticks = 0;
> +	s5pc11x_sched_timer_overflows = 0;
> +	old_overflows = 0;
> +	time_stamp = 0;
> +	sched_timer_running = 0;
> +	pending_irq = 0;
> +	s5pc11x_timer_setup();
> +	setup_irq(IRQ_RTC_TIC,&s5pc11x_tick_timer_irq);
> +	setup_irq(IRQ_SYSTIMER,&s5pc11x_systimer_irq);
> +}
> +
> +
> +struct sys_timer s3c24xx_timer = {
> +	.init		= s5pc11x_timer_init,
> +};
> +


-- 
Ben Dooks, Design & Software Engineer, Simtec Electronics

http://www.simtec.co.uk/

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

* [PATCH]HRT support in Samsung S5P Platform
@ 2010-07-21 11:54 MADHAV SINGHCHAUHAN
  0 siblings, 0 replies; 7+ messages in thread
From: MADHAV SINGHCHAUHAN @ 2010-07-21 11:54 UTC (permalink / raw)
  To: linux-arm-kernel

This new patch remove corrects redundant use of USB clock and removed few irrelevant comments.

From: Madhav Singh <singh.madhav@samsung.com>
Date: Wed, 21 Jul 2010 16:55:27 +0530
Subject: [PATCH] HRT support in in Samsung Tree
This patch implements HRT support for Samsung plat-s5p.
RTC has been used as CLOCKEVENT and SYSTIMER as CLOCKSOURCE.

Signed-off-by: Madhav Chauhan <singh.madhav@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv210/Kconfig                   |    9 +
 arch/arm/mach-s5pv210/include/mach/map.h        |    4 +
 arch/arm/plat-s5p/Makefile                      |    4 +-
 arch/arm/plat-s5p/clock.c                       |   11 +
 arch/arm/plat-s5p/hr-time-rtc.c                 |  465 +++++++++++++++++++++++
 arch/arm/plat-s5p/include/plat/regs-sys-timer.h |   63 +++
 arch/arm/plat-samsung/Makefile                  |    2 +
 7 files changed, 557 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/plat-s5p/hr-time-rtc.c
 create mode 100644 arch/arm/plat-s5p/include/plat/regs-sys-timer.h

diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 631019a..d4f7e55 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -101,4 +101,13 @@ config MACH_SMDKC110
 	  Machine support for Samsung SMDKC110
 	  S5PC110(MCP) is one of package option of S5PV210
 
+config SAMSUNG_HRT_RTC_SYSTIMER
+        bool "HRtimer and Dynamic Tick support"
+        select GENERIC_TIME
+        select GENERIC_CLOCKEVENTS
+        select HIGH_RES_TIMERS
+        default n
+        help
+          Support for HRtimer and Dynamic Tick system using RTC and SYSTEM timer
+
 endif
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index 17687f0..c7de909 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -43,6 +43,10 @@
 
 #define S5PV210_PA_SYSTIMER	(0xE2600000)
 
+#define S5PC11X_PA_RTC		(0xE2800000)
+#define S3C_PA_RTC		S5PC11X_PA_RTC
+
+
 #define S5PV210_PA_WATCHDOG	(0xE2700000)
 
 #define S5PV210_PA_UART		(0xE2900000)
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 18c9e34..9c61cf5 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -18,4 +18,6 @@ obj-y				+= cpu.o
 obj-y				+= clock.o
 obj-y				+= irq.o irq-gpioint.o
 obj-$(CONFIG_S5P_EXT_INT)	+= irq-eint.o
-
+ifdef CONFIG_SAMSUNG_HRT_RTC_SYSTIMER
+obj-y				+= hr-time-rtc.o
+endif
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index b5e2552..e2febe6 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -89,6 +89,14 @@ struct clk clk_arm = {
 	.ctrlbit	= 0,
 };
 
+/*For HRT*/
+#ifdef CONFIG_SAMSUNG_HRT_RTC_SYSTIMER
+struct clk clk_ext_xtal_rtc = {
+	.name		= "XrtcXTI",
+	.id		= -1,
+	.rate           = 32768,
+};
+#endif
 /* Possible clock sources for APLL Mux */
 static struct clk *clk_src_apll_list[] = {
 	[0] = &clk_fin_apll,
@@ -149,6 +157,9 @@ static struct clk *s5p_clks[] __initdata = {
 	&clk_arm,
 	&clk_vpll,
 	&clk_xusbxti,
+	#ifdef CONFIG_SAMSUNG_HRT_RTC_SYSTIMER
+	&clk_ext_xtal_rtc,
+	#endif
 };
 
 void __init s5p_register_clocks(unsigned long xtal_freq)
diff --git a/arch/arm/plat-s5p/hr-time-rtc.c b/arch/arm/plat-s5p/hr-time-rtc.c
new file mode 100644
index 0000000..4d9c4d9
--- /dev/null
+++ b/arch/arm/plat-s5p/hr-time-rtc.c
@@ -0,0 +1,465 @@
+/*
+ * linux/arch/arm/plat-s5p/hr-time-rtc.c
+ *
+ * S5PC11X Timers
+ *
+ * Copyright (c) 2006 Samsung Electronics
+ * Copyright (c) 2010 Samsung Electronics Madhav Chauhan <singh.madhav@samsung.com>
+ *
+ *
+ * S5PC11X (and compatible) HRT support using RTC and SYSTEM TIMER
+ *
+ * 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 <asm/system.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <plat/regs-rtc.h>
+#include <plat/regs-sys-timer.h>
+#include <mach/regs-irq.h>
+#include <mach/tick.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+/*For SCHED_CLOCK*/
+static unsigned long long time_stamp;
+static unsigned long long s5pc11x_sched_timer_overflows;
+static unsigned long long old_overflows;
+static cycle_t last_ticks;
+
+/* Sched timer interrupt is not processed right after
+ * timer counter expired
+ */
+static unsigned int pending_irq;
+
+/* sched_timer_running
+ * 0 : sched timer stopped or not initialized
+ * 1 : sched timer started
+ */
+static unsigned int sched_timer_running;
+
+void __iomem *rtc_base;
+static struct clk *clk_event;
+static int tick_timer_mode;	/* 0: oneshot, 1: autoreload */
+
+#define RTC_CLOCK		(32768)
+#define RTC_DEFAULT_TICK	((RTC_CLOCK / HZ) - 1)
+
+/*
+ * Helper functions
+ * s5pc11x_systimer_read() : Read from System timer register
+ * s5pc11x_systimer_write(): Write to System timer register
+ *
+ */
+static unsigned int s5pc11x_systimer_read(unsigned int *reg_offset)
+{
+	return __raw_readl(reg_offset);
+}
+
+static unsigned int s5pc11x_systimer_write(unsigned int *reg_offset,
+					unsigned int value)
+{
+	unsigned int temp_regs;
+
+	__raw_writel(value, reg_offset);
+
+	if (reg_offset == S3C_SYSTIMER_TCON) {
+		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
+				S3C_SYSTIMER_INT_TCON));
+		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
+		temp_regs |= S3C_SYSTIMER_INT_TCON;
+		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
+
+	} else if (reg_offset == S3C_SYSTIMER_ICNTB) {
+		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
+				S3C_SYSTIMER_INT_ICNTB));
+		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
+		temp_regs |= S3C_SYSTIMER_INT_ICNTB;
+		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
+
+	} else if (reg_offset == S3C_SYSTIMER_TCNTB) {
+		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
+				S3C_SYSTIMER_INT_TCNTB));
+		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
+		temp_regs |= S3C_SYSTIMER_INT_TCNTB;
+		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
+	}
+
+	return 0;
+}
+
+static void s5pc11x_rtc_set_tick(int enabled)
+{
+	unsigned int tmp;
+
+	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) & ~S3C_RTCCON_TICEN;
+	if (enabled)
+		tmp |= S3C_RTCCON_TICEN;
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+}
+
+static void s5pc11x_tick_timer_setup(void);
+
+static void s5pc11x_tick_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned int tmp;
+
+	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
+		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+
+	__raw_writel(load_val, rtc_base + S3C2410_TICNT);
+
+	tmp |= S3C_RTCCON_TICEN;
+
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+}
+
+static  void s5pc11x_tick_timer_stop(void)
+{
+	unsigned int tmp;
+
+	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
+		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
+
+	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
+
+}
+
+static void s5pc11x_sched_timer_start(unsigned long load_val,
+					int autoreset)
+{
+	unsigned long tcon;
+	unsigned long tcnt;
+	unsigned long tcfg;
+
+	/* clock configuration setting and enable */
+	struct clk *clk;
+
+	tcnt = TICK_MAX;  /* default value for tcnt */
+
+	/* initialize system timer clock */
+	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
+
+	tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
+	tcfg |= S3C_SYSTIMER_TCLK_USB;
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
+
+	/* TCFG must not be changed at run-time.
+	 * If you want to change TCFG, stop timer(TCON[0] = 0)
+	 */
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, 0);
+
+	/* read the current timer configuration bits */
+	tcon = s5pc11x_systimer_read(S3C_SYSTIMER_TCON);
+	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
+
+	clk = clk_get(NULL, "systimer");
+	if (IS_ERR(clk))
+		panic("failed to get clock[%s] for system timer", "systimer");
+
+	clk_enable(clk);
+
+	clk_put(clk);
+
+	tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
+	tcfg |= S3C_SYSTIMER_TCLK_USB;
+	tcfg &= ~S3C_SYSTIMER_PRESCALER_MASK;
+
+	/* check to see if timer is within 16bit range... */
+	if (tcnt > TICK_MAX) {
+		panic("setup_timer: cannot configure timer!");
+		return;
+	}
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCNTB, tcnt);
+
+	/* set timer con */
+	tcon =  S3C_SYSTIMER_INT_AUTO | S3C_SYSTIMER_START |
+			S3C_SYSTIMER_AUTO_RELOAD;
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
+
+	tcon |= S3C_SYSTIMER_INT_START;
+	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
+
+	/* Interrupt Start and Enable */
+	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT,
+				(S3C_SYSTIMER_INT_ICNTEIE |
+					S3C_SYSTIMER_INT_EN));
+	sched_timer_running = 1;
+}
+
+/*
+ * RTC tick : count down to zero, interrupt, reload
+ */
+static int s5pc11x_tick_set_next_event(unsigned long cycles,
+				   struct clock_event_device *evt)
+{
+	if  (cycles == 0)	/* Should be larger than 0 */
+		cycles = 1;
+	s5pc11x_tick_timer_start(cycles, 0);
+	return 0;
+}
+
+static void s5pc11x_tick_set_mode(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		tick_timer_mode = 1;
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		s5pc11x_tick_timer_stop();
+		tick_timer_mode = 0;
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		/* Sched timer stopped */
+		sched_timer_running = 0;
+		/* Reset sched_clock variables after sleep/wakeup */
+		last_ticks = 0;
+		s5pc11x_sched_timer_overflows = 0;
+		old_overflows = 0;
+		pending_irq = 0;
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		s5pc11x_tick_timer_setup();
+		s5pc11x_sched_timer_start(~0, 1);
+		break;
+	}
+}
+
+static struct clock_event_device clockevent_tick_timer = {
+	.name		= "S5PC110 event timer",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_next_event	= s5pc11x_tick_set_next_event,
+	.set_mode	= s5pc11x_tick_set_mode,
+};
+
+irqreturn_t s5pc11x_tick_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &clockevent_tick_timer;
+
+	__raw_writel(S3C_INTP_TIC, rtc_base + S3C_INTP);
+	/* In case of oneshot mode */
+	if (tick_timer_mode == 0)
+		s5pc11x_tick_timer_stop();
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction s5pc11x_tick_timer_irq = {
+	.name		= "rtc-tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= s5pc11x_tick_timer_interrupt,
+};
+
+static void  s5pc11x_init_dynamic_tick_timer(unsigned long rate)
+{
+	tick_timer_mode = 1;
+
+	rtc_base = ioremap(S3C_PA_RTC, SZ_4K);
+
+	s5pc11x_tick_timer_stop();
+
+	s5pc11x_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 = cpumask_of(0);
+	clockevents_register_device(&clockevent_tick_timer);
+
+	printk(KERN_INFO "mult[%u]\n", clockevent_tick_timer.mult);
+	printk(KERN_INFO "max_delta_ns[%u]\n", clockevent_tick_timer.max_delta_ns);
+	printk(KERN_INFO "min_delta_ns[%u]\n", clockevent_tick_timer.min_delta_ns);
+	printk(KERN_INFO "rate[%lu]\n", rate);
+	printk(KERN_INFO "HZ[%d]\n", HZ);
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * SYSTEM TIMER ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
+ */
+irqreturn_t s5pc11x_sched_timer_interrupt(int irq, void *dev_id)
+{
+	volatile unsigned int temp_cstat;
+
+	temp_cstat = s5pc11x_systimer_read(S3C_SYSTIMER_INT_CSTAT);
+	temp_cstat |= S3C_SYSTIMER_INT_STATS;
+
+	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT, temp_cstat);
+
+	if (unlikely(pending_irq))
+		pending_irq = 0;
+	else
+		s5pc11x_sched_timer_overflows++;
+
+	return IRQ_HANDLED;
+}
+
+struct irqaction s5pc11x_systimer_irq = {
+	.name		= "System timer",
+	.flags		= IRQF_DISABLED ,
+	.handler	= s5pc11x_sched_timer_interrupt,
+};
+
+
+static cycle_t s5pc11x_sched_timer_read(void)
+{
+	return (cycle_t)~__raw_readl(S3C_SYSTIMER_TCNTO);
+}
+
+struct clocksource clocksource_s5pc11x = {
+	.name		= "clock_source_systimer",
+	.rating		= 300,
+	.read		= s5pc11x_sched_timer_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void s5pc11x_init_clocksource(unsigned long rate)
+{
+	static char err[] __initdata = KERN_ERR
+			"%s: can't register clocksource!\n";
+
+	clocksource_s5pc11x.mult
+		= clocksource_khz2mult(rate/1000, clocksource_s5pc11x.shift);
+
+
+	s5pc11x_sched_timer_start(~0, 1);
+
+	if (clocksource_register(&clocksource_s5pc11x))
+		printk(err, clocksource_s5pc11x.name);
+}
+
+/*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+	unsigned long irq_flags;
+	cycle_t ticks, elapsed_ticks = 0;
+	unsigned long long increment = 0;
+	unsigned int overflow_cnt = 0;
+
+	local_irq_save(irq_flags);
+
+	if (likely(sched_timer_running)) {
+		overflow_cnt = (s5pc11x_sched_timer_overflows - old_overflows);
+
+		ticks = s5pc11x_sched_timer_read();
+
+		if (overflow_cnt) {
+			increment = (overflow_cnt - 1) *
+					(clocksource_cyc2ns(clocksource_s5pc11x.mask,
+					clocksource_s5pc11x.mult, clocksource_s5pc11x.shift));
+			elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks;
+		} else {
+			if (unlikely(last_ticks > ticks)) {
+				pending_irq = 1;
+				elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks;
+				s5pc11x_sched_timer_overflows++;
+			} else {
+				elapsed_ticks = (ticks - last_ticks);
+			}
+		}
+
+		time_stamp += (clocksource_cyc2ns(elapsed_ticks, clocksource_s5pc11x.mult, clocksource_s5pc11x.shift) + increment);
+
+		old_overflows = s5pc11x_sched_timer_overflows;
+		last_ticks = ticks;
+	}
+	local_irq_restore(irq_flags);
+
+	return time_stamp;
+}
+
+/*
+ *  Event/Sched Timer initialization
+ */
+static void s5pc11x_timer_setup(void)
+{
+	unsigned long rate;
+
+	/* Setup event timer using XrtcXTI */
+	if (clk_event == NULL)
+		clk_event = clk_get(NULL, "XrtcXTI");
+	if (IS_ERR(clk_event))
+		panic("failed to get clock for event timer");
+	rate = clk_get_rate(clk_event);
+	s5pc11x_init_dynamic_tick_timer(rate);
+	s5pc11x_init_clocksource(rate);
+}
+
+static void s5pc11x_tick_timer_setup(void)
+{
+	unsigned long rate;
+
+	rate = clk_get_rate(clk_event);
+	s5pc11x_tick_timer_start((rate / HZ) - 1, 1);
+}
+
+static void __init s5pc11x_timer_init(void)
+{
+	/* Initialize variables before starting each timers */
+	last_ticks = 0;
+	s5pc11x_sched_timer_overflows = 0;
+	old_overflows = 0;
+	time_stamp = 0;
+	sched_timer_running = 0;
+	pending_irq = 0;
+	s5pc11x_timer_setup();
+	setup_irq(IRQ_RTC_TIC, &s5pc11x_tick_timer_irq);
+	setup_irq(IRQ_SYSTIMER, &s5pc11x_systimer_irq);
+}
+
+
+struct sys_timer s3c24xx_timer = {
+	.init		= s5pc11x_timer_init,
+};
+
diff --git a/arch/arm/plat-s5p/include/plat/regs-sys-timer.h b/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
new file mode 100644
index 0000000..75e6267
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
@@ -0,0 +1,63 @@
+/* arch/arm/plat-s5pc1xx/include/plat/regs-sys-timer.h
+ *
+ * Copyright (c) 2008 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S5PC1XX System Timer configuration
+*/
+
+#ifndef __ASM_ARCH_REGS_SYS_TIMER_H
+#define __ASM_ARCH_REGS_SYS_TIMER_H
+
+#define S3C_SYSTIMERREG(x)		(S5P_VA_SYSTIMER + (x))
+
+#define S3C_SYSTIMER_TCFG		S3C_SYSTIMERREG(0x00)
+#define S3C_SYSTIMER_TCON		S3C_SYSTIMERREG(0x04)
+#define S3C_SYSTIMER_TCNTB		S3C_SYSTIMERREG(0x08)
+#define S3C_SYSTIMER_TCNTO		S3C_SYSTIMERREG(0x0c)
+
+#define S3C_SYSTIMER_TFCNTB		S3C_SYSTIMERREG(0x10)
+#define S3C_SYSTIMER_ICNTB		S3C_SYSTIMERREG(0x18)
+#define S3C_SYSTIMER_ICNTO		S3C_SYSTIMERREG(0x1c)
+#define S3C_SYSTIMER_INT_CSTAT	S3C_SYSTIMERREG(0x20)
+
+/* Value for TCFG */
+#define S3C_SYSTIMER_TCLK_MASK		(3<<12)
+#define S3C_SYSTIMER_TCLK_XXTI		(0<<12)
+#define S3C_SYSTIMER_TCLK_RTC		(1<<12)
+#define S3C_SYSTIMER_TCLK_USB		(2<<12)
+#define S3C_SYSTIMER_TCLK_PCLK		(3<<12)
+
+#define S3C_SYSTIMER_DIV_MASK		(7<<8)
+#define S3C_SYSTIMER_DIV_1		(0<<8)
+#define S3C_SYSTIMER_DIV_2		(1<<8)
+#define S3C_SYSTIMER_DIV_4		(2<<8)
+#define S3C_SYSTIMER_DIV_8		(3<<8)
+#define S3C_SYSTIMER_DIV_16		(4<<8)
+
+#define S3C_SYSTIMER_TARGET_HZ		200
+#define S3C_SYSTIMER_PRESCALER		5
+#define S3C_SYSTIMER_PRESCALER_MASK	(0x3f<<0)
+
+/* value for TCON */
+#define S3C_SYSTIMER_INT_AUTO		(1<<5)
+#define S3C_SYSTIMER_INT_IMM		(1<<4)
+#define S3C_SYSTIMER_INT_START		(1<<3)
+#define S3C_SYSTIMER_AUTO_RELOAD	(1<<2)
+#define S3C_SYSTIMER_IMM_UPDATE		(1<<1)
+#define S3C_SYSTIMER_START		(1<<0)
+
+/* Value for INT_CSTAT */
+#define S3C_SYSTIMER_INT_IWIE		(1<<9)
+#define S3C_SYSTIMER_INT_TWIE		(1<<10)
+#define S3C_SYSTIMER_INT_ICNTEIE	(1<<6)
+#define S3C_SYSTIMER_INT_TCON		(1<<5)
+#define S3C_SYSTIMER_INT_ICNTB		(1<<4)
+#define S3C_SYSTIMER_INT_TCNTB		(1<<2)
+#define S3C_SYSTIMER_INT_STATS		(1<<1)
+#define S3C_SYSTIMER_INT_EN		(1<<0)
+
+#endif /*  __ASM_ARCH_REGS_TIMER_H */
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 8269d80..a61c93c 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -12,7 +12,9 @@ obj-				:=
 # Objects we always build independent of SoC choice
 
 obj-y				+= init.o
+ifndef CONFIG_SAMSUNG_HRT_RTC_SYSTIMER
 obj-y				+= time.o
+endif
 obj-y				+= clock.o
 obj-y				+= pwm-clock.o
 obj-y				+= gpio.o
-- 
1.6.0.4


On 07/19/10 07:54, MADHAV SINGHCHAUHAN wrote: 
> From: Madhav Singh<singh.madhav@samsung.com> 
> Date: Mon, 19 Jul 2010 10:51:01 +0530 
> Subject: [PATCH] HRT support in Samsung Tree 
> This patch implements HRT support for Samsung plat-s5p. 
> RTC has been used as CLOCKEVENT and SYSTIMER as CLOCKSOURCE. 
> 
> Signed-off-by: Madhav Chauhan<singh.madhav@samsung.com> 
> Signed-off-by: Kyungmin Park<kyungmin.park@samsung.com> 
> --- 
>   arch/arm/mach-s5pv210/Kconfig                   |    9 + 
>   arch/arm/mach-s5pv210/include/mach/map.h        |    4 + 
>   arch/arm/plat-s5p/clock.c                       |   15 + 
>   arch/arm/plat-s5p/cpu.c                         |    8 + 
>   arch/arm/plat-s5p/hr-time-rtc.c                 |  470 +++++++++++++++++++++++ 
>   arch/arm/plat-s5p/include/plat/regs-sys-timer.h |   63 +++ 
>   arch/arm/plat-samsung/include/plat/map-base.h   |    2 + 
>   7 files changed, 571 insertions(+), 0 deletions(-) 
>   create mode 100644 arch/arm/plat-s5p/hr-time-rtc.c 
>   create mode 100644 arch/arm/plat-s5p/include/plat/regs-sys-timer.h 
> 
> diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig 
> index 631019a..9d8698e 100644 
> --- a/arch/arm/mach-s5pv210/Kconfig 
> +++ b/arch/arm/mach-s5pv210/Kconfig 
> @@ -101,4 +101,13 @@ config MACH_SMDKC110 
>         Machine support for Samsung SMDKC110 
>         S5PC110(MCP) is one of package option of S5PV210 
> 
> +config MACH_S5PV210_HRT 
> +        bool "HRtimer and Dynamic Tick support" 
> +        select GENERIC_TIME 
> +        select GENERIC_CLOCKEVENTS 
> +        select HIGH_RES_TIMERS 
> +        default n 
> +        help 
> +          Support for HRtimer and Dynamic Tick system using RTC and SYSTEM timer 
> + 
>   endif 
> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h 
> index 17687f0..fd8e504 100644 
> --- a/arch/arm/mach-s5pv210/include/mach/map.h 
> +++ b/arch/arm/mach-s5pv210/include/mach/map.h 
> @@ -42,6 +42,10 @@ 
>   #define S5P_PA_TIMER        S5PV210_PA_TIMER 
> 
>   #define S5PV210_PA_SYSTIMER    (0xE2600000) 
> +/*For RTC*/ 
> +#define S5PC11X_PA_RTC        (0xE2800000) 
> +#define S3C_PA_RTC        S5PC11X_PA_RTC 
> + 
> 
>   #define S5PV210_PA_WATCHDOG    (0xE2700000) 
> 
> diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c 
> index b5e2552..1e2a6f4 100644 
> --- a/arch/arm/plat-s5p/clock.c 
> +++ b/arch/arm/plat-s5p/clock.c 
> @@ -89,6 +89,19 @@ struct clk clk_arm = { 
>       .ctrlbit    = 0, 
>   }; 
> 
> +/*For HRT*/ 
> +struct clk clk_ext_xtal_rtc = { 
> +    .name        = "XrtcXTI", 
> +    .id        = -1, 
> +    .rate           = 32768, 
> +}; 
> + 
> +struct clk clk_ext_xtal_usb = { 
> +    .name        = "XusbXTI", 
> +    .id        = -1, 
> +    .rate        = 24000000, 
> +}; 
> + 
>   /* Possible clock sources for APLL Mux */ 
>   static struct clk *clk_src_apll_list[] = { 
>       [0] =&clk_fin_apll, 
> @@ -149,6 +162,8 @@ static struct clk *s5p_clks[] __initdata = { 
>       &clk_arm, 
>       &clk_vpll, 
>       &clk_xusbxti, 
> +    &clk_ext_xtal_usb, 
> +    &clk_ext_xtal_rtc, 

I think you've invented clk_ext_xtal_usb  which is already being used 
to feed the usb phyd. 

Do we need the XrtcXTI as iirc, this has to be 32.768KHz? 
Corrected in this patch..
>   }; 
> 
>   void __init s5p_register_clocks(unsigned long xtal_freq) 
> diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c 
> index 75cb8c3..83ae862 100644 
> --- a/arch/arm/plat-s5p/cpu.c 
> +++ b/arch/arm/plat-s5p/cpu.c 
> @@ -104,6 +104,14 @@ static struct map_desc s5p_iodesc[] __initdata = { 
>           .length        = SZ_4K, 
>           .type        = MT_DEVICE, 
>       }, 
> +#if defined(CONFIG_MACH_S5PV210_HRT) 
> +    { 
> +        .virtual        = (unsigned long)S3C_VA_RTC, 
> +        .pfn            = __phys_to_pfn(S3C_PA_RTC), 
> +        .length         = SZ_4K, 
> +        .type           = MT_DEVICE, 
> +    }, 
> +#endif 
>   }; 
> 
>   /* read cpu identification code */ 
> diff --git a/arch/arm/plat-s5p/hr-time-rtc.c b/arch/arm/plat-s5p/hr-time-rtc.c 
> new file mode 100644 
> index 0000000..8decf4e 
> --- /dev/null 
> +++ b/arch/arm/plat-s5p/hr-time-rtc.c 
> @@ -0,0 +1,470 @@ 
> +/* 
> + * linux/arch/arm/plat-s5p/hr-time-rtc.c 
> + * 
> + * S5PC11X Timers 
> + * 
> + * Copyright (c) 2006 Samsung Electronics 
> + * Copyright (c) 2010 Samsung Electronics Madhav Chauhan<singh.madhav@samsung.com> 
> + * 
> + * 
> + * S5PC11X (and compatible) HRT support using RTC and SYSTEM TIMER 
> + * 
> + * 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<asm/system.h> 
> +#include<mach/hardware.h> 
> +#include<asm/irq.h> 
> +#include<asm/mach/irq.h> 
> +#include<asm/mach/time.h> 
> +#include<asm/mach-types.h> 
> +#include<mach/map.h> 
> +#include<plat/regs-timer.h> 
> +#include<plat/regs-rtc.h> 
> +#include<plat/regs-sys-timer.h> 
> +#include<mach/regs-irq.h> 
> +#include<mach/tick.h> 
> +#include<plat/clock.h> 
> +#include<plat/cpu.h> 
> + 
> +/*For SCHED_CLOCK*/ 
> +static unsigned long long time_stamp; 
> +static unsigned long long s5pc11x_sched_timer_overflows; 
> +static unsigned long long old_overflows; 
> +static cycle_t last_ticks; 
> + 
> +/* Sched timer interrupt is not processed right after 
> + * timer counter expired 
> + */ 
> +static unsigned int pending_irq; 
> + 
> +/* sched_timer_running 
> + * 0 : sched timer stopped or not initialized 
> + * 1 : sched timer started 
> + */ 
> +static unsigned int sched_timer_running; 
> + 
> +void __iomem *rtc_base =    S3C_VA_RTC; 
> +static struct clk *clk_event; 
> +static struct clk *clk_sched; 
> +static int tick_timer_mode;    /* 0: oneshot, 1: autoreload */ 
> + 
> +#define RTC_CLOCK        (32768) 
> +#define RTC_DEFAULT_TICK    ((RTC_CLOCK / HZ) - 1) 
> + 
> +/* 
> + * Helper functions 
> + * s5pc11x_systimer_read() : Read from System timer register 
> + * s5pc11x_systimer_write(): Write to System timer register 
> + * 
> + */ 
> +static unsigned int s5pc11x_systimer_read(unsigned int *reg_offset) 
> +{ 
> +    return __raw_readl(reg_offset); 
> +} 
> + 
> +static unsigned int s5pc11x_systimer_write(unsigned int *reg_offset, 
> +                    unsigned int value) 
> +{ 
> +    unsigned int temp_regs; 
> + 
> +    __raw_writel(value, reg_offset); 
> + 
> +    if (reg_offset == S3C_SYSTIMER_TCON) { 
> +        while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT)& 
> +                S3C_SYSTIMER_INT_TCON)); 
> +        temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT); 
> +        temp_regs |= S3C_SYSTIMER_INT_TCON; 
> +        __raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT); 
> + 
> +    } else if (reg_offset == S3C_SYSTIMER_ICNTB) { 
> +        while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT)& 
> +                S3C_SYSTIMER_INT_ICNTB)); 
> +        temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT); 
> +        temp_regs |= S3C_SYSTIMER_INT_ICNTB; 
> +        __raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT); 
> + 
> +    } else if (reg_offset == S3C_SYSTIMER_TCNTB) { 
> +        while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT)& 
> +                S3C_SYSTIMER_INT_TCNTB)); 
> +        temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT); 
> +        temp_regs |= S3C_SYSTIMER_INT_TCNTB; 
> +        __raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT); 
> +    } 
> + 
> +    return 0; 
> +} 
> + 
> +static void s5pc11x_rtc_set_tick(int enabled) 
> +{ 
> +    unsigned int tmp; 
> + 
> +    tmp = __raw_readl(rtc_base + S3C2410_RTCCON)&  ~S3C_RTCCON_TICEN; 
> +    if (enabled) 
> +        tmp |= S3C_RTCCON_TICEN; 
> +    __raw_writel(tmp, rtc_base + S3C2410_RTCCON); 
> +} 
> + 
> +static void s5pc11x_tick_timer_setup(void); 
> + 
> +static void s5pc11x_tick_timer_start(unsigned long load_val, 
> +                    int autoreset) 
> +{ 
> +    unsigned int tmp; 
> + 
> +    tmp = __raw_readl(rtc_base + S3C2410_RTCCON)& 
> +        ~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN); 
> +    __raw_writel(tmp, rtc_base + S3C2410_RTCCON); 
> + 
> +    __raw_writel(load_val, rtc_base + S3C2410_TICNT); 
> + 
> +    tmp |= S3C_RTCCON_TICEN; 
> + 
> +    __raw_writel(tmp, rtc_base + S3C2410_RTCCON); 
> +} 
> + 
> +static  void s5pc11x_tick_timer_stop(void) 
> +{ 
> +    unsigned int tmp; 
> + 
> +    tmp = __raw_readl(rtc_base + S3C2410_RTCCON)& 
> +        ~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN); 
> + 
> +    __raw_writel(tmp, rtc_base + S3C2410_RTCCON); 
> + 
> +} 

Will have to think about the cross usage against the 
rtc driver. 
Will be taken care...
> +static void s5pc11x_sched_timer_start(unsigned long load_val, 
> +                    int autoreset) 
> +{ 
> +    unsigned long tcon; 
> +    unsigned long tcnt; 
> +    unsigned long tcfg; 
> + 
> +    /* clock configuration setting and enable */ 
> +    struct clk *clk; 
> + 
> +    tcnt = TICK_MAX;  /* default value for tcnt */ 
> + 
> +    /* initialize system timer clock */ 
> +    tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG); 
> + 
> +    tcfg&= ~S3C_SYSTIMER_TCLK_MASK; 
> +    tcfg |= S3C_SYSTIMER_TCLK_USB; 
> + 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg); 
> + 
> +    /* TCFG must not be changed at run-time. 
> +     * If you want to change TCFG, stop timer(TCON[0] = 0) 
> +     */ 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_TCON, 0); 
> + 
> +    /* read the current timer configuration bits */ 
> +    tcon = s5pc11x_systimer_read(S3C_SYSTIMER_TCON); 
> +    tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG); 
> + 
> +    clk = clk_get(NULL, "systimer"); 
> +    if (IS_ERR(clk)) 
> +        panic("failed to get clock[%s] for system timer", "systimer"); 
> + 
> +    clk_enable(clk); 
> + 
> +    clk_put(clk); 
> + 
> +    tcfg&= ~S3C_SYSTIMER_TCLK_MASK; 
> +    tcfg |= S3C_SYSTIMER_TCLK_USB; 
> +    tcfg&= ~S3C_SYSTIMER_PRESCALER_MASK; 
> + 
> +    /* check to see if timer is within 16bit range... */ 
> +    if (tcnt>  TICK_MAX) { 
> +        panic("setup_timer: cannot configure timer!"); 
> +        return; 
> +    } 
> + 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg); 
> + 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_TCNTB, tcnt); 
> + 
> +    /* set timer con */ 
> +    tcon =  S3C_SYSTIMER_INT_AUTO | S3C_SYSTIMER_START | 
> +            S3C_SYSTIMER_AUTO_RELOAD; 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon); 
> + 
> +    tcon |= S3C_SYSTIMER_INT_START; 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon); 
> + 
> +    /* Interrupt Start and Enable */ 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT, 
> +                (S3C_SYSTIMER_INT_ICNTEIE | 
> +                    S3C_SYSTIMER_INT_EN)); 
> +    sched_timer_running = 1; 
> +} 
> + 
> +/* 
> + * RTC tick : count down to zero, interrupt, reload 
> + */ 
> +static int s5pc11x_tick_set_next_event(unsigned long cycles, 
> +                   struct clock_event_device *evt) 
> +{ 
> +    if  (cycles == 0)    /* Should be larger than 0 */ 
> +        cycles = 1; 
> +    s5pc11x_tick_timer_start(cycles, 0); 
> +    return 0; 
> +} 
> + 
> +static void s5pc11x_tick_set_mode(enum clock_event_mode mode, 
> +                  struct clock_event_device *evt) 
> +{ 
> +    switch (mode) { 
> +    case CLOCK_EVT_MODE_PERIODIC: 
> +        tick_timer_mode = 1; 
> +        break; 
> +    case CLOCK_EVT_MODE_ONESHOT: 
> +        s5pc11x_tick_timer_stop(); 
> +        tick_timer_mode = 0; 
> +        break; 
> +    case CLOCK_EVT_MODE_UNUSED: 
> +    case CLOCK_EVT_MODE_SHUTDOWN: 
> +        /* Sched timer stopped */ 
> +        sched_timer_running = 0; 
> +        /* Reset sched_clock variables after sleep/wakeup */ 
> +        last_ticks = 0; 
> +        s5pc11x_sched_timer_overflows = 0; 
> +        old_overflows = 0; 
> +        pending_irq = 0; 
> +        break; 
> +    case CLOCK_EVT_MODE_RESUME: 
> +        s5pc11x_tick_timer_setup(); 
> +        s5pc11x_sched_timer_start(~0, 1); 
> +        break; 
> +    } 
> +} 
> + 
> +static struct clock_event_device clockevent_tick_timer = { 
> +    .name        = "S5PC110 event timer", 
> +    .features    = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 
> +    .shift        = 32, 
> +    .set_next_event    = s5pc11x_tick_set_next_event, 
> +    .set_mode    = s5pc11x_tick_set_mode, 
> +}; 
> + 
> +irqreturn_t s5pc11x_tick_timer_interrupt(int irq, void *dev_id) 
> +{ 
> +    struct clock_event_device *evt =&clockevent_tick_timer; 
> + 
> +    __raw_writel(S3C_INTP_TIC, rtc_base + S3C_INTP); 
> +    /* In case of oneshot mode */ 
> +    if (tick_timer_mode == 0) 
> +        s5pc11x_tick_timer_stop(); 
> + 
> +    evt->event_handler(evt); 
> + 
> +    return IRQ_HANDLED; 
> +} 
> + 
> +static struct irqaction s5pc11x_tick_timer_irq = { 
> +    .name        = "rtc-tick", 
> +    .flags        = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 
> +    .handler    = s5pc11x_tick_timer_interrupt, 
> +}; 
> + 
> +static void  s5pc11x_init_dynamic_tick_timer(unsigned long rate) 
> +{ 
> +    tick_timer_mode = 1; 
> + 
> +    s5pc11x_tick_timer_stop(); 
> + 
> +    s5pc11x_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 = cpumask_of(0); 
> +    clockevents_register_device(&clockevent_tick_timer); 
> + 
> +    printk(KERN_INFO "mult[%u]\n", clockevent_tick_timer.mult); 
> +    printk(KERN_INFO "max_delta_ns[%u]\n", clockevent_tick_timer.max_delta_ns); 
> +    printk(KERN_INFO "min_delta_ns[%u]\n", clockevent_tick_timer.min_delta_ns); 
> +    printk(KERN_INFO "rate[%lu]\n", rate); 
> +    printk(KERN_INFO "HZ[%d]\n", HZ); 
> +} 
> + 
> + 
> +/* 
> + * --------------------------------------------------------------------------- 
> + * SYSTEM TIMER ... free running 32-bit clock source and scheduler clock 
> + * --------------------------------------------------------------------------- 
> + */ 
> +irqreturn_t s5pc11x_sched_timer_interrupt(int irq, void *dev_id) 
> +{ 
> +    volatile unsigned int temp_cstat; 
> + 
> +    temp_cstat = s5pc11x_systimer_read(S3C_SYSTIMER_INT_CSTAT); 
> +    temp_cstat |= S3C_SYSTIMER_INT_STATS; 
> + 
> +    s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT, temp_cstat); 
> + 
> +    if (unlikely(pending_irq)) 
> +        pending_irq = 0; 
> +    else 
> +        s5pc11x_sched_timer_overflows++; 
> + 
> +    return IRQ_HANDLED; 
> +} 
> + 
> +struct irqaction s5pc11x_systimer_irq = { 
> +    .name        = "System timer", 
> +    .flags        = IRQF_DISABLED , 
> +    .handler    = s5pc11x_sched_timer_interrupt, 
> +}; 
> + 
> + 
> +static cycle_t s5pc11x_sched_timer_read(void) 
> +{ 
> +    return (cycle_t)~__raw_readl(S3C_SYSTIMER_TCNTO); 
> +} 
> + 
> +struct clocksource clocksource_s5pc11x = { 
> +    .name        = "clock_source_systimer", 
> +    .rating        = 300, 
> +    .read        = s5pc11x_sched_timer_read, 
> +    .mask        = CLOCKSOURCE_MASK(32), 
> +    .shift        = 20, 
> +    .flags        = CLOCK_SOURCE_IS_CONTINUOUS, 
> +}; 
> + 
> +static void s5pc11x_init_clocksource(unsigned long rate) 
> +{ 
> +    static char err[] __initdata = KERN_ERR 
> +            "%s: can't register clocksource!\n"; 

yuck 

> +    clocksource_s5pc11x.mult 
> +        = clocksource_khz2mult(rate/1000, clocksource_s5pc11x.shift); 
> + 
> + 
> +    s5pc11x_sched_timer_start(~0, 1); 
> + 
> +    if (clocksource_register(&clocksource_s5pc11x)) 
> +        printk(err, clocksource_s5pc11x.name); 
> +} 
> + 
> +/* 
> + * Returns current time from boot in nsecs. It's OK for this to wrap 
> + * around for now, as it's just a relative time stamp. 
> + */ 
> +unsigned long long sched_clock(void) 
> +{ 
> +    unsigned long irq_flags; 
> +    cycle_t ticks, elapsed_ticks = 0; 
> +    unsigned long long increment = 0; 
> +    unsigned int overflow_cnt = 0; 
> + 
> +    local_irq_save(irq_flags); 
> + 
> +    if (likely(sched_timer_running)) { 
> +        overflow_cnt = (s5pc11x_sched_timer_overflows - old_overflows); 
> + 
> +        ticks = s5pc11x_sched_timer_read(); 
> + 
> +        if (overflow_cnt) { 
> +            increment = (overflow_cnt - 1) * 
> +                    (clocksource_cyc2ns(clocksource_s5pc11x.mask, 
> +                    clocksource_s5pc11x.mult, clocksource_s5pc11x.shift)); 
> +            elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks; 
> +        } else { 
> +            if (unlikely(last_ticks>  ticks)) { 
> +                pending_irq = 1; 
> +                elapsed_ticks = (clocksource_s5pc11x.mask - last_ticks) + ticks; 
> +                s5pc11x_sched_timer_overflows++; 
> +            } else { 
> +                elapsed_ticks = (ticks - last_ticks); 
> +            } 
> +        } 
> + 
> +        time_stamp += (clocksource_cyc2ns(elapsed_ticks, clocksource_s5pc11x.mult, clocksource_s5pc11x.shift) + increment); 
> + 
> +        old_overflows = s5pc11x_sched_timer_overflows; 
> +        last_ticks = ticks; 
> +    } 
> +    local_irq_restore(irq_flags); 
> + 
> +    return time_stamp; 
> +} 
> + 
> +/* 
> + *  Event/Sched Timer initialization 
> + */ 
> +static void s5pc11x_timer_setup(void) 
> +{ 
> +    unsigned long rate; 
> +    /* Setup event timer using XrtcXTI */ 
> +    if (clk_event == NULL) 
> +        clk_event = clk_get(NULL, "XrtcXTI"); 
> +    if (IS_ERR(clk_event)) 
> +        panic("failed to get clock for event timer"); 
> +    rate = clk_get_rate(clk_event); 
> +    s5pc11x_init_dynamic_tick_timer(rate); 
> + 
> +    /* Setup sched-timer using XusbXTI */ 
> +    if (clk_sched == NULL) 
> +        clk_sched = clk_get(NULL, "XusbXTI"); 
> +    if (IS_ERR(clk_sched)) 
> +        panic("failed to get clock for sched-timer"); 
> +    rate = clk_get_rate(clk_sched); 
> +    s5pc11x_init_clocksource(rate); 
> +} 
> + 
> +static void s5pc11x_tick_timer_setup(void) 
> +{ 
> +    unsigned long rate; 
> + 
> +    rate = clk_get_rate(clk_event); 
> +    s5pc11x_tick_timer_start((rate / HZ) - 1, 1); 
> +} 
> + 
> +static void __init s5pc11x_timer_init(void) 
> +{ 
> +    /* Initialize variables before starting each timers */ 
> +    last_ticks = 0; 
> +    s5pc11x_sched_timer_overflows = 0; 
> +    old_overflows = 0; 
> +    time_stamp = 0; 
> +    sched_timer_running = 0; 
> +    pending_irq = 0; 
> +    s5pc11x_timer_setup(); 
> +    setup_irq(IRQ_RTC_TIC,&s5pc11x_tick_timer_irq); 
> +    setup_irq(IRQ_SYSTIMER,&s5pc11x_systimer_irq); 
> +} 
> + 
> + 
> +struct sys_timer s3c24xx_timer = { 
> +    .init        = s5pc11x_timer_init, 
> +}; 
> + 


--  
Ben Dooks, Design & Software Engineer, Simtec Electronics 

http://www.simtec.co.uk/ 

_______________________________________________ 
linux-arm-kernel mailing list 
linux-arm-kernel at lists.infradead.org 
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel 

 
 
 
 

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

* [PATCH]HRT support in Samsung S5P Platform
  2010-07-19  6:54 MADHAV SINGHCHAUHAN
  2010-07-21  0:36 ` Ben Dooks
@ 2010-07-21 12:06 ` Kukjin Kim
  2010-07-22  6:10   ` Kyungmin Park
  2010-07-22  7:55 ` Russell King - ARM Linux
  2 siblings, 1 reply; 7+ messages in thread
From: Kukjin Kim @ 2010-07-21 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

MADHAV SINGHCHAUHAN wrote:
> 
> From: Madhav Singh <singh.madhav@samsung.com>
> Date: Mon, 19 Jul 2010 10:51:01 +0530
> Subject: [PATCH] HRT support in Samsung Tree
> This patch implements HRT support for Samsung plat-s5p.
> RTC has been used as CLOCKEVENT and SYSTIMER as CLOCKSOURCE.
> 
> Signed-off-by: Madhav Chauhan <singh.madhav@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

Hi,

I'd like to say to MADHAV and Kyungmin....

Actually, your patch(code) is same with my team's code in
git(git.kernel.org, kki_ap, 2.6.29-samsung,
arch/arm/plat-s5pc11x/hr-time-rtc.c)
But I couldn't find any credits or comments about that.

If you copy some code from somewhere, please add credits and comments about
that.
It's very important.

> ---
>  arch/arm/mach-s5pv210/Kconfig                   |    9 +
>  arch/arm/mach-s5pv210/include/mach/map.h        |    4 +
>  arch/arm/plat-s5p/clock.c                       |   15 +
>  arch/arm/plat-s5p/cpu.c                         |    8 +
>  arch/arm/plat-s5p/hr-time-rtc.c                 |  470
> +++++++++++++++++++++++
>  arch/arm/plat-s5p/include/plat/regs-sys-timer.h |   63 +++
>  arch/arm/plat-samsung/include/plat/map-base.h   |    2 +
>  7 files changed, 571 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-s5p/hr-time-rtc.c
>  create mode 100644 arch/arm/plat-s5p/include/plat/regs-sys-timer.h
> 
> diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
> index 631019a..9d8698e 100644
> --- a/arch/arm/mach-s5pv210/Kconfig
> +++ b/arch/arm/mach-s5pv210/Kconfig
> @@ -101,4 +101,13 @@ config MACH_SMDKC110
>  	  Machine support for Samsung SMDKC110
>  	  S5PC110(MCP) is one of package option of S5PV210
> 
> +config MACH_S5PV210_HRT
> +        bool "HRtimer and Dynamic Tick support"
> +        select GENERIC_TIME
> +        select GENERIC_CLOCKEVENTS
> +        select HIGH_RES_TIMERS
> +        default n
> +        help
> +          Support for HRtimer and Dynamic Tick system using RTC and
> SYSTEM timer
> +
>  endif
> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
> s5pv210/include/mach/map.h
> index 17687f0..fd8e504 100644
> --- a/arch/arm/mach-s5pv210/include/mach/map.h
> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
> @@ -42,6 +42,10 @@
>  #define S5P_PA_TIMER		S5PV210_PA_TIMER
> 
>  #define S5PV210_PA_SYSTIMER	(0xE2600000)
> +/*For RTC*/
> +#define S5PC11X_PA_RTC		(0xE2800000)
> +#define S3C_PA_RTC		S5PC11X_PA_RTC
> +
> 
>  #define S5PV210_PA_WATCHDOG	(0xE2700000)
> 
> diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
> index b5e2552..1e2a6f4 100644
> --- a/arch/arm/plat-s5p/clock.c
> +++ b/arch/arm/plat-s5p/clock.c
> @@ -89,6 +89,19 @@ struct clk clk_arm = {
>  	.ctrlbit	= 0,
>  };
> 
> +/*For HRT*/
> +struct clk clk_ext_xtal_rtc = {
> +	.name		= "XrtcXTI",
> +	.id		= -1,
> +	.rate           = 32768,
> +};
> +
> +struct clk clk_ext_xtal_usb = {
> +	.name		= "XusbXTI",
> +	.id		= -1,
> +	.rate		= 24000000,
> +};
> +
>  /* Possible clock sources for APLL Mux */
>  static struct clk *clk_src_apll_list[] = {
>  	[0] = &clk_fin_apll,
> @@ -149,6 +162,8 @@ static struct clk *s5p_clks[] __initdata = {
>  	&clk_arm,
>  	&clk_vpll,
>  	&clk_xusbxti,
> +	&clk_ext_xtal_usb,
> +	&clk_ext_xtal_rtc,
>  };
> 
>  void __init s5p_register_clocks(unsigned long xtal_freq)
> diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c
> index 75cb8c3..83ae862 100644
> --- a/arch/arm/plat-s5p/cpu.c
> +++ b/arch/arm/plat-s5p/cpu.c
> @@ -104,6 +104,14 @@ static struct map_desc s5p_iodesc[] __initdata = {
>  		.length		= SZ_4K,
>  		.type		= MT_DEVICE,
>  	},
> +#if defined(CONFIG_MACH_S5PV210_HRT)
> +	{
> +		.virtual        = (unsigned long)S3C_VA_RTC,
> +		.pfn            = __phys_to_pfn(S3C_PA_RTC),
> +		.length         = SZ_4K,
> +		.type           = MT_DEVICE,
> +	},
> +#endif
>  };
> 
>  /* read cpu identification code */
> diff --git a/arch/arm/plat-s5p/hr-time-rtc.c
b/arch/arm/plat-s5p/hr-time-rtc.c
> new file mode 100644
> index 0000000..8decf4e
> --- /dev/null
> +++ b/arch/arm/plat-s5p/hr-time-rtc.c
> @@ -0,0 +1,470 @@
> +/*
> + * linux/arch/arm/plat-s5p/hr-time-rtc.c
> + *
> + * S5PC11X Timers
> + *
> + * Copyright (c) 2006 Samsung Electronics
> + * Copyright (c) 2010 Samsung Electronics Madhav Chauhan
> <singh.madhav@samsung.com>
> + *
> + *
> + * S5PC11X (and compatible) HRT support using RTC and SYSTEM TIMER
> + *
> + * 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 <asm/system.h>
> +#include <mach/hardware.h>
> +#include <asm/irq.h>
> +#include <asm/mach/irq.h>
> +#include <asm/mach/time.h>
> +#include <asm/mach-types.h>
> +#include <mach/map.h>
> +#include <plat/regs-timer.h>
> +#include <plat/regs-rtc.h>
> +#include <plat/regs-sys-timer.h>
> +#include <mach/regs-irq.h>
> +#include <mach/tick.h>
> +#include <plat/clock.h>
> +#include <plat/cpu.h>
> +
> +/*For SCHED_CLOCK*/
> +static unsigned long long time_stamp;
> +static unsigned long long s5pc11x_sched_timer_overflows;
> +static unsigned long long old_overflows;
> +static cycle_t last_ticks;
> +
> +/* Sched timer interrupt is not processed right after
> + * timer counter expired
> + */
> +static unsigned int pending_irq;
> +
> +/* sched_timer_running
> + * 0 : sched timer stopped or not initialized
> + * 1 : sched timer started
> + */
> +static unsigned int sched_timer_running;
> +
> +void __iomem *rtc_base =	S3C_VA_RTC;
> +static struct clk *clk_event;
> +static struct clk *clk_sched;
> +static int tick_timer_mode;	/* 0: oneshot, 1: autoreload */
> +
> +#define RTC_CLOCK		(32768)
> +#define RTC_DEFAULT_TICK	((RTC_CLOCK / HZ) - 1)
> +
> +/*
> + * Helper functions
> + * s5pc11x_systimer_read() : Read from System timer register
> + * s5pc11x_systimer_write(): Write to System timer register
> + *
> + */
> +static unsigned int s5pc11x_systimer_read(unsigned int *reg_offset)
> +{
> +	return __raw_readl(reg_offset);
> +}
> +
> +static unsigned int s5pc11x_systimer_write(unsigned int *reg_offset,
> +					unsigned int value)
> +{
> +	unsigned int temp_regs;
> +
> +	__raw_writel(value, reg_offset);
> +
> +	if (reg_offset == S3C_SYSTIMER_TCON) {
> +		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
> +				S3C_SYSTIMER_INT_TCON));
> +		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
> +		temp_regs |= S3C_SYSTIMER_INT_TCON;
> +		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
> +
> +	} else if (reg_offset == S3C_SYSTIMER_ICNTB) {
> +		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
> +				S3C_SYSTIMER_INT_ICNTB));
> +		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
> +		temp_regs |= S3C_SYSTIMER_INT_ICNTB;
> +		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
> +
> +	} else if (reg_offset == S3C_SYSTIMER_TCNTB) {
> +		while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
> +				S3C_SYSTIMER_INT_TCNTB));
> +		temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
> +		temp_regs |= S3C_SYSTIMER_INT_TCNTB;
> +		__raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
> +	}
> +
> +	return 0;
> +}
> +
> +static void s5pc11x_rtc_set_tick(int enabled)
> +{
> +	unsigned int tmp;
> +
> +	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
> ~S3C_RTCCON_TICEN;
> +	if (enabled)
> +		tmp |= S3C_RTCCON_TICEN;
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +}
> +
> +static void s5pc11x_tick_timer_setup(void);
> +
> +static void s5pc11x_tick_timer_start(unsigned long load_val,
> +					int autoreset)
> +{
> +	unsigned int tmp;
> +
> +	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
> +		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +
> +	__raw_writel(load_val, rtc_base + S3C2410_TICNT);
> +
> +	tmp |= S3C_RTCCON_TICEN;
> +
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +}
> +
> +static  void s5pc11x_tick_timer_stop(void)
> +{
> +	unsigned int tmp;
> +
> +	tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
> +		~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
> +
> +	__raw_writel(tmp, rtc_base + S3C2410_RTCCON);
> +
> +}
> +
> +static void s5pc11x_sched_timer_start(unsigned long load_val,
> +					int autoreset)
> +{
> +	unsigned long tcon;
> +	unsigned long tcnt;
> +	unsigned long tcfg;
> +
> +	/* clock configuration setting and enable */
> +	struct clk *clk;
> +
> +	tcnt = TICK_MAX;  /* default value for tcnt */
> +
> +	/* initialize system timer clock */
> +	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
> +
> +	tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
> +	tcfg |= S3C_SYSTIMER_TCLK_USB;
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
> +
> +	/* TCFG must not be changed at run-time.
> +	 * If you want to change TCFG, stop timer(TCON[0] = 0)
> +	 */
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, 0);
> +
> +	/* read the current timer configuration bits */
> +	tcon = s5pc11x_systimer_read(S3C_SYSTIMER_TCON);
> +	tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
> +
> +	clk = clk_get(NULL, "systimer");
> +	if (IS_ERR(clk))
> +		panic("failed to get clock[%s] for system timer",
"systimer");
> +
> +	clk_enable(clk);
> +
> +	clk_put(clk);
> +
> +	tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
> +	tcfg |= S3C_SYSTIMER_TCLK_USB;
> +	tcfg &= ~S3C_SYSTIMER_PRESCALER_MASK;
> +
> +	/* check to see if timer is within 16bit range... */
> +	if (tcnt > TICK_MAX) {
> +		panic("setup_timer: cannot configure timer!");
> +		return;
> +	}
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCNTB, tcnt);
> +
> +	/* set timer con */
> +	tcon =  S3C_SYSTIMER_INT_AUTO | S3C_SYSTIMER_START |
> +			S3C_SYSTIMER_AUTO_RELOAD;
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
> +
> +	tcon |= S3C_SYSTIMER_INT_START;
> +	s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
> +
> +	/* Interrupt Start and Enable */
> +	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT,
> +				(S3C_SYSTIMER_INT_ICNTEIE |
> +					S3C_SYSTIMER_INT_EN));
> +	sched_timer_running = 1;
> +}
> +
> +/*
> + * RTC tick : count down to zero, interrupt, reload
> + */
> +static int s5pc11x_tick_set_next_event(unsigned long cycles,
> +				   struct clock_event_device *evt)
> +{
> +	if  (cycles == 0)	/* Should be larger than 0 */
> +		cycles = 1;
> +	s5pc11x_tick_timer_start(cycles, 0);
> +	return 0;
> +}
> +
> +static void s5pc11x_tick_set_mode(enum clock_event_mode mode,
> +			      struct clock_event_device *evt)
> +{
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		tick_timer_mode = 1;
> +		break;
> +	case CLOCK_EVT_MODE_ONESHOT:
> +		s5pc11x_tick_timer_stop();
> +		tick_timer_mode = 0;
> +		break;
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +		/* Sched timer stopped */
> +		sched_timer_running = 0;
> +		/* Reset sched_clock variables after sleep/wakeup */
> +		last_ticks = 0;
> +		s5pc11x_sched_timer_overflows = 0;
> +		old_overflows = 0;
> +		pending_irq = 0;
> +		break;
> +	case CLOCK_EVT_MODE_RESUME:
> +		s5pc11x_tick_timer_setup();
> +		s5pc11x_sched_timer_start(~0, 1);
> +		break;
> +	}
> +}
> +
> +static struct clock_event_device clockevent_tick_timer = {
> +	.name		= "S5PC110 event timer",
> +	.features	= CLOCK_EVT_FEAT_PERIODIC |
> CLOCK_EVT_FEAT_ONESHOT,
> +	.shift		= 32,
> +	.set_next_event	= s5pc11x_tick_set_next_event,
> +	.set_mode	= s5pc11x_tick_set_mode,
> +};
> +
> +irqreturn_t s5pc11x_tick_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *evt = &clockevent_tick_timer;
> +
> +	__raw_writel(S3C_INTP_TIC, rtc_base + S3C_INTP);
> +	/* In case of oneshot mode */
> +	if (tick_timer_mode == 0)
> +		s5pc11x_tick_timer_stop();
> +
> +	evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static struct irqaction s5pc11x_tick_timer_irq = {
> +	.name		= "rtc-tick",
> +	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
> +	.handler	= s5pc11x_tick_timer_interrupt,
> +};
> +
> +static void  s5pc11x_init_dynamic_tick_timer(unsigned long rate)
> +{
> +	tick_timer_mode = 1;
> +
> +	s5pc11x_tick_timer_stop();
> +
> +	s5pc11x_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 = cpumask_of(0);
> +	clockevents_register_device(&clockevent_tick_timer);
> +
> +	printk(KERN_INFO "mult[%u]\n", clockevent_tick_timer.mult);
> +	printk(KERN_INFO "max_delta_ns[%u]\n",
> clockevent_tick_timer.max_delta_ns);
> +	printk(KERN_INFO "min_delta_ns[%u]\n",
> clockevent_tick_timer.min_delta_ns);
> +	printk(KERN_INFO "rate[%lu]\n", rate);
> +	printk(KERN_INFO "HZ[%d]\n", HZ);
> +}
> +
> +
> +/*
> + *
---------------------------------------------------------------------------
> + * SYSTEM TIMER ... free running 32-bit clock source and scheduler clock
> + *
---------------------------------------------------------------------------
> + */
> +irqreturn_t s5pc11x_sched_timer_interrupt(int irq, void *dev_id)
> +{
> +	volatile unsigned int temp_cstat;
> +
> +	temp_cstat = s5pc11x_systimer_read(S3C_SYSTIMER_INT_CSTAT);
> +	temp_cstat |= S3C_SYSTIMER_INT_STATS;
> +
> +	s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT, temp_cstat);
> +
> +	if (unlikely(pending_irq))
> +		pending_irq = 0;
> +	else
> +		s5pc11x_sched_timer_overflows++;
> +
> +	return IRQ_HANDLED;
> +}
> +
> +struct irqaction s5pc11x_systimer_irq = {
> +	.name		= "System timer",
> +	.flags		= IRQF_DISABLED ,
> +	.handler	= s5pc11x_sched_timer_interrupt,
> +};
> +
> +
> +static cycle_t s5pc11x_sched_timer_read(void)
> +{
> +	return (cycle_t)~__raw_readl(S3C_SYSTIMER_TCNTO);
> +}
> +
> +struct clocksource clocksource_s5pc11x = {
> +	.name		= "clock_source_systimer",
> +	.rating		= 300,
> +	.read		= s5pc11x_sched_timer_read,
> +	.mask		= CLOCKSOURCE_MASK(32),
> +	.shift		= 20,
> +	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> +};
> +
> +static void s5pc11x_init_clocksource(unsigned long rate)
> +{
> +	static char err[] __initdata = KERN_ERR
> +			"%s: can't register clocksource!\n";
> +
> +	clocksource_s5pc11x.mult
> +		= clocksource_khz2mult(rate/1000,
clocksource_s5pc11x.shift);
> +
> +
> +	s5pc11x_sched_timer_start(~0, 1);
> +
> +	if (clocksource_register(&clocksource_s5pc11x))
> +		printk(err, clocksource_s5pc11x.name);
> +}
> +
> +/*
> + * Returns current time from boot in nsecs. It's OK for this to wrap
> + * around for now, as it's just a relative time stamp.
> + */
> +unsigned long long sched_clock(void)
> +{
> +	unsigned long irq_flags;
> +	cycle_t ticks, elapsed_ticks = 0;
> +	unsigned long long increment = 0;
> +	unsigned int overflow_cnt = 0;
> +
> +	local_irq_save(irq_flags);
> +
> +	if (likely(sched_timer_running)) {
> +		overflow_cnt = (s5pc11x_sched_timer_overflows -
> old_overflows);
> +
> +		ticks = s5pc11x_sched_timer_read();
> +
> +		if (overflow_cnt) {
> +			increment = (overflow_cnt - 1) *
> +
> 	(clocksource_cyc2ns(clocksource_s5pc11x.mask,
> +					clocksource_s5pc11x.mult,
> clocksource_s5pc11x.shift));
> +			elapsed_ticks = (clocksource_s5pc11x.mask -
last_ticks)
> + ticks;
> +		} else {
> +			if (unlikely(last_ticks > ticks)) {
> +				pending_irq = 1;
> +				elapsed_ticks = (clocksource_s5pc11x.mask -
> last_ticks) + ticks;
> +				s5pc11x_sched_timer_overflows++;
> +			} else {
> +				elapsed_ticks = (ticks - last_ticks);
> +			}
> +		}
> +
> +		time_stamp += (clocksource_cyc2ns(elapsed_ticks,
> clocksource_s5pc11x.mult, clocksource_s5pc11x.shift) + increment);
> +
> +		old_overflows = s5pc11x_sched_timer_overflows;
> +		last_ticks = ticks;
> +	}
> +	local_irq_restore(irq_flags);
> +
> +	return time_stamp;
> +}
> +
> +/*
> + *  Event/Sched Timer initialization
> + */
> +static void s5pc11x_timer_setup(void)
> +{
> +	unsigned long rate;
> +	/* Setup event timer using XrtcXTI */
> +	if (clk_event == NULL)
> +		clk_event = clk_get(NULL, "XrtcXTI");
> +	if (IS_ERR(clk_event))
> +		panic("failed to get clock for event timer");
> +	rate = clk_get_rate(clk_event);
> +	s5pc11x_init_dynamic_tick_timer(rate);
> +
> +	/* Setup sched-timer using XusbXTI */
> +	if (clk_sched == NULL)
> +		clk_sched = clk_get(NULL, "XusbXTI");
> +	if (IS_ERR(clk_sched))
> +		panic("failed to get clock for sched-timer");
> +	rate = clk_get_rate(clk_sched);
> +	s5pc11x_init_clocksource(rate);
> +}
> +
> +static void s5pc11x_tick_timer_setup(void)
> +{
> +	unsigned long rate;
> +
> +	rate = clk_get_rate(clk_event);
> +	s5pc11x_tick_timer_start((rate / HZ) - 1, 1);
> +}
> +
> +static void __init s5pc11x_timer_init(void)
> +{
> +	/* Initialize variables before starting each timers */
> +	last_ticks = 0;
> +	s5pc11x_sched_timer_overflows = 0;
> +	old_overflows = 0;
> +	time_stamp = 0;
> +	sched_timer_running = 0;
> +	pending_irq = 0;
> +	s5pc11x_timer_setup();
> +	setup_irq(IRQ_RTC_TIC, &s5pc11x_tick_timer_irq);
> +	setup_irq(IRQ_SYSTIMER, &s5pc11x_systimer_irq);
> +}
> +
> +
> +struct sys_timer s3c24xx_timer = {
> +	.init		= s5pc11x_timer_init,
> +};
> +
> diff --git a/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
b/arch/arm/plat-
> s5p/include/plat/regs-sys-timer.h
> new file mode 100644
> index 0000000..75e6267
> --- /dev/null
> +++ b/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
> @@ -0,0 +1,63 @@
> +/* arch/arm/plat-s5pc1xx/include/plat/regs-sys-timer.h
> + *
> + * Copyright (c) 2008 Samsung Electronics
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * S5PC1XX System Timer configuration
> +*/
> +
> +#ifndef __ASM_ARCH_REGS_SYS_TIMER_H
> +#define __ASM_ARCH_REGS_SYS_TIMER_H
> +
> +#define S3C_SYSTIMERREG(x)		(S5P_VA_SYSTIMER + (x))
> +
> +#define S3C_SYSTIMER_TCFG		S3C_SYSTIMERREG(0x00)
> +#define S3C_SYSTIMER_TCON		S3C_SYSTIMERREG(0x04)
> +#define S3C_SYSTIMER_TCNTB		S3C_SYSTIMERREG(0x08)
> +#define S3C_SYSTIMER_TCNTO		S3C_SYSTIMERREG(0x0c)
> +
> +#define S3C_SYSTIMER_TFCNTB		S3C_SYSTIMERREG(0x10)
> +#define S3C_SYSTIMER_ICNTB		S3C_SYSTIMERREG(0x18)
> +#define S3C_SYSTIMER_ICNTO		S3C_SYSTIMERREG(0x1c)
> +#define S3C_SYSTIMER_INT_CSTAT	S3C_SYSTIMERREG(0x20)
> +
> +/* Value for TCFG */
> +#define S3C_SYSTIMER_TCLK_MASK		(3<<12)
> +#define S3C_SYSTIMER_TCLK_XXTI		(0<<12)
> +#define S3C_SYSTIMER_TCLK_RTC		(1<<12)
> +#define S3C_SYSTIMER_TCLK_USB		(2<<12)
> +#define S3C_SYSTIMER_TCLK_PCLK		(3<<12)
> +
> +#define S3C_SYSTIMER_DIV_MASK		(7<<8)
> +#define S3C_SYSTIMER_DIV_1		(0<<8)
> +#define S3C_SYSTIMER_DIV_2		(1<<8)
> +#define S3C_SYSTIMER_DIV_4		(2<<8)
> +#define S3C_SYSTIMER_DIV_8		(3<<8)
> +#define S3C_SYSTIMER_DIV_16		(4<<8)
> +
> +#define S3C_SYSTIMER_TARGET_HZ		200
> +#define S3C_SYSTIMER_PRESCALER		5
> +#define S3C_SYSTIMER_PRESCALER_MASK	(0x3f<<0)
> +
> +/* value for TCON */
> +#define S3C_SYSTIMER_INT_AUTO		(1<<5)
> +#define S3C_SYSTIMER_INT_IMM		(1<<4)
> +#define S3C_SYSTIMER_INT_START		(1<<3)
> +#define S3C_SYSTIMER_AUTO_RELOAD	(1<<2)
> +#define S3C_SYSTIMER_IMM_UPDATE		(1<<1)
> +#define S3C_SYSTIMER_START		(1<<0)
> +
> +/* Value for INT_CSTAT */
> +#define S3C_SYSTIMER_INT_IWIE		(1<<9)
> +#define S3C_SYSTIMER_INT_TWIE		(1<<10)
> +#define S3C_SYSTIMER_INT_ICNTEIE	(1<<6)
> +#define S3C_SYSTIMER_INT_TCON		(1<<5)
> +#define S3C_SYSTIMER_INT_ICNTB		(1<<4)
> +#define S3C_SYSTIMER_INT_TCNTB		(1<<2)
> +#define S3C_SYSTIMER_INT_STATS		(1<<1)
> +#define S3C_SYSTIMER_INT_EN		(1<<0)
> +
> +#endif /*  __ASM_ARCH_REGS_TIMER_H */
> diff --git a/arch/arm/plat-samsung/include/plat/map-base.h
b/arch/arm/plat-
> samsung/include/plat/map-base.h
> index 250be31..ff766d9 100644
> --- a/arch/arm/plat-samsung/include/plat/map-base.h
> +++ b/arch/arm/plat-samsung/include/plat/map-base.h
> @@ -36,6 +36,8 @@
>  #define S3C_VA_TIMER	S3C_ADDR(0x00300000)	/* timer block */
>  #define S3C_VA_WATCHDOG	S3C_ADDR(0x00400000)	/* watchdog */
>  #define S3C_VA_UART	S3C_ADDR(0x01000000)	/* UART */
> +/*For RTC*/
> +#define S3C_VA_RTC	S3C_ADDR(0x00c00000)
> 
>  /* This is used for the CPU specific mappings that may be needed, so that
>   * they do not need to directly used S3C_ADDR() and thus make it easier
to
> --
> 1.6.0.4
> 


Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

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

* [PATCH]HRT support in Samsung S5P Platform
  2010-07-21 12:06 ` Kukjin Kim
@ 2010-07-22  6:10   ` Kyungmin Park
  2010-07-23  2:48     ` Jassi Brar
  0 siblings, 1 reply; 7+ messages in thread
From: Kyungmin Park @ 2010-07-22  6:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 21, 2010 at 9:06 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
> MADHAV SINGHCHAUHAN wrote:
>>
>> From: Madhav Singh <singh.madhav@samsung.com>
>> Date: Mon, 19 Jul 2010 10:51:01 +0530
>> Subject: [PATCH] HRT support in Samsung Tree
>> This patch implements HRT support for Samsung plat-s5p.
>> RTC has been used as CLOCKEVENT and SYSTIMER as CLOCKSOURCE.
>>
>> Signed-off-by: Madhav Chauhan <singh.madhav@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>
> Hi,
>
> I'd like to say to MADHAV and Kyungmin....
>
> Actually, your patch(code) is same with my team's code in
> git(git.kernel.org, kki_ap, 2.6.29-samsung,
> arch/arm/plat-s5pc11x/hr-time-rtc.c)
> But I couldn't find any credits or comments about that.
>
> If you copy some code from somewhere, please add credits and comments about
> that.
> It's very important.

Right, it's my mistake can't check it. Madhav will add the credit and
describe the original author.
I talked to Mr. Lee jaechul and get the permission to send the patch.

To Madhav,

Next time, Add the From: Jaechul Lee at commit message and signed-off-by.

Thank you,
Kyungmin Park
>
>> ---
>> ?arch/arm/mach-s5pv210/Kconfig ? ? ? ? ? ? ? ? ? | ? ?9 +
>> ?arch/arm/mach-s5pv210/include/mach/map.h ? ? ? ?| ? ?4 +
>> ?arch/arm/plat-s5p/clock.c ? ? ? ? ? ? ? ? ? ? ? | ? 15 +
>> ?arch/arm/plat-s5p/cpu.c ? ? ? ? ? ? ? ? ? ? ? ? | ? ?8 +
>> ?arch/arm/plat-s5p/hr-time-rtc.c ? ? ? ? ? ? ? ? | ?470
>> +++++++++++++++++++++++
>> ?arch/arm/plat-s5p/include/plat/regs-sys-timer.h | ? 63 +++
>> ?arch/arm/plat-samsung/include/plat/map-base.h ? | ? ?2 +
>> ?7 files changed, 571 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/plat-s5p/hr-time-rtc.c
>> ?create mode 100644 arch/arm/plat-s5p/include/plat/regs-sys-timer.h
>>
>> diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
>> index 631019a..9d8698e 100644
>> --- a/arch/arm/mach-s5pv210/Kconfig
>> +++ b/arch/arm/mach-s5pv210/Kconfig
>> @@ -101,4 +101,13 @@ config MACH_SMDKC110
>> ? ? ? ? Machine support for Samsung SMDKC110
>> ? ? ? ? S5PC110(MCP) is one of package option of S5PV210
>>
>> +config MACH_S5PV210_HRT
>> + ? ? ? ?bool "HRtimer and Dynamic Tick support"
>> + ? ? ? ?select GENERIC_TIME
>> + ? ? ? ?select GENERIC_CLOCKEVENTS
>> + ? ? ? ?select HIGH_RES_TIMERS
>> + ? ? ? ?default n
>> + ? ? ? ?help
>> + ? ? ? ? ?Support for HRtimer and Dynamic Tick system using RTC and
>> SYSTEM timer
>> +
>> ?endif
>> diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-
>> s5pv210/include/mach/map.h
>> index 17687f0..fd8e504 100644
>> --- a/arch/arm/mach-s5pv210/include/mach/map.h
>> +++ b/arch/arm/mach-s5pv210/include/mach/map.h
>> @@ -42,6 +42,10 @@
>> ?#define S5P_PA_TIMER ? ? ? ? S5PV210_PA_TIMER
>>
>> ?#define S5PV210_PA_SYSTIMER ?(0xE2600000)
>> +/*For RTC*/
>> +#define S5PC11X_PA_RTC ? ? ? ? ? ? ? (0xE2800000)
>> +#define S3C_PA_RTC ? ? ? ? ? S5PC11X_PA_RTC
>> +
>>
>> ?#define S5PV210_PA_WATCHDOG ?(0xE2700000)
>>
>> diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
>> index b5e2552..1e2a6f4 100644
>> --- a/arch/arm/plat-s5p/clock.c
>> +++ b/arch/arm/plat-s5p/clock.c
>> @@ -89,6 +89,19 @@ struct clk clk_arm = {
>> ? ? ? .ctrlbit ? ? ? ?= 0,
>> ?};
>>
>> +/*For HRT*/
>> +struct clk clk_ext_xtal_rtc = {
>> + ? ? .name ? ? ? ? ? = "XrtcXTI",
>> + ? ? .id ? ? ? ? ? ? = -1,
>> + ? ? .rate ? ? ? ? ? = 32768,
>> +};
>> +
>> +struct clk clk_ext_xtal_usb = {
>> + ? ? .name ? ? ? ? ? = "XusbXTI",
>> + ? ? .id ? ? ? ? ? ? = -1,
>> + ? ? .rate ? ? ? ? ? = 24000000,
>> +};
>> +
>> ?/* Possible clock sources for APLL Mux */
>> ?static struct clk *clk_src_apll_list[] = {
>> ? ? ? [0] = &clk_fin_apll,
>> @@ -149,6 +162,8 @@ static struct clk *s5p_clks[] __initdata = {
>> ? ? ? &clk_arm,
>> ? ? ? &clk_vpll,
>> ? ? ? &clk_xusbxti,
>> + ? ? &clk_ext_xtal_usb,
>> + ? ? &clk_ext_xtal_rtc,
>> ?};
>>
>> ?void __init s5p_register_clocks(unsigned long xtal_freq)
>> diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c
>> index 75cb8c3..83ae862 100644
>> --- a/arch/arm/plat-s5p/cpu.c
>> +++ b/arch/arm/plat-s5p/cpu.c
>> @@ -104,6 +104,14 @@ static struct map_desc s5p_iodesc[] __initdata = {
>> ? ? ? ? ? ? ? .length ? ? ? ? = SZ_4K,
>> ? ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> ? ? ? },
>> +#if defined(CONFIG_MACH_S5PV210_HRT)
>> + ? ? {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= (unsigned long)S3C_VA_RTC,
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(S3C_PA_RTC),
>> + ? ? ? ? ? ? .length ? ? ? ? = SZ_4K,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? },
>> +#endif
>> ?};
>>
>> ?/* read cpu identification code */
>> diff --git a/arch/arm/plat-s5p/hr-time-rtc.c
> b/arch/arm/plat-s5p/hr-time-rtc.c
>> new file mode 100644
>> index 0000000..8decf4e
>> --- /dev/null
>> +++ b/arch/arm/plat-s5p/hr-time-rtc.c
>> @@ -0,0 +1,470 @@
>> +/*
>> + * linux/arch/arm/plat-s5p/hr-time-rtc.c
>> + *
>> + * S5PC11X Timers
>> + *
>> + * Copyright (c) 2006 Samsung Electronics
>> + * Copyright (c) 2010 Samsung Electronics Madhav Chauhan
>> <singh.madhav@samsung.com>
>> + *
>> + *
>> + * S5PC11X (and compatible) HRT support using RTC and SYSTEM TIMER
>> + *
>> + * 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 <asm/system.h>
>> +#include <mach/hardware.h>
>> +#include <asm/irq.h>
>> +#include <asm/mach/irq.h>
>> +#include <asm/mach/time.h>
>> +#include <asm/mach-types.h>
>> +#include <mach/map.h>
>> +#include <plat/regs-timer.h>
>> +#include <plat/regs-rtc.h>
>> +#include <plat/regs-sys-timer.h>
>> +#include <mach/regs-irq.h>
>> +#include <mach/tick.h>
>> +#include <plat/clock.h>
>> +#include <plat/cpu.h>
>> +
>> +/*For SCHED_CLOCK*/
>> +static unsigned long long time_stamp;
>> +static unsigned long long s5pc11x_sched_timer_overflows;
>> +static unsigned long long old_overflows;
>> +static cycle_t last_ticks;
>> +
>> +/* Sched timer interrupt is not processed right after
>> + * timer counter expired
>> + */
>> +static unsigned int pending_irq;
>> +
>> +/* sched_timer_running
>> + * 0 : sched timer stopped or not initialized
>> + * 1 : sched timer started
>> + */
>> +static unsigned int sched_timer_running;
>> +
>> +void __iomem *rtc_base = ? ? S3C_VA_RTC;
>> +static struct clk *clk_event;
>> +static struct clk *clk_sched;
>> +static int tick_timer_mode; ?/* 0: oneshot, 1: autoreload */
>> +
>> +#define RTC_CLOCK ? ? ? ? ? ?(32768)
>> +#define RTC_DEFAULT_TICK ? ? ((RTC_CLOCK / HZ) - 1)
>> +
>> +/*
>> + * Helper functions
>> + * s5pc11x_systimer_read() : Read from System timer register
>> + * s5pc11x_systimer_write(): Write to System timer register
>> + *
>> + */
>> +static unsigned int s5pc11x_systimer_read(unsigned int *reg_offset)
>> +{
>> + ? ? return __raw_readl(reg_offset);
>> +}
>> +
>> +static unsigned int s5pc11x_systimer_write(unsigned int *reg_offset,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned int value)
>> +{
>> + ? ? unsigned int temp_regs;
>> +
>> + ? ? __raw_writel(value, reg_offset);
>> +
>> + ? ? if (reg_offset == S3C_SYSTIMER_TCON) {
>> + ? ? ? ? ? ? while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? S3C_SYSTIMER_INT_TCON));
>> + ? ? ? ? ? ? temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
>> + ? ? ? ? ? ? temp_regs |= S3C_SYSTIMER_INT_TCON;
>> + ? ? ? ? ? ? __raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
>> +
>> + ? ? } else if (reg_offset == S3C_SYSTIMER_ICNTB) {
>> + ? ? ? ? ? ? while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? S3C_SYSTIMER_INT_ICNTB));
>> + ? ? ? ? ? ? temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
>> + ? ? ? ? ? ? temp_regs |= S3C_SYSTIMER_INT_ICNTB;
>> + ? ? ? ? ? ? __raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
>> +
>> + ? ? } else if (reg_offset == S3C_SYSTIMER_TCNTB) {
>> + ? ? ? ? ? ? while (!(__raw_readl(S3C_SYSTIMER_INT_CSTAT) &
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? S3C_SYSTIMER_INT_TCNTB));
>> + ? ? ? ? ? ? temp_regs = __raw_readl(S3C_SYSTIMER_INT_CSTAT);
>> + ? ? ? ? ? ? temp_regs |= S3C_SYSTIMER_INT_TCNTB;
>> + ? ? ? ? ? ? __raw_writel(temp_regs, S3C_SYSTIMER_INT_CSTAT);
>> + ? ? }
>> +
>> + ? ? return 0;
>> +}
>> +
>> +static void s5pc11x_rtc_set_tick(int enabled)
>> +{
>> + ? ? unsigned int tmp;
>> +
>> + ? ? tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
>> ~S3C_RTCCON_TICEN;
>> + ? ? if (enabled)
>> + ? ? ? ? ? ? tmp |= S3C_RTCCON_TICEN;
>> + ? ? __raw_writel(tmp, rtc_base + S3C2410_RTCCON);
>> +}
>> +
>> +static void s5pc11x_tick_timer_setup(void);
>> +
>> +static void s5pc11x_tick_timer_start(unsigned long load_val,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int autoreset)
>> +{
>> + ? ? unsigned int tmp;
>> +
>> + ? ? tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
>> + ? ? ? ? ? ? ~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
>> + ? ? __raw_writel(tmp, rtc_base + S3C2410_RTCCON);
>> +
>> + ? ? __raw_writel(load_val, rtc_base + S3C2410_TICNT);
>> +
>> + ? ? tmp |= S3C_RTCCON_TICEN;
>> +
>> + ? ? __raw_writel(tmp, rtc_base + S3C2410_RTCCON);
>> +}
>> +
>> +static ?void s5pc11x_tick_timer_stop(void)
>> +{
>> + ? ? unsigned int tmp;
>> +
>> + ? ? tmp = __raw_readl(rtc_base + S3C2410_RTCCON) &
>> + ? ? ? ? ? ? ~(S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN);
>> +
>> + ? ? __raw_writel(tmp, rtc_base + S3C2410_RTCCON);
>> +
>> +}
>> +
>> +static void s5pc11x_sched_timer_start(unsigned long load_val,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int autoreset)
>> +{
>> + ? ? unsigned long tcon;
>> + ? ? unsigned long tcnt;
>> + ? ? unsigned long tcfg;
>> +
>> + ? ? /* clock configuration setting and enable */
>> + ? ? struct clk *clk;
>> +
>> + ? ? tcnt = TICK_MAX; ?/* default value for tcnt */
>> +
>> + ? ? /* initialize system timer clock */
>> + ? ? tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
>> +
>> + ? ? tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
>> + ? ? tcfg |= S3C_SYSTIMER_TCLK_USB;
>> +
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
>> +
>> + ? ? /* TCFG must not be changed at run-time.
>> + ? ? ?* If you want to change TCFG, stop timer(TCON[0] = 0)
>> + ? ? ?*/
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_TCON, 0);
>> +
>> + ? ? /* read the current timer configuration bits */
>> + ? ? tcon = s5pc11x_systimer_read(S3C_SYSTIMER_TCON);
>> + ? ? tcfg = s5pc11x_systimer_read(S3C_SYSTIMER_TCFG);
>> +
>> + ? ? clk = clk_get(NULL, "systimer");
>> + ? ? if (IS_ERR(clk))
>> + ? ? ? ? ? ? panic("failed to get clock[%s] for system timer",
> "systimer");
>> +
>> + ? ? clk_enable(clk);
>> +
>> + ? ? clk_put(clk);
>> +
>> + ? ? tcfg &= ~S3C_SYSTIMER_TCLK_MASK;
>> + ? ? tcfg |= S3C_SYSTIMER_TCLK_USB;
>> + ? ? tcfg &= ~S3C_SYSTIMER_PRESCALER_MASK;
>> +
>> + ? ? /* check to see if timer is within 16bit range... */
>> + ? ? if (tcnt > TICK_MAX) {
>> + ? ? ? ? ? ? panic("setup_timer: cannot configure timer!");
>> + ? ? ? ? ? ? return;
>> + ? ? }
>> +
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_TCFG, tcfg);
>> +
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_TCNTB, tcnt);
>> +
>> + ? ? /* set timer con */
>> + ? ? tcon = ?S3C_SYSTIMER_INT_AUTO | S3C_SYSTIMER_START |
>> + ? ? ? ? ? ? ? ? ? ? S3C_SYSTIMER_AUTO_RELOAD;
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
>> +
>> + ? ? tcon |= S3C_SYSTIMER_INT_START;
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_TCON, tcon);
>> +
>> + ? ? /* Interrupt Start and Enable */
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (S3C_SYSTIMER_INT_ICNTEIE |
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? S3C_SYSTIMER_INT_EN));
>> + ? ? sched_timer_running = 1;
>> +}
>> +
>> +/*
>> + * RTC tick : count down to zero, interrupt, reload
>> + */
>> +static int s5pc11x_tick_set_next_event(unsigned long cycles,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct clock_event_device *evt)
>> +{
>> + ? ? if ?(cycles == 0) ? ? ? /* Should be larger than 0 */
>> + ? ? ? ? ? ? cycles = 1;
>> + ? ? s5pc11x_tick_timer_start(cycles, 0);
>> + ? ? return 0;
>> +}
>> +
>> +static void s5pc11x_tick_set_mode(enum clock_event_mode mode,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *evt)
>> +{
>> + ? ? switch (mode) {
>> + ? ? case CLOCK_EVT_MODE_PERIODIC:
>> + ? ? ? ? ? ? tick_timer_mode = 1;
>> + ? ? ? ? ? ? break;
>> + ? ? case CLOCK_EVT_MODE_ONESHOT:
>> + ? ? ? ? ? ? s5pc11x_tick_timer_stop();
>> + ? ? ? ? ? ? tick_timer_mode = 0;
>> + ? ? ? ? ? ? break;
>> + ? ? case CLOCK_EVT_MODE_UNUSED:
>> + ? ? case CLOCK_EVT_MODE_SHUTDOWN:
>> + ? ? ? ? ? ? /* Sched timer stopped */
>> + ? ? ? ? ? ? sched_timer_running = 0;
>> + ? ? ? ? ? ? /* Reset sched_clock variables after sleep/wakeup */
>> + ? ? ? ? ? ? last_ticks = 0;
>> + ? ? ? ? ? ? s5pc11x_sched_timer_overflows = 0;
>> + ? ? ? ? ? ? old_overflows = 0;
>> + ? ? ? ? ? ? pending_irq = 0;
>> + ? ? ? ? ? ? break;
>> + ? ? case CLOCK_EVT_MODE_RESUME:
>> + ? ? ? ? ? ? s5pc11x_tick_timer_setup();
>> + ? ? ? ? ? ? s5pc11x_sched_timer_start(~0, 1);
>> + ? ? ? ? ? ? break;
>> + ? ? }
>> +}
>> +
>> +static struct clock_event_device clockevent_tick_timer = {
>> + ? ? .name ? ? ? ? ? = "S5PC110 event timer",
>> + ? ? .features ? ? ? = CLOCK_EVT_FEAT_PERIODIC |
>> CLOCK_EVT_FEAT_ONESHOT,
>> + ? ? .shift ? ? ? ? ?= 32,
>> + ? ? .set_next_event = s5pc11x_tick_set_next_event,
>> + ? ? .set_mode ? ? ? = s5pc11x_tick_set_mode,
>> +};
>> +
>> +irqreturn_t s5pc11x_tick_timer_interrupt(int irq, void *dev_id)
>> +{
>> + ? ? struct clock_event_device *evt = &clockevent_tick_timer;
>> +
>> + ? ? __raw_writel(S3C_INTP_TIC, rtc_base + S3C_INTP);
>> + ? ? /* In case of oneshot mode */
>> + ? ? if (tick_timer_mode == 0)
>> + ? ? ? ? ? ? s5pc11x_tick_timer_stop();
>> +
>> + ? ? evt->event_handler(evt);
>> +
>> + ? ? return IRQ_HANDLED;
>> +}
>> +
>> +static struct irqaction s5pc11x_tick_timer_irq = {
>> + ? ? .name ? ? ? ? ? = "rtc-tick",
>> + ? ? .flags ? ? ? ? ?= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
>> + ? ? .handler ? ? ? ?= s5pc11x_tick_timer_interrupt,
>> +};
>> +
>> +static void ?s5pc11x_init_dynamic_tick_timer(unsigned long rate)
>> +{
>> + ? ? tick_timer_mode = 1;
>> +
>> + ? ? s5pc11x_tick_timer_stop();
>> +
>> + ? ? s5pc11x_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 = cpumask_of(0);
>> + ? ? clockevents_register_device(&clockevent_tick_timer);
>> +
>> + ? ? printk(KERN_INFO "mult[%u]\n", clockevent_tick_timer.mult);
>> + ? ? printk(KERN_INFO "max_delta_ns[%u]\n",
>> clockevent_tick_timer.max_delta_ns);
>> + ? ? printk(KERN_INFO "min_delta_ns[%u]\n",
>> clockevent_tick_timer.min_delta_ns);
>> + ? ? printk(KERN_INFO "rate[%lu]\n", rate);
>> + ? ? printk(KERN_INFO "HZ[%d]\n", HZ);
>> +}
>> +
>> +
>> +/*
>> + *
> ---------------------------------------------------------------------------
>> + * SYSTEM TIMER ... free running 32-bit clock source and scheduler clock
>> + *
> ---------------------------------------------------------------------------
>> + */
>> +irqreturn_t s5pc11x_sched_timer_interrupt(int irq, void *dev_id)
>> +{
>> + ? ? volatile unsigned int temp_cstat;
>> +
>> + ? ? temp_cstat = s5pc11x_systimer_read(S3C_SYSTIMER_INT_CSTAT);
>> + ? ? temp_cstat |= S3C_SYSTIMER_INT_STATS;
>> +
>> + ? ? s5pc11x_systimer_write(S3C_SYSTIMER_INT_CSTAT, temp_cstat);
>> +
>> + ? ? if (unlikely(pending_irq))
>> + ? ? ? ? ? ? pending_irq = 0;
>> + ? ? else
>> + ? ? ? ? ? ? s5pc11x_sched_timer_overflows++;
>> +
>> + ? ? return IRQ_HANDLED;
>> +}
>> +
>> +struct irqaction s5pc11x_systimer_irq = {
>> + ? ? .name ? ? ? ? ? = "System timer",
>> + ? ? .flags ? ? ? ? ?= IRQF_DISABLED ,
>> + ? ? .handler ? ? ? ?= s5pc11x_sched_timer_interrupt,
>> +};
>> +
>> +
>> +static cycle_t s5pc11x_sched_timer_read(void)
>> +{
>> + ? ? return (cycle_t)~__raw_readl(S3C_SYSTIMER_TCNTO);
>> +}
>> +
>> +struct clocksource clocksource_s5pc11x = {
>> + ? ? .name ? ? ? ? ? = "clock_source_systimer",
>> + ? ? .rating ? ? ? ? = 300,
>> + ? ? .read ? ? ? ? ? = s5pc11x_sched_timer_read,
>> + ? ? .mask ? ? ? ? ? = CLOCKSOURCE_MASK(32),
>> + ? ? .shift ? ? ? ? ?= 20,
>> + ? ? .flags ? ? ? ? ?= CLOCK_SOURCE_IS_CONTINUOUS,
>> +};
>> +
>> +static void s5pc11x_init_clocksource(unsigned long rate)
>> +{
>> + ? ? static char err[] __initdata = KERN_ERR
>> + ? ? ? ? ? ? ? ? ? ? "%s: can't register clocksource!\n";
>> +
>> + ? ? clocksource_s5pc11x.mult
>> + ? ? ? ? ? ? = clocksource_khz2mult(rate/1000,
> clocksource_s5pc11x.shift);
>> +
>> +
>> + ? ? s5pc11x_sched_timer_start(~0, 1);
>> +
>> + ? ? if (clocksource_register(&clocksource_s5pc11x))
>> + ? ? ? ? ? ? printk(err, clocksource_s5pc11x.name);
>> +}
>> +
>> +/*
>> + * Returns current time from boot in nsecs. It's OK for this to wrap
>> + * around for now, as it's just a relative time stamp.
>> + */
>> +unsigned long long sched_clock(void)
>> +{
>> + ? ? unsigned long irq_flags;
>> + ? ? cycle_t ticks, elapsed_ticks = 0;
>> + ? ? unsigned long long increment = 0;
>> + ? ? unsigned int overflow_cnt = 0;
>> +
>> + ? ? local_irq_save(irq_flags);
>> +
>> + ? ? if (likely(sched_timer_running)) {
>> + ? ? ? ? ? ? overflow_cnt = (s5pc11x_sched_timer_overflows -
>> old_overflows);
>> +
>> + ? ? ? ? ? ? ticks = s5pc11x_sched_timer_read();
>> +
>> + ? ? ? ? ? ? if (overflow_cnt) {
>> + ? ? ? ? ? ? ? ? ? ? increment = (overflow_cnt - 1) *
>> +
>> ? ? ? (clocksource_cyc2ns(clocksource_s5pc11x.mask,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? clocksource_s5pc11x.mult,
>> clocksource_s5pc11x.shift));
>> + ? ? ? ? ? ? ? ? ? ? elapsed_ticks = (clocksource_s5pc11x.mask -
> last_ticks)
>> + ticks;
>> + ? ? ? ? ? ? } else {
>> + ? ? ? ? ? ? ? ? ? ? if (unlikely(last_ticks > ticks)) {
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? pending_irq = 1;
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? elapsed_ticks = (clocksource_s5pc11x.mask -
>> last_ticks) + ticks;
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? s5pc11x_sched_timer_overflows++;
>> + ? ? ? ? ? ? ? ? ? ? } else {
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? elapsed_ticks = (ticks - last_ticks);
>> + ? ? ? ? ? ? ? ? ? ? }
>> + ? ? ? ? ? ? }
>> +
>> + ? ? ? ? ? ? time_stamp += (clocksource_cyc2ns(elapsed_ticks,
>> clocksource_s5pc11x.mult, clocksource_s5pc11x.shift) + increment);
>> +
>> + ? ? ? ? ? ? old_overflows = s5pc11x_sched_timer_overflows;
>> + ? ? ? ? ? ? last_ticks = ticks;
>> + ? ? }
>> + ? ? local_irq_restore(irq_flags);
>> +
>> + ? ? return time_stamp;
>> +}
>> +
>> +/*
>> + * ?Event/Sched Timer initialization
>> + */
>> +static void s5pc11x_timer_setup(void)
>> +{
>> + ? ? unsigned long rate;
>> + ? ? /* Setup event timer using XrtcXTI */
>> + ? ? if (clk_event == NULL)
>> + ? ? ? ? ? ? clk_event = clk_get(NULL, "XrtcXTI");
>> + ? ? if (IS_ERR(clk_event))
>> + ? ? ? ? ? ? panic("failed to get clock for event timer");
>> + ? ? rate = clk_get_rate(clk_event);
>> + ? ? s5pc11x_init_dynamic_tick_timer(rate);
>> +
>> + ? ? /* Setup sched-timer using XusbXTI */
>> + ? ? if (clk_sched == NULL)
>> + ? ? ? ? ? ? clk_sched = clk_get(NULL, "XusbXTI");
>> + ? ? if (IS_ERR(clk_sched))
>> + ? ? ? ? ? ? panic("failed to get clock for sched-timer");
>> + ? ? rate = clk_get_rate(clk_sched);
>> + ? ? s5pc11x_init_clocksource(rate);
>> +}
>> +
>> +static void s5pc11x_tick_timer_setup(void)
>> +{
>> + ? ? unsigned long rate;
>> +
>> + ? ? rate = clk_get_rate(clk_event);
>> + ? ? s5pc11x_tick_timer_start((rate / HZ) - 1, 1);
>> +}
>> +
>> +static void __init s5pc11x_timer_init(void)
>> +{
>> + ? ? /* Initialize variables before starting each timers */
>> + ? ? last_ticks = 0;
>> + ? ? s5pc11x_sched_timer_overflows = 0;
>> + ? ? old_overflows = 0;
>> + ? ? time_stamp = 0;
>> + ? ? sched_timer_running = 0;
>> + ? ? pending_irq = 0;
>> + ? ? s5pc11x_timer_setup();
>> + ? ? setup_irq(IRQ_RTC_TIC, &s5pc11x_tick_timer_irq);
>> + ? ? setup_irq(IRQ_SYSTIMER, &s5pc11x_systimer_irq);
>> +}
>> +
>> +
>> +struct sys_timer s3c24xx_timer = {
>> + ? ? .init ? ? ? ? ? = s5pc11x_timer_init,
>> +};
>> +
>> diff --git a/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
> b/arch/arm/plat-
>> s5p/include/plat/regs-sys-timer.h
>> new file mode 100644
>> index 0000000..75e6267
>> --- /dev/null
>> +++ b/arch/arm/plat-s5p/include/plat/regs-sys-timer.h
>> @@ -0,0 +1,63 @@
>> +/* arch/arm/plat-s5pc1xx/include/plat/regs-sys-timer.h
>> + *
>> + * Copyright (c) 2008 Samsung Electronics
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * S5PC1XX System Timer configuration
>> +*/
>> +
>> +#ifndef __ASM_ARCH_REGS_SYS_TIMER_H
>> +#define __ASM_ARCH_REGS_SYS_TIMER_H
>> +
>> +#define S3C_SYSTIMERREG(x) ? ? ? ? ? (S5P_VA_SYSTIMER + (x))
>> +
>> +#define S3C_SYSTIMER_TCFG ? ? ? ? ? ?S3C_SYSTIMERREG(0x00)
>> +#define S3C_SYSTIMER_TCON ? ? ? ? ? ?S3C_SYSTIMERREG(0x04)
>> +#define S3C_SYSTIMER_TCNTB ? ? ? ? ? S3C_SYSTIMERREG(0x08)
>> +#define S3C_SYSTIMER_TCNTO ? ? ? ? ? S3C_SYSTIMERREG(0x0c)
>> +
>> +#define S3C_SYSTIMER_TFCNTB ? ? ? ? ?S3C_SYSTIMERREG(0x10)
>> +#define S3C_SYSTIMER_ICNTB ? ? ? ? ? S3C_SYSTIMERREG(0x18)
>> +#define S3C_SYSTIMER_ICNTO ? ? ? ? ? S3C_SYSTIMERREG(0x1c)
>> +#define S3C_SYSTIMER_INT_CSTAT ? ? ? S3C_SYSTIMERREG(0x20)
>> +
>> +/* Value for TCFG */
>> +#define S3C_SYSTIMER_TCLK_MASK ? ? ? ? ? ? ? (3<<12)
>> +#define S3C_SYSTIMER_TCLK_XXTI ? ? ? ? ? ? ? (0<<12)
>> +#define S3C_SYSTIMER_TCLK_RTC ? ? ? ? ? ? ? ?(1<<12)
>> +#define S3C_SYSTIMER_TCLK_USB ? ? ? ? ? ? ? ?(2<<12)
>> +#define S3C_SYSTIMER_TCLK_PCLK ? ? ? ? ? ? ? (3<<12)
>> +
>> +#define S3C_SYSTIMER_DIV_MASK ? ? ? ? ? ? ? ?(7<<8)
>> +#define S3C_SYSTIMER_DIV_1 ? ? ? ? ? (0<<8)
>> +#define S3C_SYSTIMER_DIV_2 ? ? ? ? ? (1<<8)
>> +#define S3C_SYSTIMER_DIV_4 ? ? ? ? ? (2<<8)
>> +#define S3C_SYSTIMER_DIV_8 ? ? ? ? ? (3<<8)
>> +#define S3C_SYSTIMER_DIV_16 ? ? ? ? ?(4<<8)
>> +
>> +#define S3C_SYSTIMER_TARGET_HZ ? ? ? ? ? ? ? 200
>> +#define S3C_SYSTIMER_PRESCALER ? ? ? ? ? ? ? 5
>> +#define S3C_SYSTIMER_PRESCALER_MASK ?(0x3f<<0)
>> +
>> +/* value for TCON */
>> +#define S3C_SYSTIMER_INT_AUTO ? ? ? ? ? ? ? ?(1<<5)
>> +#define S3C_SYSTIMER_INT_IMM ? ? ? ? (1<<4)
>> +#define S3C_SYSTIMER_INT_START ? ? ? ? ? ? ? (1<<3)
>> +#define S3C_SYSTIMER_AUTO_RELOAD ? ? (1<<2)
>> +#define S3C_SYSTIMER_IMM_UPDATE ? ? ? ? ? ? ?(1<<1)
>> +#define S3C_SYSTIMER_START ? ? ? ? ? (1<<0)
>> +
>> +/* Value for INT_CSTAT */
>> +#define S3C_SYSTIMER_INT_IWIE ? ? ? ? ? ? ? ?(1<<9)
>> +#define S3C_SYSTIMER_INT_TWIE ? ? ? ? ? ? ? ?(1<<10)
>> +#define S3C_SYSTIMER_INT_ICNTEIE ? ? (1<<6)
>> +#define S3C_SYSTIMER_INT_TCON ? ? ? ? ? ? ? ?(1<<5)
>> +#define S3C_SYSTIMER_INT_ICNTB ? ? ? ? ? ? ? (1<<4)
>> +#define S3C_SYSTIMER_INT_TCNTB ? ? ? ? ? ? ? (1<<2)
>> +#define S3C_SYSTIMER_INT_STATS ? ? ? ? ? ? ? (1<<1)
>> +#define S3C_SYSTIMER_INT_EN ? ? ? ? ?(1<<0)
>> +
>> +#endif /* ?__ASM_ARCH_REGS_TIMER_H */
>> diff --git a/arch/arm/plat-samsung/include/plat/map-base.h
> b/arch/arm/plat-
>> samsung/include/plat/map-base.h
>> index 250be31..ff766d9 100644
>> --- a/arch/arm/plat-samsung/include/plat/map-base.h
>> +++ b/arch/arm/plat-samsung/include/plat/map-base.h
>> @@ -36,6 +36,8 @@
>> ?#define S3C_VA_TIMER S3C_ADDR(0x00300000) ? ?/* timer block */
>> ?#define S3C_VA_WATCHDOG ? ? ?S3C_ADDR(0x00400000) ? ?/* watchdog */
>> ?#define S3C_VA_UART ?S3C_ADDR(0x01000000) ? ?/* UART */
>> +/*For RTC*/
>> +#define S3C_VA_RTC ? S3C_ADDR(0x00c00000)
>>
>> ?/* This is used for the CPU specific mappings that may be needed, so that
>> ? * they do not need to directly used S3C_ADDR() and thus make it easier
> to
>> --
>> 1.6.0.4
>>
>
>
> Thanks.
>
> Best regards,
> Kgene.
> --
> Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

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

* [PATCH]HRT support in Samsung S5P Platform
  2010-07-19  6:54 MADHAV SINGHCHAUHAN
  2010-07-21  0:36 ` Ben Dooks
  2010-07-21 12:06 ` Kukjin Kim
@ 2010-07-22  7:55 ` Russell King - ARM Linux
  2 siblings, 0 replies; 7+ messages in thread
From: Russell King - ARM Linux @ 2010-07-22  7:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 19, 2010 at 06:54:13AM +0000, MADHAV SINGHCHAUHAN wrote:
> +config MACH_S5PV210_HRT
> +        bool "HRtimer and Dynamic Tick support"
> +        select GENERIC_TIME
> +        select GENERIC_CLOCKEVENTS
> +        select HIGH_RES_TIMERS
> +        default n

Please avoid 'default n'.

> +static unsigned int sched_timer_running;
> +
> +void __iomem *rtc_base =	S3C_VA_RTC;

static?

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

* [PATCH]HRT support in Samsung S5P Platform
  2010-07-22  6:10   ` Kyungmin Park
@ 2010-07-23  2:48     ` Jassi Brar
  0 siblings, 0 replies; 7+ messages in thread
From: Jassi Brar @ 2010-07-23  2:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jul 22, 2010 at 3:10 PM, Kyungmin Park
<kyungmin.park@samsung.com> wrote:
> On Wed, Jul 21, 2010 at 9:06 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
>> MADHAV SINGHCHAUHAN wrote:
>>>
>>> From: Madhav Singh <singh.madhav@samsung.com>
>>> Date: Mon, 19 Jul 2010 10:51:01 +0530
>>> Subject: [PATCH] HRT support in Samsung Tree
>>> This patch implements HRT support for Samsung plat-s5p.
>>> RTC has been used as CLOCKEVENT and SYSTIMER as CLOCKSOURCE.
>>>
>>> Signed-off-by: Madhav Chauhan <singh.madhav@samsung.com>
>>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>>
>> Hi,
>>
>> I'd like to say to MADHAV and Kyungmin....
>>
>> Actually, your patch(code) is same with my team's code in
>> git(git.kernel.org, kki_ap, 2.6.29-samsung,
>> arch/arm/plat-s5pc11x/hr-time-rtc.c)
>> But I couldn't find any credits or comments about that.
>>
>> If you copy some code from somewhere, please add credits and comments about
>> that.
>> It's very important.
>
> Right, it's my mistake can't check it. Madhav will add the credit and
> describe the original author.
> I talked to Mr. Lee jaechul and get the permission to send the patch.
>
> To Madhav,
>
> Next time, Add the From: Jaechul Lee at commit message and signed-off-by.
Actually it should be mentioned in the credits in source code itself
if this submission
is not much more than cleanup and polish.

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

end of thread, other threads:[~2010-07-23  2:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-21 11:54 [PATCH]HRT support in Samsung S5P Platform MADHAV SINGHCHAUHAN
  -- strict thread matches above, loose matches on Subject: below --
2010-07-19  6:54 MADHAV SINGHCHAUHAN
2010-07-21  0:36 ` Ben Dooks
2010-07-21 12:06 ` Kukjin Kim
2010-07-22  6:10   ` Kyungmin Park
2010-07-23  2:48     ` Jassi Brar
2010-07-22  7:55 ` Russell King - ARM Linux

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).