1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2018 MediaTek Inc. |
4 | */ |
5 | #include <linux/bitfield.h> |
6 | #include <linux/io.h> |
7 | #include <linux/mfd/syscon.h> |
8 | #include <linux/module.h> |
9 | #include <linux/of.h> |
10 | #include <linux/of_net.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/regmap.h> |
13 | #include <linux/stmmac.h> |
14 | |
15 | #include "stmmac.h" |
16 | #include "stmmac_platform.h" |
17 | |
18 | /* Peri Configuration register for mt2712 */ |
19 | #define PERI_ETH_PHY_INTF_SEL 0x418 |
20 | #define PHY_INTF_MII 0 |
21 | #define PHY_INTF_RGMII 1 |
22 | #define PHY_INTF_RMII 4 |
23 | #define RMII_CLK_SRC_RXC BIT(4) |
24 | #define RMII_CLK_SRC_INTERNAL BIT(5) |
25 | |
26 | #define PERI_ETH_DLY 0x428 |
27 | #define ETH_DLY_GTXC_INV BIT(6) |
28 | #define ETH_DLY_GTXC_ENABLE BIT(5) |
29 | #define ETH_DLY_GTXC_STAGES GENMASK(4, 0) |
30 | #define ETH_DLY_TXC_INV BIT(20) |
31 | #define ETH_DLY_TXC_ENABLE BIT(19) |
32 | #define ETH_DLY_TXC_STAGES GENMASK(18, 14) |
33 | #define ETH_DLY_RXC_INV BIT(13) |
34 | #define ETH_DLY_RXC_ENABLE BIT(12) |
35 | #define ETH_DLY_RXC_STAGES GENMASK(11, 7) |
36 | |
37 | #define PERI_ETH_DLY_FINE 0x800 |
38 | #define ETH_RMII_DLY_TX_INV BIT(2) |
39 | #define ETH_FINE_DLY_GTXC BIT(1) |
40 | #define ETH_FINE_DLY_RXC BIT(0) |
41 | |
42 | /* Peri Configuration register for mt8195 */ |
43 | #define MT8195_PERI_ETH_CTRL0 0xFD0 |
44 | #define MT8195_RMII_CLK_SRC_INTERNAL BIT(28) |
45 | #define MT8195_RMII_CLK_SRC_RXC BIT(27) |
46 | #define MT8195_ETH_INTF_SEL GENMASK(26, 24) |
47 | #define MT8195_RGMII_TXC_PHASE_CTRL BIT(22) |
48 | #define MT8195_EXT_PHY_MODE BIT(21) |
49 | #define MT8195_DLY_GTXC_INV BIT(12) |
50 | #define MT8195_DLY_GTXC_ENABLE BIT(5) |
51 | #define MT8195_DLY_GTXC_STAGES GENMASK(4, 0) |
52 | |
53 | #define MT8195_PERI_ETH_CTRL1 0xFD4 |
54 | #define MT8195_DLY_RXC_INV BIT(25) |
55 | #define MT8195_DLY_RXC_ENABLE BIT(18) |
56 | #define MT8195_DLY_RXC_STAGES GENMASK(17, 13) |
57 | #define MT8195_DLY_TXC_INV BIT(12) |
58 | #define MT8195_DLY_TXC_ENABLE BIT(5) |
59 | #define MT8195_DLY_TXC_STAGES GENMASK(4, 0) |
60 | |
61 | #define MT8195_PERI_ETH_CTRL2 0xFD8 |
62 | #define MT8195_DLY_RMII_RXC_INV BIT(25) |
63 | #define MT8195_DLY_RMII_RXC_ENABLE BIT(18) |
64 | #define MT8195_DLY_RMII_RXC_STAGES GENMASK(17, 13) |
65 | #define MT8195_DLY_RMII_TXC_INV BIT(12) |
66 | #define MT8195_DLY_RMII_TXC_ENABLE BIT(5) |
67 | #define MT8195_DLY_RMII_TXC_STAGES GENMASK(4, 0) |
68 | |
69 | struct mac_delay_struct { |
70 | u32 tx_delay; |
71 | u32 rx_delay; |
72 | bool tx_inv; |
73 | bool rx_inv; |
74 | }; |
75 | |
76 | struct mediatek_dwmac_plat_data { |
77 | const struct mediatek_dwmac_variant *variant; |
78 | struct mac_delay_struct mac_delay; |
79 | struct clk *rmii_internal_clk; |
80 | struct clk_bulk_data *clks; |
81 | struct regmap *peri_regmap; |
82 | struct device_node *np; |
83 | struct device *dev; |
84 | phy_interface_t phy_mode; |
85 | bool rmii_clk_from_mac; |
86 | bool rmii_rxc; |
87 | bool mac_wol; |
88 | }; |
89 | |
90 | struct mediatek_dwmac_variant { |
91 | int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat); |
92 | int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat); |
93 | |
94 | /* clock ids to be requested */ |
95 | const char * const *clk_list; |
96 | int num_clks; |
97 | |
98 | u32 dma_bit_mask; |
99 | u32 rx_delay_max; |
100 | u32 tx_delay_max; |
101 | }; |
102 | |
103 | /* list of clocks required for mac */ |
104 | static const char * const mt2712_dwmac_clk_l[] = { |
105 | "axi" , "apb" , "mac_main" , "ptp_ref" |
106 | }; |
107 | |
108 | static const char * const mt8195_dwmac_clk_l[] = { |
109 | "axi" , "apb" , "mac_cg" , "mac_main" , "ptp_ref" |
110 | }; |
111 | |
112 | static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat) |
113 | { |
114 | int rmii_clk_from_mac = plat->rmii_clk_from_mac ? RMII_CLK_SRC_INTERNAL : 0; |
115 | int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0; |
116 | u32 intf_val = 0; |
117 | |
118 | /* select phy interface in top control domain */ |
119 | switch (plat->phy_mode) { |
120 | case PHY_INTERFACE_MODE_MII: |
121 | intf_val |= PHY_INTF_MII; |
122 | break; |
123 | case PHY_INTERFACE_MODE_RMII: |
124 | intf_val |= (PHY_INTF_RMII | rmii_rxc | rmii_clk_from_mac); |
125 | break; |
126 | case PHY_INTERFACE_MODE_RGMII: |
127 | case PHY_INTERFACE_MODE_RGMII_TXID: |
128 | case PHY_INTERFACE_MODE_RGMII_RXID: |
129 | case PHY_INTERFACE_MODE_RGMII_ID: |
130 | intf_val |= PHY_INTF_RGMII; |
131 | break; |
132 | default: |
133 | dev_err(plat->dev, "phy interface not supported\n" ); |
134 | return -EINVAL; |
135 | } |
136 | |
137 | regmap_write(map: plat->peri_regmap, PERI_ETH_PHY_INTF_SEL, val: intf_val); |
138 | |
139 | return 0; |
140 | } |
141 | |
142 | static void mt2712_delay_ps2stage(struct mediatek_dwmac_plat_data *plat) |
143 | { |
144 | struct mac_delay_struct *mac_delay = &plat->mac_delay; |
145 | |
146 | switch (plat->phy_mode) { |
147 | case PHY_INTERFACE_MODE_MII: |
148 | case PHY_INTERFACE_MODE_RMII: |
149 | /* 550ps per stage for MII/RMII */ |
150 | mac_delay->tx_delay /= 550; |
151 | mac_delay->rx_delay /= 550; |
152 | break; |
153 | case PHY_INTERFACE_MODE_RGMII: |
154 | case PHY_INTERFACE_MODE_RGMII_TXID: |
155 | case PHY_INTERFACE_MODE_RGMII_RXID: |
156 | case PHY_INTERFACE_MODE_RGMII_ID: |
157 | /* 170ps per stage for RGMII */ |
158 | mac_delay->tx_delay /= 170; |
159 | mac_delay->rx_delay /= 170; |
160 | break; |
161 | default: |
162 | dev_err(plat->dev, "phy interface not supported\n" ); |
163 | break; |
164 | } |
165 | } |
166 | |
167 | static void mt2712_delay_stage2ps(struct mediatek_dwmac_plat_data *plat) |
168 | { |
169 | struct mac_delay_struct *mac_delay = &plat->mac_delay; |
170 | |
171 | switch (plat->phy_mode) { |
172 | case PHY_INTERFACE_MODE_MII: |
173 | case PHY_INTERFACE_MODE_RMII: |
174 | /* 550ps per stage for MII/RMII */ |
175 | mac_delay->tx_delay *= 550; |
176 | mac_delay->rx_delay *= 550; |
177 | break; |
178 | case PHY_INTERFACE_MODE_RGMII: |
179 | case PHY_INTERFACE_MODE_RGMII_TXID: |
180 | case PHY_INTERFACE_MODE_RGMII_RXID: |
181 | case PHY_INTERFACE_MODE_RGMII_ID: |
182 | /* 170ps per stage for RGMII */ |
183 | mac_delay->tx_delay *= 170; |
184 | mac_delay->rx_delay *= 170; |
185 | break; |
186 | default: |
187 | dev_err(plat->dev, "phy interface not supported\n" ); |
188 | break; |
189 | } |
190 | } |
191 | |
192 | static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat) |
193 | { |
194 | struct mac_delay_struct *mac_delay = &plat->mac_delay; |
195 | u32 delay_val = 0, fine_val = 0; |
196 | |
197 | mt2712_delay_ps2stage(plat); |
198 | |
199 | switch (plat->phy_mode) { |
200 | case PHY_INTERFACE_MODE_MII: |
201 | delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->tx_delay); |
202 | delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->tx_delay); |
203 | delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->tx_inv); |
204 | |
205 | delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay); |
206 | delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay); |
207 | delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv); |
208 | break; |
209 | case PHY_INTERFACE_MODE_RMII: |
210 | if (plat->rmii_clk_from_mac) { |
211 | /* case 1: mac provides the rmii reference clock, |
212 | * and the clock output to TXC pin. |
213 | * The egress timing can be adjusted by GTXC delay macro circuit. |
214 | * The ingress timing can be adjusted by TXC delay macro circuit. |
215 | */ |
216 | delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay); |
217 | delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay); |
218 | delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv); |
219 | |
220 | delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay); |
221 | delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay); |
222 | delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv); |
223 | } else { |
224 | /* case 2: the rmii reference clock is from external phy, |
225 | * and the property "rmii_rxc" indicates which pin(TXC/RXC) |
226 | * the reference clk is connected to. The reference clock is a |
227 | * received signal, so rx_delay/rx_inv are used to indicate |
228 | * the reference clock timing adjustment |
229 | */ |
230 | if (plat->rmii_rxc) { |
231 | /* the rmii reference clock from outside is connected |
232 | * to RXC pin, the reference clock will be adjusted |
233 | * by RXC delay macro circuit. |
234 | */ |
235 | delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay); |
236 | delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay); |
237 | delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv); |
238 | } else { |
239 | /* the rmii reference clock from outside is connected |
240 | * to TXC pin, the reference clock will be adjusted |
241 | * by TXC delay macro circuit. |
242 | */ |
243 | delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay); |
244 | delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay); |
245 | delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv); |
246 | } |
247 | /* tx_inv will inverse the tx clock inside mac relateive to |
248 | * reference clock from external phy, |
249 | * and this bit is located in the same register with fine-tune |
250 | */ |
251 | if (mac_delay->tx_inv) |
252 | fine_val = ETH_RMII_DLY_TX_INV; |
253 | } |
254 | break; |
255 | case PHY_INTERFACE_MODE_RGMII: |
256 | case PHY_INTERFACE_MODE_RGMII_TXID: |
257 | case PHY_INTERFACE_MODE_RGMII_RXID: |
258 | case PHY_INTERFACE_MODE_RGMII_ID: |
259 | fine_val = ETH_FINE_DLY_GTXC | ETH_FINE_DLY_RXC; |
260 | |
261 | delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay); |
262 | delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay); |
263 | delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv); |
264 | |
265 | delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay); |
266 | delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay); |
267 | delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv); |
268 | break; |
269 | default: |
270 | dev_err(plat->dev, "phy interface not supported\n" ); |
271 | return -EINVAL; |
272 | } |
273 | regmap_write(map: plat->peri_regmap, PERI_ETH_DLY, val: delay_val); |
274 | regmap_write(map: plat->peri_regmap, PERI_ETH_DLY_FINE, val: fine_val); |
275 | |
276 | mt2712_delay_stage2ps(plat); |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | static const struct mediatek_dwmac_variant mt2712_gmac_variant = { |
282 | .dwmac_set_phy_interface = mt2712_set_interface, |
283 | .dwmac_set_delay = mt2712_set_delay, |
284 | .clk_list = mt2712_dwmac_clk_l, |
285 | .num_clks = ARRAY_SIZE(mt2712_dwmac_clk_l), |
286 | .dma_bit_mask = 33, |
287 | .rx_delay_max = 17600, |
288 | .tx_delay_max = 17600, |
289 | }; |
290 | |
291 | static int mt8195_set_interface(struct mediatek_dwmac_plat_data *plat) |
292 | { |
293 | int rmii_clk_from_mac = plat->rmii_clk_from_mac ? MT8195_RMII_CLK_SRC_INTERNAL : 0; |
294 | int rmii_rxc = plat->rmii_rxc ? MT8195_RMII_CLK_SRC_RXC : 0; |
295 | u32 intf_val = 0; |
296 | |
297 | /* select phy interface in top control domain */ |
298 | switch (plat->phy_mode) { |
299 | case PHY_INTERFACE_MODE_MII: |
300 | intf_val |= FIELD_PREP(MT8195_ETH_INTF_SEL, PHY_INTF_MII); |
301 | break; |
302 | case PHY_INTERFACE_MODE_RMII: |
303 | intf_val |= (rmii_rxc | rmii_clk_from_mac); |
304 | intf_val |= FIELD_PREP(MT8195_ETH_INTF_SEL, PHY_INTF_RMII); |
305 | break; |
306 | case PHY_INTERFACE_MODE_RGMII: |
307 | case PHY_INTERFACE_MODE_RGMII_TXID: |
308 | case PHY_INTERFACE_MODE_RGMII_RXID: |
309 | case PHY_INTERFACE_MODE_RGMII_ID: |
310 | intf_val |= FIELD_PREP(MT8195_ETH_INTF_SEL, PHY_INTF_RGMII); |
311 | break; |
312 | default: |
313 | dev_err(plat->dev, "phy interface not supported\n" ); |
314 | return -EINVAL; |
315 | } |
316 | |
317 | /* MT8195 only support external PHY */ |
318 | intf_val |= MT8195_EXT_PHY_MODE; |
319 | |
320 | regmap_write(map: plat->peri_regmap, MT8195_PERI_ETH_CTRL0, val: intf_val); |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | static void mt8195_delay_ps2stage(struct mediatek_dwmac_plat_data *plat) |
326 | { |
327 | struct mac_delay_struct *mac_delay = &plat->mac_delay; |
328 | |
329 | /* 290ps per stage */ |
330 | mac_delay->tx_delay /= 290; |
331 | mac_delay->rx_delay /= 290; |
332 | } |
333 | |
334 | static void mt8195_delay_stage2ps(struct mediatek_dwmac_plat_data *plat) |
335 | { |
336 | struct mac_delay_struct *mac_delay = &plat->mac_delay; |
337 | |
338 | /* 290ps per stage */ |
339 | mac_delay->tx_delay *= 290; |
340 | mac_delay->rx_delay *= 290; |
341 | } |
342 | |
343 | static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat) |
344 | { |
345 | struct mac_delay_struct *mac_delay = &plat->mac_delay; |
346 | u32 gtxc_delay_val = 0, delay_val = 0, rmii_delay_val = 0; |
347 | |
348 | mt8195_delay_ps2stage(plat); |
349 | |
350 | switch (plat->phy_mode) { |
351 | case PHY_INTERFACE_MODE_MII: |
352 | delay_val |= FIELD_PREP(MT8195_DLY_TXC_ENABLE, !!mac_delay->tx_delay); |
353 | delay_val |= FIELD_PREP(MT8195_DLY_TXC_STAGES, mac_delay->tx_delay); |
354 | delay_val |= FIELD_PREP(MT8195_DLY_TXC_INV, mac_delay->tx_inv); |
355 | |
356 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_ENABLE, !!mac_delay->rx_delay); |
357 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_STAGES, mac_delay->rx_delay); |
358 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_INV, mac_delay->rx_inv); |
359 | break; |
360 | case PHY_INTERFACE_MODE_RMII: |
361 | if (plat->rmii_clk_from_mac) { |
362 | /* case 1: mac provides the rmii reference clock, |
363 | * and the clock output to TXC pin. |
364 | * The egress timing can be adjusted by RMII_TXC delay macro circuit. |
365 | * The ingress timing can be adjusted by RMII_RXC delay macro circuit. |
366 | */ |
367 | rmii_delay_val |= FIELD_PREP(MT8195_DLY_RMII_TXC_ENABLE, |
368 | !!mac_delay->tx_delay); |
369 | rmii_delay_val |= FIELD_PREP(MT8195_DLY_RMII_TXC_STAGES, |
370 | mac_delay->tx_delay); |
371 | rmii_delay_val |= FIELD_PREP(MT8195_DLY_RMII_TXC_INV, |
372 | mac_delay->tx_inv); |
373 | |
374 | rmii_delay_val |= FIELD_PREP(MT8195_DLY_RMII_RXC_ENABLE, |
375 | !!mac_delay->rx_delay); |
376 | rmii_delay_val |= FIELD_PREP(MT8195_DLY_RMII_RXC_STAGES, |
377 | mac_delay->rx_delay); |
378 | rmii_delay_val |= FIELD_PREP(MT8195_DLY_RMII_RXC_INV, |
379 | mac_delay->rx_inv); |
380 | } else { |
381 | /* case 2: the rmii reference clock is from external phy, |
382 | * and the property "rmii_rxc" indicates which pin(TXC/RXC) |
383 | * the reference clk is connected to. The reference clock is a |
384 | * received signal, so rx_delay/rx_inv are used to indicate |
385 | * the reference clock timing adjustment |
386 | */ |
387 | if (plat->rmii_rxc) { |
388 | /* the rmii reference clock from outside is connected |
389 | * to RXC pin, the reference clock will be adjusted |
390 | * by RXC delay macro circuit. |
391 | */ |
392 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_ENABLE, |
393 | !!mac_delay->rx_delay); |
394 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_STAGES, |
395 | mac_delay->rx_delay); |
396 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_INV, |
397 | mac_delay->rx_inv); |
398 | } else { |
399 | /* the rmii reference clock from outside is connected |
400 | * to TXC pin, the reference clock will be adjusted |
401 | * by TXC delay macro circuit. |
402 | */ |
403 | delay_val |= FIELD_PREP(MT8195_DLY_TXC_ENABLE, |
404 | !!mac_delay->rx_delay); |
405 | delay_val |= FIELD_PREP(MT8195_DLY_TXC_STAGES, |
406 | mac_delay->rx_delay); |
407 | delay_val |= FIELD_PREP(MT8195_DLY_TXC_INV, |
408 | mac_delay->rx_inv); |
409 | } |
410 | } |
411 | break; |
412 | case PHY_INTERFACE_MODE_RGMII: |
413 | case PHY_INTERFACE_MODE_RGMII_TXID: |
414 | case PHY_INTERFACE_MODE_RGMII_RXID: |
415 | case PHY_INTERFACE_MODE_RGMII_ID: |
416 | gtxc_delay_val |= FIELD_PREP(MT8195_DLY_GTXC_ENABLE, !!mac_delay->tx_delay); |
417 | gtxc_delay_val |= FIELD_PREP(MT8195_DLY_GTXC_STAGES, mac_delay->tx_delay); |
418 | gtxc_delay_val |= FIELD_PREP(MT8195_DLY_GTXC_INV, mac_delay->tx_inv); |
419 | |
420 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_ENABLE, !!mac_delay->rx_delay); |
421 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_STAGES, mac_delay->rx_delay); |
422 | delay_val |= FIELD_PREP(MT8195_DLY_RXC_INV, mac_delay->rx_inv); |
423 | |
424 | break; |
425 | default: |
426 | dev_err(plat->dev, "phy interface not supported\n" ); |
427 | return -EINVAL; |
428 | } |
429 | |
430 | regmap_update_bits(map: plat->peri_regmap, |
431 | MT8195_PERI_ETH_CTRL0, |
432 | MT8195_RGMII_TXC_PHASE_CTRL | |
433 | MT8195_DLY_GTXC_INV | |
434 | MT8195_DLY_GTXC_ENABLE | |
435 | MT8195_DLY_GTXC_STAGES, |
436 | val: gtxc_delay_val); |
437 | regmap_write(map: plat->peri_regmap, MT8195_PERI_ETH_CTRL1, val: delay_val); |
438 | regmap_write(map: plat->peri_regmap, MT8195_PERI_ETH_CTRL2, val: rmii_delay_val); |
439 | |
440 | mt8195_delay_stage2ps(plat); |
441 | |
442 | return 0; |
443 | } |
444 | |
445 | static const struct mediatek_dwmac_variant mt8195_gmac_variant = { |
446 | .dwmac_set_phy_interface = mt8195_set_interface, |
447 | .dwmac_set_delay = mt8195_set_delay, |
448 | .clk_list = mt8195_dwmac_clk_l, |
449 | .num_clks = ARRAY_SIZE(mt8195_dwmac_clk_l), |
450 | .dma_bit_mask = 35, |
451 | .rx_delay_max = 9280, |
452 | .tx_delay_max = 9280, |
453 | }; |
454 | |
455 | static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat) |
456 | { |
457 | struct mac_delay_struct *mac_delay = &plat->mac_delay; |
458 | u32 tx_delay_ps, rx_delay_ps; |
459 | int err; |
460 | |
461 | plat->peri_regmap = syscon_regmap_lookup_by_phandle(np: plat->np, property: "mediatek,pericfg" ); |
462 | if (IS_ERR(ptr: plat->peri_regmap)) { |
463 | dev_err(plat->dev, "Failed to get pericfg syscon\n" ); |
464 | return PTR_ERR(ptr: plat->peri_regmap); |
465 | } |
466 | |
467 | err = of_get_phy_mode(np: plat->np, interface: &plat->phy_mode); |
468 | if (err) { |
469 | dev_err(plat->dev, "not find phy-mode\n" ); |
470 | return err; |
471 | } |
472 | |
473 | if (!of_property_read_u32(np: plat->np, propname: "mediatek,tx-delay-ps" , out_value: &tx_delay_ps)) { |
474 | if (tx_delay_ps < plat->variant->tx_delay_max) { |
475 | mac_delay->tx_delay = tx_delay_ps; |
476 | } else { |
477 | dev_err(plat->dev, "Invalid TX clock delay: %dps\n" , tx_delay_ps); |
478 | return -EINVAL; |
479 | } |
480 | } |
481 | |
482 | if (!of_property_read_u32(np: plat->np, propname: "mediatek,rx-delay-ps" , out_value: &rx_delay_ps)) { |
483 | if (rx_delay_ps < plat->variant->rx_delay_max) { |
484 | mac_delay->rx_delay = rx_delay_ps; |
485 | } else { |
486 | dev_err(plat->dev, "Invalid RX clock delay: %dps\n" , rx_delay_ps); |
487 | return -EINVAL; |
488 | } |
489 | } |
490 | |
491 | mac_delay->tx_inv = of_property_read_bool(np: plat->np, propname: "mediatek,txc-inverse" ); |
492 | mac_delay->rx_inv = of_property_read_bool(np: plat->np, propname: "mediatek,rxc-inverse" ); |
493 | plat->rmii_rxc = of_property_read_bool(np: plat->np, propname: "mediatek,rmii-rxc" ); |
494 | plat->rmii_clk_from_mac = of_property_read_bool(np: plat->np, propname: "mediatek,rmii-clk-from-mac" ); |
495 | plat->mac_wol = of_property_read_bool(np: plat->np, propname: "mediatek,mac-wol" ); |
496 | |
497 | return 0; |
498 | } |
499 | |
500 | static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat) |
501 | { |
502 | const struct mediatek_dwmac_variant *variant = plat->variant; |
503 | int i, ret; |
504 | |
505 | plat->clks = devm_kcalloc(dev: plat->dev, n: variant->num_clks, size: sizeof(*plat->clks), GFP_KERNEL); |
506 | if (!plat->clks) |
507 | return -ENOMEM; |
508 | |
509 | for (i = 0; i < variant->num_clks; i++) |
510 | plat->clks[i].id = variant->clk_list[i]; |
511 | |
512 | ret = devm_clk_bulk_get(dev: plat->dev, num_clks: variant->num_clks, clks: plat->clks); |
513 | if (ret) |
514 | return ret; |
515 | |
516 | /* The clock labeled as "rmii_internal" is needed only in RMII(when |
517 | * MAC provides the reference clock), and useless for RGMII/MII or |
518 | * RMII(when PHY provides the reference clock). |
519 | * So, "rmii_internal" clock is got and configured only when |
520 | * reference clock of RMII is from MAC. |
521 | */ |
522 | if (plat->rmii_clk_from_mac) { |
523 | plat->rmii_internal_clk = devm_clk_get(dev: plat->dev, id: "rmii_internal" ); |
524 | if (IS_ERR(ptr: plat->rmii_internal_clk)) |
525 | ret = PTR_ERR(ptr: plat->rmii_internal_clk); |
526 | } else { |
527 | plat->rmii_internal_clk = NULL; |
528 | } |
529 | |
530 | return ret; |
531 | } |
532 | |
533 | static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) |
534 | { |
535 | struct mediatek_dwmac_plat_data *plat = priv; |
536 | const struct mediatek_dwmac_variant *variant = plat->variant; |
537 | int ret; |
538 | |
539 | if (variant->dwmac_set_phy_interface) { |
540 | ret = variant->dwmac_set_phy_interface(plat); |
541 | if (ret) { |
542 | dev_err(plat->dev, "failed to set phy interface, err = %d\n" , ret); |
543 | return ret; |
544 | } |
545 | } |
546 | |
547 | if (variant->dwmac_set_delay) { |
548 | ret = variant->dwmac_set_delay(plat); |
549 | if (ret) { |
550 | dev_err(plat->dev, "failed to set delay value, err = %d\n" , ret); |
551 | return ret; |
552 | } |
553 | } |
554 | |
555 | return 0; |
556 | } |
557 | |
558 | static int mediatek_dwmac_clks_config(void *priv, bool enabled) |
559 | { |
560 | struct mediatek_dwmac_plat_data *plat = priv; |
561 | const struct mediatek_dwmac_variant *variant = plat->variant; |
562 | int ret = 0; |
563 | |
564 | if (enabled) { |
565 | ret = clk_bulk_prepare_enable(num_clks: variant->num_clks, clks: plat->clks); |
566 | if (ret) { |
567 | dev_err(plat->dev, "failed to enable clks, err = %d\n" , ret); |
568 | return ret; |
569 | } |
570 | |
571 | ret = clk_prepare_enable(clk: plat->rmii_internal_clk); |
572 | if (ret) { |
573 | dev_err(plat->dev, "failed to enable rmii internal clk, err = %d\n" , ret); |
574 | return ret; |
575 | } |
576 | } else { |
577 | clk_disable_unprepare(clk: plat->rmii_internal_clk); |
578 | clk_bulk_disable_unprepare(num_clks: variant->num_clks, clks: plat->clks); |
579 | } |
580 | |
581 | return ret; |
582 | } |
583 | |
584 | static int mediatek_dwmac_common_data(struct platform_device *pdev, |
585 | struct plat_stmmacenet_data *plat, |
586 | struct mediatek_dwmac_plat_data *priv_plat) |
587 | { |
588 | int i; |
589 | |
590 | plat->mac_interface = priv_plat->phy_mode; |
591 | if (priv_plat->mac_wol) |
592 | plat->flags |= STMMAC_FLAG_USE_PHY_WOL; |
593 | else |
594 | plat->flags &= ~STMMAC_FLAG_USE_PHY_WOL; |
595 | plat->riwt_off = 1; |
596 | plat->maxmtu = ETH_DATA_LEN; |
597 | plat->host_dma_width = priv_plat->variant->dma_bit_mask; |
598 | plat->bsp_priv = priv_plat; |
599 | plat->init = mediatek_dwmac_init; |
600 | plat->clks_config = mediatek_dwmac_clks_config; |
601 | |
602 | plat->safety_feat_cfg = devm_kzalloc(dev: &pdev->dev, |
603 | size: sizeof(*plat->safety_feat_cfg), |
604 | GFP_KERNEL); |
605 | if (!plat->safety_feat_cfg) |
606 | return -ENOMEM; |
607 | |
608 | plat->safety_feat_cfg->tsoee = 1; |
609 | plat->safety_feat_cfg->mrxpee = 0; |
610 | plat->safety_feat_cfg->mestee = 1; |
611 | plat->safety_feat_cfg->mrxee = 1; |
612 | plat->safety_feat_cfg->mtxee = 1; |
613 | plat->safety_feat_cfg->epsi = 0; |
614 | plat->safety_feat_cfg->edpp = 1; |
615 | plat->safety_feat_cfg->prtyen = 1; |
616 | plat->safety_feat_cfg->tmouten = 1; |
617 | |
618 | for (i = 0; i < plat->tx_queues_to_use; i++) { |
619 | /* Default TX Q0 to use TSO and rest TXQ for TBS */ |
620 | if (i > 0) |
621 | plat->tx_queues_cfg[i].tbs_en = 1; |
622 | } |
623 | |
624 | return 0; |
625 | } |
626 | |
627 | static int mediatek_dwmac_probe(struct platform_device *pdev) |
628 | { |
629 | struct mediatek_dwmac_plat_data *priv_plat; |
630 | struct plat_stmmacenet_data *plat_dat; |
631 | struct stmmac_resources stmmac_res; |
632 | int ret; |
633 | |
634 | priv_plat = devm_kzalloc(dev: &pdev->dev, size: sizeof(*priv_plat), GFP_KERNEL); |
635 | if (!priv_plat) |
636 | return -ENOMEM; |
637 | |
638 | priv_plat->variant = of_device_get_match_data(dev: &pdev->dev); |
639 | if (!priv_plat->variant) { |
640 | dev_err(&pdev->dev, "Missing dwmac-mediatek variant\n" ); |
641 | return -EINVAL; |
642 | } |
643 | |
644 | priv_plat->dev = &pdev->dev; |
645 | priv_plat->np = pdev->dev.of_node; |
646 | |
647 | ret = mediatek_dwmac_config_dt(plat: priv_plat); |
648 | if (ret) |
649 | return ret; |
650 | |
651 | ret = mediatek_dwmac_clk_init(plat: priv_plat); |
652 | if (ret) |
653 | return ret; |
654 | |
655 | ret = stmmac_get_platform_resources(pdev, stmmac_res: &stmmac_res); |
656 | if (ret) |
657 | return ret; |
658 | |
659 | plat_dat = devm_stmmac_probe_config_dt(pdev, mac: stmmac_res.mac); |
660 | if (IS_ERR(ptr: plat_dat)) |
661 | return PTR_ERR(ptr: plat_dat); |
662 | |
663 | mediatek_dwmac_common_data(pdev, plat: plat_dat, priv_plat); |
664 | mediatek_dwmac_init(pdev, priv: priv_plat); |
665 | |
666 | ret = mediatek_dwmac_clks_config(priv: priv_plat, enabled: true); |
667 | if (ret) |
668 | return ret; |
669 | |
670 | ret = stmmac_dvr_probe(device: &pdev->dev, plat_dat, res: &stmmac_res); |
671 | if (ret) |
672 | goto err_drv_probe; |
673 | |
674 | return 0; |
675 | |
676 | err_drv_probe: |
677 | mediatek_dwmac_clks_config(priv: priv_plat, enabled: false); |
678 | |
679 | return ret; |
680 | } |
681 | |
682 | static void mediatek_dwmac_remove(struct platform_device *pdev) |
683 | { |
684 | struct mediatek_dwmac_plat_data *priv_plat = get_stmmac_bsp_priv(dev: &pdev->dev); |
685 | |
686 | stmmac_pltfr_remove(pdev); |
687 | mediatek_dwmac_clks_config(priv: priv_plat, enabled: false); |
688 | } |
689 | |
690 | static const struct of_device_id mediatek_dwmac_match[] = { |
691 | { .compatible = "mediatek,mt2712-gmac" , |
692 | .data = &mt2712_gmac_variant }, |
693 | { .compatible = "mediatek,mt8195-gmac" , |
694 | .data = &mt8195_gmac_variant }, |
695 | { } |
696 | }; |
697 | |
698 | MODULE_DEVICE_TABLE(of, mediatek_dwmac_match); |
699 | |
700 | static struct platform_driver mediatek_dwmac_driver = { |
701 | .probe = mediatek_dwmac_probe, |
702 | .remove_new = mediatek_dwmac_remove, |
703 | .driver = { |
704 | .name = "dwmac-mediatek" , |
705 | .pm = &stmmac_pltfr_pm_ops, |
706 | .of_match_table = mediatek_dwmac_match, |
707 | }, |
708 | }; |
709 | module_platform_driver(mediatek_dwmac_driver); |
710 | |
711 | MODULE_AUTHOR("Biao Huang <biao.huang@mediatek.com>" ); |
712 | MODULE_DESCRIPTION("MediaTek DWMAC specific glue layer" ); |
713 | MODULE_LICENSE("GPL v2" ); |
714 | |