18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * AMD 10Gb Ethernet driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is available to you under your choice of the following two
58c2ecf20Sopenharmony_ci * licenses:
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * License 1: GPLv2
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Copyright (c) 2014 Advanced Micro Devices, Inc.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify
128c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
138c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at
148c2ecf20Sopenharmony_ci * your option) any later version.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * This file is distributed in the hope that it will be useful, but
178c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
188c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
198c2ecf20Sopenharmony_ci * General Public License for more details.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License
228c2ecf20Sopenharmony_ci * along with this program.  If not, see <http://www.gnu.org/licenses/>.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and
258c2ecf20Sopenharmony_ci * permission notice:
268c2ecf20Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
278c2ecf20Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
288c2ecf20Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
298c2ecf20Sopenharmony_ci *     and you.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
328c2ecf20Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
338c2ecf20Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
348c2ecf20Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
358c2ecf20Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
368c2ecf20Sopenharmony_ci *     without restriction, including without limitation the rights to use,
378c2ecf20Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
388c2ecf20Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
398c2ecf20Sopenharmony_ci *     to do so, subject to the following conditions:
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
428c2ecf20Sopenharmony_ci *     in all copies or substantial portions of the Software.
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
458c2ecf20Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
468c2ecf20Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
478c2ecf20Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
488c2ecf20Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
498c2ecf20Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
508c2ecf20Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
518c2ecf20Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
528c2ecf20Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
538c2ecf20Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
548c2ecf20Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * License 2: Modified BSD
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci * Copyright (c) 2014 Advanced Micro Devices, Inc.
608c2ecf20Sopenharmony_ci * All rights reserved.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
638c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
648c2ecf20Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
658c2ecf20Sopenharmony_ci *       notice, this list of conditions and the following disclaimer.
668c2ecf20Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
678c2ecf20Sopenharmony_ci *       notice, this list of conditions and the following disclaimer in the
688c2ecf20Sopenharmony_ci *       documentation and/or other materials provided with the distribution.
698c2ecf20Sopenharmony_ci *     * Neither the name of Advanced Micro Devices, Inc. nor the
708c2ecf20Sopenharmony_ci *       names of its contributors may be used to endorse or promote products
718c2ecf20Sopenharmony_ci *       derived from this software without specific prior written permission.
728c2ecf20Sopenharmony_ci *
738c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
748c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
758c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
768c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
778c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
788c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
798c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
808c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
818c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
828c2ecf20Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and
858c2ecf20Sopenharmony_ci * permission notice:
868c2ecf20Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
878c2ecf20Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
888c2ecf20Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
898c2ecf20Sopenharmony_ci *     and you.
908c2ecf20Sopenharmony_ci *
918c2ecf20Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
928c2ecf20Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
938c2ecf20Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
948c2ecf20Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
958c2ecf20Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
968c2ecf20Sopenharmony_ci *     without restriction, including without limitation the rights to use,
978c2ecf20Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
988c2ecf20Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
998c2ecf20Sopenharmony_ci *     to do so, subject to the following conditions:
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
1028c2ecf20Sopenharmony_ci *     in all copies or substantial portions of the Software.
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
1058c2ecf20Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1068c2ecf20Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
1078c2ecf20Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
1088c2ecf20Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1098c2ecf20Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1108c2ecf20Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1118c2ecf20Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1128c2ecf20Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1138c2ecf20Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1148c2ecf20Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#include <linux/clk.h>
1188c2ecf20Sopenharmony_ci#include <linux/clocksource.h>
1198c2ecf20Sopenharmony_ci#include <linux/ptp_clock_kernel.h>
1208c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h>
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci#include "xgbe.h"
1238c2ecf20Sopenharmony_ci#include "xgbe-common.h"
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic u64 xgbe_cc_read(const struct cyclecounter *cc)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(cc,
1288c2ecf20Sopenharmony_ci						   struct xgbe_prv_data,
1298c2ecf20Sopenharmony_ci						   tstamp_cc);
1308c2ecf20Sopenharmony_ci	u64 nsec;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	nsec = pdata->hw_if.get_tstamp_time(pdata);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return nsec;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic int xgbe_adjfreq(struct ptp_clock_info *info, s32 delta)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
1408c2ecf20Sopenharmony_ci						   struct xgbe_prv_data,
1418c2ecf20Sopenharmony_ci						   ptp_clock_info);
1428c2ecf20Sopenharmony_ci	unsigned long flags;
1438c2ecf20Sopenharmony_ci	u64 adjust;
1448c2ecf20Sopenharmony_ci	u32 addend, diff;
1458c2ecf20Sopenharmony_ci	unsigned int neg_adjust = 0;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (delta < 0) {
1488c2ecf20Sopenharmony_ci		neg_adjust = 1;
1498c2ecf20Sopenharmony_ci		delta = -delta;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	adjust = pdata->tstamp_addend;
1538c2ecf20Sopenharmony_ci	adjust *= delta;
1548c2ecf20Sopenharmony_ci	diff = div_u64(adjust, 1000000000UL);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	addend = (neg_adjust) ? pdata->tstamp_addend - diff :
1578c2ecf20Sopenharmony_ci				pdata->tstamp_addend + diff;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	pdata->hw_if.update_tstamp_addend(pdata, addend);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic int xgbe_adjtime(struct ptp_clock_info *info, s64 delta)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
1718c2ecf20Sopenharmony_ci						   struct xgbe_prv_data,
1728c2ecf20Sopenharmony_ci						   ptp_clock_info);
1738c2ecf20Sopenharmony_ci	unsigned long flags;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
1768c2ecf20Sopenharmony_ci	timecounter_adjtime(&pdata->tstamp_tc, delta);
1778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return 0;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic int xgbe_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
1858c2ecf20Sopenharmony_ci						   struct xgbe_prv_data,
1868c2ecf20Sopenharmony_ci						   ptp_clock_info);
1878c2ecf20Sopenharmony_ci	unsigned long flags;
1888c2ecf20Sopenharmony_ci	u64 nsec;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	nsec = timecounter_read(&pdata->tstamp_tc);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	*ts = ns_to_timespec64(nsec);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	return 0;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic int xgbe_settime(struct ptp_clock_info *info,
2028c2ecf20Sopenharmony_ci			const struct timespec64 *ts)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
2058c2ecf20Sopenharmony_ci						   struct xgbe_prv_data,
2068c2ecf20Sopenharmony_ci						   ptp_clock_info);
2078c2ecf20Sopenharmony_ci	unsigned long flags;
2088c2ecf20Sopenharmony_ci	u64 nsec;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	nsec = timespec64_to_ns(ts);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return 0;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic int xgbe_enable(struct ptp_clock_info *info,
2228c2ecf20Sopenharmony_ci		       struct ptp_clock_request *request, int on)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_civoid xgbe_ptp_register(struct xgbe_prv_data *pdata)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	struct ptp_clock_info *info = &pdata->ptp_clock_info;
2308c2ecf20Sopenharmony_ci	struct ptp_clock *clock;
2318c2ecf20Sopenharmony_ci	struct cyclecounter *cc = &pdata->tstamp_cc;
2328c2ecf20Sopenharmony_ci	u64 dividend;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	snprintf(info->name, sizeof(info->name), "%s",
2358c2ecf20Sopenharmony_ci		 netdev_name(pdata->netdev));
2368c2ecf20Sopenharmony_ci	info->owner = THIS_MODULE;
2378c2ecf20Sopenharmony_ci	info->max_adj = pdata->ptpclk_rate;
2388c2ecf20Sopenharmony_ci	info->adjfreq = xgbe_adjfreq;
2398c2ecf20Sopenharmony_ci	info->adjtime = xgbe_adjtime;
2408c2ecf20Sopenharmony_ci	info->gettime64 = xgbe_gettime;
2418c2ecf20Sopenharmony_ci	info->settime64 = xgbe_settime;
2428c2ecf20Sopenharmony_ci	info->enable = xgbe_enable;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	clock = ptp_clock_register(info, pdata->dev);
2458c2ecf20Sopenharmony_ci	if (IS_ERR(clock)) {
2468c2ecf20Sopenharmony_ci		dev_err(pdata->dev, "ptp_clock_register failed\n");
2478c2ecf20Sopenharmony_ci		return;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	pdata->ptp_clock = clock;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* Calculate the addend:
2538c2ecf20Sopenharmony_ci	 *   addend = 2^32 / (PTP ref clock / 50Mhz)
2548c2ecf20Sopenharmony_ci	 *          = (2^32 * 50Mhz) / PTP ref clock
2558c2ecf20Sopenharmony_ci	 */
2568c2ecf20Sopenharmony_ci	dividend = 50000000;
2578c2ecf20Sopenharmony_ci	dividend <<= 32;
2588c2ecf20Sopenharmony_ci	pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* Setup the timecounter */
2618c2ecf20Sopenharmony_ci	cc->read = xgbe_cc_read;
2628c2ecf20Sopenharmony_ci	cc->mask = CLOCKSOURCE_MASK(64);
2638c2ecf20Sopenharmony_ci	cc->mult = 1;
2648c2ecf20Sopenharmony_ci	cc->shift = 0;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc,
2678c2ecf20Sopenharmony_ci			 ktime_to_ns(ktime_get_real()));
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* Disable all timestamping to start */
2708c2ecf20Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_TSCR, 0);
2718c2ecf20Sopenharmony_ci	pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
2728c2ecf20Sopenharmony_ci	pdata->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_civoid xgbe_ptp_unregister(struct xgbe_prv_data *pdata)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	if (pdata->ptp_clock)
2788c2ecf20Sopenharmony_ci		ptp_clock_unregister(pdata->ptp_clock);
2798c2ecf20Sopenharmony_ci}
280