linux/drivers/ptp/ptp_ocp.c
<<
>>
Prefs
   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");
 401