linux/drivers/net/ethernet/xilinx/xilinx_tsn_ptp_clock.c
<<
>>
Prefs
   1/*
   2 * Xilinx FPGA Xilinx TSN PTP protocol clock Controller module.
   3 *
   4 * Copyright (c) 2017 Xilinx Pvt., Ltd
   5 *
   6 * Author: Syed S <syeds@xilinx.com>
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <linux/device.h>
  19#include <linux/err.h>
  20#include <linux/io.h>
  21#include <linux/irq.h>
  22#include <linux/interrupt.h>
  23#include <linux/slab.h>
  24#include <linux/kernel.h>
  25#include <linux/ptp_clock_kernel.h>
  26#include <linux/platform_device.h>
  27#include <linux/of_irq.h>
  28#include "xilinx_tsn_timer.h"
  29
  30struct xlnx_ptp_timer {
  31        struct                 device *dev;
  32        void __iomem          *baseaddr;
  33        struct ptp_clock      *ptp_clock;
  34        struct ptp_clock_info  ptp_clock_info;
  35        spinlock_t             reg_lock; /* ptp timer lock */
  36        int                    irq;
  37        int                    pps_enable;
  38        int                    countpulse;
  39};
  40
  41static void xlnx_tod_read(struct xlnx_ptp_timer *timer, struct timespec64 *ts)
  42{
  43        u32 sec, nsec;
  44
  45        nsec = in_be32(timer->baseaddr + XTIMER1588_CURRENT_RTC_NS);
  46        sec = in_be32(timer->baseaddr + XTIMER1588_CURRENT_RTC_SEC_L);
  47
  48        ts->tv_sec = sec;
  49        ts->tv_nsec = nsec;
  50}
  51
  52static void xlnx_rtc_offset_write(struct xlnx_ptp_timer *timer,
  53                                  const struct timespec64 *ts)
  54{
  55        pr_debug("%s: sec: %ld nsec: %ld\n", __func__, ts->tv_sec, ts->tv_nsec);
  56
  57        out_be32((timer->baseaddr + XTIMER1588_RTC_OFFSET_SEC_H), 0);
  58        out_be32((timer->baseaddr + XTIMER1588_RTC_OFFSET_SEC_L),
  59                 (ts->tv_sec));
  60        out_be32((timer->baseaddr + XTIMER1588_RTC_OFFSET_NS), ts->tv_nsec);
  61}
  62
  63static void xlnx_rtc_offset_read(struct xlnx_ptp_timer *timer,
  64                                 struct timespec64 *ts)
  65{
  66        ts->tv_sec = in_be32(timer->baseaddr + XTIMER1588_RTC_OFFSET_SEC_L);
  67        ts->tv_nsec = in_be32(timer->baseaddr + XTIMER1588_RTC_OFFSET_NS);
  68}
  69
  70/* PTP clock operations
  71 */
  72static int xlnx_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
  73{
  74        struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
  75                                                    ptp_clock_info);
  76
  77        int neg_adj = 0;
  78        u64 freq;
  79        u32 diff, incval;
  80
  81        /* This number should be replaced by a call to get the frequency
  82         * from the device-tree. Currently assumes 125MHz
  83         */
  84        incval = 0x800000;
  85        /* for 156.25 MHZ Ref clk the value is  incval = 0x800000; */
  86
  87        if (ppb < 0) {
  88                neg_adj = 1;
  89                ppb = -ppb;
  90        }
  91
  92        freq = incval;
  93        freq *= ppb;
  94        diff = div_u64(freq, 1000000000ULL);
  95
  96        pr_debug("%s: adj: %d ppb: %d\n", __func__, diff, ppb);
  97
  98        incval = neg_adj ? (incval - diff) : (incval + diff);
  99        out_be32((timer->baseaddr + XTIMER1588_RTC_INCREMENT), incval);
 100        return 0;
 101}
 102
 103static int xlnx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 104{
 105        unsigned long flags;
 106        struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
 107                                                    ptp_clock_info);
 108        struct timespec64 now, then = ns_to_timespec64(delta);
 109
 110        spin_lock_irqsave(&timer->reg_lock, flags);
 111
 112        xlnx_rtc_offset_read(timer, &now);
 113
 114        now = timespec64_add(now, then);
 115
 116        xlnx_rtc_offset_write(timer, (const struct timespec64 *)&now);
 117        spin_unlock_irqrestore(&timer->reg_lock, flags);
 118
 119        return 0;
 120}
 121
 122static int xlnx_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
 123{
 124        unsigned long flags;
 125        struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
 126                                                    ptp_clock_info);
 127        spin_lock_irqsave(&timer->reg_lock, flags);
 128
 129        xlnx_tod_read(timer, ts);
 130
 131        spin_unlock_irqrestore(&timer->reg_lock, flags);
 132        return 0;
 133}
 134
 135/**
 136 * xlnx_ptp_settime - Set the current time on the hardware clock
 137 * @ptp: ptp clock structure
 138 * @ts: timespec64 containing the new time for the cycle counter
 139 *
 140 * Return: 0 in all cases.
 141 *
 142 * The seconds register is written first, then the nanosecond
 143 * The hardware loads the entire new value when a nanosecond register
 144 * is written
 145 **/
 146static int xlnx_ptp_settime(struct ptp_clock_info *ptp,
 147                            const struct timespec64 *ts)
 148{
 149        struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
 150                                                    ptp_clock_info);
 151        struct timespec64 delta, tod;
 152        struct timespec64 offset;
 153        unsigned long flags;
 154
 155        spin_lock_irqsave(&timer->reg_lock, flags);
 156
 157        /* First zero the offset */
 158        offset.tv_sec = 0;
 159        offset.tv_nsec = 0;
 160        xlnx_rtc_offset_write(timer, &offset);
 161
 162        /* Get the current timer value */
 163        xlnx_tod_read(timer, &tod);
 164
 165        /* Subtract the current reported time from our desired time */
 166        delta = timespec64_sub(*ts, tod);
 167
 168        /* Don't write a negative offset */
 169        if (delta.tv_sec <= 0) {
 170                delta.tv_sec = 0;
 171                if (delta.tv_nsec < 0)
 172                        delta.tv_nsec = 0;
 173        }
 174
 175        xlnx_rtc_offset_write(timer, &delta);
 176        spin_unlock_irqrestore(&timer->reg_lock, flags);
 177        return 0;
 178}
 179
 180static int xlnx_ptp_enable(struct ptp_clock_info *ptp,
 181                           struct ptp_clock_request *rq, int on)
 182{
 183        struct xlnx_ptp_timer *timer = container_of(ptp, struct xlnx_ptp_timer,
 184                                                    ptp_clock_info);
 185
 186        switch (rq->type) {
 187        case PTP_CLK_REQ_PPS:
 188                timer->pps_enable = 1;
 189                return 0;
 190        default:
 191                break;
 192        }
 193
 194        return -EOPNOTSUPP;
 195}
 196
 197static struct ptp_clock_info xlnx_ptp_clock_info = {
 198        .owner    = THIS_MODULE,
 199        .name     = "Xilinx Timer",
 200        .max_adj  = 999999999,
 201        .n_ext_ts       = 0,
 202        .pps      = 1,
 203        .adjfreq  = xlnx_ptp_adjfreq,
 204        .adjtime  = xlnx_ptp_adjtime,
 205        .gettime64  = xlnx_ptp_gettime,
 206        .settime64 = xlnx_ptp_settime,
 207        .enable   = xlnx_ptp_enable,
 208};
 209
 210/* module operations */
 211
 212/**
 213 * xlnx_ptp_timer_isr - Interrupt Service Routine
 214 * @irq:               IRQ number
 215 * @priv:              pointer to the timer structure
 216 *
 217 * Returns: IRQ_HANDLED for all cases
 218 *
 219 * Handles the timer interrupt. The timer interrupt fires 128 times per
 220 * secound. When our count reaches 128 emit a PTP_CLOCK_PPS event
 221 */
 222static irqreturn_t xlnx_ptp_timer_isr(int irq, void *priv)
 223{
 224        struct xlnx_ptp_timer *timer = (struct xlnx_ptp_timer *)priv;
 225        struct ptp_clock_event event;
 226
 227        event.type = PTP_CLOCK_PPS;
 228        ++timer->countpulse;
 229        if (timer->countpulse >= PULSESIN1PPS) {
 230                timer->countpulse = 0;
 231                if ((timer->ptp_clock) && (timer->pps_enable))
 232                        ptp_clock_event(timer->ptp_clock, &event);
 233        }
 234        out_be32((timer->baseaddr + XTIMER1588_INTERRUPT),
 235                 (1 << XTIMER1588_INT_SHIFT));
 236
 237        return IRQ_HANDLED;
 238}
 239
 240int axienet_ptp_timer_remove(void *priv)
 241{
 242        struct xlnx_ptp_timer *timer = (struct xlnx_ptp_timer *)priv;
 243
 244        free_irq(timer->irq, (void *)timer);
 245
 246        axienet_phc_index = -1;
 247        if (timer->ptp_clock) {
 248                ptp_clock_unregister(timer->ptp_clock);
 249                timer->ptp_clock = NULL;
 250        }
 251        kfree(timer);
 252        return 0;
 253}
 254
 255int axienet_get_phc_index(void *priv)
 256{
 257        struct xlnx_ptp_timer *timer = (struct xlnx_ptp_timer *)priv;
 258
 259        if (timer->ptp_clock)
 260                return ptp_clock_index(timer->ptp_clock);
 261        else
 262                return -1;
 263}
 264
 265void *axienet_ptp_timer_probe(void __iomem *base, struct platform_device *pdev)
 266{
 267        struct xlnx_ptp_timer *timer;
 268        struct timespec64 ts;
 269        int err = 0;
 270
 271        timer = kzalloc(sizeof(*timer), GFP_KERNEL);
 272        if (!timer)
 273                return NULL;
 274
 275        timer->baseaddr = base;
 276
 277        timer->irq = platform_get_irq_byname(pdev, "interrupt_ptp_timer");
 278
 279        if (timer->irq < 0) {
 280                timer->irq = platform_get_irq_byname(pdev, "rtc_irq");
 281                if (timer->irq > 0) {
 282                        pr_err("ptp timer interrupt name 'rtc_irq' is"
 283                                "deprecated\n");
 284                } else {
 285                        pr_err("ptp timer interrupt not found\n");
 286                        kfree(timer);
 287                        return NULL;
 288                }
 289        }
 290        spin_lock_init(&timer->reg_lock);
 291
 292        timer->ptp_clock_info = xlnx_ptp_clock_info;
 293
 294        timer->ptp_clock = ptp_clock_register(&timer->ptp_clock_info,
 295                                              &pdev->dev);
 296
 297        if (IS_ERR(timer->ptp_clock)) {
 298                err = PTR_ERR(timer->ptp_clock);
 299                pr_debug("Failed to register ptp clock\n");
 300                goto out;
 301        }
 302
 303        axienet_phc_index = ptp_clock_index(timer->ptp_clock);
 304
 305        ts = ktime_to_timespec64(ktime_get_real());
 306
 307        xlnx_ptp_settime(&timer->ptp_clock_info, &ts);
 308
 309        /* Enable interrupts */
 310        err = request_irq(timer->irq,
 311                          xlnx_ptp_timer_isr,
 312                          0,
 313                          "ptp_rtc",
 314                          (void *)timer);
 315        if (err)
 316                goto err_irq;
 317
 318        return timer;
 319
 320err_irq:
 321        ptp_clock_unregister(timer->ptp_clock);
 322out:
 323        timer->ptp_clock = NULL;
 324        return NULL;
 325}
 326