162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright 2021 NXP
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci#include <linux/pcs/pcs-xpcs.h>
562306a36Sopenharmony_ci#include "pcs-xpcs.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci/* LANE_DRIVER1_0 register */
862306a36Sopenharmony_ci#define SJA1110_LANE_DRIVER1_0		0x8038
962306a36Sopenharmony_ci#define SJA1110_TXDRV(x)		(((x) << 12) & GENMASK(14, 12))
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* LANE_DRIVER2_0 register */
1262306a36Sopenharmony_ci#define SJA1110_LANE_DRIVER2_0		0x803a
1362306a36Sopenharmony_ci#define SJA1110_TXDRVTRIM_LSB(x)	((x) & GENMASK_ULL(15, 0))
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* LANE_DRIVER2_1 register */
1662306a36Sopenharmony_ci#define SJA1110_LANE_DRIVER2_1		0x803b
1762306a36Sopenharmony_ci#define SJA1110_LANE_DRIVER2_1_RSV	BIT(9)
1862306a36Sopenharmony_ci#define SJA1110_TXDRVTRIM_MSB(x)	(((x) & GENMASK_ULL(23, 16)) >> 16)
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* LANE_TRIM register */
2162306a36Sopenharmony_ci#define SJA1110_LANE_TRIM		0x8040
2262306a36Sopenharmony_ci#define SJA1110_TXTEN			BIT(11)
2362306a36Sopenharmony_ci#define SJA1110_TXRTRIM(x)		(((x) << 8) & GENMASK(10, 8))
2462306a36Sopenharmony_ci#define SJA1110_TXPLL_BWSEL		BIT(7)
2562306a36Sopenharmony_ci#define SJA1110_RXTEN			BIT(6)
2662306a36Sopenharmony_ci#define SJA1110_RXRTRIM(x)		(((x) << 3) & GENMASK(5, 3))
2762306a36Sopenharmony_ci#define SJA1110_CDR_GAIN		BIT(2)
2862306a36Sopenharmony_ci#define SJA1110_ACCOUPLE_RXVCM_EN	BIT(0)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* LANE_DATAPATH_1 register */
3162306a36Sopenharmony_ci#define SJA1110_LANE_DATAPATH_1		0x8037
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* POWERDOWN_ENABLE register */
3462306a36Sopenharmony_ci#define SJA1110_POWERDOWN_ENABLE	0x8041
3562306a36Sopenharmony_ci#define SJA1110_TXPLL_PD		BIT(12)
3662306a36Sopenharmony_ci#define SJA1110_TXPD			BIT(11)
3762306a36Sopenharmony_ci#define SJA1110_RXPKDETEN		BIT(10)
3862306a36Sopenharmony_ci#define SJA1110_RXCH_PD			BIT(9)
3962306a36Sopenharmony_ci#define SJA1110_RXBIAS_PD		BIT(8)
4062306a36Sopenharmony_ci#define SJA1110_RESET_SER_EN		BIT(7)
4162306a36Sopenharmony_ci#define SJA1110_RESET_SER		BIT(6)
4262306a36Sopenharmony_ci#define SJA1110_RESET_DES		BIT(5)
4362306a36Sopenharmony_ci#define SJA1110_RCVEN			BIT(4)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* RXPLL_CTRL0 register */
4662306a36Sopenharmony_ci#define SJA1110_RXPLL_CTRL0		0x8065
4762306a36Sopenharmony_ci#define SJA1110_RXPLL_FBDIV(x)		(((x) << 2) & GENMASK(9, 2))
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* RXPLL_CTRL1 register */
5062306a36Sopenharmony_ci#define SJA1110_RXPLL_CTRL1		0x8066
5162306a36Sopenharmony_ci#define SJA1110_RXPLL_REFDIV(x)		((x) & GENMASK(4, 0))
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* TXPLL_CTRL0 register */
5462306a36Sopenharmony_ci#define SJA1110_TXPLL_CTRL0		0x806d
5562306a36Sopenharmony_ci#define SJA1110_TXPLL_FBDIV(x)		((x) & GENMASK(11, 0))
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* TXPLL_CTRL1 register */
5862306a36Sopenharmony_ci#define SJA1110_TXPLL_CTRL1		0x806e
5962306a36Sopenharmony_ci#define SJA1110_TXPLL_REFDIV(x)		((x) & GENMASK(5, 0))
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* RX_DATA_DETECT register */
6262306a36Sopenharmony_ci#define SJA1110_RX_DATA_DETECT		0x8045
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* RX_CDR_CTLE register */
6562306a36Sopenharmony_ci#define SJA1110_RX_CDR_CTLE		0x8042
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane
6862306a36Sopenharmony_ci * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain
6962306a36Sopenharmony_ci * normal non-inverted behavior, the TX lane polarity must be inverted in the
7062306a36Sopenharmony_ci * PCS, via the DIGITAL_CONTROL_2 register.
7162306a36Sopenharmony_ci */
7262306a36Sopenharmony_ciint nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2,
7562306a36Sopenharmony_ci			  DW_VR_MII_DIG_CTRL2_TX_POL_INV);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int nxp_sja1110_pma_config(struct dw_xpcs *xpcs,
7962306a36Sopenharmony_ci				  u16 txpll_fbdiv, u16 txpll_refdiv,
8062306a36Sopenharmony_ci				  u16 rxpll_fbdiv, u16 rxpll_refdiv,
8162306a36Sopenharmony_ci				  u16 rx_cdr_ctle)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	u16 val;
8462306a36Sopenharmony_ci	int ret;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Program TX PLL feedback divider and reference divider settings for
8762306a36Sopenharmony_ci	 * correct oscillation frequency.
8862306a36Sopenharmony_ci	 */
8962306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0,
9062306a36Sopenharmony_ci			 SJA1110_TXPLL_FBDIV(txpll_fbdiv));
9162306a36Sopenharmony_ci	if (ret < 0)
9262306a36Sopenharmony_ci		return ret;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1,
9562306a36Sopenharmony_ci			 SJA1110_TXPLL_REFDIV(txpll_refdiv));
9662306a36Sopenharmony_ci	if (ret < 0)
9762306a36Sopenharmony_ci		return ret;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	/* Program transmitter amplitude and disable amplitude trimming */
10062306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER1_0,
10162306a36Sopenharmony_ci			 SJA1110_TXDRV(0x5));
10262306a36Sopenharmony_ci	if (ret < 0)
10362306a36Sopenharmony_ci		return ret;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	val = SJA1110_TXDRVTRIM_LSB(0xffffffull);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_0, val);
10862306a36Sopenharmony_ci	if (ret < 0)
10962306a36Sopenharmony_ci		return ret;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	val = SJA1110_TXDRVTRIM_MSB(0xffffffull) | SJA1110_LANE_DRIVER2_1_RSV;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_1, val);
11462306a36Sopenharmony_ci	if (ret < 0)
11562306a36Sopenharmony_ci		return ret;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Enable input and output resistor terminations for low BER. */
11862306a36Sopenharmony_ci	val = SJA1110_ACCOUPLE_RXVCM_EN | SJA1110_CDR_GAIN |
11962306a36Sopenharmony_ci	      SJA1110_RXRTRIM(4) | SJA1110_RXTEN | SJA1110_TXPLL_BWSEL |
12062306a36Sopenharmony_ci	      SJA1110_TXRTRIM(3) | SJA1110_TXTEN;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_TRIM, val);
12362306a36Sopenharmony_ci	if (ret < 0)
12462306a36Sopenharmony_ci		return ret;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Select PCS as transmitter data source. */
12762306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DATAPATH_1, 0);
12862306a36Sopenharmony_ci	if (ret < 0)
12962306a36Sopenharmony_ci		return ret;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Program RX PLL feedback divider and reference divider for correct
13262306a36Sopenharmony_ci	 * oscillation frequency.
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0,
13562306a36Sopenharmony_ci			 SJA1110_RXPLL_FBDIV(rxpll_fbdiv));
13662306a36Sopenharmony_ci	if (ret < 0)
13762306a36Sopenharmony_ci		return ret;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1,
14062306a36Sopenharmony_ci			 SJA1110_RXPLL_REFDIV(rxpll_refdiv));
14162306a36Sopenharmony_ci	if (ret < 0)
14262306a36Sopenharmony_ci		return ret;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* Program threshold for receiver signal detector.
14562306a36Sopenharmony_ci	 * Enable control of RXPLL by receiver signal detector to disable RXPLL
14662306a36Sopenharmony_ci	 * when an input signal is not present.
14762306a36Sopenharmony_ci	 */
14862306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_DATA_DETECT, 0x0005);
14962306a36Sopenharmony_ci	if (ret < 0)
15062306a36Sopenharmony_ci		return ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* Enable TX and RX PLLs and circuits.
15362306a36Sopenharmony_ci	 * Release reset of PMA to enable data flow to/from PCS.
15462306a36Sopenharmony_ci	 */
15562306a36Sopenharmony_ci	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE);
15662306a36Sopenharmony_ci	if (ret < 0)
15762306a36Sopenharmony_ci		return ret;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	val = ret & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD |
16062306a36Sopenharmony_ci		      SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN |
16162306a36Sopenharmony_ci		      SJA1110_RESET_SER | SJA1110_RESET_DES);
16262306a36Sopenharmony_ci	val |= SJA1110_RXPKDETEN | SJA1110_RCVEN;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE, val);
16562306a36Sopenharmony_ci	if (ret < 0)
16662306a36Sopenharmony_ci		return ret;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/* Program continuous-time linear equalizer (CTLE) settings. */
16962306a36Sopenharmony_ci	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE,
17062306a36Sopenharmony_ci			 rx_cdr_ctle);
17162306a36Sopenharmony_ci	if (ret < 0)
17262306a36Sopenharmony_ci		return ret;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return 0;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ciint nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	return nxp_sja1110_pma_config(xpcs, 0x19, 0x1, 0x19, 0x1, 0x212a);
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ciint nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	return nxp_sja1110_pma_config(xpcs, 0x7d, 0x2, 0x7d, 0x2, 0x732a);
18562306a36Sopenharmony_ci}
186