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