xref: /linux/drivers/clocksource/timer-ti-dm-systimer.c (revision bceaae3bac0ce27c549bb050336d8d08abc2ee54)
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>
525de4ce5STony 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 
63425de4ce5STony Lindgren /* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */
63525de4ce5STony Lindgren static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
63625de4ce5STony Lindgren 
63725de4ce5STony Lindgren static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu)
63825de4ce5STony Lindgren {
63925de4ce5STony Lindgren 	struct dmtimer_clockevent *clkevt;
64025de4ce5STony Lindgren 	int error;
64125de4ce5STony Lindgren 
64225de4ce5STony Lindgren 	if (!cpu_possible(cpu))
64325de4ce5STony Lindgren 		return -EINVAL;
64425de4ce5STony Lindgren 
64525de4ce5STony Lindgren 	if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") ||
64625de4ce5STony Lindgren 	    !of_property_read_bool(np->parent, "ti,no-idle"))
64725de4ce5STony Lindgren 		pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent);
64825de4ce5STony Lindgren 
64925de4ce5STony Lindgren 	clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
65025de4ce5STony Lindgren 
65125de4ce5STony Lindgren 	error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT,
65225de4ce5STony Lindgren 					   cpumask_of(cpu), "percpu-dmtimer",
65325de4ce5STony Lindgren 					   500);
65425de4ce5STony Lindgren 	if (error)
65525de4ce5STony Lindgren 		return error;
65625de4ce5STony Lindgren 
65725de4ce5STony Lindgren 	return 0;
65825de4ce5STony Lindgren }
65925de4ce5STony Lindgren 
66025de4ce5STony Lindgren /* See TRM for timer internal resynch latency */
66125de4ce5STony Lindgren static int omap_dmtimer_starting_cpu(unsigned int cpu)
66225de4ce5STony Lindgren {
66325de4ce5STony Lindgren 	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
66425de4ce5STony Lindgren 	struct clock_event_device *dev = &clkevt->dev;
66525de4ce5STony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
66625de4ce5STony Lindgren 
66725de4ce5STony Lindgren 	clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX);
66825de4ce5STony Lindgren 	irq_force_affinity(dev->irq, cpumask_of(cpu));
66925de4ce5STony Lindgren 
67025de4ce5STony Lindgren 	return 0;
67125de4ce5STony Lindgren }
67225de4ce5STony Lindgren 
67325de4ce5STony Lindgren static int __init dmtimer_percpu_timer_startup(void)
67425de4ce5STony Lindgren {
67525de4ce5STony Lindgren 	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0);
67625de4ce5STony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
67725de4ce5STony Lindgren 
67825de4ce5STony Lindgren 	if (t->sysc) {
67925de4ce5STony Lindgren 		cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING,
68025de4ce5STony Lindgren 				  "clockevents/omap/gptimer:starting",
68125de4ce5STony Lindgren 				  omap_dmtimer_starting_cpu, NULL);
68225de4ce5STony Lindgren 	}
68325de4ce5STony Lindgren 
68425de4ce5STony Lindgren 	return 0;
68525de4ce5STony Lindgren }
68625de4ce5STony Lindgren subsys_initcall(dmtimer_percpu_timer_startup);
68725de4ce5STony Lindgren 
68825de4ce5STony Lindgren static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
68925de4ce5STony Lindgren {
69025de4ce5STony Lindgren 	struct device_node *arm_timer;
69125de4ce5STony Lindgren 
69225de4ce5STony Lindgren 	arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
69325de4ce5STony Lindgren 	if (of_device_is_available(arm_timer)) {
69425de4ce5STony Lindgren 		pr_warn_once("ARM architected timer wrap issue i940 detected\n");
69525de4ce5STony Lindgren 		return 0;
69625de4ce5STony Lindgren 	}
69725de4ce5STony Lindgren 
698*bceaae3bSDrew Fustini 	if (pa == 0x4882c000)           /* dra7 dmtimer15 */
69925de4ce5STony Lindgren 		return dmtimer_percpu_timer_init(np, 0);
700*bceaae3bSDrew Fustini 	else if (pa == 0x4882e000)      /* dra7 dmtimer16 */
70125de4ce5STony Lindgren 		return dmtimer_percpu_timer_init(np, 1);
70225de4ce5STony Lindgren 
70325de4ce5STony Lindgren 	return 0;
70425de4ce5STony Lindgren }
70525de4ce5STony 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 
83925de4ce5STony Lindgren 	if (of_machine_is_compatible("ti,dra7"))
84025de4ce5STony Lindgren 		return dmtimer_percpu_quirk_init(np, pa);
84125de4ce5STony 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