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