0001
0002
0003
0004
0005 #include <linux/interrupt.h>
0006 #include <linux/clockchips.h>
0007
0008 #include "timer-of.h"
0009
0010 #define CMP_OFFSET 0x10000
0011
0012 #define CNTCV_LO 0x8
0013 #define CNTCV_HI 0xc
0014 #define CMPCV_LO (CMP_OFFSET + 0x20)
0015 #define CMPCV_HI (CMP_OFFSET + 0x24)
0016 #define CMPCR (CMP_OFFSET + 0x2c)
0017
0018 #define SYS_CTR_EN 0x1
0019 #define SYS_CTR_IRQ_MASK 0x2
0020
0021 #define SYS_CTR_CLK_DIV 0x3
0022
0023 static void __iomem *sys_ctr_base __ro_after_init;
0024 static u32 cmpcr __ro_after_init;
0025
0026 static void sysctr_timer_enable(bool enable)
0027 {
0028 writel(enable ? cmpcr | SYS_CTR_EN : cmpcr, sys_ctr_base + CMPCR);
0029 }
0030
0031 static void sysctr_irq_acknowledge(void)
0032 {
0033
0034
0035
0036
0037
0038 sysctr_timer_enable(false);
0039 }
0040
0041 static inline u64 sysctr_read_counter(void)
0042 {
0043 u32 cnt_hi, tmp_hi, cnt_lo;
0044
0045 do {
0046 cnt_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
0047 cnt_lo = readl_relaxed(sys_ctr_base + CNTCV_LO);
0048 tmp_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
0049 } while (tmp_hi != cnt_hi);
0050
0051 return ((u64) cnt_hi << 32) | cnt_lo;
0052 }
0053
0054 static int sysctr_set_next_event(unsigned long delta,
0055 struct clock_event_device *evt)
0056 {
0057 u32 cmp_hi, cmp_lo;
0058 u64 next;
0059
0060 sysctr_timer_enable(false);
0061
0062 next = sysctr_read_counter();
0063
0064 next += delta;
0065
0066 cmp_hi = (next >> 32) & 0x00fffff;
0067 cmp_lo = next & 0xffffffff;
0068
0069 writel_relaxed(cmp_hi, sys_ctr_base + CMPCV_HI);
0070 writel_relaxed(cmp_lo, sys_ctr_base + CMPCV_LO);
0071
0072 sysctr_timer_enable(true);
0073
0074 return 0;
0075 }
0076
0077 static int sysctr_set_state_oneshot(struct clock_event_device *evt)
0078 {
0079 return 0;
0080 }
0081
0082 static int sysctr_set_state_shutdown(struct clock_event_device *evt)
0083 {
0084 sysctr_timer_enable(false);
0085
0086 return 0;
0087 }
0088
0089 static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
0090 {
0091 struct clock_event_device *evt = dev_id;
0092
0093 sysctr_irq_acknowledge();
0094
0095 evt->event_handler(evt);
0096
0097 return IRQ_HANDLED;
0098 }
0099
0100 static struct timer_of to_sysctr = {
0101 .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
0102 .clkevt = {
0103 .name = "i.MX system counter timer",
0104 .features = CLOCK_EVT_FEAT_ONESHOT |
0105 CLOCK_EVT_FEAT_DYNIRQ,
0106 .set_state_oneshot = sysctr_set_state_oneshot,
0107 .set_next_event = sysctr_set_next_event,
0108 .set_state_shutdown = sysctr_set_state_shutdown,
0109 .rating = 200,
0110 },
0111 .of_irq = {
0112 .handler = sysctr_timer_interrupt,
0113 .flags = IRQF_TIMER,
0114 },
0115 .of_clk = {
0116 .name = "per",
0117 },
0118 };
0119
0120 static void __init sysctr_clockevent_init(void)
0121 {
0122 to_sysctr.clkevt.cpumask = cpu_possible_mask;
0123
0124 clockevents_config_and_register(&to_sysctr.clkevt,
0125 timer_of_rate(&to_sysctr),
0126 0xff, 0x7fffffff);
0127 }
0128
0129 static int __init sysctr_timer_init(struct device_node *np)
0130 {
0131 int ret = 0;
0132
0133 ret = timer_of_init(np, &to_sysctr);
0134 if (ret)
0135 return ret;
0136
0137
0138 to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV;
0139
0140 sys_ctr_base = timer_of_base(&to_sysctr);
0141 cmpcr = readl(sys_ctr_base + CMPCR);
0142 cmpcr &= ~SYS_CTR_EN;
0143
0144 sysctr_clockevent_init();
0145
0146 return 0;
0147 }
0148 TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init);