1c9c12d33SAleksey Makarov // SPDX-License-Identifier: GPL-2.0 2cb0e3ec4SSunil Goutham /* Marvell RVU Ethernet driver 3c9c12d33SAleksey Makarov * 4cb0e3ec4SSunil Goutham * Copyright (C) 2020 Marvell. 5cb0e3ec4SSunil Goutham * 6c9c12d33SAleksey Makarov */ 7c9c12d33SAleksey Makarov 8c9c12d33SAleksey Makarov #include "otx2_common.h" 9c9c12d33SAleksey Makarov #include "otx2_ptp.h" 10c9c12d33SAleksey Makarov 11c9c12d33SAleksey Makarov static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) 12c9c12d33SAleksey Makarov { 13c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 14c9c12d33SAleksey Makarov ptp_info); 15c9c12d33SAleksey Makarov struct ptp_req *req; 16c9c12d33SAleksey Makarov 17c9c12d33SAleksey Makarov if (!ptp->nic) 18c9c12d33SAleksey Makarov return -ENODEV; 19c9c12d33SAleksey Makarov 20c9c12d33SAleksey Makarov req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 21c9c12d33SAleksey Makarov if (!req) 22c9c12d33SAleksey Makarov return -ENOMEM; 23c9c12d33SAleksey Makarov 24c9c12d33SAleksey Makarov req->op = PTP_OP_ADJFINE; 25c9c12d33SAleksey Makarov req->scaled_ppm = scaled_ppm; 26c9c12d33SAleksey Makarov 27b8d90937SZheng Yongjun return otx2_sync_mbox_msg(&ptp->nic->mbox); 28c9c12d33SAleksey Makarov } 29c9c12d33SAleksey Makarov 30*99bbc4aeSYi Guo static int ptp_set_thresh(struct otx2_ptp *ptp, u64 thresh) 31*99bbc4aeSYi Guo { 32*99bbc4aeSYi Guo struct ptp_req *req; 33*99bbc4aeSYi Guo 34*99bbc4aeSYi Guo if (!ptp->nic) 35*99bbc4aeSYi Guo return -ENODEV; 36*99bbc4aeSYi Guo 37*99bbc4aeSYi Guo req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 38*99bbc4aeSYi Guo if (!req) 39*99bbc4aeSYi Guo return -ENOMEM; 40*99bbc4aeSYi Guo 41*99bbc4aeSYi Guo req->op = PTP_OP_SET_THRESH; 42*99bbc4aeSYi Guo req->thresh = thresh; 43*99bbc4aeSYi Guo 44*99bbc4aeSYi Guo return otx2_sync_mbox_msg(&ptp->nic->mbox); 45*99bbc4aeSYi Guo } 46*99bbc4aeSYi Guo 47c9c12d33SAleksey Makarov static u64 ptp_cc_read(const struct cyclecounter *cc) 48c9c12d33SAleksey Makarov { 49c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(cc, struct otx2_ptp, cycle_counter); 50c9c12d33SAleksey Makarov struct ptp_req *req; 51c9c12d33SAleksey Makarov struct ptp_rsp *rsp; 52c9c12d33SAleksey Makarov int err; 53c9c12d33SAleksey Makarov 54c9c12d33SAleksey Makarov if (!ptp->nic) 55c9c12d33SAleksey Makarov return 0; 56c9c12d33SAleksey Makarov 57c9c12d33SAleksey Makarov req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 58c9c12d33SAleksey Makarov if (!req) 59c9c12d33SAleksey Makarov return 0; 60c9c12d33SAleksey Makarov 61c9c12d33SAleksey Makarov req->op = PTP_OP_GET_CLOCK; 62c9c12d33SAleksey Makarov 63c9c12d33SAleksey Makarov err = otx2_sync_mbox_msg(&ptp->nic->mbox); 64c9c12d33SAleksey Makarov if (err) 65c9c12d33SAleksey Makarov return 0; 66c9c12d33SAleksey Makarov 67c9c12d33SAleksey Makarov rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0, 68c9c12d33SAleksey Makarov &req->hdr); 69c9c12d33SAleksey Makarov if (IS_ERR(rsp)) 70c9c12d33SAleksey Makarov return 0; 71c9c12d33SAleksey Makarov 72c9c12d33SAleksey Makarov return rsp->clk; 73c9c12d33SAleksey Makarov } 74c9c12d33SAleksey Makarov 75*99bbc4aeSYi Guo static u64 ptp_tstmp_read(struct otx2_ptp *ptp) 76*99bbc4aeSYi Guo { 77*99bbc4aeSYi Guo struct ptp_req *req; 78*99bbc4aeSYi Guo struct ptp_rsp *rsp; 79*99bbc4aeSYi Guo int err; 80*99bbc4aeSYi Guo 81*99bbc4aeSYi Guo if (!ptp->nic) 82*99bbc4aeSYi Guo return 0; 83*99bbc4aeSYi Guo 84*99bbc4aeSYi Guo req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 85*99bbc4aeSYi Guo if (!req) 86*99bbc4aeSYi Guo return 0; 87*99bbc4aeSYi Guo 88*99bbc4aeSYi Guo req->op = PTP_OP_GET_TSTMP; 89*99bbc4aeSYi Guo 90*99bbc4aeSYi Guo err = otx2_sync_mbox_msg(&ptp->nic->mbox); 91*99bbc4aeSYi Guo if (err) 92*99bbc4aeSYi Guo return 0; 93*99bbc4aeSYi Guo 94*99bbc4aeSYi Guo rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0, 95*99bbc4aeSYi Guo &req->hdr); 96*99bbc4aeSYi Guo if (IS_ERR(rsp)) 97*99bbc4aeSYi Guo return 0; 98*99bbc4aeSYi Guo 99*99bbc4aeSYi Guo return rsp->clk; 100*99bbc4aeSYi Guo } 101*99bbc4aeSYi Guo 102c9c12d33SAleksey Makarov static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta) 103c9c12d33SAleksey Makarov { 104c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 105c9c12d33SAleksey Makarov ptp_info); 106c9c12d33SAleksey Makarov struct otx2_nic *pfvf = ptp->nic; 107c9c12d33SAleksey Makarov 108c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 109c9c12d33SAleksey Makarov timecounter_adjtime(&ptp->time_counter, delta); 110c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 111c9c12d33SAleksey Makarov 112c9c12d33SAleksey Makarov return 0; 113c9c12d33SAleksey Makarov } 114c9c12d33SAleksey Makarov 115c9c12d33SAleksey Makarov static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info, 116c9c12d33SAleksey Makarov struct timespec64 *ts) 117c9c12d33SAleksey Makarov { 118c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 119c9c12d33SAleksey Makarov ptp_info); 120c9c12d33SAleksey Makarov struct otx2_nic *pfvf = ptp->nic; 121c9c12d33SAleksey Makarov u64 nsec; 122c9c12d33SAleksey Makarov 123c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 124c9c12d33SAleksey Makarov nsec = timecounter_read(&ptp->time_counter); 125c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 126c9c12d33SAleksey Makarov 127c9c12d33SAleksey Makarov *ts = ns_to_timespec64(nsec); 128c9c12d33SAleksey Makarov 129c9c12d33SAleksey Makarov return 0; 130c9c12d33SAleksey Makarov } 131c9c12d33SAleksey Makarov 132c9c12d33SAleksey Makarov static int otx2_ptp_settime(struct ptp_clock_info *ptp_info, 133c9c12d33SAleksey Makarov const struct timespec64 *ts) 134c9c12d33SAleksey Makarov { 135c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 136c9c12d33SAleksey Makarov ptp_info); 137c9c12d33SAleksey Makarov struct otx2_nic *pfvf = ptp->nic; 138c9c12d33SAleksey Makarov u64 nsec; 139c9c12d33SAleksey Makarov 140c9c12d33SAleksey Makarov nsec = timespec64_to_ns(ts); 141c9c12d33SAleksey Makarov 142c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 143c9c12d33SAleksey Makarov timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec); 144c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 145c9c12d33SAleksey Makarov 146c9c12d33SAleksey Makarov return 0; 147c9c12d33SAleksey Makarov } 148c9c12d33SAleksey Makarov 149*99bbc4aeSYi Guo static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, 150*99bbc4aeSYi Guo enum ptp_pin_function func, unsigned int chan) 151*99bbc4aeSYi Guo { 152*99bbc4aeSYi Guo switch (func) { 153*99bbc4aeSYi Guo case PTP_PF_NONE: 154*99bbc4aeSYi Guo case PTP_PF_EXTTS: 155*99bbc4aeSYi Guo break; 156*99bbc4aeSYi Guo case PTP_PF_PEROUT: 157*99bbc4aeSYi Guo case PTP_PF_PHYSYNC: 158*99bbc4aeSYi Guo return -1; 159*99bbc4aeSYi Guo } 160*99bbc4aeSYi Guo return 0; 161*99bbc4aeSYi Guo } 162*99bbc4aeSYi Guo 163*99bbc4aeSYi Guo static void otx2_ptp_extts_check(struct work_struct *work) 164*99bbc4aeSYi Guo { 165*99bbc4aeSYi Guo struct otx2_ptp *ptp = container_of(work, struct otx2_ptp, 166*99bbc4aeSYi Guo extts_work.work); 167*99bbc4aeSYi Guo struct ptp_clock_event event; 168*99bbc4aeSYi Guo u64 tstmp, new_thresh; 169*99bbc4aeSYi Guo 170*99bbc4aeSYi Guo mutex_lock(&ptp->nic->mbox.lock); 171*99bbc4aeSYi Guo tstmp = ptp_tstmp_read(ptp); 172*99bbc4aeSYi Guo mutex_unlock(&ptp->nic->mbox.lock); 173*99bbc4aeSYi Guo 174*99bbc4aeSYi Guo if (tstmp != ptp->last_extts) { 175*99bbc4aeSYi Guo event.type = PTP_CLOCK_EXTTS; 176*99bbc4aeSYi Guo event.index = 0; 177*99bbc4aeSYi Guo event.timestamp = timecounter_cyc2time(&ptp->time_counter, tstmp); 178*99bbc4aeSYi Guo ptp_clock_event(ptp->ptp_clock, &event); 179*99bbc4aeSYi Guo ptp->last_extts = tstmp; 180*99bbc4aeSYi Guo 181*99bbc4aeSYi Guo new_thresh = tstmp % 500000000; 182*99bbc4aeSYi Guo if (ptp->thresh != new_thresh) { 183*99bbc4aeSYi Guo mutex_lock(&ptp->nic->mbox.lock); 184*99bbc4aeSYi Guo ptp_set_thresh(ptp, new_thresh); 185*99bbc4aeSYi Guo mutex_unlock(&ptp->nic->mbox.lock); 186*99bbc4aeSYi Guo ptp->thresh = new_thresh; 187*99bbc4aeSYi Guo } 188*99bbc4aeSYi Guo } 189*99bbc4aeSYi Guo schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200)); 190*99bbc4aeSYi Guo } 191*99bbc4aeSYi Guo 192c9c12d33SAleksey Makarov static int otx2_ptp_enable(struct ptp_clock_info *ptp_info, 193c9c12d33SAleksey Makarov struct ptp_clock_request *rq, int on) 194c9c12d33SAleksey Makarov { 195*99bbc4aeSYi Guo struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 196*99bbc4aeSYi Guo ptp_info); 197*99bbc4aeSYi Guo int pin = -1; 198*99bbc4aeSYi Guo 199*99bbc4aeSYi Guo if (!ptp->nic) 200*99bbc4aeSYi Guo return -ENODEV; 201*99bbc4aeSYi Guo 202*99bbc4aeSYi Guo switch (rq->type) { 203*99bbc4aeSYi Guo case PTP_CLK_REQ_EXTTS: 204*99bbc4aeSYi Guo pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, 205*99bbc4aeSYi Guo rq->extts.index); 206*99bbc4aeSYi Guo if (pin < 0) 207*99bbc4aeSYi Guo return -EBUSY; 208*99bbc4aeSYi Guo if (on) 209*99bbc4aeSYi Guo schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200)); 210*99bbc4aeSYi Guo else 211*99bbc4aeSYi Guo cancel_delayed_work_sync(&ptp->extts_work); 212*99bbc4aeSYi Guo return 0; 213*99bbc4aeSYi Guo default: 214*99bbc4aeSYi Guo break; 215*99bbc4aeSYi Guo } 216c9c12d33SAleksey Makarov return -EOPNOTSUPP; 217c9c12d33SAleksey Makarov } 218c9c12d33SAleksey Makarov 219c9c12d33SAleksey Makarov int otx2_ptp_init(struct otx2_nic *pfvf) 220c9c12d33SAleksey Makarov { 221c9c12d33SAleksey Makarov struct otx2_ptp *ptp_ptr; 222c9c12d33SAleksey Makarov struct cyclecounter *cc; 223c9c12d33SAleksey Makarov struct ptp_req *req; 224c9c12d33SAleksey Makarov int err; 225c9c12d33SAleksey Makarov 226c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 227c9c12d33SAleksey Makarov /* check if PTP block is available */ 228c9c12d33SAleksey Makarov req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox); 229c9c12d33SAleksey Makarov if (!req) { 230c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 231c9c12d33SAleksey Makarov return -ENOMEM; 232c9c12d33SAleksey Makarov } 233c9c12d33SAleksey Makarov 234c9c12d33SAleksey Makarov req->op = PTP_OP_GET_CLOCK; 235c9c12d33SAleksey Makarov 236c9c12d33SAleksey Makarov err = otx2_sync_mbox_msg(&pfvf->mbox); 237c9c12d33SAleksey Makarov if (err) { 238c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 239c9c12d33SAleksey Makarov return err; 240c9c12d33SAleksey Makarov } 241c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 242c9c12d33SAleksey Makarov 243c9c12d33SAleksey Makarov ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL); 244c9c12d33SAleksey Makarov if (!ptp_ptr) { 245c9c12d33SAleksey Makarov err = -ENOMEM; 246c9c12d33SAleksey Makarov goto error; 247c9c12d33SAleksey Makarov } 248c9c12d33SAleksey Makarov 249c9c12d33SAleksey Makarov ptp_ptr->nic = pfvf; 250c9c12d33SAleksey Makarov 251c9c12d33SAleksey Makarov cc = &ptp_ptr->cycle_counter; 252c9c12d33SAleksey Makarov cc->read = ptp_cc_read; 253c9c12d33SAleksey Makarov cc->mask = CYCLECOUNTER_MASK(64); 254c9c12d33SAleksey Makarov cc->mult = 1; 255c9c12d33SAleksey Makarov cc->shift = 0; 256c9c12d33SAleksey Makarov 257c9c12d33SAleksey Makarov timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter, 258c9c12d33SAleksey Makarov ktime_to_ns(ktime_get_real())); 259c9c12d33SAleksey Makarov 260*99bbc4aeSYi Guo snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP"); 261*99bbc4aeSYi Guo ptp_ptr->extts_config.index = 0; 262*99bbc4aeSYi Guo ptp_ptr->extts_config.func = PTP_PF_NONE; 263*99bbc4aeSYi Guo 264c9c12d33SAleksey Makarov ptp_ptr->ptp_info = (struct ptp_clock_info) { 265c9c12d33SAleksey Makarov .owner = THIS_MODULE, 266c9c12d33SAleksey Makarov .name = "OcteonTX2 PTP", 267c9c12d33SAleksey Makarov .max_adj = 1000000000ull, 268*99bbc4aeSYi Guo .n_ext_ts = 1, 269*99bbc4aeSYi Guo .n_pins = 1, 270c9c12d33SAleksey Makarov .pps = 0, 271*99bbc4aeSYi Guo .pin_config = &ptp_ptr->extts_config, 272c9c12d33SAleksey Makarov .adjfine = otx2_ptp_adjfine, 273c9c12d33SAleksey Makarov .adjtime = otx2_ptp_adjtime, 274c9c12d33SAleksey Makarov .gettime64 = otx2_ptp_gettime, 275c9c12d33SAleksey Makarov .settime64 = otx2_ptp_settime, 276c9c12d33SAleksey Makarov .enable = otx2_ptp_enable, 277*99bbc4aeSYi Guo .verify = otx2_ptp_verify_pin, 278c9c12d33SAleksey Makarov }; 279c9c12d33SAleksey Makarov 280*99bbc4aeSYi Guo INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check); 281*99bbc4aeSYi Guo 282c9c12d33SAleksey Makarov ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev); 283c9c12d33SAleksey Makarov if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) { 284c9c12d33SAleksey Makarov err = ptp_ptr->ptp_clock ? 285c9c12d33SAleksey Makarov PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV; 286c9c12d33SAleksey Makarov kfree(ptp_ptr); 287c9c12d33SAleksey Makarov goto error; 288c9c12d33SAleksey Makarov } 289c9c12d33SAleksey Makarov 290c9c12d33SAleksey Makarov pfvf->ptp = ptp_ptr; 291c9c12d33SAleksey Makarov 292c9c12d33SAleksey Makarov error: 293c9c12d33SAleksey Makarov return err; 294c9c12d33SAleksey Makarov } 295c9c12d33SAleksey Makarov 296c9c12d33SAleksey Makarov void otx2_ptp_destroy(struct otx2_nic *pfvf) 297c9c12d33SAleksey Makarov { 298c9c12d33SAleksey Makarov struct otx2_ptp *ptp = pfvf->ptp; 299c9c12d33SAleksey Makarov 300c9c12d33SAleksey Makarov if (!ptp) 301c9c12d33SAleksey Makarov return; 302c9c12d33SAleksey Makarov 303c9c12d33SAleksey Makarov ptp_clock_unregister(ptp->ptp_clock); 304c9c12d33SAleksey Makarov kfree(ptp); 305c9c12d33SAleksey Makarov pfvf->ptp = NULL; 306c9c12d33SAleksey Makarov } 307c9c12d33SAleksey Makarov 308c9c12d33SAleksey Makarov int otx2_ptp_clock_index(struct otx2_nic *pfvf) 309c9c12d33SAleksey Makarov { 310c9c12d33SAleksey Makarov if (!pfvf->ptp) 311c9c12d33SAleksey Makarov return -ENODEV; 312c9c12d33SAleksey Makarov 313c9c12d33SAleksey Makarov return ptp_clock_index(pfvf->ptp->ptp_clock); 314c9c12d33SAleksey Makarov } 315c9c12d33SAleksey Makarov 316c9c12d33SAleksey Makarov int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns) 317c9c12d33SAleksey Makarov { 318c9c12d33SAleksey Makarov if (!pfvf->ptp) 319c9c12d33SAleksey Makarov return -ENODEV; 320c9c12d33SAleksey Makarov 321c9c12d33SAleksey Makarov *tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp); 322c9c12d33SAleksey Makarov 323c9c12d33SAleksey Makarov return 0; 324c9c12d33SAleksey Makarov } 325