| // SPDX-License-Identifier: GPL-2.0 | 
 | /* Copyright 2021 NXP | 
 |  */ | 
 | #include <linux/pcs/pcs-xpcs.h> | 
 | #include "pcs-xpcs.h" | 
 |  | 
 | /* LANE_DRIVER1_0 register */ | 
 | #define SJA1110_LANE_DRIVER1_0		0x8038 | 
 | #define SJA1110_TXDRV(x)		(((x) << 12) & GENMASK(14, 12)) | 
 |  | 
 | /* LANE_DRIVER2_0 register */ | 
 | #define SJA1110_LANE_DRIVER2_0		0x803a | 
 | #define SJA1110_TXDRVTRIM_LSB(x)	((x) & GENMASK_ULL(15, 0)) | 
 |  | 
 | /* LANE_DRIVER2_1 register */ | 
 | #define SJA1110_LANE_DRIVER2_1		0x803b | 
 | #define SJA1110_LANE_DRIVER2_1_RSV	BIT(9) | 
 | #define SJA1110_TXDRVTRIM_MSB(x)	(((x) & GENMASK_ULL(23, 16)) >> 16) | 
 |  | 
 | /* LANE_TRIM register */ | 
 | #define SJA1110_LANE_TRIM		0x8040 | 
 | #define SJA1110_TXTEN			BIT(11) | 
 | #define SJA1110_TXRTRIM(x)		(((x) << 8) & GENMASK(10, 8)) | 
 | #define SJA1110_TXPLL_BWSEL		BIT(7) | 
 | #define SJA1110_RXTEN			BIT(6) | 
 | #define SJA1110_RXRTRIM(x)		(((x) << 3) & GENMASK(5, 3)) | 
 | #define SJA1110_CDR_GAIN		BIT(2) | 
 | #define SJA1110_ACCOUPLE_RXVCM_EN	BIT(0) | 
 |  | 
 | /* LANE_DATAPATH_1 register */ | 
 | #define SJA1110_LANE_DATAPATH_1		0x8037 | 
 |  | 
 | /* POWERDOWN_ENABLE register */ | 
 | #define SJA1110_POWERDOWN_ENABLE	0x8041 | 
 | #define SJA1110_TXPLL_PD		BIT(12) | 
 | #define SJA1110_TXPD			BIT(11) | 
 | #define SJA1110_RXPKDETEN		BIT(10) | 
 | #define SJA1110_RXCH_PD			BIT(9) | 
 | #define SJA1110_RXBIAS_PD		BIT(8) | 
 | #define SJA1110_RESET_SER_EN		BIT(7) | 
 | #define SJA1110_RESET_SER		BIT(6) | 
 | #define SJA1110_RESET_DES		BIT(5) | 
 | #define SJA1110_RCVEN			BIT(4) | 
 |  | 
 | /* RXPLL_CTRL0 register */ | 
 | #define SJA1110_RXPLL_CTRL0		0x8065 | 
 | #define SJA1110_RXPLL_FBDIV(x)		(((x) << 2) & GENMASK(9, 2)) | 
 |  | 
 | /* RXPLL_CTRL1 register */ | 
 | #define SJA1110_RXPLL_CTRL1		0x8066 | 
 | #define SJA1110_RXPLL_REFDIV(x)		((x) & GENMASK(4, 0)) | 
 |  | 
 | /* TXPLL_CTRL0 register */ | 
 | #define SJA1110_TXPLL_CTRL0		0x806d | 
 | #define SJA1110_TXPLL_FBDIV(x)		((x) & GENMASK(11, 0)) | 
 |  | 
 | /* TXPLL_CTRL1 register */ | 
 | #define SJA1110_TXPLL_CTRL1		0x806e | 
 | #define SJA1110_TXPLL_REFDIV(x)		((x) & GENMASK(5, 0)) | 
 |  | 
 | /* RX_DATA_DETECT register */ | 
 | #define SJA1110_RX_DATA_DETECT		0x8045 | 
 |  | 
 | /* RX_CDR_CTLE register */ | 
 | #define SJA1110_RX_CDR_CTLE		0x8042 | 
 |  | 
 | /* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane | 
 |  * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain | 
 |  * normal non-inverted behavior, the TX lane polarity must be inverted in the | 
 |  * PCS, via the DIGITAL_CONTROL_2 register. | 
 |  */ | 
 | int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs) | 
 | { | 
 | 	return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2, | 
 | 			  DW_VR_MII_DIG_CTRL2_TX_POL_INV); | 
 | } | 
 |  | 
 | static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs, | 
 | 				  u16 txpll_fbdiv, u16 txpll_refdiv, | 
 | 				  u16 rxpll_fbdiv, u16 rxpll_refdiv, | 
 | 				  u16 rx_cdr_ctle) | 
 | { | 
 | 	u16 val; | 
 | 	int ret; | 
 |  | 
 | 	/* Program TX PLL feedback divider and reference divider settings for | 
 | 	 * correct oscillation frequency. | 
 | 	 */ | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0, | 
 | 			 SJA1110_TXPLL_FBDIV(txpll_fbdiv)); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1, | 
 | 			 SJA1110_TXPLL_REFDIV(txpll_refdiv)); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	/* Program transmitter amplitude and disable amplitude trimming */ | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER1_0, | 
 | 			 SJA1110_TXDRV(0x5)); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	val = SJA1110_TXDRVTRIM_LSB(0xffffffull); | 
 |  | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_0, val); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	val = SJA1110_TXDRVTRIM_MSB(0xffffffull) | SJA1110_LANE_DRIVER2_1_RSV; | 
 |  | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_1, val); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	/* Enable input and output resistor terminations for low BER. */ | 
 | 	val = SJA1110_ACCOUPLE_RXVCM_EN | SJA1110_CDR_GAIN | | 
 | 	      SJA1110_RXRTRIM(4) | SJA1110_RXTEN | SJA1110_TXPLL_BWSEL | | 
 | 	      SJA1110_TXRTRIM(3) | SJA1110_TXTEN; | 
 |  | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_TRIM, val); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	/* Select PCS as transmitter data source. */ | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DATAPATH_1, 0); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	/* Program RX PLL feedback divider and reference divider for correct | 
 | 	 * oscillation frequency. | 
 | 	 */ | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0, | 
 | 			 SJA1110_RXPLL_FBDIV(rxpll_fbdiv)); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1, | 
 | 			 SJA1110_RXPLL_REFDIV(rxpll_refdiv)); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	/* Program threshold for receiver signal detector. | 
 | 	 * Enable control of RXPLL by receiver signal detector to disable RXPLL | 
 | 	 * when an input signal is not present. | 
 | 	 */ | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_DATA_DETECT, 0x0005); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	/* Enable TX and RX PLLs and circuits. | 
 | 	 * Release reset of PMA to enable data flow to/from PCS. | 
 | 	 */ | 
 | 	ret = xpcs_read(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	val = ret & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD | | 
 | 		      SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN | | 
 | 		      SJA1110_RESET_SER | SJA1110_RESET_DES); | 
 | 	val |= SJA1110_RXPKDETEN | SJA1110_RCVEN; | 
 |  | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE, val); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	/* Program continuous-time linear equalizer (CTLE) settings. */ | 
 | 	ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE, | 
 | 			 rx_cdr_ctle); | 
 | 	if (ret < 0) | 
 | 		return ret; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs) | 
 | { | 
 | 	return nxp_sja1110_pma_config(xpcs, 0x19, 0x1, 0x19, 0x1, 0x212a); | 
 | } | 
 |  | 
 | int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs) | 
 | { | 
 | 	return nxp_sja1110_pma_config(xpcs, 0x7d, 0x2, 0x7d, 0x2, 0x732a); | 
 | } |