xref: /linux/drivers/clocksource/timer-ti-dm-systimer.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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 */
dmtimer_systimer_revision1(struct dmtimer_systimer * t)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 
dmtimer_systimer_enable(struct dmtimer_systimer * t)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 
dmtimer_systimer_disable(struct dmtimer_systimer * t)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 
dmtimer_systimer_type1_reset(struct dmtimer_systimer * t)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 */
dmtimer_systimer_type2_reset(struct dmtimer_systimer * t)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 
dmtimer_systimer_reset(struct dmtimer_systimer * t)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  */
dmtimer_systimer_check_counter32k(void)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  */
dmtimer_is_preferred(struct device_node * np)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  */
dmtimer_systimer_assign_alwon(void)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 */
2448840f546SAnthoine Bourgeois 	if (of_machine_is_compatible("ti,omap3-beagle-ab4")) {
24552762fbdSTony Lindgren 		quirk_unreliable_oscillator = true;
24652762fbdSTony Lindgren 		counter_32k = -ENODEV;
24752762fbdSTony Lindgren 	}
24852762fbdSTony Lindgren 
24952762fbdSTony Lindgren 	/* Quirk am437x using am335x style dmtimer clocksource */
25052762fbdSTony Lindgren 	if (of_machine_is_compatible("ti,am43"))
25152762fbdSTony Lindgren 		counter_32k = -ENODEV;
25252762fbdSTony Lindgren 
25352762fbdSTony Lindgren 	for_each_matching_node(np, dmtimer_match_table) {
2540fabf9f3SRob Herring 		struct resource res;
25552762fbdSTony Lindgren 		if (!dmtimer_is_preferred(np))
25652762fbdSTony Lindgren 			continue;
25752762fbdSTony Lindgren 
2580fabf9f3SRob Herring 		if (!of_property_read_bool(np, "ti,timer-alwon"))
2590fabf9f3SRob Herring 			continue;
26052762fbdSTony Lindgren 
2610fabf9f3SRob Herring 		if (of_address_to_resource(np, 0, &res))
2620fabf9f3SRob Herring 			continue;
2630fabf9f3SRob Herring 
2648d7aac51STony Lindgren 		pa = res.start;
2658d7aac51STony Lindgren 
26652762fbdSTony Lindgren 		/* Quirky omap3 boards must use dmtimer12 */
2678d7aac51STony Lindgren 		if (quirk_unreliable_oscillator && pa == 0x48318000)
26852762fbdSTony Lindgren 			continue;
26952762fbdSTony Lindgren 
27052762fbdSTony Lindgren 		of_node_put(np);
27152762fbdSTony Lindgren 		break;
27252762fbdSTony Lindgren 	}
27352762fbdSTony Lindgren 
27452762fbdSTony Lindgren 	/* Usually no need for dmtimer clocksource if we have counter32 */
27552762fbdSTony Lindgren 	if (counter_32k >= 0) {
27652762fbdSTony Lindgren 		clockevent = pa;
27752762fbdSTony Lindgren 		clocksource = 0;
27852762fbdSTony Lindgren 	} else {
27952762fbdSTony Lindgren 		clocksource = pa;
28052762fbdSTony Lindgren 		clockevent = DMTIMER_INST_DONT_CARE;
28152762fbdSTony Lindgren 	}
28252762fbdSTony Lindgren }
28352762fbdSTony Lindgren 
28452762fbdSTony Lindgren /* Finds the first usable dmtimer, used for the don't care case */
dmtimer_systimer_find_first_available(void)28552762fbdSTony Lindgren static u32 __init dmtimer_systimer_find_first_available(void)
28652762fbdSTony Lindgren {
28752762fbdSTony Lindgren 	struct device_node *np;
28852762fbdSTony Lindgren 	u32 pa = 0;
28952762fbdSTony Lindgren 
29052762fbdSTony Lindgren 	for_each_matching_node(np, dmtimer_match_table) {
2910fabf9f3SRob Herring 		struct resource res;
29252762fbdSTony Lindgren 		if (!dmtimer_is_preferred(np))
29352762fbdSTony Lindgren 			continue;
29452762fbdSTony Lindgren 
2950fabf9f3SRob Herring 		if (of_address_to_resource(np, 0, &res))
29652762fbdSTony Lindgren 			continue;
29752762fbdSTony Lindgren 
2980fabf9f3SRob Herring 		if (res.start == clocksource || res.start == clockevent)
2990fabf9f3SRob Herring 			continue;
3000fabf9f3SRob Herring 
3010fabf9f3SRob Herring 		pa = res.start;
30252762fbdSTony Lindgren 		of_node_put(np);
30352762fbdSTony Lindgren 		break;
30452762fbdSTony Lindgren 	}
30552762fbdSTony Lindgren 
30652762fbdSTony Lindgren 	return pa;
30752762fbdSTony Lindgren }
30852762fbdSTony Lindgren 
30952762fbdSTony Lindgren /* Selects the best clocksource and clockevent to use */
dmtimer_systimer_select_best(void)31052762fbdSTony Lindgren static void __init dmtimer_systimer_select_best(void)
31152762fbdSTony Lindgren {
31252762fbdSTony Lindgren 	dmtimer_systimer_check_counter32k();
31352762fbdSTony Lindgren 	dmtimer_systimer_assign_alwon();
31452762fbdSTony Lindgren 
31552762fbdSTony Lindgren 	if (clockevent == DMTIMER_INST_DONT_CARE)
31652762fbdSTony Lindgren 		clockevent = dmtimer_systimer_find_first_available();
31752762fbdSTony Lindgren 
31852762fbdSTony Lindgren 	pr_debug("%s: counter_32k: %i clocksource: %08x clockevent: %08x\n",
31952762fbdSTony Lindgren 		 __func__, counter_32k, clocksource, clockevent);
32052762fbdSTony Lindgren }
32152762fbdSTony Lindgren 
32252762fbdSTony Lindgren /* Interface clocks are only available on some SoCs variants */
dmtimer_systimer_init_clock(struct dmtimer_systimer * t,struct device_node * np,const char * name,unsigned long * rate)3236cfcd556STony Lindgren static int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
3246cfcd556STony Lindgren 					      struct device_node *np,
32552762fbdSTony Lindgren 					      const char *name,
32652762fbdSTony Lindgren 					      unsigned long *rate)
32752762fbdSTony Lindgren {
32852762fbdSTony Lindgren 	struct clk *clock;
32952762fbdSTony Lindgren 	unsigned long r;
3306cfcd556STony Lindgren 	bool is_ick = false;
33152762fbdSTony Lindgren 	int error;
33252762fbdSTony Lindgren 
3336cfcd556STony Lindgren 	is_ick = !strncmp(name, "ick", 3);
3346cfcd556STony Lindgren 
33552762fbdSTony Lindgren 	clock = of_clk_get_by_name(np, name);
3366cfcd556STony Lindgren 	if ((PTR_ERR(clock) == -EINVAL) && is_ick)
33752762fbdSTony Lindgren 		return 0;
33852762fbdSTony Lindgren 	else if (IS_ERR(clock))
33952762fbdSTony Lindgren 		return PTR_ERR(clock);
34052762fbdSTony Lindgren 
34152762fbdSTony Lindgren 	error = clk_prepare_enable(clock);
34252762fbdSTony Lindgren 	if (error)
34352762fbdSTony Lindgren 		return error;
34452762fbdSTony Lindgren 
34552762fbdSTony Lindgren 	r = clk_get_rate(clock);
346180d35a7SYang Yingliang 	if (!r) {
347180d35a7SYang Yingliang 		clk_disable_unprepare(clock);
34852762fbdSTony Lindgren 		return -ENODEV;
349180d35a7SYang Yingliang 	}
35052762fbdSTony Lindgren 
3516cfcd556STony Lindgren 	if (is_ick)
3526cfcd556STony Lindgren 		t->ick = clock;
3536cfcd556STony Lindgren 	else
3546cfcd556STony Lindgren 		t->fck = clock;
3556cfcd556STony Lindgren 
35652762fbdSTony Lindgren 	*rate = r;
35752762fbdSTony Lindgren 
35852762fbdSTony Lindgren 	return 0;
35952762fbdSTony Lindgren }
36052762fbdSTony Lindgren 
dmtimer_systimer_setup(struct device_node * np,struct dmtimer_systimer * t)36152762fbdSTony Lindgren static int __init dmtimer_systimer_setup(struct device_node *np,
36252762fbdSTony Lindgren 					 struct dmtimer_systimer *t)
36352762fbdSTony Lindgren {
36452762fbdSTony Lindgren 	unsigned long rate;
36552762fbdSTony Lindgren 	u8 regbase;
36652762fbdSTony Lindgren 	int error;
36752762fbdSTony Lindgren 
36852762fbdSTony Lindgren 	if (!of_device_is_compatible(np->parent, "ti,sysc"))
36952762fbdSTony Lindgren 		return -EINVAL;
37052762fbdSTony Lindgren 
37152762fbdSTony Lindgren 	t->base = of_iomap(np, 0);
37252762fbdSTony Lindgren 	if (!t->base)
37352762fbdSTony Lindgren 		return -ENXIO;
37452762fbdSTony Lindgren 
37552762fbdSTony Lindgren 	/*
37652762fbdSTony Lindgren 	 * Enable optional assigned-clock-parents configured at the timer
37752762fbdSTony Lindgren 	 * node level. For regular device drivers, this is done automatically
37852762fbdSTony Lindgren 	 * by bus related code such as platform_drv_probe().
37952762fbdSTony Lindgren 	 */
38052762fbdSTony Lindgren 	error = of_clk_set_defaults(np, false);
38152762fbdSTony Lindgren 	if (error < 0)
38252762fbdSTony Lindgren 		pr_err("%s: clock source init failed: %i\n", __func__, error);
38352762fbdSTony Lindgren 
38452762fbdSTony Lindgren 	/* For ti-sysc, we have timer clocks at the parent module level */
3856cfcd556STony Lindgren 	error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate);
38652762fbdSTony Lindgren 	if (error)
38752762fbdSTony Lindgren 		goto err_unmap;
38852762fbdSTony Lindgren 
38952762fbdSTony Lindgren 	t->rate = rate;
39052762fbdSTony Lindgren 
3916cfcd556STony Lindgren 	error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate);
39252762fbdSTony Lindgren 	if (error)
39352762fbdSTony Lindgren 		goto err_unmap;
39452762fbdSTony Lindgren 
39552762fbdSTony Lindgren 	if (dmtimer_systimer_revision1(t)) {
39652762fbdSTony Lindgren 		t->irq_stat = OMAP_TIMER_V1_STAT_OFFSET;
39752762fbdSTony Lindgren 		t->irq_ena = OMAP_TIMER_V1_INT_EN_OFFSET;
39852762fbdSTony Lindgren 		t->pend = _OMAP_TIMER_WRITE_PEND_OFFSET;
39952762fbdSTony Lindgren 		regbase = 0;
40052762fbdSTony Lindgren 	} else {
40152762fbdSTony Lindgren 		t->irq_stat = OMAP_TIMER_V2_IRQSTATUS;
40252762fbdSTony Lindgren 		t->irq_ena = OMAP_TIMER_V2_IRQENABLE_SET;
40352762fbdSTony Lindgren 		regbase = OMAP_TIMER_V2_FUNC_OFFSET;
40452762fbdSTony Lindgren 		t->pend = regbase + _OMAP_TIMER_WRITE_PEND_OFFSET;
40552762fbdSTony Lindgren 	}
40652762fbdSTony Lindgren 
40752762fbdSTony Lindgren 	t->sysc = OMAP_TIMER_OCP_CFG_OFFSET;
40852762fbdSTony Lindgren 	t->load = regbase + _OMAP_TIMER_LOAD_OFFSET;
40952762fbdSTony Lindgren 	t->counter = regbase + _OMAP_TIMER_COUNTER_OFFSET;
41052762fbdSTony Lindgren 	t->ctrl = regbase + _OMAP_TIMER_CTRL_OFFSET;
41152762fbdSTony Lindgren 	t->wakeup = regbase + _OMAP_TIMER_WAKEUP_EN_OFFSET;
41252762fbdSTony Lindgren 	t->ifctrl = regbase + _OMAP_TIMER_IF_CTRL_OFFSET;
41352762fbdSTony Lindgren 
41452762fbdSTony Lindgren 	dmtimer_systimer_reset(t);
41516480515STony Lindgren 	dmtimer_systimer_enable(t);
41652762fbdSTony Lindgren 	pr_debug("dmtimer rev %08x sysc %08x\n", readl_relaxed(t->base),
41752762fbdSTony Lindgren 		 readl_relaxed(t->base + t->sysc));
41852762fbdSTony Lindgren 
41952762fbdSTony Lindgren 	return 0;
42052762fbdSTony Lindgren 
42152762fbdSTony Lindgren err_unmap:
42252762fbdSTony Lindgren 	iounmap(t->base);
42352762fbdSTony Lindgren 
42452762fbdSTony Lindgren 	return error;
42552762fbdSTony Lindgren }
42652762fbdSTony Lindgren 
42752762fbdSTony Lindgren /* Clockevent */
42852762fbdSTony Lindgren static struct dmtimer_clockevent *
to_dmtimer_clockevent(struct clock_event_device * clockevent)42952762fbdSTony Lindgren to_dmtimer_clockevent(struct clock_event_device *clockevent)
43052762fbdSTony Lindgren {
43152762fbdSTony Lindgren 	return container_of(clockevent, struct dmtimer_clockevent, dev);
43252762fbdSTony Lindgren }
43352762fbdSTony Lindgren 
dmtimer_clockevent_interrupt(int irq,void * data)43452762fbdSTony Lindgren static irqreturn_t dmtimer_clockevent_interrupt(int irq, void *data)
43552762fbdSTony Lindgren {
43652762fbdSTony Lindgren 	struct dmtimer_clockevent *clkevt = data;
43752762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
43852762fbdSTony Lindgren 
43952762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat);
44052762fbdSTony Lindgren 	clkevt->dev.event_handler(&clkevt->dev);
44152762fbdSTony Lindgren 
44252762fbdSTony Lindgren 	return IRQ_HANDLED;
44352762fbdSTony Lindgren }
44452762fbdSTony Lindgren 
dmtimer_set_next_event(unsigned long cycles,struct clock_event_device * evt)44552762fbdSTony Lindgren static int dmtimer_set_next_event(unsigned long cycles,
44652762fbdSTony Lindgren 				  struct clock_event_device *evt)
44752762fbdSTony Lindgren {
44852762fbdSTony Lindgren 	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
44952762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
45052762fbdSTony Lindgren 	void __iomem *pend = t->base + t->pend;
45152762fbdSTony Lindgren 
45252762fbdSTony Lindgren 	while (readl_relaxed(pend) & WP_TCRR)
45352762fbdSTony Lindgren 		cpu_relax();
45421270992STony Lindgren 	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
45552762fbdSTony Lindgren 
45652762fbdSTony Lindgren 	while (readl_relaxed(pend) & WP_TCLR)
45752762fbdSTony Lindgren 		cpu_relax();
45821270992STony Lindgren 	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
45952762fbdSTony Lindgren 
46052762fbdSTony Lindgren 	return 0;
46152762fbdSTony Lindgren }
46252762fbdSTony Lindgren 
dmtimer_clockevent_shutdown(struct clock_event_device * evt)46352762fbdSTony Lindgren static int dmtimer_clockevent_shutdown(struct clock_event_device *evt)
46452762fbdSTony Lindgren {
46552762fbdSTony Lindgren 	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
46652762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
46752762fbdSTony Lindgren 	void __iomem *ctrl = t->base + t->ctrl;
46852762fbdSTony Lindgren 	u32 l;
46952762fbdSTony Lindgren 
47052762fbdSTony Lindgren 	l = readl_relaxed(ctrl);
47152762fbdSTony Lindgren 	if (l & OMAP_TIMER_CTRL_ST) {
47252762fbdSTony Lindgren 		l &= ~BIT(0);
47352762fbdSTony Lindgren 		writel_relaxed(l, ctrl);
47452762fbdSTony Lindgren 		/* Flush posted write */
47552762fbdSTony Lindgren 		l = readl_relaxed(ctrl);
47652762fbdSTony Lindgren 		/*  Wait for functional clock period x 3.5 */
47752762fbdSTony Lindgren 		udelay(3500000 / t->rate + 1);
47852762fbdSTony Lindgren 	}
47952762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat);
48052762fbdSTony Lindgren 
48152762fbdSTony Lindgren 	return 0;
48252762fbdSTony Lindgren }
48352762fbdSTony Lindgren 
dmtimer_set_periodic(struct clock_event_device * evt)48452762fbdSTony Lindgren static int dmtimer_set_periodic(struct clock_event_device *evt)
48552762fbdSTony Lindgren {
48652762fbdSTony Lindgren 	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
48752762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
48852762fbdSTony Lindgren 	void __iomem *pend = t->base + t->pend;
48952762fbdSTony Lindgren 
49052762fbdSTony Lindgren 	dmtimer_clockevent_shutdown(evt);
49152762fbdSTony Lindgren 
49252762fbdSTony Lindgren 	/* Looks like we need to first set the load value separately */
49352762fbdSTony Lindgren 	while (readl_relaxed(pend) & WP_TLDR)
49452762fbdSTony Lindgren 		cpu_relax();
49521270992STony Lindgren 	writel_relaxed(clkevt->period, t->base + t->load);
49652762fbdSTony Lindgren 
49752762fbdSTony Lindgren 	while (readl_relaxed(pend) & WP_TCRR)
49852762fbdSTony Lindgren 		cpu_relax();
49921270992STony Lindgren 	writel_relaxed(clkevt->period, t->base + t->counter);
50052762fbdSTony Lindgren 
50152762fbdSTony Lindgren 	while (readl_relaxed(pend) & WP_TCLR)
50252762fbdSTony Lindgren 		cpu_relax();
50321270992STony Lindgren 	writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
50421270992STony Lindgren 		       t->base + t->ctrl);
50552762fbdSTony Lindgren 
50652762fbdSTony Lindgren 	return 0;
50752762fbdSTony Lindgren }
50852762fbdSTony Lindgren 
omap_clockevent_idle(struct clock_event_device * evt)50952762fbdSTony Lindgren static void omap_clockevent_idle(struct clock_event_device *evt)
51052762fbdSTony Lindgren {
51152762fbdSTony Lindgren 	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
51252762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
51352762fbdSTony Lindgren 
51452762fbdSTony Lindgren 	dmtimer_systimer_disable(t);
5156cfcd556STony Lindgren 	clk_disable(t->fck);
51652762fbdSTony Lindgren }
51752762fbdSTony Lindgren 
omap_clockevent_unidle(struct clock_event_device * evt)51852762fbdSTony Lindgren static void omap_clockevent_unidle(struct clock_event_device *evt)
51952762fbdSTony Lindgren {
52052762fbdSTony Lindgren 	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
52152762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
5226cfcd556STony Lindgren 	int error;
5236cfcd556STony Lindgren 
5246cfcd556STony Lindgren 	error = clk_enable(t->fck);
5256cfcd556STony Lindgren 	if (error)
5266cfcd556STony Lindgren 		pr_err("could not enable timer fck on resume: %i\n", error);
52752762fbdSTony Lindgren 
52852762fbdSTony Lindgren 	dmtimer_systimer_enable(t);
52952762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
53052762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
53152762fbdSTony Lindgren }
53252762fbdSTony Lindgren 
dmtimer_clkevt_init_common(struct dmtimer_clockevent * clkevt,struct device_node * np,unsigned int features,const struct cpumask * cpumask,const char * name,int rating)5333efe7a87STony Lindgren static int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt,
5343efe7a87STony Lindgren 					     struct device_node *np,
5353efe7a87STony Lindgren 					     unsigned int features,
5363efe7a87STony Lindgren 					     const struct cpumask *cpumask,
5373efe7a87STony Lindgren 					     const char *name,
5383efe7a87STony Lindgren 					     int rating)
53952762fbdSTony Lindgren {
54052762fbdSTony Lindgren 	struct clock_event_device *dev;
54152762fbdSTony Lindgren 	struct dmtimer_systimer *t;
54252762fbdSTony Lindgren 	int error;
54352762fbdSTony Lindgren 
54452762fbdSTony Lindgren 	t = &clkevt->t;
54552762fbdSTony Lindgren 	dev = &clkevt->dev;
54652762fbdSTony Lindgren 
54752762fbdSTony Lindgren 	/*
54852762fbdSTony Lindgren 	 * We mostly use cpuidle_coupled with ARM local timers for runtime,
54952762fbdSTony Lindgren 	 * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here.
55052762fbdSTony Lindgren 	 */
5513efe7a87STony Lindgren 	dev->features = features;
5523efe7a87STony Lindgren 	dev->rating = rating;
55352762fbdSTony Lindgren 	dev->set_next_event = dmtimer_set_next_event;
55452762fbdSTony Lindgren 	dev->set_state_shutdown = dmtimer_clockevent_shutdown;
55552762fbdSTony Lindgren 	dev->set_state_periodic = dmtimer_set_periodic;
55652762fbdSTony Lindgren 	dev->set_state_oneshot = dmtimer_clockevent_shutdown;
557ac4daf73STony Lindgren 	dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown;
55852762fbdSTony Lindgren 	dev->tick_resume = dmtimer_clockevent_shutdown;
5593efe7a87STony Lindgren 	dev->cpumask = cpumask;
56052762fbdSTony Lindgren 
56152762fbdSTony Lindgren 	dev->irq = irq_of_parse_and_map(np, 0);
5623efe7a87STony Lindgren 	if (!dev->irq)
5633efe7a87STony Lindgren 		return -ENXIO;
56452762fbdSTony Lindgren 
56552762fbdSTony Lindgren 	error = dmtimer_systimer_setup(np, &clkevt->t);
56652762fbdSTony Lindgren 	if (error)
5673efe7a87STony Lindgren 		return error;
56852762fbdSTony Lindgren 
56952762fbdSTony Lindgren 	clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ);
57052762fbdSTony Lindgren 
57152762fbdSTony Lindgren 	/*
57252762fbdSTony Lindgren 	 * For clock-event timers we never read the timer counter and
57352762fbdSTony Lindgren 	 * so we are not impacted by errata i103 and i767. Therefore,
57452762fbdSTony Lindgren 	 * we can safely ignore this errata for clock-event timers.
57552762fbdSTony Lindgren 	 */
57652762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl);
57752762fbdSTony Lindgren 
57852762fbdSTony Lindgren 	error = request_irq(dev->irq, dmtimer_clockevent_interrupt,
5793efe7a87STony Lindgren 			    IRQF_TIMER, name, clkevt);
58052762fbdSTony Lindgren 	if (error)
58152762fbdSTony Lindgren 		goto err_out_unmap;
58252762fbdSTony Lindgren 
58352762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
58452762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
58552762fbdSTony Lindgren 
5863efe7a87STony Lindgren 	pr_info("TI gptimer %s: %s%lu Hz at %pOF\n",
587*87dd04f9SRob Herring 		name, of_property_read_bool(np, "ti,timer-alwon") ?
58852762fbdSTony Lindgren 		"always-on " : "", t->rate, np->parent);
58952762fbdSTony Lindgren 
59052762fbdSTony Lindgren 	return 0;
59152762fbdSTony Lindgren 
59252762fbdSTony Lindgren err_out_unmap:
59352762fbdSTony Lindgren 	iounmap(t->base);
59452762fbdSTony Lindgren 
5953efe7a87STony Lindgren 	return error;
5963efe7a87STony Lindgren }
5973efe7a87STony Lindgren 
dmtimer_clockevent_init(struct device_node * np)5983efe7a87STony Lindgren static int __init dmtimer_clockevent_init(struct device_node *np)
5993efe7a87STony Lindgren {
6003efe7a87STony Lindgren 	struct dmtimer_clockevent *clkevt;
6013efe7a87STony Lindgren 	int error;
6023efe7a87STony Lindgren 
6033efe7a87STony Lindgren 	clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
6043efe7a87STony Lindgren 	if (!clkevt)
6053efe7a87STony Lindgren 		return -ENOMEM;
6063efe7a87STony Lindgren 
6073efe7a87STony Lindgren 	error = dmtimer_clkevt_init_common(clkevt, np,
6083efe7a87STony Lindgren 					   CLOCK_EVT_FEAT_PERIODIC |
6093efe7a87STony Lindgren 					   CLOCK_EVT_FEAT_ONESHOT,
6103efe7a87STony Lindgren 					   cpu_possible_mask, "clockevent",
6113efe7a87STony Lindgren 					   300);
6123efe7a87STony Lindgren 	if (error)
6133efe7a87STony Lindgren 		goto err_out_free;
6143efe7a87STony Lindgren 
6153efe7a87STony Lindgren 	clockevents_config_and_register(&clkevt->dev, clkevt->t.rate,
6163efe7a87STony Lindgren 					3, /* Timer internal resync latency */
6173efe7a87STony Lindgren 					0xffffffff);
6183efe7a87STony Lindgren 
6193efe7a87STony Lindgren 	if (of_machine_is_compatible("ti,am33xx") ||
6203efe7a87STony Lindgren 	    of_machine_is_compatible("ti,am43")) {
6213efe7a87STony Lindgren 		clkevt->dev.suspend = omap_clockevent_idle;
6223efe7a87STony Lindgren 		clkevt->dev.resume = omap_clockevent_unidle;
6233efe7a87STony Lindgren 	}
6243efe7a87STony Lindgren 
6253efe7a87STony Lindgren 	return 0;
6263efe7a87STony Lindgren 
62752762fbdSTony Lindgren err_out_free:
62852762fbdSTony Lindgren 	kfree(clkevt);
62952762fbdSTony Lindgren 
63052762fbdSTony Lindgren 	return error;
63152762fbdSTony Lindgren }
63252762fbdSTony Lindgren 
63325de4ce5STony Lindgren /* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */
63425de4ce5STony Lindgren static DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
63525de4ce5STony Lindgren 
dmtimer_percpu_timer_init(struct device_node * np,int cpu)63625de4ce5STony Lindgren static int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu)
63725de4ce5STony Lindgren {
63825de4ce5STony Lindgren 	struct dmtimer_clockevent *clkevt;
63925de4ce5STony Lindgren 	int error;
64025de4ce5STony Lindgren 
64125de4ce5STony Lindgren 	if (!cpu_possible(cpu))
64225de4ce5STony Lindgren 		return -EINVAL;
64325de4ce5STony Lindgren 
64425de4ce5STony Lindgren 	if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") ||
64525de4ce5STony Lindgren 	    !of_property_read_bool(np->parent, "ti,no-idle"))
64625de4ce5STony Lindgren 		pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent);
64725de4ce5STony Lindgren 
64825de4ce5STony Lindgren 	clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
64925de4ce5STony Lindgren 
65025de4ce5STony Lindgren 	error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT,
65125de4ce5STony Lindgren 					   cpumask_of(cpu), "percpu-dmtimer",
65225de4ce5STony Lindgren 					   500);
65325de4ce5STony Lindgren 	if (error)
65425de4ce5STony Lindgren 		return error;
65525de4ce5STony Lindgren 
65625de4ce5STony Lindgren 	return 0;
65725de4ce5STony Lindgren }
65825de4ce5STony Lindgren 
65925de4ce5STony Lindgren /* See TRM for timer internal resynch latency */
omap_dmtimer_starting_cpu(unsigned int cpu)66025de4ce5STony Lindgren static int omap_dmtimer_starting_cpu(unsigned int cpu)
66125de4ce5STony Lindgren {
66225de4ce5STony Lindgren 	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
66325de4ce5STony Lindgren 	struct clock_event_device *dev = &clkevt->dev;
66425de4ce5STony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
66525de4ce5STony Lindgren 
66625de4ce5STony Lindgren 	clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX);
66725de4ce5STony Lindgren 	irq_force_affinity(dev->irq, cpumask_of(cpu));
66825de4ce5STony Lindgren 
66925de4ce5STony Lindgren 	return 0;
67025de4ce5STony Lindgren }
67125de4ce5STony Lindgren 
dmtimer_percpu_timer_startup(void)67225de4ce5STony Lindgren static int __init dmtimer_percpu_timer_startup(void)
67325de4ce5STony Lindgren {
67425de4ce5STony Lindgren 	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0);
67525de4ce5STony Lindgren 	struct dmtimer_systimer *t = &clkevt->t;
67625de4ce5STony Lindgren 
67725de4ce5STony Lindgren 	if (t->sysc) {
67825de4ce5STony Lindgren 		cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING,
67925de4ce5STony Lindgren 				  "clockevents/omap/gptimer:starting",
68025de4ce5STony Lindgren 				  omap_dmtimer_starting_cpu, NULL);
68125de4ce5STony Lindgren 	}
68225de4ce5STony Lindgren 
68325de4ce5STony Lindgren 	return 0;
68425de4ce5STony Lindgren }
68525de4ce5STony Lindgren subsys_initcall(dmtimer_percpu_timer_startup);
68625de4ce5STony Lindgren 
dmtimer_percpu_quirk_init(struct device_node * np,u32 pa)68725de4ce5STony Lindgren static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
68825de4ce5STony Lindgren {
68925de4ce5STony Lindgren 	struct device_node *arm_timer;
69025de4ce5STony Lindgren 
69125de4ce5STony Lindgren 	arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
69225de4ce5STony Lindgren 	if (of_device_is_available(arm_timer)) {
69325de4ce5STony Lindgren 		pr_warn_once("ARM architected timer wrap issue i940 detected\n");
69425de4ce5STony Lindgren 		return 0;
69525de4ce5STony Lindgren 	}
69625de4ce5STony Lindgren 
697bceaae3bSDrew Fustini 	if (pa == 0x4882c000)           /* dra7 dmtimer15 */
69825de4ce5STony Lindgren 		return dmtimer_percpu_timer_init(np, 0);
699bceaae3bSDrew Fustini 	else if (pa == 0x4882e000)      /* dra7 dmtimer16 */
70025de4ce5STony Lindgren 		return dmtimer_percpu_timer_init(np, 1);
70125de4ce5STony Lindgren 
70225de4ce5STony Lindgren 	return 0;
70325de4ce5STony Lindgren }
70425de4ce5STony Lindgren 
70552762fbdSTony Lindgren /* Clocksource */
70652762fbdSTony Lindgren static struct dmtimer_clocksource *
to_dmtimer_clocksource(struct clocksource * cs)70752762fbdSTony Lindgren to_dmtimer_clocksource(struct clocksource *cs)
70852762fbdSTony Lindgren {
70952762fbdSTony Lindgren 	return container_of(cs, struct dmtimer_clocksource, dev);
71052762fbdSTony Lindgren }
71152762fbdSTony Lindgren 
dmtimer_clocksource_read_cycles(struct clocksource * cs)71252762fbdSTony Lindgren static u64 dmtimer_clocksource_read_cycles(struct clocksource *cs)
71352762fbdSTony Lindgren {
71452762fbdSTony Lindgren 	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
71552762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clksrc->t;
71652762fbdSTony Lindgren 
71752762fbdSTony Lindgren 	return (u64)readl_relaxed(t->base + t->counter);
71852762fbdSTony Lindgren }
71952762fbdSTony Lindgren 
72052762fbdSTony Lindgren static void __iomem *dmtimer_sched_clock_counter;
72152762fbdSTony Lindgren 
dmtimer_read_sched_clock(void)72252762fbdSTony Lindgren static u64 notrace dmtimer_read_sched_clock(void)
72352762fbdSTony Lindgren {
72452762fbdSTony Lindgren 	return readl_relaxed(dmtimer_sched_clock_counter);
72552762fbdSTony Lindgren }
72652762fbdSTony Lindgren 
dmtimer_clocksource_suspend(struct clocksource * cs)72752762fbdSTony Lindgren static void dmtimer_clocksource_suspend(struct clocksource *cs)
72852762fbdSTony Lindgren {
72952762fbdSTony Lindgren 	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
73052762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clksrc->t;
73152762fbdSTony Lindgren 
73252762fbdSTony Lindgren 	clksrc->loadval = readl_relaxed(t->base + t->counter);
73352762fbdSTony Lindgren 	dmtimer_systimer_disable(t);
7346cfcd556STony Lindgren 	clk_disable(t->fck);
73552762fbdSTony Lindgren }
73652762fbdSTony Lindgren 
dmtimer_clocksource_resume(struct clocksource * cs)73752762fbdSTony Lindgren static void dmtimer_clocksource_resume(struct clocksource *cs)
73852762fbdSTony Lindgren {
73952762fbdSTony Lindgren 	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
74052762fbdSTony Lindgren 	struct dmtimer_systimer *t = &clksrc->t;
7416cfcd556STony Lindgren 	int error;
7426cfcd556STony Lindgren 
7436cfcd556STony Lindgren 	error = clk_enable(t->fck);
7446cfcd556STony Lindgren 	if (error)
7456cfcd556STony Lindgren 		pr_err("could not enable timer fck on resume: %i\n", error);
74652762fbdSTony Lindgren 
74752762fbdSTony Lindgren 	dmtimer_systimer_enable(t);
74852762fbdSTony Lindgren 	writel_relaxed(clksrc->loadval, t->base + t->counter);
74952762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
75052762fbdSTony Lindgren 		       t->base + t->ctrl);
75152762fbdSTony Lindgren }
75252762fbdSTony Lindgren 
dmtimer_clocksource_init(struct device_node * np)75352762fbdSTony Lindgren static int __init dmtimer_clocksource_init(struct device_node *np)
75452762fbdSTony Lindgren {
75552762fbdSTony Lindgren 	struct dmtimer_clocksource *clksrc;
75652762fbdSTony Lindgren 	struct dmtimer_systimer *t;
75752762fbdSTony Lindgren 	struct clocksource *dev;
75852762fbdSTony Lindgren 	int error;
75952762fbdSTony Lindgren 
76052762fbdSTony Lindgren 	clksrc = kzalloc(sizeof(*clksrc), GFP_KERNEL);
76152762fbdSTony Lindgren 	if (!clksrc)
76252762fbdSTony Lindgren 		return -ENOMEM;
76352762fbdSTony Lindgren 
76452762fbdSTony Lindgren 	dev = &clksrc->dev;
76552762fbdSTony Lindgren 	t = &clksrc->t;
76652762fbdSTony Lindgren 
76752762fbdSTony Lindgren 	error = dmtimer_systimer_setup(np, t);
76852762fbdSTony Lindgren 	if (error)
76952762fbdSTony Lindgren 		goto err_out_free;
77052762fbdSTony Lindgren 
77152762fbdSTony Lindgren 	dev->name = "dmtimer";
77252762fbdSTony Lindgren 	dev->rating = 300;
77352762fbdSTony Lindgren 	dev->read = dmtimer_clocksource_read_cycles;
77452762fbdSTony Lindgren 	dev->mask = CLOCKSOURCE_MASK(32);
77552762fbdSTony Lindgren 	dev->flags = CLOCK_SOURCE_IS_CONTINUOUS;
77652762fbdSTony Lindgren 
7776cfcd556STony Lindgren 	/* Unlike for clockevent, legacy code sets suspend only for am4 */
7786cfcd556STony Lindgren 	if (of_machine_is_compatible("ti,am43")) {
77952762fbdSTony Lindgren 		dev->suspend = dmtimer_clocksource_suspend;
78052762fbdSTony Lindgren 		dev->resume = dmtimer_clocksource_resume;
78152762fbdSTony Lindgren 	}
78252762fbdSTony Lindgren 
78352762fbdSTony Lindgren 	writel_relaxed(0, t->base + t->counter);
78452762fbdSTony Lindgren 	writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
78552762fbdSTony Lindgren 		       t->base + t->ctrl);
78652762fbdSTony Lindgren 
78752762fbdSTony Lindgren 	pr_info("TI gptimer clocksource: %s%pOF\n",
788*87dd04f9SRob Herring 		of_property_read_bool(np, "ti,timer-alwon") ?
78952762fbdSTony Lindgren 		"always-on " : "", np->parent);
79052762fbdSTony Lindgren 
79152762fbdSTony Lindgren 	if (!dmtimer_sched_clock_counter) {
79252762fbdSTony Lindgren 		dmtimer_sched_clock_counter = t->base + t->counter;
79352762fbdSTony Lindgren 		sched_clock_register(dmtimer_read_sched_clock, 32, t->rate);
79452762fbdSTony Lindgren 	}
79552762fbdSTony Lindgren 
79652762fbdSTony Lindgren 	if (clocksource_register_hz(dev, t->rate))
79752762fbdSTony Lindgren 		pr_err("Could not register clocksource %pOF\n", np);
79852762fbdSTony Lindgren 
79952762fbdSTony Lindgren 	return 0;
80052762fbdSTony Lindgren 
80152762fbdSTony Lindgren err_out_free:
80252762fbdSTony Lindgren 	kfree(clksrc);
80352762fbdSTony Lindgren 
80452762fbdSTony Lindgren 	return -ENODEV;
80552762fbdSTony Lindgren }
80652762fbdSTony Lindgren 
80752762fbdSTony Lindgren /*
80852762fbdSTony Lindgren  * To detect between a clocksource and clockevent, we assume the device tree
80952762fbdSTony Lindgren  * has no interrupts configured for a clocksource timer.
81052762fbdSTony Lindgren  */
dmtimer_systimer_init(struct device_node * np)81152762fbdSTony Lindgren static int __init dmtimer_systimer_init(struct device_node *np)
81252762fbdSTony Lindgren {
8130fabf9f3SRob Herring 	struct resource res;
81452762fbdSTony Lindgren 	u32 pa;
81552762fbdSTony Lindgren 
81652762fbdSTony Lindgren 	/* One time init for the preferred timer configuration */
81752762fbdSTony Lindgren 	if (!clocksource && !clockevent)
81852762fbdSTony Lindgren 		dmtimer_systimer_select_best();
81952762fbdSTony Lindgren 
82052762fbdSTony Lindgren 	if (!clocksource && !clockevent) {
821ac593e62SColin Ian King 		pr_err("%s: unable to detect system timers, update dtb?\n",
82252762fbdSTony Lindgren 		       __func__);
82352762fbdSTony Lindgren 
82452762fbdSTony Lindgren 		return -EINVAL;
82552762fbdSTony Lindgren 	}
82652762fbdSTony Lindgren 
8270fabf9f3SRob Herring 
8280fabf9f3SRob Herring 	of_address_to_resource(np, 0, &res);
8290fabf9f3SRob Herring 	pa = (u32)res.start;
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