xref: /linux/drivers/net/ethernet/amd/xgbe/xgbe-pps.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause)
2 /*
3  * Copyright (c) 2014-2025, Advanced Micro Devices, Inc.
4  * Copyright (c) 2014, Synopsys, Inc.
5  * All rights reserved
6  *
7  * Author: Raju Rangoju <Raju.Rangoju@amd.com>
8  */
9 
10 #include "xgbe.h"
11 #include "xgbe-common.h"
12 
13 static u32 get_pps_mask(unsigned int x)
14 {
15 	return GENMASK(PPS_MAXIDX(x), PPS_MINIDX(x));
16 }
17 
18 static u32 get_pps_cmd(unsigned int x, u32 val)
19 {
20 	return (val & GENMASK(3, 0)) << PPS_MINIDX(x);
21 }
22 
23 static u32 get_target_mode_sel(unsigned int x, u32 val)
24 {
25 	return (val & GENMASK(1, 0)) << (PPS_MAXIDX(x) - 2);
26 }
27 
28 int xgbe_pps_config(struct xgbe_prv_data *pdata,
29 		    struct xgbe_pps_config *cfg, int index, bool on)
30 {
31 	unsigned int ppscr = 0;
32 	unsigned int tnsec;
33 	u64 period;
34 
35 	/* Check if target time register is busy */
36 	tnsec = XGMAC_IOREAD(pdata, MAC_PPSx_TTNSR(index));
37 	if (XGMAC_GET_BITS(tnsec, MAC_PPSx_TTNSR, TRGTBUSY0))
38 		return -EBUSY;
39 
40 	ppscr = XGMAC_IOREAD(pdata, MAC_PPSCR);
41 	ppscr &= ~get_pps_mask(index);
42 
43 	if (!on) {
44 		/* Disable PPS output */
45 		ppscr |= get_pps_cmd(index, XGBE_PPSCMD_STOP);
46 		ppscr |= PPSEN0;
47 		XGMAC_IOWRITE(pdata, MAC_PPSCR, ppscr);
48 
49 		return 0;
50 	}
51 
52 	/* Configure start time */
53 	XGMAC_IOWRITE(pdata, MAC_PPSx_TTSR(index), cfg->start.tv_sec);
54 	XGMAC_IOWRITE(pdata, MAC_PPSx_TTNSR(index), cfg->start.tv_nsec);
55 
56 	period = cfg->period.tv_sec * NSEC_PER_SEC + cfg->period.tv_nsec;
57 	period = div_u64(period, XGBE_V2_TSTAMP_SSINC);
58 
59 	if (period < 4)
60 		return -EINVAL;
61 
62 	/* Configure interval and pulse width (50% duty cycle) */
63 	XGMAC_IOWRITE(pdata, MAC_PPSx_INTERVAL(index), period - 1);
64 	XGMAC_IOWRITE(pdata, MAC_PPSx_WIDTH(index), (period >> 1) - 1);
65 
66 	/* Enable PPS with pulse train mode */
67 	ppscr |= get_pps_cmd(index, XGBE_PPSCMD_START);
68 	ppscr |= get_target_mode_sel(index, XGBE_PPSTARGET_PULSE);
69 	ppscr |= PPSEN0;
70 
71 	XGMAC_IOWRITE(pdata, MAC_PPSCR, ppscr);
72 
73 	return 0;
74 }
75