ocelot_ptp.c (9640B)
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);