1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) ST-Ericsson SA 2011
4  *
5  * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson
6  * Author: Sundar Iyer for ST-Ericsson
7  * sched_clock implementation is based on:
8  * plat-nomadik/timer.c Linus Walleij <linus.walleij@stericsson.com>
9  *
10  * DBx500-PRCMU Timer
11  * The PRCMU has 5 timers which are available in a always-on
12  * power domain.  We use the Timer 4 for our always-on clock
13  * source on DB8500.
14  */
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/clockchips.h>
18 
19 #define RATE_32K		32768
20 
21 #define TIMER_MODE_CONTINOUS	0x1
22 #define TIMER_DOWNCOUNT_VAL	0xffffffff
23 
24 #define PRCMU_TIMER_REF		0
25 #define PRCMU_TIMER_DOWNCOUNT	0x4
26 #define PRCMU_TIMER_MODE	0x8
27 
28 static void __iomem *clksrc_dbx500_timer_base;
29 
30 static u64 notrace clksrc_dbx500_prcmu_read(struct clocksource *cs)
31 {
32 	void __iomem *base = clksrc_dbx500_timer_base;
33 	u32 count, count2;
34 
35 	do {
36 		count = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
37 		count2 = readl_relaxed(base + PRCMU_TIMER_DOWNCOUNT);
38 	} while (count2 != count);
39 
40 	/* Negate because the timer is a decrementing counter */
41 	return ~count;
42 }
43 
44 static struct clocksource clocksource_dbx500_prcmu = {
45 	.name		= "dbx500-prcmu-timer",
46 	.rating		= 100,
47 	.read		= clksrc_dbx500_prcmu_read,
48 	.mask		= CLOCKSOURCE_MASK(32),
49 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_SUSPEND_NONSTOP,
50 };
51 
52 static int __init clksrc_dbx500_prcmu_init(struct device_node *node)
53 {
54 	clksrc_dbx500_timer_base = of_iomap(node, 0);
55 
56 	/*
57 	 * The A9 sub system expects the timer to be configured as
58 	 * a continous looping timer.
59 	 * The PRCMU should configure it but if it for some reason
60 	 * don't we do it here.
61 	 */
62 	if (readl(clksrc_dbx500_timer_base + PRCMU_TIMER_MODE) !=
63 	    TIMER_MODE_CONTINOUS) {
64 		writel(TIMER_MODE_CONTINOUS,
65 		       clksrc_dbx500_timer_base + PRCMU_TIMER_MODE);
66 		writel(TIMER_DOWNCOUNT_VAL,
67 		       clksrc_dbx500_timer_base + PRCMU_TIMER_REF);
68 	}
69 	return clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
70 }
71 TIMER_OF_DECLARE(dbx500_prcmu, "stericsson,db8500-prcmu-timer-4",
72 		       clksrc_dbx500_prcmu_init);
73