]>
Commit | Line | Data |
---|---|---|
74ba9207 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
c78275f3 | 2 | /* |
ceefc71d | 3 | * PTP 1588 clock for Freescale QorIQ 1588 timer |
c78275f3 RC |
4 | * |
5 | * Copyright (C) 2010 OMICRON electronics GmbH | |
c78275f3 | 6 | */ |
375d6a1b JP |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
9 | ||
c78275f3 RC |
10 | #include <linux/device.h> |
11 | #include <linux/hrtimer.h> | |
c78275f3 RC |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | |
14 | #include <linux/of.h> | |
9ffc4de5 | 15 | #include <linux/platform_device.h> |
c78275f3 | 16 | #include <linux/timex.h> |
ceefc71d | 17 | #include <linux/slab.h> |
91305f28 | 18 | #include <linux/clk.h> |
c78275f3 | 19 | |
6c50c1ed | 20 | #include <linux/fsl/ptp_qoriq.h> |
ceefc71d | 21 | |
c78275f3 RC |
22 | /* |
23 | * Register access functions | |
24 | */ | |
25 | ||
1e562c81 YL |
26 | /* Caller must hold ptp_qoriq->lock. */ |
27 | static u64 tmr_cnt_read(struct ptp_qoriq *ptp_qoriq) | |
c78275f3 | 28 | { |
1e562c81 | 29 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
c78275f3 RC |
30 | u64 ns; |
31 | u32 lo, hi; | |
32 | ||
f038ddf2 YL |
33 | lo = ptp_qoriq->read(®s->ctrl_regs->tmr_cnt_l); |
34 | hi = ptp_qoriq->read(®s->ctrl_regs->tmr_cnt_h); | |
c78275f3 RC |
35 | ns = ((u64) hi) << 32; |
36 | ns |= lo; | |
37 | return ns; | |
38 | } | |
39 | ||
1e562c81 YL |
40 | /* Caller must hold ptp_qoriq->lock. */ |
41 | static void tmr_cnt_write(struct ptp_qoriq *ptp_qoriq, u64 ns) | |
c78275f3 | 42 | { |
1e562c81 | 43 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
c78275f3 RC |
44 | u32 hi = ns >> 32; |
45 | u32 lo = ns & 0xffffffff; | |
46 | ||
f038ddf2 YL |
47 | ptp_qoriq->write(®s->ctrl_regs->tmr_cnt_l, lo); |
48 | ptp_qoriq->write(®s->ctrl_regs->tmr_cnt_h, hi); | |
c78275f3 RC |
49 | } |
50 | ||
24a7fffb NG |
51 | static u64 tmr_offset_read(struct ptp_qoriq *ptp_qoriq) |
52 | { | |
53 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
54 | u32 lo, hi; | |
55 | u64 ns; | |
56 | ||
57 | lo = ptp_qoriq->read(®s->ctrl_regs->tmroff_l); | |
58 | hi = ptp_qoriq->read(®s->ctrl_regs->tmroff_h); | |
59 | ns = ((u64) hi) << 32; | |
60 | ns |= lo; | |
61 | return ns; | |
62 | } | |
63 | ||
64 | static void tmr_offset_write(struct ptp_qoriq *ptp_qoriq, u64 delta_ns) | |
65 | { | |
66 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
67 | u32 lo = delta_ns & 0xffffffff; | |
68 | u32 hi = delta_ns >> 32; | |
69 | ||
70 | ptp_qoriq->write(®s->ctrl_regs->tmroff_l, lo); | |
71 | ptp_qoriq->write(®s->ctrl_regs->tmroff_h, hi); | |
72 | } | |
73 | ||
1e562c81 YL |
74 | /* Caller must hold ptp_qoriq->lock. */ |
75 | static void set_alarm(struct ptp_qoriq *ptp_qoriq) | |
c78275f3 | 76 | { |
1e562c81 | 77 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
c78275f3 RC |
78 | u64 ns; |
79 | u32 lo, hi; | |
80 | ||
24a7fffb NG |
81 | ns = tmr_cnt_read(ptp_qoriq) + tmr_offset_read(ptp_qoriq) |
82 | + 1500000000ULL; | |
83 | ||
c78275f3 | 84 | ns = div_u64(ns, 1000000000UL) * 1000000000ULL; |
1e562c81 | 85 | ns -= ptp_qoriq->tclk_period; |
c78275f3 RC |
86 | hi = ns >> 32; |
87 | lo = ns & 0xffffffff; | |
f038ddf2 YL |
88 | ptp_qoriq->write(®s->alarm_regs->tmr_alarm1_l, lo); |
89 | ptp_qoriq->write(®s->alarm_regs->tmr_alarm1_h, hi); | |
c78275f3 RC |
90 | } |
91 | ||
1e562c81 YL |
92 | /* Caller must hold ptp_qoriq->lock. */ |
93 | static void set_fipers(struct ptp_qoriq *ptp_qoriq) | |
c78275f3 | 94 | { |
1e562c81 | 95 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
a8f62d0c | 96 | |
1e562c81 | 97 | set_alarm(ptp_qoriq); |
f038ddf2 YL |
98 | ptp_qoriq->write(®s->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1); |
99 | ptp_qoriq->write(®s->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2); | |
6d23d831 YL |
100 | |
101 | if (ptp_qoriq->fiper3_support) | |
102 | ptp_qoriq->write(®s->fiper_regs->tmr_fiper3, | |
103 | ptp_qoriq->tmr_fiper3); | |
c78275f3 RC |
104 | } |
105 | ||
9429439f | 106 | int extts_clean_up(struct ptp_qoriq *ptp_qoriq, int index, bool update_event) |
6815d8b0 | 107 | { |
1e562c81 | 108 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; |
6815d8b0 YL |
109 | struct ptp_clock_event event; |
110 | void __iomem *reg_etts_l; | |
111 | void __iomem *reg_etts_h; | |
10bc877c | 112 | u32 valid, lo, hi; |
6815d8b0 YL |
113 | |
114 | switch (index) { | |
115 | case 0: | |
116 | valid = ETS1_VLD; | |
117 | reg_etts_l = ®s->etts_regs->tmr_etts1_l; | |
118 | reg_etts_h = ®s->etts_regs->tmr_etts1_h; | |
119 | break; | |
120 | case 1: | |
121 | valid = ETS2_VLD; | |
122 | reg_etts_l = ®s->etts_regs->tmr_etts2_l; | |
123 | reg_etts_h = ®s->etts_regs->tmr_etts2_h; | |
124 | break; | |
125 | default: | |
126 | return -EINVAL; | |
127 | } | |
128 | ||
129 | event.type = PTP_CLOCK_EXTTS; | |
130 | event.index = index; | |
131 | ||
10bc877c YL |
132 | if (ptp_qoriq->extts_fifo_support) |
133 | if (!(ptp_qoriq->read(®s->ctrl_regs->tmr_stat) & valid)) | |
134 | return 0; | |
135 | ||
6815d8b0 | 136 | do { |
f038ddf2 YL |
137 | lo = ptp_qoriq->read(reg_etts_l); |
138 | hi = ptp_qoriq->read(reg_etts_h); | |
6815d8b0 YL |
139 | |
140 | if (update_event) { | |
141 | event.timestamp = ((u64) hi) << 32; | |
142 | event.timestamp |= lo; | |
1e562c81 | 143 | ptp_clock_event(ptp_qoriq->clock, &event); |
6815d8b0 YL |
144 | } |
145 | ||
10bc877c YL |
146 | if (!ptp_qoriq->extts_fifo_support) |
147 | break; | |
148 | } while (ptp_qoriq->read(®s->ctrl_regs->tmr_stat) & valid); | |
6815d8b0 YL |
149 | |
150 | return 0; | |
151 | } | |
9429439f | 152 | EXPORT_SYMBOL_GPL(extts_clean_up); |
6815d8b0 | 153 | |
c78275f3 RC |
154 | /* |
155 | * Interrupt service routine | |
156 | */ | |
157 | ||
73356e4e | 158 | irqreturn_t ptp_qoriq_isr(int irq, void *priv) |
c78275f3 | 159 | { |
1e562c81 YL |
160 | struct ptp_qoriq *ptp_qoriq = priv; |
161 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
c78275f3 | 162 | struct ptp_clock_event event; |
d71151a3 | 163 | u32 ack = 0, mask, val, irqs; |
b0bc10cc | 164 | |
1e562c81 | 165 | spin_lock(&ptp_qoriq->lock); |
c78275f3 | 166 | |
f038ddf2 YL |
167 | val = ptp_qoriq->read(®s->ctrl_regs->tmr_tevent); |
168 | mask = ptp_qoriq->read(®s->ctrl_regs->tmr_temask); | |
b0bc10cc | 169 | |
1e562c81 | 170 | spin_unlock(&ptp_qoriq->lock); |
b0bc10cc YL |
171 | |
172 | irqs = val & mask; | |
c78275f3 | 173 | |
b0bc10cc | 174 | if (irqs & ETS1) { |
c78275f3 | 175 | ack |= ETS1; |
1e562c81 | 176 | extts_clean_up(ptp_qoriq, 0, true); |
c78275f3 RC |
177 | } |
178 | ||
b0bc10cc | 179 | if (irqs & ETS2) { |
c78275f3 | 180 | ack |= ETS2; |
1e562c81 | 181 | extts_clean_up(ptp_qoriq, 1, true); |
c78275f3 RC |
182 | } |
183 | ||
b0bc10cc | 184 | if (irqs & PP1) { |
c78275f3 RC |
185 | ack |= PP1; |
186 | event.type = PTP_CLOCK_PPS; | |
1e562c81 | 187 | ptp_clock_event(ptp_qoriq->clock, &event); |
c78275f3 RC |
188 | } |
189 | ||
190 | if (ack) { | |
f038ddf2 | 191 | ptp_qoriq->write(®s->ctrl_regs->tmr_tevent, ack); |
c78275f3 RC |
192 | return IRQ_HANDLED; |
193 | } else | |
194 | return IRQ_NONE; | |
195 | } | |
73356e4e | 196 | EXPORT_SYMBOL_GPL(ptp_qoriq_isr); |
c78275f3 RC |
197 | |
198 | /* | |
199 | * PTP clock operations | |
200 | */ | |
201 | ||
73356e4e | 202 | int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) |
c78275f3 | 203 | { |
42895116 UDB |
204 | u64 adj, diff; |
205 | u32 tmr_add; | |
c78275f3 | 206 | int neg_adj = 0; |
1e562c81 YL |
207 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
208 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
c78275f3 | 209 | |
42895116 | 210 | if (scaled_ppm < 0) { |
c78275f3 | 211 | neg_adj = 1; |
42895116 | 212 | scaled_ppm = -scaled_ppm; |
c78275f3 | 213 | } |
1e562c81 | 214 | tmr_add = ptp_qoriq->tmr_add; |
c78275f3 | 215 | adj = tmr_add; |
42895116 | 216 | |
f51d7bf1 YL |
217 | /* |
218 | * Calculate diff and round() to the nearest integer | |
219 | * | |
220 | * diff = adj * (ppb / 1000000000) | |
221 | * = adj * scaled_ppm / 65536000000 | |
42895116 | 222 | */ |
f51d7bf1 YL |
223 | diff = mul_u64_u64_div_u64(adj, scaled_ppm, 32768000000); |
224 | diff = DIV64_U64_ROUND_UP(diff, 2); | |
c78275f3 RC |
225 | |
226 | tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff; | |
f038ddf2 | 227 | ptp_qoriq->write(®s->ctrl_regs->tmr_add, tmr_add); |
c78275f3 RC |
228 | |
229 | return 0; | |
230 | } | |
73356e4e | 231 | EXPORT_SYMBOL_GPL(ptp_qoriq_adjfine); |
c78275f3 | 232 | |
73356e4e | 233 | int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta) |
c78275f3 | 234 | { |
1e562c81 | 235 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
24a7fffb NG |
236 | s64 now, curr_delta; |
237 | unsigned long flags; | |
c78275f3 | 238 | |
1e562c81 | 239 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 240 | |
24a7fffb NG |
241 | /* On LS1021A, eTSEC2 and eTSEC3 do not take into account the TMR_OFF |
242 | * adjustment | |
243 | */ | |
244 | if (ptp_qoriq->etsec) { | |
245 | now = tmr_cnt_read(ptp_qoriq); | |
246 | now += delta; | |
247 | tmr_cnt_write(ptp_qoriq, now); | |
248 | } else { | |
249 | curr_delta = tmr_offset_read(ptp_qoriq); | |
250 | curr_delta += delta; | |
251 | tmr_offset_write(ptp_qoriq, curr_delta); | |
252 | } | |
1e562c81 | 253 | set_fipers(ptp_qoriq); |
c78275f3 | 254 | |
1e562c81 | 255 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 | 256 | |
c78275f3 RC |
257 | return 0; |
258 | } | |
73356e4e | 259 | EXPORT_SYMBOL_GPL(ptp_qoriq_adjtime); |
c78275f3 | 260 | |
73356e4e | 261 | int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) |
c78275f3 RC |
262 | { |
263 | u64 ns; | |
c78275f3 | 264 | unsigned long flags; |
1e562c81 | 265 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
c78275f3 | 266 | |
1e562c81 | 267 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 268 | |
24a7fffb | 269 | ns = tmr_cnt_read(ptp_qoriq) + tmr_offset_read(ptp_qoriq); |
c78275f3 | 270 | |
1e562c81 | 271 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 | 272 | |
3359e7c2 RC |
273 | *ts = ns_to_timespec64(ns); |
274 | ||
c78275f3 RC |
275 | return 0; |
276 | } | |
73356e4e | 277 | EXPORT_SYMBOL_GPL(ptp_qoriq_gettime); |
c78275f3 | 278 | |
73356e4e YL |
279 | int ptp_qoriq_settime(struct ptp_clock_info *ptp, |
280 | const struct timespec64 *ts) | |
c78275f3 RC |
281 | { |
282 | u64 ns; | |
283 | unsigned long flags; | |
1e562c81 | 284 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
c78275f3 | 285 | |
3359e7c2 | 286 | ns = timespec64_to_ns(ts); |
c78275f3 | 287 | |
1e562c81 | 288 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 289 | |
24a7fffb | 290 | tmr_offset_write(ptp_qoriq, 0); |
1e562c81 YL |
291 | tmr_cnt_write(ptp_qoriq, ns); |
292 | set_fipers(ptp_qoriq); | |
c78275f3 | 293 | |
1e562c81 | 294 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 RC |
295 | |
296 | return 0; | |
297 | } | |
73356e4e | 298 | EXPORT_SYMBOL_GPL(ptp_qoriq_settime); |
c78275f3 | 299 | |
73356e4e YL |
300 | int ptp_qoriq_enable(struct ptp_clock_info *ptp, |
301 | struct ptp_clock_request *rq, int on) | |
c78275f3 | 302 | { |
1e562c81 YL |
303 | struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps); |
304 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
c78275f3 | 305 | unsigned long flags; |
b0bc10cc | 306 | u32 bit, mask = 0; |
c78275f3 RC |
307 | |
308 | switch (rq->type) { | |
309 | case PTP_CLK_REQ_EXTTS: | |
310 | switch (rq->extts.index) { | |
311 | case 0: | |
312 | bit = ETS1EN; | |
313 | break; | |
314 | case 1: | |
315 | bit = ETS2EN; | |
316 | break; | |
317 | default: | |
318 | return -EINVAL; | |
319 | } | |
6815d8b0 YL |
320 | |
321 | if (on) | |
1e562c81 | 322 | extts_clean_up(ptp_qoriq, rq->extts.index, false); |
6815d8b0 | 323 | |
b0bc10cc | 324 | break; |
c78275f3 | 325 | case PTP_CLK_REQ_PPS: |
b0bc10cc | 326 | bit = PP1EN; |
c78275f3 | 327 | break; |
b0bc10cc YL |
328 | default: |
329 | return -EOPNOTSUPP; | |
330 | } | |
331 | ||
1e562c81 | 332 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
b0bc10cc | 333 | |
f038ddf2 | 334 | mask = ptp_qoriq->read(®s->ctrl_regs->tmr_temask); |
b0bc10cc YL |
335 | if (on) { |
336 | mask |= bit; | |
f038ddf2 | 337 | ptp_qoriq->write(®s->ctrl_regs->tmr_tevent, bit); |
b0bc10cc YL |
338 | } else { |
339 | mask &= ~bit; | |
c78275f3 RC |
340 | } |
341 | ||
f038ddf2 | 342 | ptp_qoriq->write(®s->ctrl_regs->tmr_temask, mask); |
b0bc10cc | 343 | |
1e562c81 | 344 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
b0bc10cc | 345 | return 0; |
c78275f3 | 346 | } |
73356e4e | 347 | EXPORT_SYMBOL_GPL(ptp_qoriq_enable); |
c78275f3 | 348 | |
ceefc71d | 349 | static const struct ptp_clock_info ptp_qoriq_caps = { |
c78275f3 | 350 | .owner = THIS_MODULE, |
ceefc71d | 351 | .name = "qoriq ptp clock", |
c78275f3 | 352 | .max_adj = 512000, |
cd4baaaa | 353 | .n_alarm = 0, |
c78275f3 RC |
354 | .n_ext_ts = N_EXT_TS, |
355 | .n_per_out = 0, | |
4986b4f0 | 356 | .n_pins = 0, |
c78275f3 | 357 | .pps = 1, |
ceefc71d YL |
358 | .adjfine = ptp_qoriq_adjfine, |
359 | .adjtime = ptp_qoriq_adjtime, | |
360 | .gettime64 = ptp_qoriq_gettime, | |
361 | .settime64 = ptp_qoriq_settime, | |
362 | .enable = ptp_qoriq_enable, | |
c78275f3 RC |
363 | }; |
364 | ||
91305f28 | 365 | /** |
1e562c81 | 366 | * ptp_qoriq_nominal_freq - calculate nominal frequency according to |
91305f28 YL |
367 | * reference clock frequency |
368 | * | |
369 | * @clk_src: reference clock frequency | |
370 | * | |
371 | * The nominal frequency is the desired clock frequency. | |
372 | * It should be less than the reference clock frequency. | |
373 | * It should be a factor of 1000MHz. | |
374 | * | |
375 | * Return the nominal frequency | |
376 | */ | |
1e562c81 | 377 | static u32 ptp_qoriq_nominal_freq(u32 clk_src) |
91305f28 YL |
378 | { |
379 | u32 remainder = 0; | |
380 | ||
381 | clk_src /= 1000000; | |
382 | remainder = clk_src % 100; | |
383 | if (remainder) { | |
384 | clk_src -= remainder; | |
385 | clk_src += 100; | |
386 | } | |
387 | ||
388 | do { | |
389 | clk_src -= 100; | |
390 | ||
391 | } while (1000 % clk_src); | |
392 | ||
393 | return clk_src * 1000000; | |
394 | } | |
395 | ||
396 | /** | |
1e562c81 | 397 | * ptp_qoriq_auto_config - calculate a set of default configurations |
91305f28 | 398 | * |
1e562c81 | 399 | * @ptp_qoriq: pointer to ptp_qoriq |
91305f28 YL |
400 | * @node: pointer to device_node |
401 | * | |
402 | * If below dts properties are not provided, this function will be | |
403 | * called to calculate a set of default configurations for them. | |
404 | * "fsl,tclk-period" | |
405 | * "fsl,tmr-prsc" | |
406 | * "fsl,tmr-add" | |
407 | * "fsl,tmr-fiper1" | |
408 | * "fsl,tmr-fiper2" | |
6d23d831 | 409 | * "fsl,tmr-fiper3" (required only for DPAA2 and ENETC hardware) |
91305f28 YL |
410 | * "fsl,max-adj" |
411 | * | |
412 | * Return 0 if success | |
413 | */ | |
1e562c81 | 414 | static int ptp_qoriq_auto_config(struct ptp_qoriq *ptp_qoriq, |
91305f28 YL |
415 | struct device_node *node) |
416 | { | |
417 | struct clk *clk; | |
418 | u64 freq_comp; | |
419 | u64 max_adj; | |
420 | u32 nominal_freq; | |
74c05a33 | 421 | u32 remainder = 0; |
91305f28 YL |
422 | u32 clk_src = 0; |
423 | ||
1e562c81 | 424 | ptp_qoriq->cksel = DEFAULT_CKSEL; |
91305f28 YL |
425 | |
426 | clk = of_clk_get(node, 0); | |
427 | if (!IS_ERR(clk)) { | |
428 | clk_src = clk_get_rate(clk); | |
429 | clk_put(clk); | |
430 | } | |
431 | ||
432 | if (clk_src <= 100000000UL) { | |
433 | pr_err("error reference clock value, or lower than 100MHz\n"); | |
434 | return -EINVAL; | |
435 | } | |
436 | ||
1e562c81 | 437 | nominal_freq = ptp_qoriq_nominal_freq(clk_src); |
91305f28 YL |
438 | if (!nominal_freq) |
439 | return -EINVAL; | |
440 | ||
1e562c81 YL |
441 | ptp_qoriq->tclk_period = 1000000000UL / nominal_freq; |
442 | ptp_qoriq->tmr_prsc = DEFAULT_TMR_PRSC; | |
91305f28 YL |
443 | |
444 | /* Calculate initial frequency compensation value for TMR_ADD register. | |
445 | * freq_comp = ceil(2^32 / freq_ratio) | |
446 | * freq_ratio = reference_clock_freq / nominal_freq | |
447 | */ | |
448 | freq_comp = ((u64)1 << 32) * nominal_freq; | |
74c05a33 YL |
449 | freq_comp = div_u64_rem(freq_comp, clk_src, &remainder); |
450 | if (remainder) | |
91305f28 YL |
451 | freq_comp++; |
452 | ||
1e562c81 YL |
453 | ptp_qoriq->tmr_add = freq_comp; |
454 | ptp_qoriq->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - ptp_qoriq->tclk_period; | |
455 | ptp_qoriq->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - ptp_qoriq->tclk_period; | |
6d23d831 | 456 | ptp_qoriq->tmr_fiper3 = DEFAULT_FIPER3_PERIOD - ptp_qoriq->tclk_period; |
91305f28 YL |
457 | |
458 | /* max_adj = 1000000000 * (freq_ratio - 1.0) - 1 | |
459 | * freq_ratio = reference_clock_freq / nominal_freq | |
460 | */ | |
461 | max_adj = 1000000000ULL * (clk_src - nominal_freq); | |
74c05a33 | 462 | max_adj = div_u64(max_adj, nominal_freq) - 1; |
1e562c81 | 463 | ptp_qoriq->caps.max_adj = max_adj; |
91305f28 YL |
464 | |
465 | return 0; | |
466 | } | |
467 | ||
ff54571a | 468 | int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base, |
58066ac9 | 469 | const struct ptp_clock_info *caps) |
c78275f3 | 470 | { |
ff54571a | 471 | struct device_node *node = ptp_qoriq->dev->of_node; |
1e562c81 | 472 | struct ptp_qoriq_registers *regs; |
d28fdf0f | 473 | struct timespec64 now; |
c78275f3 | 474 | unsigned long flags; |
ff54571a | 475 | u32 tmr_ctrl; |
c78275f3 | 476 | |
7f4399ba CM |
477 | if (!node) |
478 | return -ENODEV; | |
479 | ||
ff54571a | 480 | ptp_qoriq->base = base; |
58066ac9 | 481 | ptp_qoriq->caps = *caps; |
e58f6f4f | 482 | |
1e562c81 YL |
483 | if (of_property_read_u32(node, "fsl,cksel", &ptp_qoriq->cksel)) |
484 | ptp_qoriq->cksel = DEFAULT_CKSEL; | |
c78275f3 | 485 | |
6815d8b0 | 486 | if (of_property_read_bool(node, "fsl,extts-fifo")) |
1e562c81 | 487 | ptp_qoriq->extts_fifo_support = true; |
6815d8b0 | 488 | else |
1e562c81 | 489 | ptp_qoriq->extts_fifo_support = false; |
6815d8b0 | 490 | |
6d23d831 YL |
491 | if (of_device_is_compatible(node, "fsl,dpaa2-ptp") || |
492 | of_device_is_compatible(node, "fsl,enetc-ptp")) | |
493 | ptp_qoriq->fiper3_support = true; | |
494 | ||
c35ec779 | 495 | if (of_property_read_u32(node, |
1e562c81 | 496 | "fsl,tclk-period", &ptp_qoriq->tclk_period) || |
c35ec779 | 497 | of_property_read_u32(node, |
1e562c81 | 498 | "fsl,tmr-prsc", &ptp_qoriq->tmr_prsc) || |
c35ec779 | 499 | of_property_read_u32(node, |
1e562c81 | 500 | "fsl,tmr-add", &ptp_qoriq->tmr_add) || |
c35ec779 | 501 | of_property_read_u32(node, |
1e562c81 | 502 | "fsl,tmr-fiper1", &ptp_qoriq->tmr_fiper1) || |
c35ec779 | 503 | of_property_read_u32(node, |
1e562c81 | 504 | "fsl,tmr-fiper2", &ptp_qoriq->tmr_fiper2) || |
c35ec779 | 505 | of_property_read_u32(node, |
6d23d831 YL |
506 | "fsl,max-adj", &ptp_qoriq->caps.max_adj) || |
507 | (ptp_qoriq->fiper3_support && | |
508 | of_property_read_u32(node, "fsl,tmr-fiper3", | |
509 | &ptp_qoriq->tmr_fiper3))) { | |
91305f28 YL |
510 | pr_warn("device tree node missing required elements, try automatic configuration\n"); |
511 | ||
1e562c81 | 512 | if (ptp_qoriq_auto_config(ptp_qoriq, node)) |
ff54571a | 513 | return -ENODEV; |
c78275f3 RC |
514 | } |
515 | ||
f038ddf2 YL |
516 | if (of_property_read_bool(node, "little-endian")) { |
517 | ptp_qoriq->read = qoriq_read_le; | |
518 | ptp_qoriq->write = qoriq_write_le; | |
519 | } else { | |
520 | ptp_qoriq->read = qoriq_read_be; | |
521 | ptp_qoriq->write = qoriq_write_be; | |
522 | } | |
523 | ||
d4e17687 YL |
524 | /* The eTSEC uses differnt memory map with DPAA/ENETC */ |
525 | if (of_device_is_compatible(node, "fsl,etsec-ptp")) { | |
24a7fffb | 526 | ptp_qoriq->etsec = true; |
d4e17687 YL |
527 | ptp_qoriq->regs.ctrl_regs = base + ETSEC_CTRL_REGS_OFFSET; |
528 | ptp_qoriq->regs.alarm_regs = base + ETSEC_ALARM_REGS_OFFSET; | |
529 | ptp_qoriq->regs.fiper_regs = base + ETSEC_FIPER_REGS_OFFSET; | |
530 | ptp_qoriq->regs.etts_regs = base + ETSEC_ETTS_REGS_OFFSET; | |
a8f62d0c | 531 | } else { |
1e562c81 YL |
532 | ptp_qoriq->regs.ctrl_regs = base + CTRL_REGS_OFFSET; |
533 | ptp_qoriq->regs.alarm_regs = base + ALARM_REGS_OFFSET; | |
534 | ptp_qoriq->regs.fiper_regs = base + FIPER_REGS_OFFSET; | |
535 | ptp_qoriq->regs.etts_regs = base + ETTS_REGS_OFFSET; | |
a8f62d0c YL |
536 | } |
537 | ||
db34a471 VO |
538 | spin_lock_init(&ptp_qoriq->lock); |
539 | ||
f696a21c | 540 | ktime_get_real_ts64(&now); |
1e562c81 | 541 | ptp_qoriq_settime(&ptp_qoriq->caps, &now); |
c78275f3 RC |
542 | |
543 | tmr_ctrl = | |
1e562c81 YL |
544 | (ptp_qoriq->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT | |
545 | (ptp_qoriq->cksel & CKSEL_MASK) << CKSEL_SHIFT; | |
c78275f3 | 546 | |
1e562c81 | 547 | spin_lock_irqsave(&ptp_qoriq->lock, flags); |
c78275f3 | 548 | |
1e562c81 | 549 | regs = &ptp_qoriq->regs; |
f038ddf2 YL |
550 | ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl, tmr_ctrl); |
551 | ptp_qoriq->write(®s->ctrl_regs->tmr_add, ptp_qoriq->tmr_add); | |
552 | ptp_qoriq->write(®s->ctrl_regs->tmr_prsc, ptp_qoriq->tmr_prsc); | |
553 | ptp_qoriq->write(®s->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1); | |
554 | ptp_qoriq->write(®s->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2); | |
6d23d831 YL |
555 | |
556 | if (ptp_qoriq->fiper3_support) | |
557 | ptp_qoriq->write(®s->fiper_regs->tmr_fiper3, | |
558 | ptp_qoriq->tmr_fiper3); | |
559 | ||
1e562c81 | 560 | set_alarm(ptp_qoriq); |
f038ddf2 YL |
561 | ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl, |
562 | tmr_ctrl|FIPERST|RTPE|TE|FRD); | |
c78275f3 | 563 | |
1e562c81 | 564 | spin_unlock_irqrestore(&ptp_qoriq->lock, flags); |
c78275f3 | 565 | |
ff54571a YL |
566 | ptp_qoriq->clock = ptp_clock_register(&ptp_qoriq->caps, ptp_qoriq->dev); |
567 | if (IS_ERR(ptp_qoriq->clock)) | |
568 | return PTR_ERR(ptp_qoriq->clock); | |
c78275f3 | 569 | |
ff54571a | 570 | ptp_qoriq->phc_index = ptp_clock_index(ptp_qoriq->clock); |
1e562c81 | 571 | ptp_qoriq_create_debugfs(ptp_qoriq); |
ff54571a YL |
572 | return 0; |
573 | } | |
574 | EXPORT_SYMBOL_GPL(ptp_qoriq_init); | |
575 | ||
576 | void ptp_qoriq_free(struct ptp_qoriq *ptp_qoriq) | |
577 | { | |
578 | struct ptp_qoriq_registers *regs = &ptp_qoriq->regs; | |
579 | ||
f038ddf2 YL |
580 | ptp_qoriq->write(®s->ctrl_regs->tmr_temask, 0); |
581 | ptp_qoriq->write(®s->ctrl_regs->tmr_ctrl, 0); | |
ff54571a YL |
582 | |
583 | ptp_qoriq_remove_debugfs(ptp_qoriq); | |
584 | ptp_clock_unregister(ptp_qoriq->clock); | |
585 | iounmap(ptp_qoriq->base); | |
586 | free_irq(ptp_qoriq->irq, ptp_qoriq); | |
587 | } | |
588 | EXPORT_SYMBOL_GPL(ptp_qoriq_free); | |
589 | ||
590 | static int ptp_qoriq_probe(struct platform_device *dev) | |
591 | { | |
592 | struct ptp_qoriq *ptp_qoriq; | |
593 | int err = -ENOMEM; | |
594 | void __iomem *base; | |
c78275f3 | 595 | |
ff54571a YL |
596 | ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL); |
597 | if (!ptp_qoriq) | |
598 | goto no_memory; | |
599 | ||
600 | ptp_qoriq->dev = &dev->dev; | |
601 | ||
602 | err = -ENODEV; | |
603 | ||
604 | ptp_qoriq->irq = platform_get_irq(dev, 0); | |
605 | if (ptp_qoriq->irq < 0) { | |
606 | pr_err("irq not in device tree\n"); | |
607 | goto no_node; | |
608 | } | |
609 | if (request_irq(ptp_qoriq->irq, ptp_qoriq_isr, IRQF_SHARED, | |
610 | DRIVER, ptp_qoriq)) { | |
611 | pr_err("request_irq failed\n"); | |
612 | goto no_node; | |
613 | } | |
614 | ||
615 | ptp_qoriq->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0); | |
616 | if (!ptp_qoriq->rsrc) { | |
617 | pr_err("no resource\n"); | |
618 | goto no_resource; | |
619 | } | |
620 | if (request_resource(&iomem_resource, ptp_qoriq->rsrc)) { | |
621 | pr_err("resource busy\n"); | |
622 | goto no_resource; | |
623 | } | |
624 | ||
625 | base = ioremap(ptp_qoriq->rsrc->start, | |
626 | resource_size(ptp_qoriq->rsrc)); | |
627 | if (!base) { | |
628 | pr_err("ioremap ptp registers failed\n"); | |
629 | goto no_ioremap; | |
630 | } | |
631 | ||
58066ac9 | 632 | err = ptp_qoriq_init(ptp_qoriq, base, &ptp_qoriq_caps); |
ff54571a YL |
633 | if (err) |
634 | goto no_clock; | |
635 | ||
636 | platform_set_drvdata(dev, ptp_qoriq); | |
c78275f3 RC |
637 | return 0; |
638 | ||
639 | no_clock: | |
f3364222 | 640 | iounmap(base); |
c78275f3 | 641 | no_ioremap: |
1e562c81 | 642 | release_resource(ptp_qoriq->rsrc); |
c78275f3 | 643 | no_resource: |
1e562c81 | 644 | free_irq(ptp_qoriq->irq, ptp_qoriq); |
c78275f3 | 645 | no_node: |
1e562c81 | 646 | kfree(ptp_qoriq); |
c78275f3 RC |
647 | no_memory: |
648 | return err; | |
649 | } | |
650 | ||
1e562c81 | 651 | static int ptp_qoriq_remove(struct platform_device *dev) |
c78275f3 | 652 | { |
1e562c81 | 653 | struct ptp_qoriq *ptp_qoriq = platform_get_drvdata(dev); |
c78275f3 | 654 | |
ff54571a | 655 | ptp_qoriq_free(ptp_qoriq); |
1e562c81 | 656 | release_resource(ptp_qoriq->rsrc); |
1e562c81 | 657 | kfree(ptp_qoriq); |
c78275f3 RC |
658 | return 0; |
659 | } | |
660 | ||
94e5a2a8 | 661 | static const struct of_device_id match_table[] = { |
c78275f3 | 662 | { .compatible = "fsl,etsec-ptp" }, |
a8f62d0c | 663 | { .compatible = "fsl,fman-ptp-timer" }, |
c78275f3 RC |
664 | {}, |
665 | }; | |
23860063 | 666 | MODULE_DEVICE_TABLE(of, match_table); |
c78275f3 | 667 | |
1e562c81 | 668 | static struct platform_driver ptp_qoriq_driver = { |
c78275f3 | 669 | .driver = { |
ceefc71d | 670 | .name = "ptp_qoriq", |
c78275f3 | 671 | .of_match_table = match_table, |
c78275f3 | 672 | }, |
1e562c81 YL |
673 | .probe = ptp_qoriq_probe, |
674 | .remove = ptp_qoriq_remove, | |
c78275f3 RC |
675 | }; |
676 | ||
1e562c81 | 677 | module_platform_driver(ptp_qoriq_driver); |
c78275f3 | 678 | |
c2ec3ff6 | 679 | MODULE_AUTHOR("Richard Cochran <[email protected]>"); |
ceefc71d | 680 | MODULE_DESCRIPTION("PTP clock for Freescale QorIQ 1588 timer"); |
c78275f3 | 681 | MODULE_LICENSE("GPL"); |