0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/bitfield.h>
0009 #include <linux/device.h>
0010 #include <linux/module.h>
0011 #include <linux/pci.h>
0012
0013 #include "ptp.h"
0014 #include "mbox.h"
0015 #include "rvu.h"
0016
0017 #define DRV_NAME "Marvell PTP Driver"
0018
0019 #define PCI_DEVID_OCTEONTX2_PTP 0xA00C
0020 #define PCI_SUBSYS_DEVID_OCTX2_98xx_PTP 0xB100
0021 #define PCI_SUBSYS_DEVID_OCTX2_96XX_PTP 0xB200
0022 #define PCI_SUBSYS_DEVID_OCTX2_95XX_PTP 0xB300
0023 #define PCI_SUBSYS_DEVID_OCTX2_95XXN_PTP 0xB400
0024 #define PCI_SUBSYS_DEVID_OCTX2_95MM_PTP 0xB500
0025 #define PCI_SUBSYS_DEVID_OCTX2_95XXO_PTP 0xB600
0026 #define PCI_DEVID_OCTEONTX2_RST 0xA085
0027 #define PCI_DEVID_CN10K_PTP 0xA09E
0028 #define PCI_SUBSYS_DEVID_CN10K_A_PTP 0xB900
0029 #define PCI_SUBSYS_DEVID_CNF10K_A_PTP 0xBA00
0030 #define PCI_SUBSYS_DEVID_CNF10K_B_PTP 0xBC00
0031
0032 #define PCI_PTP_BAR_NO 0
0033
0034 #define PTP_CLOCK_CFG 0xF00ULL
0035 #define PTP_CLOCK_CFG_PTP_EN BIT_ULL(0)
0036 #define PTP_CLOCK_CFG_EXT_CLK_EN BIT_ULL(1)
0037 #define PTP_CLOCK_CFG_EXT_CLK_IN_MASK GENMASK_ULL(7, 2)
0038 #define PTP_CLOCK_CFG_TSTMP_EDGE BIT_ULL(9)
0039 #define PTP_CLOCK_CFG_TSTMP_EN BIT_ULL(8)
0040 #define PTP_CLOCK_CFG_TSTMP_IN_MASK GENMASK_ULL(15, 10)
0041 #define PTP_CLOCK_CFG_PPS_EN BIT_ULL(30)
0042 #define PTP_CLOCK_CFG_PPS_INV BIT_ULL(31)
0043
0044 #define PTP_PPS_HI_INCR 0xF60ULL
0045 #define PTP_PPS_LO_INCR 0xF68ULL
0046 #define PTP_PPS_THRESH_HI 0xF58ULL
0047
0048 #define PTP_CLOCK_LO 0xF08ULL
0049 #define PTP_CLOCK_HI 0xF10ULL
0050 #define PTP_CLOCK_COMP 0xF18ULL
0051 #define PTP_TIMESTAMP 0xF20ULL
0052 #define PTP_CLOCK_SEC 0xFD0ULL
0053
0054 #define CYCLE_MULT 1000
0055
0056 static struct ptp *first_ptp_block;
0057 static const struct pci_device_id ptp_id_table[];
0058
0059 static bool cn10k_ptp_errata(struct ptp *ptp)
0060 {
0061 if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP ||
0062 ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP)
0063 return true;
0064 return false;
0065 }
0066
0067 static bool is_ptp_tsfmt_sec_nsec(struct ptp *ptp)
0068 {
0069 if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP ||
0070 ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP)
0071 return true;
0072 return false;
0073 }
0074
0075 static u64 read_ptp_tstmp_sec_nsec(struct ptp *ptp)
0076 {
0077 u64 sec, sec1, nsec;
0078 unsigned long flags;
0079
0080 spin_lock_irqsave(&ptp->ptp_lock, flags);
0081 sec = readq(ptp->reg_base + PTP_CLOCK_SEC) & 0xFFFFFFFFUL;
0082 nsec = readq(ptp->reg_base + PTP_CLOCK_HI);
0083 sec1 = readq(ptp->reg_base + PTP_CLOCK_SEC) & 0xFFFFFFFFUL;
0084
0085 if (sec1 > sec) {
0086 nsec = readq(ptp->reg_base + PTP_CLOCK_HI);
0087 sec = sec1;
0088 }
0089 spin_unlock_irqrestore(&ptp->ptp_lock, flags);
0090
0091 return sec * NSEC_PER_SEC + nsec;
0092 }
0093
0094 static u64 read_ptp_tstmp_nsec(struct ptp *ptp)
0095 {
0096 return readq(ptp->reg_base + PTP_CLOCK_HI);
0097 }
0098
0099 static u64 ptp_calc_adjusted_comp(u64 ptp_clock_freq)
0100 {
0101 u64 comp, adj = 0, cycles_per_sec, ns_drift = 0;
0102 u32 ptp_clock_nsec, cycle_time;
0103 int cycle;
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 comp = ((u64)1000000000ULL << 32) / ptp_clock_freq;
0116
0117 cycle_time = NSEC_PER_SEC * CYCLE_MULT / ptp_clock_freq;
0118
0119 cycles_per_sec = ptp_clock_freq;
0120
0121
0122 cycle = cycles_per_sec - 1;
0123 ptp_clock_nsec = (cycle * comp) >> 32;
0124 while (ptp_clock_nsec < NSEC_PER_SEC) {
0125 if (ptp_clock_nsec == 0x3B9AC9FF)
0126 goto calc_adj_comp;
0127 cycle++;
0128 ptp_clock_nsec = (cycle * comp) >> 32;
0129 }
0130
0131 ns_drift = ptp_clock_nsec - NSEC_PER_SEC;
0132
0133 if (ns_drift > 0) {
0134 adj = comp * ns_drift;
0135 adj = adj / 1000000000ULL;
0136 }
0137
0138 comp += adj;
0139 return comp;
0140
0141 calc_adj_comp:
0142
0143 adj = comp * cycle_time;
0144 adj = adj / 1000000000ULL;
0145 adj = adj / CYCLE_MULT;
0146 comp -= adj;
0147
0148 return comp;
0149 }
0150
0151 struct ptp *ptp_get(void)
0152 {
0153 struct ptp *ptp = first_ptp_block;
0154
0155
0156 if (!pci_dev_present(ptp_id_table))
0157 return ERR_PTR(-ENODEV);
0158
0159 if (!ptp)
0160 ptp = ERR_PTR(-EPROBE_DEFER);
0161 else
0162 pci_dev_get(ptp->pdev);
0163
0164 return ptp;
0165 }
0166
0167 void ptp_put(struct ptp *ptp)
0168 {
0169 if (!ptp)
0170 return;
0171
0172 pci_dev_put(ptp->pdev);
0173 }
0174
0175 static int ptp_adjfine(struct ptp *ptp, long scaled_ppm)
0176 {
0177 bool neg_adj = false;
0178 u32 freq, freq_adj;
0179 u64 comp, adj;
0180 s64 ppb;
0181
0182 if (scaled_ppm < 0) {
0183 neg_adj = true;
0184 scaled_ppm = -scaled_ppm;
0185 }
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 ppb = 1 + scaled_ppm;
0203 ppb *= 125;
0204 ppb >>= 13;
0205
0206 if (cn10k_ptp_errata(ptp)) {
0207
0208 freq_adj = (ptp->clock_rate * ppb) / 1000000000ULL;
0209 freq = neg_adj ? ptp->clock_rate + freq_adj : ptp->clock_rate - freq_adj;
0210 comp = ptp_calc_adjusted_comp(freq);
0211 } else {
0212 comp = ((u64)1000000000ull << 32) / ptp->clock_rate;
0213 adj = comp * ppb;
0214 adj = div_u64(adj, 1000000000ull);
0215 comp = neg_adj ? comp - adj : comp + adj;
0216 }
0217 writeq(comp, ptp->reg_base + PTP_CLOCK_COMP);
0218
0219 return 0;
0220 }
0221
0222 static int ptp_get_clock(struct ptp *ptp, u64 *clk)
0223 {
0224
0225 *clk = ptp->read_ptp_tstmp(ptp);
0226
0227 return 0;
0228 }
0229
0230 void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
0231 {
0232 struct pci_dev *pdev;
0233 u64 clock_comp;
0234 u64 clock_cfg;
0235
0236 if (!ptp)
0237 return;
0238
0239 pdev = ptp->pdev;
0240
0241 if (!sclk) {
0242 dev_err(&pdev->dev, "PTP input clock cannot be zero\n");
0243 return;
0244 }
0245
0246
0247 ptp->clock_rate = sclk * 1000000;
0248
0249
0250 clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG);
0251
0252 if (ext_clk_freq) {
0253 ptp->clock_rate = ext_clk_freq;
0254
0255 clock_cfg &= ~PTP_CLOCK_CFG_EXT_CLK_IN_MASK;
0256 clock_cfg |= PTP_CLOCK_CFG_EXT_CLK_EN;
0257 }
0258
0259 if (extts) {
0260 clock_cfg |= PTP_CLOCK_CFG_TSTMP_EDGE;
0261
0262 clock_cfg &= ~PTP_CLOCK_CFG_TSTMP_IN_MASK;
0263 clock_cfg |= PTP_CLOCK_CFG_TSTMP_EN;
0264 }
0265
0266 clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
0267 clock_cfg |= PTP_CLOCK_CFG_PPS_EN | PTP_CLOCK_CFG_PPS_INV;
0268 writeq(clock_cfg, ptp->reg_base + PTP_CLOCK_CFG);
0269
0270
0271 writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_HI_INCR);
0272 writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_LO_INCR);
0273
0274 if (cn10k_ptp_errata(ptp))
0275 clock_comp = ptp_calc_adjusted_comp(ptp->clock_rate);
0276 else
0277 clock_comp = ((u64)1000000000ull << 32) / ptp->clock_rate;
0278
0279
0280 writeq(clock_comp, ptp->reg_base + PTP_CLOCK_COMP);
0281 }
0282
0283 static int ptp_get_tstmp(struct ptp *ptp, u64 *clk)
0284 {
0285 *clk = readq(ptp->reg_base + PTP_TIMESTAMP);
0286
0287 return 0;
0288 }
0289
0290 static int ptp_set_thresh(struct ptp *ptp, u64 thresh)
0291 {
0292 writeq(thresh, ptp->reg_base + PTP_PPS_THRESH_HI);
0293
0294 return 0;
0295 }
0296
0297 static int ptp_probe(struct pci_dev *pdev,
0298 const struct pci_device_id *ent)
0299 {
0300 struct device *dev = &pdev->dev;
0301 struct ptp *ptp;
0302 int err;
0303
0304 ptp = devm_kzalloc(dev, sizeof(*ptp), GFP_KERNEL);
0305 if (!ptp) {
0306 err = -ENOMEM;
0307 goto error;
0308 }
0309
0310 ptp->pdev = pdev;
0311
0312 err = pcim_enable_device(pdev);
0313 if (err)
0314 goto error_free;
0315
0316 err = pcim_iomap_regions(pdev, 1 << PCI_PTP_BAR_NO, pci_name(pdev));
0317 if (err)
0318 goto error_free;
0319
0320 ptp->reg_base = pcim_iomap_table(pdev)[PCI_PTP_BAR_NO];
0321
0322 pci_set_drvdata(pdev, ptp);
0323 if (!first_ptp_block)
0324 first_ptp_block = ptp;
0325
0326 spin_lock_init(&ptp->ptp_lock);
0327 if (is_ptp_tsfmt_sec_nsec(ptp))
0328 ptp->read_ptp_tstmp = &read_ptp_tstmp_sec_nsec;
0329 else
0330 ptp->read_ptp_tstmp = &read_ptp_tstmp_nsec;
0331
0332 return 0;
0333
0334 error_free:
0335 devm_kfree(dev, ptp);
0336
0337 error:
0338
0339
0340
0341
0342
0343
0344 pci_set_drvdata(pdev, ERR_PTR(err));
0345 if (!first_ptp_block)
0346 first_ptp_block = ERR_PTR(err);
0347
0348 return 0;
0349 }
0350
0351 static void ptp_remove(struct pci_dev *pdev)
0352 {
0353 struct ptp *ptp = pci_get_drvdata(pdev);
0354 u64 clock_cfg;
0355
0356 if (IS_ERR_OR_NULL(ptp))
0357 return;
0358
0359
0360 clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG);
0361 clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
0362 writeq(clock_cfg, ptp->reg_base + PTP_CLOCK_CFG);
0363 }
0364
0365 static const struct pci_device_id ptp_id_table[] = {
0366 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_PTP,
0367 PCI_VENDOR_ID_CAVIUM,
0368 PCI_SUBSYS_DEVID_OCTX2_98xx_PTP) },
0369 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_PTP,
0370 PCI_VENDOR_ID_CAVIUM,
0371 PCI_SUBSYS_DEVID_OCTX2_96XX_PTP) },
0372 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_PTP,
0373 PCI_VENDOR_ID_CAVIUM,
0374 PCI_SUBSYS_DEVID_OCTX2_95XX_PTP) },
0375 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_PTP,
0376 PCI_VENDOR_ID_CAVIUM,
0377 PCI_SUBSYS_DEVID_OCTX2_95XXN_PTP) },
0378 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_PTP,
0379 PCI_VENDOR_ID_CAVIUM,
0380 PCI_SUBSYS_DEVID_OCTX2_95MM_PTP) },
0381 { PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_PTP,
0382 PCI_VENDOR_ID_CAVIUM,
0383 PCI_SUBSYS_DEVID_OCTX2_95XXO_PTP) },
0384 { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_CN10K_PTP) },
0385 { 0, }
0386 };
0387
0388 struct pci_driver ptp_driver = {
0389 .name = DRV_NAME,
0390 .id_table = ptp_id_table,
0391 .probe = ptp_probe,
0392 .remove = ptp_remove,
0393 };
0394
0395 int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req,
0396 struct ptp_rsp *rsp)
0397 {
0398 int err = 0;
0399
0400
0401
0402
0403
0404
0405
0406
0407 if (!rvu->ptp)
0408 return -ENODEV;
0409
0410 switch (req->op) {
0411 case PTP_OP_ADJFINE:
0412 err = ptp_adjfine(rvu->ptp, req->scaled_ppm);
0413 break;
0414 case PTP_OP_GET_CLOCK:
0415 err = ptp_get_clock(rvu->ptp, &rsp->clk);
0416 break;
0417 case PTP_OP_GET_TSTMP:
0418 err = ptp_get_tstmp(rvu->ptp, &rsp->clk);
0419 break;
0420 case PTP_OP_SET_THRESH:
0421 err = ptp_set_thresh(rvu->ptp, req->thresh);
0422 break;
0423 default:
0424 err = -EINVAL;
0425 break;
0426 }
0427
0428 return err;
0429 }