1 // SPDX-License-Identifier: GPL-2.0-only 2 /******************************************************************************* 3 PTP 1588 clock using the STMMAC. 4 5 Copyright (C) 2013 Vayavya Labs Pvt Ltd 6 7 8 Author: Rayagond Kokatanur <rayagond@vayavyalabs.com> 9 *******************************************************************************/ 10 #include "stmmac.h" 11 #include "stmmac_ptp.h" 12 13 /** 14 * stmmac_adjust_freq 15 * 16 * @ptp: pointer to ptp_clock_info structure 17 * @scaled_ppm: desired period change in scaled parts per million 18 * 19 * Description: this function will adjust the frequency of hardware clock. 20 * 21 * Scaled parts per million is ppm with a 16-bit binary fractional field. 22 */ 23 static int stmmac_adjust_freq(struct ptp_clock_info *ptp, long scaled_ppm) 24 { 25 struct stmmac_priv *priv = 26 container_of(ptp, struct stmmac_priv, ptp_clock_ops); 27 unsigned long flags; 28 u32 addend; 29 30 addend = adjust_by_scaled_ppm(priv->default_addend, scaled_ppm); 31 32 write_lock_irqsave(&priv->ptp_lock, flags); 33 stmmac_config_addend(priv, priv->ptpaddr, addend); 34 write_unlock_irqrestore(&priv->ptp_lock, flags); 35 36 return 0; 37 } 38 39 /** 40 * stmmac_adjust_time 41 * 42 * @ptp: pointer to ptp_clock_info structure 43 * @delta: desired change in nanoseconds 44 * 45 * Description: this function will shift/adjust the hardware clock time. 46 */ 47 static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) 48 { 49 struct stmmac_priv *priv = 50 container_of(ptp, struct stmmac_priv, ptp_clock_ops); 51 unsigned long flags; 52 u32 sec, nsec; 53 u32 quotient, reminder; 54 int neg_adj = 0; 55 bool xmac, est_rst = false; 56 int ret; 57 58 xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; 59 60 if (delta < 0) { 61 neg_adj = 1; 62 delta = -delta; 63 } 64 65 quotient = div_u64_rem(delta, 1000000000ULL, &reminder); 66 sec = quotient; 67 nsec = reminder; 68 69 /* If EST is enabled, disabled it before adjust ptp time. */ 70 if (priv->est && priv->est->enable) { 71 est_rst = true; 72 mutex_lock(&priv->est_lock); 73 priv->est->enable = false; 74 stmmac_est_configure(priv, priv, priv->est, 75 priv->plat->clk_ptp_rate); 76 mutex_unlock(&priv->est_lock); 77 } 78 79 write_lock_irqsave(&priv->ptp_lock, flags); 80 stmmac_adjust_systime(priv, priv->ptpaddr, sec, nsec, neg_adj, xmac); 81 write_unlock_irqrestore(&priv->ptp_lock, flags); 82 83 /* Calculate new basetime and re-configured EST after PTP time adjust. */ 84 if (est_rst) { 85 struct timespec64 current_time, time; 86 ktime_t current_time_ns, basetime; 87 u64 cycle_time; 88 89 mutex_lock(&priv->est_lock); 90 priv->ptp_clock_ops.gettime64(&priv->ptp_clock_ops, ¤t_time); 91 current_time_ns = timespec64_to_ktime(current_time); 92 time.tv_nsec = priv->est->btr_reserve[0]; 93 time.tv_sec = priv->est->btr_reserve[1]; 94 basetime = timespec64_to_ktime(time); 95 cycle_time = (u64)priv->est->ctr[1] * NSEC_PER_SEC + 96 priv->est->ctr[0]; 97 time = stmmac_calc_tas_basetime(basetime, 98 current_time_ns, 99 cycle_time); 100 101 priv->est->btr[0] = (u32)time.tv_nsec; 102 priv->est->btr[1] = (u32)time.tv_sec; 103 priv->est->enable = true; 104 ret = stmmac_est_configure(priv, priv, priv->est, 105 priv->plat->clk_ptp_rate); 106 mutex_unlock(&priv->est_lock); 107 if (ret) 108 netdev_err(priv->dev, "failed to configure EST\n"); 109 } 110 111 return 0; 112 } 113 114 /** 115 * stmmac_get_time 116 * 117 * @ptp: pointer to ptp_clock_info structure 118 * @ts: pointer to hold time/result 119 * 120 * Description: this function will read the current time from the 121 * hardware clock and store it in @ts. 122 */ 123 static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts) 124 { 125 struct stmmac_priv *priv = 126 container_of(ptp, struct stmmac_priv, ptp_clock_ops); 127 unsigned long flags; 128 u64 ns = 0; 129 130 read_lock_irqsave(&priv->ptp_lock, flags); 131 stmmac_get_systime(priv, priv->ptpaddr, &ns); 132 read_unlock_irqrestore(&priv->ptp_lock, flags); 133 134 *ts = ns_to_timespec64(ns); 135 136 return 0; 137 } 138 139 /** 140 * stmmac_set_time 141 * 142 * @ptp: pointer to ptp_clock_info structure 143 * @ts: time value to set 144 * 145 * Description: this function will set the current time on the 146 * hardware clock. 147 */ 148 static int stmmac_set_time(struct ptp_clock_info *ptp, 149 const struct timespec64 *ts) 150 { 151 struct stmmac_priv *priv = 152 container_of(ptp, struct stmmac_priv, ptp_clock_ops); 153 unsigned long flags; 154 155 write_lock_irqsave(&priv->ptp_lock, flags); 156 stmmac_init_systime(priv, priv->ptpaddr, ts->tv_sec, ts->tv_nsec); 157 write_unlock_irqrestore(&priv->ptp_lock, flags); 158 159 return 0; 160 } 161 162 static int stmmac_enable(struct ptp_clock_info *ptp, 163 struct ptp_clock_request *rq, int on) 164 { 165 struct stmmac_priv *priv = 166 container_of(ptp, struct stmmac_priv, ptp_clock_ops); 167 void __iomem *ptpaddr = priv->ptpaddr; 168 struct stmmac_pps_cfg *cfg; 169 int ret = -EOPNOTSUPP; 170 unsigned long flags; 171 u32 acr_value; 172 173 switch (rq->type) { 174 case PTP_CLK_REQ_PEROUT: 175 /* Reject requests with unsupported flags */ 176 if (rq->perout.flags) 177 return -EOPNOTSUPP; 178 179 cfg = &priv->pps[rq->perout.index]; 180 181 cfg->start.tv_sec = rq->perout.start.sec; 182 cfg->start.tv_nsec = rq->perout.start.nsec; 183 cfg->period.tv_sec = rq->perout.period.sec; 184 cfg->period.tv_nsec = rq->perout.period.nsec; 185 186 write_lock_irqsave(&priv->ptp_lock, flags); 187 ret = stmmac_flex_pps_config(priv, priv->ioaddr, 188 rq->perout.index, cfg, on, 189 priv->sub_second_inc, 190 priv->systime_flags); 191 write_unlock_irqrestore(&priv->ptp_lock, flags); 192 break; 193 case PTP_CLK_REQ_EXTTS: { 194 u8 channel; 195 196 mutex_lock(&priv->aux_ts_lock); 197 acr_value = readl(ptpaddr + PTP_ACR); 198 channel = ilog2(FIELD_GET(PTP_ACR_MASK, acr_value)); 199 acr_value &= ~PTP_ACR_MASK; 200 201 if (on) { 202 if (FIELD_GET(PTP_ACR_MASK, acr_value)) { 203 netdev_err(priv->dev, 204 "Cannot enable auxiliary snapshot %d as auxiliary snapshot %d is already enabled", 205 rq->extts.index, channel); 206 mutex_unlock(&priv->aux_ts_lock); 207 return -EBUSY; 208 } 209 210 priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN; 211 212 /* Enable External snapshot trigger */ 213 acr_value |= PTP_ACR_ATSEN(rq->extts.index); 214 acr_value |= PTP_ACR_ATSFC; 215 } else { 216 priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN; 217 } 218 netdev_dbg(priv->dev, "Auxiliary Snapshot %d %s.\n", 219 rq->extts.index, on ? "enabled" : "disabled"); 220 writel(acr_value, ptpaddr + PTP_ACR); 221 mutex_unlock(&priv->aux_ts_lock); 222 /* wait for auxts fifo clear to finish */ 223 ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value, 224 !(acr_value & PTP_ACR_ATSFC), 225 10, 10000); 226 break; 227 } 228 229 default: 230 break; 231 } 232 233 return ret; 234 } 235 236 /** 237 * stmmac_get_syncdevicetime 238 * @device: current device time 239 * @system: system counter value read synchronously with device time 240 * @ctx: context provided by timekeeping code 241 * Description: Read device and system clock simultaneously and return the 242 * corrected clock values in ns. 243 **/ 244 static int stmmac_get_syncdevicetime(ktime_t *device, 245 struct system_counterval_t *system, 246 void *ctx) 247 { 248 struct stmmac_priv *priv = (struct stmmac_priv *)ctx; 249 250 if (priv->plat->crosststamp) 251 return priv->plat->crosststamp(device, system, ctx); 252 else 253 return -EOPNOTSUPP; 254 } 255 256 static int stmmac_getcrosststamp(struct ptp_clock_info *ptp, 257 struct system_device_crosststamp *xtstamp) 258 { 259 struct stmmac_priv *priv = 260 container_of(ptp, struct stmmac_priv, ptp_clock_ops); 261 262 return get_device_system_crosststamp(stmmac_get_syncdevicetime, 263 priv, NULL, xtstamp); 264 } 265 266 /* structure describing a PTP hardware clock */ 267 const struct ptp_clock_info stmmac_ptp_clock_ops = { 268 .owner = THIS_MODULE, 269 .name = "stmmac ptp", 270 .max_adj = 62500000, 271 .n_alarm = 0, 272 .n_ext_ts = 0, /* will be overwritten in stmmac_ptp_register */ 273 .n_per_out = 0, /* will be overwritten in stmmac_ptp_register */ 274 .n_pins = 0, 275 .pps = 0, 276 .adjfine = stmmac_adjust_freq, 277 .adjtime = stmmac_adjust_time, 278 .gettime64 = stmmac_get_time, 279 .settime64 = stmmac_set_time, 280 .enable = stmmac_enable, 281 .getcrosststamp = stmmac_getcrosststamp, 282 }; 283 284 /* structure describing a PTP hardware clock */ 285 const struct ptp_clock_info dwmac1000_ptp_clock_ops = { 286 .owner = THIS_MODULE, 287 .name = "stmmac ptp", 288 .max_adj = 62500000, 289 .n_alarm = 0, 290 .n_ext_ts = 1, 291 .n_per_out = 0, 292 .n_pins = 0, 293 .pps = 0, 294 .adjfine = stmmac_adjust_freq, 295 .adjtime = stmmac_adjust_time, 296 .gettime64 = stmmac_get_time, 297 .settime64 = stmmac_set_time, 298 .enable = dwmac1000_ptp_enable, 299 .getcrosststamp = stmmac_getcrosststamp, 300 }; 301 302 /** 303 * stmmac_ptp_register 304 * @priv: driver private structure 305 * Description: this function will register the ptp clock driver 306 * to kernel. It also does some house keeping work. 307 */ 308 void stmmac_ptp_register(struct stmmac_priv *priv) 309 { 310 int i; 311 312 for (i = 0; i < priv->dma_cap.pps_out_num; i++) { 313 if (i >= STMMAC_PPS_MAX) 314 break; 315 priv->pps[i].available = true; 316 } 317 318 /* Calculate the clock domain crossing (CDC) error if necessary */ 319 priv->plat->cdc_error_adj = 0; 320 if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) 321 priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate; 322 323 /* Update the ptp clock parameters based on feature discovery, when 324 * available 325 */ 326 if (priv->dma_cap.pps_out_num) 327 priv->ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num; 328 329 if (priv->dma_cap.aux_snapshot_n) 330 priv->ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n; 331 332 if (priv->plat->ptp_max_adj) 333 priv->ptp_clock_ops.max_adj = priv->plat->ptp_max_adj; 334 335 rwlock_init(&priv->ptp_lock); 336 mutex_init(&priv->aux_ts_lock); 337 338 priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops, 339 priv->device); 340 if (IS_ERR(priv->ptp_clock)) { 341 netdev_err(priv->dev, "ptp_clock_register failed\n"); 342 priv->ptp_clock = NULL; 343 } else if (priv->ptp_clock) 344 netdev_info(priv->dev, "registered PTP clock\n"); 345 } 346 347 /** 348 * stmmac_ptp_unregister 349 * @priv: driver private structure 350 * Description: this function will remove/unregister the ptp clock driver 351 * from the kernel. 352 */ 353 void stmmac_ptp_unregister(struct stmmac_priv *priv) 354 { 355 if (priv->ptp_clock) { 356 ptp_clock_unregister(priv->ptp_clock); 357 priv->ptp_clock = NULL; 358 pr_debug("Removed PTP HW clock successfully on %s\n", 359 priv->dev->name); 360 } 361 362 mutex_destroy(&priv->aux_ts_lock); 363 } 364