FILE
rcar_gen4_ptp.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/renesas/rcar_gen4_ptp.c
1// SPDX-License-Identifier: GPL-2.0 2/* Renesas R-Car Gen4 gPTP device driver 3 * 4 * Copyright (C) 2022 Renesas Electronics Corporation 5 */ 6 7#include <linux/err.h> 8#include <linux/etherdevice.h> 9#include <linux/kernel.h> 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <linux/slab.h> 13 14#include "rcar_gen4_ptp.h" 15 16#define PTPTMEC_REG 0x0010 17#define PTPTMDC_REG 0x0014 18#define PTPTIVC0_REG 0x0020 19#define PTPTOVC00_REG 0x0030 20#define PTPTOVC10_REG 0x0034 21#define PTPTOVC20_REG 0x0038 22#define PTPGPTPTM00_REG 0x0050 23#define PTPGPTPTM10_REG 0x0054 24#define PTPGPTPTM20_REG 0x0058 25 26#define ptp_to_priv(ptp) container_of(ptp, struct rcar_gen4_ptp_private, info) 27 28static int rcar_gen4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) 29{ 30 struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp); 31 s64 addend = ptp_priv->default_addend; 32 bool neg_adj = scaled_ppm < 0; 33 s64 diff; 34 35 if (neg_adj) 36 scaled_ppm = -scaled_ppm; 37 diff = div_s64(addend * scaled_ppm_to_ppb(scaled_ppm), NSEC_PER_SEC); 38 addend = neg_adj ? addend - diff : addend + diff; 39 40 iowrite32(addend, ptp_priv->addr + PTPTIVC0_REG); 41 42 return 0; 43} 44 45static void _rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp, 46 struct timespec64 *ts) 47{ 48 struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp); 49 50 lockdep_assert_held(&ptp_priv->lock); 51 52 ts->tv_nsec = ioread32(ptp_priv->addr + PTPGPTPTM00_REG); 53 ts->tv_sec = ioread32(ptp_priv->addr + PTPGPTPTM10_REG) | 54 ((s64)ioread32(ptp_priv->addr + PTPGPTPTM20_REG) << 32); 55} 56 57static int rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp, 58 struct timespec64 *ts) 59{ 60 struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp); 61 unsigned long flags; 62 63 spin_lock_irqsave(&ptp_priv->lock, flags); 64 _rcar_gen4_ptp_gettime(ptp, ts); 65 spin_unlock_irqrestore(&ptp_priv->lock, flags); 66 67 return 0; 68} 69 70/* Caller must hold the lock */ 71static void _rcar_gen4_ptp_settime(struct ptp_clock_info *ptp, 72 const struct timespec64 *ts) 73{ 74 struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp); 75 76 iowrite32(1, ptp_priv->addr + PTPTMDC_REG); 77 iowrite32(0, ptp_priv->addr + PTPTOVC20_REG); 78 iowrite32(0, ptp_priv->addr + PTPTOVC10_REG); 79 iowrite32(0, ptp_priv->addr + PTPTOVC00_REG); 80 iowrite32(1, ptp_priv->addr + PTPTMEC_REG); 81 iowrite32(ts->tv_sec >> 32, ptp_priv->addr + PTPTOVC20_REG); 82 iowrite32(ts->tv_sec, ptp_priv->addr + PTPTOVC10_REG); 83 iowrite32(ts->tv_nsec, ptp_priv->addr + PTPTOVC00_REG); 84} 85 86static int rcar_gen4_ptp_settime(struct ptp_clock_info *ptp, 87 const struct timespec64 *ts) 88{ 89 struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp); 90 unsigned long flags; 91 92 spin_lock_irqsave(&ptp_priv->lock, flags); 93 _rcar_gen4_ptp_settime(ptp, ts); 94 spin_unlock_irqrestore(&ptp_priv->lock, flags); 95 96 return 0; 97} 98 99static int rcar_gen4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 100{ 101 struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp); 102 struct timespec64 ts; 103 unsigned long flags; 104 s64 now; 105 106 spin_lock_irqsave(&ptp_priv->lock, flags); 107 _rcar_gen4_ptp_gettime(ptp, &ts); 108 now = ktime_to_ns(timespec64_to_ktime(ts)); 109 ts = ns_to_timespec64(now + delta); 110 _rcar_gen4_ptp_settime(ptp, &ts); 111 spin_unlock_irqrestore(&ptp_priv->lock, flags); 112 113 return 0; 114} 115 116static int rcar_gen4_ptp_enable(struct ptp_clock_info *ptp, 117 struct ptp_clock_request *rq, int on) 118{ 119 return -EOPNOTSUPP; 120} 121 122static struct ptp_clock_info rcar_gen4_ptp_info = { 123 .owner = THIS_MODULE, 124 .name = "rcar_gen4_ptp", 125 .max_adj = 50000000, 126 .adjfine = rcar_gen4_ptp_adjfine, 127 .adjtime = rcar_gen4_ptp_adjtime, 128 .gettime64 = rcar_gen4_ptp_gettime, 129 .settime64 = rcar_gen4_ptp_settime, 130 .enable = rcar_gen4_ptp_enable, 131}; 132 133static s64 rcar_gen4_ptp_rate_to_increment(u32 rate) 134{ 135 /* Timer increment in ns. 136 * bit[31:27] - integer 137 * bit[26:0] - decimal 138 * increment[ns] = perid[ns] * 2^27 => (1ns * 2^27) / rate[hz] 139 */ 140 return div_s64(1000000000LL << 27, rate); 141} 142 143int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv, u32 rate) 144{ 145 if (ptp_priv->initialized) 146 return 0; 147 148 spin_lock_init(&ptp_priv->lock); 149 150 ptp_priv->default_addend = rcar_gen4_ptp_rate_to_increment(rate); 151 iowrite32(ptp_priv->default_addend, ptp_priv->addr + PTPTIVC0_REG); 152 ptp_priv->clock = ptp_clock_register(&ptp_priv->info, NULL); 153 if (IS_ERR(ptp_priv->clock)) 154 return PTR_ERR(ptp_priv->clock); 155 156 iowrite32(0x01, ptp_priv->addr + PTPTMEC_REG); 157 ptp_priv->initialized = true; 158 159 return 0; 160} 161EXPORT_SYMBOL_GPL(rcar_gen4_ptp_register); 162 163int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv) 164{ 165 iowrite32(1, ptp_priv->addr + PTPTMDC_REG); 166 167 return ptp_clock_unregister(ptp_priv->clock); 168} 169EXPORT_SYMBOL_GPL(rcar_gen4_ptp_unregister); 170 171struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev) 172{ 173 struct rcar_gen4_ptp_private *ptp; 174 175 ptp = devm_kzalloc(&pdev->dev, sizeof(*ptp), GFP_KERNEL); 176 if (!ptp) 177 return NULL; 178 179 ptp->info = rcar_gen4_ptp_info; 180 181 return ptp; 182} 183EXPORT_SYMBOL_GPL(rcar_gen4_ptp_alloc); 184 185MODULE_AUTHOR("Yoshihiro Shimoda"); 186MODULE_DESCRIPTION("Renesas R-Car Gen4 gPTP driver"); 187MODULE_LICENSE("GPL");
~/
Read-only file preview.