aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-nomadik
diff options
context:
space:
mode:
authorSrinidhi Kasagar <srinidhi.kasagar@stericsson.com>2009-11-12 00:20:54 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-11-28 05:22:51 -0500
commit59b559d7a39b590aecef583af58d123ff5876570 (patch)
tree5e5f17bea4e3eb0295e6d85dc72334f23bbc9338 /arch/arm/plat-nomadik
parenta8a8a669ea13d792296737505adc43ccacf3a648 (diff)
ARM: 5786/1: Introduce plat-nomadik, MTU code re-organization
Introduce the plat-nomadik folder for ST-Ericsson machines including the existing nomadik 8815 architecture. This also moves the existing MTU (MultiTimerUnit) of nomadik 8815 to the proposed plat-nomadik and adds HAS_MTU. The patch has been re-based to 2.6.32-rc6 Signed-off-by: srinidhi kasagar <srinidhi.kasagar@stericsson.com> Acked-by: Alessandro Rubini <rubini@unipv.it> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-nomadik')
-rw-r--r--arch/arm/plat-nomadik/Kconfig22
-rw-r--r--arch/arm/plat-nomadik/Makefile5
-rw-r--r--arch/arm/plat-nomadik/include/plat/mtu.h48
-rw-r--r--arch/arm/plat-nomadik/timer.c147
4 files changed, 222 insertions, 0 deletions
diff --git a/arch/arm/plat-nomadik/Kconfig b/arch/arm/plat-nomadik/Kconfig
new file mode 100644
index 000000000000..e27ee3134056
--- /dev/null
+++ b/arch/arm/plat-nomadik/Kconfig
@@ -0,0 +1,22 @@
1# We keep common IP's here for Nomadik and other similar
2# familiy of processors from ST-Ericsson. At the moment we have
3# just MTU, others to follow soon.
4
5config PLAT_NOMADIK
6 bool
7 depends on ARCH_NOMADIK
8 default y
9 help
10 Common platform code for Nomadik and other ST-Ericsson
11 platforms.
12
13if PLAT_NOMADIK
14
15config HAS_MTU
16 bool
17 help
18 Support for Multi Timer Unit. MTU provides access
19 to multiple interrupt generating programmable
20 32-bit free running decrementing counters.
21
22endif
diff --git a/arch/arm/plat-nomadik/Makefile b/arch/arm/plat-nomadik/Makefile
new file mode 100644
index 000000000000..37c7cdd0f8f0
--- /dev/null
+++ b/arch/arm/plat-nomadik/Makefile
@@ -0,0 +1,5 @@
1# arch/arm/plat-nomadik/Makefile
2# Copyright 2009 ST-Ericsson
3# Licensed under GPLv2
4
5obj-$(CONFIG_HAS_MTU) += timer.o
diff --git a/arch/arm/plat-nomadik/include/plat/mtu.h b/arch/arm/plat-nomadik/include/plat/mtu.h
new file mode 100644
index 000000000000..42c907258b14
--- /dev/null
+++ b/arch/arm/plat-nomadik/include/plat/mtu.h
@@ -0,0 +1,48 @@
1#ifndef __PLAT_MTU_H
2#define __PLAT_MTU_H
3
4/* should be set by the platform code */
5extern void __iomem *mtu_base;
6
7/*
8 * The MTU device hosts four different counters, with 4 set of
9 * registers. These are register names.
10 */
11
12#define MTU_IMSC 0x00 /* Interrupt mask set/clear */
13#define MTU_RIS 0x04 /* Raw interrupt status */
14#define MTU_MIS 0x08 /* Masked interrupt status */
15#define MTU_ICR 0x0C /* Interrupt clear register */
16
17/* per-timer registers take 0..3 as argument */
18#define MTU_LR(x) (0x10 + 0x10 * (x) + 0x00) /* Load value */
19#define MTU_VAL(x) (0x10 + 0x10 * (x) + 0x04) /* Current value */
20#define MTU_CR(x) (0x10 + 0x10 * (x) + 0x08) /* Control reg */
21#define MTU_BGLR(x) (0x10 + 0x10 * (x) + 0x0c) /* At next overflow */
22
23/* bits for the control register */
24#define MTU_CRn_ENA 0x80
25#define MTU_CRn_PERIODIC 0x40 /* if 0 = free-running */
26#define MTU_CRn_PRESCALE_MASK 0x0c
27#define MTU_CRn_PRESCALE_1 0x00
28#define MTU_CRn_PRESCALE_16 0x04
29#define MTU_CRn_PRESCALE_256 0x08
30#define MTU_CRn_32BITS 0x02
31#define MTU_CRn_ONESHOT 0x01 /* if 0 = wraps reloading from BGLR*/
32
33/* Other registers are usual amba/primecell registers, currently not used */
34#define MTU_ITCR 0xff0
35#define MTU_ITOP 0xff4
36
37#define MTU_PERIPH_ID0 0xfe0
38#define MTU_PERIPH_ID1 0xfe4
39#define MTU_PERIPH_ID2 0xfe8
40#define MTU_PERIPH_ID3 0xfeC
41
42#define MTU_PCELL0 0xff0
43#define MTU_PCELL1 0xff4
44#define MTU_PCELL2 0xff8
45#define MTU_PCELL3 0xffC
46
47#endif /* __PLAT_MTU_H */
48
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
new file mode 100644
index 000000000000..62f18ad43a28
--- /dev/null
+++ b/arch/arm/plat-nomadik/timer.c
@@ -0,0 +1,147 @@
1/*
2 * linux/arch/arm/mach-nomadik/timer.c
3 *
4 * Copyright (C) 2008 STMicroelectronics
5 * Copyright (C) 2009 Alessandro Rubini, somewhat based on at91sam926x
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2, as
9 * published by the Free Software Foundation.
10 */
11#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/irq.h>
14#include <linux/io.h>
15#include <linux/clockchips.h>
16#include <linux/jiffies.h>
17#include <asm/mach/time.h>
18
19#include <plat/mtu.h>
20
21static u32 nmdk_count; /* accumulated count */
22static u32 nmdk_cycle; /* write-once */
23
24/* setup by the platform code */
25void __iomem *mtu_base;
26
27/*
28 * clocksource: the MTU device is a decrementing counters, so we negate
29 * the value being read.
30 */
31static cycle_t nmdk_read_timer(struct clocksource *cs)
32{
33 u32 count = readl(mtu_base + MTU_VAL(0));
34 return nmdk_count + nmdk_cycle - count;
35
36}
37
38static struct clocksource nmdk_clksrc = {
39 .name = "mtu_0",
40 .rating = 120,
41 .read = nmdk_read_timer,
42 .shift = 20,
43 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
44};
45
46/*
47 * Clockevent device: currently only periodic mode is supported
48 */
49static void nmdk_clkevt_mode(enum clock_event_mode mode,
50 struct clock_event_device *dev)
51{
52 unsigned long flags;
53
54 switch (mode) {
55 case CLOCK_EVT_MODE_PERIODIC:
56 /* enable interrupts -- and count current value? */
57 raw_local_irq_save(flags);
58 writel(readl(mtu_base + MTU_IMSC) | 1, mtu_base + MTU_IMSC);
59 raw_local_irq_restore(flags);
60 break;
61 case CLOCK_EVT_MODE_ONESHOT:
62 BUG(); /* Not supported, yet */
63 /* FALLTHROUGH */
64 case CLOCK_EVT_MODE_SHUTDOWN:
65 case CLOCK_EVT_MODE_UNUSED:
66 /* disable irq */
67 raw_local_irq_save(flags);
68 writel(readl(mtu_base + MTU_IMSC) & ~1, mtu_base + MTU_IMSC);
69 raw_local_irq_restore(flags);
70 break;
71 case CLOCK_EVT_MODE_RESUME:
72 break;
73 }
74}
75
76static struct clock_event_device nmdk_clkevt = {
77 .name = "mtu_0",
78 .features = CLOCK_EVT_FEAT_PERIODIC,
79 .shift = 32,
80 .rating = 100,
81 .set_mode = nmdk_clkevt_mode,
82};
83
84/*
85 * IRQ Handler for the timer 0 of the MTU block. The irq is not shared
86 * as we are the only users of mtu0 by now.
87 */
88static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
89{
90 /* ack: "interrupt clear register" */
91 writel(1 << 0, mtu_base + MTU_ICR);
92
93 /* we can't count lost ticks, unfortunately */
94 nmdk_count += nmdk_cycle;
95 nmdk_clkevt.event_handler(&nmdk_clkevt);
96
97 return IRQ_HANDLED;
98}
99
100/*
101 * Set up timer interrupt, and return the current time in seconds.
102 */
103static struct irqaction nmdk_timer_irq = {
104 .name = "Nomadik Timer Tick",
105 .flags = IRQF_DISABLED | IRQF_TIMER,
106 .handler = nmdk_timer_interrupt,
107};
108
109static void nmdk_timer_reset(void)
110{
111 u32 cr;
112
113 writel(0, mtu_base + MTU_CR(0)); /* off */
114
115 /* configure load and background-load, and fire it up */
116 writel(nmdk_cycle, mtu_base + MTU_LR(0));
117 writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
118 cr = MTU_CRn_PERIODIC | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS;
119 writel(cr, mtu_base + MTU_CR(0));
120 writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
121}
122
123void __init nmdk_timer_init(void)
124{
125 unsigned long rate;
126 int bits;
127
128 rate = CLOCK_TICK_RATE; /* 2.4MHz */
129 nmdk_cycle = (rate + HZ/2) / HZ;
130
131 /* Init the timer and register clocksource */
132 nmdk_timer_reset();
133
134 nmdk_clksrc.mult = clocksource_hz2mult(rate, nmdk_clksrc.shift);
135 bits = 8*sizeof(nmdk_count);
136 nmdk_clksrc.mask = CLOCKSOURCE_MASK(bits);
137
138 if (clocksource_register(&nmdk_clksrc))
139 printk(KERN_ERR "timer: failed to initialize clock "
140 "source %s\n", nmdk_clksrc.name);
141
142 /* Register irq and clockevents */
143 setup_irq(IRQ_MTU0, &nmdk_timer_irq);
144 nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
145 nmdk_clkevt.cpumask = cpumask_of(0);
146 clockevents_register_device(&nmdk_clkevt);
147}