diff options
Diffstat (limited to 'drivers/net/ethernet/amd/xgbe/xgbe-pps.c')
-rw-r--r-- | drivers/net/ethernet/amd/xgbe/xgbe-pps.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pps.c b/drivers/net/ethernet/amd/xgbe/xgbe-pps.c new file mode 100644 index 000000000000..6d03ae7ab36f --- /dev/null +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pps.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause) +/* + * Copyright (c) 2014-2025, Advanced Micro Devices, Inc. + * Copyright (c) 2014, Synopsys, Inc. + * All rights reserved + * + * Author: Raju Rangoju <Raju.Rangoju@amd.com> + */ + +#include "xgbe.h" +#include "xgbe-common.h" + +static u32 get_pps_mask(unsigned int x) +{ + return GENMASK(PPS_MAXIDX(x), PPS_MINIDX(x)); +} + +static u32 get_pps_cmd(unsigned int x, u32 val) +{ + return (val & GENMASK(3, 0)) << PPS_MINIDX(x); +} + +static u32 get_target_mode_sel(unsigned int x, u32 val) +{ + return (val & GENMASK(1, 0)) << (PPS_MAXIDX(x) - 2); +} + +int xgbe_pps_config(struct xgbe_prv_data *pdata, + struct xgbe_pps_config *cfg, int index, bool on) +{ + unsigned int ppscr = 0; + unsigned int tnsec; + u64 period; + + /* Check if target time register is busy */ + tnsec = XGMAC_IOREAD(pdata, MAC_PPSx_TTNSR(index)); + if (XGMAC_GET_BITS(tnsec, MAC_PPSx_TTNSR, TRGTBUSY0)) + return -EBUSY; + + ppscr = XGMAC_IOREAD(pdata, MAC_PPSCR); + ppscr &= ~get_pps_mask(index); + + if (!on) { + /* Disable PPS output */ + ppscr |= get_pps_cmd(index, XGBE_PPSCMD_STOP); + ppscr |= PPSEN0; + XGMAC_IOWRITE(pdata, MAC_PPSCR, ppscr); + + return 0; + } + + /* Configure start time */ + XGMAC_IOWRITE(pdata, MAC_PPSx_TTSR(index), cfg->start.tv_sec); + XGMAC_IOWRITE(pdata, MAC_PPSx_TTNSR(index), cfg->start.tv_nsec); + + period = cfg->period.tv_sec * NSEC_PER_SEC + cfg->period.tv_nsec; + period = div_u64(period, XGBE_V2_TSTAMP_SSINC); + + if (period < 4) + return -EINVAL; + + /* Configure interval and pulse width (50% duty cycle) */ + XGMAC_IOWRITE(pdata, MAC_PPSx_INTERVAL(index), period - 1); + XGMAC_IOWRITE(pdata, MAC_PPSx_WIDTH(index), (period >> 1) - 1); + + /* Enable PPS with pulse train mode */ + ppscr |= get_pps_cmd(index, XGBE_PPSCMD_START); + ppscr |= get_target_mode_sel(index, XGBE_PPSTARGET_PULSE); + ppscr |= PPSEN0; + + XGMAC_IOWRITE(pdata, MAC_PPSCR, ppscr); + + return 0; +} |