in kernel/leon_kernel.c [305:472]
void __init leon_init_timers(void)
{
int irq, eirq;
struct device_node *rootnp, *np, *nnp;
struct property *pp;
int len;
int icsel;
int ampopts;
int err;
u32 config;
u32 ctrl;
sparc_config.get_cycles_offset = leon_cycles_offset;
sparc_config.cs_period = 1000000 / HZ;
sparc_config.features |= FEAT_L10_CLOCKSOURCE;
#ifndef CONFIG_SMP
sparc_config.features |= FEAT_L10_CLOCKEVENT;
#endif
leondebug_irq_disable = 0;
leon_debug_irqout = 0;
master_l10_counter = (u32 __iomem *)&dummy_master_l10_counter;
dummy_master_l10_counter = 0;
rootnp = of_find_node_by_path("/ambapp0");
if (!rootnp)
goto bad;
/* Find System ID: GRLIB build ID and optional CHIP ID */
pp = of_find_property(rootnp, "systemid", &len);
if (pp)
amba_system_id = *(unsigned long *)pp->value;
/* Find IRQMP IRQ Controller Registers base adr otherwise bail out */
np = of_find_node_by_name(rootnp, "GAISLER_IRQMP");
if (!np) {
np = of_find_node_by_name(rootnp, "01_00d");
if (!np)
goto bad;
}
pp = of_find_property(np, "reg", &len);
if (!pp)
goto bad;
leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value;
/* Find GPTIMER Timer Registers base address otherwise bail out. */
nnp = rootnp;
retry:
np = of_find_node_by_name(nnp, "GAISLER_GPTIMER");
if (!np) {
np = of_find_node_by_name(nnp, "01_011");
if (!np)
goto bad;
}
ampopts = 0;
pp = of_find_property(np, "ampopts", &len);
if (pp) {
ampopts = *(int *)pp->value;
if (ampopts == 0) {
/* Skip this instance, resource already
* allocated by other OS */
nnp = np;
goto retry;
}
}
/* Select Timer-Instance on Timer Core. Default is zero */
leon3_gptimer_idx = ampopts & 0x7;
pp = of_find_property(np, "reg", &len);
if (pp)
leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **)
pp->value;
pp = of_find_property(np, "interrupts", &len);
if (pp)
leon3_gptimer_irq = *(unsigned int *)pp->value;
if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq))
goto bad;
ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
ctrl | LEON3_GPTIMER_CTRL_PENDING);
ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
if ((ctrl & LEON3_GPTIMER_CTRL_PENDING) != 0)
leon3_gptimer_ackmask = ~LEON3_GPTIMER_CTRL_PENDING;
else
leon3_gptimer_ackmask = ~0;
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
(((1000000 / HZ) - 1)));
LEON3_BYPASS_STORE_PA(
&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);
/*
* The IRQ controller may (if implemented) consist of multiple
* IRQ controllers, each mapped on a 4Kb boundary.
* Each CPU may be routed to different IRQCTRLs, however
* we assume that all CPUs (in SMP system) is routed to the
* same IRQ Controller, and for non-SMP only one IRQCTRL is
* accessed anyway.
* In AMP systems, Linux must run on CPU0 for the time being.
*/
icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[boot_cpu_id/8]);
icsel = (icsel >> ((7 - (boot_cpu_id&0x7)) * 4)) & 0xf;
leon3_irqctrl_regs += icsel;
/* Mask all IRQs on boot-cpu IRQ controller */
LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[boot_cpu_id], 0);
/* Probe extended IRQ controller */
eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus)
>> 16) & 0xf;
if (eirq != 0)
leon_eirq_setup(eirq);
#ifdef CONFIG_SMP
{
unsigned long flags;
/*
* In SMP, sun4m adds a IPI handler to IRQ trap handler that
* LEON never must take, sun4d and LEON overwrites the branch
* with a NOP.
*/
local_irq_save(flags);
patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
local_ops->cache_all();
local_irq_restore(flags);
}
#endif
config = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config);
if (config & (1 << LEON3_GPTIMER_SEPIRQ))
leon3_gptimer_irq += leon3_gptimer_idx;
else if ((config & LEON3_GPTIMER_TIMERS) > 1)
pr_warn("GPTIMER uses shared irqs, using other timers of the same core will fail.\n");
#ifdef CONFIG_SMP
/* Install per-cpu IRQ handler for broadcasted ticker */
irq = leon_build_device_irq(leon3_gptimer_irq, handle_percpu_irq,
"per-cpu", 0);
err = request_irq(irq, leon_percpu_timer_ce_interrupt,
IRQF_PERCPU | IRQF_TIMER, "timer", NULL);
#else
irq = _leon_build_device_irq(NULL, leon3_gptimer_irq);
err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL);
#endif
if (err) {
pr_err("Unable to attach timer IRQ%d\n", irq);
prom_halt();
}
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
LEON3_GPTIMER_EN |
LEON3_GPTIMER_RL |
LEON3_GPTIMER_LD |
LEON3_GPTIMER_IRQEN);
return;
bad:
printk(KERN_ERR "No Timer/irqctrl found\n");
BUG();
return;
}