1 /* =========================================================================
2 * The Synopsys DWC ETHER QOS Software Driver and documentation (hereinafter
3 * "Software") is an unsupported proprietary work of Synopsys, Inc. unless
4 * otherwise expressly agreed to in writing between Synopsys and you.
6 * The Software IS NOT an item of Licensed Software or Licensed Product under
7 * any End User Software License Agreement or Agreement for Licensed Product
8 * with Synopsys or any supplement thereto. Permission is hereby granted,
9 * free of charge, to any person obtaining a copy of this software annotated
10 * with this license and the Software, to deal in the Software without
11 * restriction, including without limitation the rights to use, copy, modify,
12 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
13 * and to permit persons to whom the Software is furnished to do so, subject
14 * to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30 * =========================================================================
33 * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
35 * This program is free software; you can redistribute it and/or modify it
36 * under the terms and conditions of the GNU General Public License,
37 * version 2, as published by the Free Software Foundation.
39 * This program is distributed in the hope it will be useful, but WITHOUT
40 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
41 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
45 * @brief: Driver functions.
50 * \brief API to adjust the frequency of hardware clock.
52 * \details This function is used to adjust the frequency of the
55 * \param[in] ptp – pointer to ptp_clock_info structure.
56 * \param[in] delta – desired period change in parts per billion.
60 * \retval 0 on success and -ve number on failure.
63 static int eqos_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
65 struct eqos_prv_data *pdata =
66 container_of(ptp, struct eqos_prv_data, ptp_clock_ops);
67 struct hw_if_struct *hw_if = &(pdata->hw_if);
72 DBGPR_PTP("-->eqos_adjust_freq: %d\n", ppb);
79 addend = pdata->default_addend;
83 * div_u64 will divided the "adj" by "1000000000ULL"
84 * and return the quotient.
86 diff = div_u64(adj, 1000000000ULL);
87 addend = neg_adj ? (addend - diff) : (addend + diff);
89 raw_spin_lock(&pdata->ptp_lock);
91 hw_if->config_addend(addend);
93 raw_spin_unlock(&pdata->ptp_lock);
95 DBGPR_PTP("<--eqos_adjust_freq\n");
101 * \brief API to adjust the hardware time.
103 * \details This function is used to shift/adjust the time of the
106 * \param[in] ptp – pointer to ptp_clock_info structure.
107 * \param[in] delta – desired change in nanoseconds.
111 * \retval 0 on success and -ve number on failure.
114 static int eqos_adjust_time(struct ptp_clock_info *ptp, s64 delta)
116 struct eqos_prv_data *pdata =
117 container_of(ptp, struct eqos_prv_data, ptp_clock_ops);
118 struct hw_if_struct *hw_if = &(pdata->hw_if);
120 u32 quotient, reminder;
123 DBGPR_PTP("-->eqos_adjust_time: delta = %lld\n", delta);
130 quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
134 raw_spin_lock(&pdata->ptp_lock);
136 hw_if->adjust_systime(sec, nsec, neg_adj, pdata->one_nsec_accuracy);
138 raw_spin_unlock(&pdata->ptp_lock);
140 /* Register broadcasting MAC timestamp to clients */
141 tegra_register_hwtime_source(hw_if->get_systime);
143 DBGPR_PTP("<--eqos_adjust_time\n");
149 * \brief API to get the current time.
151 * \details This function is used to read the current time from the
154 * \param[in] ptp – pointer to ptp_clock_info structure.
155 * \param[in] ts – pointer to hold the time/result.
159 * \retval 0 on success and -ve number on failure.
162 static int eqos_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
164 struct eqos_prv_data *pdata =
165 container_of(ptp, struct eqos_prv_data, ptp_clock_ops);
166 struct hw_if_struct *hw_if = &(pdata->hw_if);
171 DBGPR_PTP("-->eqos_get_time\n");
173 raw_spin_lock_irqsave(&pdata->ptp_lock, flags);
175 ns = hw_if->get_systime();
177 raw_spin_unlock_irqrestore(&pdata->ptp_lock, flags);
179 ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &reminder);
180 ts->tv_nsec = reminder;
182 DBGPR_PTP("<--eqos_get_time: ts->tv_sec = %ld, ts->tv_nsec = %ld\n",
183 ts->tv_sec, ts->tv_nsec);
189 * \brief API to set the current time.
191 * \details This function is used to set the current time on the
194 * \param[in] ptp – pointer to ptp_clock_info structure.
195 * \param[in] ts – time value to set.
199 * \retval 0 on success and -ve number on failure.
202 static int eqos_set_time(struct ptp_clock_info *ptp, const struct timespec *ts)
204 struct eqos_prv_data *pdata =
205 container_of(ptp, struct eqos_prv_data, ptp_clock_ops);
206 struct hw_if_struct *hw_if = &(pdata->hw_if);
208 DBGPR_PTP("-->eqos_set_time: ts->tv_sec = %ld, ts->tv_nsec = %ld\n",
209 ts->tv_sec, ts->tv_nsec);
211 raw_spin_lock(&pdata->ptp_lock);
213 hw_if->init_systime(ts->tv_sec, ts->tv_nsec);
215 raw_spin_unlock(&pdata->ptp_lock);
217 DBGPR_PTP("<--eqos_set_time\n");
223 * \brief API to enable/disable an ancillary feature.
225 * \details This function is used to enable or disable an ancillary
226 * device feature like PPS, PEROUT and EXTTS.
228 * \param[in] ptp – pointer to ptp_clock_info structure.
229 * \param[in] rq – desired resource to enable or disable.
230 * \param[in] on – caller passes one to enable or zero to disable.
234 * \retval 0 on success and -ve(EINVAL or EOPNOTSUPP) number on failure.
237 static int eqos_enable(struct ptp_clock_info *ptp,
238 struct ptp_clock_request *rq, int on)
243 /* structure describing a PTP hardware clock */
244 static struct ptp_clock_info eqos_ptp_clock_ops = {
245 .owner = THIS_MODULE,
247 .max_adj = EQOS_SYSCLOCK,
248 /* the max possible frequency adjustment in parts per billion */
249 .n_alarm = 0, /* the number of programmable alarms */
250 .n_ext_ts = 0, /* the number of externel time stamp channels */
251 .n_per_out = 0, /* the number of programmable periodic signals */
252 .pps = 0, /* indicates whether the clk supports a PPS callback */
253 .adjfreq = eqos_adjust_freq,
254 .adjtime = eqos_adjust_time,
255 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
256 .gettime = eqos_get_time,
257 .settime = eqos_set_time,
259 .gettime64 = eqos_get_time,
260 .settime64 = eqos_set_time,
262 .enable = eqos_enable,
266 * \brief API to register ptp clock driver.
268 * \details This function is used to register the ptp clock
269 * driver to kernel. It also does some housekeeping work.
271 * \param[in] pdata – pointer to private data structure.
275 * \retval 0 on success and -ve number on failure.
278 int eqos_ptp_init(struct eqos_prv_data *pdata)
282 DBGPR_PTP("-->eqos_ptp_init\n");
284 if (!pdata->hw_feat.tsstssel) {
286 pdata->ptp_clock = NULL;
287 pr_err("No PTP supports in HW\n"
288 "Aborting PTP clock driver registration\n");
292 raw_spin_lock_init(&pdata->ptp_lock);
294 pdata->ptp_clock_ops = eqos_ptp_clock_ops;
297 ptp_clock_register(&pdata->ptp_clock_ops, &pdata->pdev->dev);
298 if (IS_ERR(pdata->ptp_clock)) {
299 pdata->ptp_clock = NULL;
300 pr_err("ptp_clock_register() failed\n");
303 DBGPR_PTP("<--eqos_ptp_init\n");
312 * \brief API to unregister ptp clock driver.
314 * \details This function is used to remove/unregister the ptp
315 * clock driver from the kernel.
317 * \param[in] pdata – pointer to private data structure.
322 void eqos_ptp_remove(struct eqos_prv_data *pdata)
324 DBGPR_PTP("-->eqos_ptp_remove\n");
326 if (pdata->ptp_clock) {
327 ptp_clock_unregister(pdata->ptp_clock);
328 pr_err("Removed PTP HW clock successfully\n");
331 DBGPR_PTP("<--eqos_ptp_remove\n");