162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* PTP 1588 clock using the Renesas Ethernet AVB 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2013-2015 Renesas Electronics Corporation 562306a36Sopenharmony_ci * Copyright (C) 2015 Renesas Solutions Corp. 662306a36Sopenharmony_ci * Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "ravb.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic int ravb_ptp_tcr_request(struct ravb_private *priv, u32 request) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci struct net_device *ndev = priv->ndev; 1462306a36Sopenharmony_ci int error; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci error = ravb_wait(ndev, GCCR, GCCR_TCR, GCCR_TCR_NOREQ); 1762306a36Sopenharmony_ci if (error) 1862306a36Sopenharmony_ci return error; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci ravb_modify(ndev, GCCR, request, request); 2162306a36Sopenharmony_ci return ravb_wait(ndev, GCCR, GCCR_TCR, GCCR_TCR_NOREQ); 2262306a36Sopenharmony_ci} 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* Caller must hold the lock */ 2562306a36Sopenharmony_cistatic int ravb_ptp_time_read(struct ravb_private *priv, struct timespec64 *ts) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct net_device *ndev = priv->ndev; 2862306a36Sopenharmony_ci int error; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci error = ravb_ptp_tcr_request(priv, GCCR_TCR_CAPTURE); 3162306a36Sopenharmony_ci if (error) 3262306a36Sopenharmony_ci return error; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci ts->tv_nsec = ravb_read(ndev, GCT0); 3562306a36Sopenharmony_ci ts->tv_sec = ravb_read(ndev, GCT1) | 3662306a36Sopenharmony_ci ((s64)ravb_read(ndev, GCT2) << 32); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return 0; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Caller must hold the lock */ 4262306a36Sopenharmony_cistatic int ravb_ptp_time_write(struct ravb_private *priv, 4362306a36Sopenharmony_ci const struct timespec64 *ts) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct net_device *ndev = priv->ndev; 4662306a36Sopenharmony_ci int error; 4762306a36Sopenharmony_ci u32 gccr; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci error = ravb_ptp_tcr_request(priv, GCCR_TCR_RESET); 5062306a36Sopenharmony_ci if (error) 5162306a36Sopenharmony_ci return error; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci gccr = ravb_read(ndev, GCCR); 5462306a36Sopenharmony_ci if (gccr & GCCR_LTO) 5562306a36Sopenharmony_ci return -EBUSY; 5662306a36Sopenharmony_ci ravb_write(ndev, ts->tv_nsec, GTO0); 5762306a36Sopenharmony_ci ravb_write(ndev, ts->tv_sec, GTO1); 5862306a36Sopenharmony_ci ravb_write(ndev, (ts->tv_sec >> 32) & 0xffff, GTO2); 5962306a36Sopenharmony_ci ravb_write(ndev, gccr | GCCR_LTO, GCCR); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Caller must hold the lock */ 6562306a36Sopenharmony_cistatic int ravb_ptp_update_compare(struct ravb_private *priv, u32 ns) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct net_device *ndev = priv->ndev; 6862306a36Sopenharmony_ci /* When the comparison value (GPTC.PTCV) is in range of 6962306a36Sopenharmony_ci * [x-1 to x+1] (x is the configured increment value in 7062306a36Sopenharmony_ci * GTI.TIV), it may happen that a comparison match is 7162306a36Sopenharmony_ci * not detected when the timer wraps around. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci u32 gti_ns_plus_1 = (priv->ptp.current_addend >> 20) + 1; 7462306a36Sopenharmony_ci u32 gccr; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (ns < gti_ns_plus_1) 7762306a36Sopenharmony_ci ns = gti_ns_plus_1; 7862306a36Sopenharmony_ci else if (ns > 0 - gti_ns_plus_1) 7962306a36Sopenharmony_ci ns = 0 - gti_ns_plus_1; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci gccr = ravb_read(ndev, GCCR); 8262306a36Sopenharmony_ci if (gccr & GCCR_LPTC) 8362306a36Sopenharmony_ci return -EBUSY; 8462306a36Sopenharmony_ci ravb_write(ndev, ns, GPTC); 8562306a36Sopenharmony_ci ravb_write(ndev, gccr | GCCR_LPTC, GCCR); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* PTP clock operations */ 9162306a36Sopenharmony_cistatic int ravb_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct ravb_private *priv = container_of(ptp, struct ravb_private, 9462306a36Sopenharmony_ci ptp.info); 9562306a36Sopenharmony_ci struct net_device *ndev = priv->ndev; 9662306a36Sopenharmony_ci unsigned long flags; 9762306a36Sopenharmony_ci u32 addend; 9862306a36Sopenharmony_ci u32 gccr; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci addend = (u32)adjust_by_scaled_ppm(priv->ptp.default_addend, 10162306a36Sopenharmony_ci scaled_ppm); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci priv->ptp.current_addend = addend; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci gccr = ravb_read(ndev, GCCR); 10862306a36Sopenharmony_ci if (gccr & GCCR_LTI) { 10962306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 11062306a36Sopenharmony_ci return -EBUSY; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci ravb_write(ndev, addend & GTI_TIV, GTI); 11362306a36Sopenharmony_ci ravb_write(ndev, gccr | GCCR_LTI, GCCR); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int ravb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct ravb_private *priv = container_of(ptp, struct ravb_private, 12362306a36Sopenharmony_ci ptp.info); 12462306a36Sopenharmony_ci struct timespec64 ts; 12562306a36Sopenharmony_ci unsigned long flags; 12662306a36Sopenharmony_ci int error; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 12962306a36Sopenharmony_ci error = ravb_ptp_time_read(priv, &ts); 13062306a36Sopenharmony_ci if (!error) { 13162306a36Sopenharmony_ci u64 now = ktime_to_ns(timespec64_to_ktime(ts)); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ts = ns_to_timespec64(now + delta); 13462306a36Sopenharmony_ci error = ravb_ptp_time_write(priv, &ts); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return error; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int ravb_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct ravb_private *priv = container_of(ptp, struct ravb_private, 14462306a36Sopenharmony_ci ptp.info); 14562306a36Sopenharmony_ci unsigned long flags; 14662306a36Sopenharmony_ci int error; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 14962306a36Sopenharmony_ci error = ravb_ptp_time_read(priv, ts); 15062306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return error; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int ravb_ptp_settime64(struct ptp_clock_info *ptp, 15662306a36Sopenharmony_ci const struct timespec64 *ts) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct ravb_private *priv = container_of(ptp, struct ravb_private, 15962306a36Sopenharmony_ci ptp.info); 16062306a36Sopenharmony_ci unsigned long flags; 16162306a36Sopenharmony_ci int error; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 16462306a36Sopenharmony_ci error = ravb_ptp_time_write(priv, ts); 16562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return error; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int ravb_ptp_extts(struct ptp_clock_info *ptp, 17162306a36Sopenharmony_ci struct ptp_extts_request *req, int on) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct ravb_private *priv = container_of(ptp, struct ravb_private, 17462306a36Sopenharmony_ci ptp.info); 17562306a36Sopenharmony_ci const struct ravb_hw_info *info = priv->info; 17662306a36Sopenharmony_ci struct net_device *ndev = priv->ndev; 17762306a36Sopenharmony_ci unsigned long flags; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 18062306a36Sopenharmony_ci if (req->flags & ~(PTP_ENABLE_FEATURE | 18162306a36Sopenharmony_ci PTP_RISING_EDGE | 18262306a36Sopenharmony_ci PTP_FALLING_EDGE | 18362306a36Sopenharmony_ci PTP_STRICT_FLAGS)) 18462306a36Sopenharmony_ci return -EOPNOTSUPP; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (req->index) 18762306a36Sopenharmony_ci return -EINVAL; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (priv->ptp.extts[req->index] == on) 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci priv->ptp.extts[req->index] = on; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 19462306a36Sopenharmony_ci if (!info->irq_en_dis) 19562306a36Sopenharmony_ci ravb_modify(ndev, GIC, GIC_PTCE, on ? GIC_PTCE : 0); 19662306a36Sopenharmony_ci else if (on) 19762306a36Sopenharmony_ci ravb_write(ndev, GIE_PTCS, GIE); 19862306a36Sopenharmony_ci else 19962306a36Sopenharmony_ci ravb_write(ndev, GID_PTCD, GID); 20062306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int ravb_ptp_perout(struct ptp_clock_info *ptp, 20662306a36Sopenharmony_ci struct ptp_perout_request *req, int on) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct ravb_private *priv = container_of(ptp, struct ravb_private, 20962306a36Sopenharmony_ci ptp.info); 21062306a36Sopenharmony_ci const struct ravb_hw_info *info = priv->info; 21162306a36Sopenharmony_ci struct net_device *ndev = priv->ndev; 21262306a36Sopenharmony_ci struct ravb_ptp_perout *perout; 21362306a36Sopenharmony_ci unsigned long flags; 21462306a36Sopenharmony_ci int error = 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 21762306a36Sopenharmony_ci if (req->flags) 21862306a36Sopenharmony_ci return -EOPNOTSUPP; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (req->index) 22162306a36Sopenharmony_ci return -EINVAL; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (on) { 22462306a36Sopenharmony_ci u64 start_ns; 22562306a36Sopenharmony_ci u64 period_ns; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci start_ns = req->start.sec * NSEC_PER_SEC + req->start.nsec; 22862306a36Sopenharmony_ci period_ns = req->period.sec * NSEC_PER_SEC + req->period.nsec; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (start_ns > U32_MAX) { 23162306a36Sopenharmony_ci netdev_warn(ndev, 23262306a36Sopenharmony_ci "ptp: start value (nsec) is over limit. Maximum size of start is only 32 bits\n"); 23362306a36Sopenharmony_ci return -ERANGE; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (period_ns > U32_MAX) { 23762306a36Sopenharmony_ci netdev_warn(ndev, 23862306a36Sopenharmony_ci "ptp: period value (nsec) is over limit. Maximum size of period is only 32 bits\n"); 23962306a36Sopenharmony_ci return -ERANGE; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci perout = &priv->ptp.perout[req->index]; 24562306a36Sopenharmony_ci perout->target = (u32)start_ns; 24662306a36Sopenharmony_ci perout->period = (u32)period_ns; 24762306a36Sopenharmony_ci error = ravb_ptp_update_compare(priv, (u32)start_ns); 24862306a36Sopenharmony_ci if (!error) { 24962306a36Sopenharmony_ci /* Unmask interrupt */ 25062306a36Sopenharmony_ci if (!info->irq_en_dis) 25162306a36Sopenharmony_ci ravb_modify(ndev, GIC, GIC_PTME, GIC_PTME); 25262306a36Sopenharmony_ci else 25362306a36Sopenharmony_ci ravb_write(ndev, GIE_PTMS0, GIE); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci } else { 25662306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci perout = &priv->ptp.perout[req->index]; 25962306a36Sopenharmony_ci perout->period = 0; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Mask interrupt */ 26262306a36Sopenharmony_ci if (!info->irq_en_dis) 26362306a36Sopenharmony_ci ravb_modify(ndev, GIC, GIC_PTME, 0); 26462306a36Sopenharmony_ci else 26562306a36Sopenharmony_ci ravb_write(ndev, GID_PTMD0, GID); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return error; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int ravb_ptp_enable(struct ptp_clock_info *ptp, 27362306a36Sopenharmony_ci struct ptp_clock_request *req, int on) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci switch (req->type) { 27662306a36Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 27762306a36Sopenharmony_ci return ravb_ptp_extts(ptp, &req->extts, on); 27862306a36Sopenharmony_ci case PTP_CLK_REQ_PEROUT: 27962306a36Sopenharmony_ci return ravb_ptp_perout(ptp, &req->perout, on); 28062306a36Sopenharmony_ci default: 28162306a36Sopenharmony_ci return -EOPNOTSUPP; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic const struct ptp_clock_info ravb_ptp_info = { 28662306a36Sopenharmony_ci .owner = THIS_MODULE, 28762306a36Sopenharmony_ci .name = "ravb clock", 28862306a36Sopenharmony_ci .max_adj = 50000000, 28962306a36Sopenharmony_ci .n_ext_ts = N_EXT_TS, 29062306a36Sopenharmony_ci .n_per_out = N_PER_OUT, 29162306a36Sopenharmony_ci .adjfine = ravb_ptp_adjfine, 29262306a36Sopenharmony_ci .adjtime = ravb_ptp_adjtime, 29362306a36Sopenharmony_ci .gettime64 = ravb_ptp_gettime64, 29462306a36Sopenharmony_ci .settime64 = ravb_ptp_settime64, 29562306a36Sopenharmony_ci .enable = ravb_ptp_enable, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/* Caller must hold the lock */ 29962306a36Sopenharmony_civoid ravb_ptp_interrupt(struct net_device *ndev) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct ravb_private *priv = netdev_priv(ndev); 30262306a36Sopenharmony_ci u32 gis = ravb_read(ndev, GIS); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci gis &= ravb_read(ndev, GIC); 30562306a36Sopenharmony_ci if (gis & GIS_PTCF) { 30662306a36Sopenharmony_ci struct ptp_clock_event event; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci event.type = PTP_CLOCK_EXTTS; 30962306a36Sopenharmony_ci event.index = 0; 31062306a36Sopenharmony_ci event.timestamp = ravb_read(ndev, GCPT); 31162306a36Sopenharmony_ci ptp_clock_event(priv->ptp.clock, &event); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci if (gis & GIS_PTMF) { 31462306a36Sopenharmony_ci struct ravb_ptp_perout *perout = priv->ptp.perout; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (perout->period) { 31762306a36Sopenharmony_ci perout->target += perout->period; 31862306a36Sopenharmony_ci ravb_ptp_update_compare(priv, perout->target); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci ravb_write(ndev, ~(gis | GIS_RESERVED), GIS); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_civoid ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct ravb_private *priv = netdev_priv(ndev); 32862306a36Sopenharmony_ci unsigned long flags; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci priv->ptp.info = ravb_ptp_info; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci priv->ptp.default_addend = ravb_read(ndev, GTI); 33362306a36Sopenharmony_ci priv->ptp.current_addend = priv->ptp.default_addend; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 33662306a36Sopenharmony_ci ravb_wait(ndev, GCCR, GCCR_TCR, GCCR_TCR_NOREQ); 33762306a36Sopenharmony_ci ravb_modify(ndev, GCCR, GCCR_TCSS, GCCR_TCSS_ADJGPTP); 33862306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci priv->ptp.clock = ptp_clock_register(&priv->ptp.info, &pdev->dev); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_civoid ravb_ptp_stop(struct net_device *ndev) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct ravb_private *priv = netdev_priv(ndev); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci ravb_write(ndev, 0, GIC); 34862306a36Sopenharmony_ci ravb_write(ndev, 0, GIS); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci ptp_clock_unregister(priv->ptp.clock); 35162306a36Sopenharmony_ci} 352