aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/include/asm/timer_32.h43
-rw-r--r--arch/sparc/kernel/sun4m_irq.c121
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
52struct 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
65struct 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
270struct sun4m_timer_percpu {
271 u32 l14_limit;
272 u32 l14_count;
273 u32 l14_limit_noclear;
274 u32 user_timer_start_stop;
275};
276
277static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
278
279struct 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
287static 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
274static struct sun4m_timer_regs *sun4m_timers;
275unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 292unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
276 293
277static void sun4m_clear_clock_irq(void) 294static 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
283static void sun4m_clear_profile_irq(int cpu) 299static 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
290static void sun4m_load_profile_irq(int cpu, unsigned int limit) 304static 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
295static void __init sun4m_init_timers(irq_handler_t counter_fn) 309static 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;