1 // SPDX-License-Identifier: GPL-2.0-only
3 * DFL device driver for Time-of-Day (ToD) private feature
5 * Copyright (C) 2023 Intel Corporation
8 #include <linux/bitfield.h>
9 #include <linux/delay.h>
10 #include <linux/dfl.h>
11 #include <linux/gcd.h>
12 #include <linux/iopoll.h>
13 #include <linux/module.h>
14 #include <linux/ptp_clock_kernel.h>
15 #include <linux/spinlock.h>
16 #include <linux/units.h>
18 #define FME_FEATURE_ID_TOD 0x22
20 /* ToD clock register space. */
21 #define TOD_CLK_FREQ 0x038
24 * The read sequence of ToD timestamp registers: TOD_NANOSEC, TOD_SECONDSL and
25 * TOD_SECONDSH, because there is a hardware snapshot whenever the TOD_NANOSEC
28 * The ToD IP requires writing registers in the reverse order to the read sequence.
29 * The timestamp is corrected when the TOD_NANOSEC register is written, so the
30 * sequence of write TOD registers: TOD_SECONDSH, TOD_SECONDSL and TOD_NANOSEC.
32 #define TOD_SECONDSH 0x100
33 #define TOD_SECONDSL 0x104
34 #define TOD_NANOSEC 0x108
35 #define TOD_PERIOD 0x110
36 #define TOD_ADJUST_PERIOD 0x114
37 #define TOD_ADJUST_COUNT 0x118
38 #define TOD_DRIFT_ADJUST 0x11c
39 #define TOD_DRIFT_ADJUST_RATE 0x120
40 #define PERIOD_FRAC_OFFSET 16
41 #define SECONDS_MSB GENMASK_ULL(47, 32)
42 #define SECONDS_LSB GENMASK_ULL(31, 0)
43 #define TOD_SECONDSH_SEC_MSB GENMASK_ULL(15, 0)
45 #define CAL_SECONDS(m, l) ((FIELD_GET(TOD_SECONDSH_SEC_MSB, (m)) << 32) | (l))
47 #define TOD_PERIOD_MASK GENMASK_ULL(19, 0)
48 #define TOD_PERIOD_MAX FIELD_MAX(TOD_PERIOD_MASK)
49 #define TOD_PERIOD_MIN 0
50 #define TOD_DRIFT_ADJUST_MASK GENMASK_ULL(15, 0)
51 #define TOD_DRIFT_ADJUST_FNS_MAX FIELD_MAX(TOD_DRIFT_ADJUST_MASK)
52 #define TOD_DRIFT_ADJUST_RATE_MAX TOD_DRIFT_ADJUST_FNS_MAX
53 #define TOD_ADJUST_COUNT_MASK GENMASK_ULL(19, 0)
54 #define TOD_ADJUST_COUNT_MAX FIELD_MAX(TOD_ADJUST_COUNT_MASK)
55 #define TOD_ADJUST_INTERVAL_US 10
56 #define TOD_ADJUST_MS \
57 (((TOD_PERIOD_MAX >> 16) + 1) * (TOD_ADJUST_COUNT_MAX + 1))
58 #define TOD_ADJUST_MS_MAX (TOD_ADJUST_MS / MICRO)
59 #define TOD_ADJUST_MAX_US (TOD_ADJUST_MS_MAX * USEC_PER_MSEC)
60 #define TOD_MAX_ADJ (500 * MEGA)
63 struct ptp_clock_info ptp_clock_ops
;
65 struct ptp_clock
*ptp_clock
;
67 /* ToD Clock address space */
68 void __iomem
*tod_ctrl
;
70 /* ToD clock registers protection */
75 * A fine ToD HW clock offset adjustment. To perform the fine offset adjustment, the
76 * adjust_period and adjust_count argument are used to update the TOD_ADJUST_PERIOD
77 * and TOD_ADJUST_COUNT register for in hardware. The dt->tod_lock spinlock must be
78 * held when calling this function.
80 static int fine_adjust_tod_clock(struct dfl_tod
*dt
, u32 adjust_period
,
83 void __iomem
*base
= dt
->tod_ctrl
;
86 writel(adjust_period
, base
+ TOD_ADJUST_PERIOD
);
87 writel(adjust_count
, base
+ TOD_ADJUST_COUNT
);
89 /* Wait for present offset adjustment update to complete */
90 return readl_poll_timeout_atomic(base
+ TOD_ADJUST_COUNT
, val
, !val
, TOD_ADJUST_INTERVAL_US
,
95 * A coarse ToD HW clock offset adjustment. The coarse time adjustment performs by
96 * adding or subtracting the delta value from the current ToD HW clock time.
98 static int coarse_adjust_tod_clock(struct dfl_tod
*dt
, s64 delta
)
100 u32 seconds_msb
, seconds_lsb
, nanosec
;
101 void __iomem
*base
= dt
->tod_ctrl
;
107 nanosec
= readl(base
+ TOD_NANOSEC
);
108 seconds_lsb
= readl(base
+ TOD_SECONDSL
);
109 seconds_msb
= readl(base
+ TOD_SECONDSH
);
111 /* Calculate new time */
112 seconds
= CAL_SECONDS(seconds_msb
, seconds_lsb
);
113 now
= seconds
* NSEC_PER_SEC
+ nanosec
+ delta
;
115 seconds
= div_u64_rem(now
, NSEC_PER_SEC
, &nanosec
);
116 seconds_msb
= FIELD_GET(SECONDS_MSB
, seconds
);
117 seconds_lsb
= FIELD_GET(SECONDS_LSB
, seconds
);
119 writel(seconds_msb
, base
+ TOD_SECONDSH
);
120 writel(seconds_lsb
, base
+ TOD_SECONDSL
);
121 writel(nanosec
, base
+ TOD_NANOSEC
);
126 static int dfl_tod_adjust_fine(struct ptp_clock_info
*ptp
, long scaled_ppm
)
128 struct dfl_tod
*dt
= container_of(ptp
, struct dfl_tod
, ptp_clock_ops
);
129 u32 tod_period
, tod_rem
, tod_drift_adjust_fns
, tod_drift_adjust_rate
;
130 void __iomem
*base
= dt
->tod_ctrl
;
131 unsigned long flags
, rate
;
134 /* Get the clock rate from clock frequency register offset */
135 rate
= readl(base
+ TOD_CLK_FREQ
);
137 /* add GIGA as nominal ppb */
138 ppb
= scaled_ppm_to_ppb(scaled_ppm
) + GIGA
;
140 tod_period
= div_u64_rem(ppb
<< PERIOD_FRAC_OFFSET
, rate
, &tod_rem
);
141 if (tod_period
> TOD_PERIOD_MAX
)
145 * The drift of ToD adjusted periodically by adding a drift_adjust_fns
146 * correction value every drift_adjust_rate count of clock cycles.
148 tod_drift_adjust_fns
= tod_rem
/ gcd(tod_rem
, rate
);
149 tod_drift_adjust_rate
= rate
/ gcd(tod_rem
, rate
);
151 while ((tod_drift_adjust_fns
> TOD_DRIFT_ADJUST_FNS_MAX
) ||
152 (tod_drift_adjust_rate
> TOD_DRIFT_ADJUST_RATE_MAX
)) {
153 tod_drift_adjust_fns
>>= 1;
154 tod_drift_adjust_rate
>>= 1;
157 if (tod_drift_adjust_fns
== 0)
158 tod_drift_adjust_rate
= 0;
160 spin_lock_irqsave(&dt
->tod_lock
, flags
);
161 writel(tod_period
, base
+ TOD_PERIOD
);
162 writel(0, base
+ TOD_ADJUST_PERIOD
);
163 writel(0, base
+ TOD_ADJUST_COUNT
);
164 writel(tod_drift_adjust_fns
, base
+ TOD_DRIFT_ADJUST
);
165 writel(tod_drift_adjust_rate
, base
+ TOD_DRIFT_ADJUST_RATE
);
166 spin_unlock_irqrestore(&dt
->tod_lock
, flags
);
171 static int dfl_tod_adjust_time(struct ptp_clock_info
*ptp
, s64 delta
)
173 struct dfl_tod
*dt
= container_of(ptp
, struct dfl_tod
, ptp_clock_ops
);
174 u32 period
, diff
, rem
, rem_period
, adj_period
;
175 void __iomem
*base
= dt
->tod_ctrl
;
185 spin_lock_irqsave(&dt
->tod_lock
, flags
);
188 * Get the maximum possible value of the Period register offset
189 * adjustment in nanoseconds scale. This depends on the current
190 * Period register setting and the maximum and minimum possible
191 * values of the Period register.
193 period
= readl(base
+ TOD_PERIOD
);
196 diff
= (period
- TOD_PERIOD_MIN
) >> PERIOD_FRAC_OFFSET
;
197 adj_period
= period
- (diff
<< PERIOD_FRAC_OFFSET
);
198 count
= div_u64_rem(delta
, diff
, &rem
);
199 rem_period
= period
- (rem
<< PERIOD_FRAC_OFFSET
);
201 diff
= (TOD_PERIOD_MAX
- period
) >> PERIOD_FRAC_OFFSET
;
202 adj_period
= period
+ (diff
<< PERIOD_FRAC_OFFSET
);
203 count
= div_u64_rem(delta
, diff
, &rem
);
204 rem_period
= period
+ (rem
<< PERIOD_FRAC_OFFSET
);
209 if (count
> TOD_ADJUST_COUNT_MAX
) {
210 ret
= coarse_adjust_tod_clock(dt
, delta
);
212 /* Adjust the period by count cycles to adjust the time */
214 ret
= fine_adjust_tod_clock(dt
, adj_period
, count
);
216 /* If there is a remainder, adjust the period for an additional cycle */
218 ret
= fine_adjust_tod_clock(dt
, rem_period
, 1);
221 spin_unlock_irqrestore(&dt
->tod_lock
, flags
);
226 static int dfl_tod_get_timex(struct ptp_clock_info
*ptp
, struct timespec64
*ts
,
227 struct ptp_system_timestamp
*sts
)
229 struct dfl_tod
*dt
= container_of(ptp
, struct dfl_tod
, ptp_clock_ops
);
230 u32 seconds_msb
, seconds_lsb
, nanosec
;
231 void __iomem
*base
= dt
->tod_ctrl
;
235 spin_lock_irqsave(&dt
->tod_lock
, flags
);
236 ptp_read_system_prets(sts
);
237 nanosec
= readl(base
+ TOD_NANOSEC
);
238 seconds_lsb
= readl(base
+ TOD_SECONDSL
);
239 seconds_msb
= readl(base
+ TOD_SECONDSH
);
240 ptp_read_system_postts(sts
);
241 spin_unlock_irqrestore(&dt
->tod_lock
, flags
);
243 seconds
= CAL_SECONDS(seconds_msb
, seconds_lsb
);
245 ts
->tv_nsec
= nanosec
;
246 ts
->tv_sec
= seconds
;
251 static int dfl_tod_set_time(struct ptp_clock_info
*ptp
,
252 const struct timespec64
*ts
)
254 struct dfl_tod
*dt
= container_of(ptp
, struct dfl_tod
, ptp_clock_ops
);
255 u32 seconds_msb
= FIELD_GET(SECONDS_MSB
, ts
->tv_sec
);
256 u32 seconds_lsb
= FIELD_GET(SECONDS_LSB
, ts
->tv_sec
);
257 u32 nanosec
= FIELD_GET(SECONDS_LSB
, ts
->tv_nsec
);
258 void __iomem
*base
= dt
->tod_ctrl
;
261 spin_lock_irqsave(&dt
->tod_lock
, flags
);
262 writel(seconds_msb
, base
+ TOD_SECONDSH
);
263 writel(seconds_lsb
, base
+ TOD_SECONDSL
);
264 writel(nanosec
, base
+ TOD_NANOSEC
);
265 spin_unlock_irqrestore(&dt
->tod_lock
, flags
);
270 static struct ptp_clock_info dfl_tod_clock_ops
= {
271 .owner
= THIS_MODULE
,
273 .max_adj
= TOD_MAX_ADJ
,
274 .adjfine
= dfl_tod_adjust_fine
,
275 .adjtime
= dfl_tod_adjust_time
,
276 .gettimex64
= dfl_tod_get_timex
,
277 .settime64
= dfl_tod_set_time
,
280 static int dfl_tod_probe(struct dfl_device
*ddev
)
282 struct device
*dev
= &ddev
->dev
;
285 dt
= devm_kzalloc(dev
, sizeof(*dt
), GFP_KERNEL
);
289 dt
->tod_ctrl
= devm_ioremap_resource(dev
, &ddev
->mmio_res
);
290 if (IS_ERR(dt
->tod_ctrl
))
291 return PTR_ERR(dt
->tod_ctrl
);
294 spin_lock_init(&dt
->tod_lock
);
295 dev_set_drvdata(dev
, dt
);
297 dt
->ptp_clock_ops
= dfl_tod_clock_ops
;
299 dt
->ptp_clock
= ptp_clock_register(&dt
->ptp_clock_ops
, dev
);
300 if (IS_ERR(dt
->ptp_clock
))
301 return dev_err_probe(dt
->dev
, PTR_ERR(dt
->ptp_clock
),
302 "Unable to register PTP clock\n");
307 static void dfl_tod_remove(struct dfl_device
*ddev
)
309 struct dfl_tod
*dt
= dev_get_drvdata(&ddev
->dev
);
311 ptp_clock_unregister(dt
->ptp_clock
);
314 static const struct dfl_device_id dfl_tod_ids
[] = {
315 { FME_ID
, FME_FEATURE_ID_TOD
},
318 MODULE_DEVICE_TABLE(dfl
, dfl_tod_ids
);
320 static struct dfl_driver dfl_tod_driver
= {
324 .id_table
= dfl_tod_ids
,
325 .probe
= dfl_tod_probe
,
326 .remove
= dfl_tod_remove
,
328 module_dfl_driver(dfl_tod_driver
);
330 MODULE_DESCRIPTION("FPGA DFL ToD driver");
331 MODULE_AUTHOR("Intel Corporation");
332 MODULE_LICENSE("GPL");