1c9c12d33SAleksey Makarov // SPDX-License-Identifier: GPL-2.0 2c9c12d33SAleksey Makarov /* Marvell OcteonTx2 PTP support for ethernet driver 3c9c12d33SAleksey Makarov * 4c9c12d33SAleksey Makarov * Copyright (C) 2020 Marvell International Ltd. 5c9c12d33SAleksey Makarov */ 6c9c12d33SAleksey Makarov 7c9c12d33SAleksey Makarov #include "otx2_common.h" 8c9c12d33SAleksey Makarov #include "otx2_ptp.h" 9c9c12d33SAleksey Makarov 10c9c12d33SAleksey Makarov static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) 11c9c12d33SAleksey Makarov { 12c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 13c9c12d33SAleksey Makarov ptp_info); 14c9c12d33SAleksey Makarov struct ptp_req *req; 15c9c12d33SAleksey Makarov int err; 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 27c9c12d33SAleksey Makarov err = otx2_sync_mbox_msg(&ptp->nic->mbox); 28c9c12d33SAleksey Makarov if (err) 29c9c12d33SAleksey Makarov return err; 30c9c12d33SAleksey Makarov 31c9c12d33SAleksey Makarov return 0; 32c9c12d33SAleksey Makarov } 33c9c12d33SAleksey Makarov 34c9c12d33SAleksey Makarov static u64 ptp_cc_read(const struct cyclecounter *cc) 35c9c12d33SAleksey Makarov { 36c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(cc, struct otx2_ptp, cycle_counter); 37c9c12d33SAleksey Makarov struct ptp_req *req; 38c9c12d33SAleksey Makarov struct ptp_rsp *rsp; 39c9c12d33SAleksey Makarov int err; 40c9c12d33SAleksey Makarov 41c9c12d33SAleksey Makarov if (!ptp->nic) 42c9c12d33SAleksey Makarov return 0; 43c9c12d33SAleksey Makarov 44c9c12d33SAleksey Makarov req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox); 45c9c12d33SAleksey Makarov if (!req) 46c9c12d33SAleksey Makarov return 0; 47c9c12d33SAleksey Makarov 48c9c12d33SAleksey Makarov req->op = PTP_OP_GET_CLOCK; 49c9c12d33SAleksey Makarov 50c9c12d33SAleksey Makarov err = otx2_sync_mbox_msg(&ptp->nic->mbox); 51c9c12d33SAleksey Makarov if (err) 52c9c12d33SAleksey Makarov return 0; 53c9c12d33SAleksey Makarov 54c9c12d33SAleksey Makarov rsp = (struct ptp_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0, 55c9c12d33SAleksey Makarov &req->hdr); 56c9c12d33SAleksey Makarov if (IS_ERR(rsp)) 57c9c12d33SAleksey Makarov return 0; 58c9c12d33SAleksey Makarov 59c9c12d33SAleksey Makarov return rsp->clk; 60c9c12d33SAleksey Makarov } 61c9c12d33SAleksey Makarov 62c9c12d33SAleksey Makarov static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta) 63c9c12d33SAleksey Makarov { 64c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 65c9c12d33SAleksey Makarov ptp_info); 66c9c12d33SAleksey Makarov struct otx2_nic *pfvf = ptp->nic; 67c9c12d33SAleksey Makarov 68c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 69c9c12d33SAleksey Makarov timecounter_adjtime(&ptp->time_counter, delta); 70c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 71c9c12d33SAleksey Makarov 72c9c12d33SAleksey Makarov return 0; 73c9c12d33SAleksey Makarov } 74c9c12d33SAleksey Makarov 75c9c12d33SAleksey Makarov static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info, 76c9c12d33SAleksey Makarov struct timespec64 *ts) 77c9c12d33SAleksey Makarov { 78c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 79c9c12d33SAleksey Makarov ptp_info); 80c9c12d33SAleksey Makarov struct otx2_nic *pfvf = ptp->nic; 81c9c12d33SAleksey Makarov u64 nsec; 82c9c12d33SAleksey Makarov 83c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 84c9c12d33SAleksey Makarov nsec = timecounter_read(&ptp->time_counter); 85c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 86c9c12d33SAleksey Makarov 87c9c12d33SAleksey Makarov *ts = ns_to_timespec64(nsec); 88c9c12d33SAleksey Makarov 89c9c12d33SAleksey Makarov return 0; 90c9c12d33SAleksey Makarov } 91c9c12d33SAleksey Makarov 92c9c12d33SAleksey Makarov static int otx2_ptp_settime(struct ptp_clock_info *ptp_info, 93c9c12d33SAleksey Makarov const struct timespec64 *ts) 94c9c12d33SAleksey Makarov { 95c9c12d33SAleksey Makarov struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, 96c9c12d33SAleksey Makarov ptp_info); 97c9c12d33SAleksey Makarov struct otx2_nic *pfvf = ptp->nic; 98c9c12d33SAleksey Makarov u64 nsec; 99c9c12d33SAleksey Makarov 100c9c12d33SAleksey Makarov nsec = timespec64_to_ns(ts); 101c9c12d33SAleksey Makarov 102c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 103c9c12d33SAleksey Makarov timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec); 104c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 105c9c12d33SAleksey Makarov 106c9c12d33SAleksey Makarov return 0; 107c9c12d33SAleksey Makarov } 108c9c12d33SAleksey Makarov 109c9c12d33SAleksey Makarov static int otx2_ptp_enable(struct ptp_clock_info *ptp_info, 110c9c12d33SAleksey Makarov struct ptp_clock_request *rq, int on) 111c9c12d33SAleksey Makarov { 112c9c12d33SAleksey Makarov return -EOPNOTSUPP; 113c9c12d33SAleksey Makarov } 114c9c12d33SAleksey Makarov 115c9c12d33SAleksey Makarov int otx2_ptp_init(struct otx2_nic *pfvf) 116c9c12d33SAleksey Makarov { 117c9c12d33SAleksey Makarov struct otx2_ptp *ptp_ptr; 118c9c12d33SAleksey Makarov struct cyclecounter *cc; 119c9c12d33SAleksey Makarov struct ptp_req *req; 120c9c12d33SAleksey Makarov int err; 121c9c12d33SAleksey Makarov 122c9c12d33SAleksey Makarov mutex_lock(&pfvf->mbox.lock); 123c9c12d33SAleksey Makarov /* check if PTP block is available */ 124c9c12d33SAleksey Makarov req = otx2_mbox_alloc_msg_ptp_op(&pfvf->mbox); 125c9c12d33SAleksey Makarov if (!req) { 126c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 127c9c12d33SAleksey Makarov return -ENOMEM; 128c9c12d33SAleksey Makarov } 129c9c12d33SAleksey Makarov 130c9c12d33SAleksey Makarov req->op = PTP_OP_GET_CLOCK; 131c9c12d33SAleksey Makarov 132c9c12d33SAleksey Makarov err = otx2_sync_mbox_msg(&pfvf->mbox); 133c9c12d33SAleksey Makarov if (err) { 134c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 135c9c12d33SAleksey Makarov return err; 136c9c12d33SAleksey Makarov } 137c9c12d33SAleksey Makarov mutex_unlock(&pfvf->mbox.lock); 138c9c12d33SAleksey Makarov 139c9c12d33SAleksey Makarov ptp_ptr = kzalloc(sizeof(*ptp_ptr), GFP_KERNEL); 140c9c12d33SAleksey Makarov if (!ptp_ptr) { 141c9c12d33SAleksey Makarov err = -ENOMEM; 142c9c12d33SAleksey Makarov goto error; 143c9c12d33SAleksey Makarov } 144c9c12d33SAleksey Makarov 145c9c12d33SAleksey Makarov ptp_ptr->nic = pfvf; 146c9c12d33SAleksey Makarov 147c9c12d33SAleksey Makarov cc = &ptp_ptr->cycle_counter; 148c9c12d33SAleksey Makarov cc->read = ptp_cc_read; 149c9c12d33SAleksey Makarov cc->mask = CYCLECOUNTER_MASK(64); 150c9c12d33SAleksey Makarov cc->mult = 1; 151c9c12d33SAleksey Makarov cc->shift = 0; 152c9c12d33SAleksey Makarov 153c9c12d33SAleksey Makarov timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter, 154c9c12d33SAleksey Makarov ktime_to_ns(ktime_get_real())); 155c9c12d33SAleksey Makarov 156c9c12d33SAleksey Makarov ptp_ptr->ptp_info = (struct ptp_clock_info) { 157c9c12d33SAleksey Makarov .owner = THIS_MODULE, 158c9c12d33SAleksey Makarov .name = "OcteonTX2 PTP", 159c9c12d33SAleksey Makarov .max_adj = 1000000000ull, 160c9c12d33SAleksey Makarov .n_ext_ts = 0, 161c9c12d33SAleksey Makarov .n_pins = 0, 162c9c12d33SAleksey Makarov .pps = 0, 163c9c12d33SAleksey Makarov .adjfine = otx2_ptp_adjfine, 164c9c12d33SAleksey Makarov .adjtime = otx2_ptp_adjtime, 165c9c12d33SAleksey Makarov .gettime64 = otx2_ptp_gettime, 166c9c12d33SAleksey Makarov .settime64 = otx2_ptp_settime, 167c9c12d33SAleksey Makarov .enable = otx2_ptp_enable, 168c9c12d33SAleksey Makarov }; 169c9c12d33SAleksey Makarov 170c9c12d33SAleksey Makarov ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev); 171c9c12d33SAleksey Makarov if (IS_ERR_OR_NULL(ptp_ptr->ptp_clock)) { 172c9c12d33SAleksey Makarov err = ptp_ptr->ptp_clock ? 173c9c12d33SAleksey Makarov PTR_ERR(ptp_ptr->ptp_clock) : -ENODEV; 174c9c12d33SAleksey Makarov kfree(ptp_ptr); 175c9c12d33SAleksey Makarov goto error; 176c9c12d33SAleksey Makarov } 177c9c12d33SAleksey Makarov 178c9c12d33SAleksey Makarov pfvf->ptp = ptp_ptr; 179c9c12d33SAleksey Makarov 180c9c12d33SAleksey Makarov error: 181c9c12d33SAleksey Makarov return err; 182c9c12d33SAleksey Makarov } 183c9c12d33SAleksey Makarov 184c9c12d33SAleksey Makarov void otx2_ptp_destroy(struct otx2_nic *pfvf) 185c9c12d33SAleksey Makarov { 186c9c12d33SAleksey Makarov struct otx2_ptp *ptp = pfvf->ptp; 187c9c12d33SAleksey Makarov 188c9c12d33SAleksey Makarov if (!ptp) 189c9c12d33SAleksey Makarov return; 190c9c12d33SAleksey Makarov 191c9c12d33SAleksey Makarov ptp_clock_unregister(ptp->ptp_clock); 192c9c12d33SAleksey Makarov kfree(ptp); 193c9c12d33SAleksey Makarov pfvf->ptp = NULL; 194c9c12d33SAleksey Makarov } 195c9c12d33SAleksey Makarov 196c9c12d33SAleksey Makarov int otx2_ptp_clock_index(struct otx2_nic *pfvf) 197c9c12d33SAleksey Makarov { 198c9c12d33SAleksey Makarov if (!pfvf->ptp) 199c9c12d33SAleksey Makarov return -ENODEV; 200c9c12d33SAleksey Makarov 201c9c12d33SAleksey Makarov return ptp_clock_index(pfvf->ptp->ptp_clock); 202c9c12d33SAleksey Makarov } 203c9c12d33SAleksey Makarov 204c9c12d33SAleksey Makarov int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns) 205c9c12d33SAleksey Makarov { 206c9c12d33SAleksey Makarov if (!pfvf->ptp) 207c9c12d33SAleksey Makarov return -ENODEV; 208c9c12d33SAleksey Makarov 209c9c12d33SAleksey Makarov *tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp); 210c9c12d33SAleksey Makarov 211c9c12d33SAleksey Makarov return 0; 212c9c12d33SAleksey Makarov } 213