diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-23 13:34:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-23 13:34:47 -0400 |
commit | 9d0715630ebf7bf70daa5e6d8db0e3061268c61e (patch) | |
tree | 54562185002b22169d81e0fb3c21312cb510ac40 | |
parent | c0c463d34adf0c150e5e24fa412fa23f3f7ddc27 (diff) | |
parent | 06c3df49521c1b112b777cc4946e5de057c814ba (diff) |
Merge branch 'timers-clocksource-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-clocksource-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
clocksource: apb: Share APB timer code with other platforms
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/apb_timer.h | 22 | ||||
-rw-r--r-- | arch/x86/kernel/apb_timer.c | 409 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 3 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
-rw-r--r-- | drivers/clocksource/dw_apb_timer.c | 401 | ||||
-rw-r--r-- | include/linux/dw_apb_timer.h | 56 |
7 files changed, 533 insertions, 360 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5f60ea190d5b..c3e03e46bc64 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -623,6 +623,7 @@ config HPET_EMULATE_RTC | |||
623 | config APB_TIMER | 623 | config APB_TIMER |
624 | def_bool y if MRST | 624 | def_bool y if MRST |
625 | prompt "Langwell APB Timer Support" if X86_MRST | 625 | prompt "Langwell APB Timer Support" if X86_MRST |
626 | select DW_APB_TIMER | ||
626 | help | 627 | help |
627 | APB timer is the replacement for 8254, HPET on X86 MID platforms. | 628 | APB timer is the replacement for 8254, HPET on X86 MID platforms. |
628 | The APBT provides a stable time base on SMP | 629 | The APBT provides a stable time base on SMP |
diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h index 082cf8184935..0acbac299e49 100644 --- a/arch/x86/include/asm/apb_timer.h +++ b/arch/x86/include/asm/apb_timer.h | |||
@@ -18,24 +18,6 @@ | |||
18 | 18 | ||
19 | #ifdef CONFIG_APB_TIMER | 19 | #ifdef CONFIG_APB_TIMER |
20 | 20 | ||
21 | /* Langwell DW APB timer registers */ | ||
22 | #define APBTMR_N_LOAD_COUNT 0x00 | ||
23 | #define APBTMR_N_CURRENT_VALUE 0x04 | ||
24 | #define APBTMR_N_CONTROL 0x08 | ||
25 | #define APBTMR_N_EOI 0x0c | ||
26 | #define APBTMR_N_INT_STATUS 0x10 | ||
27 | |||
28 | #define APBTMRS_INT_STATUS 0xa0 | ||
29 | #define APBTMRS_EOI 0xa4 | ||
30 | #define APBTMRS_RAW_INT_STATUS 0xa8 | ||
31 | #define APBTMRS_COMP_VERSION 0xac | ||
32 | #define APBTMRS_REG_SIZE 0x14 | ||
33 | |||
34 | /* register bits */ | ||
35 | #define APBTMR_CONTROL_ENABLE (1<<0) | ||
36 | #define APBTMR_CONTROL_MODE_PERIODIC (1<<1) /*1: periodic 0:free running */ | ||
37 | #define APBTMR_CONTROL_INT (1<<2) | ||
38 | |||
39 | /* default memory mapped register base */ | 21 | /* default memory mapped register base */ |
40 | #define LNW_SCU_ADDR 0xFF100000 | 22 | #define LNW_SCU_ADDR 0xFF100000 |
41 | #define LNW_EXT_TIMER_OFFSET 0x1B800 | 23 | #define LNW_EXT_TIMER_OFFSET 0x1B800 |
@@ -43,8 +25,8 @@ | |||
43 | #define LNW_EXT_TIMER_PGOFFSET 0x800 | 25 | #define LNW_EXT_TIMER_PGOFFSET 0x800 |
44 | 26 | ||
45 | /* APBT clock speed range from PCLK to fabric base, 25-100MHz */ | 27 | /* APBT clock speed range from PCLK to fabric base, 25-100MHz */ |
46 | #define APBT_MAX_FREQ 50 | 28 | #define APBT_MAX_FREQ 50000000 |
47 | #define APBT_MIN_FREQ 1 | 29 | #define APBT_MIN_FREQ 1000000 |
48 | #define APBT_MMAP_SIZE 1024 | 30 | #define APBT_MMAP_SIZE 1024 |
49 | 31 | ||
50 | #define APBT_DEV_USED 1 | 32 | #define APBT_DEV_USED 1 |
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index 2b6630d75e17..afdc3f756dea 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c | |||
@@ -27,15 +27,12 @@ | |||
27 | * timer, but by default APB timer has higher rating than local APIC timers. | 27 | * timer, but by default APB timer has higher rating than local APIC timers. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/clocksource.h> | ||
31 | #include <linux/clockchips.h> | ||
32 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/dw_apb_timer.h> | ||
33 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
34 | #include <linux/init.h> | 33 | #include <linux/init.h> |
35 | #include <linux/sysdev.h> | ||
36 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
37 | #include <linux/pm.h> | 35 | #include <linux/pm.h> |
38 | #include <linux/pci.h> | ||
39 | #include <linux/sfi.h> | 36 | #include <linux/sfi.h> |
40 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
41 | #include <linux/cpu.h> | 38 | #include <linux/cpu.h> |
@@ -46,75 +43,46 @@ | |||
46 | #include <asm/mrst.h> | 43 | #include <asm/mrst.h> |
47 | #include <asm/time.h> | 44 | #include <asm/time.h> |
48 | 45 | ||
49 | #define APBT_MASK CLOCKSOURCE_MASK(32) | ||
50 | #define APBT_SHIFT 22 | ||
51 | #define APBT_CLOCKEVENT_RATING 110 | 46 | #define APBT_CLOCKEVENT_RATING 110 |
52 | #define APBT_CLOCKSOURCE_RATING 250 | 47 | #define APBT_CLOCKSOURCE_RATING 250 |
53 | #define APBT_MIN_DELTA_USEC 200 | ||
54 | 48 | ||
55 | #define EVT_TO_APBT_DEV(evt) container_of(evt, struct apbt_dev, evt) | ||
56 | #define APBT_CLOCKEVENT0_NUM (0) | 49 | #define APBT_CLOCKEVENT0_NUM (0) |
57 | #define APBT_CLOCKEVENT1_NUM (1) | ||
58 | #define APBT_CLOCKSOURCE_NUM (2) | 50 | #define APBT_CLOCKSOURCE_NUM (2) |
59 | 51 | ||
60 | static unsigned long apbt_address; | 52 | static phys_addr_t apbt_address; |
61 | static int apb_timer_block_enabled; | 53 | static int apb_timer_block_enabled; |
62 | static void __iomem *apbt_virt_address; | 54 | static void __iomem *apbt_virt_address; |
63 | static int phy_cs_timer_id; | ||
64 | 55 | ||
65 | /* | 56 | /* |
66 | * Common DW APB timer info | 57 | * Common DW APB timer info |
67 | */ | 58 | */ |
68 | static uint64_t apbt_freq; | 59 | static unsigned long apbt_freq; |
69 | |||
70 | static void apbt_set_mode(enum clock_event_mode mode, | ||
71 | struct clock_event_device *evt); | ||
72 | static int apbt_next_event(unsigned long delta, | ||
73 | struct clock_event_device *evt); | ||
74 | static cycle_t apbt_read_clocksource(struct clocksource *cs); | ||
75 | static void apbt_restart_clocksource(struct clocksource *cs); | ||
76 | 60 | ||
77 | struct apbt_dev { | 61 | struct apbt_dev { |
78 | struct clock_event_device evt; | 62 | struct dw_apb_clock_event_device *timer; |
79 | unsigned int num; | 63 | unsigned int num; |
80 | int cpu; | 64 | int cpu; |
81 | unsigned int irq; | 65 | unsigned int irq; |
82 | unsigned int tick; | 66 | char name[10]; |
83 | unsigned int count; | ||
84 | unsigned int flags; | ||
85 | char name[10]; | ||
86 | }; | 67 | }; |
87 | 68 | ||
88 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); | 69 | static struct dw_apb_clocksource *clocksource_apbt; |
89 | 70 | ||
90 | #ifdef CONFIG_SMP | 71 | static inline void __iomem *adev_virt_addr(struct apbt_dev *adev) |
91 | static unsigned int apbt_num_timers_used; | ||
92 | static struct apbt_dev *apbt_devs; | ||
93 | #endif | ||
94 | |||
95 | static inline unsigned long apbt_readl_reg(unsigned long a) | ||
96 | { | 72 | { |
97 | return readl(apbt_virt_address + a); | 73 | return apbt_virt_address + adev->num * APBTMRS_REG_SIZE; |
98 | } | 74 | } |
99 | 75 | ||
100 | static inline void apbt_writel_reg(unsigned long d, unsigned long a) | 76 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); |
101 | { | ||
102 | writel(d, apbt_virt_address + a); | ||
103 | } | ||
104 | |||
105 | static inline unsigned long apbt_readl(int n, unsigned long a) | ||
106 | { | ||
107 | return readl(apbt_virt_address + a + n * APBTMRS_REG_SIZE); | ||
108 | } | ||
109 | 77 | ||
110 | static inline void apbt_writel(int n, unsigned long d, unsigned long a) | 78 | #ifdef CONFIG_SMP |
111 | { | 79 | static unsigned int apbt_num_timers_used; |
112 | writel(d, apbt_virt_address + a + n * APBTMRS_REG_SIZE); | 80 | #endif |
113 | } | ||
114 | 81 | ||
115 | static inline void apbt_set_mapping(void) | 82 | static inline void apbt_set_mapping(void) |
116 | { | 83 | { |
117 | struct sfi_timer_table_entry *mtmr; | 84 | struct sfi_timer_table_entry *mtmr; |
85 | int phy_cs_timer_id = 0; | ||
118 | 86 | ||
119 | if (apbt_virt_address) { | 87 | if (apbt_virt_address) { |
120 | pr_debug("APBT base already mapped\n"); | 88 | pr_debug("APBT base already mapped\n"); |
@@ -126,21 +94,18 @@ static inline void apbt_set_mapping(void) | |||
126 | APBT_CLOCKEVENT0_NUM); | 94 | APBT_CLOCKEVENT0_NUM); |
127 | return; | 95 | return; |
128 | } | 96 | } |
129 | apbt_address = (unsigned long)mtmr->phys_addr; | 97 | apbt_address = (phys_addr_t)mtmr->phys_addr; |
130 | if (!apbt_address) { | 98 | if (!apbt_address) { |
131 | printk(KERN_WARNING "No timer base from SFI, use default\n"); | 99 | printk(KERN_WARNING "No timer base from SFI, use default\n"); |
132 | apbt_address = APBT_DEFAULT_BASE; | 100 | apbt_address = APBT_DEFAULT_BASE; |
133 | } | 101 | } |
134 | apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); | 102 | apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); |
135 | if (apbt_virt_address) { | 103 | if (!apbt_virt_address) { |
136 | pr_debug("Mapped APBT physical addr %p at virtual addr %p\n",\ | 104 | pr_debug("Failed mapping APBT phy address at %lu\n",\ |
137 | (void *)apbt_address, (void *)apbt_virt_address); | 105 | (unsigned long)apbt_address); |
138 | } else { | ||
139 | pr_debug("Failed mapping APBT phy address at %p\n",\ | ||
140 | (void *)apbt_address); | ||
141 | goto panic_noapbt; | 106 | goto panic_noapbt; |
142 | } | 107 | } |
143 | apbt_freq = mtmr->freq_hz / USEC_PER_SEC; | 108 | apbt_freq = mtmr->freq_hz; |
144 | sfi_free_mtmr(mtmr); | 109 | sfi_free_mtmr(mtmr); |
145 | 110 | ||
146 | /* Now figure out the physical timer id for clocksource device */ | 111 | /* Now figure out the physical timer id for clocksource device */ |
@@ -149,9 +114,14 @@ static inline void apbt_set_mapping(void) | |||
149 | goto panic_noapbt; | 114 | goto panic_noapbt; |
150 | 115 | ||
151 | /* Now figure out the physical timer id */ | 116 | /* Now figure out the physical timer id */ |
152 | phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) | 117 | pr_debug("Use timer %d for clocksource\n", |
153 | / APBTMRS_REG_SIZE; | 118 | (int)(mtmr->phys_addr & 0xff) / APBTMRS_REG_SIZE); |
154 | pr_debug("Use timer %d for clocksource\n", phy_cs_timer_id); | 119 | phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) / |
120 | APBTMRS_REG_SIZE; | ||
121 | |||
122 | clocksource_apbt = dw_apb_clocksource_init(APBT_CLOCKSOURCE_RATING, | ||
123 | "apbt0", apbt_virt_address + phy_cs_timer_id * | ||
124 | APBTMRS_REG_SIZE, apbt_freq); | ||
155 | return; | 125 | return; |
156 | 126 | ||
157 | panic_noapbt: | 127 | panic_noapbt: |
@@ -173,82 +143,6 @@ static inline int is_apbt_capable(void) | |||
173 | return apbt_virt_address ? 1 : 0; | 143 | return apbt_virt_address ? 1 : 0; |
174 | } | 144 | } |
175 | 145 | ||
176 | static struct clocksource clocksource_apbt = { | ||
177 | .name = "apbt", | ||
178 | .rating = APBT_CLOCKSOURCE_RATING, | ||
179 | .read = apbt_read_clocksource, | ||
180 | .mask = APBT_MASK, | ||
181 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
182 | .resume = apbt_restart_clocksource, | ||
183 | }; | ||
184 | |||
185 | /* boot APB clock event device */ | ||
186 | static struct clock_event_device apbt_clockevent = { | ||
187 | .name = "apbt0", | ||
188 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
189 | .set_mode = apbt_set_mode, | ||
190 | .set_next_event = apbt_next_event, | ||
191 | .shift = APBT_SHIFT, | ||
192 | .irq = 0, | ||
193 | .rating = APBT_CLOCKEVENT_RATING, | ||
194 | }; | ||
195 | |||
196 | /* | ||
197 | * start count down from 0xffff_ffff. this is done by toggling the enable bit | ||
198 | * then load initial load count to ~0. | ||
199 | */ | ||
200 | static void apbt_start_counter(int n) | ||
201 | { | ||
202 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
203 | |||
204 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
205 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
206 | apbt_writel(n, ~0, APBTMR_N_LOAD_COUNT); | ||
207 | /* enable, mask interrupt */ | ||
208 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
209 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); | ||
210 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
211 | /* read it once to get cached counter value initialized */ | ||
212 | apbt_read_clocksource(&clocksource_apbt); | ||
213 | } | ||
214 | |||
215 | static irqreturn_t apbt_interrupt_handler(int irq, void *data) | ||
216 | { | ||
217 | struct apbt_dev *dev = (struct apbt_dev *)data; | ||
218 | struct clock_event_device *aevt = &dev->evt; | ||
219 | |||
220 | if (!aevt->event_handler) { | ||
221 | printk(KERN_INFO "Spurious APBT timer interrupt on %d\n", | ||
222 | dev->num); | ||
223 | return IRQ_NONE; | ||
224 | } | ||
225 | aevt->event_handler(aevt); | ||
226 | return IRQ_HANDLED; | ||
227 | } | ||
228 | |||
229 | static void apbt_restart_clocksource(struct clocksource *cs) | ||
230 | { | ||
231 | apbt_start_counter(phy_cs_timer_id); | ||
232 | } | ||
233 | |||
234 | static void apbt_enable_int(int n) | ||
235 | { | ||
236 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
237 | /* clear pending intr */ | ||
238 | apbt_readl(n, APBTMR_N_EOI); | ||
239 | ctrl &= ~APBTMR_CONTROL_INT; | ||
240 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
241 | } | ||
242 | |||
243 | static void apbt_disable_int(int n) | ||
244 | { | ||
245 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
246 | |||
247 | ctrl |= APBTMR_CONTROL_INT; | ||
248 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
249 | } | ||
250 | |||
251 | |||
252 | static int __init apbt_clockevent_register(void) | 146 | static int __init apbt_clockevent_register(void) |
253 | { | 147 | { |
254 | struct sfi_timer_table_entry *mtmr; | 148 | struct sfi_timer_table_entry *mtmr; |
@@ -261,45 +155,21 @@ static int __init apbt_clockevent_register(void) | |||
261 | return -ENODEV; | 155 | return -ENODEV; |
262 | } | 156 | } |
263 | 157 | ||
264 | /* | ||
265 | * We need to calculate the scaled math multiplication factor for | ||
266 | * nanosecond to apbt tick conversion. | ||
267 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
268 | */ | ||
269 | apbt_clockevent.mult = div_sc((unsigned long) mtmr->freq_hz | ||
270 | , NSEC_PER_SEC, APBT_SHIFT); | ||
271 | |||
272 | /* Calculate the min / max delta */ | ||
273 | apbt_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | ||
274 | &apbt_clockevent); | ||
275 | apbt_clockevent.min_delta_ns = clockevent_delta2ns( | ||
276 | APBT_MIN_DELTA_USEC*apbt_freq, | ||
277 | &apbt_clockevent); | ||
278 | /* | ||
279 | * Start apbt with the boot cpu mask and make it | ||
280 | * global if not used for per cpu timer. | ||
281 | */ | ||
282 | apbt_clockevent.cpumask = cpumask_of(smp_processor_id()); | ||
283 | adev->num = smp_processor_id(); | 158 | adev->num = smp_processor_id(); |
284 | memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); | 159 | adev->timer = dw_apb_clockevent_init(smp_processor_id(), "apbt0", |
160 | mrst_timer_options == MRST_TIMER_LAPIC_APBT ? | ||
161 | APBT_CLOCKEVENT_RATING - 100 : APBT_CLOCKEVENT_RATING, | ||
162 | adev_virt_addr(adev), 0, apbt_freq); | ||
163 | /* Firmware does EOI handling for us. */ | ||
164 | adev->timer->eoi = NULL; | ||
285 | 165 | ||
286 | if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { | 166 | if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { |
287 | adev->evt.rating = APBT_CLOCKEVENT_RATING - 100; | 167 | global_clock_event = &adev->timer->ced; |
288 | global_clock_event = &adev->evt; | ||
289 | printk(KERN_DEBUG "%s clockevent registered as global\n", | 168 | printk(KERN_DEBUG "%s clockevent registered as global\n", |
290 | global_clock_event->name); | 169 | global_clock_event->name); |
291 | } | 170 | } |
292 | 171 | ||
293 | if (request_irq(apbt_clockevent.irq, apbt_interrupt_handler, | 172 | dw_apb_clockevent_register(adev->timer); |
294 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, | ||
295 | apbt_clockevent.name, adev)) { | ||
296 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
297 | apbt_clockevent.irq); | ||
298 | } | ||
299 | |||
300 | clockevents_register_device(&adev->evt); | ||
301 | /* Start APBT 0 interrupts */ | ||
302 | apbt_enable_int(APBT_CLOCKEVENT0_NUM); | ||
303 | 173 | ||
304 | sfi_free_mtmr(mtmr); | 174 | sfi_free_mtmr(mtmr); |
305 | return 0; | 175 | return 0; |
@@ -317,52 +187,34 @@ static void apbt_setup_irq(struct apbt_dev *adev) | |||
317 | irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); | 187 | irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); |
318 | /* APB timer irqs are set up as mp_irqs, timer is edge type */ | 188 | /* APB timer irqs are set up as mp_irqs, timer is edge type */ |
319 | __irq_set_handler(adev->irq, handle_edge_irq, 0, "edge"); | 189 | __irq_set_handler(adev->irq, handle_edge_irq, 0, "edge"); |
320 | |||
321 | if (system_state == SYSTEM_BOOTING) { | ||
322 | if (request_irq(adev->irq, apbt_interrupt_handler, | ||
323 | IRQF_TIMER | IRQF_DISABLED | | ||
324 | IRQF_NOBALANCING, | ||
325 | adev->name, adev)) { | ||
326 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
327 | adev->num); | ||
328 | } | ||
329 | } else | ||
330 | enable_irq(adev->irq); | ||
331 | } | 190 | } |
332 | 191 | ||
333 | /* Should be called with per cpu */ | 192 | /* Should be called with per cpu */ |
334 | void apbt_setup_secondary_clock(void) | 193 | void apbt_setup_secondary_clock(void) |
335 | { | 194 | { |
336 | struct apbt_dev *adev; | 195 | struct apbt_dev *adev; |
337 | struct clock_event_device *aevt; | ||
338 | int cpu; | 196 | int cpu; |
339 | 197 | ||
340 | /* Don't register boot CPU clockevent */ | 198 | /* Don't register boot CPU clockevent */ |
341 | cpu = smp_processor_id(); | 199 | cpu = smp_processor_id(); |
342 | if (!cpu) | 200 | if (!cpu) |
343 | return; | 201 | return; |
344 | /* | ||
345 | * We need to calculate the scaled math multiplication factor for | ||
346 | * nanosecond to apbt tick conversion. | ||
347 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
348 | */ | ||
349 | printk(KERN_INFO "Init per CPU clockevent %d\n", cpu); | ||
350 | adev = &per_cpu(cpu_apbt_dev, cpu); | ||
351 | aevt = &adev->evt; | ||
352 | 202 | ||
353 | memcpy(aevt, &apbt_clockevent, sizeof(*aevt)); | 203 | adev = &__get_cpu_var(cpu_apbt_dev); |
354 | aevt->cpumask = cpumask_of(cpu); | 204 | if (!adev->timer) { |
355 | aevt->name = adev->name; | 205 | adev->timer = dw_apb_clockevent_init(cpu, adev->name, |
356 | aevt->mode = CLOCK_EVT_MODE_UNUSED; | 206 | APBT_CLOCKEVENT_RATING, adev_virt_addr(adev), |
207 | adev->irq, apbt_freq); | ||
208 | adev->timer->eoi = NULL; | ||
209 | } else { | ||
210 | dw_apb_clockevent_resume(adev->timer); | ||
211 | } | ||
357 | 212 | ||
358 | printk(KERN_INFO "Registering CPU %d clockevent device %s, mask %08x\n", | 213 | printk(KERN_INFO "Registering CPU %d clockevent device %s, cpu %08x\n", |
359 | cpu, aevt->name, *(u32 *)aevt->cpumask); | 214 | cpu, adev->name, adev->cpu); |
360 | 215 | ||
361 | apbt_setup_irq(adev); | 216 | apbt_setup_irq(adev); |
362 | 217 | dw_apb_clockevent_register(adev->timer); | |
363 | clockevents_register_device(aevt); | ||
364 | |||
365 | apbt_enable_int(cpu); | ||
366 | 218 | ||
367 | return; | 219 | return; |
368 | } | 220 | } |
@@ -385,13 +237,12 @@ static int apbt_cpuhp_notify(struct notifier_block *n, | |||
385 | 237 | ||
386 | switch (action & 0xf) { | 238 | switch (action & 0xf) { |
387 | case CPU_DEAD: | 239 | case CPU_DEAD: |
388 | disable_irq(adev->irq); | 240 | dw_apb_clockevent_pause(adev->timer); |
389 | apbt_disable_int(cpu); | ||
390 | if (system_state == SYSTEM_RUNNING) { | 241 | if (system_state == SYSTEM_RUNNING) { |
391 | pr_debug("skipping APBT CPU %lu offline\n", cpu); | 242 | pr_debug("skipping APBT CPU %lu offline\n", cpu); |
392 | } else if (adev) { | 243 | } else if (adev) { |
393 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); | 244 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); |
394 | free_irq(adev->irq, adev); | 245 | dw_apb_clockevent_stop(adev->timer); |
395 | } | 246 | } |
396 | break; | 247 | break; |
397 | default: | 248 | default: |
@@ -416,116 +267,16 @@ void apbt_setup_secondary_clock(void) {} | |||
416 | 267 | ||
417 | #endif /* CONFIG_SMP */ | 268 | #endif /* CONFIG_SMP */ |
418 | 269 | ||
419 | static void apbt_set_mode(enum clock_event_mode mode, | ||
420 | struct clock_event_device *evt) | ||
421 | { | ||
422 | unsigned long ctrl; | ||
423 | uint64_t delta; | ||
424 | int timer_num; | ||
425 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
426 | |||
427 | BUG_ON(!apbt_virt_address); | ||
428 | |||
429 | timer_num = adev->num; | ||
430 | pr_debug("%s CPU %d timer %d mode=%d\n", | ||
431 | __func__, first_cpu(*evt->cpumask), timer_num, mode); | ||
432 | |||
433 | switch (mode) { | ||
434 | case CLOCK_EVT_MODE_PERIODIC: | ||
435 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * apbt_clockevent.mult; | ||
436 | delta >>= apbt_clockevent.shift; | ||
437 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
438 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; | ||
439 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
440 | /* | ||
441 | * DW APB p. 46, have to disable timer before load counter, | ||
442 | * may cause sync problem. | ||
443 | */ | ||
444 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
445 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
446 | udelay(1); | ||
447 | pr_debug("Setting clock period %d for HZ %d\n", (int)delta, HZ); | ||
448 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
449 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
450 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
451 | break; | ||
452 | /* APB timer does not have one-shot mode, use free running mode */ | ||
453 | case CLOCK_EVT_MODE_ONESHOT: | ||
454 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
455 | /* | ||
456 | * set free running mode, this mode will let timer reload max | ||
457 | * timeout which will give time (3min on 25MHz clock) to rearm | ||
458 | * the next event, therefore emulate the one-shot mode. | ||
459 | */ | ||
460 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
461 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
462 | |||
463 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
464 | /* write again to set free running mode */ | ||
465 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
466 | |||
467 | /* | ||
468 | * DW APB p. 46, load counter with all 1s before starting free | ||
469 | * running mode. | ||
470 | */ | ||
471 | apbt_writel(timer_num, ~0, APBTMR_N_LOAD_COUNT); | ||
472 | ctrl &= ~APBTMR_CONTROL_INT; | ||
473 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
474 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
475 | break; | ||
476 | |||
477 | case CLOCK_EVT_MODE_UNUSED: | ||
478 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
479 | apbt_disable_int(timer_num); | ||
480 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
481 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
482 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
483 | break; | ||
484 | |||
485 | case CLOCK_EVT_MODE_RESUME: | ||
486 | apbt_enable_int(timer_num); | ||
487 | break; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | static int apbt_next_event(unsigned long delta, | ||
492 | struct clock_event_device *evt) | ||
493 | { | ||
494 | unsigned long ctrl; | ||
495 | int timer_num; | ||
496 | |||
497 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
498 | |||
499 | timer_num = adev->num; | ||
500 | /* Disable timer */ | ||
501 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
502 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
503 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
504 | /* write new count */ | ||
505 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
506 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
507 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static cycle_t apbt_read_clocksource(struct clocksource *cs) | ||
512 | { | ||
513 | unsigned long current_count; | ||
514 | |||
515 | current_count = apbt_readl(phy_cs_timer_id, APBTMR_N_CURRENT_VALUE); | ||
516 | return (cycle_t)~current_count; | ||
517 | } | ||
518 | |||
519 | static int apbt_clocksource_register(void) | 270 | static int apbt_clocksource_register(void) |
520 | { | 271 | { |
521 | u64 start, now; | 272 | u64 start, now; |
522 | cycle_t t1; | 273 | cycle_t t1; |
523 | 274 | ||
524 | /* Start the counter, use timer 2 as source, timer 0/1 for event */ | 275 | /* Start the counter, use timer 2 as source, timer 0/1 for event */ |
525 | apbt_start_counter(phy_cs_timer_id); | 276 | dw_apb_clocksource_start(clocksource_apbt); |
526 | 277 | ||
527 | /* Verify whether apbt counter works */ | 278 | /* Verify whether apbt counter works */ |
528 | t1 = apbt_read_clocksource(&clocksource_apbt); | 279 | t1 = dw_apb_clocksource_read(clocksource_apbt); |
529 | rdtscll(start); | 280 | rdtscll(start); |
530 | 281 | ||
531 | /* | 282 | /* |
@@ -540,10 +291,10 @@ static int apbt_clocksource_register(void) | |||
540 | } while ((now - start) < 200000UL); | 291 | } while ((now - start) < 200000UL); |
541 | 292 | ||
542 | /* APBT is the only always on clocksource, it has to work! */ | 293 | /* APBT is the only always on clocksource, it has to work! */ |
543 | if (t1 == apbt_read_clocksource(&clocksource_apbt)) | 294 | if (t1 == dw_apb_clocksource_read(clocksource_apbt)) |
544 | panic("APBT counter not counting. APBT disabled\n"); | 295 | panic("APBT counter not counting. APBT disabled\n"); |
545 | 296 | ||
546 | clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000); | 297 | dw_apb_clocksource_register(clocksource_apbt); |
547 | 298 | ||
548 | return 0; | 299 | return 0; |
549 | } | 300 | } |
@@ -567,10 +318,7 @@ void __init apbt_time_init(void) | |||
567 | if (apb_timer_block_enabled) | 318 | if (apb_timer_block_enabled) |
568 | return; | 319 | return; |
569 | apbt_set_mapping(); | 320 | apbt_set_mapping(); |
570 | if (apbt_virt_address) { | 321 | if (!apbt_virt_address) |
571 | pr_debug("Found APBT version 0x%lx\n",\ | ||
572 | apbt_readl_reg(APBTMRS_COMP_VERSION)); | ||
573 | } else | ||
574 | goto out_noapbt; | 322 | goto out_noapbt; |
575 | /* | 323 | /* |
576 | * Read the frequency and check for a sane value, for ESL model | 324 | * Read the frequency and check for a sane value, for ESL model |
@@ -578,7 +326,7 @@ void __init apbt_time_init(void) | |||
578 | */ | 326 | */ |
579 | 327 | ||
580 | if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { | 328 | if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { |
581 | pr_debug("APBT has invalid freq 0x%llx\n", apbt_freq); | 329 | pr_debug("APBT has invalid freq 0x%lx\n", apbt_freq); |
582 | goto out_noapbt; | 330 | goto out_noapbt; |
583 | } | 331 | } |
584 | if (apbt_clocksource_register()) { | 332 | if (apbt_clocksource_register()) { |
@@ -604,30 +352,20 @@ void __init apbt_time_init(void) | |||
604 | } else { | 352 | } else { |
605 | percpu_timer = 0; | 353 | percpu_timer = 0; |
606 | apbt_num_timers_used = 1; | 354 | apbt_num_timers_used = 1; |
607 | adev = &per_cpu(cpu_apbt_dev, 0); | ||
608 | adev->flags &= ~APBT_DEV_USED; | ||
609 | } | 355 | } |
610 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); | 356 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); |
611 | 357 | ||
612 | /* here we set up per CPU timer data structure */ | 358 | /* here we set up per CPU timer data structure */ |
613 | apbt_devs = kzalloc(sizeof(struct apbt_dev) * apbt_num_timers_used, | ||
614 | GFP_KERNEL); | ||
615 | if (!apbt_devs) { | ||
616 | printk(KERN_ERR "Failed to allocate APB timer devices\n"); | ||
617 | return; | ||
618 | } | ||
619 | for (i = 0; i < apbt_num_timers_used; i++) { | 359 | for (i = 0; i < apbt_num_timers_used; i++) { |
620 | adev = &per_cpu(cpu_apbt_dev, i); | 360 | adev = &per_cpu(cpu_apbt_dev, i); |
621 | adev->num = i; | 361 | adev->num = i; |
622 | adev->cpu = i; | 362 | adev->cpu = i; |
623 | p_mtmr = sfi_get_mtmr(i); | 363 | p_mtmr = sfi_get_mtmr(i); |
624 | if (p_mtmr) { | 364 | if (p_mtmr) |
625 | adev->tick = p_mtmr->freq_hz; | ||
626 | adev->irq = p_mtmr->irq; | 365 | adev->irq = p_mtmr->irq; |
627 | } else | 366 | else |
628 | printk(KERN_ERR "Failed to get timer for cpu %d\n", i); | 367 | printk(KERN_ERR "Failed to get timer for cpu %d\n", i); |
629 | adev->count = 0; | 368 | snprintf(adev->name, sizeof(adev->name) - 1, "apbt%d", i); |
630 | sprintf(adev->name, "apbt%d", i); | ||
631 | } | 369 | } |
632 | #endif | 370 | #endif |
633 | 371 | ||
@@ -639,17 +377,8 @@ out_noapbt: | |||
639 | panic("failed to enable APB timer\n"); | 377 | panic("failed to enable APB timer\n"); |
640 | } | 378 | } |
641 | 379 | ||
642 | static inline void apbt_disable(int n) | ||
643 | { | ||
644 | if (is_apbt_capable()) { | ||
645 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
646 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
647 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | /* called before apb_timer_enable, use early map */ | 380 | /* called before apb_timer_enable, use early map */ |
652 | unsigned long apbt_quick_calibrate() | 381 | unsigned long apbt_quick_calibrate(void) |
653 | { | 382 | { |
654 | int i, scale; | 383 | int i, scale; |
655 | u64 old, new; | 384 | u64 old, new; |
@@ -658,31 +387,31 @@ unsigned long apbt_quick_calibrate() | |||
658 | u32 loop, shift; | 387 | u32 loop, shift; |
659 | 388 | ||
660 | apbt_set_mapping(); | 389 | apbt_set_mapping(); |
661 | apbt_start_counter(phy_cs_timer_id); | 390 | dw_apb_clocksource_start(clocksource_apbt); |
662 | 391 | ||
663 | /* check if the timer can count down, otherwise return */ | 392 | /* check if the timer can count down, otherwise return */ |
664 | old = apbt_read_clocksource(&clocksource_apbt); | 393 | old = dw_apb_clocksource_read(clocksource_apbt); |
665 | i = 10000; | 394 | i = 10000; |
666 | while (--i) { | 395 | while (--i) { |
667 | if (old != apbt_read_clocksource(&clocksource_apbt)) | 396 | if (old != dw_apb_clocksource_read(clocksource_apbt)) |
668 | break; | 397 | break; |
669 | } | 398 | } |
670 | if (!i) | 399 | if (!i) |
671 | goto failed; | 400 | goto failed; |
672 | 401 | ||
673 | /* count 16 ms */ | 402 | /* count 16 ms */ |
674 | loop = (apbt_freq * 1000) << 4; | 403 | loop = (apbt_freq / 1000) << 4; |
675 | 404 | ||
676 | /* restart the timer to ensure it won't get to 0 in the calibration */ | 405 | /* restart the timer to ensure it won't get to 0 in the calibration */ |
677 | apbt_start_counter(phy_cs_timer_id); | 406 | dw_apb_clocksource_start(clocksource_apbt); |
678 | 407 | ||
679 | old = apbt_read_clocksource(&clocksource_apbt); | 408 | old = dw_apb_clocksource_read(clocksource_apbt); |
680 | old += loop; | 409 | old += loop; |
681 | 410 | ||
682 | t1 = __native_read_tsc(); | 411 | t1 = __native_read_tsc(); |
683 | 412 | ||
684 | do { | 413 | do { |
685 | new = apbt_read_clocksource(&clocksource_apbt); | 414 | new = dw_apb_clocksource_read(clocksource_apbt); |
686 | } while (new < old); | 415 | } while (new < old); |
687 | 416 | ||
688 | t2 = __native_read_tsc(); | 417 | t2 = __native_read_tsc(); |
@@ -694,7 +423,7 @@ unsigned long apbt_quick_calibrate() | |||
694 | return 0; | 423 | return 0; |
695 | } | 424 | } |
696 | scale = (int)div_u64((t2 - t1), loop >> shift); | 425 | scale = (int)div_u64((t2 - t1), loop >> shift); |
697 | khz = (scale * apbt_freq * 1000) >> shift; | 426 | khz = (scale * (apbt_freq / 1000)) >> shift; |
698 | printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); | 427 | printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); |
699 | return khz; | 428 | return khz; |
700 | failed: | 429 | failed: |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index d8d3e02b912c..34e9c4f88926 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -12,3 +12,6 @@ config CLKBLD_I8253 | |||
12 | 12 | ||
13 | config CLKSRC_MMIO | 13 | config CLKSRC_MMIO |
14 | bool | 14 | bool |
15 | |||
16 | config DW_APB_TIMER | ||
17 | bool | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 7922a0cfc99f..85ad1646a7b7 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -8,3 +8,4 @@ obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o | |||
8 | obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o | 8 | obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o |
9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o | 9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o |
10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o | 10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o |
11 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o | ||
diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c new file mode 100644 index 000000000000..580f870541a3 --- /dev/null +++ b/drivers/clocksource/dw_apb_timer.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * (C) Copyright 2009 Intel Corporation | ||
3 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
4 | * | ||
5 | * Shared with ARM platforms, Jamie Iles, Picochip 2011 | ||
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 | * Support for the Synopsys DesignWare APB Timers. | ||
12 | */ | ||
13 | #include <linux/dw_apb_timer.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #define APBT_MIN_PERIOD 4 | ||
22 | #define APBT_MIN_DELTA_USEC 200 | ||
23 | |||
24 | #define APBTMR_N_LOAD_COUNT 0x00 | ||
25 | #define APBTMR_N_CURRENT_VALUE 0x04 | ||
26 | #define APBTMR_N_CONTROL 0x08 | ||
27 | #define APBTMR_N_EOI 0x0c | ||
28 | #define APBTMR_N_INT_STATUS 0x10 | ||
29 | |||
30 | #define APBTMRS_INT_STATUS 0xa0 | ||
31 | #define APBTMRS_EOI 0xa4 | ||
32 | #define APBTMRS_RAW_INT_STATUS 0xa8 | ||
33 | #define APBTMRS_COMP_VERSION 0xac | ||
34 | |||
35 | #define APBTMR_CONTROL_ENABLE (1 << 0) | ||
36 | /* 1: periodic, 0:free running. */ | ||
37 | #define APBTMR_CONTROL_MODE_PERIODIC (1 << 1) | ||
38 | #define APBTMR_CONTROL_INT (1 << 2) | ||
39 | |||
40 | static inline struct dw_apb_clock_event_device * | ||
41 | ced_to_dw_apb_ced(struct clock_event_device *evt) | ||
42 | { | ||
43 | return container_of(evt, struct dw_apb_clock_event_device, ced); | ||
44 | } | ||
45 | |||
46 | static inline struct dw_apb_clocksource * | ||
47 | clocksource_to_dw_apb_clocksource(struct clocksource *cs) | ||
48 | { | ||
49 | return container_of(cs, struct dw_apb_clocksource, cs); | ||
50 | } | ||
51 | |||
52 | static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs) | ||
53 | { | ||
54 | return readl(timer->base + offs); | ||
55 | } | ||
56 | |||
57 | static void apbt_writel(struct dw_apb_timer *timer, unsigned long val, | ||
58 | unsigned long offs) | ||
59 | { | ||
60 | writel(val, timer->base + offs); | ||
61 | } | ||
62 | |||
63 | static void apbt_disable_int(struct dw_apb_timer *timer) | ||
64 | { | ||
65 | unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); | ||
66 | |||
67 | ctrl |= APBTMR_CONTROL_INT; | ||
68 | apbt_writel(timer, ctrl, APBTMR_N_CONTROL); | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * dw_apb_clockevent_pause() - stop the clock_event_device from running | ||
73 | * | ||
74 | * @dw_ced: The APB clock to stop generating events. | ||
75 | */ | ||
76 | void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) | ||
77 | { | ||
78 | disable_irq(dw_ced->timer.irq); | ||
79 | apbt_disable_int(&dw_ced->timer); | ||
80 | } | ||
81 | |||
82 | static void apbt_eoi(struct dw_apb_timer *timer) | ||
83 | { | ||
84 | apbt_readl(timer, APBTMR_N_EOI); | ||
85 | } | ||
86 | |||
87 | static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) | ||
88 | { | ||
89 | struct clock_event_device *evt = data; | ||
90 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); | ||
91 | |||
92 | if (!evt->event_handler) { | ||
93 | pr_info("Spurious APBT timer interrupt %d", irq); | ||
94 | return IRQ_NONE; | ||
95 | } | ||
96 | |||
97 | if (dw_ced->eoi) | ||
98 | dw_ced->eoi(&dw_ced->timer); | ||
99 | |||
100 | evt->event_handler(evt); | ||
101 | return IRQ_HANDLED; | ||
102 | } | ||
103 | |||
104 | static void apbt_enable_int(struct dw_apb_timer *timer) | ||
105 | { | ||
106 | unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); | ||
107 | /* clear pending intr */ | ||
108 | apbt_readl(timer, APBTMR_N_EOI); | ||
109 | ctrl &= ~APBTMR_CONTROL_INT; | ||
110 | apbt_writel(timer, ctrl, APBTMR_N_CONTROL); | ||
111 | } | ||
112 | |||
113 | static void apbt_set_mode(enum clock_event_mode mode, | ||
114 | struct clock_event_device *evt) | ||
115 | { | ||
116 | unsigned long ctrl; | ||
117 | unsigned long period; | ||
118 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); | ||
119 | |||
120 | pr_debug("%s CPU %d mode=%d\n", __func__, first_cpu(*evt->cpumask), | ||
121 | mode); | ||
122 | |||
123 | switch (mode) { | ||
124 | case CLOCK_EVT_MODE_PERIODIC: | ||
125 | period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); | ||
126 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
127 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; | ||
128 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
129 | /* | ||
130 | * DW APB p. 46, have to disable timer before load counter, | ||
131 | * may cause sync problem. | ||
132 | */ | ||
133 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
134 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
135 | udelay(1); | ||
136 | pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); | ||
137 | apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); | ||
138 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
139 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
140 | break; | ||
141 | |||
142 | case CLOCK_EVT_MODE_ONESHOT: | ||
143 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
144 | /* | ||
145 | * set free running mode, this mode will let timer reload max | ||
146 | * timeout which will give time (3min on 25MHz clock) to rearm | ||
147 | * the next event, therefore emulate the one-shot mode. | ||
148 | */ | ||
149 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
150 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
151 | |||
152 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
153 | /* write again to set free running mode */ | ||
154 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
155 | |||
156 | /* | ||
157 | * DW APB p. 46, load counter with all 1s before starting free | ||
158 | * running mode. | ||
159 | */ | ||
160 | apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); | ||
161 | ctrl &= ~APBTMR_CONTROL_INT; | ||
162 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
163 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
164 | break; | ||
165 | |||
166 | case CLOCK_EVT_MODE_UNUSED: | ||
167 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
168 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
169 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
170 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
171 | break; | ||
172 | |||
173 | case CLOCK_EVT_MODE_RESUME: | ||
174 | apbt_enable_int(&dw_ced->timer); | ||
175 | break; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static int apbt_next_event(unsigned long delta, | ||
180 | struct clock_event_device *evt) | ||
181 | { | ||
182 | unsigned long ctrl; | ||
183 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); | ||
184 | |||
185 | /* Disable timer */ | ||
186 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
187 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
188 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
189 | /* write new count */ | ||
190 | apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT); | ||
191 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
192 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * dw_apb_clockevent_init() - use an APB timer as a clock_event_device | ||
199 | * | ||
200 | * @cpu: The CPU the events will be targeted at. | ||
201 | * @name: The name used for the timer and the IRQ for it. | ||
202 | * @rating: The rating to give the timer. | ||
203 | * @base: I/O base for the timer registers. | ||
204 | * @irq: The interrupt number to use for the timer. | ||
205 | * @freq: The frequency that the timer counts at. | ||
206 | * | ||
207 | * This creates a clock_event_device for using with the generic clock layer | ||
208 | * but does not start and register it. This should be done with | ||
209 | * dw_apb_clockevent_register() as the next step. If this is the first time | ||
210 | * it has been called for a timer then the IRQ will be requested, if not it | ||
211 | * just be enabled to allow CPU hotplug to avoid repeatedly requesting and | ||
212 | * releasing the IRQ. | ||
213 | */ | ||
214 | struct dw_apb_clock_event_device * | ||
215 | dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, | ||
216 | void __iomem *base, int irq, unsigned long freq) | ||
217 | { | ||
218 | struct dw_apb_clock_event_device *dw_ced = | ||
219 | kzalloc(sizeof(*dw_ced), GFP_KERNEL); | ||
220 | int err; | ||
221 | |||
222 | if (!dw_ced) | ||
223 | return NULL; | ||
224 | |||
225 | dw_ced->timer.base = base; | ||
226 | dw_ced->timer.irq = irq; | ||
227 | dw_ced->timer.freq = freq; | ||
228 | |||
229 | clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD); | ||
230 | dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff, | ||
231 | &dw_ced->ced); | ||
232 | dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); | ||
233 | dw_ced->ced.cpumask = cpumask_of(cpu); | ||
234 | dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
235 | dw_ced->ced.set_mode = apbt_set_mode; | ||
236 | dw_ced->ced.set_next_event = apbt_next_event; | ||
237 | dw_ced->ced.irq = dw_ced->timer.irq; | ||
238 | dw_ced->ced.rating = rating; | ||
239 | dw_ced->ced.name = name; | ||
240 | |||
241 | dw_ced->irqaction.name = dw_ced->ced.name; | ||
242 | dw_ced->irqaction.handler = dw_apb_clockevent_irq; | ||
243 | dw_ced->irqaction.dev_id = &dw_ced->ced; | ||
244 | dw_ced->irqaction.irq = irq; | ||
245 | dw_ced->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | | ||
246 | IRQF_NOBALANCING | | ||
247 | IRQF_DISABLED; | ||
248 | |||
249 | dw_ced->eoi = apbt_eoi; | ||
250 | err = setup_irq(irq, &dw_ced->irqaction); | ||
251 | if (err) { | ||
252 | pr_err("failed to request timer irq\n"); | ||
253 | kfree(dw_ced); | ||
254 | dw_ced = NULL; | ||
255 | } | ||
256 | |||
257 | return dw_ced; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * dw_apb_clockevent_resume() - resume a clock that has been paused. | ||
262 | * | ||
263 | * @dw_ced: The APB clock to resume. | ||
264 | */ | ||
265 | void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced) | ||
266 | { | ||
267 | enable_irq(dw_ced->timer.irq); | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ. | ||
272 | * | ||
273 | * @dw_ced: The APB clock to stop generating the events. | ||
274 | */ | ||
275 | void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced) | ||
276 | { | ||
277 | free_irq(dw_ced->timer.irq, &dw_ced->ced); | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * dw_apb_clockevent_register() - register the clock with the generic layer | ||
282 | * | ||
283 | * @dw_ced: The APB clock to register as a clock_event_device. | ||
284 | */ | ||
285 | void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced) | ||
286 | { | ||
287 | apbt_writel(&dw_ced->timer, 0, APBTMR_N_CONTROL); | ||
288 | clockevents_register_device(&dw_ced->ced); | ||
289 | apbt_enable_int(&dw_ced->timer); | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * dw_apb_clocksource_start() - start the clocksource counting. | ||
294 | * | ||
295 | * @dw_cs: The clocksource to start. | ||
296 | * | ||
297 | * This is used to start the clocksource before registration and can be used | ||
298 | * to enable calibration of timers. | ||
299 | */ | ||
300 | void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) | ||
301 | { | ||
302 | /* | ||
303 | * start count down from 0xffff_ffff. this is done by toggling the | ||
304 | * enable bit then load initial load count to ~0. | ||
305 | */ | ||
306 | unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL); | ||
307 | |||
308 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
309 | apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); | ||
310 | apbt_writel(&dw_cs->timer, ~0, APBTMR_N_LOAD_COUNT); | ||
311 | /* enable, mask interrupt */ | ||
312 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
313 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); | ||
314 | apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); | ||
315 | /* read it once to get cached counter value initialized */ | ||
316 | dw_apb_clocksource_read(dw_cs); | ||
317 | } | ||
318 | |||
319 | static cycle_t __apbt_read_clocksource(struct clocksource *cs) | ||
320 | { | ||
321 | unsigned long current_count; | ||
322 | struct dw_apb_clocksource *dw_cs = | ||
323 | clocksource_to_dw_apb_clocksource(cs); | ||
324 | |||
325 | current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); | ||
326 | |||
327 | return (cycle_t)~current_count; | ||
328 | } | ||
329 | |||
330 | static void apbt_restart_clocksource(struct clocksource *cs) | ||
331 | { | ||
332 | struct dw_apb_clocksource *dw_cs = | ||
333 | clocksource_to_dw_apb_clocksource(cs); | ||
334 | |||
335 | dw_apb_clocksource_start(dw_cs); | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * dw_apb_clocksource_init() - use an APB timer as a clocksource. | ||
340 | * | ||
341 | * @rating: The rating to give the clocksource. | ||
342 | * @name: The name for the clocksource. | ||
343 | * @base: The I/O base for the timer registers. | ||
344 | * @freq: The frequency that the timer counts at. | ||
345 | * | ||
346 | * This creates a clocksource using an APB timer but does not yet register it | ||
347 | * with the clocksource system. This should be done with | ||
348 | * dw_apb_clocksource_register() as the next step. | ||
349 | */ | ||
350 | struct dw_apb_clocksource * | ||
351 | dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, | ||
352 | unsigned long freq) | ||
353 | { | ||
354 | struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL); | ||
355 | |||
356 | if (!dw_cs) | ||
357 | return NULL; | ||
358 | |||
359 | dw_cs->timer.base = base; | ||
360 | dw_cs->timer.freq = freq; | ||
361 | dw_cs->cs.name = name; | ||
362 | dw_cs->cs.rating = rating; | ||
363 | dw_cs->cs.read = __apbt_read_clocksource; | ||
364 | dw_cs->cs.mask = CLOCKSOURCE_MASK(32); | ||
365 | dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
366 | dw_cs->cs.resume = apbt_restart_clocksource; | ||
367 | |||
368 | return dw_cs; | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * dw_apb_clocksource_register() - register the APB clocksource. | ||
373 | * | ||
374 | * @dw_cs: The clocksource to register. | ||
375 | */ | ||
376 | void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs) | ||
377 | { | ||
378 | clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq); | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * dw_apb_clocksource_read() - read the current value of a clocksource. | ||
383 | * | ||
384 | * @dw_cs: The clocksource to read. | ||
385 | */ | ||
386 | cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs) | ||
387 | { | ||
388 | return (cycle_t)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * dw_apb_clocksource_unregister() - unregister and free a clocksource. | ||
393 | * | ||
394 | * @dw_cs: The clocksource to unregister/free. | ||
395 | */ | ||
396 | void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs) | ||
397 | { | ||
398 | clocksource_unregister(&dw_cs->cs); | ||
399 | |||
400 | kfree(dw_cs); | ||
401 | } | ||
diff --git a/include/linux/dw_apb_timer.h b/include/linux/dw_apb_timer.h new file mode 100644 index 000000000000..49638ea3b776 --- /dev/null +++ b/include/linux/dw_apb_timer.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * (C) Copyright 2009 Intel Corporation | ||
3 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
4 | * | ||
5 | * Shared with ARM platforms, Jamie Iles, Picochip 2011 | ||
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 | * Support for the Synopsys DesignWare APB Timers. | ||
12 | */ | ||
13 | #ifndef __DW_APB_TIMER_H__ | ||
14 | #define __DW_APB_TIMER_H__ | ||
15 | |||
16 | #include <linux/clockchips.h> | ||
17 | #include <linux/clocksource.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | |||
20 | #define APBTMRS_REG_SIZE 0x14 | ||
21 | |||
22 | struct dw_apb_timer { | ||
23 | void __iomem *base; | ||
24 | unsigned long freq; | ||
25 | int irq; | ||
26 | }; | ||
27 | |||
28 | struct dw_apb_clock_event_device { | ||
29 | struct clock_event_device ced; | ||
30 | struct dw_apb_timer timer; | ||
31 | struct irqaction irqaction; | ||
32 | void (*eoi)(struct dw_apb_timer *); | ||
33 | }; | ||
34 | |||
35 | struct dw_apb_clocksource { | ||
36 | struct dw_apb_timer timer; | ||
37 | struct clocksource cs; | ||
38 | }; | ||
39 | |||
40 | void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced); | ||
41 | void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced); | ||
42 | void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced); | ||
43 | void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced); | ||
44 | |||
45 | struct dw_apb_clock_event_device * | ||
46 | dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, | ||
47 | void __iomem *base, int irq, unsigned long freq); | ||
48 | struct dw_apb_clocksource * | ||
49 | dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, | ||
50 | unsigned long freq); | ||
51 | void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs); | ||
52 | void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs); | ||
53 | cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs); | ||
54 | void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs); | ||
55 | |||
56 | #endif /* __DW_APB_TIMER_H__ */ | ||