.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Marvell 88E6xxx Switch PTP support |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Erik Hons <erik.hons@ni.com> |
---|
8 | 9 | * Brandon Streiff <brandon.streiff@ni.com> |
---|
9 | 10 | * Dane Wagner <dane.wagner@ni.com> |
---|
10 | | - * |
---|
11 | | - * This program is free software; you can redistribute it and/or modify |
---|
12 | | - * it under the terms of the GNU General Public License as published by |
---|
13 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
14 | | - * (at your option) any later version. |
---|
15 | 11 | */ |
---|
16 | 12 | |
---|
17 | 13 | #include "chip.h" |
---|
.. | .. |
---|
19 | 15 | #include "hwtstamp.h" |
---|
20 | 16 | #include "ptp.h" |
---|
21 | 17 | |
---|
22 | | -/* Raw timestamps are in units of 8-ns clock periods. */ |
---|
23 | | -#define CC_SHIFT 28 |
---|
24 | | -#define CC_MULT (8 << CC_SHIFT) |
---|
25 | | -#define CC_MULT_NUM (1 << 9) |
---|
26 | | -#define CC_MULT_DEM 15625ULL |
---|
| 18 | +#define MV88E6XXX_MAX_ADJ_PPB 1000000 |
---|
| 19 | + |
---|
| 20 | +/* Family MV88E6250: |
---|
| 21 | + * Raw timestamps are in units of 10-ns clock periods. |
---|
| 22 | + * |
---|
| 23 | + * clkadj = scaled_ppm * 10*2^28 / (10^6 * 2^16) |
---|
| 24 | + * simplifies to |
---|
| 25 | + * clkadj = scaled_ppm * 2^7 / 5^5 |
---|
| 26 | + */ |
---|
| 27 | +#define MV88E6250_CC_SHIFT 28 |
---|
| 28 | +#define MV88E6250_CC_MULT (10 << MV88E6250_CC_SHIFT) |
---|
| 29 | +#define MV88E6250_CC_MULT_NUM (1 << 7) |
---|
| 30 | +#define MV88E6250_CC_MULT_DEM 3125ULL |
---|
| 31 | + |
---|
| 32 | +/* Other families: |
---|
| 33 | + * Raw timestamps are in units of 8-ns clock periods. |
---|
| 34 | + * |
---|
| 35 | + * clkadj = scaled_ppm * 8*2^28 / (10^6 * 2^16) |
---|
| 36 | + * simplifies to |
---|
| 37 | + * clkadj = scaled_ppm * 2^9 / 5^6 |
---|
| 38 | + */ |
---|
| 39 | +#define MV88E6XXX_CC_SHIFT 28 |
---|
| 40 | +#define MV88E6XXX_CC_MULT (8 << MV88E6XXX_CC_SHIFT) |
---|
| 41 | +#define MV88E6XXX_CC_MULT_NUM (1 << 9) |
---|
| 42 | +#define MV88E6XXX_CC_MULT_DEM 15625ULL |
---|
27 | 43 | |
---|
28 | 44 | #define TAI_EVENT_WORK_INTERVAL msecs_to_jiffies(100) |
---|
29 | 45 | |
---|
.. | .. |
---|
142 | 158 | u32 raw_ts; |
---|
143 | 159 | int err; |
---|
144 | 160 | |
---|
145 | | - mutex_lock(&chip->reg_lock); |
---|
| 161 | + mv88e6xxx_reg_lock(chip); |
---|
146 | 162 | err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_EVENT_STATUS, |
---|
147 | 163 | status, ARRAY_SIZE(status)); |
---|
148 | | - mutex_unlock(&chip->reg_lock); |
---|
| 164 | + mv88e6xxx_reg_unlock(chip); |
---|
149 | 165 | |
---|
150 | 166 | if (err) { |
---|
151 | 167 | dev_err(chip->dev, "failed to read TAI status register\n"); |
---|
.. | .. |
---|
162 | 178 | |
---|
163 | 179 | /* Clear the valid bit so the next timestamp can come in */ |
---|
164 | 180 | status[0] &= ~MV88E6XXX_TAI_EVENT_STATUS_VALID; |
---|
165 | | - mutex_lock(&chip->reg_lock); |
---|
| 181 | + mv88e6xxx_reg_lock(chip); |
---|
166 | 182 | err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS, status[0]); |
---|
167 | | - mutex_unlock(&chip->reg_lock); |
---|
| 183 | + mv88e6xxx_reg_unlock(chip); |
---|
168 | 184 | |
---|
169 | 185 | /* This is an external timestamp */ |
---|
170 | 186 | ev.type = PTP_CLOCK_EXTTS; |
---|
171 | 187 | |
---|
172 | 188 | /* We only have one timestamping channel. */ |
---|
173 | 189 | ev.index = 0; |
---|
174 | | - mutex_lock(&chip->reg_lock); |
---|
| 190 | + mv88e6xxx_reg_lock(chip); |
---|
175 | 191 | ev.timestamp = timecounter_cyc2time(&chip->tstamp_tc, raw_ts); |
---|
176 | | - mutex_unlock(&chip->reg_lock); |
---|
| 192 | + mv88e6xxx_reg_unlock(chip); |
---|
177 | 193 | |
---|
178 | 194 | ptp_clock_event(chip->ptp_clock, &ev); |
---|
179 | 195 | out: |
---|
.. | .. |
---|
183 | 199 | static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) |
---|
184 | 200 | { |
---|
185 | 201 | struct mv88e6xxx_chip *chip = ptp_to_chip(ptp); |
---|
| 202 | + const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops; |
---|
186 | 203 | int neg_adj = 0; |
---|
187 | 204 | u32 diff, mult; |
---|
188 | 205 | u64 adj; |
---|
.. | .. |
---|
191 | 208 | neg_adj = 1; |
---|
192 | 209 | scaled_ppm = -scaled_ppm; |
---|
193 | 210 | } |
---|
194 | | - mult = CC_MULT; |
---|
195 | | - adj = CC_MULT_NUM; |
---|
196 | | - adj *= scaled_ppm; |
---|
197 | | - diff = div_u64(adj, CC_MULT_DEM); |
---|
198 | 211 | |
---|
199 | | - mutex_lock(&chip->reg_lock); |
---|
| 212 | + mult = ptp_ops->cc_mult; |
---|
| 213 | + adj = ptp_ops->cc_mult_num; |
---|
| 214 | + adj *= scaled_ppm; |
---|
| 215 | + diff = div_u64(adj, ptp_ops->cc_mult_dem); |
---|
| 216 | + |
---|
| 217 | + mv88e6xxx_reg_lock(chip); |
---|
200 | 218 | |
---|
201 | 219 | timecounter_read(&chip->tstamp_tc); |
---|
202 | 220 | chip->tstamp_cc.mult = neg_adj ? mult - diff : mult + diff; |
---|
203 | 221 | |
---|
204 | | - mutex_unlock(&chip->reg_lock); |
---|
| 222 | + mv88e6xxx_reg_unlock(chip); |
---|
205 | 223 | |
---|
206 | 224 | return 0; |
---|
207 | 225 | } |
---|
.. | .. |
---|
210 | 228 | { |
---|
211 | 229 | struct mv88e6xxx_chip *chip = ptp_to_chip(ptp); |
---|
212 | 230 | |
---|
213 | | - mutex_lock(&chip->reg_lock); |
---|
| 231 | + mv88e6xxx_reg_lock(chip); |
---|
214 | 232 | timecounter_adjtime(&chip->tstamp_tc, delta); |
---|
215 | | - mutex_unlock(&chip->reg_lock); |
---|
| 233 | + mv88e6xxx_reg_unlock(chip); |
---|
216 | 234 | |
---|
217 | 235 | return 0; |
---|
218 | 236 | } |
---|
.. | .. |
---|
223 | 241 | struct mv88e6xxx_chip *chip = ptp_to_chip(ptp); |
---|
224 | 242 | u64 ns; |
---|
225 | 243 | |
---|
226 | | - mutex_lock(&chip->reg_lock); |
---|
| 244 | + mv88e6xxx_reg_lock(chip); |
---|
227 | 245 | ns = timecounter_read(&chip->tstamp_tc); |
---|
228 | | - mutex_unlock(&chip->reg_lock); |
---|
| 246 | + mv88e6xxx_reg_unlock(chip); |
---|
229 | 247 | |
---|
230 | 248 | *ts = ns_to_timespec64(ns); |
---|
231 | 249 | |
---|
.. | .. |
---|
240 | 258 | |
---|
241 | 259 | ns = timespec64_to_ns(ts); |
---|
242 | 260 | |
---|
243 | | - mutex_lock(&chip->reg_lock); |
---|
| 261 | + mv88e6xxx_reg_lock(chip); |
---|
244 | 262 | timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ns); |
---|
245 | | - mutex_unlock(&chip->reg_lock); |
---|
| 263 | + mv88e6xxx_reg_unlock(chip); |
---|
246 | 264 | |
---|
247 | 265 | return 0; |
---|
248 | 266 | } |
---|
.. | .. |
---|
255 | 273 | int pin; |
---|
256 | 274 | int err; |
---|
257 | 275 | |
---|
| 276 | + /* Reject requests with unsupported flags */ |
---|
| 277 | + if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | |
---|
| 278 | + PTP_RISING_EDGE | |
---|
| 279 | + PTP_FALLING_EDGE | |
---|
| 280 | + PTP_STRICT_FLAGS)) |
---|
| 281 | + return -EOPNOTSUPP; |
---|
| 282 | + |
---|
| 283 | + /* Reject requests to enable time stamping on both edges. */ |
---|
| 284 | + if ((rq->extts.flags & PTP_STRICT_FLAGS) && |
---|
| 285 | + (rq->extts.flags & PTP_ENABLE_FEATURE) && |
---|
| 286 | + (rq->extts.flags & PTP_EXTTS_EDGES) == PTP_EXTTS_EDGES) |
---|
| 287 | + return -EOPNOTSUPP; |
---|
| 288 | + |
---|
258 | 289 | pin = ptp_find_pin(chip->ptp_clock, PTP_PF_EXTTS, rq->extts.index); |
---|
259 | 290 | |
---|
260 | 291 | if (pin < 0) |
---|
261 | 292 | return -EBUSY; |
---|
262 | 293 | |
---|
263 | | - mutex_lock(&chip->reg_lock); |
---|
| 294 | + mv88e6xxx_reg_lock(chip); |
---|
264 | 295 | |
---|
265 | 296 | if (on) { |
---|
266 | 297 | func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ; |
---|
.. | .. |
---|
282 | 313 | } |
---|
283 | 314 | |
---|
284 | 315 | out: |
---|
285 | | - mutex_unlock(&chip->reg_lock); |
---|
| 316 | + mv88e6xxx_reg_unlock(chip); |
---|
286 | 317 | |
---|
287 | 318 | return err; |
---|
288 | 319 | } |
---|
.. | .. |
---|
314 | 345 | return 0; |
---|
315 | 346 | } |
---|
316 | 347 | |
---|
| 348 | +const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = { |
---|
| 349 | + .clock_read = mv88e6165_ptp_clock_read, |
---|
| 350 | + .global_enable = mv88e6165_global_enable, |
---|
| 351 | + .global_disable = mv88e6165_global_disable, |
---|
| 352 | + .arr0_sts_reg = MV88E6165_PORT_PTP_ARR0_STS, |
---|
| 353 | + .arr1_sts_reg = MV88E6165_PORT_PTP_ARR1_STS, |
---|
| 354 | + .dep_sts_reg = MV88E6165_PORT_PTP_DEP_STS, |
---|
| 355 | + .rx_filters = (1 << HWTSTAMP_FILTER_NONE) | |
---|
| 356 | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | |
---|
| 357 | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | |
---|
| 358 | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | |
---|
| 359 | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | |
---|
| 360 | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | |
---|
| 361 | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), |
---|
| 362 | + .cc_shift = MV88E6XXX_CC_SHIFT, |
---|
| 363 | + .cc_mult = MV88E6XXX_CC_MULT, |
---|
| 364 | + .cc_mult_num = MV88E6XXX_CC_MULT_NUM, |
---|
| 365 | + .cc_mult_dem = MV88E6XXX_CC_MULT_DEM, |
---|
| 366 | +}; |
---|
| 367 | + |
---|
| 368 | +const struct mv88e6xxx_ptp_ops mv88e6250_ptp_ops = { |
---|
| 369 | + .clock_read = mv88e6352_ptp_clock_read, |
---|
| 370 | + .ptp_enable = mv88e6352_ptp_enable, |
---|
| 371 | + .ptp_verify = mv88e6352_ptp_verify, |
---|
| 372 | + .event_work = mv88e6352_tai_event_work, |
---|
| 373 | + .port_enable = mv88e6352_hwtstamp_port_enable, |
---|
| 374 | + .port_disable = mv88e6352_hwtstamp_port_disable, |
---|
| 375 | + .n_ext_ts = 1, |
---|
| 376 | + .arr0_sts_reg = MV88E6XXX_PORT_PTP_ARR0_STS, |
---|
| 377 | + .arr1_sts_reg = MV88E6XXX_PORT_PTP_ARR1_STS, |
---|
| 378 | + .dep_sts_reg = MV88E6XXX_PORT_PTP_DEP_STS, |
---|
| 379 | + .rx_filters = (1 << HWTSTAMP_FILTER_NONE) | |
---|
| 380 | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | |
---|
| 381 | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | |
---|
| 382 | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | |
---|
| 383 | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | |
---|
| 384 | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | |
---|
| 385 | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | |
---|
| 386 | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | |
---|
| 387 | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | |
---|
| 388 | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), |
---|
| 389 | + .cc_shift = MV88E6250_CC_SHIFT, |
---|
| 390 | + .cc_mult = MV88E6250_CC_MULT, |
---|
| 391 | + .cc_mult_num = MV88E6250_CC_MULT_NUM, |
---|
| 392 | + .cc_mult_dem = MV88E6250_CC_MULT_DEM, |
---|
| 393 | +}; |
---|
| 394 | + |
---|
317 | 395 | const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = { |
---|
318 | 396 | .clock_read = mv88e6352_ptp_clock_read, |
---|
319 | 397 | .ptp_enable = mv88e6352_ptp_enable, |
---|
.. | .. |
---|
335 | 413 | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | |
---|
336 | 414 | (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | |
---|
337 | 415 | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), |
---|
338 | | -}; |
---|
339 | | - |
---|
340 | | -const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = { |
---|
341 | | - .clock_read = mv88e6165_ptp_clock_read, |
---|
342 | | - .global_enable = mv88e6165_global_enable, |
---|
343 | | - .global_disable = mv88e6165_global_disable, |
---|
344 | | - .arr0_sts_reg = MV88E6165_PORT_PTP_ARR0_STS, |
---|
345 | | - .arr1_sts_reg = MV88E6165_PORT_PTP_ARR1_STS, |
---|
346 | | - .dep_sts_reg = MV88E6165_PORT_PTP_DEP_STS, |
---|
347 | | - .rx_filters = (1 << HWTSTAMP_FILTER_NONE) | |
---|
348 | | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | |
---|
349 | | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | |
---|
350 | | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | |
---|
351 | | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | |
---|
352 | | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | |
---|
353 | | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), |
---|
| 416 | + .cc_shift = MV88E6XXX_CC_SHIFT, |
---|
| 417 | + .cc_mult = MV88E6XXX_CC_MULT, |
---|
| 418 | + .cc_mult_num = MV88E6XXX_CC_MULT_NUM, |
---|
| 419 | + .cc_mult_dem = MV88E6XXX_CC_MULT_DEM, |
---|
354 | 420 | }; |
---|
355 | 421 | |
---|
356 | 422 | static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc) |
---|
.. | .. |
---|
388 | 454 | memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc)); |
---|
389 | 455 | chip->tstamp_cc.read = mv88e6xxx_ptp_clock_read; |
---|
390 | 456 | chip->tstamp_cc.mask = CYCLECOUNTER_MASK(32); |
---|
391 | | - chip->tstamp_cc.mult = CC_MULT; |
---|
392 | | - chip->tstamp_cc.shift = CC_SHIFT; |
---|
| 457 | + chip->tstamp_cc.mult = ptp_ops->cc_mult; |
---|
| 458 | + chip->tstamp_cc.shift = ptp_ops->cc_shift; |
---|
393 | 459 | |
---|
394 | 460 | timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, |
---|
395 | 461 | ktime_to_ns(ktime_get_real())); |
---|
.. | .. |
---|
400 | 466 | |
---|
401 | 467 | chip->ptp_clock_info.owner = THIS_MODULE; |
---|
402 | 468 | snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name), |
---|
403 | | - dev_name(chip->dev)); |
---|
404 | | - chip->ptp_clock_info.max_adj = 1000000; |
---|
| 469 | + "%s", dev_name(chip->dev)); |
---|
405 | 470 | |
---|
406 | 471 | chip->ptp_clock_info.n_ext_ts = ptp_ops->n_ext_ts; |
---|
407 | 472 | chip->ptp_clock_info.n_per_out = 0; |
---|
.. | .. |
---|
417 | 482 | } |
---|
418 | 483 | chip->ptp_clock_info.pin_config = chip->pin_config; |
---|
419 | 484 | |
---|
| 485 | + chip->ptp_clock_info.max_adj = MV88E6XXX_MAX_ADJ_PPB; |
---|
420 | 486 | chip->ptp_clock_info.adjfine = mv88e6xxx_ptp_adjfine; |
---|
421 | 487 | chip->ptp_clock_info.adjtime = mv88e6xxx_ptp_adjtime; |
---|
422 | 488 | chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime; |
---|