|
@@ -321,3 +321,196 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
|
|
|
clkev.errata = omap_dm_timer_get_errata();
|
|
|
|
|
|
/*
|
|
|
+ * 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.
|
|
|
+ */
|
|
|
+ __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767);
|
|
|
+
|
|
|
+ res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property,
|
|
|
+ OMAP_TIMER_POSTED);
|
|
|
+ BUG_ON(res);
|
|
|
+
|
|
|
+ omap2_gp_timer_irq.dev_id = &clkev;
|
|
|
+ setup_irq(clkev.irq, &omap2_gp_timer_irq);
|
|
|
+
|
|
|
+ __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW);
|
|
|
+
|
|
|
+ clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC,
|
|
|
+ clockevent_gpt.shift);
|
|
|
+ clockevent_gpt.max_delta_ns =
|
|
|
+ clockevent_delta2ns(0xffffffff, &clockevent_gpt);
|
|
|
+ clockevent_gpt.min_delta_ns =
|
|
|
+ clockevent_delta2ns(3, &clockevent_gpt);
|
|
|
+ /* Timer internal resynch latency. */
|
|
|
+
|
|
|
+ clockevent_gpt.cpumask = cpu_possible_mask;
|
|
|
+ clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev);
|
|
|
+ clockevents_register_device(&clockevent_gpt);
|
|
|
+
|
|
|
+ pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz\n",
|
|
|
+ gptimer_id, clkev.rate);
|
|
|
+}
|
|
|
+
|
|
|
+/* Clocksource code */
|
|
|
+static struct omap_dm_timer clksrc;
|
|
|
+static bool use_gptimer_clksrc;
|
|
|
+
|
|
|
+/*
|
|
|
+ * clocksource
|
|
|
+ */
|
|
|
+static cycle_t clocksource_read_cycles(struct clocksource *cs)
|
|
|
+{
|
|
|
+ return (cycle_t)__omap_dm_timer_read_counter(&clksrc,
|
|
|
+ OMAP_TIMER_NONPOSTED);
|
|
|
+}
|
|
|
+
|
|
|
+static struct clocksource clocksource_gpt = {
|
|
|
+ .name = "gp_timer",
|
|
|
+ .rating = 300,
|
|
|
+ .read = clocksource_read_cycles,
|
|
|
+ .mask = CLOCKSOURCE_MASK(32),
|
|
|
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
|
|
+};
|
|
|
+
|
|
|
+static u32 notrace dmtimer_read_sched_clock(void)
|
|
|
+{
|
|
|
+ if (clksrc.reserved)
|
|
|
+ return __omap_dm_timer_read_counter(&clksrc,
|
|
|
+ OMAP_TIMER_NONPOSTED);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct of_device_id omap_counter_match[] __initdata = {
|
|
|
+ { .compatible = "ti,omap-counter32k", },
|
|
|
+ { }
|
|
|
+};
|
|
|
+
|
|
|
+/* Setup free-running counter for clocksource */
|
|
|
+static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ struct device_node *np = NULL;
|
|
|
+ struct omap_hwmod *oh;
|
|
|
+ void __iomem *vbase;
|
|
|
+ const char *oh_name = "counter_32k";
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If device-tree is present, then search the DT blob
|
|
|
+ * to see if the 32kHz counter is supported.
|
|
|
+ */
|
|
|
+ if (of_have_populated_dt()) {
|
|
|
+ np = omap_get_timer_dt(omap_counter_match, NULL);
|
|
|
+ if (!np)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
|
|
|
+ if (!oh_name)
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * First check hwmod data is available for sync32k counter
|
|
|
+ */
|
|
|
+ oh = omap_hwmod_lookup(oh_name);
|
|
|
+ if (!oh || oh->slaves_cnt == 0)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ omap_hwmod_setup_one(oh_name);
|
|
|
+
|
|
|
+ if (np) {
|
|
|
+ vbase = of_iomap(np, 0);
|
|
|
+ of_node_put(np);
|
|
|
+ } else {
|
|
|
+ vbase = omap_hwmod_get_mpu_rt_va(oh);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!vbase) {
|
|
|
+ pr_warn("%s: failed to get counter_32k resource\n", __func__);
|
|
|
+ return -ENXIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = omap_hwmod_enable(oh);
|
|
|
+ if (ret) {
|
|
|
+ pr_warn("%s: failed to enable counter_32k module (%d)\n",
|
|
|
+ __func__, ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = omap_init_clocksource_32k(vbase);
|
|
|
+ if (ret) {
|
|
|
+ pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n",
|
|
|
+ __func__, ret);
|
|
|
+ omap_hwmod_idle(oh);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void __init omap2_gptimer_clocksource_init(int gptimer_id,
|
|
|
+ const char *fck_source)
|
|
|
+{
|
|
|
+ int res;
|
|
|
+
|
|
|
+ clksrc.errata = omap_dm_timer_get_errata();
|
|
|
+
|
|
|
+ res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL,
|
|
|
+ OMAP_TIMER_NONPOSTED);
|
|
|
+ BUG_ON(res);
|
|
|
+
|
|
|
+ __omap_dm_timer_load_start(&clksrc,
|
|
|
+ OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0,
|
|
|
+ OMAP_TIMER_NONPOSTED);
|
|
|
+ setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
|
|
|
+
|
|
|
+ if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
|
|
|
+ pr_err("Could not register clocksource %s\n",
|
|
|
+ clocksource_gpt.name);
|
|
|
+ else
|
|
|
+ pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
|
|
|
+ gptimer_id, clksrc.rate);
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
|
|
|
+/*
|
|
|
+ * The realtime counter also called master counter, is a free-running
|
|
|
+ * counter, which is related to real time. It produces the count used
|
|
|
+ * by the CPU local timer peripherals in the MPU cluster. The timer counts
|
|
|
+ * at a rate of 6.144 MHz. Because the device operates on different clocks
|
|
|
+ * in different power modes, the master counter shifts operation between
|
|
|
+ * clocks, adjusting the increment per clock in hardware accordingly to
|
|
|
+ * maintain a constant count rate.
|
|
|
+ */
|
|
|
+static void __init realtime_counter_init(void)
|
|
|
+{
|
|
|
+ void __iomem *base;
|
|
|
+ static struct clk *sys_clk;
|
|
|
+ unsigned long rate;
|
|
|
+ unsigned int reg, num, den;
|
|
|
+
|
|
|
+ base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
|
|
|
+ if (!base) {
|
|
|
+ pr_err("%s: ioremap failed\n", __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sys_clk = clk_get(NULL, "sys_clkin_ck");
|
|
|
+ if (IS_ERR(sys_clk)) {
|
|
|
+ pr_err("%s: failed to get system clock handle\n", __func__);
|
|
|
+ iounmap(base);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ rate = clk_get_rate(sys_clk);
|
|
|
+ /* Numerator/denumerator values refer TRM Realtime Counter section */
|
|
|
+ switch (rate) {
|
|
|
+ case 1200000:
|
|
|
+ num = 64;
|
|
|
+ den = 125;
|
|
|
+ break;
|
|
|
+ case 1300000:
|
|
|
+ num = 768;
|
|
|
+ den = 1625;
|
|
|
+ break;
|
|
|
+ case 19200000:
|
|
|
+ num = 8;
|