summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/timer-t3.c
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@nvidia.com>2011-06-13 18:42:28 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:46:45 -0800
commitadf27214e7c5b669adda02dfc1a483b48f876008 (patch)
tree8ac225d3f6598a0b877cf44e9d44040968a94d81 /arch/arm/mach-tegra/timer-t3.c
parent3c152b307286a4a32d2daeb3ca5e2caed646f795 (diff)
HACKY: timer-t3 updates for K39
Rebase-Id: Re2ca6bafa842d114859a40c7ab19097fd86fc635
Diffstat (limited to 'arch/arm/mach-tegra/timer-t3.c')
-rw-r--r--arch/arm/mach-tegra/timer-t3.c112
1 files changed, 79 insertions, 33 deletions
diff --git a/arch/arm/mach-tegra/timer-t3.c b/arch/arm/mach-tegra/timer-t3.c
index 629438869bf7..18f68649777e 100644
--- a/arch/arm/mach-tegra/timer-t3.c
+++ b/arch/arm/mach-tegra/timer-t3.c
@@ -19,6 +19,8 @@
*/
#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/sched.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -26,19 +28,18 @@
#include <linux/clocksource.h>
#include <linux/clk.h>
#include <linux/io.h>
-#include <linux/cnt32_to_63.h>
#include <linux/smp.h>
+#include <linux/syscore_ops.h>
#include <asm/mach/time.h>
-#include <asm/mach/time.h>
#include <asm/localtimer.h>
+#include <asm/sched_clock.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
#include "board.h"
#include "clock.h"
-#include "pm.h"
/*
* Timers usage:
@@ -75,15 +76,16 @@
static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE);
static void __iomem *rtc_base = IO_ADDRESS(TEGRA_RTC_BASE);
+static struct timespec persistent_ts;
+static u64 persistent_ms, last_persistent_ms;
+static u32 usec_offset;
+static bool usec_suspended;
+
#define timer_writel(value, reg) \
__raw_writel(value, (u32)timer_reg_base + (reg))
#define timer_readl(reg) \
__raw_readl((u32)timer_reg_base + (reg))
-static u64 tegra_sched_clock_offset;
-static u64 tegra_sched_clock_suspend_val;
-static u64 tegra_sched_clock_suspend_rtc;
-
static int tegra_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
@@ -137,24 +139,33 @@ static struct clocksource tegra_clocksource = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-unsigned long long sched_clock(void)
+static DEFINE_CLOCK_DATA(cd);
+
+/* TODO: is this right for Tegra3?
+ * Constants generated by clocks_calc_mult_shift(m, s, 1MHz, NSEC_PER_SEC, 60).
+ * This gives a resolution of about 1us and a wrap period of about 1h11min.
+ */
+#define SC_MULT 4194304000u
+#define SC_SHIFT 22
+
+static u32 notrace tegra_read_usec(void)
{
- return tegra_sched_clock_offset +
- cnt32_to_63(timer_readl(TIMERUS_CNTR_1US)) * NSEC_PER_USEC;
+ u32 cyc = usec_offset;
+ if (!usec_suspended)
+ cyc += timer_readl(TIMERUS_CNTR_1US);
+ return cyc;
}
-static void tegra_sched_clock_suspend(void)
+unsigned long long notrace sched_clock(void)
{
- tegra_sched_clock_suspend_val = sched_clock();
- tegra_sched_clock_suspend_rtc = tegra_rtc_read_ms();
+ u32 cyc = tegra_read_usec();
+ return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
}
-static void tegra_sched_clock_resume(void)
+static void notrace tegra_update_sched_clock(void)
{
- u64 rtc_offset_ms = tegra_rtc_read_ms() - tegra_sched_clock_suspend_rtc;
- tegra_sched_clock_offset = tegra_sched_clock_suspend_val +
- rtc_offset_ms * NSEC_PER_MSEC -
- (sched_clock() - tegra_sched_clock_offset);
+ u32 cyc = tegra_read_usec();
+ update_sched_clock(&cd, cyc, (u32)~0);
}
/*
@@ -180,8 +191,6 @@ u64 tegra_rtc_read_ms(void)
* tegra_rtc driver could be executing to avoid race conditions
* on the RTC shadow register
*/
-static struct timespec persistent_ts;
-static u64 persistent_ms, last_persistent_ms;
void read_persistent_clock(struct timespec *ts)
{
u64 delta;
@@ -211,6 +220,32 @@ static struct irqaction tegra_timer_irq = {
.irq = INT_TMR1,
};
+static u32 usec_config;
+
+static int tegra_timer_suspend(void)
+{
+ usec_config = timer_readl(TIMERUS_USEC_CFG);
+
+ usec_offset += timer_readl(TIMERUS_CNTR_1US);
+ usec_suspended = true;
+
+ return 0;
+}
+
+static void tegra_timer_resume(void)
+{
+ timer_writel(usec_config, TIMERUS_USEC_CFG);
+
+ usec_offset -= timer_readl(TIMERUS_CNTR_1US);
+ usec_suspended = false;
+}
+
+static struct syscore_ops tegra_timer_syscore_ops = {
+ .suspend = tegra_timer_suspend,
+ .resume = tegra_timer_resume,
+};
+
+#if 0
static int lp2_wake_timers[] = {
TIMER3_OFFSET,
TIMER4_OFFSET,
@@ -292,14 +327,28 @@ static void test_lp2_wake_timers(void)
#else
static void test_lp2_wake_timers(void){}
#endif
+#endif
static void __init tegra_init_timer(void)
{
+ struct clk *clk;
unsigned long rate = clk_measure_input_freq();
void __iomem *chip_id = IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804;
unsigned long id;
int ret;
+ clk = clk_get_sys("timer", NULL);
+ BUG_ON(IS_ERR(clk));
+ clk_enable(clk);
+
+ /*
+ * rtc registers are used by read_persistent_clock, keep the rtc clock
+ * enabled
+ */
+ clk = clk_get_sys("rtc-tegra", NULL);
+ BUG_ON(IS_ERR(clk));
+ clk_enable(clk);
+
#ifdef CONFIG_HAVE_ARM_TWD
twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600);
#endif
@@ -330,6 +379,9 @@ static void __init tegra_init_timer(void)
WARN(1, "Unknown clock rate");
}
+ init_fixed_sched_clock(&cd, tegra_update_sched_clock, 32,
+ 1000000, SC_MULT, SC_SHIFT);
+
if (clocksource_register_hz(&tegra_clocksource, 1000000)) {
printk(KERN_ERR "Failed to register clocksource\n");
BUG();
@@ -341,6 +393,7 @@ static void __init tegra_init_timer(void)
BUG();
}
+#if 0
/* For T30.A01 use INT_TMR_SHARED instead of INT_TMR6. */
id = readl(chip_id);
if (((id & 0xFF00) >> 8) == 0x30) {
@@ -360,6 +413,7 @@ static void __init tegra_init_timer(void)
}
REGISTER_LP2_WAKE_IRQS();
+#endif
clockevents_calc_mult_shift(&tegra_clockevent, 1000000, 5);
tegra_clockevent.max_delta_ns =
@@ -370,7 +424,10 @@ static void __init tegra_init_timer(void)
tegra_clockevent.irq = tegra_timer_irq.irq;
clockevents_register_device(&tegra_clockevent);
+ register_syscore_ops(&tegra_timer_syscore_ops);
+#if 0
test_lp2_wake_timers();
+#endif
return;
}
@@ -378,6 +435,7 @@ struct sys_timer tegra_timer = {
.init = tegra_init_timer,
};
+#if 0
#ifdef CONFIG_SMP
#define hard_smp_processor_id() \
({ \
@@ -418,16 +476,4 @@ unsigned long tegra_lp2_timer_remain(void)
timer_base = lp2_wake_timers[cpu];
return timer_readl(timer_base + TIMER_PCR) & 0x1ffffffful;
}
-
-static u32 usec_config;
-void tegra_timer_suspend(void)
-{
- tegra_sched_clock_suspend();
- usec_config = timer_readl(TIMERUS_USEC_CFG);
-}
-
-void tegra_timer_resume(void)
-{
- timer_writel(usec_config, TIMERUS_USEC_CFG);
- tegra_sched_clock_resume();
-}
+#endif