staticint __init dmtimer_systimer_reset(struct dmtimer_systimer *t)
{ int ret;
if (dmtimer_systimer_revision1(t))
ret = dmtimer_systimer_type1_reset(t); else
ret = dmtimer_systimer_type2_reset(t); if (ret < 0) {
pr_err("%s failed with %i\n", __func__, ret);
/* * Check if the SoC als has a usable working 32 KiHz counter. The 32 KiHz * counter is handled by timer-ti-32k, but we need to detect it as it * affects the preferred dmtimer system timer configuration. There is * typically no use for a dmtimer clocksource if the 32 KiHz counter is * present, except on am437x as described below.
*/ staticvoid __init dmtimer_systimer_check_counter32k(void)
{ struct device_node *np;
if (counter_32k) return;
np = of_find_matching_node(NULL, counter_match_table); if (!np) {
counter_32k = -ENODEV;
return;
}
if (of_device_is_available(np))
counter_32k = 1; else
counter_32k = -ENODEV;
/* * Checks that system timers are configured to not reset and idle during * the generic timer-ti-dm device driver probe. And that the system timer * source clocks are properly configured. Also, let's not hog any DSP and * PWM capable timers unnecessarily as system timers.
*/ staticbool __init dmtimer_is_preferred(struct device_node *np)
{ if (!of_device_is_available(np)) returnfalse;
if (!of_property_read_bool(np->parent, "ti,no-reset-on-init")) returnfalse;
if (!of_property_read_bool(np->parent, "ti,no-idle")) returnfalse;
/* Secure gptimer12 is always clocked with a fixed source */ if (!of_property_read_bool(np, "ti,timer-secure")) { if (!of_property_present(np, "assigned-clocks")) returnfalse;
if (!of_property_present(np, "assigned-clock-parents")) returnfalse;
}
if (of_property_read_bool(np, "ti,timer-dsp")) returnfalse;
if (of_property_read_bool(np, "ti,timer-pwm")) returnfalse;
returntrue;
}
/* * Finds the first available usable always-on timer, and assigns it to either * clockevent or clocksource depending if the counter_32k is available on the * SoC or not. * * Some omap3 boards with unreliable oscillator must not use the counter_32k * or dmtimer1 with 32 KiHz source. Additionally, the boards with unreliable * oscillator should really set counter_32k as disabled, and delete dmtimer1 * ti,always-on property, but let's not count on it. For these quirky cases, * we prefer using the always-on secure dmtimer12 with the internal 32 KiHz * clock as the clocksource, and any available dmtimer as clockevent. * * For am437x, we are using am335x style dmtimer clocksource. It is unclear * if this quirk handling is really needed, but let's change it separately * based on testing as it might cause side effects.
*/ staticvoid __init dmtimer_systimer_assign_alwon(void)
{ struct device_node *np;
u32 pa = 0; bool quirk_unreliable_oscillator = false;
/* Quirk unreliable 32 KiHz oscillator with incomplete dts */ if (of_machine_is_compatible("ti,omap3-beagle-ab4")) {
quirk_unreliable_oscillator = true;
counter_32k = -ENODEV;
}
/* Quirk am437x using am335x style dmtimer clocksource */ if (of_machine_is_compatible("ti,am43"))
counter_32k = -ENODEV;
for_each_matching_node(np, dmtimer_match_table) { struct resource res; if (!dmtimer_is_preferred(np)) continue;
if (!of_property_read_bool(np, "ti,timer-alwon")) continue;
if (of_address_to_resource(np, 0, &res)) continue;
pa = res.start;
/* Quirky omap3 boards must use dmtimer12 */ if (quirk_unreliable_oscillator && pa == 0x48318000) continue;
of_node_put(np); break;
}
/* Usually no need for dmtimer clocksource if we have counter32 */ if (counter_32k >= 0) {
clockevent = pa;
clocksource = 0;
} else {
clocksource = pa;
clockevent = DMTIMER_INST_DONT_CARE;
}
}
/* Finds the first usable dmtimer, used for the don't care case */ static u32 __init dmtimer_systimer_find_first_available(void)
{ struct device_node *np;
u32 pa = 0;
for_each_matching_node(np, dmtimer_match_table) { struct resource res; if (!dmtimer_is_preferred(np)) continue;
if (of_address_to_resource(np, 0, &res)) continue;
if (res.start == clocksource || res.start == clockevent) continue;
pa = res.start;
of_node_put(np); break;
}
return pa;
}
/* Selects the best clocksource and clockevent to use */ staticvoid __init dmtimer_systimer_select_best(void)
{
dmtimer_systimer_check_counter32k();
dmtimer_systimer_assign_alwon();
if (clockevent == DMTIMER_INST_DONT_CARE)
clockevent = dmtimer_systimer_find_first_available();
if (!of_device_is_compatible(np->parent, "ti,sysc")) return -EINVAL;
t->base = of_iomap(np, 0); if (!t->base) return -ENXIO;
/* * Enable optional assigned-clock-parents configured at the timer * node level. For regular device drivers, this is done automatically * by bus related code such as platform_drv_probe().
*/
error = of_clk_set_defaults(np, false); if (error < 0)
pr_err("%s: clock source init failed: %i\n", __func__, error);
/* For ti-sysc, we have timer clocks at the parent module level */
error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate); if (error) goto err_unmap;
t->rate = rate;
error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate); if (error) goto err_unmap;
/* Looks like we need to first set the load value separately */ while (readl_relaxed(pend) & WP_TLDR)
cpu_relax();
writel_relaxed(clkevt->period, t->base + t->load);
while (readl_relaxed(pend) & WP_TCRR)
cpu_relax();
writel_relaxed(clkevt->period, t->base + t->counter);
/* * We mostly use cpuidle_coupled with ARM local timers for runtime, * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here.
*/
dev->features = features;
dev->rating = rating;
dev->set_next_event = dmtimer_set_next_event;
dev->set_state_shutdown = dmtimer_clockevent_shutdown;
dev->set_state_periodic = dmtimer_set_periodic;
dev->set_state_oneshot = dmtimer_clockevent_shutdown;
dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown;
dev->tick_resume = dmtimer_clockevent_shutdown;
dev->cpumask = cpumask;
dev->irq = irq_of_parse_and_map(np, 0); if (!dev->irq) return -ENXIO;
error = dmtimer_systimer_setup(np, &clkevt->t); if (error) return error;
/* * For clock-event timers we never read the timer counter and * so we are not impacted by errata i103 and i767. Therefore, * we can safely ignore this errata for clock-event timers.
*/
writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl);
if (clocksource_register_hz(dev, t->rate))
pr_err("Could not register clocksource %pOF\n", np);
return 0;
err_out_free:
kfree(clksrc);
return -ENODEV;
}
/* * To detect between a clocksource and clockevent, we assume the device tree * has no interrupts configured for a clocksource timer.
*/ staticint __init dmtimer_systimer_init(struct device_node *np)
{ struct resource res;
u32 pa;
/* One time init for the preferred timer configuration */ if (!clocksource && !clockevent)
dmtimer_systimer_select_best();
if (!clocksource && !clockevent) {
pr_err("%s: unable to detect system timers, update dtb?\n",
__func__);
return -EINVAL;
}
of_address_to_resource(np, 0, &res);
pa = (u32)res.start; if (!pa) return -EINVAL;
if (counter_32k <= 0 && clocksource == pa) return dmtimer_clocksource_init(np);
if (clockevent == pa) return dmtimer_clockevent_init(np);
if (of_machine_is_compatible("ti,dra7")) return dmtimer_percpu_quirk_init(np, pa);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.