xref: /OK3568_Linux_fs/kernel/drivers/ptp/ptp_qoriq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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(&regs->ctrl_regs->tmr_cnt_l);
34*4882a593Smuzhiyun 	hi = ptp_qoriq->read(&regs->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(&regs->ctrl_regs->tmr_cnt_l, lo);
48*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->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(&regs->alarm_regs->tmr_alarm1_l, lo);
64*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->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(&regs->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
74*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (ptp_qoriq->fiper3_support)
77*4882a593Smuzhiyun 		ptp_qoriq->write(&regs->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 = &regs->etts_regs->tmr_etts1_l;
93*4882a593Smuzhiyun 		reg_etts_h = &regs->etts_regs->tmr_etts1_h;
94*4882a593Smuzhiyun 		break;
95*4882a593Smuzhiyun 	case 1:
96*4882a593Smuzhiyun 		valid = ETS2_VLD;
97*4882a593Smuzhiyun 		reg_etts_l = &regs->etts_regs->tmr_etts2_l;
98*4882a593Smuzhiyun 		reg_etts_h = &regs->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(&regs->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(&regs->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(&regs->ctrl_regs->tmr_tevent);
143*4882a593Smuzhiyun 	mask = ptp_qoriq->read(&regs->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(&regs->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(&regs->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(&regs->ctrl_regs->tmr_temask);
300*4882a593Smuzhiyun 	if (on) {
301*4882a593Smuzhiyun 		mask |= bit;
302*4882a593Smuzhiyun 		ptp_qoriq->write(&regs->ctrl_regs->tmr_tevent, bit);
303*4882a593Smuzhiyun 	} else {
304*4882a593Smuzhiyun 		mask &= ~bit;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->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(&regs->ctrl_regs->tmr_ctrl, tmr_ctrl);
515*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->ctrl_regs->tmr_add, ptp_qoriq->tmr_add);
516*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->ctrl_regs->tmr_prsc, ptp_qoriq->tmr_prsc);
517*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
518*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (ptp_qoriq->fiper3_support)
521*4882a593Smuzhiyun 		ptp_qoriq->write(&regs->fiper_regs->tmr_fiper3,
522*4882a593Smuzhiyun 				 ptp_qoriq->tmr_fiper3);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	set_alarm(ptp_qoriq);
525*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->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(&regs->ctrl_regs->tmr_temask, 0);
545*4882a593Smuzhiyun 	ptp_qoriq->write(&regs->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