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