162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * AMD 10Gb Ethernet driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is available to you under your choice of the following two
562306a36Sopenharmony_ci * licenses:
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * License 1: GPLv2
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (c) 2014 Advanced Micro Devices, Inc.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify
1262306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
1362306a36Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at
1462306a36Sopenharmony_ci * your option) any later version.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * This file is distributed in the hope that it will be useful, but
1762306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
1862306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1962306a36Sopenharmony_ci * General Public License for more details.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License
2262306a36Sopenharmony_ci * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and
2562306a36Sopenharmony_ci * permission notice:
2662306a36Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
2762306a36Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
2862306a36Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
2962306a36Sopenharmony_ci *     and you.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
3262306a36Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
3362306a36Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
3462306a36Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
3562306a36Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
3662306a36Sopenharmony_ci *     without restriction, including without limitation the rights to use,
3762306a36Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
3862306a36Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
3962306a36Sopenharmony_ci *     to do so, subject to the following conditions:
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
4262306a36Sopenharmony_ci *     in all copies or substantial portions of the Software.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4562306a36Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4662306a36Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
4762306a36Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
4862306a36Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4962306a36Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5062306a36Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5162306a36Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5262306a36Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5362306a36Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
5462306a36Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * License 2: Modified BSD
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Copyright (c) 2014 Advanced Micro Devices, Inc.
6062306a36Sopenharmony_ci * All rights reserved.
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
6362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
6462306a36Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
6562306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer.
6662306a36Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
6762306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer in the
6862306a36Sopenharmony_ci *       documentation and/or other materials provided with the distribution.
6962306a36Sopenharmony_ci *     * Neither the name of Advanced Micro Devices, Inc. nor the
7062306a36Sopenharmony_ci *       names of its contributors may be used to endorse or promote products
7162306a36Sopenharmony_ci *       derived from this software without specific prior written permission.
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7462306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7562306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7662306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
7762306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7862306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7962306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
8062306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8162306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
8262306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and
8562306a36Sopenharmony_ci * permission notice:
8662306a36Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
8762306a36Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
8862306a36Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
8962306a36Sopenharmony_ci *     and you.
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
9262306a36Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
9362306a36Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
9462306a36Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
9562306a36Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
9662306a36Sopenharmony_ci *     without restriction, including without limitation the rights to use,
9762306a36Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9862306a36Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
9962306a36Sopenharmony_ci *     to do so, subject to the following conditions:
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
10262306a36Sopenharmony_ci *     in all copies or substantial portions of the Software.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10562306a36Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10662306a36Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
10762306a36Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
10862306a36Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10962306a36Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
11062306a36Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
11162306a36Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
11262306a36Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
11362306a36Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
11462306a36Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#include <linux/clk.h>
11862306a36Sopenharmony_ci#include <linux/clocksource.h>
11962306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h>
12062306a36Sopenharmony_ci#include <linux/net_tstamp.h>
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#include "xgbe.h"
12362306a36Sopenharmony_ci#include "xgbe-common.h"
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic u64 xgbe_cc_read(const struct cyclecounter *cc)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(cc,
12862306a36Sopenharmony_ci						   struct xgbe_prv_data,
12962306a36Sopenharmony_ci						   tstamp_cc);
13062306a36Sopenharmony_ci	u64 nsec;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	nsec = pdata->hw_if.get_tstamp_time(pdata);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return nsec;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic int xgbe_adjfine(struct ptp_clock_info *info, long scaled_ppm)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
14062306a36Sopenharmony_ci						   struct xgbe_prv_data,
14162306a36Sopenharmony_ci						   ptp_clock_info);
14262306a36Sopenharmony_ci	unsigned long flags;
14362306a36Sopenharmony_ci	u64 addend;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	addend = adjust_by_scaled_ppm(pdata->tstamp_addend, scaled_ppm);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	pdata->hw_if.update_tstamp_addend(pdata, addend);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int xgbe_adjtime(struct ptp_clock_info *info, s64 delta)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
15962306a36Sopenharmony_ci						   struct xgbe_prv_data,
16062306a36Sopenharmony_ci						   ptp_clock_info);
16162306a36Sopenharmony_ci	unsigned long flags;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
16462306a36Sopenharmony_ci	timecounter_adjtime(&pdata->tstamp_tc, delta);
16562306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int xgbe_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
17362306a36Sopenharmony_ci						   struct xgbe_prv_data,
17462306a36Sopenharmony_ci						   ptp_clock_info);
17562306a36Sopenharmony_ci	unsigned long flags;
17662306a36Sopenharmony_ci	u64 nsec;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	nsec = timecounter_read(&pdata->tstamp_tc);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	*ts = ns_to_timespec64(nsec);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int xgbe_settime(struct ptp_clock_info *info,
19062306a36Sopenharmony_ci			const struct timespec64 *ts)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = container_of(info,
19362306a36Sopenharmony_ci						   struct xgbe_prv_data,
19462306a36Sopenharmony_ci						   ptp_clock_info);
19562306a36Sopenharmony_ci	unsigned long flags;
19662306a36Sopenharmony_ci	u64 nsec;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	nsec = timespec64_to_ns(ts);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	spin_lock_irqsave(&pdata->tstamp_lock, flags);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return 0;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int xgbe_enable(struct ptp_clock_info *info,
21062306a36Sopenharmony_ci		       struct ptp_clock_request *request, int on)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	return -EOPNOTSUPP;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_civoid xgbe_ptp_register(struct xgbe_prv_data *pdata)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct ptp_clock_info *info = &pdata->ptp_clock_info;
21862306a36Sopenharmony_ci	struct ptp_clock *clock;
21962306a36Sopenharmony_ci	struct cyclecounter *cc = &pdata->tstamp_cc;
22062306a36Sopenharmony_ci	u64 dividend;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	snprintf(info->name, sizeof(info->name), "%s",
22362306a36Sopenharmony_ci		 netdev_name(pdata->netdev));
22462306a36Sopenharmony_ci	info->owner = THIS_MODULE;
22562306a36Sopenharmony_ci	info->max_adj = pdata->ptpclk_rate;
22662306a36Sopenharmony_ci	info->adjfine = xgbe_adjfine;
22762306a36Sopenharmony_ci	info->adjtime = xgbe_adjtime;
22862306a36Sopenharmony_ci	info->gettime64 = xgbe_gettime;
22962306a36Sopenharmony_ci	info->settime64 = xgbe_settime;
23062306a36Sopenharmony_ci	info->enable = xgbe_enable;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	clock = ptp_clock_register(info, pdata->dev);
23362306a36Sopenharmony_ci	if (IS_ERR(clock)) {
23462306a36Sopenharmony_ci		dev_err(pdata->dev, "ptp_clock_register failed\n");
23562306a36Sopenharmony_ci		return;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	pdata->ptp_clock = clock;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/* Calculate the addend:
24162306a36Sopenharmony_ci	 *   addend = 2^32 / (PTP ref clock / 50Mhz)
24262306a36Sopenharmony_ci	 *          = (2^32 * 50Mhz) / PTP ref clock
24362306a36Sopenharmony_ci	 */
24462306a36Sopenharmony_ci	dividend = 50000000;
24562306a36Sopenharmony_ci	dividend <<= 32;
24662306a36Sopenharmony_ci	pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* Setup the timecounter */
24962306a36Sopenharmony_ci	cc->read = xgbe_cc_read;
25062306a36Sopenharmony_ci	cc->mask = CLOCKSOURCE_MASK(64);
25162306a36Sopenharmony_ci	cc->mult = 1;
25262306a36Sopenharmony_ci	cc->shift = 0;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc,
25562306a36Sopenharmony_ci			 ktime_to_ns(ktime_get_real()));
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* Disable all timestamping to start */
25862306a36Sopenharmony_ci	XGMAC_IOWRITE(pdata, MAC_TSCR, 0);
25962306a36Sopenharmony_ci	pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF;
26062306a36Sopenharmony_ci	pdata->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_civoid xgbe_ptp_unregister(struct xgbe_prv_data *pdata)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	if (pdata->ptp_clock)
26662306a36Sopenharmony_ci		ptp_clock_unregister(pdata->ptp_clock);
26762306a36Sopenharmony_ci}
268