18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2011
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
68c2ecf20Sopenharmony_ci * Author: Sundar Iyer for ST-Ericsson
78c2ecf20Sopenharmony_ci * sched_clock implementation is based on:
88c2ecf20Sopenharmony_ci * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * DBx500-PRCMU Timer
118c2ecf20Sopenharmony_ci * The PRCMU has 5 timers which are available in a always-on
128c2ecf20Sopenharmony_ci * power domain.  We use the Timer 4 for our always-on clock
138c2ecf20Sopenharmony_ci * source on DB8500.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci#include <linux/of.h>
168c2ecf20Sopenharmony_ci#include <linux/of_address.h>
178c2ecf20Sopenharmony_ci#include <linux/clockchips.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define RATE_32K		32768
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define TIMER_MODE_CONTINOUS	0x1
228c2ecf20Sopenharmony_ci#define TIMER_DOWNCOUNT_VAL	0xffffffff
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define PRCMU_TIMER_REF		0
258c2ecf20Sopenharmony_ci#define PRCMU_TIMER_DOWNCOUNT	0x4
268c2ecf20Sopenharmony_ci#define PRCMU_TIMER_MODE	0x8
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void __iomem *clksrc_dbx500_timer_base;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic u64 notrace clksrc_dbx500_prcmu_read(struct clocksource *cs)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	void __iomem *base = clksrc_dbx500_timer_base;
338c2ecf20Sopenharmony_ci	u32 count, count2;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	do {
368c2ecf20Sopenharmony_ci		count = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
378c2ecf20Sopenharmony_ci		count2 = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
388c2ecf20Sopenharmony_ci	} while (count2 != count);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* Negate because the timer is a decrementing counter */
418c2ecf20Sopenharmony_ci	return ~count;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic struct clocksource clocksource_dbx500_prcmu = {
458c2ecf20Sopenharmony_ci	.name		= "dbx500-prcmu-timer",
468c2ecf20Sopenharmony_ci	.rating		= 100,
478c2ecf20Sopenharmony_ci	.read		= clksrc_dbx500_prcmu_read,
488c2ecf20Sopenharmony_ci	.mask		= CLOCKSOURCE_MASK(32),
498c2ecf20Sopenharmony_ci	.flags		= CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic int __init clksrc_dbx500_prcmu_init(struct device_node *node)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	clksrc_dbx500_timer_base = of_iomap(node, 0);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * The A9 sub system expects the timer to be configured as
588c2ecf20Sopenharmony_ci	 * a continous looping timer.
598c2ecf20Sopenharmony_ci	 * The PRCMU should configure it but if it for some reason
608c2ecf20Sopenharmony_ci	 * don't we do it here.
618c2ecf20Sopenharmony_ci	 */
628c2ecf20Sopenharmony_ci	if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) !=
638c2ecf20Sopenharmony_ci	    TIMER_MODE_CONTINOUS) {
648c2ecf20Sopenharmony_ci		writel(TIMER_MODE_CONTINOUS,
658c2ecf20Sopenharmony_ci		       clksrc_dbx500_timer_base + PRCMU_TIMER_MODE);
668c2ecf20Sopenharmony_ci		writel(TIMER_DOWNCOUNT_VAL,
678c2ecf20Sopenharmony_ci		       clksrc_dbx500_timer_base + PRCMU_TIMER_REF);
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci	return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4",
728c2ecf20Sopenharmony_ci		       clksrc_dbx500_prcmu_init);
73