0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include <linux/io.h>
0036 #include <linux/ptp_clock_kernel.h>
0037 #include <linux/slab.h>
0038
0039 #include "mvpp2.h"
0040
0041 #define CR0_SW_NRESET BIT(0)
0042
0043 #define TCFCR0_PHASE_UPDATE_ENABLE BIT(8)
0044 #define TCFCR0_TCF_MASK (7 << 2)
0045 #define TCFCR0_TCF_UPDATE (0 << 2)
0046 #define TCFCR0_TCF_FREQUPDATE (1 << 2)
0047 #define TCFCR0_TCF_INCREMENT (2 << 2)
0048 #define TCFCR0_TCF_DECREMENT (3 << 2)
0049 #define TCFCR0_TCF_CAPTURE (4 << 2)
0050 #define TCFCR0_TCF_NOP (7 << 2)
0051 #define TCFCR0_TCF_TRIGGER BIT(0)
0052
0053 #define TCSR_CAPTURE_1_VALID BIT(1)
0054 #define TCSR_CAPTURE_0_VALID BIT(0)
0055
0056 struct mvpp2_tai {
0057 struct ptp_clock_info caps;
0058 struct ptp_clock *ptp_clock;
0059 void __iomem *base;
0060 spinlock_t lock;
0061 u64 period;
0062
0063 struct timespec64 stamp;
0064 };
0065
0066 static void mvpp2_tai_modify(void __iomem *reg, u32 mask, u32 set)
0067 {
0068 u32 val;
0069
0070 val = readl_relaxed(reg) & ~mask;
0071 val |= set & mask;
0072 writel(val, reg);
0073 }
0074
0075 static void mvpp2_tai_write(u32 val, void __iomem *reg)
0076 {
0077 writel_relaxed(val & 0xffff, reg);
0078 }
0079
0080 static u32 mvpp2_tai_read(void __iomem *reg)
0081 {
0082 return readl_relaxed(reg) & 0xffff;
0083 }
0084
0085 static struct mvpp2_tai *ptp_to_tai(struct ptp_clock_info *ptp)
0086 {
0087 return container_of(ptp, struct mvpp2_tai, caps);
0088 }
0089
0090 static void mvpp22_tai_read_ts(struct timespec64 *ts, void __iomem *base)
0091 {
0092 ts->tv_sec = (u64)mvpp2_tai_read(base + 0) << 32 |
0093 mvpp2_tai_read(base + 4) << 16 |
0094 mvpp2_tai_read(base + 8);
0095
0096 ts->tv_nsec = mvpp2_tai_read(base + 12) << 16 |
0097 mvpp2_tai_read(base + 16);
0098
0099
0100 readl_relaxed(base + 20);
0101 readl_relaxed(base + 24);
0102 }
0103
0104 static void mvpp2_tai_write_tlv(const struct timespec64 *ts, u32 frac,
0105 void __iomem *base)
0106 {
0107 mvpp2_tai_write(ts->tv_sec >> 32, base + MVPP22_TAI_TLV_SEC_HIGH);
0108 mvpp2_tai_write(ts->tv_sec >> 16, base + MVPP22_TAI_TLV_SEC_MED);
0109 mvpp2_tai_write(ts->tv_sec, base + MVPP22_TAI_TLV_SEC_LOW);
0110 mvpp2_tai_write(ts->tv_nsec >> 16, base + MVPP22_TAI_TLV_NANO_HIGH);
0111 mvpp2_tai_write(ts->tv_nsec, base + MVPP22_TAI_TLV_NANO_LOW);
0112 mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
0113 mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
0114 }
0115
0116 static void mvpp2_tai_op(u32 op, void __iomem *base)
0117 {
0118
0119
0120
0121 mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
0122 TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
0123 op | TCFCR0_TCF_TRIGGER);
0124 mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
0125 TCFCR0_TCF_NOP);
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152 static u64 mvpp22_calc_frac_ppm(struct mvpp2_tai *tai, long abs_scaled_ppm)
0153 {
0154 u64 val = tai->period * abs_scaled_ppm >> 4;
0155
0156 return div_u64(val, (1000000 << 12) + (abs_scaled_ppm >> 4));
0157 }
0158
0159 static s32 mvpp22_calc_max_adj(struct mvpp2_tai *tai)
0160 {
0161 return 1000000;
0162 }
0163
0164 static int mvpp22_tai_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
0165 {
0166 struct mvpp2_tai *tai = ptp_to_tai(ptp);
0167 unsigned long flags;
0168 void __iomem *base;
0169 bool neg_adj;
0170 s32 frac;
0171 u64 val;
0172
0173 neg_adj = scaled_ppm < 0;
0174 if (neg_adj)
0175 scaled_ppm = -scaled_ppm;
0176
0177 val = mvpp22_calc_frac_ppm(tai, scaled_ppm);
0178
0179
0180 if (neg_adj) {
0181
0182
0183
0184 if (val > 0x80000000)
0185 return -ERANGE;
0186
0187 frac = -val;
0188 } else {
0189 if (val > S32_MAX)
0190 return -ERANGE;
0191
0192 frac = val;
0193 }
0194
0195 base = tai->base;
0196 spin_lock_irqsave(&tai->lock, flags);
0197 mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
0198 mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
0199 mvpp2_tai_op(TCFCR0_TCF_FREQUPDATE, base);
0200 spin_unlock_irqrestore(&tai->lock, flags);
0201
0202 return 0;
0203 }
0204
0205 static int mvpp22_tai_adjtime(struct ptp_clock_info *ptp, s64 delta)
0206 {
0207 struct mvpp2_tai *tai = ptp_to_tai(ptp);
0208 struct timespec64 ts;
0209 unsigned long flags;
0210 void __iomem *base;
0211 u32 tcf;
0212
0213
0214 if (delta == S64_MIN)
0215 return -ERANGE;
0216
0217 if (delta < 0) {
0218 delta = -delta;
0219 tcf = TCFCR0_TCF_DECREMENT;
0220 } else {
0221 tcf = TCFCR0_TCF_INCREMENT;
0222 }
0223
0224 ts = ns_to_timespec64(delta);
0225
0226 base = tai->base;
0227 spin_lock_irqsave(&tai->lock, flags);
0228 mvpp2_tai_write_tlv(&ts, 0, base);
0229 mvpp2_tai_op(tcf, base);
0230 spin_unlock_irqrestore(&tai->lock, flags);
0231
0232 return 0;
0233 }
0234
0235 static int mvpp22_tai_gettimex64(struct ptp_clock_info *ptp,
0236 struct timespec64 *ts,
0237 struct ptp_system_timestamp *sts)
0238 {
0239 struct mvpp2_tai *tai = ptp_to_tai(ptp);
0240 unsigned long flags;
0241 void __iomem *base;
0242 u32 tcsr;
0243 int ret;
0244
0245 base = tai->base;
0246 spin_lock_irqsave(&tai->lock, flags);
0247
0248
0249
0250
0251
0252 ptp_read_system_prets(sts);
0253 mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
0254 TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
0255 TCFCR0_TCF_CAPTURE | TCFCR0_TCF_TRIGGER);
0256 ptp_read_system_postts(sts);
0257 mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
0258 TCFCR0_TCF_NOP);
0259
0260 tcsr = readl(base + MVPP22_TAI_TCSR);
0261 if (tcsr & TCSR_CAPTURE_1_VALID) {
0262 mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV1_SEC_HIGH);
0263 ret = 0;
0264 } else if (tcsr & TCSR_CAPTURE_0_VALID) {
0265 mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV0_SEC_HIGH);
0266 ret = 0;
0267 } else {
0268
0269 ret = -EBUSY;
0270 }
0271 spin_unlock_irqrestore(&tai->lock, flags);
0272
0273 return ret;
0274 }
0275
0276 static int mvpp22_tai_settime64(struct ptp_clock_info *ptp,
0277 const struct timespec64 *ts)
0278 {
0279 struct mvpp2_tai *tai = ptp_to_tai(ptp);
0280 unsigned long flags;
0281 void __iomem *base;
0282
0283 base = tai->base;
0284 spin_lock_irqsave(&tai->lock, flags);
0285 mvpp2_tai_write_tlv(ts, 0, base);
0286
0287
0288
0289
0290
0291 mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
0292 TCFCR0_PHASE_UPDATE_ENABLE |
0293 TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
0294 TCFCR0_TCF_UPDATE | TCFCR0_TCF_TRIGGER);
0295 mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
0296 TCFCR0_TCF_NOP);
0297 spin_unlock_irqrestore(&tai->lock, flags);
0298
0299 return 0;
0300 }
0301
0302 static long mvpp22_tai_aux_work(struct ptp_clock_info *ptp)
0303 {
0304 struct mvpp2_tai *tai = ptp_to_tai(ptp);
0305
0306 mvpp22_tai_gettimex64(ptp, &tai->stamp, NULL);
0307
0308 return msecs_to_jiffies(2000);
0309 }
0310
0311 static void mvpp22_tai_set_step(struct mvpp2_tai *tai)
0312 {
0313 void __iomem *base = tai->base;
0314 u32 nano, frac;
0315
0316 nano = upper_32_bits(tai->period);
0317 frac = lower_32_bits(tai->period);
0318
0319
0320
0321
0322 if (frac >= 0x80000000)
0323 nano += 1;
0324
0325 mvpp2_tai_write(nano, base + MVPP22_TAI_TOD_STEP_NANO_CR);
0326 mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TOD_STEP_FRAC_HIGH);
0327 mvpp2_tai_write(frac, base + MVPP22_TAI_TOD_STEP_FRAC_LOW);
0328 }
0329
0330 static void mvpp22_tai_init(struct mvpp2_tai *tai)
0331 {
0332 void __iomem *base = tai->base;
0333
0334 mvpp22_tai_set_step(tai);
0335
0336
0337 mvpp2_tai_modify(base + MVPP22_TAI_CR0, CR0_SW_NRESET, CR0_SW_NRESET);
0338 }
0339
0340 int mvpp22_tai_ptp_clock_index(struct mvpp2_tai *tai)
0341 {
0342 return ptp_clock_index(tai->ptp_clock);
0343 }
0344
0345 void mvpp22_tai_tstamp(struct mvpp2_tai *tai, u32 tstamp,
0346 struct skb_shared_hwtstamps *hwtstamp)
0347 {
0348 struct timespec64 ts;
0349 int delta;
0350
0351
0352
0353
0354
0355 ts.tv_sec = READ_ONCE(tai->stamp.tv_sec);
0356 ts.tv_nsec = tstamp & 0x3fffffff;
0357
0358
0359
0360
0361
0362 delta = ((tstamp >> 30) - (ts.tv_sec & 3)) & 3;
0363 if (delta == 3)
0364 delta -= 4;
0365 ts.tv_sec += delta;
0366
0367 memset(hwtstamp, 0, sizeof(*hwtstamp));
0368 hwtstamp->hwtstamp = timespec64_to_ktime(ts);
0369 }
0370
0371 void mvpp22_tai_start(struct mvpp2_tai *tai)
0372 {
0373 long delay;
0374
0375 delay = mvpp22_tai_aux_work(&tai->caps);
0376
0377 ptp_schedule_worker(tai->ptp_clock, delay);
0378 }
0379
0380 void mvpp22_tai_stop(struct mvpp2_tai *tai)
0381 {
0382 ptp_cancel_worker_sync(tai->ptp_clock);
0383 }
0384
0385 static void mvpp22_tai_remove(void *priv)
0386 {
0387 struct mvpp2_tai *tai = priv;
0388
0389 if (!IS_ERR(tai->ptp_clock))
0390 ptp_clock_unregister(tai->ptp_clock);
0391 }
0392
0393 int mvpp22_tai_probe(struct device *dev, struct mvpp2 *priv)
0394 {
0395 struct mvpp2_tai *tai;
0396 int ret;
0397
0398 tai = devm_kzalloc(dev, sizeof(*tai), GFP_KERNEL);
0399 if (!tai)
0400 return -ENOMEM;
0401
0402 spin_lock_init(&tai->lock);
0403
0404 tai->base = priv->iface_base;
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433 tai->period = 3ULL << 32;
0434
0435 mvpp22_tai_init(tai);
0436
0437 tai->caps.owner = THIS_MODULE;
0438 strscpy(tai->caps.name, "Marvell PP2.2", sizeof(tai->caps.name));
0439 tai->caps.max_adj = mvpp22_calc_max_adj(tai);
0440 tai->caps.adjfine = mvpp22_tai_adjfine;
0441 tai->caps.adjtime = mvpp22_tai_adjtime;
0442 tai->caps.gettimex64 = mvpp22_tai_gettimex64;
0443 tai->caps.settime64 = mvpp22_tai_settime64;
0444 tai->caps.do_aux_work = mvpp22_tai_aux_work;
0445
0446 ret = devm_add_action(dev, mvpp22_tai_remove, tai);
0447 if (ret)
0448 return ret;
0449
0450 tai->ptp_clock = ptp_clock_register(&tai->caps, dev);
0451 if (IS_ERR(tai->ptp_clock))
0452 return PTR_ERR(tai->ptp_clock);
0453
0454 priv->tai = tai;
0455
0456 return 0;
0457 }