1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Copyright 2017-2019 NXP 4 5 #include <linux/interrupt.h> 6 #include <linux/clockchips.h> 7 #include <linux/slab.h> 8 9 #include "timer-of.h" 10 11 #define CMP_OFFSET 0x10000 12 #define RD_OFFSET 0x20000 13 14 #define CNTCV_LO 0x8 15 #define CNTCV_HI 0xc 16 #define CMPCV_LO (CMP_OFFSET + 0x20) 17 #define CMPCV_HI (CMP_OFFSET + 0x24) 18 #define CMPCR (CMP_OFFSET + 0x2c) 19 #define CNTCV_LO_IMX95 (RD_OFFSET + 0x8) 20 #define CNTCV_HI_IMX95 (RD_OFFSET + 0xc) 21 22 #define SYS_CTR_EN 0x1 23 #define SYS_CTR_IRQ_MASK 0x2 24 25 #define SYS_CTR_CLK_DIV 0x3 26 27 struct sysctr_private { 28 u32 cmpcr; 29 u32 lo_off; 30 u32 hi_off; 31 }; 32 33 static void sysctr_timer_enable(struct clock_event_device *evt, bool enable) 34 { 35 struct timer_of *to = to_timer_of(evt); 36 struct sysctr_private *priv = to->private_data; 37 void __iomem *base = timer_of_base(to); 38 39 writel(enable ? priv->cmpcr | SYS_CTR_EN : priv->cmpcr, base + CMPCR); 40 } 41 42 static void sysctr_irq_acknowledge(struct clock_event_device *evt) 43 { 44 /* 45 * clear the enable bit(EN =0) will clear 46 * the status bit(ISTAT = 0), then the interrupt 47 * signal will be negated(acknowledged). 48 */ 49 sysctr_timer_enable(evt, false); 50 } 51 52 static inline u64 sysctr_read_counter(struct clock_event_device *evt) 53 { 54 struct timer_of *to = to_timer_of(evt); 55 struct sysctr_private *priv = to->private_data; 56 void __iomem *base = timer_of_base(to); 57 u32 cnt_hi, tmp_hi, cnt_lo; 58 59 do { 60 cnt_hi = readl_relaxed(base + priv->hi_off); 61 cnt_lo = readl_relaxed(base + priv->lo_off); 62 tmp_hi = readl_relaxed(base + priv->hi_off); 63 } while (tmp_hi != cnt_hi); 64 65 return ((u64) cnt_hi << 32) | cnt_lo; 66 } 67 68 static int sysctr_set_next_event(unsigned long delta, 69 struct clock_event_device *evt) 70 { 71 struct timer_of *to = to_timer_of(evt); 72 void __iomem *base = timer_of_base(to); 73 u32 cmp_hi, cmp_lo; 74 u64 next; 75 76 sysctr_timer_enable(evt, false); 77 78 next = sysctr_read_counter(evt); 79 80 next += delta; 81 82 cmp_hi = (next >> 32) & 0x00fffff; 83 cmp_lo = next & 0xffffffff; 84 85 writel_relaxed(cmp_hi, base + CMPCV_HI); 86 writel_relaxed(cmp_lo, base + CMPCV_LO); 87 88 sysctr_timer_enable(evt, true); 89 90 return 0; 91 } 92 93 static int sysctr_set_state_oneshot(struct clock_event_device *evt) 94 { 95 return 0; 96 } 97 98 static int sysctr_set_state_shutdown(struct clock_event_device *evt) 99 { 100 sysctr_timer_enable(evt, false); 101 102 return 0; 103 } 104 105 static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id) 106 { 107 struct clock_event_device *evt = dev_id; 108 109 sysctr_irq_acknowledge(evt); 110 111 evt->event_handler(evt); 112 113 return IRQ_HANDLED; 114 } 115 116 static struct timer_of to_sysctr = { 117 .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE, 118 .clkevt = { 119 .name = "i.MX system counter timer", 120 .features = CLOCK_EVT_FEAT_ONESHOT | 121 CLOCK_EVT_FEAT_DYNIRQ, 122 .set_state_oneshot = sysctr_set_state_oneshot, 123 .set_next_event = sysctr_set_next_event, 124 .set_state_shutdown = sysctr_set_state_shutdown, 125 .rating = 200, 126 }, 127 .of_irq = { 128 .handler = sysctr_timer_interrupt, 129 .flags = IRQF_TIMER, 130 }, 131 .of_clk = { 132 .name = "per", 133 }, 134 }; 135 136 static int __init __sysctr_timer_init(struct device_node *np) 137 { 138 struct sysctr_private *priv; 139 void __iomem *base; 140 int ret; 141 142 priv = kzalloc(sizeof(struct sysctr_private), GFP_KERNEL); 143 if (!priv) 144 return -ENOMEM; 145 146 ret = timer_of_init(np, &to_sysctr); 147 if (ret) { 148 kfree(priv); 149 return ret; 150 } 151 152 if (!of_property_read_bool(np, "nxp,no-divider")) { 153 /* system counter clock is divided by 3 internally */ 154 to_sysctr.of_clk.rate /= SYS_CTR_CLK_DIV; 155 } 156 157 to_sysctr.clkevt.cpumask = cpu_possible_mask; 158 to_sysctr.private_data = priv; 159 160 base = timer_of_base(&to_sysctr); 161 priv->cmpcr = readl(base + CMPCR) & ~SYS_CTR_EN; 162 163 return 0; 164 } 165 166 static int __init sysctr_timer_init(struct device_node *np) 167 { 168 struct sysctr_private *priv; 169 int ret; 170 171 ret = __sysctr_timer_init(np); 172 if (ret) 173 return ret; 174 175 priv = to_sysctr.private_data; 176 priv->lo_off = CNTCV_LO; 177 priv->hi_off = CNTCV_HI; 178 179 clockevents_config_and_register(&to_sysctr.clkevt, 180 timer_of_rate(&to_sysctr), 181 0xff, 0x7fffffff); 182 183 return 0; 184 } 185 186 static int __init sysctr_timer_imx95_init(struct device_node *np) 187 { 188 struct sysctr_private *priv; 189 int ret; 190 191 ret = __sysctr_timer_init(np); 192 if (ret) 193 return ret; 194 195 priv = to_sysctr.private_data; 196 priv->lo_off = CNTCV_LO_IMX95; 197 priv->hi_off = CNTCV_HI_IMX95; 198 199 clockevents_config_and_register(&to_sysctr.clkevt, 200 timer_of_rate(&to_sysctr), 201 0xff, 0x7fffffff); 202 203 return 0; 204 } 205 206 TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init); 207 TIMER_OF_DECLARE(sysctr_timer_imx95, "nxp,imx95-sysctr-timer", sysctr_timer_imx95_init); 208