void __init leon_init_timers()

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;
}