sparc32: Use PROM infrastructure for probing and mapping sun4d timers.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2008-09-13 22:04:55 -07:00
parent 69c010b245
commit f5f1085720
2 changed files with 85 additions and 71 deletions

View file

@ -35,19 +35,6 @@ struct sun4c_timer_info {
#define SUN_TIMER_PHYSADDR 0xf3000000
#define SUN4D_PRM_CNT_L 0x80000000
#define SUN4D_PRM_CNT_LVALUE 0x7FFFFC00
struct sun4d_timer_regs {
volatile unsigned int l10_timer_limit;
volatile unsigned int l10_cur_countx;
volatile unsigned int l10_limit_noclear;
volatile unsigned int ctrl;
volatile unsigned int l10_cur_count;
};
extern struct sun4d_timer_regs *sun4d_timers;
extern __volatile__ unsigned int *master_l10_counter;
extern __volatile__ unsigned int *master_l10_limit;

View file

@ -45,7 +45,16 @@
/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
/* #define DISTRIBUTE_IRQS */
struct sun4d_timer_regs *sun4d_timers;
struct sun4d_timer_regs {
u32 l10_timer_limit;
u32 l10_cur_countx;
u32 l10_limit_noclear;
u32 ctrl;
u32 l10_cur_count;
};
static struct sun4d_timer_regs __iomem *sun4d_timers;
#define TIMER_IRQ 10
#define MAX_STATIC_ALLOC 4
@ -446,8 +455,7 @@ void __init sun4d_distribute_irqs(void)
static void sun4d_clear_clock_irq(void)
{
volatile unsigned int clear_intr;
clear_intr = sun4d_timers->l10_timer_limit;
sbus_readl(&sun4d_timers->l10_timer_limit);
}
static void sun4d_clear_profile_irq(int cpu)
@ -460,73 +468,92 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
bw_set_prof_limit(cpu, limit);
}
static void __init sun4d_init_timers(irq_handler_t counter_fn)
static void __init sun4d_load_profile_irqs(void)
{
int irq;
int cpu;
struct resource r;
int mid;
int cpu = 0, mid;
/* Map the User Timer registers. */
memset(&r, 0, sizeof(r));
#ifdef CONFIG_SMP
r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
#else
r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
#endif
r.flags = 0xf;
sun4d_timers = (struct sun4d_timer_regs *) of_ioremap(&r, 0,
PAGE_SIZE, "user timer");
sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
master_l10_counter = &sun4d_timers->l10_cur_count;
master_l10_limit = &sun4d_timers->l10_timer_limit;
irq = request_irq(TIMER_IRQ,
counter_fn,
(IRQF_DISABLED | SA_STATIC_ALLOC),
"timer", NULL);
if (irq) {
prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
prom_halt();
}
/* Enable user timer free run for CPU 0 in BW */
/* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
cpu = 0;
while (!cpu_find_by_instance(cpu, NULL, &mid)) {
sun4d_load_profile_irq(mid >> 3, 0);
cpu++;
}
}
static void __init sun4d_fixup_trap_table(void)
{
#ifdef CONFIG_SMP
{
unsigned long flags;
extern unsigned long lvl14_save[4];
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
extern unsigned int real_irq_entry[], smp4d_ticker[];
extern unsigned int patchme_maybe_smp_msg[];
unsigned long flags;
extern unsigned long lvl14_save[4];
struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
extern unsigned int real_irq_entry[], smp4d_ticker[];
extern unsigned int patchme_maybe_smp_msg[];
/* Adjust so that we jump directly to smp4d_ticker */
lvl14_save[2] += smp4d_ticker - real_irq_entry;
/* Adjust so that we jump directly to smp4d_ticker */
lvl14_save[2] += smp4d_ticker - real_irq_entry;
/* For SMP we use the level 14 ticker, however the bootup code
* has copied the firmware's level 14 vector into the boot cpu's
* trap table, we must fix this now or we get squashed.
*/
local_irq_save(flags);
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
trap_table->inst_one = lvl14_save[0];
trap_table->inst_two = lvl14_save[1];
trap_table->inst_three = lvl14_save[2];
trap_table->inst_four = lvl14_save[3];
local_flush_cache_all();
local_irq_restore(flags);
}
/* For SMP we use the level 14 ticker, however the bootup code
* has copied the firmware's level 14 vector into the boot cpu's
* trap table, we must fix this now or we get squashed.
*/
local_irq_save(flags);
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
trap_table->inst_one = lvl14_save[0];
trap_table->inst_two = lvl14_save[1];
trap_table->inst_three = lvl14_save[2];
trap_table->inst_four = lvl14_save[3];
local_flush_cache_all();
local_irq_restore(flags);
#endif
}
static void __init sun4d_init_timers(irq_handler_t counter_fn)
{
struct device_node *dp;
struct resource res;
const u32 *reg;
int err;
dp = of_find_node_by_name(NULL, "cpu-unit");
if (!dp) {
prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
prom_halt();
}
/* Which cpu-unit we use is arbitrary, we can view the bootbus timer
* registers via any cpu's mapping. The first 'reg' property is the
* bootbus.
*/
reg = of_get_property(dp, "reg", NULL);
if (!reg) {
prom_printf("sun4d_init_timers: No reg property\n");
prom_halt();
}
res.start = reg[1];
res.end = reg[2] - 1;
res.flags = reg[0] & 0xff;
sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
sizeof(struct sun4d_timer_regs), "user timer");
if (!sun4d_timers) {
prom_printf("sun4d_init_timers: Can't map timer regs\n");
prom_halt();
}
sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
master_l10_counter = &sun4d_timers->l10_cur_count;
master_l10_limit = &sun4d_timers->l10_timer_limit;
err = request_irq(TIMER_IRQ, counter_fn,
(IRQF_DISABLED | SA_STATIC_ALLOC),
"timer", NULL);
if (err) {
prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
prom_halt();
}
sun4d_load_profile_irqs();
sun4d_fixup_trap_table();
}
void __init sun4d_init_sbi_irq(void)
{
struct device_node *dp;