162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * MPIC timer driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2013 Freescale Semiconductor, Inc.
662306a36Sopenharmony_ci * Author: Dongsheng Wang <Dongsheng.Wang@freescale.com>
762306a36Sopenharmony_ci *	   Li Yang <leoli@freescale.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/mm.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/of_address.h>
1962306a36Sopenharmony_ci#include <linux/of_irq.h>
2062306a36Sopenharmony_ci#include <linux/syscore_ops.h>
2162306a36Sopenharmony_ci#include <sysdev/fsl_soc.h>
2262306a36Sopenharmony_ci#include <asm/io.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <asm/mpic_timer.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define FSL_GLOBAL_TIMER		0x1
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* Clock Ratio
2962306a36Sopenharmony_ci * Divide by 64 0x00000300
3062306a36Sopenharmony_ci * Divide by 32 0x00000200
3162306a36Sopenharmony_ci * Divide by 16 0x00000100
3262306a36Sopenharmony_ci * Divide by  8 0x00000000 (Hardware default div)
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci#define MPIC_TIMER_TCR_CLKDIV		0x00000300
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define MPIC_TIMER_TCR_ROVR_OFFSET	24
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define TIMER_STOP			0x80000000
3962306a36Sopenharmony_ci#define GTCCR_TOG			0x80000000
4062306a36Sopenharmony_ci#define TIMERS_PER_GROUP		4
4162306a36Sopenharmony_ci#define MAX_TICKS			(~0U >> 1)
4262306a36Sopenharmony_ci#define MAX_TICKS_CASCADE		(~0U)
4362306a36Sopenharmony_ci#define TIMER_OFFSET(num)		(1 << (TIMERS_PER_GROUP - 1 - num))
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct timer_regs {
4662306a36Sopenharmony_ci	u32	gtccr;
4762306a36Sopenharmony_ci	u32	res0[3];
4862306a36Sopenharmony_ci	u32	gtbcr;
4962306a36Sopenharmony_ci	u32	res1[3];
5062306a36Sopenharmony_ci	u32	gtvpr;
5162306a36Sopenharmony_ci	u32	res2[3];
5262306a36Sopenharmony_ci	u32	gtdr;
5362306a36Sopenharmony_ci	u32	res3[3];
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct cascade_priv {
5762306a36Sopenharmony_ci	u32 tcr_value;			/* TCR register: CASC & ROVR value */
5862306a36Sopenharmony_ci	unsigned int cascade_map;	/* cascade map */
5962306a36Sopenharmony_ci	unsigned int timer_num;		/* cascade control timer */
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistruct timer_group_priv {
6362306a36Sopenharmony_ci	struct timer_regs __iomem	*regs;
6462306a36Sopenharmony_ci	struct mpic_timer		timer[TIMERS_PER_GROUP];
6562306a36Sopenharmony_ci	struct list_head		node;
6662306a36Sopenharmony_ci	unsigned int			timerfreq;
6762306a36Sopenharmony_ci	unsigned int			idle;
6862306a36Sopenharmony_ci	unsigned int			flags;
6962306a36Sopenharmony_ci	spinlock_t			lock;
7062306a36Sopenharmony_ci	void __iomem			*group_tcr;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic struct cascade_priv cascade_timer[] = {
7462306a36Sopenharmony_ci	/* cascade timer 0 and 1 */
7562306a36Sopenharmony_ci	{0x1, 0xc, 0x1},
7662306a36Sopenharmony_ci	/* cascade timer 1 and 2 */
7762306a36Sopenharmony_ci	{0x2, 0x6, 0x2},
7862306a36Sopenharmony_ci	/* cascade timer 2 and 3 */
7962306a36Sopenharmony_ci	{0x4, 0x3, 0x3}
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic LIST_HEAD(timer_group_list);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void convert_ticks_to_time(struct timer_group_priv *priv,
8562306a36Sopenharmony_ci		const u64 ticks, time64_t *time)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	*time = (u64)div_u64(ticks, priv->timerfreq);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* the time set by the user is converted to "ticks" */
9162306a36Sopenharmony_cistatic int convert_time_to_ticks(struct timer_group_priv *priv,
9262306a36Sopenharmony_ci		time64_t time, u64 *ticks)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	u64 max_value;		/* prevent u64 overflow */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	max_value = div_u64(ULLONG_MAX, priv->timerfreq);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (time > max_value)
9962306a36Sopenharmony_ci		return -EINVAL;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	*ticks = (u64)time * (u64)priv->timerfreq;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* detect whether there is a cascade timer available */
10762306a36Sopenharmony_cistatic struct mpic_timer *detect_idle_cascade_timer(
10862306a36Sopenharmony_ci					struct timer_group_priv *priv)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct cascade_priv *casc_priv;
11162306a36Sopenharmony_ci	unsigned int map;
11262306a36Sopenharmony_ci	unsigned int array_size = ARRAY_SIZE(cascade_timer);
11362306a36Sopenharmony_ci	unsigned int num;
11462306a36Sopenharmony_ci	unsigned int i;
11562306a36Sopenharmony_ci	unsigned long flags;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	casc_priv = cascade_timer;
11862306a36Sopenharmony_ci	for (i = 0; i < array_size; i++) {
11962306a36Sopenharmony_ci		spin_lock_irqsave(&priv->lock, flags);
12062306a36Sopenharmony_ci		map = casc_priv->cascade_map & priv->idle;
12162306a36Sopenharmony_ci		if (map == casc_priv->cascade_map) {
12262306a36Sopenharmony_ci			num = casc_priv->timer_num;
12362306a36Sopenharmony_ci			priv->timer[num].cascade_handle = casc_priv;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci			/* set timer busy */
12662306a36Sopenharmony_ci			priv->idle &= ~casc_priv->cascade_map;
12762306a36Sopenharmony_ci			spin_unlock_irqrestore(&priv->lock, flags);
12862306a36Sopenharmony_ci			return &priv->timer[num];
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci		spin_unlock_irqrestore(&priv->lock, flags);
13162306a36Sopenharmony_ci		casc_priv++;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return NULL;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic int set_cascade_timer(struct timer_group_priv *priv, u64 ticks,
13862306a36Sopenharmony_ci		unsigned int num)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct cascade_priv *casc_priv;
14162306a36Sopenharmony_ci	u32 tcr;
14262306a36Sopenharmony_ci	u32 tmp_ticks;
14362306a36Sopenharmony_ci	u32 rem_ticks;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* set group tcr reg for cascade */
14662306a36Sopenharmony_ci	casc_priv = priv->timer[num].cascade_handle;
14762306a36Sopenharmony_ci	if (!casc_priv)
14862306a36Sopenharmony_ci		return -EINVAL;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	tcr = casc_priv->tcr_value |
15162306a36Sopenharmony_ci		(casc_priv->tcr_value << MPIC_TIMER_TCR_ROVR_OFFSET);
15262306a36Sopenharmony_ci	setbits32(priv->group_tcr, tcr);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	tmp_ticks = div_u64_rem(ticks, MAX_TICKS_CASCADE, &rem_ticks);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	out_be32(&priv->regs[num].gtccr, 0);
15762306a36Sopenharmony_ci	out_be32(&priv->regs[num].gtbcr, tmp_ticks | TIMER_STOP);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	out_be32(&priv->regs[num - 1].gtccr, 0);
16062306a36Sopenharmony_ci	out_be32(&priv->regs[num - 1].gtbcr, rem_ticks);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic struct mpic_timer *get_cascade_timer(struct timer_group_priv *priv,
16662306a36Sopenharmony_ci					u64 ticks)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct mpic_timer *allocated_timer;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Two cascade timers: Support the maximum time */
17162306a36Sopenharmony_ci	const u64 max_ticks = (u64)MAX_TICKS * (u64)MAX_TICKS_CASCADE;
17262306a36Sopenharmony_ci	int ret;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (ticks > max_ticks)
17562306a36Sopenharmony_ci		return NULL;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* detect idle timer */
17862306a36Sopenharmony_ci	allocated_timer = detect_idle_cascade_timer(priv);
17962306a36Sopenharmony_ci	if (!allocated_timer)
18062306a36Sopenharmony_ci		return NULL;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* set ticks to timer */
18362306a36Sopenharmony_ci	ret = set_cascade_timer(priv, ticks, allocated_timer->num);
18462306a36Sopenharmony_ci	if (ret < 0)
18562306a36Sopenharmony_ci		return NULL;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return allocated_timer;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic struct mpic_timer *get_timer(time64_t time)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct timer_group_priv *priv;
19362306a36Sopenharmony_ci	struct mpic_timer *timer;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	u64 ticks;
19662306a36Sopenharmony_ci	unsigned int num;
19762306a36Sopenharmony_ci	unsigned int i;
19862306a36Sopenharmony_ci	unsigned long flags;
19962306a36Sopenharmony_ci	int ret;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	list_for_each_entry(priv, &timer_group_list, node) {
20262306a36Sopenharmony_ci		ret = convert_time_to_ticks(priv, time, &ticks);
20362306a36Sopenharmony_ci		if (ret < 0)
20462306a36Sopenharmony_ci			return NULL;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		if (ticks > MAX_TICKS) {
20762306a36Sopenharmony_ci			if (!(priv->flags & FSL_GLOBAL_TIMER))
20862306a36Sopenharmony_ci				return NULL;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci			timer = get_cascade_timer(priv, ticks);
21162306a36Sopenharmony_ci			if (!timer)
21262306a36Sopenharmony_ci				continue;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci			return timer;
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		for (i = 0; i < TIMERS_PER_GROUP; i++) {
21862306a36Sopenharmony_ci			/* one timer: Reverse allocation */
21962306a36Sopenharmony_ci			num = TIMERS_PER_GROUP - 1 - i;
22062306a36Sopenharmony_ci			spin_lock_irqsave(&priv->lock, flags);
22162306a36Sopenharmony_ci			if (priv->idle & (1 << i)) {
22262306a36Sopenharmony_ci				/* set timer busy */
22362306a36Sopenharmony_ci				priv->idle &= ~(1 << i);
22462306a36Sopenharmony_ci				/* set ticks & stop timer */
22562306a36Sopenharmony_ci				out_be32(&priv->regs[num].gtbcr,
22662306a36Sopenharmony_ci					ticks | TIMER_STOP);
22762306a36Sopenharmony_ci				out_be32(&priv->regs[num].gtccr, 0);
22862306a36Sopenharmony_ci				priv->timer[num].cascade_handle = NULL;
22962306a36Sopenharmony_ci				spin_unlock_irqrestore(&priv->lock, flags);
23062306a36Sopenharmony_ci				return &priv->timer[num];
23162306a36Sopenharmony_ci			}
23262306a36Sopenharmony_ci			spin_unlock_irqrestore(&priv->lock, flags);
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return NULL;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/**
24062306a36Sopenharmony_ci * mpic_start_timer - start hardware timer
24162306a36Sopenharmony_ci * @handle: the timer to be started.
24262306a36Sopenharmony_ci *
24362306a36Sopenharmony_ci * It will do ->fn(->dev) callback from the hardware interrupt at
24462306a36Sopenharmony_ci * the 'time64_t' point in the future.
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_civoid mpic_start_timer(struct mpic_timer *handle)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
24962306a36Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	clrbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ciEXPORT_SYMBOL(mpic_start_timer);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/**
25662306a36Sopenharmony_ci * mpic_stop_timer - stop hardware timer
25762306a36Sopenharmony_ci * @handle: the timer to be stopped
25862306a36Sopenharmony_ci *
25962306a36Sopenharmony_ci * The timer periodically generates an interrupt. Unless user stops the timer.
26062306a36Sopenharmony_ci */
26162306a36Sopenharmony_civoid mpic_stop_timer(struct mpic_timer *handle)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
26462306a36Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
26562306a36Sopenharmony_ci	struct cascade_priv *casc_priv;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	setbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	casc_priv = priv->timer[handle->num].cascade_handle;
27062306a36Sopenharmony_ci	if (casc_priv) {
27162306a36Sopenharmony_ci		out_be32(&priv->regs[handle->num].gtccr, 0);
27262306a36Sopenharmony_ci		out_be32(&priv->regs[handle->num - 1].gtccr, 0);
27362306a36Sopenharmony_ci	} else {
27462306a36Sopenharmony_ci		out_be32(&priv->regs[handle->num].gtccr, 0);
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ciEXPORT_SYMBOL(mpic_stop_timer);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/**
28062306a36Sopenharmony_ci * mpic_get_remain_time - get timer time
28162306a36Sopenharmony_ci * @handle: the timer to be selected.
28262306a36Sopenharmony_ci * @time: time for timer
28362306a36Sopenharmony_ci *
28462306a36Sopenharmony_ci * Query timer remaining time.
28562306a36Sopenharmony_ci */
28662306a36Sopenharmony_civoid mpic_get_remain_time(struct mpic_timer *handle, time64_t *time)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
28962306a36Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
29062306a36Sopenharmony_ci	struct cascade_priv *casc_priv;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	u64 ticks;
29362306a36Sopenharmony_ci	u32 tmp_ticks;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	casc_priv = priv->timer[handle->num].cascade_handle;
29662306a36Sopenharmony_ci	if (casc_priv) {
29762306a36Sopenharmony_ci		tmp_ticks = in_be32(&priv->regs[handle->num].gtccr);
29862306a36Sopenharmony_ci		tmp_ticks &= ~GTCCR_TOG;
29962306a36Sopenharmony_ci		ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE;
30062306a36Sopenharmony_ci		tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr);
30162306a36Sopenharmony_ci		ticks += tmp_ticks;
30262306a36Sopenharmony_ci	} else {
30362306a36Sopenharmony_ci		ticks = in_be32(&priv->regs[handle->num].gtccr);
30462306a36Sopenharmony_ci		ticks &= ~GTCCR_TOG;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	convert_ticks_to_time(priv, ticks, time);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ciEXPORT_SYMBOL(mpic_get_remain_time);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/**
31262306a36Sopenharmony_ci * mpic_free_timer - free hardware timer
31362306a36Sopenharmony_ci * @handle: the timer to be removed.
31462306a36Sopenharmony_ci *
31562306a36Sopenharmony_ci * Free the timer.
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci * Note: can not be used in interrupt context.
31862306a36Sopenharmony_ci */
31962306a36Sopenharmony_civoid mpic_free_timer(struct mpic_timer *handle)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
32262306a36Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	struct cascade_priv *casc_priv;
32562306a36Sopenharmony_ci	unsigned long flags;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	mpic_stop_timer(handle);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	casc_priv = priv->timer[handle->num].cascade_handle;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	free_irq(priv->timer[handle->num].irq, priv->timer[handle->num].dev);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, flags);
33462306a36Sopenharmony_ci	if (casc_priv) {
33562306a36Sopenharmony_ci		u32 tcr;
33662306a36Sopenharmony_ci		tcr = casc_priv->tcr_value | (casc_priv->tcr_value <<
33762306a36Sopenharmony_ci					MPIC_TIMER_TCR_ROVR_OFFSET);
33862306a36Sopenharmony_ci		clrbits32(priv->group_tcr, tcr);
33962306a36Sopenharmony_ci		priv->idle |= casc_priv->cascade_map;
34062306a36Sopenharmony_ci		priv->timer[handle->num].cascade_handle = NULL;
34162306a36Sopenharmony_ci	} else {
34262306a36Sopenharmony_ci		priv->idle |= TIMER_OFFSET(handle->num);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, flags);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ciEXPORT_SYMBOL(mpic_free_timer);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/**
34962306a36Sopenharmony_ci * mpic_request_timer - get a hardware timer
35062306a36Sopenharmony_ci * @fn: interrupt handler function
35162306a36Sopenharmony_ci * @dev: callback function of the data
35262306a36Sopenharmony_ci * @time: time for timer
35362306a36Sopenharmony_ci *
35462306a36Sopenharmony_ci * This executes the "request_irq", returning NULL
35562306a36Sopenharmony_ci * else "handle" on success.
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_cistruct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
35862306a36Sopenharmony_ci				      time64_t time)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	struct mpic_timer *allocated_timer;
36162306a36Sopenharmony_ci	int ret;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (list_empty(&timer_group_list))
36462306a36Sopenharmony_ci		return NULL;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (time < 0)
36762306a36Sopenharmony_ci		return NULL;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	allocated_timer = get_timer(time);
37062306a36Sopenharmony_ci	if (!allocated_timer)
37162306a36Sopenharmony_ci		return NULL;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	ret = request_irq(allocated_timer->irq, fn,
37462306a36Sopenharmony_ci			IRQF_TRIGGER_LOW, "global-timer", dev);
37562306a36Sopenharmony_ci	if (ret) {
37662306a36Sopenharmony_ci		mpic_free_timer(allocated_timer);
37762306a36Sopenharmony_ci		return NULL;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	allocated_timer->dev = dev;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return allocated_timer;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ciEXPORT_SYMBOL(mpic_request_timer);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic int __init timer_group_get_freq(struct device_node *np,
38762306a36Sopenharmony_ci			struct timer_group_priv *priv)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	u32 div;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER) {
39262306a36Sopenharmony_ci		struct device_node *dn;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		dn = of_find_compatible_node(NULL, NULL, "fsl,mpic");
39562306a36Sopenharmony_ci		if (dn) {
39662306a36Sopenharmony_ci			of_property_read_u32(dn, "clock-frequency",
39762306a36Sopenharmony_ci					&priv->timerfreq);
39862306a36Sopenharmony_ci			of_node_put(dn);
39962306a36Sopenharmony_ci		}
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (priv->timerfreq <= 0)
40362306a36Sopenharmony_ci		return -EINVAL;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER) {
40662306a36Sopenharmony_ci		div = (1 << (MPIC_TIMER_TCR_CLKDIV >> 8)) * 8;
40762306a36Sopenharmony_ci		priv->timerfreq /= div;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic int __init timer_group_get_irq(struct device_node *np,
41462306a36Sopenharmony_ci		struct timer_group_priv *priv)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	const u32 all_timer[] = { 0, TIMERS_PER_GROUP };
41762306a36Sopenharmony_ci	const u32 *p;
41862306a36Sopenharmony_ci	u32 offset;
41962306a36Sopenharmony_ci	u32 count;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	unsigned int i;
42262306a36Sopenharmony_ci	unsigned int j;
42362306a36Sopenharmony_ci	unsigned int irq_index = 0;
42462306a36Sopenharmony_ci	unsigned int irq;
42562306a36Sopenharmony_ci	int len;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	p = of_get_property(np, "fsl,available-ranges", &len);
42862306a36Sopenharmony_ci	if (p && len % (2 * sizeof(u32)) != 0) {
42962306a36Sopenharmony_ci		pr_err("%pOF: malformed available-ranges property.\n", np);
43062306a36Sopenharmony_ci		return -EINVAL;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (!p) {
43462306a36Sopenharmony_ci		p = all_timer;
43562306a36Sopenharmony_ci		len = sizeof(all_timer);
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	len /= 2 * sizeof(u32);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
44162306a36Sopenharmony_ci		offset = p[i * 2];
44262306a36Sopenharmony_ci		count = p[i * 2 + 1];
44362306a36Sopenharmony_ci		for (j = 0; j < count; j++) {
44462306a36Sopenharmony_ci			irq = irq_of_parse_and_map(np, irq_index);
44562306a36Sopenharmony_ci			if (!irq) {
44662306a36Sopenharmony_ci				pr_err("%pOF: irq parse and map failed.\n", np);
44762306a36Sopenharmony_ci				return -EINVAL;
44862306a36Sopenharmony_ci			}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci			/* Set timer idle */
45162306a36Sopenharmony_ci			priv->idle |= TIMER_OFFSET((offset + j));
45262306a36Sopenharmony_ci			priv->timer[offset + j].irq = irq;
45362306a36Sopenharmony_ci			priv->timer[offset + j].num = offset + j;
45462306a36Sopenharmony_ci			irq_index++;
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return 0;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic void __init timer_group_init(struct device_node *np)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct timer_group_priv *priv;
46462306a36Sopenharmony_ci	unsigned int i = 0;
46562306a36Sopenharmony_ci	int ret;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	priv = kzalloc(sizeof(struct timer_group_priv), GFP_KERNEL);
46862306a36Sopenharmony_ci	if (!priv) {
46962306a36Sopenharmony_ci		pr_err("%pOF: cannot allocate memory for group.\n", np);
47062306a36Sopenharmony_ci		return;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,mpic-global-timer"))
47462306a36Sopenharmony_ci		priv->flags |= FSL_GLOBAL_TIMER;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	priv->regs = of_iomap(np, i++);
47762306a36Sopenharmony_ci	if (!priv->regs) {
47862306a36Sopenharmony_ci		pr_err("%pOF: cannot ioremap timer register address.\n", np);
47962306a36Sopenharmony_ci		goto out;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER) {
48362306a36Sopenharmony_ci		priv->group_tcr = of_iomap(np, i++);
48462306a36Sopenharmony_ci		if (!priv->group_tcr) {
48562306a36Sopenharmony_ci			pr_err("%pOF: cannot ioremap tcr address.\n", np);
48662306a36Sopenharmony_ci			goto out;
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ret = timer_group_get_freq(np, priv);
49162306a36Sopenharmony_ci	if (ret < 0) {
49262306a36Sopenharmony_ci		pr_err("%pOF: cannot get timer frequency.\n", np);
49362306a36Sopenharmony_ci		goto out;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	ret = timer_group_get_irq(np, priv);
49762306a36Sopenharmony_ci	if (ret < 0) {
49862306a36Sopenharmony_ci		pr_err("%pOF: cannot get timer irqs.\n", np);
49962306a36Sopenharmony_ci		goto out;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	spin_lock_init(&priv->lock);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/* Init FSL timer hardware */
50562306a36Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER)
50662306a36Sopenharmony_ci		setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	list_add_tail(&priv->node, &timer_group_list);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	return;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ciout:
51362306a36Sopenharmony_ci	if (priv->regs)
51462306a36Sopenharmony_ci		iounmap(priv->regs);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (priv->group_tcr)
51762306a36Sopenharmony_ci		iounmap(priv->group_tcr);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	kfree(priv);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic void mpic_timer_resume(void)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	struct timer_group_priv *priv;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	list_for_each_entry(priv, &timer_group_list, node) {
52762306a36Sopenharmony_ci		/* Init FSL timer hardware */
52862306a36Sopenharmony_ci		if (priv->flags & FSL_GLOBAL_TIMER)
52962306a36Sopenharmony_ci			setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic const struct of_device_id mpic_timer_ids[] = {
53462306a36Sopenharmony_ci	{ .compatible = "fsl,mpic-global-timer", },
53562306a36Sopenharmony_ci	{},
53662306a36Sopenharmony_ci};
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic struct syscore_ops mpic_timer_syscore_ops = {
53962306a36Sopenharmony_ci	.resume = mpic_timer_resume,
54062306a36Sopenharmony_ci};
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic int __init mpic_timer_init(void)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct device_node *np = NULL;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	for_each_matching_node(np, mpic_timer_ids)
54762306a36Sopenharmony_ci		timer_group_init(np);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	register_syscore_ops(&mpic_timer_syscore_ops);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (list_empty(&timer_group_list))
55262306a36Sopenharmony_ci		return -ENODEV;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	return 0;
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_cisubsys_initcall(mpic_timer_init);
557