in timer-tegra.c [251:371]
static int __init tegra_init_timer(struct device_node *np, bool tegra20,
int rating)
{
struct timer_of *to;
int cpu, ret;
to = this_cpu_ptr(&tegra_to);
ret = timer_of_init(np, to);
if (ret)
goto out;
timer_reg_base = timer_of_base(to);
/*
* Configure microsecond timers to have 1MHz clock
* Config register is 0xqqww, where qq is "dividend", ww is "divisor"
* Uses n+1 scheme
*/
switch (timer_of_rate(to)) {
case 12000000:
usec_config = 0x000b; /* (11+1)/(0+1) */
break;
case 12800000:
usec_config = 0x043f; /* (63+1)/(4+1) */
break;
case 13000000:
usec_config = 0x000c; /* (12+1)/(0+1) */
break;
case 16800000:
usec_config = 0x0453; /* (83+1)/(4+1) */
break;
case 19200000:
usec_config = 0x045f; /* (95+1)/(4+1) */
break;
case 26000000:
usec_config = 0x0019; /* (25+1)/(0+1) */
break;
case 38400000:
usec_config = 0x04bf; /* (191+1)/(4+1) */
break;
case 48000000:
usec_config = 0x002f; /* (47+1)/(0+1) */
break;
default:
ret = -EINVAL;
goto out;
}
writel_relaxed(usec_config, timer_reg_base + TIMERUS_USEC_CFG);
for_each_possible_cpu(cpu) {
struct timer_of *cpu_to = per_cpu_ptr(&tegra_to, cpu);
unsigned long flags = IRQF_TIMER | IRQF_NOBALANCING;
unsigned long rate = tegra_rate_for_timer(to, tegra20);
unsigned int base = tegra_base_for_cpu(cpu, tegra20);
unsigned int idx = tegra_irq_idx_for_cpu(cpu, tegra20);
unsigned int irq = irq_of_parse_and_map(np, idx);
if (!irq) {
pr_err("failed to map irq for cpu%d\n", cpu);
ret = -EINVAL;
goto out_irq;
}
cpu_to->clkevt.irq = irq;
cpu_to->clkevt.rating = rating;
cpu_to->clkevt.cpumask = cpumask_of(cpu);
cpu_to->of_base.base = timer_reg_base + base;
cpu_to->of_clk.period = rate / HZ;
cpu_to->of_clk.rate = rate;
irq_set_status_flags(cpu_to->clkevt.irq, IRQ_NOAUTOEN);
ret = request_irq(cpu_to->clkevt.irq, tegra_timer_isr, flags,
cpu_to->clkevt.name, &cpu_to->clkevt);
if (ret) {
pr_err("failed to set up irq for cpu%d: %d\n",
cpu, ret);
irq_dispose_mapping(cpu_to->clkevt.irq);
cpu_to->clkevt.irq = 0;
goto out_irq;
}
}
sched_clock_register(tegra_read_sched_clock, 32, TIMER_1MHz);
ret = clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
"timer_us", TIMER_1MHz, 300, 32,
clocksource_mmio_readl_up);
if (ret)
pr_err("failed to register clocksource: %d\n", ret);
#ifdef CONFIG_ARM
register_current_timer_delay(&tegra_delay_timer);
#endif
ret = cpuhp_setup_state(CPUHP_AP_TEGRA_TIMER_STARTING,
"AP_TEGRA_TIMER_STARTING", tegra_timer_setup,
tegra_timer_stop);
if (ret)
pr_err("failed to set up cpu hp state: %d\n", ret);
return ret;
out_irq:
for_each_possible_cpu(cpu) {
struct timer_of *cpu_to;
cpu_to = per_cpu_ptr(&tegra_to, cpu);
if (cpu_to->clkevt.irq) {
free_irq(cpu_to->clkevt.irq, &cpu_to->clkevt);
irq_dispose_mapping(cpu_to->clkevt.irq);
}
}
to->of_base.base = timer_reg_base;
out:
timer_of_cleanup(to);
return ret;
}