linux/drivers/net/ethernet/mscc/ocelot_ptp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
   2/* Microsemi Ocelot PTP clock driver
   3 *
   4 * Copyright (c) 2017 Microsemi Corporation
   5 * Copyright 2020 NXP
   6 */
   7#include <soc/mscc/ocelot_ptp.h>
   8#include <soc/mscc/ocelot_sys.h>
   9#include <soc/mscc/ocelot.h>
  10
  11int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
  12{
  13        struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
  14        unsigned long flags;
  15        time64_t s;
  16        u32 val;
  17        s64 ns;
  18
  19        spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
  20
  21        val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
  22        val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
  23        val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_SAVE);
  24        ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
  25
  26        s = ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN) & 0xffff;
  27        s <<= 32;
  28        s += ocelot_read_rix(ocelot, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
  29        ns = ocelot_read_rix(ocelot, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
  30
  31        spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
  32
  33        /* Deal with negative values */
  34        if (ns >= 0x3ffffff0 && ns <= 0x3fffffff) {
  35                s--;
  36                ns &= 0xf;
  37                ns += 999999984;
  38        }
  39
  40        set_normalized_timespec64(ts, s, ns);
  41        return 0;
  42}
  43EXPORT_SYMBOL(ocelot_ptp_gettime64);
  44
  45int ocelot_ptp_settime64(struct ptp_clock_info *ptp,
  46                         const struct timespec64 *ts)
  47{
  48        struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
  49        unsigned long flags;
  50        u32 val;
  51
  52        spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
  53
  54        val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
  55        val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
  56        val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
  57
  58        ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
  59
  60        ocelot_write_rix(ocelot, lower_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_LSB,
  61                         TOD_ACC_PIN);
  62        ocelot_write_rix(ocelot, upper_32_bits(ts->tv_sec), PTP_PIN_TOD_SEC_MSB,
  63                         TOD_ACC_PIN);
  64        ocelot_write_rix(ocelot, ts->tv_nsec, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
  65
  66        val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
  67        val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
  68        val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD);
  69
  70        ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
  71
  72        spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
  73        return 0;
  74}
  75EXPORT_SYMBOL(ocelot_ptp_settime64);
  76
  77int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
  78{
  79        if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) {
  80                struct ocelot *ocelot = container_of(ptp, struct ocelot,
  81                                                     ptp_info);
  82                unsigned long flags;
  83                u32 val;
  84
  85                spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
  86
  87                val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
  88                val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK |
  89                         PTP_PIN_CFG_DOM);
  90                val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
  91
  92                ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
  93
  94                ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_LSB, TOD_ACC_PIN);
  95                ocelot_write_rix(ocelot, 0, PTP_PIN_TOD_SEC_MSB, TOD_ACC_PIN);
  96                ocelot_write_rix(ocelot, delta, PTP_PIN_TOD_NSEC, TOD_ACC_PIN);
  97
  98                val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
  99                val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK |
 100                         PTP_PIN_CFG_DOM);
 101                val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA);
 102
 103                ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
 104
 105                spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 106        } else {
 107                /* Fall back using ocelot_ptp_settime64 which is not exact. */
 108                struct timespec64 ts;
 109                u64 now;
 110
 111                ocelot_ptp_gettime64(ptp, &ts);
 112
 113                now = ktime_to_ns(timespec64_to_ktime(ts));
 114                ts = ns_to_timespec64(now + delta);
 115
 116                ocelot_ptp_settime64(ptp, &ts);
 117        }
 118        return 0;
 119}
 120EXPORT_SYMBOL(ocelot_ptp_adjtime);
 121
 122int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
 123{
 124        struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
 125        u32 unit = 0, direction = 0;
 126        unsigned long flags;
 127        u64 adj = 0;
 128
 129        spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
 130
 131        if (!scaled_ppm)
 132                goto disable_adj;
 133
 134        if (scaled_ppm < 0) {
 135                direction = PTP_CFG_CLK_ADJ_CFG_DIR;
 136                scaled_ppm = -scaled_ppm;
 137        }
 138
 139        adj = PSEC_PER_SEC << 16;
 140        do_div(adj, scaled_ppm);
 141        do_div(adj, 1000);
 142
 143        /* If the adjustment value is too large, use ns instead */
 144        if (adj >= (1L << 30)) {
 145                unit = PTP_CFG_CLK_ADJ_FREQ_NS;
 146                do_div(adj, 1000);
 147        }
 148
 149        /* Still too big */
 150        if (adj >= (1L << 30))
 151                goto disable_adj;
 152
 153        ocelot_write(ocelot, unit | adj, PTP_CLK_CFG_ADJ_FREQ);
 154        ocelot_write(ocelot, PTP_CFG_CLK_ADJ_CFG_ENA | direction,
 155                     PTP_CLK_CFG_ADJ_CFG);
 156
 157        spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 158        return 0;
 159
 160disable_adj:
 161        ocelot_write(ocelot, 0, PTP_CLK_CFG_ADJ_CFG);
 162
 163        spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 164        return 0;
 165}
 166EXPORT_SYMBOL(ocelot_ptp_adjfine);
 167
 168int ocelot_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
 169                      enum ptp_pin_function func, unsigned int chan)
 170{
 171        switch (func) {
 172        case PTP_PF_NONE:
 173        case PTP_PF_PEROUT:
 174                break;
 175        case PTP_PF_EXTTS:
 176        case PTP_PF_PHYSYNC:
 177                return -1;
 178        }
 179        return 0;
 180}
 181EXPORT_SYMBOL(ocelot_ptp_verify);
 182
 183int ocelot_ptp_enable(struct ptp_clock_info *ptp,
 184                      struct ptp_clock_request *rq, int on)
 185{
 186        struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
 187        struct timespec64 ts_phase, ts_period;
 188        enum ocelot_ptp_pins ptp_pin;
 189        unsigned long flags;
 190        bool pps = false;
 191        int pin = -1;
 192        s64 wf_high;
 193        s64 wf_low;
 194        u32 val;
 195
 196        switch (rq->type) {
 197        case PTP_CLK_REQ_PEROUT:
 198                /* Reject requests with unsupported flags */
 199                if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE |
 200                                         PTP_PEROUT_PHASE))
 201                        return -EOPNOTSUPP;
 202
 203                pin = ptp_find_pin(ocelot->ptp_clock, PTP_PF_PEROUT,
 204                                   rq->perout.index);
 205                if (pin == 0)
 206                        ptp_pin = PTP_PIN_0;
 207                else if (pin == 1)
 208                        ptp_pin = PTP_PIN_1;
 209                else if (pin == 2)
 210                        ptp_pin = PTP_PIN_2;
 211                else if (pin == 3)
 212                        ptp_pin = PTP_PIN_3;
 213                else
 214                        return -EBUSY;
 215
 216                ts_period.tv_sec = rq->perout.period.sec;
 217                ts_period.tv_nsec = rq->perout.period.nsec;
 218
 219                if (ts_period.tv_sec == 1 && ts_period.tv_nsec == 0)
 220                        pps = true;
 221
 222                /* Handle turning off */
 223                if (!on) {
 224                        spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
 225                        val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
 226                        ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
 227                        spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 228                        break;
 229                }
 230
 231                if (rq->perout.flags & PTP_PEROUT_PHASE) {
 232                        ts_phase.tv_sec = rq->perout.phase.sec;
 233                        ts_phase.tv_nsec = rq->perout.phase.nsec;
 234                } else {
 235                        /* Compatibility */
 236                        ts_phase.tv_sec = rq->perout.start.sec;
 237                        ts_phase.tv_nsec = rq->perout.start.nsec;
 238                }
 239                if (ts_phase.tv_sec || (ts_phase.tv_nsec && !pps)) {
 240                        dev_warn(ocelot->dev,
 241                                 "Absolute start time not supported!\n");
 242                        dev_warn(ocelot->dev,
 243                                 "Accept nsec for PPS phase adjustment, otherwise start time should be 0 0.\n");
 244                        return -EINVAL;
 245                }
 246
 247                /* Calculate waveform high and low times */
 248                if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) {
 249                        struct timespec64 ts_on;
 250
 251                        ts_on.tv_sec = rq->perout.on.sec;
 252                        ts_on.tv_nsec = rq->perout.on.nsec;
 253
 254                        wf_high = timespec64_to_ns(&ts_on);
 255                } else {
 256                        if (pps) {
 257                                wf_high = 1000;
 258                        } else {
 259                                wf_high = timespec64_to_ns(&ts_period);
 260                                wf_high = div_s64(wf_high, 2);
 261                        }
 262                }
 263
 264                wf_low = timespec64_to_ns(&ts_period);
 265                wf_low -= wf_high;
 266
 267                /* Handle PPS request */
 268                if (pps) {
 269                        spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
 270                        ocelot_write_rix(ocelot, ts_phase.tv_nsec,
 271                                         PTP_PIN_WF_LOW_PERIOD, ptp_pin);
 272                        ocelot_write_rix(ocelot, wf_high,
 273                                         PTP_PIN_WF_HIGH_PERIOD, ptp_pin);
 274                        val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
 275                        val |= PTP_PIN_CFG_SYNC;
 276                        ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
 277                        spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 278                        break;
 279                }
 280
 281                /* Handle periodic clock */
 282                if (wf_high > 0x3fffffff || wf_high <= 0x6)
 283                        return -EINVAL;
 284                if (wf_low > 0x3fffffff || wf_low <= 0x6)
 285                        return -EINVAL;
 286
 287                spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
 288                ocelot_write_rix(ocelot, wf_low, PTP_PIN_WF_LOW_PERIOD,
 289                                 ptp_pin);
 290                ocelot_write_rix(ocelot, wf_high, PTP_PIN_WF_HIGH_PERIOD,
 291                                 ptp_pin);
 292                val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
 293                ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
 294                spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
 295                break;
 296        default:
 297                return -EOPNOTSUPP;
 298        }
 299        return 0;
 300}
 301EXPORT_SYMBOL(ocelot_ptp_enable);
 302
 303int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info)
 304{
 305        struct ptp_clock *ptp_clock;
 306        int i;
 307
 308        ocelot->ptp_info = *info;
 309
 310        for (i = 0; i < OCELOT_PTP_PINS_NUM; i++) {
 311                struct ptp_pin_desc *p = &ocelot->ptp_pins[i];
 312
 313                snprintf(p->name, sizeof(p->name), "switch_1588_dat%d", i);
 314                p->index = i;
 315                p->func = PTP_PF_NONE;
 316        }
 317
 318        ocelot->ptp_info.pin_config = &ocelot->ptp_pins[0];
 319
 320        ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
 321        if (IS_ERR(ptp_clock))
 322                return PTR_ERR(ptp_clock);
 323        /* Check if PHC support is missing at the configuration level */
 324        if (!ptp_clock)
 325                return 0;
 326
 327        ocelot->ptp_clock = ptp_clock;
 328
 329        ocelot_write(ocelot, SYS_PTP_CFG_PTP_STAMP_WID(30), SYS_PTP_CFG);
 330        ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_LOW);
 331        ocelot_write(ocelot, 0xffffffff, ANA_TABLES_PTP_ID_HIGH);
 332
 333        ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC);
 334
 335        /* There is no device reconfiguration, PTP Rx stamping is always
 336         * enabled.
 337         */
 338        ocelot->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 339
 340        return 0;
 341}
 342EXPORT_SYMBOL(ocelot_init_timestamp);
 343
 344int ocelot_deinit_timestamp(struct ocelot *ocelot)
 345{
 346        if (ocelot->ptp_clock)
 347                ptp_clock_unregister(ocelot->ptp_clock);
 348        return 0;
 349}
 350EXPORT_SYMBOL(ocelot_deinit_timestamp);
 351