162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci#include <linux/clk.h>
362306a36Sopenharmony_ci#include <linux/clocksource.h>
462306a36Sopenharmony_ci#include <linux/clockchips.h>
562306a36Sopenharmony_ci#include <linux/cpuhotplug.h>
662306a36Sopenharmony_ci#include <linux/interrupt.h>
762306a36Sopenharmony_ci#include <linux/io.h>
862306a36Sopenharmony_ci#include <linux/iopoll.h>
962306a36Sopenharmony_ci#include <linux/err.h>
1062306a36Sopenharmony_ci#include <linux/of.h>
1162306a36Sopenharmony_ci#include <linux/of_address.h>
1262306a36Sopenharmony_ci#include <linux/of_irq.h>
1362306a36Sopenharmony_ci#include <linux/sched_clock.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/clk/clk-conf.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <clocksource/timer-ti-dm.h>
1862306a36Sopenharmony_ci#include <dt-bindings/bus/ti-sysc.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* For type1, set SYSC_OMAP2_CLOCKACTIVITY for fck off on idle, l4 clock on */
2162306a36Sopenharmony_ci#define DMTIMER_TYPE1_ENABLE	((1 << 9) | (SYSC_IDLE_SMART << 3) | \
2262306a36Sopenharmony_ci				 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_AUTOIDLE)
2362306a36Sopenharmony_ci#define DMTIMER_TYPE1_DISABLE	(SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE)
2462306a36Sopenharmony_ci#define DMTIMER_TYPE2_ENABLE	(SYSC_IDLE_SMART_WKUP << 2)
2562306a36Sopenharmony_ci#define DMTIMER_RESET_WAIT	100000
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define DMTIMER_INST_DONT_CARE	~0U
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int counter_32k;
3062306a36Sopenharmony_cistatic u32 clocksource;
3162306a36Sopenharmony_cistatic u32 clockevent;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Subset of the timer registers we use. Note that the register offsets
3562306a36Sopenharmony_ci * depend on the timer revision detected.
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistruct dmtimer_systimer {
3862306a36Sopenharmony_ci	void __iomem *base;
3962306a36Sopenharmony_ci	u8 sysc;
4062306a36Sopenharmony_ci	u8 irq_stat;
4162306a36Sopenharmony_ci	u8 irq_ena;
4262306a36Sopenharmony_ci	u8 pend;
4362306a36Sopenharmony_ci	u8 load;
4462306a36Sopenharmony_ci	u8 counter;
4562306a36Sopenharmony_ci	u8 ctrl;
4662306a36Sopenharmony_ci	u8 wakeup;
4762306a36Sopenharmony_ci	u8 ifctrl;
4862306a36Sopenharmony_ci	struct clk *fck;
4962306a36Sopenharmony_ci	struct clk *ick;
5062306a36Sopenharmony_ci	unsigned long rate;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct dmtimer_clockevent {
5462306a36Sopenharmony_ci	struct clock_event_device dev;
5562306a36Sopenharmony_ci	struct dmtimer_systimer t;
5662306a36Sopenharmony_ci	u32 period;
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct dmtimer_clocksource {
6062306a36Sopenharmony_ci	struct clocksource dev;
6162306a36Sopenharmony_ci	struct dmtimer_systimer t;
6262306a36Sopenharmony_ci	unsigned int loadval;
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* Assumes v1 ip if bits [31:16] are zero */
6662306a36Sopenharmony_cistatic bool dmtimer_systimer_revision1(struct dmtimer_systimer *t)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	u32 tidr = readl_relaxed(t->base);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return !(tidr >> 16);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void dmtimer_systimer_enable(struct dmtimer_systimer *t)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	u32 val;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (dmtimer_systimer_revision1(t))
7862306a36Sopenharmony_ci		val = DMTIMER_TYPE1_ENABLE;
7962306a36Sopenharmony_ci	else
8062306a36Sopenharmony_ci		val = DMTIMER_TYPE2_ENABLE;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	writel_relaxed(val, t->base + t->sysc);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic void dmtimer_systimer_disable(struct dmtimer_systimer *t)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	if (!dmtimer_systimer_revision1(t))
8862306a36Sopenharmony_ci		return;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	writel_relaxed(DMTIMER_TYPE1_DISABLE, t->base + t->sysc);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int __init dmtimer_systimer_type1_reset(struct dmtimer_systimer *t)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	void __iomem *syss = t->base + OMAP_TIMER_V1_SYS_STAT_OFFSET;
9662306a36Sopenharmony_ci	int ret;
9762306a36Sopenharmony_ci	u32 l;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	dmtimer_systimer_enable(t);
10062306a36Sopenharmony_ci	writel_relaxed(BIT(1) | BIT(2), t->base + t->ifctrl);
10162306a36Sopenharmony_ci	ret = readl_poll_timeout_atomic(syss, l, l & BIT(0), 100,
10262306a36Sopenharmony_ci					DMTIMER_RESET_WAIT);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return ret;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/* Note we must use io_base instead of func_base for type2 OCP regs */
10862306a36Sopenharmony_cistatic int __init dmtimer_systimer_type2_reset(struct dmtimer_systimer *t)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	void __iomem *sysc = t->base + t->sysc;
11162306a36Sopenharmony_ci	u32 l;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	dmtimer_systimer_enable(t);
11462306a36Sopenharmony_ci	l = readl_relaxed(sysc);
11562306a36Sopenharmony_ci	l |= BIT(0);
11662306a36Sopenharmony_ci	writel_relaxed(l, sysc);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return readl_poll_timeout_atomic(sysc, l, !(l & BIT(0)), 100,
11962306a36Sopenharmony_ci					 DMTIMER_RESET_WAIT);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int __init dmtimer_systimer_reset(struct dmtimer_systimer *t)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	int ret;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (dmtimer_systimer_revision1(t))
12762306a36Sopenharmony_ci		ret = dmtimer_systimer_type1_reset(t);
12862306a36Sopenharmony_ci	else
12962306a36Sopenharmony_ci		ret = dmtimer_systimer_type2_reset(t);
13062306a36Sopenharmony_ci	if (ret < 0) {
13162306a36Sopenharmony_ci		pr_err("%s failed with %i\n", __func__, ret);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		return ret;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic const struct of_device_id counter_match_table[] = {
14062306a36Sopenharmony_ci	{ .compatible = "ti,omap-counter32k" },
14162306a36Sopenharmony_ci	{ /* Sentinel */ },
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*
14562306a36Sopenharmony_ci * Check if the SoC als has a usable working 32 KiHz counter. The 32 KiHz
14662306a36Sopenharmony_ci * counter is handled by timer-ti-32k, but we need to detect it as it
14762306a36Sopenharmony_ci * affects the preferred dmtimer system timer configuration. There is
14862306a36Sopenharmony_ci * typically no use for a dmtimer clocksource if the 32 KiHz counter is
14962306a36Sopenharmony_ci * present, except on am437x as described below.
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_cistatic void __init dmtimer_systimer_check_counter32k(void)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct device_node *np;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (counter_32k)
15662306a36Sopenharmony_ci		return;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	np = of_find_matching_node(NULL, counter_match_table);
15962306a36Sopenharmony_ci	if (!np) {
16062306a36Sopenharmony_ci		counter_32k = -ENODEV;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		return;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (of_device_is_available(np))
16662306a36Sopenharmony_ci		counter_32k = 1;
16762306a36Sopenharmony_ci	else
16862306a36Sopenharmony_ci		counter_32k = -ENODEV;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	of_node_put(np);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic const struct of_device_id dmtimer_match_table[] = {
17462306a36Sopenharmony_ci	{ .compatible = "ti,omap2420-timer", },
17562306a36Sopenharmony_ci	{ .compatible = "ti,omap3430-timer", },
17662306a36Sopenharmony_ci	{ .compatible = "ti,omap4430-timer", },
17762306a36Sopenharmony_ci	{ .compatible = "ti,omap5430-timer", },
17862306a36Sopenharmony_ci	{ .compatible = "ti,am335x-timer", },
17962306a36Sopenharmony_ci	{ .compatible = "ti,am335x-timer-1ms", },
18062306a36Sopenharmony_ci	{ .compatible = "ti,dm814-timer", },
18162306a36Sopenharmony_ci	{ .compatible = "ti,dm816-timer", },
18262306a36Sopenharmony_ci	{ /* Sentinel */ },
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci * Checks that system timers are configured to not reset and idle during
18762306a36Sopenharmony_ci * the generic timer-ti-dm device driver probe. And that the system timer
18862306a36Sopenharmony_ci * source clocks are properly configured. Also, let's not hog any DSP and
18962306a36Sopenharmony_ci * PWM capable timers unnecessarily as system timers.
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_cistatic bool __init dmtimer_is_preferred(struct device_node *np)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	if (!of_device_is_available(np))
19462306a36Sopenharmony_ci		return false;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (!of_property_read_bool(np->parent,
19762306a36Sopenharmony_ci				   "ti,no-reset-on-init"))
19862306a36Sopenharmony_ci		return false;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (!of_property_read_bool(np->parent, "ti,no-idle"))
20162306a36Sopenharmony_ci		return false;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* Secure gptimer12 is always clocked with a fixed source */
20462306a36Sopenharmony_ci	if (!of_property_read_bool(np, "ti,timer-secure")) {
20562306a36Sopenharmony_ci		if (!of_property_read_bool(np, "assigned-clocks"))
20662306a36Sopenharmony_ci			return false;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci		if (!of_property_read_bool(np, "assigned-clock-parents"))
20962306a36Sopenharmony_ci			return false;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (of_property_read_bool(np, "ti,timer-dsp"))
21362306a36Sopenharmony_ci		return false;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (of_property_read_bool(np, "ti,timer-pwm"))
21662306a36Sopenharmony_ci		return false;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return true;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/*
22262306a36Sopenharmony_ci * Finds the first available usable always-on timer, and assigns it to either
22362306a36Sopenharmony_ci * clockevent or clocksource depending if the counter_32k is available on the
22462306a36Sopenharmony_ci * SoC or not.
22562306a36Sopenharmony_ci *
22662306a36Sopenharmony_ci * Some omap3 boards with unreliable oscillator must not use the counter_32k
22762306a36Sopenharmony_ci * or dmtimer1 with 32 KiHz source. Additionally, the boards with unreliable
22862306a36Sopenharmony_ci * oscillator should really set counter_32k as disabled, and delete dmtimer1
22962306a36Sopenharmony_ci * ti,always-on property, but let's not count on it. For these quirky cases,
23062306a36Sopenharmony_ci * we prefer using the always-on secure dmtimer12 with the internal 32 KiHz
23162306a36Sopenharmony_ci * clock as the clocksource, and any available dmtimer as clockevent.
23262306a36Sopenharmony_ci *
23362306a36Sopenharmony_ci * For am437x, we are using am335x style dmtimer clocksource. It is unclear
23462306a36Sopenharmony_ci * if this quirk handling is really needed, but let's change it separately
23562306a36Sopenharmony_ci * based on testing as it might cause side effects.
23662306a36Sopenharmony_ci */
23762306a36Sopenharmony_cistatic void __init dmtimer_systimer_assign_alwon(void)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct device_node *np;
24062306a36Sopenharmony_ci	u32 pa = 0;
24162306a36Sopenharmony_ci	bool quirk_unreliable_oscillator = false;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* Quirk unreliable 32 KiHz oscillator with incomplete dts */
24462306a36Sopenharmony_ci	if (of_machine_is_compatible("ti,omap3-beagle-ab4")) {
24562306a36Sopenharmony_ci		quirk_unreliable_oscillator = true;
24662306a36Sopenharmony_ci		counter_32k = -ENODEV;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* Quirk am437x using am335x style dmtimer clocksource */
25062306a36Sopenharmony_ci	if (of_machine_is_compatible("ti,am43"))
25162306a36Sopenharmony_ci		counter_32k = -ENODEV;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	for_each_matching_node(np, dmtimer_match_table) {
25462306a36Sopenharmony_ci		struct resource res;
25562306a36Sopenharmony_ci		if (!dmtimer_is_preferred(np))
25662306a36Sopenharmony_ci			continue;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		if (!of_property_read_bool(np, "ti,timer-alwon"))
25962306a36Sopenharmony_ci			continue;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if (of_address_to_resource(np, 0, &res))
26262306a36Sopenharmony_ci			continue;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		pa = res.start;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		/* Quirky omap3 boards must use dmtimer12 */
26762306a36Sopenharmony_ci		if (quirk_unreliable_oscillator && pa == 0x48318000)
26862306a36Sopenharmony_ci			continue;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		of_node_put(np);
27162306a36Sopenharmony_ci		break;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* Usually no need for dmtimer clocksource if we have counter32 */
27562306a36Sopenharmony_ci	if (counter_32k >= 0) {
27662306a36Sopenharmony_ci		clockevent = pa;
27762306a36Sopenharmony_ci		clocksource = 0;
27862306a36Sopenharmony_ci	} else {
27962306a36Sopenharmony_ci		clocksource = pa;
28062306a36Sopenharmony_ci		clockevent = DMTIMER_INST_DONT_CARE;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/* Finds the first usable dmtimer, used for the don't care case */
28562306a36Sopenharmony_cistatic u32 __init dmtimer_systimer_find_first_available(void)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct device_node *np;
28862306a36Sopenharmony_ci	u32 pa = 0;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	for_each_matching_node(np, dmtimer_match_table) {
29162306a36Sopenharmony_ci		struct resource res;
29262306a36Sopenharmony_ci		if (!dmtimer_is_preferred(np))
29362306a36Sopenharmony_ci			continue;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		if (of_address_to_resource(np, 0, &res))
29662306a36Sopenharmony_ci			continue;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		if (res.start == clocksource || res.start == clockevent)
29962306a36Sopenharmony_ci			continue;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		pa = res.start;
30262306a36Sopenharmony_ci		of_node_put(np);
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return pa;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/* Selects the best clocksource and clockevent to use */
31062306a36Sopenharmony_cistatic void __init dmtimer_systimer_select_best(void)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	dmtimer_systimer_check_counter32k();
31362306a36Sopenharmony_ci	dmtimer_systimer_assign_alwon();
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (clockevent == DMTIMER_INST_DONT_CARE)
31662306a36Sopenharmony_ci		clockevent = dmtimer_systimer_find_first_available();
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	pr_debug("%s: counter_32k: %i clocksource: %08x clockevent: %08x\n",
31962306a36Sopenharmony_ci		 __func__, counter_32k, clocksource, clockevent);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/* Interface clocks are only available on some SoCs variants */
32362306a36Sopenharmony_cistatic int __init dmtimer_systimer_init_clock(struct dmtimer_systimer *t,
32462306a36Sopenharmony_ci					      struct device_node *np,
32562306a36Sopenharmony_ci					      const char *name,
32662306a36Sopenharmony_ci					      unsigned long *rate)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct clk *clock;
32962306a36Sopenharmony_ci	unsigned long r;
33062306a36Sopenharmony_ci	bool is_ick = false;
33162306a36Sopenharmony_ci	int error;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	is_ick = !strncmp(name, "ick", 3);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	clock = of_clk_get_by_name(np, name);
33662306a36Sopenharmony_ci	if ((PTR_ERR(clock) == -EINVAL) && is_ick)
33762306a36Sopenharmony_ci		return 0;
33862306a36Sopenharmony_ci	else if (IS_ERR(clock))
33962306a36Sopenharmony_ci		return PTR_ERR(clock);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	error = clk_prepare_enable(clock);
34262306a36Sopenharmony_ci	if (error)
34362306a36Sopenharmony_ci		return error;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	r = clk_get_rate(clock);
34662306a36Sopenharmony_ci	if (!r) {
34762306a36Sopenharmony_ci		clk_disable_unprepare(clock);
34862306a36Sopenharmony_ci		return -ENODEV;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (is_ick)
35262306a36Sopenharmony_ci		t->ick = clock;
35362306a36Sopenharmony_ci	else
35462306a36Sopenharmony_ci		t->fck = clock;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	*rate = r;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic int __init dmtimer_systimer_setup(struct device_node *np,
36262306a36Sopenharmony_ci					 struct dmtimer_systimer *t)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	unsigned long rate;
36562306a36Sopenharmony_ci	u8 regbase;
36662306a36Sopenharmony_ci	int error;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (!of_device_is_compatible(np->parent, "ti,sysc"))
36962306a36Sopenharmony_ci		return -EINVAL;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	t->base = of_iomap(np, 0);
37262306a36Sopenharmony_ci	if (!t->base)
37362306a36Sopenharmony_ci		return -ENXIO;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/*
37662306a36Sopenharmony_ci	 * Enable optional assigned-clock-parents configured at the timer
37762306a36Sopenharmony_ci	 * node level. For regular device drivers, this is done automatically
37862306a36Sopenharmony_ci	 * by bus related code such as platform_drv_probe().
37962306a36Sopenharmony_ci	 */
38062306a36Sopenharmony_ci	error = of_clk_set_defaults(np, false);
38162306a36Sopenharmony_ci	if (error < 0)
38262306a36Sopenharmony_ci		pr_err("%s: clock source init failed: %i\n", __func__, error);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/* For ti-sysc, we have timer clocks at the parent module level */
38562306a36Sopenharmony_ci	error = dmtimer_systimer_init_clock(t, np->parent, "fck", &rate);
38662306a36Sopenharmony_ci	if (error)
38762306a36Sopenharmony_ci		goto err_unmap;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	t->rate = rate;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	error = dmtimer_systimer_init_clock(t, np->parent, "ick", &rate);
39262306a36Sopenharmony_ci	if (error)
39362306a36Sopenharmony_ci		goto err_unmap;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (dmtimer_systimer_revision1(t)) {
39662306a36Sopenharmony_ci		t->irq_stat = OMAP_TIMER_V1_STAT_OFFSET;
39762306a36Sopenharmony_ci		t->irq_ena = OMAP_TIMER_V1_INT_EN_OFFSET;
39862306a36Sopenharmony_ci		t->pend = _OMAP_TIMER_WRITE_PEND_OFFSET;
39962306a36Sopenharmony_ci		regbase = 0;
40062306a36Sopenharmony_ci	} else {
40162306a36Sopenharmony_ci		t->irq_stat = OMAP_TIMER_V2_IRQSTATUS;
40262306a36Sopenharmony_ci		t->irq_ena = OMAP_TIMER_V2_IRQENABLE_SET;
40362306a36Sopenharmony_ci		regbase = OMAP_TIMER_V2_FUNC_OFFSET;
40462306a36Sopenharmony_ci		t->pend = regbase + _OMAP_TIMER_WRITE_PEND_OFFSET;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	t->sysc = OMAP_TIMER_OCP_CFG_OFFSET;
40862306a36Sopenharmony_ci	t->load = regbase + _OMAP_TIMER_LOAD_OFFSET;
40962306a36Sopenharmony_ci	t->counter = regbase + _OMAP_TIMER_COUNTER_OFFSET;
41062306a36Sopenharmony_ci	t->ctrl = regbase + _OMAP_TIMER_CTRL_OFFSET;
41162306a36Sopenharmony_ci	t->wakeup = regbase + _OMAP_TIMER_WAKEUP_EN_OFFSET;
41262306a36Sopenharmony_ci	t->ifctrl = regbase + _OMAP_TIMER_IF_CTRL_OFFSET;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	dmtimer_systimer_reset(t);
41562306a36Sopenharmony_ci	dmtimer_systimer_enable(t);
41662306a36Sopenharmony_ci	pr_debug("dmtimer rev %08x sysc %08x\n", readl_relaxed(t->base),
41762306a36Sopenharmony_ci		 readl_relaxed(t->base + t->sysc));
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cierr_unmap:
42262306a36Sopenharmony_ci	iounmap(t->base);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return error;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/* Clockevent */
42862306a36Sopenharmony_cistatic struct dmtimer_clockevent *
42962306a36Sopenharmony_cito_dmtimer_clockevent(struct clock_event_device *clockevent)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	return container_of(clockevent, struct dmtimer_clockevent, dev);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic irqreturn_t dmtimer_clockevent_interrupt(int irq, void *data)
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = data;
43762306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat);
44062306a36Sopenharmony_ci	clkevt->dev.event_handler(&clkevt->dev);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return IRQ_HANDLED;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int dmtimer_set_next_event(unsigned long cycles,
44662306a36Sopenharmony_ci				  struct clock_event_device *evt)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
44962306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
45062306a36Sopenharmony_ci	void __iomem *pend = t->base + t->pend;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	while (readl_relaxed(pend) & WP_TCRR)
45362306a36Sopenharmony_ci		cpu_relax();
45462306a36Sopenharmony_ci	writel_relaxed(0xffffffff - cycles, t->base + t->counter);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	while (readl_relaxed(pend) & WP_TCLR)
45762306a36Sopenharmony_ci		cpu_relax();
45862306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_CTRL_ST, t->base + t->ctrl);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return 0;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic int dmtimer_clockevent_shutdown(struct clock_event_device *evt)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
46662306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
46762306a36Sopenharmony_ci	void __iomem *ctrl = t->base + t->ctrl;
46862306a36Sopenharmony_ci	u32 l;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	l = readl_relaxed(ctrl);
47162306a36Sopenharmony_ci	if (l & OMAP_TIMER_CTRL_ST) {
47262306a36Sopenharmony_ci		l &= ~BIT(0);
47362306a36Sopenharmony_ci		writel_relaxed(l, ctrl);
47462306a36Sopenharmony_ci		/* Flush posted write */
47562306a36Sopenharmony_ci		l = readl_relaxed(ctrl);
47662306a36Sopenharmony_ci		/*  Wait for functional clock period x 3.5 */
47762306a36Sopenharmony_ci		udelay(3500000 / t->rate + 1);
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_stat);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	return 0;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic int dmtimer_set_periodic(struct clock_event_device *evt)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
48762306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
48862306a36Sopenharmony_ci	void __iomem *pend = t->base + t->pend;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	dmtimer_clockevent_shutdown(evt);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* Looks like we need to first set the load value separately */
49362306a36Sopenharmony_ci	while (readl_relaxed(pend) & WP_TLDR)
49462306a36Sopenharmony_ci		cpu_relax();
49562306a36Sopenharmony_ci	writel_relaxed(clkevt->period, t->base + t->load);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	while (readl_relaxed(pend) & WP_TCRR)
49862306a36Sopenharmony_ci		cpu_relax();
49962306a36Sopenharmony_ci	writel_relaxed(clkevt->period, t->base + t->counter);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	while (readl_relaxed(pend) & WP_TCLR)
50262306a36Sopenharmony_ci		cpu_relax();
50362306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST,
50462306a36Sopenharmony_ci		       t->base + t->ctrl);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic void omap_clockevent_idle(struct clock_event_device *evt)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
51262306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	dmtimer_systimer_disable(t);
51562306a36Sopenharmony_ci	clk_disable(t->fck);
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic void omap_clockevent_unidle(struct clock_event_device *evt)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = to_dmtimer_clockevent(evt);
52162306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
52262306a36Sopenharmony_ci	int error;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	error = clk_enable(t->fck);
52562306a36Sopenharmony_ci	if (error)
52662306a36Sopenharmony_ci		pr_err("could not enable timer fck on resume: %i\n", error);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	dmtimer_systimer_enable(t);
52962306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
53062306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic int __init dmtimer_clkevt_init_common(struct dmtimer_clockevent *clkevt,
53462306a36Sopenharmony_ci					     struct device_node *np,
53562306a36Sopenharmony_ci					     unsigned int features,
53662306a36Sopenharmony_ci					     const struct cpumask *cpumask,
53762306a36Sopenharmony_ci					     const char *name,
53862306a36Sopenharmony_ci					     int rating)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct clock_event_device *dev;
54162306a36Sopenharmony_ci	struct dmtimer_systimer *t;
54262306a36Sopenharmony_ci	int error;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	t = &clkevt->t;
54562306a36Sopenharmony_ci	dev = &clkevt->dev;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/*
54862306a36Sopenharmony_ci	 * We mostly use cpuidle_coupled with ARM local timers for runtime,
54962306a36Sopenharmony_ci	 * so there's probably no use for CLOCK_EVT_FEAT_DYNIRQ here.
55062306a36Sopenharmony_ci	 */
55162306a36Sopenharmony_ci	dev->features = features;
55262306a36Sopenharmony_ci	dev->rating = rating;
55362306a36Sopenharmony_ci	dev->set_next_event = dmtimer_set_next_event;
55462306a36Sopenharmony_ci	dev->set_state_shutdown = dmtimer_clockevent_shutdown;
55562306a36Sopenharmony_ci	dev->set_state_periodic = dmtimer_set_periodic;
55662306a36Sopenharmony_ci	dev->set_state_oneshot = dmtimer_clockevent_shutdown;
55762306a36Sopenharmony_ci	dev->set_state_oneshot_stopped = dmtimer_clockevent_shutdown;
55862306a36Sopenharmony_ci	dev->tick_resume = dmtimer_clockevent_shutdown;
55962306a36Sopenharmony_ci	dev->cpumask = cpumask;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	dev->irq = irq_of_parse_and_map(np, 0);
56262306a36Sopenharmony_ci	if (!dev->irq)
56362306a36Sopenharmony_ci		return -ENXIO;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	error = dmtimer_systimer_setup(np, &clkevt->t);
56662306a36Sopenharmony_ci	if (error)
56762306a36Sopenharmony_ci		return error;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	clkevt->period = 0xffffffff - DIV_ROUND_CLOSEST(t->rate, HZ);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/*
57262306a36Sopenharmony_ci	 * For clock-event timers we never read the timer counter and
57362306a36Sopenharmony_ci	 * so we are not impacted by errata i103 and i767. Therefore,
57462306a36Sopenharmony_ci	 * we can safely ignore this errata for clock-event timers.
57562306a36Sopenharmony_ci	 */
57662306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_CTRL_POSTED, t->base + t->ifctrl);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	error = request_irq(dev->irq, dmtimer_clockevent_interrupt,
57962306a36Sopenharmony_ci			    IRQF_TIMER, name, clkevt);
58062306a36Sopenharmony_ci	if (error)
58162306a36Sopenharmony_ci		goto err_out_unmap;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
58462306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	pr_info("TI gptimer %s: %s%lu Hz at %pOF\n",
58762306a36Sopenharmony_ci		name, of_property_read_bool(np, "ti,timer-alwon") ?
58862306a36Sopenharmony_ci		"always-on " : "", t->rate, np->parent);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	return 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cierr_out_unmap:
59362306a36Sopenharmony_ci	iounmap(t->base);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	return error;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic int __init dmtimer_clockevent_init(struct device_node *np)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt;
60162306a36Sopenharmony_ci	int error;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
60462306a36Sopenharmony_ci	if (!clkevt)
60562306a36Sopenharmony_ci		return -ENOMEM;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	error = dmtimer_clkevt_init_common(clkevt, np,
60862306a36Sopenharmony_ci					   CLOCK_EVT_FEAT_PERIODIC |
60962306a36Sopenharmony_ci					   CLOCK_EVT_FEAT_ONESHOT,
61062306a36Sopenharmony_ci					   cpu_possible_mask, "clockevent",
61162306a36Sopenharmony_ci					   300);
61262306a36Sopenharmony_ci	if (error)
61362306a36Sopenharmony_ci		goto err_out_free;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	clockevents_config_and_register(&clkevt->dev, clkevt->t.rate,
61662306a36Sopenharmony_ci					3, /* Timer internal resync latency */
61762306a36Sopenharmony_ci					0xffffffff);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (of_machine_is_compatible("ti,am33xx") ||
62062306a36Sopenharmony_ci	    of_machine_is_compatible("ti,am43")) {
62162306a36Sopenharmony_ci		clkevt->dev.suspend = omap_clockevent_idle;
62262306a36Sopenharmony_ci		clkevt->dev.resume = omap_clockevent_unidle;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	return 0;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cierr_out_free:
62862306a36Sopenharmony_ci	kfree(clkevt);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return error;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci/* Dmtimer as percpu timer. See dra7 ARM architected timer wrap erratum i940 */
63462306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct dmtimer_clockevent, dmtimer_percpu_timer);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic int __init dmtimer_percpu_timer_init(struct device_node *np, int cpu)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt;
63962306a36Sopenharmony_ci	int error;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	if (!cpu_possible(cpu))
64262306a36Sopenharmony_ci		return -EINVAL;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	if (!of_property_read_bool(np->parent, "ti,no-reset-on-init") ||
64562306a36Sopenharmony_ci	    !of_property_read_bool(np->parent, "ti,no-idle"))
64662306a36Sopenharmony_ci		pr_warn("Incomplete dtb for percpu dmtimer %pOF\n", np->parent);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	error = dmtimer_clkevt_init_common(clkevt, np, CLOCK_EVT_FEAT_ONESHOT,
65162306a36Sopenharmony_ci					   cpumask_of(cpu), "percpu-dmtimer",
65262306a36Sopenharmony_ci					   500);
65362306a36Sopenharmony_ci	if (error)
65462306a36Sopenharmony_ci		return error;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/* See TRM for timer internal resynch latency */
66062306a36Sopenharmony_cistatic int omap_dmtimer_starting_cpu(unsigned int cpu)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, cpu);
66362306a36Sopenharmony_ci	struct clock_event_device *dev = &clkevt->dev;
66462306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	clockevents_config_and_register(dev, t->rate, 3, ULONG_MAX);
66762306a36Sopenharmony_ci	irq_force_affinity(dev->irq, cpumask_of(cpu));
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	return 0;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic int __init dmtimer_percpu_timer_startup(void)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	struct dmtimer_clockevent *clkevt = per_cpu_ptr(&dmtimer_percpu_timer, 0);
67562306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clkevt->t;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (t->sysc) {
67862306a36Sopenharmony_ci		cpuhp_setup_state(CPUHP_AP_TI_GP_TIMER_STARTING,
67962306a36Sopenharmony_ci				  "clockevents/omap/gptimer:starting",
68062306a36Sopenharmony_ci				  omap_dmtimer_starting_cpu, NULL);
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	return 0;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_cisubsys_initcall(dmtimer_percpu_timer_startup);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct device_node *arm_timer;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
69262306a36Sopenharmony_ci	if (of_device_is_available(arm_timer)) {
69362306a36Sopenharmony_ci		pr_warn_once("ARM architected timer wrap issue i940 detected\n");
69462306a36Sopenharmony_ci		return 0;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (pa == 0x4882c000)           /* dra7 dmtimer15 */
69862306a36Sopenharmony_ci		return dmtimer_percpu_timer_init(np, 0);
69962306a36Sopenharmony_ci	else if (pa == 0x4882e000)      /* dra7 dmtimer16 */
70062306a36Sopenharmony_ci		return dmtimer_percpu_timer_init(np, 1);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	return 0;
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci/* Clocksource */
70662306a36Sopenharmony_cistatic struct dmtimer_clocksource *
70762306a36Sopenharmony_cito_dmtimer_clocksource(struct clocksource *cs)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	return container_of(cs, struct dmtimer_clocksource, dev);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic u64 dmtimer_clocksource_read_cycles(struct clocksource *cs)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
71562306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clksrc->t;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	return (u64)readl_relaxed(t->base + t->counter);
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic void __iomem *dmtimer_sched_clock_counter;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic u64 notrace dmtimer_read_sched_clock(void)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	return readl_relaxed(dmtimer_sched_clock_counter);
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic void dmtimer_clocksource_suspend(struct clocksource *cs)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
73062306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clksrc->t;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	clksrc->loadval = readl_relaxed(t->base + t->counter);
73362306a36Sopenharmony_ci	dmtimer_systimer_disable(t);
73462306a36Sopenharmony_ci	clk_disable(t->fck);
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic void dmtimer_clocksource_resume(struct clocksource *cs)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct dmtimer_clocksource *clksrc = to_dmtimer_clocksource(cs);
74062306a36Sopenharmony_ci	struct dmtimer_systimer *t = &clksrc->t;
74162306a36Sopenharmony_ci	int error;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	error = clk_enable(t->fck);
74462306a36Sopenharmony_ci	if (error)
74562306a36Sopenharmony_ci		pr_err("could not enable timer fck on resume: %i\n", error);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	dmtimer_systimer_enable(t);
74862306a36Sopenharmony_ci	writel_relaxed(clksrc->loadval, t->base + t->counter);
74962306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
75062306a36Sopenharmony_ci		       t->base + t->ctrl);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic int __init dmtimer_clocksource_init(struct device_node *np)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	struct dmtimer_clocksource *clksrc;
75662306a36Sopenharmony_ci	struct dmtimer_systimer *t;
75762306a36Sopenharmony_ci	struct clocksource *dev;
75862306a36Sopenharmony_ci	int error;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	clksrc = kzalloc(sizeof(*clksrc), GFP_KERNEL);
76162306a36Sopenharmony_ci	if (!clksrc)
76262306a36Sopenharmony_ci		return -ENOMEM;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	dev = &clksrc->dev;
76562306a36Sopenharmony_ci	t = &clksrc->t;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	error = dmtimer_systimer_setup(np, t);
76862306a36Sopenharmony_ci	if (error)
76962306a36Sopenharmony_ci		goto err_out_free;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	dev->name = "dmtimer";
77262306a36Sopenharmony_ci	dev->rating = 300;
77362306a36Sopenharmony_ci	dev->read = dmtimer_clocksource_read_cycles;
77462306a36Sopenharmony_ci	dev->mask = CLOCKSOURCE_MASK(32);
77562306a36Sopenharmony_ci	dev->flags = CLOCK_SOURCE_IS_CONTINUOUS;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	/* Unlike for clockevent, legacy code sets suspend only for am4 */
77862306a36Sopenharmony_ci	if (of_machine_is_compatible("ti,am43")) {
77962306a36Sopenharmony_ci		dev->suspend = dmtimer_clocksource_suspend;
78062306a36Sopenharmony_ci		dev->resume = dmtimer_clocksource_resume;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	writel_relaxed(0, t->base + t->counter);
78462306a36Sopenharmony_ci	writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
78562306a36Sopenharmony_ci		       t->base + t->ctrl);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	pr_info("TI gptimer clocksource: %s%pOF\n",
78862306a36Sopenharmony_ci		of_property_read_bool(np, "ti,timer-alwon") ?
78962306a36Sopenharmony_ci		"always-on " : "", np->parent);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (!dmtimer_sched_clock_counter) {
79262306a36Sopenharmony_ci		dmtimer_sched_clock_counter = t->base + t->counter;
79362306a36Sopenharmony_ci		sched_clock_register(dmtimer_read_sched_clock, 32, t->rate);
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	if (clocksource_register_hz(dev, t->rate))
79762306a36Sopenharmony_ci		pr_err("Could not register clocksource %pOF\n", np);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	return 0;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cierr_out_free:
80262306a36Sopenharmony_ci	kfree(clksrc);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return -ENODEV;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci/*
80862306a36Sopenharmony_ci * To detect between a clocksource and clockevent, we assume the device tree
80962306a36Sopenharmony_ci * has no interrupts configured for a clocksource timer.
81062306a36Sopenharmony_ci */
81162306a36Sopenharmony_cistatic int __init dmtimer_systimer_init(struct device_node *np)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	struct resource res;
81462306a36Sopenharmony_ci	u32 pa;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	/* One time init for the preferred timer configuration */
81762306a36Sopenharmony_ci	if (!clocksource && !clockevent)
81862306a36Sopenharmony_ci		dmtimer_systimer_select_best();
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	if (!clocksource && !clockevent) {
82162306a36Sopenharmony_ci		pr_err("%s: unable to detect system timers, update dtb?\n",
82262306a36Sopenharmony_ci		       __func__);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		return -EINVAL;
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	of_address_to_resource(np, 0, &res);
82962306a36Sopenharmony_ci	pa = (u32)res.start;
83062306a36Sopenharmony_ci	if (!pa)
83162306a36Sopenharmony_ci		return -EINVAL;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if (counter_32k <= 0 && clocksource == pa)
83462306a36Sopenharmony_ci		return dmtimer_clocksource_init(np);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (clockevent == pa)
83762306a36Sopenharmony_ci		return dmtimer_clockevent_init(np);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (of_machine_is_compatible("ti,dra7"))
84062306a36Sopenharmony_ci		return dmtimer_percpu_quirk_init(np, pa);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	return 0;
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap2, "ti,omap2420-timer", dmtimer_systimer_init);
84662306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap3, "ti,omap3430-timer", dmtimer_systimer_init);
84762306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap4, "ti,omap4430-timer", dmtimer_systimer_init);
84862306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_omap5, "ti,omap5430-timer", dmtimer_systimer_init);
84962306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_am33x, "ti,am335x-timer", dmtimer_systimer_init);
85062306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_am3ms, "ti,am335x-timer-1ms", dmtimer_systimer_init);
85162306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_dm814, "ti,dm814-timer", dmtimer_systimer_init);
85262306a36Sopenharmony_ciTIMER_OF_DECLARE(systimer_dm816, "ti,dm816-timer", dmtimer_systimer_init);
853