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