Blame view

drivers/ptp/ptp_qoriq.c 15.5 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
c78275f36   Richard Cochran   ptp: Added a cloc...
2
  /*
ceefc71d4   Yangbo Lu   ptp: rework gianf...
3
   * PTP 1588 clock for Freescale QorIQ 1588 timer
c78275f36   Richard Cochran   ptp: Added a cloc...
4
5
   *
   * Copyright (C) 2010 OMICRON electronics GmbH
c78275f36   Richard Cochran   ptp: Added a cloc...
6
   */
375d6a1b4   Joe Perches   gianfar: Use netd...
7
8
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
c78275f36   Richard Cochran   ptp: Added a cloc...
9
10
  #include <linux/device.h>
  #include <linux/hrtimer.h>
c78275f36   Richard Cochran   ptp: Added a cloc...
11
12
13
14
15
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/of_platform.h>
  #include <linux/timex.h>
ceefc71d4   Yangbo Lu   ptp: rework gianf...
16
  #include <linux/slab.h>
91305f281   Yangbo Lu   ptp_qoriq: suppor...
17
  #include <linux/clk.h>
c78275f36   Richard Cochran   ptp: Added a cloc...
18

6c50c1ed7   Yangbo Lu   ptp_qoriq: move s...
19
  #include <linux/fsl/ptp_qoriq.h>
ceefc71d4   Yangbo Lu   ptp: rework gianf...
20

c78275f36   Richard Cochran   ptp: Added a cloc...
21
22
23
  /*
   * Register access functions
   */
1e562c815   Yangbo Lu   ptp_qoriq: make s...
24
25
  /* Caller must hold ptp_qoriq->lock. */
  static u64 tmr_cnt_read(struct ptp_qoriq *ptp_qoriq)
c78275f36   Richard Cochran   ptp: Added a cloc...
26
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
27
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
c78275f36   Richard Cochran   ptp: Added a cloc...
28
29
  	u64 ns;
  	u32 lo, hi;
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
30
31
  	lo = ptp_qoriq->read(&regs->ctrl_regs->tmr_cnt_l);
  	hi = ptp_qoriq->read(&regs->ctrl_regs->tmr_cnt_h);
c78275f36   Richard Cochran   ptp: Added a cloc...
32
33
34
35
  	ns = ((u64) hi) << 32;
  	ns |= lo;
  	return ns;
  }
1e562c815   Yangbo Lu   ptp_qoriq: make s...
36
37
  /* Caller must hold ptp_qoriq->lock. */
  static void tmr_cnt_write(struct ptp_qoriq *ptp_qoriq, u64 ns)
c78275f36   Richard Cochran   ptp: Added a cloc...
38
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
39
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
c78275f36   Richard Cochran   ptp: Added a cloc...
40
41
  	u32 hi = ns >> 32;
  	u32 lo = ns & 0xffffffff;
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
42
43
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_cnt_l, lo);
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_cnt_h, hi);
c78275f36   Richard Cochran   ptp: Added a cloc...
44
  }
1e562c815   Yangbo Lu   ptp_qoriq: make s...
45
46
  /* Caller must hold ptp_qoriq->lock. */
  static void set_alarm(struct ptp_qoriq *ptp_qoriq)
c78275f36   Richard Cochran   ptp: Added a cloc...
47
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
48
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
c78275f36   Richard Cochran   ptp: Added a cloc...
49
50
  	u64 ns;
  	u32 lo, hi;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
51
  	ns = tmr_cnt_read(ptp_qoriq) + 1500000000ULL;
c78275f36   Richard Cochran   ptp: Added a cloc...
52
  	ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
53
  	ns -= ptp_qoriq->tclk_period;
c78275f36   Richard Cochran   ptp: Added a cloc...
54
55
  	hi = ns >> 32;
  	lo = ns & 0xffffffff;
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
56
57
  	ptp_qoriq->write(&regs->alarm_regs->tmr_alarm1_l, lo);
  	ptp_qoriq->write(&regs->alarm_regs->tmr_alarm1_h, hi);
c78275f36   Richard Cochran   ptp: Added a cloc...
58
  }
1e562c815   Yangbo Lu   ptp_qoriq: make s...
59
60
  /* Caller must hold ptp_qoriq->lock. */
  static void set_fipers(struct ptp_qoriq *ptp_qoriq)
c78275f36   Richard Cochran   ptp: Added a cloc...
61
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
62
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
a8f62d0c6   Yangbo Lu   ptp: support DPAA...
63

1e562c815   Yangbo Lu   ptp_qoriq: make s...
64
  	set_alarm(ptp_qoriq);
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
65
66
  	ptp_qoriq->write(&regs->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
  	ptp_qoriq->write(&regs->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2);
6d23d831e   Yangbo Lu   ptp_qoriq: suppor...
67
68
69
70
  
  	if (ptp_qoriq->fiper3_support)
  		ptp_qoriq->write(&regs->fiper_regs->tmr_fiper3,
  				 ptp_qoriq->tmr_fiper3);
c78275f36   Richard Cochran   ptp: Added a cloc...
71
  }
9429439f5   Yangbo Lu   ptp_qoriq: export...
72
  int extts_clean_up(struct ptp_qoriq *ptp_qoriq, int index, bool update_event)
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
73
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
74
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
75
76
77
  	struct ptp_clock_event event;
  	void __iomem *reg_etts_l;
  	void __iomem *reg_etts_h;
10bc877c7   Yangbo Lu   ptp_qoriq: check ...
78
  	u32 valid, lo, hi;
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  
  	switch (index) {
  	case 0:
  		valid = ETS1_VLD;
  		reg_etts_l = &regs->etts_regs->tmr_etts1_l;
  		reg_etts_h = &regs->etts_regs->tmr_etts1_h;
  		break;
  	case 1:
  		valid = ETS2_VLD;
  		reg_etts_l = &regs->etts_regs->tmr_etts2_l;
  		reg_etts_h = &regs->etts_regs->tmr_etts2_h;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	event.type = PTP_CLOCK_EXTTS;
  	event.index = index;
10bc877c7   Yangbo Lu   ptp_qoriq: check ...
97
98
99
  	if (ptp_qoriq->extts_fifo_support)
  		if (!(ptp_qoriq->read(&regs->ctrl_regs->tmr_stat) & valid))
  			return 0;
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
100
  	do {
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
101
102
  		lo = ptp_qoriq->read(reg_etts_l);
  		hi = ptp_qoriq->read(reg_etts_h);
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
103
104
105
106
  
  		if (update_event) {
  			event.timestamp = ((u64) hi) << 32;
  			event.timestamp |= lo;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
107
  			ptp_clock_event(ptp_qoriq->clock, &event);
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
108
  		}
10bc877c7   Yangbo Lu   ptp_qoriq: check ...
109
110
111
  		if (!ptp_qoriq->extts_fifo_support)
  			break;
  	} while (ptp_qoriq->read(&regs->ctrl_regs->tmr_stat) & valid);
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
112
113
114
  
  	return 0;
  }
9429439f5   Yangbo Lu   ptp_qoriq: export...
115
  EXPORT_SYMBOL_GPL(extts_clean_up);
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
116

c78275f36   Richard Cochran   ptp: Added a cloc...
117
118
119
  /*
   * Interrupt service routine
   */
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
120
  irqreturn_t ptp_qoriq_isr(int irq, void *priv)
c78275f36   Richard Cochran   ptp: Added a cloc...
121
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
122
123
  	struct ptp_qoriq *ptp_qoriq = priv;
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
c78275f36   Richard Cochran   ptp: Added a cloc...
124
  	struct ptp_clock_event event;
d71151a39   Yangbo Lu   ptp_qoriq: drop t...
125
  	u32 ack = 0, mask, val, irqs;
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
126

1e562c815   Yangbo Lu   ptp_qoriq: make s...
127
  	spin_lock(&ptp_qoriq->lock);
c78275f36   Richard Cochran   ptp: Added a cloc...
128

f038ddf25   Yangbo Lu   ptp_qoriq: add li...
129
130
  	val = ptp_qoriq->read(&regs->ctrl_regs->tmr_tevent);
  	mask = ptp_qoriq->read(&regs->ctrl_regs->tmr_temask);
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
131

1e562c815   Yangbo Lu   ptp_qoriq: make s...
132
  	spin_unlock(&ptp_qoriq->lock);
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
133
134
  
  	irqs = val & mask;
c78275f36   Richard Cochran   ptp: Added a cloc...
135

b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
136
  	if (irqs & ETS1) {
c78275f36   Richard Cochran   ptp: Added a cloc...
137
  		ack |= ETS1;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
138
  		extts_clean_up(ptp_qoriq, 0, true);
c78275f36   Richard Cochran   ptp: Added a cloc...
139
  	}
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
140
  	if (irqs & ETS2) {
c78275f36   Richard Cochran   ptp: Added a cloc...
141
  		ack |= ETS2;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
142
  		extts_clean_up(ptp_qoriq, 1, true);
c78275f36   Richard Cochran   ptp: Added a cloc...
143
  	}
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
144
  	if (irqs & PP1) {
c78275f36   Richard Cochran   ptp: Added a cloc...
145
146
  		ack |= PP1;
  		event.type = PTP_CLOCK_PPS;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
147
  		ptp_clock_event(ptp_qoriq->clock, &event);
c78275f36   Richard Cochran   ptp: Added a cloc...
148
149
150
  	}
  
  	if (ack) {
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
151
  		ptp_qoriq->write(&regs->ctrl_regs->tmr_tevent, ack);
c78275f36   Richard Cochran   ptp: Added a cloc...
152
153
154
155
  		return IRQ_HANDLED;
  	} else
  		return IRQ_NONE;
  }
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
156
  EXPORT_SYMBOL_GPL(ptp_qoriq_isr);
c78275f36   Richard Cochran   ptp: Added a cloc...
157
158
159
160
  
  /*
   * PTP clock operations
   */
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
161
  int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
c78275f36   Richard Cochran   ptp: Added a cloc...
162
  {
428951161   Ulrik De Bie   ptp: gianfar: Use...
163
164
  	u64 adj, diff;
  	u32 tmr_add;
c78275f36   Richard Cochran   ptp: Added a cloc...
165
  	int neg_adj = 0;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
166
167
  	struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
c78275f36   Richard Cochran   ptp: Added a cloc...
168

428951161   Ulrik De Bie   ptp: gianfar: Use...
169
  	if (scaled_ppm < 0) {
c78275f36   Richard Cochran   ptp: Added a cloc...
170
  		neg_adj = 1;
428951161   Ulrik De Bie   ptp: gianfar: Use...
171
  		scaled_ppm = -scaled_ppm;
c78275f36   Richard Cochran   ptp: Added a cloc...
172
  	}
1e562c815   Yangbo Lu   ptp_qoriq: make s...
173
  	tmr_add = ptp_qoriq->tmr_add;
c78275f36   Richard Cochran   ptp: Added a cloc...
174
  	adj = tmr_add;
428951161   Ulrik De Bie   ptp: gianfar: Use...
175
176
177
178
179
180
181
  
  	/* calculate diff as adj*(scaled_ppm/65536)/1000000
  	 * and round() to the nearest integer
  	 */
  	adj *= scaled_ppm;
  	diff = div_u64(adj, 8000000);
  	diff = (diff >> 13) + ((diff >> 12) & 1);
c78275f36   Richard Cochran   ptp: Added a cloc...
182
183
  
  	tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
184
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_add, tmr_add);
c78275f36   Richard Cochran   ptp: Added a cloc...
185
186
187
  
  	return 0;
  }
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
188
  EXPORT_SYMBOL_GPL(ptp_qoriq_adjfine);
c78275f36   Richard Cochran   ptp: Added a cloc...
189

73356e4ea   Yangbo Lu   ptp_qoriq: make p...
190
  int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta)
c78275f36   Richard Cochran   ptp: Added a cloc...
191
192
193
  {
  	s64 now;
  	unsigned long flags;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
194
  	struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
c78275f36   Richard Cochran   ptp: Added a cloc...
195

1e562c815   Yangbo Lu   ptp_qoriq: make s...
196
  	spin_lock_irqsave(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
197

1e562c815   Yangbo Lu   ptp_qoriq: make s...
198
  	now = tmr_cnt_read(ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
199
  	now += delta;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
200
201
  	tmr_cnt_write(ptp_qoriq, now);
  	set_fipers(ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
202

1e562c815   Yangbo Lu   ptp_qoriq: make s...
203
  	spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
204

c78275f36   Richard Cochran   ptp: Added a cloc...
205
206
  	return 0;
  }
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
207
  EXPORT_SYMBOL_GPL(ptp_qoriq_adjtime);
c78275f36   Richard Cochran   ptp: Added a cloc...
208

73356e4ea   Yangbo Lu   ptp_qoriq: make p...
209
  int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
c78275f36   Richard Cochran   ptp: Added a cloc...
210
211
  {
  	u64 ns;
c78275f36   Richard Cochran   ptp: Added a cloc...
212
  	unsigned long flags;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
213
  	struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
c78275f36   Richard Cochran   ptp: Added a cloc...
214

1e562c815   Yangbo Lu   ptp_qoriq: make s...
215
  	spin_lock_irqsave(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
216

1e562c815   Yangbo Lu   ptp_qoriq: make s...
217
  	ns = tmr_cnt_read(ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
218

1e562c815   Yangbo Lu   ptp_qoriq: make s...
219
  	spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
220

3359e7c2e   Richard Cochran   ptp: gianfar: use...
221
  	*ts = ns_to_timespec64(ns);
c78275f36   Richard Cochran   ptp: Added a cloc...
222
223
  	return 0;
  }
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
224
  EXPORT_SYMBOL_GPL(ptp_qoriq_gettime);
c78275f36   Richard Cochran   ptp: Added a cloc...
225

73356e4ea   Yangbo Lu   ptp_qoriq: make p...
226
227
  int ptp_qoriq_settime(struct ptp_clock_info *ptp,
  		      const struct timespec64 *ts)
c78275f36   Richard Cochran   ptp: Added a cloc...
228
229
230
  {
  	u64 ns;
  	unsigned long flags;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
231
  	struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
c78275f36   Richard Cochran   ptp: Added a cloc...
232

3359e7c2e   Richard Cochran   ptp: gianfar: use...
233
  	ns = timespec64_to_ns(ts);
c78275f36   Richard Cochran   ptp: Added a cloc...
234

1e562c815   Yangbo Lu   ptp_qoriq: make s...
235
  	spin_lock_irqsave(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
236

1e562c815   Yangbo Lu   ptp_qoriq: make s...
237
238
  	tmr_cnt_write(ptp_qoriq, ns);
  	set_fipers(ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
239

1e562c815   Yangbo Lu   ptp_qoriq: make s...
240
  	spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
241
242
243
  
  	return 0;
  }
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
244
  EXPORT_SYMBOL_GPL(ptp_qoriq_settime);
c78275f36   Richard Cochran   ptp: Added a cloc...
245

73356e4ea   Yangbo Lu   ptp_qoriq: make p...
246
247
  int ptp_qoriq_enable(struct ptp_clock_info *ptp,
  		     struct ptp_clock_request *rq, int on)
c78275f36   Richard Cochran   ptp: Added a cloc...
248
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
249
250
  	struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
c78275f36   Richard Cochran   ptp: Added a cloc...
251
  	unsigned long flags;
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
252
  	u32 bit, mask = 0;
c78275f36   Richard Cochran   ptp: Added a cloc...
253
254
255
256
257
258
259
260
261
262
263
264
265
  
  	switch (rq->type) {
  	case PTP_CLK_REQ_EXTTS:
  		switch (rq->extts.index) {
  		case 0:
  			bit = ETS1EN;
  			break;
  		case 1:
  			bit = ETS2EN;
  			break;
  		default:
  			return -EINVAL;
  		}
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
266
267
  
  		if (on)
1e562c815   Yangbo Lu   ptp_qoriq: make s...
268
  			extts_clean_up(ptp_qoriq, rq->extts.index, false);
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
269

b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
270
  		break;
c78275f36   Richard Cochran   ptp: Added a cloc...
271
  	case PTP_CLK_REQ_PPS:
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
272
  		bit = PP1EN;
c78275f36   Richard Cochran   ptp: Added a cloc...
273
  		break;
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
274
275
276
  	default:
  		return -EOPNOTSUPP;
  	}
1e562c815   Yangbo Lu   ptp_qoriq: make s...
277
  	spin_lock_irqsave(&ptp_qoriq->lock, flags);
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
278

f038ddf25   Yangbo Lu   ptp_qoriq: add li...
279
  	mask = ptp_qoriq->read(&regs->ctrl_regs->tmr_temask);
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
280
281
  	if (on) {
  		mask |= bit;
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
282
  		ptp_qoriq->write(&regs->ctrl_regs->tmr_tevent, bit);
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
283
284
  	} else {
  		mask &= ~bit;
c78275f36   Richard Cochran   ptp: Added a cloc...
285
  	}
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
286
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_temask, mask);
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
287

1e562c815   Yangbo Lu   ptp_qoriq: make s...
288
  	spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
b0bc10cc8   Yangbo Lu   ptp_qoriq: fix in...
289
  	return 0;
c78275f36   Richard Cochran   ptp: Added a cloc...
290
  }
73356e4ea   Yangbo Lu   ptp_qoriq: make p...
291
  EXPORT_SYMBOL_GPL(ptp_qoriq_enable);
c78275f36   Richard Cochran   ptp: Added a cloc...
292

ceefc71d4   Yangbo Lu   ptp: rework gianf...
293
  static const struct ptp_clock_info ptp_qoriq_caps = {
c78275f36   Richard Cochran   ptp: Added a cloc...
294
  	.owner		= THIS_MODULE,
ceefc71d4   Yangbo Lu   ptp: rework gianf...
295
  	.name		= "qoriq ptp clock",
c78275f36   Richard Cochran   ptp: Added a cloc...
296
  	.max_adj	= 512000,
cd4baaaa0   Richard Cochran   gianfar: do not a...
297
  	.n_alarm	= 0,
c78275f36   Richard Cochran   ptp: Added a cloc...
298
299
  	.n_ext_ts	= N_EXT_TS,
  	.n_per_out	= 0,
4986b4f00   Richard Cochran   ptp: drivers: set...
300
  	.n_pins		= 0,
c78275f36   Richard Cochran   ptp: Added a cloc...
301
  	.pps		= 1,
ceefc71d4   Yangbo Lu   ptp: rework gianf...
302
303
304
305
306
  	.adjfine	= ptp_qoriq_adjfine,
  	.adjtime	= ptp_qoriq_adjtime,
  	.gettime64	= ptp_qoriq_gettime,
  	.settime64	= ptp_qoriq_settime,
  	.enable		= ptp_qoriq_enable,
c78275f36   Richard Cochran   ptp: Added a cloc...
307
  };
91305f281   Yangbo Lu   ptp_qoriq: suppor...
308
  /**
1e562c815   Yangbo Lu   ptp_qoriq: make s...
309
   * ptp_qoriq_nominal_freq - calculate nominal frequency according to
91305f281   Yangbo Lu   ptp_qoriq: suppor...
310
311
312
313
314
315
316
317
318
319
   *			    reference clock frequency
   *
   * @clk_src: reference clock frequency
   *
   * The nominal frequency is the desired clock frequency.
   * It should be less than the reference clock frequency.
   * It should be a factor of 1000MHz.
   *
   * Return the nominal frequency
   */
1e562c815   Yangbo Lu   ptp_qoriq: make s...
320
  static u32 ptp_qoriq_nominal_freq(u32 clk_src)
91305f281   Yangbo Lu   ptp_qoriq: suppor...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
  {
  	u32 remainder = 0;
  
  	clk_src /= 1000000;
  	remainder = clk_src % 100;
  	if (remainder) {
  		clk_src -= remainder;
  		clk_src += 100;
  	}
  
  	do {
  		clk_src -= 100;
  
  	} while (1000 % clk_src);
  
  	return clk_src * 1000000;
  }
  
  /**
1e562c815   Yangbo Lu   ptp_qoriq: make s...
340
   * ptp_qoriq_auto_config - calculate a set of default configurations
91305f281   Yangbo Lu   ptp_qoriq: suppor...
341
   *
1e562c815   Yangbo Lu   ptp_qoriq: make s...
342
   * @ptp_qoriq: pointer to ptp_qoriq
91305f281   Yangbo Lu   ptp_qoriq: suppor...
343
344
345
346
347
348
349
350
351
   * @node: pointer to device_node
   *
   * If below dts properties are not provided, this function will be
   * called to calculate a set of default configurations for them.
   *   "fsl,tclk-period"
   *   "fsl,tmr-prsc"
   *   "fsl,tmr-add"
   *   "fsl,tmr-fiper1"
   *   "fsl,tmr-fiper2"
6d23d831e   Yangbo Lu   ptp_qoriq: suppor...
352
   *   "fsl,tmr-fiper3" (required only for DPAA2 and ENETC hardware)
91305f281   Yangbo Lu   ptp_qoriq: suppor...
353
354
355
356
   *   "fsl,max-adj"
   *
   * Return 0 if success
   */
1e562c815   Yangbo Lu   ptp_qoriq: make s...
357
  static int ptp_qoriq_auto_config(struct ptp_qoriq *ptp_qoriq,
91305f281   Yangbo Lu   ptp_qoriq: suppor...
358
359
360
361
362
363
  				 struct device_node *node)
  {
  	struct clk *clk;
  	u64 freq_comp;
  	u64 max_adj;
  	u32 nominal_freq;
74c05a33c   Yangbo Lu   ptp_qoriq: use di...
364
  	u32 remainder = 0;
91305f281   Yangbo Lu   ptp_qoriq: suppor...
365
  	u32 clk_src = 0;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
366
  	ptp_qoriq->cksel = DEFAULT_CKSEL;
91305f281   Yangbo Lu   ptp_qoriq: suppor...
367
368
369
370
371
372
373
374
375
376
377
378
  
  	clk = of_clk_get(node, 0);
  	if (!IS_ERR(clk)) {
  		clk_src = clk_get_rate(clk);
  		clk_put(clk);
  	}
  
  	if (clk_src <= 100000000UL) {
  		pr_err("error reference clock value, or lower than 100MHz
  ");
  		return -EINVAL;
  	}
1e562c815   Yangbo Lu   ptp_qoriq: make s...
379
  	nominal_freq = ptp_qoriq_nominal_freq(clk_src);
91305f281   Yangbo Lu   ptp_qoriq: suppor...
380
381
  	if (!nominal_freq)
  		return -EINVAL;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
382
383
  	ptp_qoriq->tclk_period = 1000000000UL / nominal_freq;
  	ptp_qoriq->tmr_prsc = DEFAULT_TMR_PRSC;
91305f281   Yangbo Lu   ptp_qoriq: suppor...
384
385
386
387
388
389
  
  	/* Calculate initial frequency compensation value for TMR_ADD register.
  	 * freq_comp = ceil(2^32 / freq_ratio)
  	 * freq_ratio = reference_clock_freq / nominal_freq
  	 */
  	freq_comp = ((u64)1 << 32) * nominal_freq;
74c05a33c   Yangbo Lu   ptp_qoriq: use di...
390
391
  	freq_comp = div_u64_rem(freq_comp, clk_src, &remainder);
  	if (remainder)
91305f281   Yangbo Lu   ptp_qoriq: suppor...
392
  		freq_comp++;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
393
394
395
  	ptp_qoriq->tmr_add = freq_comp;
  	ptp_qoriq->tmr_fiper1 = DEFAULT_FIPER1_PERIOD - ptp_qoriq->tclk_period;
  	ptp_qoriq->tmr_fiper2 = DEFAULT_FIPER2_PERIOD - ptp_qoriq->tclk_period;
6d23d831e   Yangbo Lu   ptp_qoriq: suppor...
396
  	ptp_qoriq->tmr_fiper3 = DEFAULT_FIPER3_PERIOD - ptp_qoriq->tclk_period;
91305f281   Yangbo Lu   ptp_qoriq: suppor...
397
398
399
400
401
  
  	/* max_adj = 1000000000 * (freq_ratio - 1.0) - 1
  	 * freq_ratio = reference_clock_freq / nominal_freq
  	 */
  	max_adj = 1000000000ULL * (clk_src - nominal_freq);
74c05a33c   Yangbo Lu   ptp_qoriq: use di...
402
  	max_adj = div_u64(max_adj, nominal_freq) - 1;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
403
  	ptp_qoriq->caps.max_adj = max_adj;
91305f281   Yangbo Lu   ptp_qoriq: suppor...
404
405
406
  
  	return 0;
  }
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
407
  int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base,
58066ac9d   Colin Ian King   ptp_qoriq: don't ...
408
  		   const struct ptp_clock_info *caps)
c78275f36   Richard Cochran   ptp: Added a cloc...
409
  {
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
410
  	struct device_node *node = ptp_qoriq->dev->of_node;
1e562c815   Yangbo Lu   ptp_qoriq: make s...
411
  	struct ptp_qoriq_registers *regs;
d28fdf0fe   Richard Cochran   ptp: gianfar: con...
412
  	struct timespec64 now;
c78275f36   Richard Cochran   ptp: Added a cloc...
413
  	unsigned long flags;
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
414
  	u32 tmr_ctrl;
c78275f36   Richard Cochran   ptp: Added a cloc...
415

7f4399ba4   Claudiu Manoil   ptp_qoriq: fix NU...
416
417
  	if (!node)
  		return -ENODEV;
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
418
  	ptp_qoriq->base = base;
58066ac9d   Colin Ian King   ptp_qoriq: don't ...
419
  	ptp_qoriq->caps = *caps;
e58f6f4fb   Aida Mynzhasova   powerpc/83xx: gia...
420

1e562c815   Yangbo Lu   ptp_qoriq: make s...
421
422
  	if (of_property_read_u32(node, "fsl,cksel", &ptp_qoriq->cksel))
  		ptp_qoriq->cksel = DEFAULT_CKSEL;
c78275f36   Richard Cochran   ptp: Added a cloc...
423

6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
424
  	if (of_property_read_bool(node, "fsl,extts-fifo"))
1e562c815   Yangbo Lu   ptp_qoriq: make s...
425
  		ptp_qoriq->extts_fifo_support = true;
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
426
  	else
1e562c815   Yangbo Lu   ptp_qoriq: make s...
427
  		ptp_qoriq->extts_fifo_support = false;
6815d8b09   Yangbo Lu   ptp_qoriq: suppor...
428

6d23d831e   Yangbo Lu   ptp_qoriq: suppor...
429
430
431
  	if (of_device_is_compatible(node, "fsl,dpaa2-ptp") ||
  	    of_device_is_compatible(node, "fsl,enetc-ptp"))
  		ptp_qoriq->fiper3_support = true;
c35ec7796   Yangbo Lu   gianfar_ptp: repl...
432
  	if (of_property_read_u32(node,
1e562c815   Yangbo Lu   ptp_qoriq: make s...
433
  				 "fsl,tclk-period", &ptp_qoriq->tclk_period) ||
c35ec7796   Yangbo Lu   gianfar_ptp: repl...
434
  	    of_property_read_u32(node,
1e562c815   Yangbo Lu   ptp_qoriq: make s...
435
  				 "fsl,tmr-prsc", &ptp_qoriq->tmr_prsc) ||
c35ec7796   Yangbo Lu   gianfar_ptp: repl...
436
  	    of_property_read_u32(node,
1e562c815   Yangbo Lu   ptp_qoriq: make s...
437
  				 "fsl,tmr-add", &ptp_qoriq->tmr_add) ||
c35ec7796   Yangbo Lu   gianfar_ptp: repl...
438
  	    of_property_read_u32(node,
1e562c815   Yangbo Lu   ptp_qoriq: make s...
439
  				 "fsl,tmr-fiper1", &ptp_qoriq->tmr_fiper1) ||
c35ec7796   Yangbo Lu   gianfar_ptp: repl...
440
  	    of_property_read_u32(node,
1e562c815   Yangbo Lu   ptp_qoriq: make s...
441
  				 "fsl,tmr-fiper2", &ptp_qoriq->tmr_fiper2) ||
c35ec7796   Yangbo Lu   gianfar_ptp: repl...
442
  	    of_property_read_u32(node,
6d23d831e   Yangbo Lu   ptp_qoriq: suppor...
443
444
445
446
  				 "fsl,max-adj", &ptp_qoriq->caps.max_adj) ||
  	    (ptp_qoriq->fiper3_support &&
  	     of_property_read_u32(node, "fsl,tmr-fiper3",
  				  &ptp_qoriq->tmr_fiper3))) {
91305f281   Yangbo Lu   ptp_qoriq: suppor...
447
448
  		pr_warn("device tree node missing required elements, try automatic configuration
  ");
1e562c815   Yangbo Lu   ptp_qoriq: make s...
449
  		if (ptp_qoriq_auto_config(ptp_qoriq, node))
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
450
  			return -ENODEV;
c78275f36   Richard Cochran   ptp: Added a cloc...
451
  	}
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
452
453
454
455
456
457
458
  	if (of_property_read_bool(node, "little-endian")) {
  		ptp_qoriq->read = qoriq_read_le;
  		ptp_qoriq->write = qoriq_write_le;
  	} else {
  		ptp_qoriq->read = qoriq_read_be;
  		ptp_qoriq->write = qoriq_write_be;
  	}
d4e176870   Yangbo Lu   ptp_qoriq: fix re...
459
460
461
462
463
464
  	/* The eTSEC uses differnt memory map with DPAA/ENETC */
  	if (of_device_is_compatible(node, "fsl,etsec-ptp")) {
  		ptp_qoriq->regs.ctrl_regs = base + ETSEC_CTRL_REGS_OFFSET;
  		ptp_qoriq->regs.alarm_regs = base + ETSEC_ALARM_REGS_OFFSET;
  		ptp_qoriq->regs.fiper_regs = base + ETSEC_FIPER_REGS_OFFSET;
  		ptp_qoriq->regs.etts_regs = base + ETSEC_ETTS_REGS_OFFSET;
a8f62d0c6   Yangbo Lu   ptp: support DPAA...
465
  	} else {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
466
467
468
469
  		ptp_qoriq->regs.ctrl_regs = base + CTRL_REGS_OFFSET;
  		ptp_qoriq->regs.alarm_regs = base + ALARM_REGS_OFFSET;
  		ptp_qoriq->regs.fiper_regs = base + FIPER_REGS_OFFSET;
  		ptp_qoriq->regs.etts_regs = base + ETTS_REGS_OFFSET;
a8f62d0c6   Yangbo Lu   ptp: support DPAA...
470
  	}
db34a4714   Vladimir Oltean   ptp_qoriq: Initia...
471
  	spin_lock_init(&ptp_qoriq->lock);
f696a21c2   Arnd Bergmann   ptp: replace getn...
472
  	ktime_get_real_ts64(&now);
1e562c815   Yangbo Lu   ptp_qoriq: make s...
473
  	ptp_qoriq_settime(&ptp_qoriq->caps, &now);
c78275f36   Richard Cochran   ptp: Added a cloc...
474
475
  
  	tmr_ctrl =
1e562c815   Yangbo Lu   ptp_qoriq: make s...
476
477
  	  (ptp_qoriq->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT |
  	  (ptp_qoriq->cksel & CKSEL_MASK) << CKSEL_SHIFT;
c78275f36   Richard Cochran   ptp: Added a cloc...
478

1e562c815   Yangbo Lu   ptp_qoriq: make s...
479
  	spin_lock_irqsave(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
480

1e562c815   Yangbo Lu   ptp_qoriq: make s...
481
  	regs = &ptp_qoriq->regs;
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
482
483
484
485
486
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, tmr_ctrl);
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_add, ptp_qoriq->tmr_add);
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_prsc, ptp_qoriq->tmr_prsc);
  	ptp_qoriq->write(&regs->fiper_regs->tmr_fiper1, ptp_qoriq->tmr_fiper1);
  	ptp_qoriq->write(&regs->fiper_regs->tmr_fiper2, ptp_qoriq->tmr_fiper2);
6d23d831e   Yangbo Lu   ptp_qoriq: suppor...
487
488
489
490
  
  	if (ptp_qoriq->fiper3_support)
  		ptp_qoriq->write(&regs->fiper_regs->tmr_fiper3,
  				 ptp_qoriq->tmr_fiper3);
1e562c815   Yangbo Lu   ptp_qoriq: make s...
491
  	set_alarm(ptp_qoriq);
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
492
493
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl,
  			 tmr_ctrl|FIPERST|RTPE|TE|FRD);
c78275f36   Richard Cochran   ptp: Added a cloc...
494

1e562c815   Yangbo Lu   ptp_qoriq: make s...
495
  	spin_unlock_irqrestore(&ptp_qoriq->lock, flags);
c78275f36   Richard Cochran   ptp: Added a cloc...
496

ff54571a7   Yangbo Lu   ptp_qoriq: conver...
497
498
499
  	ptp_qoriq->clock = ptp_clock_register(&ptp_qoriq->caps, ptp_qoriq->dev);
  	if (IS_ERR(ptp_qoriq->clock))
  		return PTR_ERR(ptp_qoriq->clock);
c78275f36   Richard Cochran   ptp: Added a cloc...
500

ff54571a7   Yangbo Lu   ptp_qoriq: conver...
501
  	ptp_qoriq->phc_index = ptp_clock_index(ptp_qoriq->clock);
1e562c815   Yangbo Lu   ptp_qoriq: make s...
502
  	ptp_qoriq_create_debugfs(ptp_qoriq);
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
503
504
505
506
507
508
509
  	return 0;
  }
  EXPORT_SYMBOL_GPL(ptp_qoriq_init);
  
  void ptp_qoriq_free(struct ptp_qoriq *ptp_qoriq)
  {
  	struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
f038ddf25   Yangbo Lu   ptp_qoriq: add li...
510
511
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_temask, 0);
  	ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl,   0);
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
512
513
514
515
516
517
518
519
520
521
522
523
524
  
  	ptp_qoriq_remove_debugfs(ptp_qoriq);
  	ptp_clock_unregister(ptp_qoriq->clock);
  	iounmap(ptp_qoriq->base);
  	free_irq(ptp_qoriq->irq, ptp_qoriq);
  }
  EXPORT_SYMBOL_GPL(ptp_qoriq_free);
  
  static int ptp_qoriq_probe(struct platform_device *dev)
  {
  	struct ptp_qoriq *ptp_qoriq;
  	int err = -ENOMEM;
  	void __iomem *base;
c78275f36   Richard Cochran   ptp: Added a cloc...
525

ff54571a7   Yangbo Lu   ptp_qoriq: conver...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  	ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL);
  	if (!ptp_qoriq)
  		goto no_memory;
  
  	ptp_qoriq->dev = &dev->dev;
  
  	err = -ENODEV;
  
  	ptp_qoriq->irq = platform_get_irq(dev, 0);
  	if (ptp_qoriq->irq < 0) {
  		pr_err("irq not in device tree
  ");
  		goto no_node;
  	}
  	if (request_irq(ptp_qoriq->irq, ptp_qoriq_isr, IRQF_SHARED,
  			DRIVER, ptp_qoriq)) {
  		pr_err("request_irq failed
  ");
  		goto no_node;
  	}
  
  	ptp_qoriq->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0);
  	if (!ptp_qoriq->rsrc) {
  		pr_err("no resource
  ");
  		goto no_resource;
  	}
  	if (request_resource(&iomem_resource, ptp_qoriq->rsrc)) {
  		pr_err("resource busy
  ");
  		goto no_resource;
  	}
  
  	base = ioremap(ptp_qoriq->rsrc->start,
  		       resource_size(ptp_qoriq->rsrc));
  	if (!base) {
  		pr_err("ioremap ptp registers failed
  ");
  		goto no_ioremap;
  	}
58066ac9d   Colin Ian King   ptp_qoriq: don't ...
566
  	err = ptp_qoriq_init(ptp_qoriq, base, &ptp_qoriq_caps);
ff54571a7   Yangbo Lu   ptp_qoriq: conver...
567
568
569
570
  	if (err)
  		goto no_clock;
  
  	platform_set_drvdata(dev, ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
571
572
573
  	return 0;
  
  no_clock:
1e562c815   Yangbo Lu   ptp_qoriq: make s...
574
  	iounmap(ptp_qoriq->base);
c78275f36   Richard Cochran   ptp: Added a cloc...
575
  no_ioremap:
1e562c815   Yangbo Lu   ptp_qoriq: make s...
576
  	release_resource(ptp_qoriq->rsrc);
c78275f36   Richard Cochran   ptp: Added a cloc...
577
  no_resource:
1e562c815   Yangbo Lu   ptp_qoriq: make s...
578
  	free_irq(ptp_qoriq->irq, ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
579
  no_node:
1e562c815   Yangbo Lu   ptp_qoriq: make s...
580
  	kfree(ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
581
582
583
  no_memory:
  	return err;
  }
1e562c815   Yangbo Lu   ptp_qoriq: make s...
584
  static int ptp_qoriq_remove(struct platform_device *dev)
c78275f36   Richard Cochran   ptp: Added a cloc...
585
  {
1e562c815   Yangbo Lu   ptp_qoriq: make s...
586
  	struct ptp_qoriq *ptp_qoriq = platform_get_drvdata(dev);
c78275f36   Richard Cochran   ptp: Added a cloc...
587

ff54571a7   Yangbo Lu   ptp_qoriq: conver...
588
  	ptp_qoriq_free(ptp_qoriq);
1e562c815   Yangbo Lu   ptp_qoriq: make s...
589
  	release_resource(ptp_qoriq->rsrc);
1e562c815   Yangbo Lu   ptp_qoriq: make s...
590
  	kfree(ptp_qoriq);
c78275f36   Richard Cochran   ptp: Added a cloc...
591
592
  	return 0;
  }
94e5a2a88   Fabian Frederick   net/fsl: constify...
593
  static const struct of_device_id match_table[] = {
c78275f36   Richard Cochran   ptp: Added a cloc...
594
  	{ .compatible = "fsl,etsec-ptp" },
a8f62d0c6   Yangbo Lu   ptp: support DPAA...
595
  	{ .compatible = "fsl,fman-ptp-timer" },
c78275f36   Richard Cochran   ptp: Added a cloc...
596
597
  	{},
  };
238600637   Luis de Bethencourt   net: gianfar_ptp:...
598
  MODULE_DEVICE_TABLE(of, match_table);
c78275f36   Richard Cochran   ptp: Added a cloc...
599

1e562c815   Yangbo Lu   ptp_qoriq: make s...
600
  static struct platform_driver ptp_qoriq_driver = {
c78275f36   Richard Cochran   ptp: Added a cloc...
601
  	.driver = {
ceefc71d4   Yangbo Lu   ptp: rework gianf...
602
  		.name		= "ptp_qoriq",
c78275f36   Richard Cochran   ptp: Added a cloc...
603
  		.of_match_table	= match_table,
c78275f36   Richard Cochran   ptp: Added a cloc...
604
  	},
1e562c815   Yangbo Lu   ptp_qoriq: make s...
605
606
  	.probe       = ptp_qoriq_probe,
  	.remove      = ptp_qoriq_remove,
c78275f36   Richard Cochran   ptp: Added a cloc...
607
  };
1e562c815   Yangbo Lu   ptp_qoriq: make s...
608
  module_platform_driver(ptp_qoriq_driver);
c78275f36   Richard Cochran   ptp: Added a cloc...
609

c2ec3ff6b   Richard Cochran   phc: Update autho...
610
  MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
ceefc71d4   Yangbo Lu   ptp: rework gianf...
611
  MODULE_DESCRIPTION("PTP clock for Freescale QorIQ 1588 timer");
c78275f36   Richard Cochran   ptp: Added a cloc...
612
  MODULE_LICENSE("GPL");