152762fbdSTony Lindgren // SPDX-License-Identifier: GPL-2.0+ 252762fbdSTony Lindgren #include <linux/clk.h> 352762fbdSTony Lindgren #include <linux/clocksource.h> 452762fbdSTony Lindgren #include <linux/clockchips.h> 5*25de4ce5STony Lindgren #include <linux/cpuhotplug.h> 652762fbdSTony Lindgren #include <linux/interrupt.h> 752762fbdSTony Lindgren #include <linux/io.h> 852762fbdSTony Lindgren #include <linux/iopoll.h> 952762fbdSTony Lindgren #include <linux/err.h> 1052762fbdSTony Lindgren #include <linux/of.h> 1152762fbdSTony Lindgren #include <linux/of_address.h> 1252762fbdSTony Lindgren #include <linux/of_irq.h> 1352762fbdSTony Lindgren #include <linux/sched_clock.h> 1452762fbdSTony Lindgren 1552762fbdSTony Lindgren #include <linux/clk/clk-conf.h> 1652762fbdSTony Lindgren 1752762fbdSTony Lindgren #include <clocksource/timer-ti-dm.h> 1852762fbdSTony Lindgren #include <dt-bindings/bus/ti-sysc.h> 1952762fbdSTony Lindgren 2052762fbdSTony Lindgren /* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */ 2152762fbdSTony Lindgren #define DMTIMER_TYPE1_ENABLE ((1 << 9) | (SYSC_IDLE_SMART << 3) | \ 2252762fbdSTony Lindgren SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE) 236cfcd556STony Lindgren #define DMTIMER_TYPE1_DISABLE (SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE) 2452762fbdSTony Lindgren #define DMTIMER_TYPE2_ENABLE (SYSC_IDLE_SMART_WKUP << 2) 2552762fbdSTony Lindgren #define DMTIMER_RESET_WAIT 100000 2652762fbdSTony Lindgren 2752762fbdSTony Lindgren #define DMTIMER_INST_DONT_CARE ~0U 2852762fbdSTony Lindgren 2952762fbdSTony Lindgren static int counter_32k; 3052762fbdSTony Lindgren static u32 clocksource; 3152762fbdSTony Lindgren static u32 clockevent; 3252762fbdSTony Lindgren 3352762fbdSTony Lindgren /* 3452762fbdSTony Lindgren * Subset of the timer registers we use. Note that the register offsets 3552762fbdSTony Lindgren * depend on the timer revision detected. 3652762fbdSTony Lindgren */ 3752762fbdSTony Lindgren struct dmtimer_systimer { 3852762fbdSTony Lindgren void __iomem *base; 3952762fbdSTony Lindgren u8 sysc; 4052762fbdSTony Lindgren u8 irq_stat; 4152762fbdSTony Lindgren u8 irq_ena; 4252762fbdSTony Lindgren u8 pend; 4352762fbdSTony Lindgren u8 load; 4452762fbdSTony Lindgren u8 counter; 4552762fbdSTony Lindgren u8 ctrl; 4652762fbdSTony Lindgren u8 wakeup; 4752762fbdSTony Lindgren u8 ifctrl; 486cfcd556STony Lindgren struct clk *fck; 496cfcd556STony Lindgren struct clk *ick; 5052762fbdSTony Lindgren unsigned long rate; 5152762fbdSTony Lindgren }; 5252762fbdSTony Lindgren 5352762fbdSTony Lindgren struct dmtimer_clockevent { 5452762fbdSTony Lindgren struct clock_event_device dev; 5552762fbdSTony Lindgren struct dmtimer_systimer t; 5652762fbdSTony Lindgren u32 period; 5752762fbdSTony Lindgren }; 5852762fbdSTony Lindgren 5952762fbdSTony Lindgren struct dmtimer_clocksource { 6052762fbdSTony Lindgren struct clocksource dev; 6152762fbdSTony Lindgren struct dmtimer_systimer t; 6252762fbdSTony Lindgren unsigned int loadval; 6352762fbdSTony Lindgren }; 6452762fbdSTony Lindgren 6552762fbdSTony Lindgren /* Assumes v1 ip if bits [31:16] are zero */ 6652762fbdSTony Lindgren static bool dmtimer_systimer_revision1(struct dmtimer_systimer *t) 6752762fbdSTony Lindgren { 6852762fbdSTony Lindgren u32 tidr = readl_relaxed(t->base); 6952762fbdSTony Lindgren 7052762fbdSTony Lindgren return !(tidr >> 16); 7152762fbdSTony Lindgren } 7252762fbdSTony Lindgren 7316480515STony Lindgren static void dmtimer_systimer_enable(struct dmtimer_systimer *t) 7416480515STony Lindgren { 7516480515STony Lindgren u32 val; 7616480515STony Lindgren 7716480515STony Lindgren if (dmtimer_systimer_revision1(t)) 7816480515STony Lindgren val = DMTIMER_TYPE1_ENABLE; 7916480515STony Lindgren else 8016480515STony Lindgren val = DMTIMER_TYPE2_ENABLE; 8116480515STony Lindgren 8216480515STony Lindgren writel_relaxed(val, t->base + t->sysc); 8316480515STony Lindgren } 8416480515STony Lindgren 8516480515STony Lindgren static void dmtimer_systimer_disable(struct dmtimer_systimer *t) 8616480515STony Lindgren { 8716480515STony Lindgren if (!dmtimer_systimer_revision1(t)) 8816480515STony Lindgren return; 8916480515STony Lindgren 9016480515STony Lindgren writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc); 9116480515STony Lindgren } 9216480515STony Lindgren 9352762fbdSTony Lindgren static int __init dmtimer_systimer_type1_reset(struct dmtimer_systimer *t) 9452762fbdSTony Lindgren { 9552762fbdSTony Lindgren void __iomem *syss = t->base + OMAP_TIMER_V1_SYS_STAT_OFFSET; 9652762fbdSTony Lindgren int ret; 9752762fbdSTony Lindgren u32 l; 9852762fbdSTony Lindgren 9916480515STony Lindgren dmtimer_systimer_enable(t); 10052762fbdSTony Lindgren writel_relaxed(BIT(1) | BIT(2), t->base + t->ifctrl); 10152762fbdSTony Lindgren ret = readl_poll_timeout_atomic(syss, l, l & BIT(0), 100, 10252762fbdSTony Lindgren DMTIMER_RESET_WAIT); 10352762fbdSTony Lindgren 10452762fbdSTony Lindgren return ret; 10552762fbdSTony Lindgren } 10652762fbdSTony Lindgren 10752762fbdSTony Lindgren /* Note we must use io_base instead of func_base for type2 OCP regs */ 10852762fbdSTony Lindgren static int __init dmtimer_systimer_type2_reset(struct dmtimer_systimer *t) 10952762fbdSTony Lindgren { 11052762fbdSTony Lindgren void __iomem *sysc = t->base + t->sysc; 11152762fbdSTony Lindgren u32 l; 11252762fbdSTony Lindgren 11316480515STony Lindgren dmtimer_systimer_enable(t); 11452762fbdSTony Lindgren l = readl_relaxed(sysc); 11552762fbdSTony Lindgren l |= BIT(0); 11652762fbdSTony Lindgren writel_relaxed(l, sysc); 11752762fbdSTony Lindgren 11852762fbdSTony Lindgren return readl_poll_timeout_atomic(sysc, l, !(l & BIT(0)), 100, 11952762fbdSTony Lindgren DMTIMER_RESET_WAIT); 12052762fbdSTony Lindgren } 12152762fbdSTony Lindgren 12252762fbdSTony Lindgren static int __init dmtimer_systimer_reset(struct dmtimer_systimer *t) 12352762fbdSTony Lindgren { 12452762fbdSTony Lindgren int ret; 12552762fbdSTony Lindgren 12652762fbdSTony Lindgren if (dmtimer_systimer_revision1(t)) 12752762fbdSTony Lindgren ret = dmtimer_systimer_type1_reset(t); 12852762fbdSTony Lindgren else 12952762fbdSTony Lindgren ret = dmtimer_systimer_type2_reset(t); 13052762fbdSTony Lindgren if (ret < 0) { 13152762fbdSTony Lindgren pr_err("%s failed with %i\n", __func__, ret); 13252762fbdSTony Lindgren 13352762fbdSTony Lindgren return ret; 13452762fbdSTony Lindgren } 13552762fbdSTony Lindgren 13652762fbdSTony Lindgren return 0; 13752762fbdSTony Lindgren } 13852762fbdSTony Lindgren 13952762fbdSTony Lindgren static const struct of_device_id counter_match_table[] = { 14052762fbdSTony Lindgren { .compatible = "ti,omap-counter32k" }, 14152762fbdSTony Lindgren { /* Sentinel */ }, 14252762fbdSTony Lindgren }; 14352762fbdSTony Lindgren 14452762fbdSTony Lindgren /* 14552762fbdSTony Lindgren * Check if the SoC als has a usable working 32 KiHz counter. The 32 KiHz 14652762fbdSTony Lindgren * counter is handled by timer-ti-32k, but we need to detect it as it 14752762fbdSTony Lindgren * affects the preferred dmtimer system timer configuration. There is 14852762fbdSTony Lindgren * typically no use for a dmtimer clocksource if the 32 KiHz counter is 14952762fbdSTony Lindgren * present, except on am437x as described below. 15052762fbdSTony Lindgren */ 15152762fbdSTony Lindgren static void __init dmtimer_systimer_check_counter32k(void) 15252762fbdSTony Lindgren { 15352762fbdSTony Lindgren struct device_node *np; 15452762fbdSTony Lindgren 15552762fbdSTony Lindgren if (counter_32k) 15652762fbdSTony Lindgren return; 15752762fbdSTony Lindgren 15852762fbdSTony Lindgren np = of_find_matching_node(NULL, counter_match_table); 15952762fbdSTony Lindgren if (!np) { 16052762fbdSTony Lindgren counter_32k = -ENODEV; 16152762fbdSTony Lindgren 16252762fbdSTony Lindgren return; 16352762fbdSTony Lindgren } 16452762fbdSTony Lindgren 16552762fbdSTony Lindgren if (of_device_is_available(np)) 16652762fbdSTony Lindgren counter_32k = 1; 16752762fbdSTony Lindgren else 16852762fbdSTony Lindgren counter_32k = -ENODEV; 16952762fbdSTony Lindgren 17052762fbdSTony Lindgren of_node_put(np); 17152762fbdSTony Lindgren } 17252762fbdSTony Lindgren 17352762fbdSTony Lindgren static const struct of_device_id dmtimer_match_table[] = { 17452762fbdSTony Lindgren { .compatible = "ti,omap2420-timer", }, 17552762fbdSTony Lindgren { .compatible = "ti,omap3430-timer", }, 17652762fbdSTony Lindgren { .compatible = "ti,omap4430-timer", }, 17752762fbdSTony Lindgren { .compatible = "ti,omap5430-timer", }, 17852762fbdSTony Lindgren { .compatible = "ti,am335x-timer", }, 17952762fbdSTony Lindgren { .compatible = "ti,am335x-timer-1ms", }, 18052762fbdSTony Lindgren { .compatible = "ti,dm814-timer", }, 18152762fbdSTony Lindgren { .compatible = "ti,dm816-timer", }, 18252762fbdSTony Lindgren { /* Sentinel */ }, 18352762fbdSTony Lindgren }; 18452762fbdSTony Lindgren 18552762fbdSTony Lindgren /* 18652762fbdSTony Lindgren * Checks that system timers are configured to not reset and idle during 18752762fbdSTony Lindgren * the generic timer-ti-dm device driver probe. And that the system timer 18852762fbdSTony Lindgren * source clocks are properly configured. Also, let's not hog any DSP and 18952762fbdSTony Lindgren * PWM capable timers unnecessarily as system timers. 19052762fbdSTony Lindgren */ 19152762fbdSTony Lindgren static bool __init dmtimer_is_preferred(struct device_node *np) 19252762fbdSTony Lindgren { 19352762fbdSTony Lindgren if (!of_device_is_available(np)) 19452762fbdSTony Lindgren return false; 19552762fbdSTony Lindgren 19652762fbdSTony Lindgren if (!of_property_read_bool(np->parent, 19752762fbdSTony Lindgren "ti,no-reset-on-init")) 19852762fbdSTony Lindgren return false; 19952762fbdSTony Lindgren 20052762fbdSTony Lindgren if (!of_property_read_bool(np->parent, "ti,no-idle")) 20152762fbdSTony Lindgren return false; 20252762fbdSTony Lindgren 20352762fbdSTony Lindgren /* Secure gptimer12 is always clocked with a fixed source */ 20452762fbdSTony Lindgren if (!of_property_read_bool(np, "ti,timer-secure")) { 20552762fbdSTony Lindgren if (!of_property_read_bool(np, "assigned-clocks")) 20652762fbdSTony Lindgren return false; 20752762fbdSTony Lindgren 20852762fbdSTony Lindgren if (!of_property_read_bool(np, "assigned-clock-parents")) 20952762fbdSTony Lindgren return false; 21052762fbdSTony Lindgren } 21152762fbdSTony Lindgren 21252762fbdSTony Lindgren if (of_property_read_bool(np, "ti,timer-dsp")) 21352762fbdSTony Lindgren return false; 21452762fbdSTony Lindgren 21552762fbdSTony Lindgren if (of_property_read_bool(np, "ti,timer-pwm")) 21652762fbdSTony Lindgren return false; 21752762fbdSTony Lindgren 21852762fbdSTony Lindgren return true; 21952762fbdSTony Lindgren } 22052762fbdSTony Lindgren 22152762fbdSTony Lindgren /* 22252762fbdSTony Lindgren * Finds the first available usable always-on timer, and assigns it to either 22352762fbdSTony Lindgren * clockevent or clocksource depending if the counter_32k is available on the 22452762fbdSTony Lindgren * SoC or not. 22552762fbdSTony Lindgren * 22652762fbdSTony Lindgren * Some omap3 boards with unreliable oscillator must not use the counter_32k 22752762fbdSTony Lindgren * or dmtimer1 with 32 KiHz source. Additionally, the boards with unreliable 22852762fbdSTony Lindgren * oscillator should really set counter_32k as disabled, and delete dmtimer1 22952762fbdSTony Lindgren * ti,always-on property, but let's not count on it. For these quirky cases, 23052762fbdSTony Lindgren * we prefer using the always-on secure dmtimer12 with the internal 32 KiHz 23152762fbdSTony Lindgren * clock as the clocksource, and any available dmtimer as clockevent. 23252762fbdSTony Lindgren * 23352762fbdSTony Lindgren * For am437x, we are using am335x style dmtimer clocksource. It is unclear 23452762fbdSTony Lindgren * if this quirk handling is really needed, but let's change it separately 23552762fbdSTony Lindgren * based on testing as it might cause side effects. 23652762fbdSTony Lindgren */ 23752762fbdSTony Lindgren static void __init dmtimer_systimer_assign_alwon(void) 23852762fbdSTony Lindgren { 23952762fbdSTony Lindgren struct device_node *np; 24052762fbdSTony Lindgren u32 pa = 0; 24152762fbdSTony Lindgren bool quirk_unreliable_oscillator = false; 24252762fbdSTony Lindgren 24352762fbdSTony Lindgren /* Quirk unreliable 32 KiHz oscillator with incomplete dts */ 24452762fbdSTony Lindgren if (of_machine_is_compatible("ti,omap3-beagle") || 24552762fbdSTony Lindgren of_machine_is_compatible("timll,omap3-devkit8000")) { 24652762fbdSTony Lindgren quirk_unreliable_oscillator = true; 24752762fbdSTony Lindgren counter_32k = -ENODEV; 24852762fbdSTony Lindgren } 24952762fbdSTony Lindgren 25052762fbdSTony Lindgren /* Quirk am437x using am335x style dmtimer clocksource */ 25152762fbdSTony Lindgren if (of_machine_is_compatible("ti,am43")) 25252762fbdSTony Lindgren counter_32k = -ENODEV; 25352762fbdSTony Lindgren 25452762fbdSTony Lindgren for_each_matching_node(np, dmtimer_match_table) { 25552762fbdSTony Lindgren if (!dmtimer_is_preferred(np)) 25652762fbdSTony Lindgren continue; 25752762fbdSTony Lindgren 25852762fbdSTony Lindgren if (of_property_read_bool(np, "ti,timer-alwon")) { 25952762fbdSTony Lindgren const __be32 *addr; 26052762fbdSTony Lindgren 26152762fbdSTony Lindgren addr = of_get_address(np, 0, NULL, NULL); 26252762fbdSTony Lindgren pa = of_translate_address(np, addr); 26352762fbdSTony Lindgren if (pa) { 26452762fbdSTony Lindgren /* Quirky omap3 boards must use dmtimer12 */ 26552762fbdSTony Lindgren if (quirk_unreliable_oscillator && 26652762fbdSTony Lindgren pa == 0x48318000) 26752762fbdSTony Lindgren continue; 26852762fbdSTony Lindgren 26952762fbdSTony Lindgren of_node_put(np); 27052762fbdSTony Lindgren break; 27152762fbdSTony Lindgren } 27252762fbdSTony Lindgren } 27352762fbdSTony Lindgren } 27452762fbdSTony Lindgren 27552762fbdSTony Lindgren /* Usually no need for dmtimer clocksource if we have counter32 */ 27652762fbdSTony Lindgren if (counter_32k >= 0) { 27752762fbdSTony Lindgren clockevent = pa; 27852762fbdSTony Lindgren clocksource = 0; 27952762fbdSTony Lindgren } else { 28052762fbdSTony Lindgren clocksource = pa; 28152762fbdSTony Lindgren clockevent = DMTIMER_INST_DONT_CARE; 28252762fbdSTony Lindgren } 28352762fbdSTony Lindgren } 28452762fbdSTony Lindgren 28552762fbdSTony Lindgren /* Finds the first usable dmtimer, used for the don't care case */ 28652762fbdSTony Lindgren static u32 __init dmtimer_systimer_find_first_available(void) 28752762fbdSTony Lindgren { 28852762fbdSTony Lindgren struct device_node *np; 28952762fbdSTony Lindgren const __be32 *addr; 29052762fbdSTony Lindgren u32 pa = 0; 29152762fbdSTony Lindgren 29252762fbdSTony Lindgren for_each_matching_node(np, dmtimer_match_table) { 29352762fbdSTony Lindgren if (!dmtimer_is_preferred(np)) 29452762fbdSTony Lindgren continue; 29552762fbdSTony Lindgren 29652762fbdSTony Lindgren addr = of_get_address(np, 0, NULL, NULL); 29752762fbdSTony Lindgren pa = of_translate_address(np, addr); 29852762fbdSTony Lindgren if (pa) { 29952762fbdSTony Lindgren if (pa == clocksource || pa == clockevent) { 30052762fbdSTony Lindgren pa = 0; 30152762fbdSTony Lindgren continue; 30252762fbdSTony Lindgren } 30352762fbdSTony Lindgren 30452762fbdSTony Lindgren of_node_put(np); 30552762fbdSTony Lindgren break; 30652762fbdSTony Lindgren } 30752762fbdSTony Lindgren } 30852762fbdSTony Lindgren 30952762fbdSTony Lindgren return pa; 31052762fbdSTony Lindgren } 31152762fbdSTony Lindgren 31252762fbdSTony Lindgren /* Selects the best clocksource and clockevent to use */ 31352762fbdSTony Lindgren static void __init dmtimer_systimer_select_best(void) 31452762fbdSTony Lindgren { 31552762fbdSTony Lindgren dmtimer_systimer_check_counter32k(); 31652762fbdSTony Lindgren dmtimer_systimer_assign_alwon(); 31752762fbdSTony Lindgren 31852762fbdSTony Lindgren if (clockevent == DMTIMER_INST_DONT_CARE) 31952762fbdSTony Lindgren clockevent = dmtimer_systimer_find_first_available(); 32052762fbdSTony Lindgren 32152762fbdSTony Lindgren pr_debug("%s: counter_32k: %i clocksource: %08x clockevent: %08x\n", 32252762fbdSTony Lindgren __func__, counter_32k, clocksource, clockevent); 32352762fbdSTony Lindgren } 32452762fbdSTony Lindgren 32552762fbdSTony Lindgren /* Interface clocks are only available on some SoCs variants */ 3266cfcd556STony Lindgren static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t, 3276cfcd556STony Lindgren struct device_node *np, 32852762fbdSTony Lindgren const char *name, 32952762fbdSTony Lindgren unsigned long *rate) 33052762fbdSTony Lindgren { 33152762fbdSTony Lindgren struct clk *clock; 33252762fbdSTony Lindgren unsigned long r; 3336cfcd556STony Lindgren bool is_ick = false; 33452762fbdSTony Lindgren int error; 33552762fbdSTony Lindgren 3366cfcd556STony Lindgren is_ick = !strncmp(name, "ick", 3); 3376cfcd556STony Lindgren 33852762fbdSTony Lindgren clock = of_clk_get_by_name(np, name); 3396cfcd556STony Lindgren if ((PTR_ERR(clock) == -EINVAL) && is_ick) 34052762fbdSTony Lindgren return 0; 34152762fbdSTony Lindgren else if (IS_ERR(clock)) 34252762fbdSTony Lindgren return PTR_ERR(clock); 34352762fbdSTony Lindgren 34452762fbdSTony Lindgren error = clk_prepare_enable(clock); 34552762fbdSTony Lindgren if (error) 34652762fbdSTony Lindgren return error; 34752762fbdSTony Lindgren 34852762fbdSTony Lindgren r = clk_get_rate(clock); 34952762fbdSTony Lindgren if (!r) 35052762fbdSTony Lindgren return -ENODEV; 35152762fbdSTony Lindgren 3526cfcd556STony Lindgren if (is_ick) 3536cfcd556STony Lindgren t->ick = clock; 3546cfcd556STony Lindgren else 3556cfcd556STony Lindgren t->fck = clock; 3566cfcd556STony Lindgren 35752762fbdSTony Lindgren *rate = r; 35852762fbdSTony Lindgren 35952762fbdSTony Lindgren return 0; 36052762fbdSTony Lindgren } 36152762fbdSTony Lindgren 36252762fbdSTony Lindgren static int __init dmtimer_systimer_setup(struct device_node *np, 36352762fbdSTony Lindgren struct dmtimer_systimer *t) 36452762fbdSTony Lindgren { 36552762fbdSTony Lindgren unsigned long rate; 36652762fbdSTony Lindgren u8 regbase; 36752762fbdSTony Lindgren int error; 36852762fbdSTony Lindgren 36952762fbdSTony Lindgren if (!of_device_is_compatible(np->parent, "ti,sysc")) 37052762fbdSTony Lindgren return -EINVAL; 37152762fbdSTony Lindgren 37252762fbdSTony Lindgren t->base = of_iomap(np, 0); 37352762fbdSTony Lindgren if (!t->base) 37452762fbdSTony Lindgren return -ENXIO; 37552762fbdSTony Lindgren 37652762fbdSTony Lindgren /* 37752762fbdSTony Lindgren * Enable optional assigned-clock-parents configured at the timer 37852762fbdSTony Lindgren * node level. For regular device drivers, this is done automatically 37952762fbdSTony Lindgren * by bus related code such as platform_drv_probe(). 38052762fbdSTony Lindgren */ 38152762fbdSTony Lindgren error = of_clk_set_defaults(np, false); 38252762fbdSTony Lindgren if (error < 0) 38352762fbdSTony Lindgren pr_err("%s: clock source init failed: %i\n", __func__, error); 38452762fbdSTony Lindgren 38552762fbdSTony Lindgren /* For ti-sysc, we have timer clocks at the parent module level */ 3866cfcd556STony Lindgren error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate); 38752762fbdSTony Lindgren if (error) 38852762fbdSTony Lindgren goto err_unmap; 38952762fbdSTony Lindgren 39052762fbdSTony Lindgren t->rate = rate; 39152762fbdSTony Lindgren 3926cfcd556STony Lindgren error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate); 39352762fbdSTony Lindgren if (error) 39452762fbdSTony Lindgren goto err_unmap; 39552762fbdSTony Lindgren 39652762fbdSTony Lindgren if (dmtimer_systimer_revision1(t)) { 39752762fbdSTony Lindgren t->irq_stat = OMAP_TIMER_V1_STAT_OFFSET; 39852762fbdSTony Lindgren t->irq_ena = OMAP_TIMER_V1_INT_EN_OFFSET; 39952762fbdSTony Lindgren t->pend = _OMAP_TIMER_WRITE_PEND_OFFSET; 40052762fbdSTony Lindgren regbase = 0; 40152762fbdSTony Lindgren } else { 40252762fbdSTony Lindgren t->irq_stat = OMAP_TIMER_V2_IRQSTATUS; 40352762fbdSTony Lindgren t->irq_ena = OMAP_TIMER_V2_IRQENABLE_SET; 40452762fbdSTony Lindgren regbase = OMAP_TIMER_V2_FUNC_OFFSET; 40552762fbdSTony Lindgren t->pend = regbase + _OMAP_TIMER_WRITE_PEND_OFFSET; 40652762fbdSTony Lindgren } 40752762fbdSTony Lindgren 40852762fbdSTony Lindgren t->sysc = OMAP_TIMER_OCP_CFG_OFFSET; 40952762fbdSTony Lindgren t->load = regbase + _OMAP_TIMER_LOAD_OFFSET; 41052762fbdSTony Lindgren t->counter = regbase + _OMAP_TIMER_COUNTER_OFFSET; 41152762fbdSTony Lindgren t->ctrl = regbase + _OMAP_TIMER_CTRL_OFFSET; 41252762fbdSTony Lindgren t->wakeup = regbase + _OMAP_TIMER_WAKEUP_EN_OFFSET; 41352762fbdSTony Lindgren t->ifctrl = regbase + _OMAP_TIMER_IF_CTRL_OFFSET; 41452762fbdSTony Lindgren 41552762fbdSTony Lindgren dmtimer_systimer_reset(t); 41616480515STony Lindgren dmtimer_systimer_enable(t); 41752762fbdSTony Lindgren pr_debug("dmtimer rev %08x sysc %08x\n", readl_relaxed(t->base), 41852762fbdSTony Lindgren readl_relaxed(t->base + t->sysc)); 41952762fbdSTony Lindgren 42052762fbdSTony Lindgren return 0; 42152762fbdSTony Lindgren 42252762fbdSTony Lindgren err_unmap: 42352762fbdSTony Lindgren iounmap(t->base); 42452762fbdSTony Lindgren 42552762fbdSTony Lindgren return error; 42652762fbdSTony Lindgren } 42752762fbdSTony Lindgren 42852762fbdSTony Lindgren /* Clockevent */ 42952762fbdSTony Lindgren static struct dmtimer_clockevent * 43052762fbdSTony Lindgren to_dmtimer_clockevent(struct clock_event_device *clockevent) 43152762fbdSTony Lindgren { 43252762fbdSTony Lindgren return container_of(clockevent, struct dmtimer_clockevent, dev); 43352762fbdSTony Lindgren } 43452762fbdSTony Lindgren 43552762fbdSTony Lindgren static irqreturn_t dmtimer_clockevent_interrupt(int irq, void *data) 43652762fbdSTony Lindgren { 43752762fbdSTony Lindgren struct dmtimer_clockevent *clkevt = data; 43852762fbdSTony Lindgren struct dmtimer_systimer *t = &clkevt->t; 43952762fbdSTony Lindgren 44052762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat); 44152762fbdSTony Lindgren clkevt->dev.event_handler(&clkevt->dev); 44252762fbdSTony Lindgren 44352762fbdSTony Lindgren return IRQ_HANDLED; 44452762fbdSTony Lindgren } 44552762fbdSTony Lindgren 44652762fbdSTony Lindgren static int dmtimer_set_next_event(unsigned long cycles, 44752762fbdSTony Lindgren struct clock_event_device *evt) 44852762fbdSTony Lindgren { 44952762fbdSTony Lindgren struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 45052762fbdSTony Lindgren struct dmtimer_systimer *t = &clkevt->t; 45152762fbdSTony Lindgren void __iomem *pend = t->base + t->pend; 45252762fbdSTony Lindgren 45352762fbdSTony Lindgren while (readl_relaxed(pend) & WP_TCRR) 45452762fbdSTony Lindgren cpu_relax(); 45521270992STony Lindgren writel_relaxed(0xffffffff - cycles, t->base + t->counter); 45652762fbdSTony Lindgren 45752762fbdSTony Lindgren while (readl_relaxed(pend) & WP_TCLR) 45852762fbdSTony Lindgren cpu_relax(); 45921270992STony Lindgren writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl); 46052762fbdSTony Lindgren 46152762fbdSTony Lindgren return 0; 46252762fbdSTony Lindgren } 46352762fbdSTony Lindgren 46452762fbdSTony Lindgren static int dmtimer_clockevent_shutdown(struct clock_event_device *evt) 46552762fbdSTony Lindgren { 46652762fbdSTony Lindgren struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 46752762fbdSTony Lindgren struct dmtimer_systimer *t = &clkevt->t; 46852762fbdSTony Lindgren void __iomem *ctrl = t->base + t->ctrl; 46952762fbdSTony Lindgren u32 l; 47052762fbdSTony Lindgren 47152762fbdSTony Lindgren l = readl_relaxed(ctrl); 47252762fbdSTony Lindgren if (l & OMAP_TIMER_CTRL_ST) { 47352762fbdSTony Lindgren l &= ~BIT(0); 47452762fbdSTony Lindgren writel_relaxed(l, ctrl); 47552762fbdSTony Lindgren /* Flush posted write */ 47652762fbdSTony Lindgren l = readl_relaxed(ctrl); 47752762fbdSTony Lindgren /* Wait for functional clock period x 3.5 */ 47852762fbdSTony Lindgren udelay(3500000 / t->rate + 1); 47952762fbdSTony Lindgren } 48052762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat); 48152762fbdSTony Lindgren 48252762fbdSTony Lindgren return 0; 48352762fbdSTony Lindgren } 48452762fbdSTony Lindgren 48552762fbdSTony Lindgren static int dmtimer_set_periodic(struct clock_event_device *evt) 48652762fbdSTony Lindgren { 48752762fbdSTony Lindgren struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 48852762fbdSTony Lindgren struct dmtimer_systimer *t = &clkevt->t; 48952762fbdSTony Lindgren void __iomem *pend = t->base + t->pend; 49052762fbdSTony Lindgren 49152762fbdSTony Lindgren dmtimer_clockevent_shutdown(evt); 49252762fbdSTony Lindgren 49352762fbdSTony Lindgren /* Looks like we need to first set the load value separately */ 49452762fbdSTony Lindgren while (readl_relaxed(pend) & WP_TLDR) 49552762fbdSTony Lindgren cpu_relax(); 49621270992STony Lindgren writel_relaxed(clkevt->period, t->base + t->load); 49752762fbdSTony Lindgren 49852762fbdSTony Lindgren while (readl_relaxed(pend) & WP_TCRR) 49952762fbdSTony Lindgren cpu_relax(); 50021270992STony Lindgren writel_relaxed(clkevt->period, t->base + t->counter); 50152762fbdSTony Lindgren 50252762fbdSTony Lindgren while (readl_relaxed(pend) & WP_TCLR) 50352762fbdSTony Lindgren cpu_relax(); 50421270992STony Lindgren writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, 50521270992STony Lindgren t->base + t->ctrl); 50652762fbdSTony Lindgren 50752762fbdSTony Lindgren return 0; 50852762fbdSTony Lindgren } 50952762fbdSTony Lindgren 51052762fbdSTony Lindgren static void omap_clockevent_idle(struct clock_event_device *evt) 51152762fbdSTony Lindgren { 51252762fbdSTony Lindgren struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 51352762fbdSTony Lindgren struct dmtimer_systimer *t = &clkevt->t; 51452762fbdSTony Lindgren 51552762fbdSTony Lindgren dmtimer_systimer_disable(t); 5166cfcd556STony Lindgren clk_disable(t->fck); 51752762fbdSTony Lindgren } 51852762fbdSTony Lindgren 51952762fbdSTony Lindgren static void omap_clockevent_unidle(struct clock_event_device *evt) 52052762fbdSTony Lindgren { 52152762fbdSTony Lindgren struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt); 52252762fbdSTony Lindgren struct dmtimer_systimer *t = &clkevt->t; 5236cfcd556STony Lindgren int error; 5246cfcd556STony Lindgren 5256cfcd556STony Lindgren error = clk_enable(t->fck); 5266cfcd556STony Lindgren if (error) 5276cfcd556STony Lindgren pr_err("could not enable timer fck on resume: %i\n", error); 52852762fbdSTony Lindgren 52952762fbdSTony Lindgren dmtimer_systimer_enable(t); 53052762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena); 53152762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); 53252762fbdSTony Lindgren } 53352762fbdSTony Lindgren 5343efe7a87STony Lindgren static int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt, 5353efe7a87STony Lindgren struct device_node *np, 5363efe7a87STony Lindgren unsigned int features, 5373efe7a87STony Lindgren const struct cpumask *cpumask, 5383efe7a87STony Lindgren const char *name, 5393efe7a87STony Lindgren int rating) 54052762fbdSTony Lindgren { 54152762fbdSTony Lindgren struct clock_event_device *dev; 54252762fbdSTony Lindgren struct dmtimer_systimer *t; 54352762fbdSTony Lindgren int error; 54452762fbdSTony Lindgren 54552762fbdSTony Lindgren t = &clkevt->t; 54652762fbdSTony Lindgren dev = &clkevt->dev; 54752762fbdSTony Lindgren 54852762fbdSTony Lindgren /* 54952762fbdSTony Lindgren * We mostly use cpuidle_coupled with ARM local timers for runtime, 55052762fbdSTony Lindgren * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here. 55152762fbdSTony Lindgren */ 5523efe7a87STony Lindgren dev->features = features; 5533efe7a87STony Lindgren dev->rating = rating; 55452762fbdSTony Lindgren dev->set_next_event = dmtimer_set_next_event; 55552762fbdSTony Lindgren dev->set_state_shutdown = dmtimer_clockevent_shutdown; 55652762fbdSTony Lindgren dev->set_state_periodic = dmtimer_set_periodic; 55752762fbdSTony Lindgren dev->set_state_oneshot = dmtimer_clockevent_shutdown; 558ac4daf73STony Lindgren dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown; 55952762fbdSTony Lindgren dev->tick_resume = dmtimer_clockevent_shutdown; 5603efe7a87STony Lindgren dev->cpumask = cpumask; 56152762fbdSTony Lindgren 56252762fbdSTony Lindgren dev->irq = irq_of_parse_and_map(np, 0); 5633efe7a87STony Lindgren if (!dev->irq) 5643efe7a87STony Lindgren return -ENXIO; 56552762fbdSTony Lindgren 56652762fbdSTony Lindgren error = dmtimer_systimer_setup(np, &clkevt->t); 56752762fbdSTony Lindgren if (error) 5683efe7a87STony Lindgren return error; 56952762fbdSTony Lindgren 57052762fbdSTony Lindgren clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ); 57152762fbdSTony Lindgren 57252762fbdSTony Lindgren /* 57352762fbdSTony Lindgren * For clock-event timers we never read the timer counter and 57452762fbdSTony Lindgren * so we are not impacted by errata i103 and i767. Therefore, 57552762fbdSTony Lindgren * we can safely ignore this errata for clock-event timers. 57652762fbdSTony Lindgren */ 57752762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl); 57852762fbdSTony Lindgren 57952762fbdSTony Lindgren error = request_irq(dev->irq, dmtimer_clockevent_interrupt, 5803efe7a87STony Lindgren IRQF_TIMER, name, clkevt); 58152762fbdSTony Lindgren if (error) 58252762fbdSTony Lindgren goto err_out_unmap; 58352762fbdSTony Lindgren 58452762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena); 58552762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup); 58652762fbdSTony Lindgren 5873efe7a87STony Lindgren pr_info("TI gptimer %s: %s%lu Hz at %pOF\n", 5883efe7a87STony Lindgren name, of_find_property(np, "ti,timer-alwon", NULL) ? 58952762fbdSTony Lindgren "always-on " : "", t->rate, np->parent); 59052762fbdSTony Lindgren 59152762fbdSTony Lindgren return 0; 59252762fbdSTony Lindgren 59352762fbdSTony Lindgren err_out_unmap: 59452762fbdSTony Lindgren iounmap(t->base); 59552762fbdSTony Lindgren 5963efe7a87STony Lindgren return error; 5973efe7a87STony Lindgren } 5983efe7a87STony Lindgren 5993efe7a87STony Lindgren static int __init dmtimer_clockevent_init(struct device_node *np) 6003efe7a87STony Lindgren { 6013efe7a87STony Lindgren struct dmtimer_clockevent *clkevt; 6023efe7a87STony Lindgren int error; 6033efe7a87STony Lindgren 6043efe7a87STony Lindgren clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL); 6053efe7a87STony Lindgren if (!clkevt) 6063efe7a87STony Lindgren return -ENOMEM; 6073efe7a87STony Lindgren 6083efe7a87STony Lindgren error = dmtimer_clkevt_init_common(clkevt, np, 6093efe7a87STony Lindgren CLOCK_EVT_FEAT_PERIODIC | 6103efe7a87STony Lindgren CLOCK_EVT_FEAT_ONESHOT, 6113efe7a87STony Lindgren cpu_possible_mask, "clockevent", 6123efe7a87STony Lindgren 300); 6133efe7a87STony Lindgren if (error) 6143efe7a87STony Lindgren goto err_out_free; 6153efe7a87STony Lindgren 6163efe7a87STony Lindgren clockevents_config_and_register(&clkevt->dev, clkevt->t.rate, 6173efe7a87STony Lindgren 3, /* Timer internal resync latency */ 6183efe7a87STony Lindgren 0xffffffff); 6193efe7a87STony Lindgren 6203efe7a87STony Lindgren if (of_machine_is_compatible("ti,am33xx") || 6213efe7a87STony Lindgren of_machine_is_compatible("ti,am43")) { 6223efe7a87STony Lindgren clkevt->dev.suspend = omap_clockevent_idle; 6233efe7a87STony Lindgren clkevt->dev.resume = omap_clockevent_unidle; 6243efe7a87STony Lindgren } 6253efe7a87STony Lindgren 6263efe7a87STony Lindgren return 0; 6273efe7a87STony Lindgren 62852762fbdSTony Lindgren err_out_free: 62952762fbdSTony Lindgren kfree(clkevt); 63052762fbdSTony Lindgren 63152762fbdSTony Lindgren return error; 63252762fbdSTony Lindgren } 63352762fbdSTony Lindgren 634*25de4ce5STony Lindgren /* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */ 635*25de4ce5STony Lindgren static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer); 636*25de4ce5STony Lindgren 637*25de4ce5STony Lindgren static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu) 638*25de4ce5STony Lindgren { 639*25de4ce5STony Lindgren struct dmtimer_clockevent *clkevt; 640*25de4ce5STony Lindgren int error; 641*25de4ce5STony Lindgren 642*25de4ce5STony Lindgren if (!cpu_possible(cpu)) 643*25de4ce5STony Lindgren return -EINVAL; 644*25de4ce5STony Lindgren 645*25de4ce5STony Lindgren if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") || 646*25de4ce5STony Lindgren !of_property_read_bool(np->parent, "ti,no-idle")) 647*25de4ce5STony Lindgren pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent); 648*25de4ce5STony Lindgren 649*25de4ce5STony Lindgren clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); 650*25de4ce5STony Lindgren 651*25de4ce5STony Lindgren error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT, 652*25de4ce5STony Lindgren cpumask_of(cpu), "percpu-dmtimer", 653*25de4ce5STony Lindgren 500); 654*25de4ce5STony Lindgren if (error) 655*25de4ce5STony Lindgren return error; 656*25de4ce5STony Lindgren 657*25de4ce5STony Lindgren return 0; 658*25de4ce5STony Lindgren } 659*25de4ce5STony Lindgren 660*25de4ce5STony Lindgren /* See TRM for timer internal resynch latency */ 661*25de4ce5STony Lindgren static int omap_dmtimer_starting_cpu(unsigned int cpu) 662*25de4ce5STony Lindgren { 663*25de4ce5STony Lindgren struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu); 664*25de4ce5STony Lindgren struct clock_event_device *dev = &clkevt->dev; 665*25de4ce5STony Lindgren struct dmtimer_systimer *t = &clkevt->t; 666*25de4ce5STony Lindgren 667*25de4ce5STony Lindgren clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX); 668*25de4ce5STony Lindgren irq_force_affinity(dev->irq, cpumask_of(cpu)); 669*25de4ce5STony Lindgren 670*25de4ce5STony Lindgren return 0; 671*25de4ce5STony Lindgren } 672*25de4ce5STony Lindgren 673*25de4ce5STony Lindgren static int __init dmtimer_percpu_timer_startup(void) 674*25de4ce5STony Lindgren { 675*25de4ce5STony Lindgren struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0); 676*25de4ce5STony Lindgren struct dmtimer_systimer *t = &clkevt->t; 677*25de4ce5STony Lindgren 678*25de4ce5STony Lindgren if (t->sysc) { 679*25de4ce5STony Lindgren cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING, 680*25de4ce5STony Lindgren "clockevents/omap/gptimer:starting", 681*25de4ce5STony Lindgren omap_dmtimer_starting_cpu, NULL); 682*25de4ce5STony Lindgren } 683*25de4ce5STony Lindgren 684*25de4ce5STony Lindgren return 0; 685*25de4ce5STony Lindgren } 686*25de4ce5STony Lindgren subsys_initcall(dmtimer_percpu_timer_startup); 687*25de4ce5STony Lindgren 688*25de4ce5STony Lindgren static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa) 689*25de4ce5STony Lindgren { 690*25de4ce5STony Lindgren struct device_node *arm_timer; 691*25de4ce5STony Lindgren 692*25de4ce5STony Lindgren arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer"); 693*25de4ce5STony Lindgren if (of_device_is_available(arm_timer)) { 694*25de4ce5STony Lindgren pr_warn_once("ARM architected timer wrap issue i940 detected\n"); 695*25de4ce5STony Lindgren return 0; 696*25de4ce5STony Lindgren } 697*25de4ce5STony Lindgren 698*25de4ce5STony Lindgren if (pa == 0x48034000) /* dra7 dmtimer3 */ 699*25de4ce5STony Lindgren return dmtimer_percpu_timer_init(np, 0); 700*25de4ce5STony Lindgren else if (pa == 0x48036000) /* dra7 dmtimer4 */ 701*25de4ce5STony Lindgren return dmtimer_percpu_timer_init(np, 1); 702*25de4ce5STony Lindgren 703*25de4ce5STony Lindgren return 0; 704*25de4ce5STony Lindgren } 705*25de4ce5STony Lindgren 70652762fbdSTony Lindgren /* Clocksource */ 70752762fbdSTony Lindgren static struct dmtimer_clocksource * 70852762fbdSTony Lindgren to_dmtimer_clocksource(struct clocksource *cs) 70952762fbdSTony Lindgren { 71052762fbdSTony Lindgren return container_of(cs, struct dmtimer_clocksource, dev); 71152762fbdSTony Lindgren } 71252762fbdSTony Lindgren 71352762fbdSTony Lindgren static u64 dmtimer_clocksource_read_cycles(struct clocksource *cs) 71452762fbdSTony Lindgren { 71552762fbdSTony Lindgren struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 71652762fbdSTony Lindgren struct dmtimer_systimer *t = &clksrc->t; 71752762fbdSTony Lindgren 71852762fbdSTony Lindgren return (u64)readl_relaxed(t->base + t->counter); 71952762fbdSTony Lindgren } 72052762fbdSTony Lindgren 72152762fbdSTony Lindgren static void __iomem *dmtimer_sched_clock_counter; 72252762fbdSTony Lindgren 72352762fbdSTony Lindgren static u64 notrace dmtimer_read_sched_clock(void) 72452762fbdSTony Lindgren { 72552762fbdSTony Lindgren return readl_relaxed(dmtimer_sched_clock_counter); 72652762fbdSTony Lindgren } 72752762fbdSTony Lindgren 72852762fbdSTony Lindgren static void dmtimer_clocksource_suspend(struct clocksource *cs) 72952762fbdSTony Lindgren { 73052762fbdSTony Lindgren struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 73152762fbdSTony Lindgren struct dmtimer_systimer *t = &clksrc->t; 73252762fbdSTony Lindgren 73352762fbdSTony Lindgren clksrc->loadval = readl_relaxed(t->base + t->counter); 73452762fbdSTony Lindgren dmtimer_systimer_disable(t); 7356cfcd556STony Lindgren clk_disable(t->fck); 73652762fbdSTony Lindgren } 73752762fbdSTony Lindgren 73852762fbdSTony Lindgren static void dmtimer_clocksource_resume(struct clocksource *cs) 73952762fbdSTony Lindgren { 74052762fbdSTony Lindgren struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs); 74152762fbdSTony Lindgren struct dmtimer_systimer *t = &clksrc->t; 7426cfcd556STony Lindgren int error; 7436cfcd556STony Lindgren 7446cfcd556STony Lindgren error = clk_enable(t->fck); 7456cfcd556STony Lindgren if (error) 7466cfcd556STony Lindgren pr_err("could not enable timer fck on resume: %i\n", error); 74752762fbdSTony Lindgren 74852762fbdSTony Lindgren dmtimer_systimer_enable(t); 74952762fbdSTony Lindgren writel_relaxed(clksrc->loadval, t->base + t->counter); 75052762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 75152762fbdSTony Lindgren t->base + t->ctrl); 75252762fbdSTony Lindgren } 75352762fbdSTony Lindgren 75452762fbdSTony Lindgren static int __init dmtimer_clocksource_init(struct device_node *np) 75552762fbdSTony Lindgren { 75652762fbdSTony Lindgren struct dmtimer_clocksource *clksrc; 75752762fbdSTony Lindgren struct dmtimer_systimer *t; 75852762fbdSTony Lindgren struct clocksource *dev; 75952762fbdSTony Lindgren int error; 76052762fbdSTony Lindgren 76152762fbdSTony Lindgren clksrc = kzalloc(sizeof(*clksrc), GFP_KERNEL); 76252762fbdSTony Lindgren if (!clksrc) 76352762fbdSTony Lindgren return -ENOMEM; 76452762fbdSTony Lindgren 76552762fbdSTony Lindgren dev = &clksrc->dev; 76652762fbdSTony Lindgren t = &clksrc->t; 76752762fbdSTony Lindgren 76852762fbdSTony Lindgren error = dmtimer_systimer_setup(np, t); 76952762fbdSTony Lindgren if (error) 77052762fbdSTony Lindgren goto err_out_free; 77152762fbdSTony Lindgren 77252762fbdSTony Lindgren dev->name = "dmtimer"; 77352762fbdSTony Lindgren dev->rating = 300; 77452762fbdSTony Lindgren dev->read = dmtimer_clocksource_read_cycles; 77552762fbdSTony Lindgren dev->mask = CLOCKSOURCE_MASK(32); 77652762fbdSTony Lindgren dev->flags = CLOCK_SOURCE_IS_CONTINUOUS; 77752762fbdSTony Lindgren 7786cfcd556STony Lindgren /* Unlike for clockevent, legacy code sets suspend only for am4 */ 7796cfcd556STony Lindgren if (of_machine_is_compatible("ti,am43")) { 78052762fbdSTony Lindgren dev->suspend = dmtimer_clocksource_suspend; 78152762fbdSTony Lindgren dev->resume = dmtimer_clocksource_resume; 78252762fbdSTony Lindgren } 78352762fbdSTony Lindgren 78452762fbdSTony Lindgren writel_relaxed(0, t->base + t->counter); 78552762fbdSTony Lindgren writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 78652762fbdSTony Lindgren t->base + t->ctrl); 78752762fbdSTony Lindgren 78852762fbdSTony Lindgren pr_info("TI gptimer clocksource: %s%pOF\n", 78952762fbdSTony Lindgren of_find_property(np, "ti,timer-alwon", NULL) ? 79052762fbdSTony Lindgren "always-on " : "", np->parent); 79152762fbdSTony Lindgren 79252762fbdSTony Lindgren if (!dmtimer_sched_clock_counter) { 79352762fbdSTony Lindgren dmtimer_sched_clock_counter = t->base + t->counter; 79452762fbdSTony Lindgren sched_clock_register(dmtimer_read_sched_clock, 32, t->rate); 79552762fbdSTony Lindgren } 79652762fbdSTony Lindgren 79752762fbdSTony Lindgren if (clocksource_register_hz(dev, t->rate)) 79852762fbdSTony Lindgren pr_err("Could not register clocksource %pOF\n", np); 79952762fbdSTony Lindgren 80052762fbdSTony Lindgren return 0; 80152762fbdSTony Lindgren 80252762fbdSTony Lindgren err_out_free: 80352762fbdSTony Lindgren kfree(clksrc); 80452762fbdSTony Lindgren 80552762fbdSTony Lindgren return -ENODEV; 80652762fbdSTony Lindgren } 80752762fbdSTony Lindgren 80852762fbdSTony Lindgren /* 80952762fbdSTony Lindgren * To detect between a clocksource and clockevent, we assume the device tree 81052762fbdSTony Lindgren * has no interrupts configured for a clocksource timer. 81152762fbdSTony Lindgren */ 81252762fbdSTony Lindgren static int __init dmtimer_systimer_init(struct device_node *np) 81352762fbdSTony Lindgren { 81452762fbdSTony Lindgren const __be32 *addr; 81552762fbdSTony Lindgren u32 pa; 81652762fbdSTony Lindgren 81752762fbdSTony Lindgren /* One time init for the preferred timer configuration */ 81852762fbdSTony Lindgren if (!clocksource && !clockevent) 81952762fbdSTony Lindgren dmtimer_systimer_select_best(); 82052762fbdSTony Lindgren 82152762fbdSTony Lindgren if (!clocksource && !clockevent) { 822ac593e62SColin Ian King pr_err("%s: unable to detect system timers, update dtb?\n", 82352762fbdSTony Lindgren __func__); 82452762fbdSTony Lindgren 82552762fbdSTony Lindgren return -EINVAL; 82652762fbdSTony Lindgren } 82752762fbdSTony Lindgren 82852762fbdSTony Lindgren addr = of_get_address(np, 0, NULL, NULL); 82952762fbdSTony Lindgren pa = of_translate_address(np, addr); 83052762fbdSTony Lindgren if (!pa) 83152762fbdSTony Lindgren return -EINVAL; 83252762fbdSTony Lindgren 83352762fbdSTony Lindgren if (counter_32k <= 0 && clocksource == pa) 83452762fbdSTony Lindgren return dmtimer_clocksource_init(np); 83552762fbdSTony Lindgren 83652762fbdSTony Lindgren if (clockevent == pa) 83752762fbdSTony Lindgren return dmtimer_clockevent_init(np); 83852762fbdSTony Lindgren 839*25de4ce5STony Lindgren if (of_machine_is_compatible("ti,dra7")) 840*25de4ce5STony Lindgren return dmtimer_percpu_quirk_init(np, pa); 841*25de4ce5STony Lindgren 84252762fbdSTony Lindgren return 0; 84352762fbdSTony Lindgren } 84452762fbdSTony Lindgren 84552762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_omap2, "ti,omap2420-timer", dmtimer_systimer_init); 84652762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_omap3, "ti,omap3430-timer", dmtimer_systimer_init); 84752762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_omap4, "ti,omap4430-timer", dmtimer_systimer_init); 84852762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_omap5, "ti,omap5430-timer", dmtimer_systimer_init); 84952762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_am33x, "ti,am335x-timer", dmtimer_systimer_init); 85052762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_am3ms, "ti,am335x-timer-1ms", dmtimer_systimer_init); 85152762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_dm814, "ti,dm814-timer", dmtimer_systimer_init); 85252762fbdSTony Lindgren TIMER_OF_DECLARE(systimer_dm816, "ti,dm816-timer", dmtimer_systimer_init); 853