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 3099bbc4aeSYi Guo static int ptp_set_thresh(struct otx2_ptp *ptp, u64 thresh) 3199bbc4aeSYi Guo { 3299bbc4aeSYi Guo struct ptp_req *req; 3399bbc4aeSYi Guo 3499bbc4aeSYi Guo if (!ptp->nic) 3599bbc4aeSYi Guo return -ENODEV; 3699bbc4aeSYi Guo 3799bbc4aeSYi Guo req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 3899bbc4aeSYi Guo if (!req) 3999bbc4aeSYi Guo return -ENOMEM; 4099bbc4aeSYi Guo 4199bbc4aeSYi Guo req->op = PTP_OP_SET_THRESH; 4299bbc4aeSYi Guo req->thresh = thresh; 4399bbc4aeSYi Guo 4499bbc4aeSYi Guo return otx2_sync_mbox_msg(&ptp->nic->mbox); 4599bbc4aeSYi Guo } 4699bbc4aeSYi 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 7599bbc4aeSYi Guo static u64 ptp_tstmp_read(struct otx2_ptp *ptp) 7699bbc4aeSYi Guo { 7799bbc4aeSYi Guo struct ptp_req *req; 7899bbc4aeSYi Guo struct ptp_rsp *rsp; 7999bbc4aeSYi Guo int err; 8099bbc4aeSYi Guo 8199bbc4aeSYi Guo if (!ptp->nic) 8299bbc4aeSYi Guo return 0; 8399bbc4aeSYi Guo 8499bbc4aeSYi Guo req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 8599bbc4aeSYi Guo if (!req) 8699bbc4aeSYi Guo return 0; 8799bbc4aeSYi Guo 8899bbc4aeSYi Guo req->op = PTP_OP_GET_TSTMP; 8999bbc4aeSYi Guo 9099bbc4aeSYi Guo err = otx2_sync_mbox_msg(&ptp->nic->mbox); 9199bbc4aeSYi Guo if (err) 9299bbc4aeSYi Guo return 0; 9399bbc4aeSYi Guo 9499bbc4aeSYi Guo rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0, 9599bbc4aeSYi Guo &req->hdr); 9699bbc4aeSYi Guo if (IS_ERR(rsp)) 9799bbc4aeSYi Guo return 0; 9899bbc4aeSYi Guo 9999bbc4aeSYi Guo return rsp->clk; 10099bbc4aeSYi Guo } 10199bbc4aeSYi 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 14999bbc4aeSYi Guo static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, 15099bbc4aeSYi Guo enum ptp_pin_function func, unsigned int chan) 15199bbc4aeSYi Guo { 15299bbc4aeSYi Guo switch (func) { 15399bbc4aeSYi Guo case PTP_PF_NONE: 15499bbc4aeSYi Guo case PTP_PF_EXTTS: 15599bbc4aeSYi Guo break; 15699bbc4aeSYi Guo case PTP_PF_PEROUT: 15799bbc4aeSYi Guo case PTP_PF_PHYSYNC: 15899bbc4aeSYi Guo return -1; 15999bbc4aeSYi Guo } 16099bbc4aeSYi Guo return 0; 16199bbc4aeSYi Guo } 16299bbc4aeSYi Guo 16399bbc4aeSYi Guo static void otx2_ptp_extts_check(struct work_struct *work) 16499bbc4aeSYi Guo { 16599bbc4aeSYi Guo struct otx2_ptp *ptp = container_of(work, struct otx2_ptp, 16699bbc4aeSYi Guo extts_work.work); 16799bbc4aeSYi Guo struct ptp_clock_event event; 16899bbc4aeSYi Guo u64 tstmp, new_thresh; 16999bbc4aeSYi Guo 17099bbc4aeSYi Guo mutex_lock(&ptp->nic->mbox.lock); 17199bbc4aeSYi Guo tstmp = ptp_tstmp_read(ptp); 17299bbc4aeSYi Guo mutex_unlock(&ptp->nic->mbox.lock); 17399bbc4aeSYi Guo 17499bbc4aeSYi Guo if (tstmp != ptp->last_extts) { 17599bbc4aeSYi Guo event.type = PTP_CLOCK_EXTTS; 17699bbc4aeSYi Guo event.index = 0; 17799bbc4aeSYi Guo event.timestamp = timecounter_cyc2time(&ptp->time_counter, tstmp); 17899bbc4aeSYi Guo ptp_clock_event(ptp->ptp_clock, &event); 17999bbc4aeSYi Guo ptp->last_extts = tstmp; 18099bbc4aeSYi Guo 18199bbc4aeSYi Guo new_thresh = tstmp % 500000000; 18299bbc4aeSYi Guo if (ptp->thresh != new_thresh) { 18399bbc4aeSYi Guo mutex_lock(&ptp->nic->mbox.lock); 18499bbc4aeSYi Guo ptp_set_thresh(ptp, new_thresh); 18599bbc4aeSYi Guo mutex_unlock(&ptp->nic->mbox.lock); 18699bbc4aeSYi Guo ptp->thresh = new_thresh; 18799bbc4aeSYi Guo } 18899bbc4aeSYi Guo } 18999bbc4aeSYi Guo schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200)); 19099bbc4aeSYi Guo } 19199bbc4aeSYi 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 { 19599bbc4aeSYi Guo struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 19699bbc4aeSYi Guo ptp_info); 197*75f81afbSColin Ian King int pin; 19899bbc4aeSYi Guo 19999bbc4aeSYi Guo if (!ptp->nic) 20099bbc4aeSYi Guo return -ENODEV; 20199bbc4aeSYi Guo 20299bbc4aeSYi Guo switch (rq->type) { 20399bbc4aeSYi Guo case PTP_CLK_REQ_EXTTS: 20499bbc4aeSYi Guo pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, 20599bbc4aeSYi Guo rq->extts.index); 20699bbc4aeSYi Guo if (pin < 0) 20799bbc4aeSYi Guo return -EBUSY; 20899bbc4aeSYi Guo if (on) 20999bbc4aeSYi Guo schedule_delayed_work(&ptp->extts_work, msecs_to_jiffies(200)); 21099bbc4aeSYi Guo else 21199bbc4aeSYi Guo cancel_delayed_work_sync(&ptp->extts_work); 21299bbc4aeSYi Guo return 0; 21399bbc4aeSYi Guo default: 21499bbc4aeSYi Guo break; 21599bbc4aeSYi 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 22643510ef4SNaveen Mamindlapalli if (is_otx2_lbkvf(pfvf->pdev)) { 22743510ef4SNaveen Mamindlapalli pfvf->ptp = NULL; 22843510ef4SNaveen Mamindlapalli return 0; 22943510ef4SNaveen Mamindlapalli } 23043510ef4SNaveen Mamindlapalli 231c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 232c9c12d33SAleksey Makarov /* check if PTP block is available */ 233c9c12d33SAleksey Makarov req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox); 234c9c12d33SAleksey Makarov if (!req) { 235c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 236c9c12d33SAleksey Makarov return -ENOMEM; 237c9c12d33SAleksey Makarov } 238c9c12d33SAleksey Makarov 239c9c12d33SAleksey Makarov req->op = PTP_OP_GET_CLOCK; 240c9c12d33SAleksey Makarov 241c9c12d33SAleksey Makarov err = otx2_sync_mbox_msg(&pfvf->mbox); 242c9c12d33SAleksey Makarov if (err) { 243c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 244c9c12d33SAleksey Makarov return err; 245c9c12d33SAleksey Makarov } 246c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 247c9c12d33SAleksey Makarov 248c9c12d33SAleksey Makarov ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL); 249c9c12d33SAleksey Makarov if (!ptp_ptr) { 250c9c12d33SAleksey Makarov err = -ENOMEM; 251c9c12d33SAleksey Makarov goto error; 252c9c12d33SAleksey Makarov } 253c9c12d33SAleksey Makarov 254c9c12d33SAleksey Makarov ptp_ptr->nic = pfvf; 255c9c12d33SAleksey Makarov 256c9c12d33SAleksey Makarov cc = &ptp_ptr->cycle_counter; 257c9c12d33SAleksey Makarov cc->read = ptp_cc_read; 258c9c12d33SAleksey Makarov cc->mask = CYCLECOUNTER_MASK(64); 259c9c12d33SAleksey Makarov cc->mult = 1; 260c9c12d33SAleksey Makarov cc->shift = 0; 261c9c12d33SAleksey Makarov 262c9c12d33SAleksey Makarov timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter, 263c9c12d33SAleksey Makarov ktime_to_ns(ktime_get_real())); 264c9c12d33SAleksey Makarov 26599bbc4aeSYi Guo snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP"); 26699bbc4aeSYi Guo ptp_ptr->extts_config.index = 0; 26799bbc4aeSYi Guo ptp_ptr->extts_config.func = PTP_PF_NONE; 26899bbc4aeSYi Guo 269c9c12d33SAleksey Makarov ptp_ptr->ptp_info = (struct ptp_clock_info) { 270c9c12d33SAleksey Makarov .owner = THIS_MODULE, 271c9c12d33SAleksey Makarov .name = "OcteonTX2 PTP", 272c9c12d33SAleksey Makarov .max_adj = 1000000000ull, 27399bbc4aeSYi Guo .n_ext_ts = 1, 27499bbc4aeSYi Guo .n_pins = 1, 275c9c12d33SAleksey Makarov .pps = 0, 27699bbc4aeSYi Guo .pin_config = &ptp_ptr->extts_config, 277c9c12d33SAleksey Makarov .adjfine = otx2_ptp_adjfine, 278c9c12d33SAleksey Makarov .adjtime = otx2_ptp_adjtime, 279c9c12d33SAleksey Makarov .gettime64 = otx2_ptp_gettime, 280c9c12d33SAleksey Makarov .settime64 = otx2_ptp_settime, 281c9c12d33SAleksey Makarov .enable = otx2_ptp_enable, 28299bbc4aeSYi Guo .verify = otx2_ptp_verify_pin, 283c9c12d33SAleksey Makarov }; 284c9c12d33SAleksey Makarov 28599bbc4aeSYi Guo INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check); 28699bbc4aeSYi Guo 287c9c12d33SAleksey Makarov ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev); 288c9c12d33SAleksey Makarov if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) { 289c9c12d33SAleksey Makarov err = ptp_ptr->ptp_clock ? 290c9c12d33SAleksey Makarov PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV; 291c9c12d33SAleksey Makarov kfree(ptp_ptr); 292c9c12d33SAleksey Makarov goto error; 293c9c12d33SAleksey Makarov } 294c9c12d33SAleksey Makarov 295c9c12d33SAleksey Makarov pfvf->ptp = ptp_ptr; 296c9c12d33SAleksey Makarov 297c9c12d33SAleksey Makarov error: 298c9c12d33SAleksey Makarov return err; 299c9c12d33SAleksey Makarov } 300c9c12d33SAleksey Makarov 301c9c12d33SAleksey Makarov void otx2_ptp_destroy(struct otx2_nic *pfvf) 302c9c12d33SAleksey Makarov { 303c9c12d33SAleksey Makarov struct otx2_ptp *ptp = pfvf->ptp; 304c9c12d33SAleksey Makarov 305c9c12d33SAleksey Makarov if (!ptp) 306c9c12d33SAleksey Makarov return; 307c9c12d33SAleksey Makarov 308c9c12d33SAleksey Makarov ptp_clock_unregister(ptp->ptp_clock); 309c9c12d33SAleksey Makarov kfree(ptp); 310c9c12d33SAleksey Makarov pfvf->ptp = NULL; 311c9c12d33SAleksey Makarov } 312c9c12d33SAleksey Makarov 313c9c12d33SAleksey Makarov int otx2_ptp_clock_index(struct otx2_nic *pfvf) 314c9c12d33SAleksey Makarov { 315c9c12d33SAleksey Makarov if (!pfvf->ptp) 316c9c12d33SAleksey Makarov return -ENODEV; 317c9c12d33SAleksey Makarov 318c9c12d33SAleksey Makarov return ptp_clock_index(pfvf->ptp->ptp_clock); 319c9c12d33SAleksey Makarov } 320c9c12d33SAleksey Makarov 321c9c12d33SAleksey Makarov int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns) 322c9c12d33SAleksey Makarov { 323c9c12d33SAleksey Makarov if (!pfvf->ptp) 324c9c12d33SAleksey Makarov return -ENODEV; 325c9c12d33SAleksey Makarov 326c9c12d33SAleksey Makarov *tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp); 327c9c12d33SAleksey Makarov 328c9c12d33SAleksey Makarov return 0; 329c9c12d33SAleksey Makarov } 330