1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* PTP 1588 clock using the Renesas Ethernet AVB |
3 | * |
4 | * Copyright (C) 2013-2015 Renesas Electronics Corporation |
5 | * Copyright (C) 2015 Renesas Solutions Corp. |
6 | * Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com> |
7 | */ |
8 | |
9 | #include "ravb.h" |
10 | |
11 | static int ravb_ptp_tcr_request(struct ravb_private *priv, u32 request) |
12 | { |
13 | struct net_device *ndev = priv->ndev; |
14 | int error; |
15 | |
16 | error = ravb_wait(ndev, reg: GCCR, mask: GCCR_TCR, value: GCCR_TCR_NOREQ); |
17 | if (error) |
18 | return error; |
19 | |
20 | ravb_modify(ndev, reg: GCCR, clear: request, set: request); |
21 | return ravb_wait(ndev, reg: GCCR, mask: GCCR_TCR, value: GCCR_TCR_NOREQ); |
22 | } |
23 | |
24 | /* Caller must hold the lock */ |
25 | static int ravb_ptp_time_read(struct ravb_private *priv, struct timespec64 *ts) |
26 | { |
27 | struct net_device *ndev = priv->ndev; |
28 | int error; |
29 | |
30 | error = ravb_ptp_tcr_request(priv, request: GCCR_TCR_CAPTURE); |
31 | if (error) |
32 | return error; |
33 | |
34 | ts->tv_nsec = ravb_read(ndev, reg: GCT0); |
35 | ts->tv_sec = ravb_read(ndev, reg: GCT1) | |
36 | ((s64)ravb_read(ndev, reg: GCT2) << 32); |
37 | |
38 | return 0; |
39 | } |
40 | |
41 | /* Caller must hold the lock */ |
42 | static int ravb_ptp_time_write(struct ravb_private *priv, |
43 | const struct timespec64 *ts) |
44 | { |
45 | struct net_device *ndev = priv->ndev; |
46 | int error; |
47 | u32 gccr; |
48 | |
49 | error = ravb_ptp_tcr_request(priv, request: GCCR_TCR_RESET); |
50 | if (error) |
51 | return error; |
52 | |
53 | gccr = ravb_read(ndev, reg: GCCR); |
54 | if (gccr & GCCR_LTO) |
55 | return -EBUSY; |
56 | ravb_write(ndev, data: ts->tv_nsec, reg: GTO0); |
57 | ravb_write(ndev, data: ts->tv_sec, reg: GTO1); |
58 | ravb_write(ndev, data: (ts->tv_sec >> 32) & 0xffff, reg: GTO2); |
59 | ravb_write(ndev, data: gccr | GCCR_LTO, reg: GCCR); |
60 | |
61 | return 0; |
62 | } |
63 | |
64 | /* Caller must hold the lock */ |
65 | static int ravb_ptp_update_compare(struct ravb_private *priv, u32 ns) |
66 | { |
67 | struct net_device *ndev = priv->ndev; |
68 | /* When the comparison value (GPTC.PTCV) is in range of |
69 | * [x-1 to x+1] (x is the configured increment value in |
70 | * GTI.TIV), it may happen that a comparison match is |
71 | * not detected when the timer wraps around. |
72 | */ |
73 | u32 gti_ns_plus_1 = (priv->ptp.current_addend >> 20) + 1; |
74 | u32 gccr; |
75 | |
76 | if (ns < gti_ns_plus_1) |
77 | ns = gti_ns_plus_1; |
78 | else if (ns > 0 - gti_ns_plus_1) |
79 | ns = 0 - gti_ns_plus_1; |
80 | |
81 | gccr = ravb_read(ndev, reg: GCCR); |
82 | if (gccr & GCCR_LPTC) |
83 | return -EBUSY; |
84 | ravb_write(ndev, data: ns, reg: GPTC); |
85 | ravb_write(ndev, data: gccr | GCCR_LPTC, reg: GCCR); |
86 | |
87 | return 0; |
88 | } |
89 | |
90 | /* PTP clock operations */ |
91 | static int ravb_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) |
92 | { |
93 | struct ravb_private *priv = container_of(ptp, struct ravb_private, |
94 | ptp.info); |
95 | struct net_device *ndev = priv->ndev; |
96 | unsigned long flags; |
97 | u32 addend; |
98 | u32 gccr; |
99 | |
100 | addend = (u32)adjust_by_scaled_ppm(base: priv->ptp.default_addend, |
101 | scaled_ppm); |
102 | |
103 | spin_lock_irqsave(&priv->lock, flags); |
104 | |
105 | priv->ptp.current_addend = addend; |
106 | |
107 | gccr = ravb_read(ndev, reg: GCCR); |
108 | if (gccr & GCCR_LTI) { |
109 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
110 | return -EBUSY; |
111 | } |
112 | ravb_write(ndev, data: addend & GTI_TIV, reg: GTI); |
113 | ravb_write(ndev, data: gccr | GCCR_LTI, reg: GCCR); |
114 | |
115 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
116 | |
117 | return 0; |
118 | } |
119 | |
120 | static int ravb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) |
121 | { |
122 | struct ravb_private *priv = container_of(ptp, struct ravb_private, |
123 | ptp.info); |
124 | struct timespec64 ts; |
125 | unsigned long flags; |
126 | int error; |
127 | |
128 | spin_lock_irqsave(&priv->lock, flags); |
129 | error = ravb_ptp_time_read(priv, ts: &ts); |
130 | if (!error) { |
131 | u64 now = ktime_to_ns(kt: timespec64_to_ktime(ts)); |
132 | |
133 | ts = ns_to_timespec64(nsec: now + delta); |
134 | error = ravb_ptp_time_write(priv, ts: &ts); |
135 | } |
136 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
137 | |
138 | return error; |
139 | } |
140 | |
141 | static int ravb_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) |
142 | { |
143 | struct ravb_private *priv = container_of(ptp, struct ravb_private, |
144 | ptp.info); |
145 | unsigned long flags; |
146 | int error; |
147 | |
148 | spin_lock_irqsave(&priv->lock, flags); |
149 | error = ravb_ptp_time_read(priv, ts); |
150 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
151 | |
152 | return error; |
153 | } |
154 | |
155 | static int ravb_ptp_settime64(struct ptp_clock_info *ptp, |
156 | const struct timespec64 *ts) |
157 | { |
158 | struct ravb_private *priv = container_of(ptp, struct ravb_private, |
159 | ptp.info); |
160 | unsigned long flags; |
161 | int error; |
162 | |
163 | spin_lock_irqsave(&priv->lock, flags); |
164 | error = ravb_ptp_time_write(priv, ts); |
165 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
166 | |
167 | return error; |
168 | } |
169 | |
170 | static int ravb_ptp_extts(struct ptp_clock_info *ptp, |
171 | struct ptp_extts_request *req, int on) |
172 | { |
173 | struct ravb_private *priv = container_of(ptp, struct ravb_private, |
174 | ptp.info); |
175 | const struct ravb_hw_info *info = priv->info; |
176 | struct net_device *ndev = priv->ndev; |
177 | unsigned long flags; |
178 | |
179 | /* Reject requests with unsupported flags */ |
180 | if (req->flags & ~(PTP_ENABLE_FEATURE | |
181 | PTP_RISING_EDGE | |
182 | PTP_FALLING_EDGE | |
183 | PTP_STRICT_FLAGS)) |
184 | return -EOPNOTSUPP; |
185 | |
186 | if (req->index) |
187 | return -EINVAL; |
188 | |
189 | if (priv->ptp.extts[req->index] == on) |
190 | return 0; |
191 | priv->ptp.extts[req->index] = on; |
192 | |
193 | spin_lock_irqsave(&priv->lock, flags); |
194 | if (!info->irq_en_dis) |
195 | ravb_modify(ndev, reg: GIC, clear: GIC_PTCE, set: on ? GIC_PTCE : 0); |
196 | else if (on) |
197 | ravb_write(ndev, data: GIE_PTCS, reg: GIE); |
198 | else |
199 | ravb_write(ndev, data: GID_PTCD, reg: GID); |
200 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
201 | |
202 | return 0; |
203 | } |
204 | |
205 | static int ravb_ptp_perout(struct ptp_clock_info *ptp, |
206 | struct ptp_perout_request *req, int on) |
207 | { |
208 | struct ravb_private *priv = container_of(ptp, struct ravb_private, |
209 | ptp.info); |
210 | const struct ravb_hw_info *info = priv->info; |
211 | struct net_device *ndev = priv->ndev; |
212 | struct ravb_ptp_perout *perout; |
213 | unsigned long flags; |
214 | int error = 0; |
215 | |
216 | /* Reject requests with unsupported flags */ |
217 | if (req->flags) |
218 | return -EOPNOTSUPP; |
219 | |
220 | if (req->index) |
221 | return -EINVAL; |
222 | |
223 | if (on) { |
224 | u64 start_ns; |
225 | u64 period_ns; |
226 | |
227 | start_ns = req->start.sec * NSEC_PER_SEC + req->start.nsec; |
228 | period_ns = req->period.sec * NSEC_PER_SEC + req->period.nsec; |
229 | |
230 | if (start_ns > U32_MAX) { |
231 | netdev_warn(dev: ndev, |
232 | format: "ptp: start value (nsec) is over limit. Maximum size of start is only 32 bits\n" ); |
233 | return -ERANGE; |
234 | } |
235 | |
236 | if (period_ns > U32_MAX) { |
237 | netdev_warn(dev: ndev, |
238 | format: "ptp: period value (nsec) is over limit. Maximum size of period is only 32 bits\n" ); |
239 | return -ERANGE; |
240 | } |
241 | |
242 | spin_lock_irqsave(&priv->lock, flags); |
243 | |
244 | perout = &priv->ptp.perout[req->index]; |
245 | perout->target = (u32)start_ns; |
246 | perout->period = (u32)period_ns; |
247 | error = ravb_ptp_update_compare(priv, ns: (u32)start_ns); |
248 | if (!error) { |
249 | /* Unmask interrupt */ |
250 | if (!info->irq_en_dis) |
251 | ravb_modify(ndev, reg: GIC, clear: GIC_PTME, set: GIC_PTME); |
252 | else |
253 | ravb_write(ndev, data: GIE_PTMS0, reg: GIE); |
254 | } |
255 | } else { |
256 | spin_lock_irqsave(&priv->lock, flags); |
257 | |
258 | perout = &priv->ptp.perout[req->index]; |
259 | perout->period = 0; |
260 | |
261 | /* Mask interrupt */ |
262 | if (!info->irq_en_dis) |
263 | ravb_modify(ndev, reg: GIC, clear: GIC_PTME, set: 0); |
264 | else |
265 | ravb_write(ndev, data: GID_PTMD0, reg: GID); |
266 | } |
267 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
268 | |
269 | return error; |
270 | } |
271 | |
272 | static int ravb_ptp_enable(struct ptp_clock_info *ptp, |
273 | struct ptp_clock_request *req, int on) |
274 | { |
275 | switch (req->type) { |
276 | case PTP_CLK_REQ_EXTTS: |
277 | return ravb_ptp_extts(ptp, req: &req->extts, on); |
278 | case PTP_CLK_REQ_PEROUT: |
279 | return ravb_ptp_perout(ptp, req: &req->perout, on); |
280 | default: |
281 | return -EOPNOTSUPP; |
282 | } |
283 | } |
284 | |
285 | static const struct ptp_clock_info ravb_ptp_info = { |
286 | .owner = THIS_MODULE, |
287 | .name = "ravb clock" , |
288 | .max_adj = 50000000, |
289 | .n_ext_ts = N_EXT_TS, |
290 | .n_per_out = N_PER_OUT, |
291 | .adjfine = ravb_ptp_adjfine, |
292 | .adjtime = ravb_ptp_adjtime, |
293 | .gettime64 = ravb_ptp_gettime64, |
294 | .settime64 = ravb_ptp_settime64, |
295 | .enable = ravb_ptp_enable, |
296 | }; |
297 | |
298 | /* Caller must hold the lock */ |
299 | void ravb_ptp_interrupt(struct net_device *ndev) |
300 | { |
301 | struct ravb_private *priv = netdev_priv(dev: ndev); |
302 | u32 gis = ravb_read(ndev, reg: GIS); |
303 | |
304 | gis &= ravb_read(ndev, reg: GIC); |
305 | if (gis & GIS_PTCF) { |
306 | struct ptp_clock_event event; |
307 | |
308 | event.type = PTP_CLOCK_EXTTS; |
309 | event.index = 0; |
310 | event.timestamp = ravb_read(ndev, reg: GCPT); |
311 | ptp_clock_event(ptp: priv->ptp.clock, event: &event); |
312 | } |
313 | if (gis & GIS_PTMF) { |
314 | struct ravb_ptp_perout *perout = priv->ptp.perout; |
315 | |
316 | if (perout->period) { |
317 | perout->target += perout->period; |
318 | ravb_ptp_update_compare(priv, ns: perout->target); |
319 | } |
320 | } |
321 | |
322 | ravb_write(ndev, data: ~(gis | GIS_RESERVED), reg: GIS); |
323 | } |
324 | |
325 | void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev) |
326 | { |
327 | struct ravb_private *priv = netdev_priv(dev: ndev); |
328 | unsigned long flags; |
329 | |
330 | priv->ptp.info = ravb_ptp_info; |
331 | |
332 | priv->ptp.default_addend = ravb_read(ndev, reg: GTI); |
333 | priv->ptp.current_addend = priv->ptp.default_addend; |
334 | |
335 | spin_lock_irqsave(&priv->lock, flags); |
336 | ravb_wait(ndev, reg: GCCR, mask: GCCR_TCR, value: GCCR_TCR_NOREQ); |
337 | ravb_modify(ndev, reg: GCCR, clear: GCCR_TCSS, set: GCCR_TCSS_ADJGPTP); |
338 | spin_unlock_irqrestore(lock: &priv->lock, flags); |
339 | |
340 | priv->ptp.clock = ptp_clock_register(info: &priv->ptp.info, parent: &pdev->dev); |
341 | } |
342 | |
343 | void ravb_ptp_stop(struct net_device *ndev) |
344 | { |
345 | struct ravb_private *priv = netdev_priv(dev: ndev); |
346 | |
347 | ravb_write(ndev, data: 0, reg: GIC); |
348 | ravb_write(ndev, data: 0, reg: GIS); |
349 | |
350 | ptp_clock_unregister(ptp: priv->ptp.clock); |
351 | } |
352 | |