summaryrefslogtreecommitdiffstats
path: root/target/linux/cns3xxx/patches-3.3/102-cns3xxx_timers.patch
blob: c8e9be3e4b03d69c5c1a6654f268ba71ac7d7ab1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
--- a/arch/arm/mach-cns3xxx/core.c
+++ b/arch/arm/mach-cns3xxx/core.c
@@ -115,12 +115,13 @@ static void cns3xxx_timer_set_mode(enum
 
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
-		reload = pclk * 20 / (3 * HZ) * 0x25000;
+		reload = pclk * 1000000 / HZ;
 		writel(reload, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
 		ctrl |= (1 << 0) | (1 << 2) | (1 << 9);
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
 		/* period set, and timer enabled in 'next_event' hook */
+		writel(0, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
 		ctrl |= (1 << 2) | (1 << 9);
 		break;
 	case CLOCK_EVT_MODE_UNUSED:
@@ -145,11 +146,11 @@ static int cns3xxx_timer_set_next_event(
 
 static struct clock_event_device cns3xxx_tmr1_clockevent = {
 	.name		= "cns3xxx timer1",
-	.shift		= 8,
+	.shift		= 32,
 	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 	.set_mode	= cns3xxx_timer_set_mode,
 	.set_next_event	= cns3xxx_timer_set_next_event,
-	.rating		= 350,
+	.rating		= 300,
 	.cpumask	= cpu_all_mask,
 };
 
@@ -191,6 +192,35 @@ static struct irqaction cns3xxx_timer_ir
 	.handler	= cns3xxx_timer_interrupt,
 };
 
+static cycle_t cns3xxx_get_cycles(struct clocksource *cs)
+{
+  u64 val;
+
+  val = readl(cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
+  val &= 0xffff;
+
+  return ((val << 32) | readl(cns3xxx_tmr1 + TIMER_FREERUN_OFFSET));
+}
+
+static struct clocksource clocksource_cns3xxx = {
+	.name = "freerun",
+	.rating = 200,
+	.read = cns3xxx_get_cycles,
+	.mask = CLOCKSOURCE_MASK(48),
+	.shift  = 16,
+	.flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init cns3xxx_clocksource_init(void)
+{
+	/* Reset the FreeRunning counter */
+	writel((1 << 16), cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
+
+	clocksource_cns3xxx.mult =
+		clocksource_khz2mult(100, clocksource_cns3xxx.shift);
+	clocksource_register(&clocksource_cns3xxx);
+}
+
 /*
  * Set up the clock source and clock events devices
  */
@@ -208,13 +238,12 @@ static void __init __cns3xxx_timer_init(
 	/* stop free running timer3 */
 	writel(0, cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
 
-	/* timer1 */
-	writel(0x5C800, cns3xxx_tmr1 + TIMER1_COUNTER_OFFSET);
-	writel(0x5C800, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
-
 	writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V1_OFFSET);
 	writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V2_OFFSET);
 
+	val = (cns3xxx_cpu_clock() >> 3) * 1000000 / HZ;
+	writel(val, cns3xxx_tmr1 + TIMER1_COUNTER_OFFSET);
+
 	/* mask irq, non-mask timer1 overflow */
 	irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
 	irq_mask &= ~(1 << 2);
@@ -226,23 +255,9 @@ static void __init __cns3xxx_timer_init(
 	val |= (1 << 9);
 	writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
 
-	/* timer2 */
-	writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V1_OFFSET);
-	writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V2_OFFSET);
-
-	/* mask irq */
-	irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
-	irq_mask |= ((1 << 3) | (1 << 4) | (1 << 5));
-	writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
-
-	/* down counter */
-	val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
-	val |= (1 << 10);
-	writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
-
-	/* Make irqs happen for the system timer */
 	setup_irq(timer_irq, &cns3xxx_timer_irq);
 
+	cns3xxx_clocksource_init();
 	cns3xxx_clockevents_init(timer_irq);
 }