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 | */ |
72 | int 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 | |
78 | static 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 | |
177 | int 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 | |
182 | int 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 | |