diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/include/asm/timer_32.h | 43 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4m_irq.c | 121 |
2 files changed, 57 insertions, 107 deletions
diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h index adab3def007c..8906e987ef82 100644 --- a/arch/sparc/include/asm/timer_32.h +++ b/arch/sparc/include/asm/timer_32.h | |||
@@ -35,49 +35,6 @@ struct sun4c_timer_info { | |||
35 | 35 | ||
36 | #define SUN_TIMER_PHYSADDR 0xf3000000 | 36 | #define SUN_TIMER_PHYSADDR 0xf3000000 |
37 | 37 | ||
38 | /* A sun4m has two blocks of registers which are probably of the same | ||
39 | * structure. LSI Logic's L64851 is told to _decrement_ from the limit | ||
40 | * value. Aurora behaves similarly but its limit value is compacted in | ||
41 | * other fashion (it's wider). Documented fields are defined here. | ||
42 | */ | ||
43 | |||
44 | /* As with the interrupt register, we have two classes of timer registers | ||
45 | * which are per-cpu and master. Per-cpu timers only hit that cpu and are | ||
46 | * only level 14 ticks, master timer hits all cpus and is level 10. | ||
47 | */ | ||
48 | |||
49 | #define SUN4M_PRM_CNT_L 0x80000000 | ||
50 | #define SUN4M_PRM_CNT_LVALUE 0x7FFFFC00 | ||
51 | |||
52 | struct sun4m_timer_percpu_info { | ||
53 | __volatile__ unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */ | ||
54 | __volatile__ unsigned int l14_cur_count; | ||
55 | |||
56 | /* This register appears to be write only and/or inaccessible | ||
57 | * on Uni-Processor sun4m machines. | ||
58 | */ | ||
59 | __volatile__ unsigned int l14_limit_noclear; /* Data access error is here */ | ||
60 | |||
61 | __volatile__ unsigned int cntrl; /* =1 after POST on Aurora */ | ||
62 | __volatile__ unsigned char space[PAGE_SIZE - 16]; | ||
63 | }; | ||
64 | |||
65 | struct sun4m_timer_regs { | ||
66 | struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS]; | ||
67 | volatile unsigned int l10_timer_limit; | ||
68 | volatile unsigned int l10_cur_count; | ||
69 | |||
70 | /* Again, this appears to be write only and/or inaccessible | ||
71 | * on uni-processor sun4m machines. | ||
72 | */ | ||
73 | volatile unsigned int l10_limit_noclear; | ||
74 | |||
75 | /* This register too, it must be magic. */ | ||
76 | volatile unsigned int foobar; | ||
77 | |||
78 | volatile unsigned int cfg; /* equals zero at boot time... */ | ||
79 | }; | ||
80 | |||
81 | #define SUN4D_PRM_CNT_L 0x80000000 | 38 | #define SUN4D_PRM_CNT_L 0x80000000 |
82 | #define SUN4D_PRM_CNT_LVALUE 0x7FFFFC00 | 39 | #define SUN4D_PRM_CNT_LVALUE 0x7FFFFC00 |
83 | 40 | ||
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 3481feca3354..5b17146f0c1f 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c | |||
@@ -267,95 +267,88 @@ static void sun4m_set_udt(int cpu) | |||
267 | } | 267 | } |
268 | #endif | 268 | #endif |
269 | 269 | ||
270 | struct sun4m_timer_percpu { | ||
271 | u32 l14_limit; | ||
272 | u32 l14_count; | ||
273 | u32 l14_limit_noclear; | ||
274 | u32 user_timer_start_stop; | ||
275 | }; | ||
276 | |||
277 | static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS]; | ||
278 | |||
279 | struct sun4m_timer_global { | ||
280 | u32 l10_limit; | ||
281 | u32 l10_count; | ||
282 | u32 l10_limit_noclear; | ||
283 | u32 reserved; | ||
284 | u32 timer_config; | ||
285 | }; | ||
286 | |||
287 | static struct sun4m_timer_global __iomem *timers_global; | ||
288 | |||
270 | #define OBIO_INTR 0x20 | 289 | #define OBIO_INTR 0x20 |
271 | #define TIMER_IRQ (OBIO_INTR | 10) | 290 | #define TIMER_IRQ (OBIO_INTR | 10) |
272 | #define PROFILE_IRQ (OBIO_INTR | 14) | ||
273 | 291 | ||
274 | static struct sun4m_timer_regs *sun4m_timers; | ||
275 | unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); | 292 | unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); |
276 | 293 | ||
277 | static void sun4m_clear_clock_irq(void) | 294 | static void sun4m_clear_clock_irq(void) |
278 | { | 295 | { |
279 | volatile unsigned int clear_intr; | 296 | sbus_readl(&timers_global->l10_limit); |
280 | clear_intr = sun4m_timers->l10_timer_limit; | ||
281 | } | 297 | } |
282 | 298 | ||
283 | static void sun4m_clear_profile_irq(int cpu) | 299 | static void sun4m_clear_profile_irq(int cpu) |
284 | { | 300 | { |
285 | volatile unsigned int clear; | 301 | sbus_readl(&timers_percpu[cpu]->l14_limit); |
286 | |||
287 | clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit; | ||
288 | } | 302 | } |
289 | 303 | ||
290 | static void sun4m_load_profile_irq(int cpu, unsigned int limit) | 304 | static void sun4m_load_profile_irq(int cpu, unsigned int limit) |
291 | { | 305 | { |
292 | sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; | 306 | sbus_writel(limit, &timers_percpu[cpu]->l14_limit); |
293 | } | 307 | } |
294 | 308 | ||
295 | static void __init sun4m_init_timers(irq_handler_t counter_fn) | 309 | static void __init sun4m_init_timers(irq_handler_t counter_fn) |
296 | { | 310 | { |
297 | int reg_count, irq, cpu; | 311 | struct device_node *dp = of_find_node_by_name(NULL, "counter"); |
298 | struct linux_prom_registers cnt_regs[PROMREG_MAX]; | 312 | int i, err, len, num_cpu_timers; |
299 | int obio_node, cnt_node; | 313 | const u32 *addr; |
300 | struct resource r; | ||
301 | 314 | ||
302 | cnt_node = 0; | 315 | if (!dp) { |
303 | if((obio_node = | 316 | printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n"); |
304 | prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || | 317 | return; |
305 | (obio_node = prom_getchild (obio_node)) == 0 || | ||
306 | (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { | ||
307 | prom_printf("Cannot find /obio/counter node\n"); | ||
308 | prom_halt(); | ||
309 | } | 318 | } |
310 | reg_count = prom_getproperty(cnt_node, "reg", | 319 | |
311 | (void *) cnt_regs, sizeof(cnt_regs)); | 320 | addr = of_get_property(dp, "address", &len); |
312 | reg_count = (reg_count/sizeof(struct linux_prom_registers)); | 321 | if (!addr) { |
313 | 322 | printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n"); | |
314 | /* Apply the obio ranges to the timer registers. */ | 323 | return; |
315 | prom_apply_obio_ranges(cnt_regs, reg_count); | ||
316 | |||
317 | cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; | ||
318 | cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; | ||
319 | cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; | ||
320 | for(obio_node = 1; obio_node < 4; obio_node++) { | ||
321 | cnt_regs[obio_node].phys_addr = | ||
322 | cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; | ||
323 | cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; | ||
324 | cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; | ||
325 | } | 324 | } |
326 | 325 | ||
327 | memset((char*)&r, 0, sizeof(struct resource)); | 326 | num_cpu_timers = (len / sizeof(u32)) - 1; |
328 | /* Map the per-cpu Counter registers. */ | 327 | for (i = 0; i < num_cpu_timers; i++) { |
329 | r.flags = cnt_regs[0].which_io; | 328 | timers_percpu[i] = (void __iomem *) |
330 | r.start = cnt_regs[0].phys_addr; | 329 | (unsigned long) addr[i]; |
331 | sun4m_timers = (struct sun4m_timer_regs *) of_ioremap(&r, 0, | ||
332 | PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); | ||
333 | /* Map the system Counter register. */ | ||
334 | /* XXX Here we expect consequent calls to yeld adjusent maps. */ | ||
335 | r.flags = cnt_regs[4].which_io; | ||
336 | r.start = cnt_regs[4].phys_addr; | ||
337 | of_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); | ||
338 | |||
339 | sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); | ||
340 | master_l10_counter = &sun4m_timers->l10_cur_count; | ||
341 | master_l10_limit = &sun4m_timers->l10_timer_limit; | ||
342 | |||
343 | irq = request_irq(TIMER_IRQ, | ||
344 | counter_fn, | ||
345 | (IRQF_DISABLED | SA_STATIC_ALLOC), | ||
346 | "timer", NULL); | ||
347 | if (irq) { | ||
348 | prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); | ||
349 | prom_halt(); | ||
350 | } | 330 | } |
351 | 331 | timers_global = (void __iomem *) | |
352 | if (!cpu_find_by_instance(1, NULL, NULL)) { | 332 | (unsigned long) addr[num_cpu_timers]; |
353 | for(cpu = 0; cpu < 4; cpu++) | 333 | |
354 | sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; | 334 | sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit); |
355 | sun4m_interrupts->set = SUN4M_INT_E14; | 335 | |
356 | } else { | 336 | master_l10_counter = &timers_global->l10_count; |
357 | sun4m_timers->cpu_timers[0].l14_timer_limit = 0; | 337 | master_l10_limit = &timers_global->l10_limit; |
338 | |||
339 | err = request_irq(TIMER_IRQ, counter_fn, | ||
340 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | ||
341 | if (err) { | ||
342 | printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", | ||
343 | err); | ||
344 | return; | ||
358 | } | 345 | } |
346 | |||
347 | for (i = 0; i < num_cpu_timers; i++) | ||
348 | sbus_writel(0, &timers_percpu[i]->l14_limit); | ||
349 | if (num_cpu_timers == 4) | ||
350 | sbus_writel(SUN4M_INT_E14, &sun4m_interrupts->set); | ||
351 | |||
359 | #ifdef CONFIG_SMP | 352 | #ifdef CONFIG_SMP |
360 | { | 353 | { |
361 | unsigned long flags; | 354 | unsigned long flags; |