diff options
| -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; |
