1 // SPDX-License-Identifier: GPL-2.0+
3 // Copyright 2017-2019 NXP
5 #include <linux/interrupt.h>
6 #include <linux/clockchips.h>
10 #define CMP_OFFSET 0x10000
14 #define CMPCV_LO (CMP_OFFSET + 0x20)
15 #define CMPCV_HI (CMP_OFFSET + 0x24)
16 #define CMPCR (CMP_OFFSET + 0x2c)
18 #define SYS_CTR_EN 0x1
19 #define SYS_CTR_IRQ_MASK 0x2
21 #define SYS_CTR_CLK_DIV 0x3
23 static void __iomem
*sys_ctr_base
;
26 static void sysctr_timer_enable(bool enable
)
28 writel(enable
? cmpcr
| SYS_CTR_EN
: cmpcr
, sys_ctr_base
+ CMPCR
);
31 static void sysctr_irq_acknowledge(void)
34 * clear the enable bit(EN =0) will clear
35 * the status bit(ISTAT = 0), then the interrupt
36 * signal will be negated(acknowledged).
38 sysctr_timer_enable(false);
41 static inline u64
sysctr_read_counter(void)
43 u32 cnt_hi
, tmp_hi
, cnt_lo
;
46 cnt_hi
= readl_relaxed(sys_ctr_base
+ CNTCV_HI
);
47 cnt_lo
= readl_relaxed(sys_ctr_base
+ CNTCV_LO
);
48 tmp_hi
= readl_relaxed(sys_ctr_base
+ CNTCV_HI
);
49 } while (tmp_hi
!= cnt_hi
);
51 return ((u64
) cnt_hi
<< 32) | cnt_lo
;
54 static int sysctr_set_next_event(unsigned long delta
,
55 struct clock_event_device
*evt
)
60 sysctr_timer_enable(false);
62 next
= sysctr_read_counter();
66 cmp_hi
= (next
>> 32) & 0x00fffff;
67 cmp_lo
= next
& 0xffffffff;
69 writel_relaxed(cmp_hi
, sys_ctr_base
+ CMPCV_HI
);
70 writel_relaxed(cmp_lo
, sys_ctr_base
+ CMPCV_LO
);
72 sysctr_timer_enable(true);
77 static int sysctr_set_state_oneshot(struct clock_event_device
*evt
)
82 static int sysctr_set_state_shutdown(struct clock_event_device
*evt
)
84 sysctr_timer_enable(false);
89 static irqreturn_t
sysctr_timer_interrupt(int irq
, void *dev_id
)
91 struct clock_event_device
*evt
= dev_id
;
93 sysctr_irq_acknowledge();
95 evt
->event_handler(evt
);
100 static struct timer_of to_sysctr
= {
101 .flags
= TIMER_OF_IRQ
| TIMER_OF_CLOCK
| TIMER_OF_BASE
,
103 .name
= "i.MX system counter timer",
104 .features
= CLOCK_EVT_FEAT_ONESHOT
|
105 CLOCK_EVT_FEAT_DYNIRQ
,
106 .set_state_oneshot
= sysctr_set_state_oneshot
,
107 .set_next_event
= sysctr_set_next_event
,
108 .set_state_shutdown
= sysctr_set_state_shutdown
,
112 .handler
= sysctr_timer_interrupt
,
113 .flags
= IRQF_TIMER
| IRQF_IRQPOLL
,
120 static void __init
sysctr_clockevent_init(void)
122 to_sysctr
.clkevt
.cpumask
= cpumask_of(0);
124 clockevents_config_and_register(&to_sysctr
.clkevt
,
125 timer_of_rate(&to_sysctr
),
129 static int __init
sysctr_timer_init(struct device_node
*np
)
133 ret
= timer_of_init(np
, &to_sysctr
);
137 /* system counter clock is divided by 3 internally */
138 to_sysctr
.of_clk
.rate
/= SYS_CTR_CLK_DIV
;
140 sys_ctr_base
= timer_of_base(&to_sysctr
);
141 cmpcr
= readl(sys_ctr_base
+ CMPCR
);
142 cmpcr
&= ~SYS_CTR_EN
;
144 sysctr_clockevent_init();
148 TIMER_OF_DECLARE(sysctr_timer
, "nxp,sysctr-timer", sysctr_timer_init
);