18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * MPIC timer driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2013 Freescale Semiconductor, Inc.
68c2ecf20Sopenharmony_ci * Author: Dongsheng Wang <Dongsheng.Wang@freescale.com>
78c2ecf20Sopenharmony_ci *	   Li Yang <leoli@freescale.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/mm.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/of_address.h>
198c2ecf20Sopenharmony_ci#include <linux/of_device.h>
208c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
218c2ecf20Sopenharmony_ci#include <linux/syscore_ops.h>
228c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h>
238c2ecf20Sopenharmony_ci#include <asm/io.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <asm/mpic_timer.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define FSL_GLOBAL_TIMER		0x1
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Clock Ratio
308c2ecf20Sopenharmony_ci * Divide by 64 0x00000300
318c2ecf20Sopenharmony_ci * Divide by 32 0x00000200
328c2ecf20Sopenharmony_ci * Divide by 16 0x00000100
338c2ecf20Sopenharmony_ci * Divide by  8 0x00000000 (Hardware default div)
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_ci#define MPIC_TIMER_TCR_CLKDIV		0x00000300
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#define MPIC_TIMER_TCR_ROVR_OFFSET	24
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#define TIMER_STOP			0x80000000
408c2ecf20Sopenharmony_ci#define GTCCR_TOG			0x80000000
418c2ecf20Sopenharmony_ci#define TIMERS_PER_GROUP		4
428c2ecf20Sopenharmony_ci#define MAX_TICKS			(~0U >> 1)
438c2ecf20Sopenharmony_ci#define MAX_TICKS_CASCADE		(~0U)
448c2ecf20Sopenharmony_ci#define TIMER_OFFSET(num)		(1 << (TIMERS_PER_GROUP - 1 - num))
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistruct timer_regs {
478c2ecf20Sopenharmony_ci	u32	gtccr;
488c2ecf20Sopenharmony_ci	u32	res0[3];
498c2ecf20Sopenharmony_ci	u32	gtbcr;
508c2ecf20Sopenharmony_ci	u32	res1[3];
518c2ecf20Sopenharmony_ci	u32	gtvpr;
528c2ecf20Sopenharmony_ci	u32	res2[3];
538c2ecf20Sopenharmony_ci	u32	gtdr;
548c2ecf20Sopenharmony_ci	u32	res3[3];
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistruct cascade_priv {
588c2ecf20Sopenharmony_ci	u32 tcr_value;			/* TCR register: CASC & ROVR value */
598c2ecf20Sopenharmony_ci	unsigned int cascade_map;	/* cascade map */
608c2ecf20Sopenharmony_ci	unsigned int timer_num;		/* cascade control timer */
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistruct timer_group_priv {
648c2ecf20Sopenharmony_ci	struct timer_regs __iomem	*regs;
658c2ecf20Sopenharmony_ci	struct mpic_timer		timer[TIMERS_PER_GROUP];
668c2ecf20Sopenharmony_ci	struct list_head		node;
678c2ecf20Sopenharmony_ci	unsigned int			timerfreq;
688c2ecf20Sopenharmony_ci	unsigned int			idle;
698c2ecf20Sopenharmony_ci	unsigned int			flags;
708c2ecf20Sopenharmony_ci	spinlock_t			lock;
718c2ecf20Sopenharmony_ci	void __iomem			*group_tcr;
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic struct cascade_priv cascade_timer[] = {
758c2ecf20Sopenharmony_ci	/* cascade timer 0 and 1 */
768c2ecf20Sopenharmony_ci	{0x1, 0xc, 0x1},
778c2ecf20Sopenharmony_ci	/* cascade timer 1 and 2 */
788c2ecf20Sopenharmony_ci	{0x2, 0x6, 0x2},
798c2ecf20Sopenharmony_ci	/* cascade timer 2 and 3 */
808c2ecf20Sopenharmony_ci	{0x4, 0x3, 0x3}
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic LIST_HEAD(timer_group_list);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void convert_ticks_to_time(struct timer_group_priv *priv,
868c2ecf20Sopenharmony_ci		const u64 ticks, time64_t *time)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	*time = (u64)div_u64(ticks, priv->timerfreq);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* the time set by the user is converted to "ticks" */
928c2ecf20Sopenharmony_cistatic int convert_time_to_ticks(struct timer_group_priv *priv,
938c2ecf20Sopenharmony_ci		time64_t time, u64 *ticks)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	u64 max_value;		/* prevent u64 overflow */
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	max_value = div_u64(ULLONG_MAX, priv->timerfreq);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (time > max_value)
1008c2ecf20Sopenharmony_ci		return -EINVAL;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	*ticks = (u64)time * (u64)priv->timerfreq;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return 0;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/* detect whether there is a cascade timer available */
1088c2ecf20Sopenharmony_cistatic struct mpic_timer *detect_idle_cascade_timer(
1098c2ecf20Sopenharmony_ci					struct timer_group_priv *priv)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct cascade_priv *casc_priv;
1128c2ecf20Sopenharmony_ci	unsigned int map;
1138c2ecf20Sopenharmony_ci	unsigned int array_size = ARRAY_SIZE(cascade_timer);
1148c2ecf20Sopenharmony_ci	unsigned int num;
1158c2ecf20Sopenharmony_ci	unsigned int i;
1168c2ecf20Sopenharmony_ci	unsigned long flags;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	casc_priv = cascade_timer;
1198c2ecf20Sopenharmony_ci	for (i = 0; i < array_size; i++) {
1208c2ecf20Sopenharmony_ci		spin_lock_irqsave(&priv->lock, flags);
1218c2ecf20Sopenharmony_ci		map = casc_priv->cascade_map & priv->idle;
1228c2ecf20Sopenharmony_ci		if (map == casc_priv->cascade_map) {
1238c2ecf20Sopenharmony_ci			num = casc_priv->timer_num;
1248c2ecf20Sopenharmony_ci			priv->timer[num].cascade_handle = casc_priv;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci			/* set timer busy */
1278c2ecf20Sopenharmony_ci			priv->idle &= ~casc_priv->cascade_map;
1288c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&priv->lock, flags);
1298c2ecf20Sopenharmony_ci			return &priv->timer[num];
1308c2ecf20Sopenharmony_ci		}
1318c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&priv->lock, flags);
1328c2ecf20Sopenharmony_ci		casc_priv++;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return NULL;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int set_cascade_timer(struct timer_group_priv *priv, u64 ticks,
1398c2ecf20Sopenharmony_ci		unsigned int num)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct cascade_priv *casc_priv;
1428c2ecf20Sopenharmony_ci	u32 tcr;
1438c2ecf20Sopenharmony_ci	u32 tmp_ticks;
1448c2ecf20Sopenharmony_ci	u32 rem_ticks;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* set group tcr reg for cascade */
1478c2ecf20Sopenharmony_ci	casc_priv = priv->timer[num].cascade_handle;
1488c2ecf20Sopenharmony_ci	if (!casc_priv)
1498c2ecf20Sopenharmony_ci		return -EINVAL;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	tcr = casc_priv->tcr_value |
1528c2ecf20Sopenharmony_ci		(casc_priv->tcr_value << MPIC_TIMER_TCR_ROVR_OFFSET);
1538c2ecf20Sopenharmony_ci	setbits32(priv->group_tcr, tcr);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	tmp_ticks = div_u64_rem(ticks, MAX_TICKS_CASCADE, &rem_ticks);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	out_be32(&priv->regs[num].gtccr, 0);
1588c2ecf20Sopenharmony_ci	out_be32(&priv->regs[num].gtbcr, tmp_ticks | TIMER_STOP);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	out_be32(&priv->regs[num - 1].gtccr, 0);
1618c2ecf20Sopenharmony_ci	out_be32(&priv->regs[num - 1].gtbcr, rem_ticks);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic struct mpic_timer *get_cascade_timer(struct timer_group_priv *priv,
1678c2ecf20Sopenharmony_ci					u64 ticks)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct mpic_timer *allocated_timer;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* Two cascade timers: Support the maximum time */
1728c2ecf20Sopenharmony_ci	const u64 max_ticks = (u64)MAX_TICKS * (u64)MAX_TICKS_CASCADE;
1738c2ecf20Sopenharmony_ci	int ret;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (ticks > max_ticks)
1768c2ecf20Sopenharmony_ci		return NULL;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* detect idle timer */
1798c2ecf20Sopenharmony_ci	allocated_timer = detect_idle_cascade_timer(priv);
1808c2ecf20Sopenharmony_ci	if (!allocated_timer)
1818c2ecf20Sopenharmony_ci		return NULL;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	/* set ticks to timer */
1848c2ecf20Sopenharmony_ci	ret = set_cascade_timer(priv, ticks, allocated_timer->num);
1858c2ecf20Sopenharmony_ci	if (ret < 0)
1868c2ecf20Sopenharmony_ci		return NULL;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return allocated_timer;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic struct mpic_timer *get_timer(time64_t time)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct timer_group_priv *priv;
1948c2ecf20Sopenharmony_ci	struct mpic_timer *timer;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	u64 ticks;
1978c2ecf20Sopenharmony_ci	unsigned int num;
1988c2ecf20Sopenharmony_ci	unsigned int i;
1998c2ecf20Sopenharmony_ci	unsigned long flags;
2008c2ecf20Sopenharmony_ci	int ret;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	list_for_each_entry(priv, &timer_group_list, node) {
2038c2ecf20Sopenharmony_ci		ret = convert_time_to_ticks(priv, time, &ticks);
2048c2ecf20Sopenharmony_ci		if (ret < 0)
2058c2ecf20Sopenharmony_ci			return NULL;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		if (ticks > MAX_TICKS) {
2088c2ecf20Sopenharmony_ci			if (!(priv->flags & FSL_GLOBAL_TIMER))
2098c2ecf20Sopenharmony_ci				return NULL;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci			timer = get_cascade_timer(priv, ticks);
2128c2ecf20Sopenharmony_ci			if (!timer)
2138c2ecf20Sopenharmony_ci				continue;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci			return timer;
2168c2ecf20Sopenharmony_ci		}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		for (i = 0; i < TIMERS_PER_GROUP; i++) {
2198c2ecf20Sopenharmony_ci			/* one timer: Reverse allocation */
2208c2ecf20Sopenharmony_ci			num = TIMERS_PER_GROUP - 1 - i;
2218c2ecf20Sopenharmony_ci			spin_lock_irqsave(&priv->lock, flags);
2228c2ecf20Sopenharmony_ci			if (priv->idle & (1 << i)) {
2238c2ecf20Sopenharmony_ci				/* set timer busy */
2248c2ecf20Sopenharmony_ci				priv->idle &= ~(1 << i);
2258c2ecf20Sopenharmony_ci				/* set ticks & stop timer */
2268c2ecf20Sopenharmony_ci				out_be32(&priv->regs[num].gtbcr,
2278c2ecf20Sopenharmony_ci					ticks | TIMER_STOP);
2288c2ecf20Sopenharmony_ci				out_be32(&priv->regs[num].gtccr, 0);
2298c2ecf20Sopenharmony_ci				priv->timer[num].cascade_handle = NULL;
2308c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&priv->lock, flags);
2318c2ecf20Sopenharmony_ci				return &priv->timer[num];
2328c2ecf20Sopenharmony_ci			}
2338c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&priv->lock, flags);
2348c2ecf20Sopenharmony_ci		}
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return NULL;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci/**
2418c2ecf20Sopenharmony_ci * mpic_start_timer - start hardware timer
2428c2ecf20Sopenharmony_ci * @handle: the timer to be started.
2438c2ecf20Sopenharmony_ci *
2448c2ecf20Sopenharmony_ci * It will do ->fn(->dev) callback from the hardware interrupt at
2458c2ecf20Sopenharmony_ci * the 'time64_t' point in the future.
2468c2ecf20Sopenharmony_ci */
2478c2ecf20Sopenharmony_civoid mpic_start_timer(struct mpic_timer *handle)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
2508c2ecf20Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	clrbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpic_start_timer);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/**
2578c2ecf20Sopenharmony_ci * mpic_stop_timer - stop hardware timer
2588c2ecf20Sopenharmony_ci * @handle: the timer to be stoped
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci * The timer periodically generates an interrupt. Unless user stops the timer.
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_civoid mpic_stop_timer(struct mpic_timer *handle)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
2658c2ecf20Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
2668c2ecf20Sopenharmony_ci	struct cascade_priv *casc_priv;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	setbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	casc_priv = priv->timer[handle->num].cascade_handle;
2718c2ecf20Sopenharmony_ci	if (casc_priv) {
2728c2ecf20Sopenharmony_ci		out_be32(&priv->regs[handle->num].gtccr, 0);
2738c2ecf20Sopenharmony_ci		out_be32(&priv->regs[handle->num - 1].gtccr, 0);
2748c2ecf20Sopenharmony_ci	} else {
2758c2ecf20Sopenharmony_ci		out_be32(&priv->regs[handle->num].gtccr, 0);
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpic_stop_timer);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/**
2818c2ecf20Sopenharmony_ci * mpic_get_remain_time - get timer time
2828c2ecf20Sopenharmony_ci * @handle: the timer to be selected.
2838c2ecf20Sopenharmony_ci * @time: time for timer
2848c2ecf20Sopenharmony_ci *
2858c2ecf20Sopenharmony_ci * Query timer remaining time.
2868c2ecf20Sopenharmony_ci */
2878c2ecf20Sopenharmony_civoid mpic_get_remain_time(struct mpic_timer *handle, time64_t *time)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
2908c2ecf20Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
2918c2ecf20Sopenharmony_ci	struct cascade_priv *casc_priv;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	u64 ticks;
2948c2ecf20Sopenharmony_ci	u32 tmp_ticks;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	casc_priv = priv->timer[handle->num].cascade_handle;
2978c2ecf20Sopenharmony_ci	if (casc_priv) {
2988c2ecf20Sopenharmony_ci		tmp_ticks = in_be32(&priv->regs[handle->num].gtccr);
2998c2ecf20Sopenharmony_ci		tmp_ticks &= ~GTCCR_TOG;
3008c2ecf20Sopenharmony_ci		ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE;
3018c2ecf20Sopenharmony_ci		tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr);
3028c2ecf20Sopenharmony_ci		ticks += tmp_ticks;
3038c2ecf20Sopenharmony_ci	} else {
3048c2ecf20Sopenharmony_ci		ticks = in_be32(&priv->regs[handle->num].gtccr);
3058c2ecf20Sopenharmony_ci		ticks &= ~GTCCR_TOG;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	convert_ticks_to_time(priv, ticks, time);
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpic_get_remain_time);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/**
3138c2ecf20Sopenharmony_ci * mpic_free_timer - free hardware timer
3148c2ecf20Sopenharmony_ci * @handle: the timer to be removed.
3158c2ecf20Sopenharmony_ci *
3168c2ecf20Sopenharmony_ci * Free the timer.
3178c2ecf20Sopenharmony_ci *
3188c2ecf20Sopenharmony_ci * Note: can not be used in interrupt context.
3198c2ecf20Sopenharmony_ci */
3208c2ecf20Sopenharmony_civoid mpic_free_timer(struct mpic_timer *handle)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct timer_group_priv *priv = container_of(handle,
3238c2ecf20Sopenharmony_ci			struct timer_group_priv, timer[handle->num]);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	struct cascade_priv *casc_priv;
3268c2ecf20Sopenharmony_ci	unsigned long flags;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	mpic_stop_timer(handle);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	casc_priv = priv->timer[handle->num].cascade_handle;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	free_irq(priv->timer[handle->num].irq, priv->timer[handle->num].dev);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->lock, flags);
3358c2ecf20Sopenharmony_ci	if (casc_priv) {
3368c2ecf20Sopenharmony_ci		u32 tcr;
3378c2ecf20Sopenharmony_ci		tcr = casc_priv->tcr_value | (casc_priv->tcr_value <<
3388c2ecf20Sopenharmony_ci					MPIC_TIMER_TCR_ROVR_OFFSET);
3398c2ecf20Sopenharmony_ci		clrbits32(priv->group_tcr, tcr);
3408c2ecf20Sopenharmony_ci		priv->idle |= casc_priv->cascade_map;
3418c2ecf20Sopenharmony_ci		priv->timer[handle->num].cascade_handle = NULL;
3428c2ecf20Sopenharmony_ci	} else {
3438c2ecf20Sopenharmony_ci		priv->idle |= TIMER_OFFSET(handle->num);
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, flags);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpic_free_timer);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/**
3508c2ecf20Sopenharmony_ci * mpic_request_timer - get a hardware timer
3518c2ecf20Sopenharmony_ci * @fn: interrupt handler function
3528c2ecf20Sopenharmony_ci * @dev: callback function of the data
3538c2ecf20Sopenharmony_ci * @time: time for timer
3548c2ecf20Sopenharmony_ci *
3558c2ecf20Sopenharmony_ci * This executes the "request_irq", returning NULL
3568c2ecf20Sopenharmony_ci * else "handle" on success.
3578c2ecf20Sopenharmony_ci */
3588c2ecf20Sopenharmony_cistruct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
3598c2ecf20Sopenharmony_ci				      time64_t time)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct mpic_timer *allocated_timer;
3628c2ecf20Sopenharmony_ci	int ret;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (list_empty(&timer_group_list))
3658c2ecf20Sopenharmony_ci		return NULL;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (time < 0)
3688c2ecf20Sopenharmony_ci		return NULL;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	allocated_timer = get_timer(time);
3718c2ecf20Sopenharmony_ci	if (!allocated_timer)
3728c2ecf20Sopenharmony_ci		return NULL;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	ret = request_irq(allocated_timer->irq, fn,
3758c2ecf20Sopenharmony_ci			IRQF_TRIGGER_LOW, "global-timer", dev);
3768c2ecf20Sopenharmony_ci	if (ret) {
3778c2ecf20Sopenharmony_ci		mpic_free_timer(allocated_timer);
3788c2ecf20Sopenharmony_ci		return NULL;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	allocated_timer->dev = dev;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	return allocated_timer;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mpic_request_timer);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int timer_group_get_freq(struct device_node *np,
3888c2ecf20Sopenharmony_ci			struct timer_group_priv *priv)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	u32 div;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER) {
3938c2ecf20Sopenharmony_ci		struct device_node *dn;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		dn = of_find_compatible_node(NULL, NULL, "fsl,mpic");
3968c2ecf20Sopenharmony_ci		if (dn) {
3978c2ecf20Sopenharmony_ci			of_property_read_u32(dn, "clock-frequency",
3988c2ecf20Sopenharmony_ci					&priv->timerfreq);
3998c2ecf20Sopenharmony_ci			of_node_put(dn);
4008c2ecf20Sopenharmony_ci		}
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (priv->timerfreq <= 0)
4048c2ecf20Sopenharmony_ci		return -EINVAL;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER) {
4078c2ecf20Sopenharmony_ci		div = (1 << (MPIC_TIMER_TCR_CLKDIV >> 8)) * 8;
4088c2ecf20Sopenharmony_ci		priv->timerfreq /= div;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	return 0;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic int timer_group_get_irq(struct device_node *np,
4158c2ecf20Sopenharmony_ci		struct timer_group_priv *priv)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	const u32 all_timer[] = { 0, TIMERS_PER_GROUP };
4188c2ecf20Sopenharmony_ci	const u32 *p;
4198c2ecf20Sopenharmony_ci	u32 offset;
4208c2ecf20Sopenharmony_ci	u32 count;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	unsigned int i;
4238c2ecf20Sopenharmony_ci	unsigned int j;
4248c2ecf20Sopenharmony_ci	unsigned int irq_index = 0;
4258c2ecf20Sopenharmony_ci	unsigned int irq;
4268c2ecf20Sopenharmony_ci	int len;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	p = of_get_property(np, "fsl,available-ranges", &len);
4298c2ecf20Sopenharmony_ci	if (p && len % (2 * sizeof(u32)) != 0) {
4308c2ecf20Sopenharmony_ci		pr_err("%pOF: malformed available-ranges property.\n", np);
4318c2ecf20Sopenharmony_ci		return -EINVAL;
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (!p) {
4358c2ecf20Sopenharmony_ci		p = all_timer;
4368c2ecf20Sopenharmony_ci		len = sizeof(all_timer);
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	len /= 2 * sizeof(u32);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
4428c2ecf20Sopenharmony_ci		offset = p[i * 2];
4438c2ecf20Sopenharmony_ci		count = p[i * 2 + 1];
4448c2ecf20Sopenharmony_ci		for (j = 0; j < count; j++) {
4458c2ecf20Sopenharmony_ci			irq = irq_of_parse_and_map(np, irq_index);
4468c2ecf20Sopenharmony_ci			if (!irq) {
4478c2ecf20Sopenharmony_ci				pr_err("%pOF: irq parse and map failed.\n", np);
4488c2ecf20Sopenharmony_ci				return -EINVAL;
4498c2ecf20Sopenharmony_ci			}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci			/* Set timer idle */
4528c2ecf20Sopenharmony_ci			priv->idle |= TIMER_OFFSET((offset + j));
4538c2ecf20Sopenharmony_ci			priv->timer[offset + j].irq = irq;
4548c2ecf20Sopenharmony_ci			priv->timer[offset + j].num = offset + j;
4558c2ecf20Sopenharmony_ci			irq_index++;
4568c2ecf20Sopenharmony_ci		}
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	return 0;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic void timer_group_init(struct device_node *np)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	struct timer_group_priv *priv;
4658c2ecf20Sopenharmony_ci	unsigned int i = 0;
4668c2ecf20Sopenharmony_ci	int ret;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	priv = kzalloc(sizeof(struct timer_group_priv), GFP_KERNEL);
4698c2ecf20Sopenharmony_ci	if (!priv) {
4708c2ecf20Sopenharmony_ci		pr_err("%pOF: cannot allocate memory for group.\n", np);
4718c2ecf20Sopenharmony_ci		return;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,mpic-global-timer"))
4758c2ecf20Sopenharmony_ci		priv->flags |= FSL_GLOBAL_TIMER;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	priv->regs = of_iomap(np, i++);
4788c2ecf20Sopenharmony_ci	if (!priv->regs) {
4798c2ecf20Sopenharmony_ci		pr_err("%pOF: cannot ioremap timer register address.\n", np);
4808c2ecf20Sopenharmony_ci		goto out;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER) {
4848c2ecf20Sopenharmony_ci		priv->group_tcr = of_iomap(np, i++);
4858c2ecf20Sopenharmony_ci		if (!priv->group_tcr) {
4868c2ecf20Sopenharmony_ci			pr_err("%pOF: cannot ioremap tcr address.\n", np);
4878c2ecf20Sopenharmony_ci			goto out;
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	ret = timer_group_get_freq(np, priv);
4928c2ecf20Sopenharmony_ci	if (ret < 0) {
4938c2ecf20Sopenharmony_ci		pr_err("%pOF: cannot get timer frequency.\n", np);
4948c2ecf20Sopenharmony_ci		goto out;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	ret = timer_group_get_irq(np, priv);
4988c2ecf20Sopenharmony_ci	if (ret < 0) {
4998c2ecf20Sopenharmony_ci		pr_err("%pOF: cannot get timer irqs.\n", np);
5008c2ecf20Sopenharmony_ci		goto out;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	spin_lock_init(&priv->lock);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* Init FSL timer hardware */
5068c2ecf20Sopenharmony_ci	if (priv->flags & FSL_GLOBAL_TIMER)
5078c2ecf20Sopenharmony_ci		setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	list_add_tail(&priv->node, &timer_group_list);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	return;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ciout:
5148c2ecf20Sopenharmony_ci	if (priv->regs)
5158c2ecf20Sopenharmony_ci		iounmap(priv->regs);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (priv->group_tcr)
5188c2ecf20Sopenharmony_ci		iounmap(priv->group_tcr);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	kfree(priv);
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic void mpic_timer_resume(void)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct timer_group_priv *priv;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	list_for_each_entry(priv, &timer_group_list, node) {
5288c2ecf20Sopenharmony_ci		/* Init FSL timer hardware */
5298c2ecf20Sopenharmony_ci		if (priv->flags & FSL_GLOBAL_TIMER)
5308c2ecf20Sopenharmony_ci			setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic const struct of_device_id mpic_timer_ids[] = {
5358c2ecf20Sopenharmony_ci	{ .compatible = "fsl,mpic-global-timer", },
5368c2ecf20Sopenharmony_ci	{},
5378c2ecf20Sopenharmony_ci};
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic struct syscore_ops mpic_timer_syscore_ops = {
5408c2ecf20Sopenharmony_ci	.resume = mpic_timer_resume,
5418c2ecf20Sopenharmony_ci};
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int __init mpic_timer_init(void)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct device_node *np = NULL;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	for_each_matching_node(np, mpic_timer_ids)
5488c2ecf20Sopenharmony_ci		timer_group_init(np);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	register_syscore_ops(&mpic_timer_syscore_ops);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (list_empty(&timer_group_list))
5538c2ecf20Sopenharmony_ci		return -ENODEV;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	return 0;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_cisubsys_initcall(mpic_timer_init);
558