Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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>
  9#include <linux/ptp_clock_kernel.h>
 10
 11static const struct pci_device_id ptp_ocp_pcidev_id[] = {
 12	{ PCI_DEVICE(0x1d9b, 0x0400) },
 13	{ 0 }
 14};
 15MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
 16
 17#define OCP_REGISTER_OFFSET	0x01000000
 18
 19struct ocp_reg {
 20	u32	ctrl;
 21	u32	status;
 22	u32	select;
 23	u32	version;
 24	u32	time_ns;
 25	u32	time_sec;
 26	u32	__pad0[2];
 27	u32	adjust_ns;
 28	u32	adjust_sec;
 29	u32	__pad1[2];
 30	u32	offset_ns;
 31	u32	offset_window_ns;
 32};
 33
 34#define OCP_CTRL_ENABLE		BIT(0)
 35#define OCP_CTRL_ADJUST_TIME	BIT(1)
 36#define OCP_CTRL_ADJUST_OFFSET	BIT(2)
 37#define OCP_CTRL_READ_TIME_REQ	BIT(30)
 38#define OCP_CTRL_READ_TIME_DONE	BIT(31)
 39
 40#define OCP_STATUS_IN_SYNC	BIT(0)
 41
 42#define OCP_SELECT_CLK_NONE	0
 43#define OCP_SELECT_CLK_REG	6
 44
 45struct tod_reg {
 46	u32	ctrl;
 47	u32	status;
 48	u32	uart_polarity;
 49	u32	version;
 50	u32	correction_sec;
 51	u32	__pad0[3];
 52	u32	uart_baud;
 53	u32	__pad1[3];
 54	u32	utc_status;
 55	u32	leap;
 56};
 57
 58#define TOD_REGISTER_OFFSET	0x01050000
 59
 60#define TOD_CTRL_PROTOCOL	BIT(28)
 61#define TOD_CTRL_DISABLE_FMT_A	BIT(17)
 62#define TOD_CTRL_DISABLE_FMT_B	BIT(16)
 63#define TOD_CTRL_ENABLE		BIT(0)
 64#define TOD_CTRL_GNSS_MASK	((1U << 4) - 1)
 65#define TOD_CTRL_GNSS_SHIFT	24
 66
 67#define TOD_STATUS_UTC_MASK	0xff
 68#define TOD_STATUS_UTC_VALID	BIT(8)
 69#define TOD_STATUS_LEAP_VALID	BIT(16)
 70
 71struct ptp_ocp {
 72	struct pci_dev		*pdev;
 73	spinlock_t		lock;
 74	void __iomem		*base;
 75	struct ocp_reg __iomem	*reg;
 76	struct tod_reg __iomem	*tod;
 77	struct ptp_clock	*ptp;
 78	struct ptp_clock_info	ptp_info;
 79};
 80
 81static int
 82__ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts,
 83			 struct ptp_system_timestamp *sts)
 84{
 85	u32 ctrl, time_sec, time_ns;
 86	int i;
 87
 88	ctrl = ioread32(&bp->reg->ctrl);
 89	ctrl |= OCP_CTRL_READ_TIME_REQ;
 90
 91	ptp_read_system_prets(sts);
 92	iowrite32(ctrl, &bp->reg->ctrl);
 93
 94	for (i = 0; i < 100; i++) {
 95		ctrl = ioread32(&bp->reg->ctrl);
 96		if (ctrl & OCP_CTRL_READ_TIME_DONE)
 97			break;
 98	}
 99	ptp_read_system_postts(sts);
100
101	time_ns = ioread32(&bp->reg->time_ns);
102	time_sec = ioread32(&bp->reg->time_sec);
103
104	ts->tv_sec = time_sec;
105	ts->tv_nsec = time_ns;
106
107	return ctrl & OCP_CTRL_READ_TIME_DONE ? 0 : -ETIMEDOUT;
108}
109
110static int
111ptp_ocp_gettimex(struct ptp_clock_info *ptp_info, struct timespec64 *ts,
112		 struct ptp_system_timestamp *sts)
113{
114	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
115	unsigned long flags;
116	int err;
117
118	spin_lock_irqsave(&bp->lock, flags);
119	err = __ptp_ocp_gettime_locked(bp, ts, sts);
120	spin_unlock_irqrestore(&bp->lock, flags);
121
122	return err;
123}
124
125static void
126__ptp_ocp_settime_locked(struct ptp_ocp *bp, const struct timespec64 *ts)
127{
128	u32 ctrl, time_sec, time_ns;
129	u32 select;
130
131	time_ns = ts->tv_nsec;
132	time_sec = ts->tv_sec;
133
134	select = ioread32(&bp->reg->select);
135	iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select);
136
137	iowrite32(time_ns, &bp->reg->adjust_ns);
138	iowrite32(time_sec, &bp->reg->adjust_sec);
139
140	ctrl = ioread32(&bp->reg->ctrl);
141	ctrl |= OCP_CTRL_ADJUST_TIME;
142	iowrite32(ctrl, &bp->reg->ctrl);
143
144	/* restore clock selection */
145	iowrite32(select >> 16, &bp->reg->select);
146}
147
148static int
149ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts)
150{
151	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
152	unsigned long flags;
153
154	if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
155		return 0;
156
157	spin_lock_irqsave(&bp->lock, flags);
158	__ptp_ocp_settime_locked(bp, ts);
159	spin_unlock_irqrestore(&bp->lock, flags);
160
161	return 0;
162}
163
164static int
165ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
166{
167	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
168	struct timespec64 ts;
169	unsigned long flags;
170	int err;
171
172	if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
173		return 0;
174
175	spin_lock_irqsave(&bp->lock, flags);
176	err = __ptp_ocp_gettime_locked(bp, &ts, NULL);
177	if (likely(!err)) {
178		timespec64_add_ns(&ts, delta_ns);
179		__ptp_ocp_settime_locked(bp, &ts);
180	}
181	spin_unlock_irqrestore(&bp->lock, flags);
182
183	return err;
184}
185
186static int
187ptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
188{
189	if (scaled_ppm == 0)
190		return 0;
191
192	return -EOPNOTSUPP;
193}
194
195static const struct ptp_clock_info ptp_ocp_clock_info = {
196	.owner		= THIS_MODULE,
197	.name		= KBUILD_MODNAME,
198	.max_adj	= 100000000,
199	.gettimex64	= ptp_ocp_gettimex,
200	.settime64	= ptp_ocp_settime,
201	.adjtime	= ptp_ocp_adjtime,
202	.adjfine	= ptp_ocp_null_adjfine,
203};
204
205static int
206ptp_ocp_check_clock(struct ptp_ocp *bp)
207{
208	struct timespec64 ts;
209	bool sync;
210	u32 ctrl;
211
212	/* make sure clock is enabled */
213	ctrl = ioread32(&bp->reg->ctrl);
214	ctrl |= OCP_CTRL_ENABLE;
215	iowrite32(ctrl, &bp->reg->ctrl);
216
217	if ((ioread32(&bp->reg->ctrl) & OCP_CTRL_ENABLE) == 0) {
218		dev_err(&bp->pdev->dev, "clock not enabled\n");
219		return -ENODEV;
220	}
221
222	sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
223	if (!sync) {
224		ktime_get_real_ts64(&ts);
225		ptp_ocp_settime(&bp->ptp_info, &ts);
226	}
227	if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL))
228		dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n",
229			 ts.tv_sec, ts.tv_nsec,
230			 sync ? "in-sync" : "UNSYNCED");
231
232	return 0;
233}
234
235static void
236ptp_ocp_tod_info(struct ptp_ocp *bp)
237{
238	static const char * const proto_name[] = {
239		"NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none",
240		"UBX", "UBX_UTC", "UBX_LS", "UBX_none"
241	};
242	static const char * const gnss_name[] = {
243		"ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU",
244	};
245	u32 version, ctrl, reg;
246	int idx;
247
248	version = ioread32(&bp->tod->version);
249	dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n",
250		 version >> 24, (version >> 16) & 0xff, version & 0xffff);
251
252	ctrl = ioread32(&bp->tod->ctrl);
253	ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE;
254	ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B);
255	iowrite32(ctrl, &bp->tod->ctrl);
256
257	ctrl = ioread32(&bp->tod->ctrl);
258	idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0;
259	idx += (ctrl >> 16) & 3;
260	dev_info(&bp->pdev->dev, "control: %x\n", ctrl);
261	dev_info(&bp->pdev->dev, "TOD Protocol %s %s\n", proto_name[idx],
262		 ctrl & TOD_CTRL_ENABLE ? "enabled" : "");
263
264	idx = (ctrl >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK;
265	if (idx < ARRAY_SIZE(gnss_name))
266		dev_info(&bp->pdev->dev, "GNSS %s\n", gnss_name[idx]);
267
268	reg = ioread32(&bp->tod->status);
269	dev_info(&bp->pdev->dev, "status: %x\n", reg);
270
271	reg = ioread32(&bp->tod->correction_sec);
272	dev_info(&bp->pdev->dev, "correction: %d\n", reg);
273
274	reg = ioread32(&bp->tod->utc_status);
275	dev_info(&bp->pdev->dev, "utc_status: %x\n", reg);
276	dev_info(&bp->pdev->dev, "utc_offset: %d  valid:%d  leap_valid:%d\n",
277		 reg & TOD_STATUS_UTC_MASK, reg & TOD_STATUS_UTC_VALID ? 1 : 0,
278		 reg & TOD_STATUS_LEAP_VALID ? 1 : 0);
279}
280
281static void
282ptp_ocp_info(struct ptp_ocp *bp)
283{
284	static const char * const clock_name[] = {
285		"NO", "TOD", "IRIG", "PPS", "PTP", "RTC", "REGS", "EXT"
286	};
287	u32 version, select;
288
289	version = ioread32(&bp->reg->version);
290	select = ioread32(&bp->reg->select);
291	dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n",
292		 version >> 24, (version >> 16) & 0xff, version & 0xffff,
293		 clock_name[select & 7],
294		 ptp_clock_index(bp->ptp));
295
296	ptp_ocp_tod_info(bp);
297}
298
299static int
300ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
301{
302	struct ptp_ocp *bp;
303	int err;
304
305	bp = kzalloc(sizeof(*bp), GFP_KERNEL);
306	if (!bp)
307		return -ENOMEM;
308	bp->pdev = pdev;
309	pci_set_drvdata(pdev, bp);
310
311	err = pci_enable_device(pdev);
312	if (err) {
313		dev_err(&pdev->dev, "pci_enable_device\n");
314		goto out_free;
315	}
316
317	err = pci_request_regions(pdev, KBUILD_MODNAME);
318	if (err) {
319		dev_err(&pdev->dev, "pci_request_region\n");
320		goto out_disable;
321	}
322
323	bp->base = pci_ioremap_bar(pdev, 0);
324	if (!bp->base) {
325		dev_err(&pdev->dev, "io_remap bar0\n");
326		err = -ENOMEM;
327		goto out_release_regions;
328	}
329	bp->reg = bp->base + OCP_REGISTER_OFFSET;
330	bp->tod = bp->base + TOD_REGISTER_OFFSET;
331	bp->ptp_info = ptp_ocp_clock_info;
332	spin_lock_init(&bp->lock);
333
334	err = ptp_ocp_check_clock(bp);
335	if (err)
336		goto out;
337
338	bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev);
339	if (IS_ERR(bp->ptp)) {
340		dev_err(&pdev->dev, "ptp_clock_register\n");
341		err = PTR_ERR(bp->ptp);
342		goto out;
343	}
344
345	ptp_ocp_info(bp);
346
347	return 0;
348
349out:
350	pci_iounmap(pdev, bp->base);
351out_release_regions:
352	pci_release_regions(pdev);
353out_disable:
354	pci_disable_device(pdev);
355out_free:
356	kfree(bp);
357
358	return err;
359}
360
361static void
362ptp_ocp_remove(struct pci_dev *pdev)
363{
364	struct ptp_ocp *bp = pci_get_drvdata(pdev);
365
366	ptp_clock_unregister(bp->ptp);
367	pci_iounmap(pdev, bp->base);
368	pci_release_regions(pdev);
369	pci_disable_device(pdev);
370	pci_set_drvdata(pdev, NULL);
371	kfree(bp);
372}
373
374static struct pci_driver ptp_ocp_driver = {
375	.name		= KBUILD_MODNAME,
376	.id_table	= ptp_ocp_pcidev_id,
377	.probe		= ptp_ocp_probe,
378	.remove		= ptp_ocp_remove,
379};
380
381static int __init
382ptp_ocp_init(void)
383{
384	int err;
385
386	err = pci_register_driver(&ptp_ocp_driver);
387	return err;
388}
389
390static void __exit
391ptp_ocp_fini(void)
392{
393	pci_unregister_driver(&ptp_ocp_driver);
394}
395
396module_init(ptp_ocp_init);
397module_exit(ptp_ocp_fini);
398
399MODULE_DESCRIPTION("OpenCompute TimeCard driver");
400MODULE_LICENSE("GPL v2");