]>
Commit | Line | Data |
---|---|---|
a7e1abad JL |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (c) 2020 Facebook */ | |
3 | ||
4 | #include <linux/err.h> | |
5 | #include <linux/kernel.h> | |
6 | #include <linux/module.h> | |
7 | #include <linux/init.h> | |
8 | #include <linux/pci.h> | |
773bda96 JL |
9 | #include <linux/serial_8250.h> |
10 | #include <linux/clkdev.h> | |
11 | #include <linux/clk-provider.h> | |
12 | #include <linux/platform_device.h> | |
a7e1abad | 13 | #include <linux/ptp_clock_kernel.h> |
773bda96 JL |
14 | #include <linux/spi/spi.h> |
15 | #include <linux/spi/xilinx_spi.h> | |
16 | #include <net/devlink.h> | |
17 | #include <linux/i2c.h> | |
18 | #include <linux/mtd/mtd.h> | |
a7e1abad | 19 | |
773bda96 JL |
20 | #ifndef PCI_VENDOR_ID_FACEBOOK |
21 | #define PCI_VENDOR_ID_FACEBOOK 0x1d9b | |
22 | #endif | |
a7e1abad | 23 | |
773bda96 JL |
24 | #ifndef PCI_DEVICE_ID_FACEBOOK_TIMECARD |
25 | #define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400 | |
26 | #endif | |
27 | ||
28 | static struct class timecard_class = { | |
29 | .owner = THIS_MODULE, | |
30 | .name = "timecard", | |
31 | }; | |
a7e1abad JL |
32 | |
33 | struct ocp_reg { | |
34 | u32 ctrl; | |
35 | u32 status; | |
36 | u32 select; | |
37 | u32 version; | |
38 | u32 time_ns; | |
39 | u32 time_sec; | |
40 | u32 __pad0[2]; | |
41 | u32 adjust_ns; | |
42 | u32 adjust_sec; | |
43 | u32 __pad1[2]; | |
44 | u32 offset_ns; | |
45 | u32 offset_window_ns; | |
773bda96 JL |
46 | u32 __pad2[2]; |
47 | u32 drift_ns; | |
48 | u32 drift_window_ns; | |
49 | u32 __pad3[6]; | |
50 | u32 servo_offset_p; | |
51 | u32 servo_offset_i; | |
52 | u32 servo_drift_p; | |
53 | u32 servo_drift_i; | |
a7e1abad JL |
54 | }; |
55 | ||
56 | #define OCP_CTRL_ENABLE BIT(0) | |
57 | #define OCP_CTRL_ADJUST_TIME BIT(1) | |
58 | #define OCP_CTRL_ADJUST_OFFSET BIT(2) | |
773bda96 JL |
59 | #define OCP_CTRL_ADJUST_DRIFT BIT(3) |
60 | #define OCP_CTRL_ADJUST_SERVO BIT(8) | |
a7e1abad JL |
61 | #define OCP_CTRL_READ_TIME_REQ BIT(30) |
62 | #define OCP_CTRL_READ_TIME_DONE BIT(31) | |
63 | ||
64 | #define OCP_STATUS_IN_SYNC BIT(0) | |
773bda96 | 65 | #define OCP_STATUS_IN_HOLDOVER BIT(1) |
a7e1abad JL |
66 | |
67 | #define OCP_SELECT_CLK_NONE 0 | |
773bda96 | 68 | #define OCP_SELECT_CLK_REG 0xfe |
a7e1abad JL |
69 | |
70 | struct tod_reg { | |
71 | u32 ctrl; | |
72 | u32 status; | |
73 | u32 uart_polarity; | |
74 | u32 version; | |
75 | u32 correction_sec; | |
76 | u32 __pad0[3]; | |
77 | u32 uart_baud; | |
78 | u32 __pad1[3]; | |
79 | u32 utc_status; | |
80 | u32 leap; | |
81 | }; | |
82 | ||
a7e1abad JL |
83 | #define TOD_CTRL_PROTOCOL BIT(28) |
84 | #define TOD_CTRL_DISABLE_FMT_A BIT(17) | |
85 | #define TOD_CTRL_DISABLE_FMT_B BIT(16) | |
86 | #define TOD_CTRL_ENABLE BIT(0) | |
87 | #define TOD_CTRL_GNSS_MASK ((1U << 4) - 1) | |
88 | #define TOD_CTRL_GNSS_SHIFT 24 | |
89 | ||
90 | #define TOD_STATUS_UTC_MASK 0xff | |
91 | #define TOD_STATUS_UTC_VALID BIT(8) | |
92 | #define TOD_STATUS_LEAP_VALID BIT(16) | |
93 | ||
773bda96 JL |
94 | struct ts_reg { |
95 | u32 enable; | |
96 | u32 error; | |
97 | u32 polarity; | |
98 | u32 version; | |
99 | u32 __pad0[4]; | |
100 | u32 cable_delay; | |
101 | u32 __pad1[3]; | |
102 | u32 intr; | |
103 | u32 intr_mask; | |
104 | u32 event_count; | |
105 | u32 __pad2[1]; | |
106 | u32 ts_count; | |
107 | u32 time_ns; | |
108 | u32 time_sec; | |
109 | u32 data_width; | |
110 | u32 data; | |
111 | }; | |
112 | ||
113 | struct pps_reg { | |
114 | u32 ctrl; | |
115 | u32 status; | |
0d43d4f2 JL |
116 | u32 __pad0[6]; |
117 | u32 cable_delay; | |
773bda96 JL |
118 | }; |
119 | ||
120 | #define PPS_STATUS_FILTER_ERR BIT(0) | |
121 | #define PPS_STATUS_SUPERV_ERR BIT(1) | |
122 | ||
123 | struct img_reg { | |
124 | u32 version; | |
125 | }; | |
126 | ||
127 | struct ptp_ocp_flash_info { | |
128 | const char *name; | |
129 | int pci_offset; | |
130 | int data_size; | |
131 | void *data; | |
132 | }; | |
133 | ||
134 | struct ptp_ocp_ext_info { | |
135 | const char *name; | |
136 | int index; | |
137 | irqreturn_t (*irq_fcn)(int irq, void *priv); | |
138 | int (*enable)(void *priv, bool enable); | |
139 | }; | |
140 | ||
141 | struct ptp_ocp_ext_src { | |
142 | void __iomem *mem; | |
143 | struct ptp_ocp *bp; | |
144 | struct ptp_ocp_ext_info *info; | |
145 | int irq_vec; | |
146 | }; | |
147 | ||
a7e1abad JL |
148 | struct ptp_ocp { |
149 | struct pci_dev *pdev; | |
773bda96 | 150 | struct device dev; |
a7e1abad | 151 | spinlock_t lock; |
a7e1abad JL |
152 | struct ocp_reg __iomem *reg; |
153 | struct tod_reg __iomem *tod; | |
0d43d4f2 JL |
154 | struct pps_reg __iomem *pps_to_ext; |
155 | struct pps_reg __iomem *pps_to_clk; | |
773bda96 JL |
156 | struct ptp_ocp_ext_src *pps; |
157 | struct ptp_ocp_ext_src *ts0; | |
158 | struct ptp_ocp_ext_src *ts1; | |
159 | struct img_reg __iomem *image; | |
a7e1abad JL |
160 | struct ptp_clock *ptp; |
161 | struct ptp_clock_info ptp_info; | |
773bda96 JL |
162 | struct platform_device *i2c_ctrl; |
163 | struct platform_device *spi_flash; | |
164 | struct clk_hw *i2c_clk; | |
773bda96 | 165 | struct timer_list watchdog; |
ef0cfb34 | 166 | time64_t gnss_lost; |
773bda96 JL |
167 | int id; |
168 | int n_irqs; | |
ef0cfb34 | 169 | int gnss_port; |
773bda96 JL |
170 | int mac_port; /* miniature atomic clock */ |
171 | u8 serial[6]; | |
172 | int flash_start; | |
173 | bool has_serial; | |
773bda96 JL |
174 | }; |
175 | ||
176 | struct ocp_resource { | |
177 | unsigned long offset; | |
178 | int size; | |
179 | int irq_vec; | |
180 | int (*setup)(struct ptp_ocp *bp, struct ocp_resource *r); | |
181 | void *extra; | |
182 | unsigned long bp_offset; | |
183 | }; | |
184 | ||
773bda96 JL |
185 | static int ptp_ocp_register_mem(struct ptp_ocp *bp, struct ocp_resource *r); |
186 | static int ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r); | |
187 | static int ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r); | |
188 | static int ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r); | |
189 | static int ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r); | |
190 | static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r); | |
191 | static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv); | |
192 | static int ptp_ocp_ts_enable(void *priv, bool enable); | |
193 | ||
194 | #define bp_assign_entry(bp, res, val) ({ \ | |
195 | uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset; \ | |
196 | *(typeof(val) *)addr = val; \ | |
197 | }) | |
198 | ||
199 | #define OCP_RES_LOCATION(member) \ | |
200 | .bp_offset = offsetof(struct ptp_ocp, member) | |
201 | ||
202 | #define OCP_MEM_RESOURCE(member) \ | |
203 | OCP_RES_LOCATION(member), .setup = ptp_ocp_register_mem | |
204 | ||
205 | #define OCP_SERIAL_RESOURCE(member) \ | |
206 | OCP_RES_LOCATION(member), .setup = ptp_ocp_register_serial | |
207 | ||
208 | #define OCP_I2C_RESOURCE(member) \ | |
209 | OCP_RES_LOCATION(member), .setup = ptp_ocp_register_i2c | |
210 | ||
211 | #define OCP_SPI_RESOURCE(member) \ | |
212 | OCP_RES_LOCATION(member), .setup = ptp_ocp_register_spi | |
213 | ||
214 | #define OCP_EXT_RESOURCE(member) \ | |
215 | OCP_RES_LOCATION(member), .setup = ptp_ocp_register_ext | |
216 | ||
217 | /* This is the MSI vector mapping used. | |
218 | * 0: N/C | |
219 | * 1: TS0 | |
220 | * 2: TS1 | |
221 | * 3: GPS | |
222 | * 4: GPS2 (n/c) | |
223 | * 5: MAC | |
224 | * 6: SPI IMU (inertial measurement unit) | |
225 | * 7: I2C oscillator | |
226 | * 8: HWICAP | |
227 | * 9: SPI Flash | |
228 | */ | |
229 | ||
230 | static struct ocp_resource ocp_fb_resource[] = { | |
231 | { | |
232 | OCP_MEM_RESOURCE(reg), | |
233 | .offset = 0x01000000, .size = 0x10000, | |
234 | }, | |
235 | { | |
236 | OCP_EXT_RESOURCE(ts0), | |
237 | .offset = 0x01010000, .size = 0x10000, .irq_vec = 1, | |
238 | .extra = &(struct ptp_ocp_ext_info) { | |
239 | .name = "ts0", .index = 0, | |
240 | .irq_fcn = ptp_ocp_ts_irq, | |
241 | .enable = ptp_ocp_ts_enable, | |
242 | }, | |
243 | }, | |
244 | { | |
245 | OCP_EXT_RESOURCE(ts1), | |
246 | .offset = 0x01020000, .size = 0x10000, .irq_vec = 2, | |
247 | .extra = &(struct ptp_ocp_ext_info) { | |
248 | .name = "ts1", .index = 1, | |
249 | .irq_fcn = ptp_ocp_ts_irq, | |
250 | .enable = ptp_ocp_ts_enable, | |
251 | }, | |
252 | }, | |
253 | { | |
0d43d4f2 JL |
254 | OCP_MEM_RESOURCE(pps_to_ext), |
255 | .offset = 0x01030000, .size = 0x10000, | |
256 | }, | |
257 | { | |
258 | OCP_MEM_RESOURCE(pps_to_clk), | |
773bda96 JL |
259 | .offset = 0x01040000, .size = 0x10000, |
260 | }, | |
261 | { | |
262 | OCP_MEM_RESOURCE(tod), | |
263 | .offset = 0x01050000, .size = 0x10000, | |
264 | }, | |
265 | { | |
266 | OCP_MEM_RESOURCE(image), | |
267 | .offset = 0x00020000, .size = 0x1000, | |
268 | }, | |
269 | { | |
270 | OCP_I2C_RESOURCE(i2c_ctrl), | |
271 | .offset = 0x00150000, .size = 0x10000, .irq_vec = 7, | |
272 | }, | |
273 | { | |
ef0cfb34 | 274 | OCP_SERIAL_RESOURCE(gnss_port), |
773bda96 JL |
275 | .offset = 0x00160000 + 0x1000, .irq_vec = 3, |
276 | }, | |
277 | { | |
278 | OCP_SERIAL_RESOURCE(mac_port), | |
279 | .offset = 0x00180000 + 0x1000, .irq_vec = 5, | |
280 | }, | |
281 | { | |
282 | OCP_SPI_RESOURCE(spi_flash), | |
283 | .offset = 0x00310000, .size = 0x10000, .irq_vec = 9, | |
284 | .extra = &(struct ptp_ocp_flash_info) { | |
285 | .name = "xilinx_spi", .pci_offset = 0, | |
286 | .data_size = sizeof(struct xspi_platform_data), | |
287 | .data = &(struct xspi_platform_data) { | |
288 | .num_chipselect = 1, | |
289 | .bits_per_word = 8, | |
290 | .num_devices = 1, | |
291 | .devices = &(struct spi_board_info) { | |
292 | .modalias = "spi-nor", | |
293 | }, | |
294 | }, | |
295 | }, | |
296 | }, | |
297 | { | |
298 | .setup = ptp_ocp_fb_board_init, | |
299 | }, | |
300 | { } | |
301 | }; | |
302 | ||
303 | static const struct pci_device_id ptp_ocp_pcidev_id[] = { | |
304 | { PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) }, | |
305 | { 0 } | |
306 | }; | |
307 | MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id); | |
308 | ||
309 | static DEFINE_MUTEX(ptp_ocp_lock); | |
310 | static DEFINE_IDR(ptp_ocp_idr); | |
311 | ||
312 | static struct { | |
313 | const char *name; | |
314 | int value; | |
315 | } ptp_ocp_clock[] = { | |
316 | { .name = "NONE", .value = 0 }, | |
317 | { .name = "TOD", .value = 1 }, | |
318 | { .name = "IRIG", .value = 2 }, | |
319 | { .name = "PPS", .value = 3 }, | |
320 | { .name = "PTP", .value = 4 }, | |
321 | { .name = "RTC", .value = 5 }, | |
322 | { .name = "DCF", .value = 6 }, | |
323 | { .name = "REGS", .value = 0xfe }, | |
324 | { .name = "EXT", .value = 0xff }, | |
a7e1abad JL |
325 | }; |
326 | ||
773bda96 JL |
327 | static const char * |
328 | ptp_ocp_clock_name_from_val(int val) | |
329 | { | |
330 | int i; | |
331 | ||
332 | for (i = 0; i < ARRAY_SIZE(ptp_ocp_clock); i++) | |
333 | if (ptp_ocp_clock[i].value == val) | |
334 | return ptp_ocp_clock[i].name; | |
335 | return NULL; | |
336 | } | |
337 | ||
338 | static int | |
339 | ptp_ocp_clock_val_from_name(const char *name) | |
340 | { | |
341 | const char *clk; | |
342 | int i; | |
343 | ||
344 | for (i = 0; i < ARRAY_SIZE(ptp_ocp_clock); i++) { | |
345 | clk = ptp_ocp_clock[i].name; | |
346 | if (!strncasecmp(name, clk, strlen(clk))) | |
347 | return ptp_ocp_clock[i].value; | |
348 | } | |
349 | return -EINVAL; | |
350 | } | |
351 | ||
a7e1abad JL |
352 | static int |
353 | __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts, | |
354 | struct ptp_system_timestamp *sts) | |
355 | { | |
356 | u32 ctrl, time_sec, time_ns; | |
357 | int i; | |
358 | ||
359 | ctrl = ioread32(&bp->reg->ctrl); | |
360 | ctrl |= OCP_CTRL_READ_TIME_REQ; | |
361 | ||
362 | ptp_read_system_prets(sts); | |
363 | iowrite32(ctrl, &bp->reg->ctrl); | |
364 | ||
365 | for (i = 0; i < 100; i++) { | |
366 | ctrl = ioread32(&bp->reg->ctrl); | |
367 | if (ctrl & OCP_CTRL_READ_TIME_DONE) | |
368 | break; | |
369 | } | |
370 | ptp_read_system_postts(sts); | |
371 | ||
372 | time_ns = ioread32(&bp->reg->time_ns); | |
373 | time_sec = ioread32(&bp->reg->time_sec); | |
374 | ||
375 | ts->tv_sec = time_sec; | |
376 | ts->tv_nsec = time_ns; | |
377 | ||
378 | return ctrl & OCP_CTRL_READ_TIME_DONE ? 0 : -ETIMEDOUT; | |
379 | } | |
380 | ||
381 | static int | |
382 | ptp_ocp_gettimex(struct ptp_clock_info *ptp_info, struct timespec64 *ts, | |
383 | struct ptp_system_timestamp *sts) | |
384 | { | |
385 | struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); | |
386 | unsigned long flags; | |
387 | int err; | |
388 | ||
389 | spin_lock_irqsave(&bp->lock, flags); | |
390 | err = __ptp_ocp_gettime_locked(bp, ts, sts); | |
391 | spin_unlock_irqrestore(&bp->lock, flags); | |
392 | ||
393 | return err; | |
394 | } | |
395 | ||
396 | static void | |
397 | __ptp_ocp_settime_locked(struct ptp_ocp *bp, const struct timespec64 *ts) | |
398 | { | |
399 | u32 ctrl, time_sec, time_ns; | |
400 | u32 select; | |
401 | ||
402 | time_ns = ts->tv_nsec; | |
403 | time_sec = ts->tv_sec; | |
404 | ||
405 | select = ioread32(&bp->reg->select); | |
406 | iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select); | |
407 | ||
408 | iowrite32(time_ns, &bp->reg->adjust_ns); | |
409 | iowrite32(time_sec, &bp->reg->adjust_sec); | |
410 | ||
411 | ctrl = ioread32(&bp->reg->ctrl); | |
412 | ctrl |= OCP_CTRL_ADJUST_TIME; | |
413 | iowrite32(ctrl, &bp->reg->ctrl); | |
414 | ||
415 | /* restore clock selection */ | |
416 | iowrite32(select >> 16, &bp->reg->select); | |
417 | } | |
418 | ||
419 | static int | |
420 | ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts) | |
421 | { | |
422 | struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); | |
423 | unsigned long flags; | |
424 | ||
425 | if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC) | |
426 | return 0; | |
427 | ||
428 | spin_lock_irqsave(&bp->lock, flags); | |
429 | __ptp_ocp_settime_locked(bp, ts); | |
430 | spin_unlock_irqrestore(&bp->lock, flags); | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
435 | static int | |
436 | ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns) | |
437 | { | |
438 | struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); | |
439 | struct timespec64 ts; | |
440 | unsigned long flags; | |
441 | int err; | |
442 | ||
443 | if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC) | |
444 | return 0; | |
445 | ||
446 | spin_lock_irqsave(&bp->lock, flags); | |
447 | err = __ptp_ocp_gettime_locked(bp, &ts, NULL); | |
448 | if (likely(!err)) { | |
449 | timespec64_add_ns(&ts, delta_ns); | |
450 | __ptp_ocp_settime_locked(bp, &ts); | |
451 | } | |
452 | spin_unlock_irqrestore(&bp->lock, flags); | |
453 | ||
454 | return err; | |
455 | } | |
456 | ||
457 | static int | |
458 | ptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) | |
459 | { | |
460 | if (scaled_ppm == 0) | |
461 | return 0; | |
462 | ||
463 | return -EOPNOTSUPP; | |
464 | } | |
465 | ||
773bda96 JL |
466 | static int |
467 | ptp_ocp_adjphase(struct ptp_clock_info *ptp_info, s32 phase_ns) | |
468 | { | |
469 | return -EOPNOTSUPP; | |
470 | } | |
471 | ||
472 | static int | |
473 | ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq, | |
474 | int on) | |
475 | { | |
476 | struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); | |
477 | struct ptp_ocp_ext_src *ext = NULL; | |
478 | int err; | |
479 | ||
480 | switch (rq->type) { | |
481 | case PTP_CLK_REQ_EXTTS: | |
482 | switch (rq->extts.index) { | |
483 | case 0: | |
484 | ext = bp->ts0; | |
485 | break; | |
486 | case 1: | |
487 | ext = bp->ts1; | |
488 | break; | |
489 | } | |
490 | break; | |
491 | case PTP_CLK_REQ_PPS: | |
492 | ext = bp->pps; | |
493 | break; | |
494 | default: | |
495 | return -EOPNOTSUPP; | |
496 | } | |
497 | ||
498 | err = -ENXIO; | |
499 | if (ext) | |
500 | err = ext->info->enable(ext, on); | |
501 | ||
502 | return err; | |
503 | } | |
504 | ||
a7e1abad JL |
505 | static const struct ptp_clock_info ptp_ocp_clock_info = { |
506 | .owner = THIS_MODULE, | |
507 | .name = KBUILD_MODNAME, | |
508 | .max_adj = 100000000, | |
509 | .gettimex64 = ptp_ocp_gettimex, | |
510 | .settime64 = ptp_ocp_settime, | |
511 | .adjtime = ptp_ocp_adjtime, | |
512 | .adjfine = ptp_ocp_null_adjfine, | |
773bda96 JL |
513 | .adjphase = ptp_ocp_adjphase, |
514 | .enable = ptp_ocp_enable, | |
515 | .pps = true, | |
516 | .n_ext_ts = 2, | |
a7e1abad JL |
517 | }; |
518 | ||
773bda96 JL |
519 | static void |
520 | __ptp_ocp_clear_drift_locked(struct ptp_ocp *bp) | |
521 | { | |
522 | u32 ctrl, select; | |
523 | ||
524 | select = ioread32(&bp->reg->select); | |
525 | iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select); | |
526 | ||
527 | iowrite32(0, &bp->reg->drift_ns); | |
528 | ||
529 | ctrl = ioread32(&bp->reg->ctrl); | |
530 | ctrl |= OCP_CTRL_ADJUST_DRIFT; | |
531 | iowrite32(ctrl, &bp->reg->ctrl); | |
532 | ||
533 | /* restore clock selection */ | |
534 | iowrite32(select >> 16, &bp->reg->select); | |
535 | } | |
536 | ||
537 | static void | |
538 | ptp_ocp_watchdog(struct timer_list *t) | |
539 | { | |
540 | struct ptp_ocp *bp = from_timer(bp, t, watchdog); | |
541 | unsigned long flags; | |
542 | u32 status; | |
543 | ||
0d43d4f2 | 544 | status = ioread32(&bp->pps_to_clk->status); |
773bda96 JL |
545 | |
546 | if (status & PPS_STATUS_SUPERV_ERR) { | |
0d43d4f2 | 547 | iowrite32(status, &bp->pps_to_clk->status); |
ef0cfb34 | 548 | if (!bp->gnss_lost) { |
773bda96 JL |
549 | spin_lock_irqsave(&bp->lock, flags); |
550 | __ptp_ocp_clear_drift_locked(bp); | |
551 | spin_unlock_irqrestore(&bp->lock, flags); | |
ef0cfb34 | 552 | bp->gnss_lost = ktime_get_real_seconds(); |
773bda96 JL |
553 | } |
554 | ||
ef0cfb34 JL |
555 | } else if (bp->gnss_lost) { |
556 | bp->gnss_lost = 0; | |
773bda96 JL |
557 | } |
558 | ||
559 | mod_timer(&bp->watchdog, jiffies + HZ); | |
560 | } | |
561 | ||
a7e1abad | 562 | static int |
773bda96 | 563 | ptp_ocp_init_clock(struct ptp_ocp *bp) |
a7e1abad JL |
564 | { |
565 | struct timespec64 ts; | |
566 | bool sync; | |
567 | u32 ctrl; | |
568 | ||
569 | /* make sure clock is enabled */ | |
570 | ctrl = ioread32(&bp->reg->ctrl); | |
571 | ctrl |= OCP_CTRL_ENABLE; | |
572 | iowrite32(ctrl, &bp->reg->ctrl); | |
573 | ||
773bda96 JL |
574 | /* NO DRIFT Correction */ |
575 | /* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */ | |
576 | iowrite32(0x2000, &bp->reg->servo_offset_p); | |
577 | iowrite32(0x1000, &bp->reg->servo_offset_i); | |
578 | iowrite32(0, &bp->reg->servo_drift_p); | |
579 | iowrite32(0, &bp->reg->servo_drift_i); | |
580 | ||
581 | /* latch servo values */ | |
582 | ctrl |= OCP_CTRL_ADJUST_SERVO; | |
583 | iowrite32(ctrl, &bp->reg->ctrl); | |
584 | ||
a7e1abad JL |
585 | if ((ioread32(&bp->reg->ctrl) & OCP_CTRL_ENABLE) == 0) { |
586 | dev_err(&bp->pdev->dev, "clock not enabled\n"); | |
587 | return -ENODEV; | |
588 | } | |
589 | ||
590 | sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; | |
591 | if (!sync) { | |
592 | ktime_get_real_ts64(&ts); | |
593 | ptp_ocp_settime(&bp->ptp_info, &ts); | |
594 | } | |
595 | if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL)) | |
596 | dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n", | |
597 | ts.tv_sec, ts.tv_nsec, | |
598 | sync ? "in-sync" : "UNSYNCED"); | |
599 | ||
773bda96 JL |
600 | timer_setup(&bp->watchdog, ptp_ocp_watchdog, 0); |
601 | mod_timer(&bp->watchdog, jiffies + HZ); | |
602 | ||
a7e1abad JL |
603 | return 0; |
604 | } | |
605 | ||
606 | static void | |
607 | ptp_ocp_tod_info(struct ptp_ocp *bp) | |
608 | { | |
609 | static const char * const proto_name[] = { | |
610 | "NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none", | |
611 | "UBX", "UBX_UTC", "UBX_LS", "UBX_none" | |
612 | }; | |
613 | static const char * const gnss_name[] = { | |
614 | "ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU", | |
615 | }; | |
616 | u32 version, ctrl, reg; | |
617 | int idx; | |
618 | ||
619 | version = ioread32(&bp->tod->version); | |
620 | dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n", | |
621 | version >> 24, (version >> 16) & 0xff, version & 0xffff); | |
622 | ||
623 | ctrl = ioread32(&bp->tod->ctrl); | |
624 | ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE; | |
625 | ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B); | |
626 | iowrite32(ctrl, &bp->tod->ctrl); | |
627 | ||
628 | ctrl = ioread32(&bp->tod->ctrl); | |
629 | idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0; | |
630 | idx += (ctrl >> 16) & 3; | |
631 | dev_info(&bp->pdev->dev, "control: %x\n", ctrl); | |
632 | dev_info(&bp->pdev->dev, "TOD Protocol %s %s\n", proto_name[idx], | |
633 | ctrl & TOD_CTRL_ENABLE ? "enabled" : ""); | |
634 | ||
635 | idx = (ctrl >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK; | |
636 | if (idx < ARRAY_SIZE(gnss_name)) | |
637 | dev_info(&bp->pdev->dev, "GNSS %s\n", gnss_name[idx]); | |
638 | ||
639 | reg = ioread32(&bp->tod->status); | |
640 | dev_info(&bp->pdev->dev, "status: %x\n", reg); | |
641 | ||
642 | reg = ioread32(&bp->tod->correction_sec); | |
643 | dev_info(&bp->pdev->dev, "correction: %d\n", reg); | |
644 | ||
645 | reg = ioread32(&bp->tod->utc_status); | |
646 | dev_info(&bp->pdev->dev, "utc_status: %x\n", reg); | |
647 | dev_info(&bp->pdev->dev, "utc_offset: %d valid:%d leap_valid:%d\n", | |
648 | reg & TOD_STATUS_UTC_MASK, reg & TOD_STATUS_UTC_VALID ? 1 : 0, | |
649 | reg & TOD_STATUS_LEAP_VALID ? 1 : 0); | |
650 | } | |
651 | ||
773bda96 JL |
652 | static int |
653 | ptp_ocp_firstchild(struct device *dev, void *data) | |
654 | { | |
655 | return 1; | |
656 | } | |
657 | ||
658 | static int | |
659 | ptp_ocp_read_i2c(struct i2c_adapter *adap, u8 addr, u8 reg, u8 sz, u8 *data) | |
660 | { | |
661 | struct i2c_msg msgs[2] = { | |
662 | { | |
663 | .addr = addr, | |
664 | .len = 1, | |
665 | .buf = ®, | |
666 | }, | |
667 | { | |
668 | .addr = addr, | |
669 | .flags = I2C_M_RD, | |
670 | .len = 2, | |
671 | .buf = data, | |
672 | }, | |
673 | }; | |
674 | int err; | |
675 | u8 len; | |
676 | ||
677 | /* xiic-i2c for some stupid reason only does 2 byte reads. */ | |
678 | while (sz) { | |
679 | len = min_t(u8, sz, 2); | |
680 | msgs[1].len = len; | |
681 | err = i2c_transfer(adap, msgs, 2); | |
682 | if (err != msgs[1].len) | |
683 | return err; | |
684 | msgs[1].buf += len; | |
685 | reg += len; | |
686 | sz -= len; | |
687 | } | |
688 | return 0; | |
689 | } | |
690 | ||
691 | static void | |
692 | ptp_ocp_get_serial_number(struct ptp_ocp *bp) | |
693 | { | |
694 | struct i2c_adapter *adap; | |
695 | struct device *dev; | |
696 | int err; | |
697 | ||
698 | dev = device_find_child(&bp->i2c_ctrl->dev, NULL, ptp_ocp_firstchild); | |
699 | if (!dev) { | |
700 | dev_err(&bp->pdev->dev, "Can't find I2C adapter\n"); | |
701 | return; | |
702 | } | |
703 | ||
704 | adap = i2c_verify_adapter(dev); | |
705 | if (!adap) { | |
706 | dev_err(&bp->pdev->dev, "device '%s' isn't an I2C adapter\n", | |
707 | dev_name(dev)); | |
708 | goto out; | |
709 | } | |
710 | ||
711 | err = ptp_ocp_read_i2c(adap, 0x58, 0x9A, 6, bp->serial); | |
712 | if (err) { | |
713 | dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", err); | |
714 | goto out; | |
715 | } | |
716 | ||
717 | bp->has_serial = true; | |
718 | ||
719 | out: | |
720 | put_device(dev); | |
721 | } | |
722 | ||
a7e1abad JL |
723 | static void |
724 | ptp_ocp_info(struct ptp_ocp *bp) | |
725 | { | |
a7e1abad JL |
726 | u32 version, select; |
727 | ||
728 | version = ioread32(&bp->reg->version); | |
729 | select = ioread32(&bp->reg->select); | |
730 | dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n", | |
731 | version >> 24, (version >> 16) & 0xff, version & 0xffff, | |
773bda96 | 732 | ptp_ocp_clock_name_from_val(select >> 16), |
a7e1abad JL |
733 | ptp_clock_index(bp->ptp)); |
734 | ||
735 | ptp_ocp_tod_info(bp); | |
736 | } | |
737 | ||
773bda96 JL |
738 | static struct device * |
739 | ptp_ocp_find_flash(struct ptp_ocp *bp) | |
740 | { | |
741 | struct device *dev, *last; | |
742 | ||
743 | last = NULL; | |
744 | dev = &bp->spi_flash->dev; | |
745 | ||
746 | while ((dev = device_find_child(dev, NULL, ptp_ocp_firstchild))) { | |
747 | if (!strcmp("mtd", dev_bus_name(dev))) | |
748 | break; | |
749 | put_device(last); | |
750 | last = dev; | |
751 | } | |
752 | put_device(last); | |
753 | ||
754 | return dev; | |
755 | } | |
756 | ||
757 | static int | |
758 | ptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev, | |
759 | const struct firmware *fw) | |
760 | { | |
761 | struct mtd_info *mtd = dev_get_drvdata(dev); | |
762 | struct ptp_ocp *bp = devlink_priv(devlink); | |
763 | size_t off, len, resid, wrote; | |
764 | struct erase_info erase; | |
765 | size_t base, blksz; | |
7c807572 | 766 | int err = 0; |
773bda96 JL |
767 | |
768 | off = 0; | |
769 | base = bp->flash_start; | |
770 | blksz = 4096; | |
771 | resid = fw->size; | |
772 | ||
773 | while (resid) { | |
774 | devlink_flash_update_status_notify(devlink, "Flashing", | |
775 | NULL, off, fw->size); | |
776 | ||
777 | len = min_t(size_t, resid, blksz); | |
778 | erase.addr = base + off; | |
779 | erase.len = blksz; | |
780 | ||
781 | err = mtd_erase(mtd, &erase); | |
782 | if (err) | |
783 | goto out; | |
784 | ||
785 | err = mtd_write(mtd, base + off, len, &wrote, &fw->data[off]); | |
786 | if (err) | |
787 | goto out; | |
788 | ||
789 | off += blksz; | |
790 | resid -= len; | |
791 | } | |
792 | out: | |
793 | return err; | |
794 | } | |
795 | ||
796 | static int | |
797 | ptp_ocp_devlink_flash_update(struct devlink *devlink, | |
798 | struct devlink_flash_update_params *params, | |
799 | struct netlink_ext_ack *extack) | |
800 | { | |
801 | struct ptp_ocp *bp = devlink_priv(devlink); | |
802 | struct device *dev; | |
803 | const char *msg; | |
804 | int err; | |
805 | ||
806 | dev = ptp_ocp_find_flash(bp); | |
807 | if (!dev) { | |
808 | dev_err(&bp->pdev->dev, "Can't find Flash SPI adapter\n"); | |
809 | return -ENODEV; | |
810 | } | |
811 | ||
812 | devlink_flash_update_status_notify(devlink, "Preparing to flash", | |
813 | NULL, 0, 0); | |
814 | ||
815 | err = ptp_ocp_devlink_flash(devlink, dev, params->fw); | |
816 | ||
817 | msg = err ? "Flash error" : "Flash complete"; | |
818 | devlink_flash_update_status_notify(devlink, msg, NULL, 0, 0); | |
819 | ||
773bda96 JL |
820 | put_device(dev); |
821 | return err; | |
822 | } | |
823 | ||
824 | static int | |
825 | ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, | |
826 | struct netlink_ext_ack *extack) | |
827 | { | |
828 | struct ptp_ocp *bp = devlink_priv(devlink); | |
829 | char buf[32]; | |
830 | int err; | |
831 | ||
832 | err = devlink_info_driver_name_put(req, KBUILD_MODNAME); | |
833 | if (err) | |
834 | return err; | |
835 | ||
773bda96 JL |
836 | if (bp->image) { |
837 | u32 ver = ioread32(&bp->image->version); | |
838 | ||
839 | if (ver & 0xffff) { | |
840 | sprintf(buf, "%d", ver); | |
841 | err = devlink_info_version_running_put(req, | |
1a052da9 | 842 | "fw", |
773bda96 JL |
843 | buf); |
844 | } else { | |
845 | sprintf(buf, "%d", ver >> 16); | |
846 | err = devlink_info_version_running_put(req, | |
1a052da9 | 847 | "loader", |
773bda96 JL |
848 | buf); |
849 | } | |
850 | if (err) | |
851 | return err; | |
852 | } | |
853 | ||
854 | if (!bp->has_serial) | |
855 | ptp_ocp_get_serial_number(bp); | |
856 | ||
857 | if (bp->has_serial) { | |
858 | sprintf(buf, "%pM", bp->serial); | |
859 | err = devlink_info_serial_number_put(req, buf); | |
860 | if (err) | |
861 | return err; | |
862 | } | |
863 | ||
864 | return 0; | |
865 | } | |
866 | ||
867 | static const struct devlink_ops ptp_ocp_devlink_ops = { | |
868 | .flash_update = ptp_ocp_devlink_flash_update, | |
869 | .info_get = ptp_ocp_devlink_info_get, | |
870 | }; | |
871 | ||
773bda96 JL |
872 | static void __iomem * |
873 | __ptp_ocp_get_mem(struct ptp_ocp *bp, unsigned long start, int size) | |
874 | { | |
875 | struct resource res = DEFINE_RES_MEM_NAMED(start, size, "ptp_ocp"); | |
876 | ||
877 | return devm_ioremap_resource(&bp->pdev->dev, &res); | |
878 | } | |
879 | ||
880 | static void __iomem * | |
881 | ptp_ocp_get_mem(struct ptp_ocp *bp, struct ocp_resource *r) | |
882 | { | |
883 | unsigned long start; | |
884 | ||
885 | start = pci_resource_start(bp->pdev, 0) + r->offset; | |
886 | return __ptp_ocp_get_mem(bp, start, r->size); | |
887 | } | |
888 | ||
889 | static void | |
890 | ptp_ocp_set_irq_resource(struct resource *res, int irq) | |
891 | { | |
892 | struct resource r = DEFINE_RES_IRQ(irq); | |
893 | *res = r; | |
894 | } | |
895 | ||
896 | static void | |
897 | ptp_ocp_set_mem_resource(struct resource *res, unsigned long start, int size) | |
898 | { | |
899 | struct resource r = DEFINE_RES_MEM(start, size); | |
900 | *res = r; | |
901 | } | |
902 | ||
903 | static int | |
904 | ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r) | |
905 | { | |
906 | struct ptp_ocp_flash_info *info; | |
907 | struct pci_dev *pdev = bp->pdev; | |
908 | struct platform_device *p; | |
909 | struct resource res[2]; | |
910 | unsigned long start; | |
911 | int id; | |
912 | ||
913 | /* XXX hack to work around old FPGA */ | |
914 | if (bp->n_irqs < 10) { | |
915 | dev_err(&bp->pdev->dev, "FPGA does not have SPI devices\n"); | |
916 | return 0; | |
917 | } | |
918 | ||
919 | if (r->irq_vec > bp->n_irqs) { | |
920 | dev_err(&bp->pdev->dev, "spi device irq %d out of range\n", | |
921 | r->irq_vec); | |
922 | return 0; | |
923 | } | |
924 | ||
925 | start = pci_resource_start(pdev, 0) + r->offset; | |
926 | ptp_ocp_set_mem_resource(&res[0], start, r->size); | |
927 | ptp_ocp_set_irq_resource(&res[1], pci_irq_vector(pdev, r->irq_vec)); | |
928 | ||
929 | info = r->extra; | |
930 | id = pci_dev_id(pdev) << 1; | |
931 | id += info->pci_offset; | |
932 | ||
933 | p = platform_device_register_resndata(&pdev->dev, info->name, id, | |
934 | res, 2, info->data, | |
935 | info->data_size); | |
936 | if (IS_ERR(p)) | |
937 | return PTR_ERR(p); | |
938 | ||
939 | bp_assign_entry(bp, r, p); | |
940 | ||
941 | return 0; | |
942 | } | |
943 | ||
944 | static struct platform_device * | |
945 | ptp_ocp_i2c_bus(struct pci_dev *pdev, struct ocp_resource *r, int id) | |
946 | { | |
947 | struct resource res[2]; | |
948 | unsigned long start; | |
949 | ||
950 | start = pci_resource_start(pdev, 0) + r->offset; | |
951 | ptp_ocp_set_mem_resource(&res[0], start, r->size); | |
952 | ptp_ocp_set_irq_resource(&res[1], pci_irq_vector(pdev, r->irq_vec)); | |
953 | ||
954 | return platform_device_register_resndata(&pdev->dev, "xiic-i2c", | |
955 | id, res, 2, NULL, 0); | |
956 | } | |
957 | ||
958 | static int | |
959 | ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r) | |
960 | { | |
961 | struct pci_dev *pdev = bp->pdev; | |
962 | struct platform_device *p; | |
963 | struct clk_hw *clk; | |
964 | char buf[32]; | |
965 | int id; | |
966 | ||
967 | if (r->irq_vec > bp->n_irqs) { | |
968 | dev_err(&bp->pdev->dev, "i2c device irq %d out of range\n", | |
969 | r->irq_vec); | |
970 | return 0; | |
971 | } | |
972 | ||
973 | id = pci_dev_id(bp->pdev); | |
974 | ||
975 | sprintf(buf, "AXI.%d", id); | |
976 | clk = clk_hw_register_fixed_rate(&pdev->dev, buf, NULL, 0, 50000000); | |
977 | if (IS_ERR(clk)) | |
978 | return PTR_ERR(clk); | |
979 | bp->i2c_clk = clk; | |
980 | ||
981 | sprintf(buf, "xiic-i2c.%d", id); | |
982 | devm_clk_hw_register_clkdev(&pdev->dev, clk, NULL, buf); | |
983 | p = ptp_ocp_i2c_bus(bp->pdev, r, id); | |
984 | if (IS_ERR(p)) | |
985 | return PTR_ERR(p); | |
986 | ||
987 | bp_assign_entry(bp, r, p); | |
988 | ||
989 | return 0; | |
990 | } | |
991 | ||
992 | static irqreturn_t | |
993 | ptp_ocp_ts_irq(int irq, void *priv) | |
994 | { | |
995 | struct ptp_ocp_ext_src *ext = priv; | |
996 | struct ts_reg __iomem *reg = ext->mem; | |
997 | struct ptp_clock_event ev; | |
998 | u32 sec, nsec; | |
999 | ||
1000 | /* XXX should fix API - this converts s/ns -> ts -> s/ns */ | |
1001 | sec = ioread32(®->time_sec); | |
1002 | nsec = ioread32(®->time_ns); | |
1003 | ||
1004 | ev.type = PTP_CLOCK_EXTTS; | |
1005 | ev.index = ext->info->index; | |
1006 | ev.timestamp = sec * 1000000000ULL + nsec; | |
1007 | ||
1008 | ptp_clock_event(ext->bp->ptp, &ev); | |
1009 | ||
1010 | iowrite32(1, ®->intr); /* write 1 to ack */ | |
1011 | ||
1012 | return IRQ_HANDLED; | |
1013 | } | |
1014 | ||
1015 | static int | |
1016 | ptp_ocp_ts_enable(void *priv, bool enable) | |
1017 | { | |
1018 | struct ptp_ocp_ext_src *ext = priv; | |
1019 | struct ts_reg __iomem *reg = ext->mem; | |
1020 | ||
1021 | if (enable) { | |
1022 | iowrite32(1, ®->enable); | |
1023 | iowrite32(1, ®->intr_mask); | |
1024 | iowrite32(1, ®->intr); | |
1025 | } else { | |
1026 | iowrite32(0, ®->intr_mask); | |
1027 | iowrite32(0, ®->enable); | |
1028 | } | |
1029 | ||
1030 | return 0; | |
1031 | } | |
1032 | ||
1033 | static void | |
1034 | ptp_ocp_unregister_ext(struct ptp_ocp_ext_src *ext) | |
1035 | { | |
1036 | ext->info->enable(ext, false); | |
1037 | pci_free_irq(ext->bp->pdev, ext->irq_vec, ext); | |
1038 | kfree(ext); | |
1039 | } | |
1040 | ||
1041 | static int | |
1042 | ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r) | |
1043 | { | |
1044 | struct pci_dev *pdev = bp->pdev; | |
1045 | struct ptp_ocp_ext_src *ext; | |
1046 | int err; | |
1047 | ||
1048 | ext = kzalloc(sizeof(*ext), GFP_KERNEL); | |
1049 | if (!ext) | |
a7e1abad | 1050 | return -ENOMEM; |
a7e1abad | 1051 | |
773bda96 JL |
1052 | err = -EINVAL; |
1053 | ext->mem = ptp_ocp_get_mem(bp, r); | |
1054 | if (!ext->mem) | |
1055 | goto out; | |
1056 | ||
1057 | ext->bp = bp; | |
1058 | ext->info = r->extra; | |
1059 | ext->irq_vec = r->irq_vec; | |
1060 | ||
1061 | err = pci_request_irq(pdev, r->irq_vec, ext->info->irq_fcn, NULL, | |
1062 | ext, "ocp%d.%s", bp->id, ext->info->name); | |
a7e1abad | 1063 | if (err) { |
773bda96 JL |
1064 | dev_err(&pdev->dev, "Could not get irq %d\n", r->irq_vec); |
1065 | goto out; | |
a7e1abad JL |
1066 | } |
1067 | ||
773bda96 JL |
1068 | bp_assign_entry(bp, r, ext); |
1069 | ||
1070 | return 0; | |
1071 | ||
1072 | out: | |
1073 | kfree(ext); | |
1074 | return err; | |
1075 | } | |
1076 | ||
1077 | static int | |
1078 | ptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r) | |
1079 | { | |
1080 | struct pci_dev *pdev = bp->pdev; | |
1081 | struct uart_8250_port uart; | |
1082 | ||
1083 | /* Setting UPF_IOREMAP and leaving port.membase unspecified lets | |
1084 | * the serial port device claim and release the pci resource. | |
1085 | */ | |
1086 | memset(&uart, 0, sizeof(uart)); | |
1087 | uart.port.dev = &pdev->dev; | |
1088 | uart.port.iotype = UPIO_MEM; | |
1089 | uart.port.regshift = 2; | |
1090 | uart.port.mapbase = pci_resource_start(pdev, 0) + r->offset; | |
1091 | uart.port.irq = pci_irq_vector(pdev, r->irq_vec); | |
1092 | uart.port.uartclk = 50000000; | |
1093 | uart.port.flags = UPF_FIXED_TYPE | UPF_IOREMAP; | |
1094 | uart.port.type = PORT_16550A; | |
1095 | ||
1096 | return serial8250_register_8250_port(&uart); | |
1097 | } | |
1098 | ||
1099 | static int | |
1100 | ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r) | |
1101 | { | |
1102 | int port; | |
1103 | ||
1104 | if (r->irq_vec > bp->n_irqs) { | |
1105 | dev_err(&bp->pdev->dev, "serial device irq %d out of range\n", | |
1106 | r->irq_vec); | |
1107 | return 0; | |
a7e1abad JL |
1108 | } |
1109 | ||
773bda96 JL |
1110 | port = ptp_ocp_serial_line(bp, r); |
1111 | if (port < 0) | |
1112 | return port; | |
1113 | ||
1114 | bp_assign_entry(bp, r, port); | |
1115 | ||
1116 | return 0; | |
1117 | } | |
1118 | ||
1119 | static int | |
1120 | ptp_ocp_register_mem(struct ptp_ocp *bp, struct ocp_resource *r) | |
1121 | { | |
1122 | void __iomem *mem; | |
1123 | ||
1124 | mem = ptp_ocp_get_mem(bp, r); | |
1125 | if (!mem) | |
1126 | return -EINVAL; | |
1127 | ||
1128 | bp_assign_entry(bp, r, mem); | |
1129 | ||
1130 | return 0; | |
1131 | } | |
1132 | ||
1133 | /* FB specific board initializers; last "resource" registered. */ | |
1134 | static int | |
1135 | ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r) | |
1136 | { | |
1137 | bp->flash_start = 1024 * 4096; | |
1138 | ||
1139 | return ptp_ocp_init_clock(bp); | |
1140 | } | |
1141 | ||
1142 | static int | |
1143 | ptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data) | |
1144 | { | |
1145 | struct ocp_resource *r, *table; | |
1146 | int err = 0; | |
1147 | ||
1148 | table = (struct ocp_resource *)driver_data; | |
1149 | for (r = table; r->setup; r++) { | |
1150 | err = r->setup(bp, r); | |
1151 | if (err) | |
1152 | break; | |
a7e1abad | 1153 | } |
773bda96 JL |
1154 | return err; |
1155 | } | |
1156 | ||
1157 | static ssize_t | |
1158 | serialnum_show(struct device *dev, struct device_attribute *attr, char *buf) | |
1159 | { | |
1160 | struct ptp_ocp *bp = dev_get_drvdata(dev); | |
1161 | ||
1162 | if (!bp->has_serial) | |
1163 | ptp_ocp_get_serial_number(bp); | |
1164 | ||
1165 | return sysfs_emit(buf, "%pM\n", bp->serial); | |
1166 | } | |
1167 | static DEVICE_ATTR_RO(serialnum); | |
1168 | ||
1169 | static ssize_t | |
ef0cfb34 | 1170 | gnss_sync_show(struct device *dev, struct device_attribute *attr, char *buf) |
773bda96 JL |
1171 | { |
1172 | struct ptp_ocp *bp = dev_get_drvdata(dev); | |
1173 | ssize_t ret; | |
1174 | ||
ef0cfb34 JL |
1175 | if (bp->gnss_lost) |
1176 | ret = sysfs_emit(buf, "LOST @ %ptT\n", &bp->gnss_lost); | |
773bda96 JL |
1177 | else |
1178 | ret = sysfs_emit(buf, "SYNC\n"); | |
1179 | ||
1180 | return ret; | |
1181 | } | |
ef0cfb34 | 1182 | static DEVICE_ATTR_RO(gnss_sync); |
773bda96 JL |
1183 | |
1184 | static ssize_t | |
1185 | clock_source_show(struct device *dev, struct device_attribute *attr, char *buf) | |
1186 | { | |
1187 | struct ptp_ocp *bp = dev_get_drvdata(dev); | |
1188 | const char *p; | |
1189 | u32 select; | |
1190 | ||
1191 | select = ioread32(&bp->reg->select); | |
1192 | p = ptp_ocp_clock_name_from_val(select >> 16); | |
1193 | ||
1194 | return sysfs_emit(buf, "%s\n", p); | |
1195 | } | |
1196 | ||
1197 | static ssize_t | |
1198 | clock_source_store(struct device *dev, struct device_attribute *attr, | |
1199 | const char *buf, size_t count) | |
1200 | { | |
1201 | struct ptp_ocp *bp = dev_get_drvdata(dev); | |
1202 | unsigned long flags; | |
1203 | int val; | |
1204 | ||
1205 | val = ptp_ocp_clock_val_from_name(buf); | |
1206 | if (val < 0) | |
1207 | return val; | |
1208 | ||
1209 | spin_lock_irqsave(&bp->lock, flags); | |
1210 | iowrite32(val, &bp->reg->select); | |
1211 | spin_unlock_irqrestore(&bp->lock, flags); | |
1212 | ||
1213 | return count; | |
1214 | } | |
1215 | static DEVICE_ATTR_RW(clock_source); | |
1216 | ||
1217 | static ssize_t | |
1218 | available_clock_sources_show(struct device *dev, | |
1219 | struct device_attribute *attr, char *buf) | |
1220 | { | |
1221 | const char *clk; | |
1222 | ssize_t count; | |
1223 | int i; | |
1224 | ||
1225 | count = 0; | |
1226 | for (i = 0; i < ARRAY_SIZE(ptp_ocp_clock); i++) { | |
1227 | clk = ptp_ocp_clock[i].name; | |
1228 | count += sysfs_emit_at(buf, count, "%s ", clk); | |
1229 | } | |
1230 | if (count) | |
1231 | count--; | |
1232 | count += sysfs_emit_at(buf, count, "\n"); | |
1233 | return count; | |
1234 | } | |
1235 | static DEVICE_ATTR_RO(available_clock_sources); | |
1236 | ||
1237 | static struct attribute *timecard_attrs[] = { | |
1238 | &dev_attr_serialnum.attr, | |
ef0cfb34 | 1239 | &dev_attr_gnss_sync.attr, |
773bda96 JL |
1240 | &dev_attr_clock_source.attr, |
1241 | &dev_attr_available_clock_sources.attr, | |
1242 | NULL, | |
1243 | }; | |
1244 | ATTRIBUTE_GROUPS(timecard); | |
1245 | ||
1246 | static void | |
1247 | ptp_ocp_dev_release(struct device *dev) | |
1248 | { | |
1249 | struct ptp_ocp *bp = dev_get_drvdata(dev); | |
1250 | ||
1251 | mutex_lock(&ptp_ocp_lock); | |
1252 | idr_remove(&ptp_ocp_idr, bp->id); | |
1253 | mutex_unlock(&ptp_ocp_lock); | |
1254 | } | |
1255 | ||
1256 | static int | |
1257 | ptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev) | |
1258 | { | |
1259 | int err; | |
1260 | ||
1261 | mutex_lock(&ptp_ocp_lock); | |
1262 | err = idr_alloc(&ptp_ocp_idr, bp, 0, 0, GFP_KERNEL); | |
1263 | mutex_unlock(&ptp_ocp_lock); | |
1264 | if (err < 0) { | |
1265 | dev_err(&pdev->dev, "idr_alloc failed: %d\n", err); | |
1266 | return err; | |
1267 | } | |
1268 | bp->id = err; | |
1269 | ||
a7e1abad JL |
1270 | bp->ptp_info = ptp_ocp_clock_info; |
1271 | spin_lock_init(&bp->lock); | |
ef0cfb34 | 1272 | bp->gnss_port = -1; |
773bda96 JL |
1273 | bp->mac_port = -1; |
1274 | bp->pdev = pdev; | |
1275 | ||
1276 | device_initialize(&bp->dev); | |
1277 | dev_set_name(&bp->dev, "ocp%d", bp->id); | |
1278 | bp->dev.class = &timecard_class; | |
1279 | bp->dev.parent = &pdev->dev; | |
1280 | bp->dev.release = ptp_ocp_dev_release; | |
1281 | dev_set_drvdata(&bp->dev, bp); | |
1282 | ||
1283 | err = device_add(&bp->dev); | |
1284 | if (err) { | |
1285 | dev_err(&bp->dev, "device add failed: %d\n", err); | |
773bda96 JL |
1286 | goto out; |
1287 | } | |
1288 | ||
1289 | pci_set_drvdata(pdev, bp); | |
1290 | ||
1291 | return 0; | |
1292 | ||
1293 | out: | |
1294 | ptp_ocp_dev_release(&bp->dev); | |
d12f23fa | 1295 | put_device(&bp->dev); |
773bda96 JL |
1296 | return err; |
1297 | } | |
1298 | ||
1299 | static void | |
1300 | ptp_ocp_symlink(struct ptp_ocp *bp, struct device *child, const char *link) | |
1301 | { | |
1302 | struct device *dev = &bp->dev; | |
1303 | ||
1304 | if (sysfs_create_link(&dev->kobj, &child->kobj, link)) | |
1305 | dev_err(dev, "%s symlink failed\n", link); | |
1306 | } | |
1307 | ||
1308 | static void | |
1309 | ptp_ocp_link_child(struct ptp_ocp *bp, const char *name, const char *link) | |
1310 | { | |
1311 | struct device *dev, *child; | |
1312 | ||
1313 | dev = &bp->pdev->dev; | |
1314 | ||
1315 | child = device_find_child_by_name(dev, name); | |
1316 | if (!child) { | |
1317 | dev_err(dev, "Could not find device %s\n", name); | |
1318 | return; | |
1319 | } | |
1320 | ||
1321 | ptp_ocp_symlink(bp, child, link); | |
1322 | put_device(child); | |
1323 | } | |
1324 | ||
1325 | static int | |
1326 | ptp_ocp_complete(struct ptp_ocp *bp) | |
1327 | { | |
1328 | struct pps_device *pps; | |
1329 | char buf[32]; | |
1330 | ||
ef0cfb34 JL |
1331 | if (bp->gnss_port != -1) { |
1332 | sprintf(buf, "ttyS%d", bp->gnss_port); | |
1333 | ptp_ocp_link_child(bp, buf, "ttyGNSS"); | |
773bda96 JL |
1334 | } |
1335 | if (bp->mac_port != -1) { | |
1336 | sprintf(buf, "ttyS%d", bp->mac_port); | |
1337 | ptp_ocp_link_child(bp, buf, "ttyMAC"); | |
1338 | } | |
1339 | sprintf(buf, "ptp%d", ptp_clock_index(bp->ptp)); | |
1340 | ptp_ocp_link_child(bp, buf, "ptp"); | |
1341 | ||
1342 | pps = pps_lookup_dev(bp->ptp); | |
1343 | if (pps) | |
1344 | ptp_ocp_symlink(bp, pps->dev, "pps"); | |
1345 | ||
1346 | if (device_add_groups(&bp->dev, timecard_groups)) | |
1347 | pr_err("device add groups failed\n"); | |
1348 | ||
1349 | return 0; | |
1350 | } | |
1351 | ||
1352 | static void | |
1353 | ptp_ocp_resource_summary(struct ptp_ocp *bp) | |
1354 | { | |
1355 | struct device *dev = &bp->pdev->dev; | |
1356 | ||
1357 | if (bp->image) { | |
1358 | u32 ver = ioread32(&bp->image->version); | |
1359 | ||
1360 | dev_info(dev, "version %x\n", ver); | |
1361 | if (ver & 0xffff) | |
1362 | dev_info(dev, "regular image, version %d\n", | |
1363 | ver & 0xffff); | |
1364 | else | |
1365 | dev_info(dev, "golden image, version %d\n", | |
1366 | ver >> 16); | |
1367 | } | |
ef0cfb34 JL |
1368 | if (bp->gnss_port != -1) |
1369 | dev_info(dev, "GNSS @ /dev/ttyS%d 115200\n", bp->gnss_port); | |
773bda96 JL |
1370 | if (bp->mac_port != -1) |
1371 | dev_info(dev, "MAC @ /dev/ttyS%d 57600\n", bp->mac_port); | |
1372 | } | |
a7e1abad | 1373 | |
773bda96 JL |
1374 | static void |
1375 | ptp_ocp_detach_sysfs(struct ptp_ocp *bp) | |
1376 | { | |
1377 | struct device *dev = &bp->dev; | |
1378 | ||
ef0cfb34 | 1379 | sysfs_remove_link(&dev->kobj, "ttyGNSS"); |
773bda96 JL |
1380 | sysfs_remove_link(&dev->kobj, "ttyMAC"); |
1381 | sysfs_remove_link(&dev->kobj, "ptp"); | |
1382 | sysfs_remove_link(&dev->kobj, "pps"); | |
1383 | device_remove_groups(dev, timecard_groups); | |
1384 | } | |
1385 | ||
1386 | static void | |
1387 | ptp_ocp_detach(struct ptp_ocp *bp) | |
1388 | { | |
1389 | ptp_ocp_detach_sysfs(bp); | |
1390 | if (timer_pending(&bp->watchdog)) | |
1391 | del_timer_sync(&bp->watchdog); | |
1392 | if (bp->ts0) | |
1393 | ptp_ocp_unregister_ext(bp->ts0); | |
1394 | if (bp->ts1) | |
1395 | ptp_ocp_unregister_ext(bp->ts1); | |
1396 | if (bp->pps) | |
1397 | ptp_ocp_unregister_ext(bp->pps); | |
ef0cfb34 JL |
1398 | if (bp->gnss_port != -1) |
1399 | serial8250_unregister_port(bp->gnss_port); | |
773bda96 JL |
1400 | if (bp->mac_port != -1) |
1401 | serial8250_unregister_port(bp->mac_port); | |
1402 | if (bp->spi_flash) | |
1403 | platform_device_unregister(bp->spi_flash); | |
1404 | if (bp->i2c_ctrl) | |
1405 | platform_device_unregister(bp->i2c_ctrl); | |
1406 | if (bp->i2c_clk) | |
1407 | clk_hw_unregister_fixed_rate(bp->i2c_clk); | |
1408 | if (bp->n_irqs) | |
1409 | pci_free_irq_vectors(bp->pdev); | |
1410 | if (bp->ptp) | |
1411 | ptp_clock_unregister(bp->ptp); | |
773bda96 JL |
1412 | device_unregister(&bp->dev); |
1413 | } | |
1414 | ||
1415 | static int | |
1416 | ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |
1417 | { | |
1418 | struct devlink *devlink; | |
1419 | struct ptp_ocp *bp; | |
1420 | int err; | |
1421 | ||
919d13a7 | 1422 | devlink = devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev); |
773bda96 JL |
1423 | if (!devlink) { |
1424 | dev_err(&pdev->dev, "devlink_alloc failed\n"); | |
1425 | return -ENOMEM; | |
1426 | } | |
1427 | ||
919d13a7 | 1428 | err = devlink_register(devlink); |
773bda96 JL |
1429 | if (err) |
1430 | goto out_free; | |
1431 | ||
1432 | err = pci_enable_device(pdev); | |
1433 | if (err) { | |
1434 | dev_err(&pdev->dev, "pci_enable_device\n"); | |
1435 | goto out_unregister; | |
1436 | } | |
1437 | ||
1438 | bp = devlink_priv(devlink); | |
1439 | err = ptp_ocp_device_init(bp, pdev); | |
1440 | if (err) | |
d9fdbf13 | 1441 | goto out_disable; |
773bda96 JL |
1442 | |
1443 | /* compat mode. | |
1444 | * Older FPGA firmware only returns 2 irq's. | |
1445 | * allow this - if not all of the IRQ's are returned, skip the | |
1446 | * extra devices and just register the clock. | |
1447 | */ | |
1448 | err = pci_alloc_irq_vectors(pdev, 1, 10, PCI_IRQ_MSI | PCI_IRQ_MSIX); | |
1449 | if (err < 0) { | |
1450 | dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err); | |
1451 | goto out; | |
1452 | } | |
1453 | bp->n_irqs = err; | |
1454 | pci_set_master(pdev); | |
1455 | ||
1456 | err = ptp_ocp_register_resources(bp, id->driver_data); | |
a7e1abad JL |
1457 | if (err) |
1458 | goto out; | |
1459 | ||
1460 | bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev); | |
1461 | if (IS_ERR(bp->ptp)) { | |
a7e1abad | 1462 | err = PTR_ERR(bp->ptp); |
773bda96 JL |
1463 | dev_err(&pdev->dev, "ptp_clock_register: %d\n", err); |
1464 | bp->ptp = NULL; | |
a7e1abad JL |
1465 | goto out; |
1466 | } | |
1467 | ||
773bda96 JL |
1468 | err = ptp_ocp_complete(bp); |
1469 | if (err) | |
1470 | goto out; | |
1471 | ||
a7e1abad | 1472 | ptp_ocp_info(bp); |
773bda96 | 1473 | ptp_ocp_resource_summary(bp); |
a7e1abad JL |
1474 | |
1475 | return 0; | |
1476 | ||
1477 | out: | |
773bda96 | 1478 | ptp_ocp_detach(bp); |
773bda96 | 1479 | pci_set_drvdata(pdev, NULL); |
d9fdbf13 JL |
1480 | out_disable: |
1481 | pci_disable_device(pdev); | |
773bda96 | 1482 | out_unregister: |
919d13a7 | 1483 | devlink_unregister(devlink); |
a7e1abad | 1484 | out_free: |
773bda96 | 1485 | devlink_free(devlink); |
a7e1abad JL |
1486 | |
1487 | return err; | |
1488 | } | |
1489 | ||
1490 | static void | |
1491 | ptp_ocp_remove(struct pci_dev *pdev) | |
1492 | { | |
1493 | struct ptp_ocp *bp = pci_get_drvdata(pdev); | |
773bda96 | 1494 | struct devlink *devlink = priv_to_devlink(bp); |
a7e1abad | 1495 | |
773bda96 | 1496 | ptp_ocp_detach(bp); |
a7e1abad | 1497 | pci_set_drvdata(pdev, NULL); |
d9fdbf13 | 1498 | pci_disable_device(pdev); |
773bda96 | 1499 | |
919d13a7 | 1500 | devlink_unregister(devlink); |
773bda96 | 1501 | devlink_free(devlink); |
a7e1abad JL |
1502 | } |
1503 | ||
1504 | static struct pci_driver ptp_ocp_driver = { | |
1505 | .name = KBUILD_MODNAME, | |
1506 | .id_table = ptp_ocp_pcidev_id, | |
1507 | .probe = ptp_ocp_probe, | |
1508 | .remove = ptp_ocp_remove, | |
1509 | }; | |
1510 | ||
773bda96 JL |
1511 | static int |
1512 | ptp_ocp_i2c_notifier_call(struct notifier_block *nb, | |
1513 | unsigned long action, void *data) | |
1514 | { | |
1515 | struct device *dev, *child = data; | |
1516 | struct ptp_ocp *bp; | |
1517 | bool add; | |
1518 | ||
1519 | switch (action) { | |
1520 | case BUS_NOTIFY_ADD_DEVICE: | |
1521 | case BUS_NOTIFY_DEL_DEVICE: | |
1522 | add = action == BUS_NOTIFY_ADD_DEVICE; | |
1523 | break; | |
1524 | default: | |
1525 | return 0; | |
1526 | } | |
1527 | ||
1528 | if (!i2c_verify_adapter(child)) | |
1529 | return 0; | |
1530 | ||
1531 | dev = child; | |
1532 | while ((dev = dev->parent)) | |
1533 | if (dev->driver && !strcmp(dev->driver->name, KBUILD_MODNAME)) | |
1534 | goto found; | |
1535 | return 0; | |
1536 | ||
1537 | found: | |
1538 | bp = dev_get_drvdata(dev); | |
1539 | if (add) | |
1540 | ptp_ocp_symlink(bp, child, "i2c"); | |
1541 | else | |
1542 | sysfs_remove_link(&bp->dev.kobj, "i2c"); | |
1543 | ||
1544 | return 0; | |
1545 | } | |
1546 | ||
1547 | static struct notifier_block ptp_ocp_i2c_notifier = { | |
1548 | .notifier_call = ptp_ocp_i2c_notifier_call, | |
1549 | }; | |
1550 | ||
a7e1abad JL |
1551 | static int __init |
1552 | ptp_ocp_init(void) | |
1553 | { | |
773bda96 | 1554 | const char *what; |
a7e1abad JL |
1555 | int err; |
1556 | ||
773bda96 JL |
1557 | what = "timecard class"; |
1558 | err = class_register(&timecard_class); | |
1559 | if (err) | |
1560 | goto out; | |
1561 | ||
1562 | what = "i2c notifier"; | |
1563 | err = bus_register_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier); | |
1564 | if (err) | |
1565 | goto out_notifier; | |
1566 | ||
1567 | what = "ptp_ocp driver"; | |
a7e1abad | 1568 | err = pci_register_driver(&ptp_ocp_driver); |
773bda96 JL |
1569 | if (err) |
1570 | goto out_register; | |
1571 | ||
1572 | return 0; | |
1573 | ||
1574 | out_register: | |
1575 | bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier); | |
1576 | out_notifier: | |
1577 | class_unregister(&timecard_class); | |
1578 | out: | |
1579 | pr_err(KBUILD_MODNAME ": failed to register %s: %d\n", what, err); | |
a7e1abad JL |
1580 | return err; |
1581 | } | |
1582 | ||
1583 | static void __exit | |
1584 | ptp_ocp_fini(void) | |
1585 | { | |
773bda96 | 1586 | bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier); |
a7e1abad | 1587 | pci_unregister_driver(&ptp_ocp_driver); |
773bda96 | 1588 | class_unregister(&timecard_class); |
a7e1abad JL |
1589 | } |
1590 | ||
1591 | module_init(ptp_ocp_init); | |
1592 | module_exit(ptp_ocp_fini); | |
1593 | ||
1594 | MODULE_DESCRIPTION("OpenCompute TimeCard driver"); | |
1595 | MODULE_LICENSE("GPL v2"); |