summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/amd/xgbe/xgbe-pps.c
blob: 6d03ae7ab36f22419d49c17e812b1262ae9da84a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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;
}