Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
  2/* Microsemi Ocelot PTP clock driver
  3 *
  4 * Copyright (c) 2017 Microsemi Corporation
  5 * Copyright 2020 NXP
  6 */
  7#include <linux/time64.h>
  8
  9#include <soc/mscc/ocelot_ptp.h>
 10#include <soc/mscc/ocelot_sys.h>
 11#include <soc/mscc/ocelot.h>
 12
 13int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
 14{
 15	struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
 16	unsigned long flags;
 17	time64_t s;
 18	u32 val;
 19	s64 ns;
 20
 21	spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
 22
 23	val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
 24	val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
 25	val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE);
 26	ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
 27
 28	s = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN) & 0xffff;
 29	s <<= 32;
 30	s += ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
 31	ns = ocelot_read_rix(ocelot, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
 32
 33	spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 34
 35	/* Deal with negative values */
 36	if (ns >= 0x3ffffff0 && ns <= 0x3fffffff) {
 37		s--;
 38		ns &= 0xf;
 39		ns += 999999984;
 40	}
 41
 42	set_normalized_timespec64(ts, s, ns);
 43	return 0;
 44}
 45EXPORT_SYMBOL(ocelot_ptp_gettime64);
 46
 47int ocelot_ptp_settime64(struct ptp_clock_info *ptp,
 48			 const struct timespec64 *ts)
 49{
 50	struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
 51	unsigned long flags;
 52	u32 val;
 53
 54	spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
 55
 56	val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
 57	val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
 58	val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
 59
 60	ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
 61
 62	ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB,
 63			 TOD_ACC_PIN);
 64	ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB,
 65			 TOD_ACC_PIN);
 66	ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
 67
 68	val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
 69	val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
 70	val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD);
 71
 72	ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
 73
 74	spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 75	return 0;
 76}
 77EXPORT_SYMBOL(ocelot_ptp_settime64);
 78
 79int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 80{
 81	if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) {
 82		struct ocelot *ocelot = container_of(ptp, struct ocelot,
 83						     ptp_info);
 84		unsigned long flags;
 85		u32 val;
 86
 87		spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
 88
 89		val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
 90		val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK |
 91			 PTP_PIN_CFG_DOM);
 92		val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
 93
 94		ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
 95
 96		ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
 97		ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN);
 98		ocelot_write_rix(ocelot, delta, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
 99
100		val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
101		val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK |
102			 PTP_PIN_CFG_DOM);
103		val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA);
104
105		ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
106
107		spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
108	} else {
109		/* Fall back using ocelot_ptp_settime64 which is not exact. */
110		struct timespec64 ts;
111		u64 now;
112
113		ocelot_ptp_gettime64(ptp, &ts);
114
115		now = ktime_to_ns(timespec64_to_ktime(ts));
116		ts = ns_to_timespec64(now + delta);
117
118		ocelot_ptp_settime64(ptp, &ts);
119	}
120	return 0;
121}
122EXPORT_SYMBOL(ocelot_ptp_adjtime);
123
124int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
125{
126	struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
127	u32 unit = 0, direction = 0;
128	unsigned long flags;
129	u64 adj = 0;
130
131	spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
132
133	if (!scaled_ppm)
134		goto disable_adj;
135
136	if (scaled_ppm < 0) {
137		direction = PTP_CFG_CLK_ADJ_CFG_DIR;
138		scaled_ppm = -scaled_ppm;
139	}
140
141	adj = PSEC_PER_SEC << 16;
142	do_div(adj, scaled_ppm);
143	do_div(adj, 1000);
144
145	/* If the adjustment value is too large, use ns instead */
146	if (adj >= (1L << 30)) {
147		unit = PTP_CFG_CLK_ADJ_FREQ_NS;
148		do_div(adj, 1000);
149	}
150
151	/* Still too big */
152	if (adj >= (1L << 30))
153		goto disable_adj;
154
155	ocelot_write(ocelot, unit | adj, PTP_CLK_CFG_ADJ_FREQ);
156	ocelot_write(ocelot, PTP_CFG_CLK_ADJ_CFG_ENA | direction,
157		     PTP_CLK_CFG_ADJ_CFG);
158
159	spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
160	return 0;
161
162disable_adj:
163	ocelot_write(ocelot, 0, PTP_CLK_CFG_ADJ_CFG);
164
165	spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
166	return 0;
167}
168EXPORT_SYMBOL(ocelot_ptp_adjfine);
169
170int ocelot_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
171		      enum ptp_pin_function func, unsigned int chan)
172{
173	switch (func) {
174	case PTP_PF_NONE:
175	case PTP_PF_PEROUT:
176		break;
177	case PTP_PF_EXTTS:
178	case PTP_PF_PHYSYNC:
179		return -1;
180	}
181	return 0;
182}
183EXPORT_SYMBOL(ocelot_ptp_verify);
184
185int ocelot_ptp_enable(struct ptp_clock_info *ptp,
186		      struct ptp_clock_request *rq, int on)
187{
188	struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
189	struct timespec64 ts_phase, ts_period;
190	enum ocelot_ptp_pins ptp_pin;
191	unsigned long flags;
192	bool pps = false;
193	int pin = -1;
194	s64 wf_high;
195	s64 wf_low;
196	u32 val;
197
198	switch (rq->type) {
199	case PTP_CLK_REQ_PEROUT:
200		/* Reject requests with unsupported flags */
201		if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE |
202					 PTP_PEROUT_PHASE))
203			return -EOPNOTSUPP;
204
205		pin = ptp_find_pin(ocelot->ptp_clock, PTP_PF_PEROUT,
206				   rq->perout.index);
207		if (pin == 0)
208			ptp_pin = PTP_PIN_0;
209		else if (pin == 1)
210			ptp_pin = PTP_PIN_1;
211		else if (pin == 2)
212			ptp_pin = PTP_PIN_2;
213		else if (pin == 3)
214			ptp_pin = PTP_PIN_3;
215		else
216			return -EBUSY;
217
218		ts_period.tv_sec = rq->perout.period.sec;
219		ts_period.tv_nsec = rq->perout.period.nsec;
220
221		if (ts_period.tv_sec == 1 && ts_period.tv_nsec == 0)
222			pps = true;
223
224		/* Handle turning off */
225		if (!on) {
226			spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
227			val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
228			ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
229			spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
230			break;
231		}
232
233		if (rq->perout.flags & PTP_PEROUT_PHASE) {
234			ts_phase.tv_sec = rq->perout.phase.sec;
235			ts_phase.tv_nsec = rq->perout.phase.nsec;
236		} else {
237			/* Compatibility */
238			ts_phase.tv_sec = rq->perout.start.sec;
239			ts_phase.tv_nsec = rq->perout.start.nsec;
240		}
241		if (ts_phase.tv_sec || (ts_phase.tv_nsec && !pps)) {
242			dev_warn(ocelot->dev,
243				 "Absolute start time not supported!\n");
244			dev_warn(ocelot->dev,
245				 "Accept nsec for PPS phase adjustment, otherwise start time should be 0 0.\n");
246			return -EINVAL;
247		}
248
249		/* Calculate waveform high and low times */
250		if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) {
251			struct timespec64 ts_on;
252
253			ts_on.tv_sec = rq->perout.on.sec;
254			ts_on.tv_nsec = rq->perout.on.nsec;
255
256			wf_high = timespec64_to_ns(&ts_on);
257		} else {
258			if (pps) {
259				wf_high = 1000;
260			} else {
261				wf_high = timespec64_to_ns(&ts_period);
262				wf_high = div_s64(wf_high, 2);
263			}
264		}
265
266		wf_low = timespec64_to_ns(&ts_period);
267		wf_low -= wf_high;
268
269		/* Handle PPS request */
270		if (pps) {
271			spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
272			ocelot_write_rix(ocelot, ts_phase.tv_nsec,
273					 PTP_PIN_WF_LOW_PERIOD, ptp_pin);
274			ocelot_write_rix(ocelot, wf_high,
275					 PTP_PIN_WF_HIGH_PERIOD, ptp_pin);
276			val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
277			val |= PTP_PIN_CFG_SYNC;
278			ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
279			spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
280			break;
281		}
282
283		/* Handle periodic clock */
284		if (wf_high > 0x3fffffff || wf_high <= 0x6)
285			return -EINVAL;
286		if (wf_low > 0x3fffffff || wf_low <= 0x6)
287			return -EINVAL;
288
289		spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
290		ocelot_write_rix(ocelot, wf_low, PTP_PIN_WF_LOW_PERIOD,
291				 ptp_pin);
292		ocelot_write_rix(ocelot, wf_high, PTP_PIN_WF_HIGH_PERIOD,
293				 ptp_pin);
294		val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
295		ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
296		spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
297		break;
298	default:
299		return -EOPNOTSUPP;
300	}
301	return 0;
302}
303EXPORT_SYMBOL(ocelot_ptp_enable);
304
305int ocelot_init_timestamp(struct ocelot *ocelot,
306			  const struct ptp_clock_info *info)
307{
308	struct ptp_clock *ptp_clock;
309	int i;
310
311	ocelot->ptp_info = *info;
312
313	for (i = 0; i < OCELOT_PTP_PINS_NUM; i++) {
314		struct ptp_pin_desc *p = &ocelot->ptp_pins[i];
315
316		snprintf(p->name, sizeof(p->name), "switch_1588_dat%d", i);
317		p->index = i;
318		p->func = PTP_PF_NONE;
319	}
320
321	ocelot->ptp_info.pin_config = &ocelot->ptp_pins[0];
322
323	ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
324	if (IS_ERR(ptp_clock))
325		return PTR_ERR(ptp_clock);
326	/* Check if PHC support is missing at the configuration level */
327	if (!ptp_clock)
328		return 0;
329
330	ocelot->ptp_clock = ptp_clock;
331
332	ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG);
333	ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW);
334	ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH);
335
336	ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC);
337
338	/* There is no device reconfiguration, PTP Rx stamping is always
339	 * enabled.
340	 */
341	ocelot->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
342
343	return 0;
344}
345EXPORT_SYMBOL(ocelot_init_timestamp);
346
347int ocelot_deinit_timestamp(struct ocelot *ocelot)
348{
349	if (ocelot->ptp_clock)
350		ptp_clock_unregister(ocelot->ptp_clock);
351	return 0;
352}
353EXPORT_SYMBOL(ocelot_deinit_timestamp);