1// SPDX-License-Identifier: GPL-2.0
2/* Copyright 2021 NXP
3 */
4#include <linux/pcs/pcs-xpcs.h>
5#include "pcs-xpcs.h"
6
7/* LANE_DRIVER1_0 register */
8#define SJA1110_LANE_DRIVER1_0 0x8038
9#define SJA1110_TXDRV(x) (((x) << 12) & GENMASK(14, 12))
10
11/* LANE_DRIVER2_0 register */
12#define SJA1110_LANE_DRIVER2_0 0x803a
13#define SJA1110_TXDRVTRIM_LSB(x) ((x) & GENMASK_ULL(15, 0))
14
15/* LANE_DRIVER2_1 register */
16#define SJA1110_LANE_DRIVER2_1 0x803b
17#define SJA1110_LANE_DRIVER2_1_RSV BIT(9)
18#define SJA1110_TXDRVTRIM_MSB(x) (((x) & GENMASK_ULL(23, 16)) >> 16)
19
20/* LANE_TRIM register */
21#define SJA1110_LANE_TRIM 0x8040
22#define SJA1110_TXTEN BIT(11)
23#define SJA1110_TXRTRIM(x) (((x) << 8) & GENMASK(10, 8))
24#define SJA1110_TXPLL_BWSEL BIT(7)
25#define SJA1110_RXTEN BIT(6)
26#define SJA1110_RXRTRIM(x) (((x) << 3) & GENMASK(5, 3))
27#define SJA1110_CDR_GAIN BIT(2)
28#define SJA1110_ACCOUPLE_RXVCM_EN BIT(0)
29
30/* LANE_DATAPATH_1 register */
31#define SJA1110_LANE_DATAPATH_1 0x8037
32
33/* POWERDOWN_ENABLE register */
34#define SJA1110_POWERDOWN_ENABLE 0x8041
35#define SJA1110_TXPLL_PD BIT(12)
36#define SJA1110_TXPD BIT(11)
37#define SJA1110_RXPKDETEN BIT(10)
38#define SJA1110_RXCH_PD BIT(9)
39#define SJA1110_RXBIAS_PD BIT(8)
40#define SJA1110_RESET_SER_EN BIT(7)
41#define SJA1110_RESET_SER BIT(6)
42#define SJA1110_RESET_DES BIT(5)
43#define SJA1110_RCVEN BIT(4)
44
45/* RXPLL_CTRL0 register */
46#define SJA1110_RXPLL_CTRL0 0x8065
47#define SJA1110_RXPLL_FBDIV(x) (((x) << 2) & GENMASK(9, 2))
48
49/* RXPLL_CTRL1 register */
50#define SJA1110_RXPLL_CTRL1 0x8066
51#define SJA1110_RXPLL_REFDIV(x) ((x) & GENMASK(4, 0))
52
53/* TXPLL_CTRL0 register */
54#define SJA1110_TXPLL_CTRL0 0x806d
55#define SJA1110_TXPLL_FBDIV(x) ((x) & GENMASK(11, 0))
56
57/* TXPLL_CTRL1 register */
58#define SJA1110_TXPLL_CTRL1 0x806e
59#define SJA1110_TXPLL_REFDIV(x) ((x) & GENMASK(5, 0))
60
61/* RX_DATA_DETECT register */
62#define SJA1110_RX_DATA_DETECT 0x8045
63
64/* RX_CDR_CTLE register */
65#define SJA1110_RX_CDR_CTLE 0x8042
66
67/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane
68 * polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain
69 * normal non-inverted behavior, the TX lane polarity must be inverted in the
70 * PCS, via the DIGITAL_CONTROL_2 register.
71 */
72int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs)
73{
74 return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2,
75 DW_VR_MII_DIG_CTRL2_TX_POL_INV);
76}
77
78static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs,
79 u16 txpll_fbdiv, u16 txpll_refdiv,
80 u16 rxpll_fbdiv, u16 rxpll_refdiv,
81 u16 rx_cdr_ctle)
82{
83 u16 val;
84 int ret;
85
86 /* Program TX PLL feedback divider and reference divider settings for
87 * correct oscillation frequency.
88 */
89 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0,
90 SJA1110_TXPLL_FBDIV(txpll_fbdiv));
91 if (ret < 0)
92 return ret;
93
94 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1,
95 SJA1110_TXPLL_REFDIV(txpll_refdiv));
96 if (ret < 0)
97 return ret;
98
99 /* Program transmitter amplitude and disable amplitude trimming */
100 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER1_0,
101 SJA1110_TXDRV(0x5));
102 if (ret < 0)
103 return ret;
104
105 val = SJA1110_TXDRVTRIM_LSB(0xffffffull);
106
107 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_0, val);
108 if (ret < 0)
109 return ret;
110
111 val = SJA1110_TXDRVTRIM_MSB(0xffffffull) | SJA1110_LANE_DRIVER2_1_RSV;
112
113 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_1, val);
114 if (ret < 0)
115 return ret;
116
117 /* Enable input and output resistor terminations for low BER. */
118 val = SJA1110_ACCOUPLE_RXVCM_EN | SJA1110_CDR_GAIN |
119 SJA1110_RXRTRIM(4) | SJA1110_RXTEN | SJA1110_TXPLL_BWSEL |
120 SJA1110_TXRTRIM(3) | SJA1110_TXTEN;
121
122 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_TRIM, val);
123 if (ret < 0)
124 return ret;
125
126 /* Select PCS as transmitter data source. */
127 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DATAPATH_1, val: 0);
128 if (ret < 0)
129 return ret;
130
131 /* Program RX PLL feedback divider and reference divider for correct
132 * oscillation frequency.
133 */
134 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0,
135 SJA1110_RXPLL_FBDIV(rxpll_fbdiv));
136 if (ret < 0)
137 return ret;
138
139 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1,
140 SJA1110_RXPLL_REFDIV(rxpll_refdiv));
141 if (ret < 0)
142 return ret;
143
144 /* Program threshold for receiver signal detector.
145 * Enable control of RXPLL by receiver signal detector to disable RXPLL
146 * when an input signal is not present.
147 */
148 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_DATA_DETECT, val: 0x0005);
149 if (ret < 0)
150 return ret;
151
152 /* Enable TX and RX PLLs and circuits.
153 * Release reset of PMA to enable data flow to/from PCS.
154 */
155 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE);
156 if (ret < 0)
157 return ret;
158
159 val = ret & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD |
160 SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN |
161 SJA1110_RESET_SER | SJA1110_RESET_DES);
162 val |= SJA1110_RXPKDETEN | SJA1110_RCVEN;
163
164 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE, val);
165 if (ret < 0)
166 return ret;
167
168 /* Program continuous-time linear equalizer (CTLE) settings. */
169 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE,
170 val: rx_cdr_ctle);
171 if (ret < 0)
172 return ret;
173
174 return 0;
175}
176
177int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs)
178{
179 return nxp_sja1110_pma_config(xpcs, txpll_fbdiv: 0x19, txpll_refdiv: 0x1, rxpll_fbdiv: 0x19, rxpll_refdiv: 0x1, rx_cdr_ctle: 0x212a);
180}
181
182int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs)
183{
184 return nxp_sja1110_pma_config(xpcs, txpll_fbdiv: 0x7d, txpll_refdiv: 0x2, rxpll_fbdiv: 0x7d, rxpll_refdiv: 0x2, rx_cdr_ctle: 0x732a);
185}
186

source code of linux/drivers/net/pcs/pcs-xpcs-nxp.c