* [PATCH] ptp: Add clock driver for the OpenCompute TimeCard.
@ 2020-12-01 20:51 Jonathan Lemon
2020-12-02 3:20 ` kernel test robot
0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Lemon @ 2020-12-01 20:51 UTC (permalink / raw)
To: richardcochran, netdev, kuba; +Cc: kernel-team
The OpenCompute time card is an atomic clock along with
a GPS receiver that provides a Grandmaster clock source
for a PTP enabled network.
More information is available at http://www.timingcard.com/
Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
---
drivers/ptp/Kconfig | 13 ++
drivers/ptp/Makefile | 1 +
drivers/ptp/ptp_ocp.c | 407 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 421 insertions(+)
create mode 100644 drivers/ptp/ptp_ocp.c
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 942f72d8151d..125463068d70 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -151,4 +151,17 @@ config PTP_1588_CLOCK_VMW
To compile this driver as a module, choose M here: the module
will be called ptp_vmw.
+config PTP_OCP
+ tristate "OpenCompute TimeCard"
+ depends on HAS_IOMEM
+ default n
+ help
+ This driver adds support for an OpenCompute time card.
+
+ The OpenCompute time card is an atomic clock along with
+ a GPS receiver that provides a Grandmaster clock source
+ for a PTP enabled network.
+
+ More information is available at http://www.timingcard.com/
+
endmenu
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
index 7aff75f745dc..cd80eccb80c9 100644
--- a/drivers/ptp/Makefile
+++ b/drivers/ptp/Makefile
@@ -15,3 +15,4 @@ ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o
obj-$(CONFIG_PTP_1588_CLOCK_IDTCM) += ptp_clockmatrix.o
obj-$(CONFIG_PTP_1588_CLOCK_IDT82P33) += ptp_idt82p33.o
obj-$(CONFIG_PTP_1588_CLOCK_VMW) += ptp_vmw.o
+obj-$(CONFIG_PTP_OCP) += ptp_ocp.o
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
new file mode 100644
index 000000000000..f7457a78791d
--- /dev/null
+++ b/drivers/ptp/ptp_ocp.c
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020 Facebook */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ptp_clock_kernel.h>
+
+static const struct pci_device_id ptp_ocp_pcidev_id[] = {
+ { PCI_DEVICE(0x1d9b, 0x0400) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
+
+#define OCP_REGISTER_OFFSET 0x01000000
+
+struct ocp_reg {
+ u32 ctrl;
+ u32 status;
+ u32 select;
+ u32 version;
+ u32 time_ns;
+ u32 time_sec;
+ u32 __pad0[2];
+ u32 adjust_ns;
+ u32 adjust_sec;
+ u32 __pad1[2];
+ u32 offset_ns;
+ u32 offset_window_ns;
+};
+
+#define OCP_CTRL_ENABLE BIT(0)
+#define OCP_CTRL_ADJUST_TIME BIT(1)
+#define OCP_CTRL_ADJUST_OFFSET BIT(2)
+#define OCP_CTRL_READ_TIME_REQ BIT(30)
+#define OCP_CTRL_READ_TIME_DONE BIT(31)
+
+#define OCP_STATUS_IN_SYNC BIT(0)
+
+#define OCP_SELECT_CLK_NONE 0
+#define OCP_SELECT_CLK_REG 6
+
+struct tod_reg {
+ u32 ctrl;
+ u32 status;
+ u32 uart_polarity;
+ u32 version;
+ u32 correction_sec;
+ u32 __pad0[3];
+ u32 uart_baud;
+ u32 __pad1[3];
+ u32 utc_status;
+ u32 leap;
+};
+
+#define TOD_REGISTER_OFFSET 0x01050000
+
+#define TOD_CTRL_PROTOCOL BIT(28)
+#define TOD_CTRL_DISABLE_FMT_A BIT(17)
+#define TOD_CTRL_DISABLE_FMT_B BIT(16)
+#define TOD_CTRL_ENABLE BIT(0)
+#define TOD_CTRL_GNSS_MASK ((1U << 4) - 1)
+#define TOD_CTRL_GNSS_SHIFT 24
+
+#define TOD_STATUS_UTC_MASK 0xff
+#define TOD_STATUS_UTC_VALID BIT(8)
+#define TOD_STATUS_LEAP_VALID BIT(16)
+
+struct ptp_ocp {
+ struct pci_dev *pdev;
+ spinlock_t lock;
+ void __iomem *base;
+ struct ocp_reg __iomem *reg;
+ struct tod_reg __iomem *tod;
+ struct ptp_clock *ptp;
+ struct ptp_clock_info ptp_info;
+};
+
+static int
+__ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ u32 ctrl, time_sec, time_ns;
+ int i;
+
+ ctrl = ioread32(&bp->reg->ctrl);
+ ctrl |= OCP_CTRL_READ_TIME_REQ;
+
+ ptp_read_system_prets(sts);
+ iowrite32(ctrl, &bp->reg->ctrl);
+
+ for (i = 0; i < 100; i++) {
+ ctrl = ioread32(&bp->reg->ctrl);
+ if (ctrl & OCP_CTRL_READ_TIME_DONE)
+ break;
+ }
+ ptp_read_system_postts(sts);
+
+ time_ns = ioread32(&bp->reg->time_ns);
+ time_sec = ioread32(&bp->reg->time_sec);
+
+ ts->tv_sec = time_sec;
+ ts->tv_nsec = time_ns;
+
+ return ctrl & OCP_CTRL_READ_TIME_DONE ? 0 : -ETIMEDOUT;
+}
+
+static int
+ptp_ocp_gettimex(struct ptp_clock_info *ptp_info, struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&bp->lock, flags);
+ err = __ptp_ocp_gettime_locked(bp, ts, sts);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ return err;
+}
+
+static void
+__ptp_ocp_settime_locked(struct ptp_ocp *bp, const struct timespec64 *ts)
+{
+ u32 ctrl, time_sec, time_ns;
+ u32 select;
+
+ time_ns = ts->tv_nsec;
+ time_sec = ts->tv_sec;
+
+ select = ioread32(&bp->reg->select);
+ iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select);
+
+ iowrite32(time_ns, &bp->reg->adjust_ns);
+ iowrite32(time_sec, &bp->reg->adjust_sec);
+
+ ctrl = ioread32(&bp->reg->ctrl);
+ ctrl |= OCP_CTRL_ADJUST_TIME;
+ iowrite32(ctrl, &bp->reg->ctrl);
+
+ /* restore clock selection */
+ iowrite32(select >> 16, &bp->reg->select);
+}
+
+static int
+ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts)
+{
+ struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
+ unsigned long flags;
+
+ if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
+ return 0;
+
+ dev_info(&bp->pdev->dev, "settime to: %lld.%ld\n",
+ ts->tv_sec, ts->tv_nsec);
+
+ spin_lock_irqsave(&bp->lock, flags);
+ __ptp_ocp_settime_locked(bp, ts);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ return 0;
+}
+
+static int
+ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
+{
+ struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
+ struct timespec64 ts;
+ unsigned long flags;
+ int err;
+
+ if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
+ return 0;
+
+ dev_info(&bp->pdev->dev, "adjtime , adjust by: %lld\n", delta_ns);
+
+ spin_lock_irqsave(&bp->lock, flags);
+ err = __ptp_ocp_gettime_locked(bp, &ts, NULL);
+ if (likely(!err)) {
+ timespec64_add_ns(&ts, delta_ns);
+ __ptp_ocp_settime_locked(bp, &ts);
+ }
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ return err;
+}
+
+static int
+ptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
+{
+ struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
+
+ if (scaled_ppm == 0)
+ return 0;
+
+ dev_info(&bp->pdev->dev, "adjfine, scaled by: %ld\n", scaled_ppm);
+
+ return -EOPNOTSUPP;
+}
+
+static const struct ptp_clock_info ptp_ocp_clock_info = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .max_adj = 100000000,
+ .gettimex64 = ptp_ocp_gettimex,
+ .settime64 = ptp_ocp_settime,
+ .adjtime = ptp_ocp_adjtime,
+ .adjfine = ptp_ocp_null_adjfine,
+};
+
+static int
+ptp_ocp_check_clock(struct ptp_ocp *bp)
+{
+ struct timespec64 ts;
+ bool sync;
+ u32 ctrl;
+
+ /* make sure clock is enabled */
+ ctrl = ioread32(&bp->reg->ctrl);
+ ctrl |= OCP_CTRL_ENABLE;
+ iowrite32(ctrl, &bp->reg->ctrl);
+
+ if ((ioread32(&bp->reg->ctrl) & OCP_CTRL_ENABLE) == 0) {
+ dev_err(&bp->pdev->dev, "clock not enabled\n");
+ return -ENODEV;
+ }
+
+ sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
+ if (!sync) {
+ ktime_get_real_ts64(&ts);
+ ptp_ocp_settime(&bp->ptp_info, &ts);
+ }
+ if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL))
+ dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n",
+ ts.tv_sec, ts.tv_nsec,
+ sync ? "in-sync" : "UNSYNCED");
+
+ return 0;
+}
+
+static void
+ptp_ocp_tod_info(struct ptp_ocp *bp)
+{
+ static const char * const proto_name[] = {
+ "NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none",
+ "UBX", "UBX_UTC", "UBX_LS", "UBX_none"
+ };
+ static const char * const gnss_name[] = {
+ "ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU",
+ };
+ u32 version, ctrl, reg;
+ int idx;
+
+ version = ioread32(&bp->tod->version);
+ dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n",
+ version >> 24, (version >> 16) & 0xff, version & 0xffff);
+
+ ctrl = ioread32(&bp->tod->ctrl);
+ ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE;
+ ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B);
+ iowrite32(ctrl, &bp->tod->ctrl);
+
+ ctrl = ioread32(&bp->tod->ctrl);
+ idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0;
+ idx += (ctrl >> 16) & 3;
+ dev_info(&bp->pdev->dev, "control: %x\n", ctrl);
+ dev_info(&bp->pdev->dev, "TOD Protocol %s %s\n", proto_name[idx],
+ ctrl & TOD_CTRL_ENABLE ? "enabled" : "");
+
+ idx = (ctrl >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK;
+ if (idx < ARRAY_SIZE(gnss_name))
+ dev_info(&bp->pdev->dev, "GNSS %s\n", gnss_name[idx]);
+
+ reg = ioread32(&bp->tod->status);
+ dev_info(&bp->pdev->dev, "status: %x\n", reg);
+
+ reg = ioread32(&bp->tod->correction_sec);
+ dev_info(&bp->pdev->dev, "correction: %d\n", reg);
+
+ reg = ioread32(&bp->tod->utc_status);
+ dev_info(&bp->pdev->dev, "utc_status: %x\n", reg);
+ dev_info(&bp->pdev->dev, "utc_offset: %d valid:%d leap_valid:%d\n",
+ reg & TOD_STATUS_UTC_MASK, reg & TOD_STATUS_UTC_VALID ? 1 : 0,
+ reg & TOD_STATUS_LEAP_VALID ? 1 : 0);
+}
+
+static void
+ptp_ocp_info(struct ptp_ocp *bp)
+{
+ static const char * const clock_name[] = {
+ "NO", "TOD", "IRIG", "PPS", "PTP", "RTC", "REGS", "EXT"
+ };
+ u32 version, select;
+
+ version = ioread32(&bp->reg->version);
+ select = ioread32(&bp->reg->select);
+ dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n",
+ version >> 24, (version >> 16) & 0xff, version & 0xffff,
+ clock_name[select & 7],
+ ptp_clock_index(bp->ptp));
+
+ ptp_ocp_tod_info(bp);
+}
+
+static int
+ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct ptp_ocp *bp;
+ int err;
+
+ bp = kzalloc(sizeof(*bp), GFP_KERNEL);
+ if (!bp)
+ return -ENOMEM;
+ bp->pdev = pdev;
+ pci_set_drvdata(pdev, bp);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "pci_enable_device\n");
+ goto out_free;
+ }
+
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (err) {
+ dev_err(&pdev->dev, "pci_request_region\n");
+ goto out_disable;
+ }
+
+ bp->base = pci_ioremap_bar(pdev, 0);
+ if (!bp->base) {
+ dev_err(&pdev->dev, "io_remap bar0\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ bp->reg = bp->base + OCP_REGISTER_OFFSET;
+ bp->tod = bp->base + TOD_REGISTER_OFFSET;
+ bp->ptp_info = ptp_ocp_clock_info;
+ spin_lock_init(&bp->lock);
+
+ err = ptp_ocp_check_clock(bp);
+ if (err)
+ goto out;
+
+ bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev);
+ if (IS_ERR(bp->ptp)) {
+ dev_err(&pdev->dev, "ptp_clock_register\n");
+ err = PTR_ERR(bp->ptp);
+ goto out;
+ }
+
+ ptp_ocp_info(bp);
+
+ return 0;
+
+out:
+ pci_release_regions(pdev);
+out_disable:
+ pci_disable_device(pdev);
+out_free:
+ kfree(bp);
+
+ return err;
+}
+
+static void
+ptp_ocp_remove(struct pci_dev *pdev)
+{
+ struct ptp_ocp *bp = pci_get_drvdata(pdev);
+
+ ptp_clock_unregister(bp->ptp);
+ pci_iounmap(pdev, bp->base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ kfree(bp);
+}
+
+static struct pci_driver ptp_ocp_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ptp_ocp_pcidev_id,
+ .probe = ptp_ocp_probe,
+ .remove = ptp_ocp_remove,
+};
+
+static int __init
+ptp_ocp_init(void)
+{
+ int err;
+
+ err = pci_register_driver(&ptp_ocp_driver);
+ return err;
+}
+
+static void __exit
+ptp_ocp_fini(void)
+{
+ pci_unregister_driver(&ptp_ocp_driver);
+}
+
+module_init(ptp_ocp_init);
+module_exit(ptp_ocp_fini);
+
+MODULE_DESCRIPTION("OpenCompute TimeCard driver");
+MODULE_LICENSE("GPL v2");
--
2.18.4
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] ptp: Add clock driver for the OpenCompute TimeCard.
2020-12-01 20:51 [PATCH] ptp: Add clock driver for the OpenCompute TimeCard Jonathan Lemon
@ 2020-12-02 3:20 ` kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2020-12-02 3:20 UTC (permalink / raw)
To: Jonathan Lemon, richardcochran, netdev, kuba; +Cc: kbuild-all, kernel-team
[-- Attachment #1: Type: text/plain, Size: 2356 bytes --]
Hi Jonathan,
I love your patch! Yet something to improve:
[auto build test ERROR on net/master]
[also build test ERROR on ipvs/master net-next/master linus/master v5.10-rc6 next-20201201]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Jonathan-Lemon/ptp-Add-clock-driver-for-the-OpenCompute-TimeCard/20201202-045520
base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git 14483cbf040fcb38113497161088a1ce8ce5d713
config: sh-allmodconfig (attached as .config)
compiler: sh4-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/212c31abce553dfb3146a24086b8a50046097f0d
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Jonathan-Lemon/ptp-Add-clock-driver-for-the-OpenCompute-TimeCard/20201202-045520
git checkout 212c31abce553dfb3146a24086b8a50046097f0d
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=sh
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
drivers/ptp/ptp_ocp.c: In function 'ptp_ocp_remove':
>> drivers/ptp/ptp_ocp.c:374:2: error: implicit declaration of function 'pci_iounmap'; did you mean 'pcim_iounmap'? [-Werror=implicit-function-declaration]
374 | pci_iounmap(pdev, bp->base);
| ^~~~~~~~~~~
| pcim_iounmap
cc1: some warnings being treated as errors
vim +374 drivers/ptp/ptp_ocp.c
367
368 static void
369 ptp_ocp_remove(struct pci_dev *pdev)
370 {
371 struct ptp_ocp *bp = pci_get_drvdata(pdev);
372
373 ptp_clock_unregister(bp->ptp);
> 374 pci_iounmap(pdev, bp->base);
375 pci_release_regions(pdev);
376 pci_disable_device(pdev);
377 pci_set_drvdata(pdev, NULL);
378 kfree(bp);
379 }
380
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 53576 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-12-02 3:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-12-01 20:51 [PATCH] ptp: Add clock driver for the OpenCompute TimeCard Jonathan Lemon
2020-12-02 3:20 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).