// 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 */ #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; }