]>
Commit | Line | Data |
---|---|---|
07679b11 PH |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Driver for Renesas Ethernet RSwitch2 (Ethernet-TSN). | |
4 | * | |
5 | * Copyright (C) 2021 Renesas Electronics Corporation | |
6 | * | |
7 | * Based on the Renesas Ethernet AVB driver. | |
8 | */ | |
9 | ||
10 | #include <asm/io.h> | |
11 | #include <clk.h> | |
07679b11 PH |
12 | #include <dm.h> |
13 | #include <dm/device-internal.h> | |
14 | #include <dm/device_compat.h> | |
15 | #include <dm/lists.h> | |
16 | #include <errno.h> | |
17 | #include <generic-phy.h> | |
18 | #include <linux/bitops.h> | |
19 | #include <linux/delay.h> | |
20 | #include <linux/iopoll.h> | |
21 | #include <linux/mii.h> | |
22 | #include <eth_phy.h> | |
23 | #include <log.h> | |
24 | #include <malloc.h> | |
25 | #include <miiphy.h> | |
26 | ||
27 | #define RSWITCH_SLEEP_US 1000 | |
28 | #define RSWITCH_TIMEOUT_US 1000000 | |
29 | ||
30 | #define RSWITCH_NUM_HW 5 | |
31 | ||
32 | #define ETHA_TO_GWCA(i) ((i) % 2) | |
33 | #define GWCA_TO_HW_INDEX(i) ((i) + 3) | |
34 | #define HW_INDEX_TO_GWCA(i) ((i) - 3) | |
35 | ||
36 | #define RSWITCH_MAX_CTAG_PCP 7 | |
37 | ||
38 | /* Registers */ | |
39 | #define RSWITCH_COMA_OFFSET 0x00009000 | |
40 | #define RSWITCH_ETHA_OFFSET 0x0000a000 /* with RMAC */ | |
41 | #define RSWITCH_ETHA_SIZE 0x00002000 /* with RMAC */ | |
42 | #define RSWITCH_GWCA_OFFSET 0x00010000 | |
43 | #define RSWITCH_GWCA_SIZE 0x00002000 | |
44 | ||
45 | #define FWRO 0 | |
46 | #define CARO RSWITCH_COMA_OFFSET | |
47 | #define GWRO 0 | |
48 | #define TARO 0 | |
49 | #define RMRO 0x1000 | |
50 | ||
51 | enum rswitch_reg { | |
52 | EAMC = TARO + 0x0000, | |
53 | EAMS = TARO + 0x0004, | |
54 | EATDQDC = TARO + 0x0060, | |
55 | EATTFC = TARO + 0x0138, | |
56 | EATASRIRM = TARO + 0x03E4, | |
57 | ||
58 | GWMC = GWRO + 0x0000, | |
59 | GWMS = GWRO + 0x0004, | |
60 | GWMTIRM = GWRO + 0x0100, | |
61 | GWVCC = GWRO + 0x0130, | |
62 | GWTTFC = GWRO + 0x0138, | |
63 | GWDCBAC0 = GWRO + 0x0194, | |
64 | GWDCBAC1 = GWRO + 0x0198, | |
65 | GWTRC = GWRO + 0x0200, | |
66 | GWARIRM = GWRO + 0x0380, | |
67 | GWDCC = GWRO + 0x0400, | |
68 | ||
69 | RRC = CARO + 0x0004, | |
70 | RCEC = CARO + 0x0008, | |
71 | RCDC = CARO + 0x000C, | |
72 | CABPIRM = CARO + 0x0140, | |
73 | ||
74 | FWPC0 = FWRO + 0x0100, | |
75 | FWPBFC = FWRO + 0x4A00, | |
76 | FWPBFCSDC = FWRO + 0x4A04, | |
77 | ||
78 | MPSM = RMRO + 0x0000, | |
79 | MPIC = RMRO + 0x0004, | |
80 | MRMAC0 = RMRO + 0x0084, | |
81 | MRMAC1 = RMRO + 0x0088, | |
82 | MRAFC = RMRO + 0x008C, | |
83 | MRSCE = RMRO + 0x0090, | |
84 | MRSCP = RMRO + 0x0094, | |
85 | MLVC = RMRO + 0x0180, | |
86 | MLBC = RMRO + 0x0188, | |
87 | MXGMIIC = RMRO + 0x0190, | |
88 | MPCH = RMRO + 0x0194, | |
89 | MANM = RMRO + 0x019C, | |
90 | MMIS0 = RMRO + 0x0210, | |
91 | MMIS1 = RMRO + 0x0220, | |
92 | }; | |
93 | ||
94 | /* COMA */ | |
95 | #define RRC_RR BIT(0) | |
96 | #define RCEC_RCE BIT(16) | |
97 | ||
98 | #define CABPIRM_BPIOG BIT(0) | |
99 | #define CABPIRM_BPR BIT(1) | |
100 | ||
101 | /* MFWD */ | |
102 | #define FWPC0(i) (FWPC0 + (i) * 0x10) | |
103 | #define FWPC0_LTHTA BIT(0) | |
104 | #define FWPC0_IP4UE BIT(3) | |
105 | #define FWPC0_IP4TE BIT(4) | |
106 | #define FWPC0_IP4OE BIT(5) | |
107 | #define FWPC0_L2SE BIT(9) | |
108 | #define FWPC0_IP4EA BIT(10) | |
109 | #define FWPC0_IPDSA BIT(12) | |
110 | #define FWPC0_IPHLA BIT(18) | |
111 | #define FWPC0_MACSDA BIT(20) | |
112 | #define FWPC0_MACHLA BIT(26) | |
113 | #define FWPC0_MACHMA BIT(27) | |
114 | #define FWPC0_VLANSA BIT(28) | |
115 | ||
116 | #define FWPC0_DEFAULT (FWPC0_LTHTA | FWPC0_IP4UE | FWPC0_IP4TE | \ | |
117 | FWPC0_IP4OE | FWPC0_L2SE | FWPC0_IP4EA | \ | |
118 | FWPC0_IPDSA | FWPC0_IPHLA | FWPC0_MACSDA | \ | |
119 | FWPC0_MACHLA | FWPC0_MACHMA | FWPC0_VLANSA) | |
120 | ||
121 | #define FWPBFC(i) (FWPBFC + (i) * 0x10) | |
122 | #define FWPBFCSDC(j, i) (FWPBFCSDC + (i) * 0x10 + (j) * 0x04) | |
123 | ||
124 | /* ETHA */ | |
125 | #define EATASRIRM_TASRIOG BIT(0) | |
126 | #define EATASRIRM_TASRR BIT(1) | |
127 | #define EATDQDC(q) (EATDQDC + (q) * 0x04) | |
128 | #define EATDQDC_DQD (0xff) | |
129 | ||
130 | /* RMAC */ | |
131 | #define MPIC_PIS_GMII 0x02 | |
132 | #define MPIC_LSC_MASK (0x07 << 3) | |
133 | #define MPIC_LSC_100 (0x01 << 3) | |
134 | #define MPIC_LSC_1000 (0x02 << 3) | |
135 | #define MPIC_LSC_2500 (0x03 << 3) | |
136 | #define MLVC_PLV BIT(16) | |
137 | #define MLVC_LVT 0x09 | |
138 | #define MMIS0_LVSS 0x02 | |
139 | ||
140 | #define MPIC_PSMCS_MASK (0x7f << 16) | |
141 | #define MPIC_PSMHT_MASK (0x06 << 24) | |
142 | #define MPIC_MDC_CLK_SET (0x06050000) | |
143 | ||
144 | #define MPSM_MFF_C45 BIT(2) | |
145 | #define MPSM_MFF_C22 0x0 | |
146 | #define MPSM_PSME BIT(0) | |
147 | ||
148 | #define MDIO_READ_C45 0x03 | |
149 | #define MDIO_WRITE_C45 0x01 | |
150 | #define MDIO_ADDR_C45 0x00 | |
151 | ||
152 | #define MDIO_READ_C22 0x02 | |
153 | #define MDIO_WRITE_C22 0x01 | |
154 | ||
155 | #define MPSM_POP_MASK (0x03 << 13) | |
156 | #define MPSM_PRA_MASK (0x1f << 8) | |
157 | #define MPSM_PDA_MASK (0x1f << 3) | |
158 | #define MPSM_PRD_MASK (0xffff << 16) | |
159 | ||
160 | /* Completion flags */ | |
161 | #define MMIS1_PAACS BIT(2) /* Address */ | |
162 | #define MMIS1_PWACS BIT(1) /* Write */ | |
163 | #define MMIS1_PRACS BIT(0) /* Read */ | |
164 | #define MMIS1_CLEAR_FLAGS 0xf | |
165 | ||
166 | /* ETHA */ | |
167 | enum rswitch_etha_mode { | |
168 | EAMC_OPC_RESET, | |
169 | EAMC_OPC_DISABLE, | |
170 | EAMC_OPC_CONFIG, | |
171 | EAMC_OPC_OPERATION, | |
172 | }; | |
173 | ||
174 | #define EAMS_OPS_MASK EAMC_OPC_OPERATION | |
175 | ||
176 | /* GWCA */ | |
177 | enum rswitch_gwca_mode { | |
178 | GWMC_OPC_RESET, | |
179 | GWMC_OPC_DISABLE, | |
180 | GWMC_OPC_CONFIG, | |
181 | GWMC_OPC_OPERATION, | |
182 | }; | |
183 | ||
184 | #define GWMS_OPS_MASK GWMC_OPC_OPERATION | |
185 | ||
186 | #define GWMTIRM_MTIOG BIT(0) | |
187 | #define GWMTIRM_MTR BIT(1) | |
188 | #define GWARIRM_ARIOG BIT(0) | |
189 | #define GWARIRM_ARR BIT(1) | |
190 | #define GWVCC_VEM_SC_TAG (0x3 << 16) | |
191 | #define GWDCBAC0_DCBAUP (0xff) | |
192 | #define GWTRC(i) (GWTRC + (i) * 0x04) | |
193 | #define GWDCC(i) (GWDCC + (i) * 0x04) | |
194 | #define GWDCC_DQT BIT(11) | |
195 | #define GWDCC_BALR BIT(24) | |
196 | ||
197 | struct rswitch_etha { | |
198 | int index; | |
199 | void __iomem *addr; | |
200 | struct phy_device *phydev; | |
201 | struct mii_dev *bus; | |
202 | unsigned char *enetaddr; | |
203 | }; | |
204 | ||
205 | struct rswitch_gwca { | |
206 | int index; | |
207 | void __iomem *addr; | |
208 | int num_chain; | |
209 | }; | |
210 | ||
211 | /* Setting value */ | |
212 | #define LINK_SPEED_100 100 | |
213 | #define LINK_SPEED_1000 1000 | |
214 | #define LINK_SPEED_2500 2500 | |
215 | ||
216 | /* Decriptor */ | |
217 | #define RSWITCH_NUM_BASE_DESC 2 | |
218 | #define RSWITCH_TX_CHAIN_INDEX 0 | |
219 | #define RSWITCH_RX_CHAIN_INDEX 1 | |
220 | #define RSWITCH_NUM_TX_DESC 8 | |
221 | #define RSWITCH_NUM_RX_DESC 8 | |
222 | ||
223 | enum RX_DS_CC_BIT { | |
224 | RX_DS = 0x0fff, /* Data size */ | |
225 | RX_TR = 0x1000, /* Truncation indication */ | |
226 | RX_EI = 0x2000, /* Error indication */ | |
227 | RX_PS = 0xc000, /* Padding selection */ | |
228 | }; | |
229 | ||
230 | enum DIE_DT { | |
231 | /* Frame data */ | |
232 | DT_FSINGLE = 0x80, | |
233 | DT_FSTART = 0x90, | |
234 | DT_FMID = 0xa0, | |
235 | DT_FEND = 0xb8, | |
236 | ||
237 | /* Chain control */ | |
238 | DT_LEMPTY = 0xc0, | |
239 | DT_EEMPTY = 0xd0, | |
240 | DT_LINKFIX = 0x00, | |
241 | DT_LINK = 0xe0, | |
242 | DT_EOS = 0xf0, | |
243 | /* HW/SW arbitration */ | |
244 | DT_FEMPTY = 0x40, | |
245 | DT_FEMPTY_IS = 0x10, | |
246 | DT_FEMPTY_IC = 0x20, | |
247 | DT_FEMPTY_ND = 0x38, | |
248 | DT_FEMPTY_START = 0x50, | |
249 | DT_FEMPTY_MID = 0x60, | |
250 | DT_FEMPTY_END = 0x70, | |
251 | ||
252 | DT_MASK = 0xf0, | |
253 | DIE = 0x08, /* Descriptor Interrupt Enable */ | |
254 | }; | |
255 | ||
256 | struct rswitch_desc { | |
257 | __le16 info_ds; /* Descriptor size */ | |
258 | u8 die_dt; /* Descriptor interrupt enable and type */ | |
259 | __u8 dptrh; /* Descriptor pointer MSB */ | |
260 | __le32 dptrl; /* Descriptor pointer LSW */ | |
261 | } __packed; | |
262 | ||
263 | struct rswitch_rxdesc { | |
264 | struct rswitch_desc data; | |
265 | struct rswitch_desc link; | |
266 | u8 __pad[48]; | |
267 | u8 packet[PKTSIZE_ALIGN]; | |
268 | } __packed; | |
269 | ||
270 | struct rswitch_port_priv { | |
271 | void __iomem *addr; | |
272 | struct phy serdes; | |
273 | struct rswitch_etha etha; | |
274 | struct rswitch_gwca gwca; | |
275 | struct rswitch_desc bat_desc[RSWITCH_NUM_BASE_DESC]; | |
276 | struct rswitch_desc tx_desc[RSWITCH_NUM_TX_DESC]; | |
277 | struct rswitch_rxdesc rx_desc[RSWITCH_NUM_RX_DESC]; | |
278 | u32 rx_desc_index; | |
279 | u32 tx_desc_index; | |
280 | }; | |
281 | ||
282 | struct rswitch_priv { | |
283 | void __iomem *addr; | |
284 | struct clk *rsw_clk; | |
285 | }; | |
286 | ||
287 | static inline void rswitch_flush_dcache(u32 addr, u32 len) | |
288 | { | |
289 | flush_dcache_range(addr, addr + len); | |
290 | } | |
291 | ||
292 | static inline void rswitch_invalidate_dcache(u32 addr, u32 len) | |
293 | { | |
294 | u32 start = addr & ~((uintptr_t)ARCH_DMA_MINALIGN - 1); | |
295 | u32 end = roundup(addr + len, ARCH_DMA_MINALIGN); | |
296 | ||
297 | invalidate_dcache_range(start, end); | |
298 | } | |
299 | ||
300 | static void rswitch_agent_clock_ctrl(struct rswitch_port_priv *priv, int port, int enable) | |
301 | { | |
302 | u32 val; | |
303 | ||
304 | if (enable) { | |
305 | val = readl(priv->addr + RCEC); | |
306 | if ((val & (RCEC_RCE | BIT(port))) != (RCEC_RCE | BIT(port))) | |
307 | writel(val | RCEC_RCE | BIT(port), priv->addr + RCEC); | |
308 | } else { | |
309 | setbits_le32(priv->addr + RCDC, BIT(port)); | |
310 | } | |
311 | } | |
312 | ||
313 | static int rswitch_etha_change_mode(struct rswitch_port_priv *priv, | |
314 | enum rswitch_etha_mode mode) | |
315 | { | |
316 | struct rswitch_etha *etha = &priv->etha; | |
317 | u32 pval; | |
318 | int ret; | |
319 | ||
320 | /* Enable clock */ | |
321 | rswitch_agent_clock_ctrl(priv, etha->index, 1); | |
322 | ||
323 | writel(mode, etha->addr + EAMC); | |
324 | ||
325 | ret = readl_poll_sleep_timeout(etha->addr + EAMS, pval, | |
326 | (pval & EAMS_OPS_MASK) == mode, | |
327 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
328 | ||
329 | /* Disable clock */ | |
330 | if (mode == EAMC_OPC_DISABLE) | |
331 | rswitch_agent_clock_ctrl(priv, etha->index, 0); | |
332 | ||
333 | return ret; | |
334 | } | |
335 | ||
336 | static int rswitch_gwca_change_mode(struct rswitch_port_priv *priv, | |
337 | enum rswitch_gwca_mode mode) | |
338 | { | |
339 | struct rswitch_gwca *gwca = &priv->gwca; | |
340 | u32 pval; | |
341 | int ret; | |
342 | ||
343 | /* Enable clock */ | |
344 | rswitch_agent_clock_ctrl(priv, gwca->index, 1); | |
345 | ||
346 | writel(mode, gwca->addr + GWMC); | |
347 | ||
348 | ret = readl_poll_sleep_timeout(gwca->addr + GWMS, pval, | |
349 | (pval & GWMS_OPS_MASK) == mode, | |
350 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
351 | ||
352 | /* Disable clock */ | |
353 | if (mode == GWMC_OPC_DISABLE) | |
354 | rswitch_agent_clock_ctrl(priv, gwca->index, 0); | |
355 | ||
356 | return ret; | |
357 | } | |
358 | ||
359 | static int rswitch_mii_access_c45(struct rswitch_etha *etha, bool read, | |
360 | int phyad, int devad, int regad, int data) | |
361 | { | |
362 | u32 pval, val; | |
363 | int ret; | |
364 | ||
365 | /* No match device */ | |
366 | if (devad == 0xffffffff) | |
367 | return 0; | |
368 | ||
369 | /* Clear completion flags */ | |
370 | writel(MMIS1_CLEAR_FLAGS, etha->addr + MMIS1); | |
371 | ||
372 | /* Submit address to PHY (MDIO_ADDR_C45 << 13) */ | |
373 | val = MPSM_PSME | MPSM_MFF_C45 | (devad << 8) | (phyad << 3); | |
374 | writel((regad << 16) | val, etha->addr + MPSM); | |
375 | ||
376 | ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval, | |
377 | pval & MMIS1_PAACS, | |
378 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
379 | if (ret) | |
380 | return ret; | |
381 | ||
382 | /* Clear address completion flag */ | |
383 | setbits_le32(etha->addr + MMIS1, MMIS1_PAACS); | |
384 | ||
385 | /* Read/Write PHY register */ | |
386 | if (read) { | |
387 | val |= MDIO_READ_C45 << 13; | |
388 | writel(val, etha->addr + MPSM); | |
389 | ||
390 | ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval, | |
391 | pval & MMIS1_PRACS, | |
392 | RSWITCH_SLEEP_US, | |
393 | RSWITCH_TIMEOUT_US); | |
394 | if (ret) | |
395 | return ret; | |
396 | ||
397 | /* Read data */ | |
398 | ret = (readl(etha->addr + MPSM) & MPSM_PRD_MASK) >> 16; | |
399 | ||
400 | /* Clear read completion flag */ | |
401 | setbits_le32(etha->addr + MMIS1, MMIS1_PRACS); | |
402 | } else { | |
403 | val |= MDIO_WRITE_C45 << 13; | |
404 | val |= data << 16; | |
405 | writel(val, etha->addr + MPSM); | |
406 | ||
407 | ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval, | |
408 | pval & MMIS1_PWACS, | |
409 | RSWITCH_SLEEP_US, | |
410 | RSWITCH_TIMEOUT_US); | |
411 | } | |
412 | ||
413 | return ret; | |
414 | } | |
415 | ||
416 | static int rswitch_mii_read_c45(struct mii_dev *miidev, int phyad, int devad, int regad) | |
417 | { | |
418 | struct rswitch_port_priv *priv = miidev->priv; | |
419 | struct rswitch_etha *etha = &priv->etha; | |
420 | int val; | |
421 | int reg; | |
422 | ||
423 | /* Change to disable mode */ | |
424 | rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); | |
425 | ||
426 | /* Change to config mode */ | |
427 | rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG); | |
428 | ||
429 | /* Enable Station Management clock */ | |
430 | reg = readl(etha->addr + MPIC); | |
431 | reg &= ~MPIC_PSMCS_MASK & ~MPIC_PSMHT_MASK; | |
432 | writel(reg | MPIC_MDC_CLK_SET, etha->addr + MPIC); | |
433 | ||
434 | /* Set Station Management Mode : Clause 45 */ | |
435 | setbits_le32(etha->addr + MPSM, MPSM_MFF_C45); | |
436 | ||
437 | /* Access PHY register */ | |
438 | val = rswitch_mii_access_c45(etha, true, phyad, devad, regad, 0); | |
439 | ||
440 | /* Disable Station Management Clock */ | |
441 | clrbits_le32(etha->addr + MPIC, MPIC_PSMCS_MASK); | |
442 | ||
443 | /* Change to disable mode */ | |
444 | rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); | |
445 | ||
446 | return val; | |
447 | } | |
448 | ||
449 | int rswitch_mii_write_c45(struct mii_dev *miidev, int phyad, int devad, int regad, u16 data) | |
450 | { | |
451 | struct rswitch_port_priv *priv = miidev->priv; | |
452 | struct rswitch_etha *etha = &priv->etha; | |
453 | int reg; | |
454 | ||
455 | /* Change to disable mode */ | |
456 | rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); | |
457 | ||
458 | /* Change to config mode */ | |
459 | rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG); | |
460 | ||
461 | /* Enable Station Management clock */ | |
462 | reg = readl(etha->addr + MPIC); | |
463 | reg &= ~MPIC_PSMCS_MASK & ~MPIC_PSMHT_MASK; | |
464 | writel(reg | MPIC_MDC_CLK_SET, etha->addr + MPIC); | |
465 | ||
466 | /* Set Station Management Mode : Clause 45 */ | |
467 | setbits_le32(etha->addr + MPSM, MPSM_MFF_C45); | |
468 | ||
469 | /* Access PHY register */ | |
470 | rswitch_mii_access_c45(etha, false, phyad, devad, regad, data); | |
471 | ||
472 | /* Disable Station Management Clock */ | |
473 | clrbits_le32(etha->addr + MPIC, MPIC_PSMCS_MASK); | |
474 | ||
475 | /* Change to disable mode */ | |
476 | rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); | |
477 | ||
478 | return 0; | |
479 | } | |
480 | ||
481 | static int rswitch_check_link(struct rswitch_etha *etha) | |
482 | { | |
483 | u32 pval; | |
484 | int ret; | |
485 | ||
486 | /* Request Link Verification */ | |
487 | writel(MLVC_PLV, etha->addr + MLVC); | |
488 | ||
489 | /* Complete Link Verification */ | |
490 | ret = readl_poll_sleep_timeout(etha->addr + MLVC, pval, | |
491 | !(pval & MLVC_PLV), | |
492 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
493 | if (ret) { | |
494 | debug("\n%s: Link verification timeout!", __func__); | |
495 | return ret; | |
496 | } | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
501 | static int rswitch_reset(struct rswitch_port_priv *priv) | |
502 | { | |
503 | int ret; | |
504 | ||
505 | setbits_le32(priv->addr + RRC, RRC_RR); | |
506 | clrbits_le32(priv->addr + RRC, RRC_RR); | |
507 | ||
508 | ret = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE); | |
509 | if (ret) | |
510 | return ret; | |
511 | ||
512 | ret = rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); | |
513 | if (ret) | |
514 | return ret; | |
515 | ||
516 | return 0; | |
517 | } | |
518 | ||
519 | static void rswitch_bat_desc_init(struct rswitch_port_priv *priv) | |
520 | { | |
521 | const u32 desc_size = RSWITCH_NUM_BASE_DESC * sizeof(struct rswitch_desc); | |
522 | int i; | |
523 | ||
524 | /* Initialize all descriptors */ | |
525 | memset(priv->bat_desc, 0x0, desc_size); | |
526 | ||
527 | for (i = 0; i < RSWITCH_NUM_BASE_DESC; i++) | |
528 | priv->bat_desc[i].die_dt = DT_EOS; | |
529 | ||
530 | rswitch_flush_dcache((uintptr_t)priv->bat_desc, desc_size); | |
531 | } | |
532 | ||
533 | static void rswitch_tx_desc_init(struct rswitch_port_priv *priv) | |
534 | { | |
535 | const u32 desc_size = RSWITCH_NUM_TX_DESC * sizeof(struct rswitch_desc); | |
536 | u64 tx_desc_addr; | |
537 | int i; | |
538 | ||
539 | /* Initialize all descriptor */ | |
540 | memset(priv->tx_desc, 0x0, desc_size); | |
541 | priv->tx_desc_index = 0; | |
542 | ||
543 | for (i = 0; i < RSWITCH_NUM_TX_DESC; i++) | |
544 | priv->tx_desc[i].die_dt = DT_EEMPTY; | |
545 | ||
546 | /* Mark the end of the descriptors */ | |
547 | priv->tx_desc[RSWITCH_NUM_TX_DESC - 1].die_dt = DT_LINKFIX; | |
548 | tx_desc_addr = (uintptr_t)priv->tx_desc; | |
549 | priv->tx_desc[RSWITCH_NUM_TX_DESC - 1].dptrl = lower_32_bits(tx_desc_addr); | |
550 | priv->tx_desc[RSWITCH_NUM_TX_DESC - 1].dptrh = upper_32_bits(tx_desc_addr); | |
551 | rswitch_flush_dcache(tx_desc_addr, desc_size); | |
552 | ||
553 | /* Point the controller to the TX descriptor list */ | |
554 | priv->bat_desc[RSWITCH_TX_CHAIN_INDEX].die_dt = DT_LINKFIX; | |
555 | priv->bat_desc[RSWITCH_TX_CHAIN_INDEX].dptrl = lower_32_bits(tx_desc_addr); | |
556 | priv->bat_desc[RSWITCH_TX_CHAIN_INDEX].dptrh = upper_32_bits(tx_desc_addr); | |
557 | rswitch_flush_dcache((uintptr_t)&priv->bat_desc[RSWITCH_TX_CHAIN_INDEX], | |
558 | sizeof(struct rswitch_desc)); | |
559 | } | |
560 | ||
561 | static void rswitch_rx_desc_init(struct rswitch_port_priv *priv) | |
562 | { | |
563 | const u32 desc_size = RSWITCH_NUM_RX_DESC * sizeof(struct rswitch_rxdesc); | |
564 | int i; | |
565 | u64 packet_addr; | |
566 | u64 next_rx_desc_addr; | |
567 | u64 rx_desc_addr; | |
568 | ||
569 | /* Initialize all descriptor */ | |
570 | memset(priv->rx_desc, 0x0, desc_size); | |
571 | priv->rx_desc_index = 0; | |
572 | ||
573 | for (i = 0; i < RSWITCH_NUM_RX_DESC; i++) { | |
574 | priv->rx_desc[i].data.die_dt = DT_EEMPTY; | |
575 | priv->rx_desc[i].data.info_ds = PKTSIZE_ALIGN; | |
576 | packet_addr = (uintptr_t)priv->rx_desc[i].packet; | |
577 | priv->rx_desc[i].data.dptrl = lower_32_bits(packet_addr); | |
578 | priv->rx_desc[i].data.dptrh = upper_32_bits(packet_addr); | |
579 | ||
580 | priv->rx_desc[i].link.die_dt = DT_LINKFIX; | |
581 | next_rx_desc_addr = (uintptr_t)&priv->rx_desc[i + 1]; | |
582 | priv->rx_desc[i].link.dptrl = lower_32_bits(next_rx_desc_addr); | |
583 | priv->rx_desc[i].link.dptrh = upper_32_bits(next_rx_desc_addr); | |
584 | } | |
585 | ||
586 | /* Mark the end of the descriptors */ | |
587 | priv->rx_desc[RSWITCH_NUM_RX_DESC - 1].link.die_dt = DT_LINKFIX; | |
588 | rx_desc_addr = (uintptr_t)priv->rx_desc; | |
589 | priv->rx_desc[RSWITCH_NUM_RX_DESC - 1].link.dptrl = lower_32_bits(rx_desc_addr); | |
590 | priv->rx_desc[RSWITCH_NUM_RX_DESC - 1].link.dptrh = upper_32_bits(rx_desc_addr); | |
591 | rswitch_flush_dcache(rx_desc_addr, desc_size); | |
592 | ||
593 | /* Point the controller to the rx descriptor list */ | |
594 | priv->bat_desc[RSWITCH_RX_CHAIN_INDEX].die_dt = DT_LINKFIX; | |
595 | priv->bat_desc[RSWITCH_RX_CHAIN_INDEX].dptrl = lower_32_bits(rx_desc_addr); | |
596 | priv->bat_desc[RSWITCH_RX_CHAIN_INDEX].dptrh = upper_32_bits(rx_desc_addr); | |
597 | rswitch_flush_dcache((uintptr_t)&priv->bat_desc[RSWITCH_RX_CHAIN_INDEX], | |
598 | sizeof(struct rswitch_desc)); | |
599 | } | |
600 | ||
601 | static void rswitch_clock_enable(struct rswitch_port_priv *priv) | |
602 | { | |
603 | struct rswitch_etha *etha = &priv->etha; | |
604 | struct rswitch_gwca *gwca = &priv->gwca; | |
605 | ||
606 | setbits_le32(priv->addr + RCEC, BIT(etha->index) | BIT(gwca->index) | RCEC_RCE); | |
607 | } | |
608 | ||
609 | static int rswitch_bpool_init(struct rswitch_port_priv *priv) | |
610 | { | |
611 | u32 pval; | |
612 | ||
613 | writel(CABPIRM_BPIOG, priv->addr + CABPIRM); | |
614 | ||
615 | return readl_poll_sleep_timeout(priv->addr + CABPIRM, pval, | |
616 | pval & CABPIRM_BPR, | |
617 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
618 | } | |
619 | ||
620 | static void rswitch_mfwd_init(struct rswitch_port_priv *priv) | |
621 | { | |
622 | struct rswitch_etha *etha = &priv->etha; | |
623 | struct rswitch_gwca *gwca = &priv->gwca; | |
624 | ||
625 | writel(FWPC0_DEFAULT, priv->addr + FWPC0(etha->index)); | |
626 | writel(FWPC0_DEFAULT, priv->addr + FWPC0(gwca->index)); | |
627 | ||
628 | writel(RSWITCH_RX_CHAIN_INDEX, | |
629 | priv->addr + FWPBFCSDC(HW_INDEX_TO_GWCA(gwca->index), etha->index)); | |
630 | ||
631 | writel(BIT(gwca->index), | |
632 | priv->addr + FWPBFC(etha->index)); | |
633 | ||
634 | writel(BIT(etha->index), | |
635 | priv->addr + FWPBFC(gwca->index)); | |
636 | } | |
637 | ||
638 | static void rswitch_rmac_init(struct rswitch_etha *etha) | |
639 | { | |
640 | unsigned char *mac = etha->enetaddr; | |
641 | ||
642 | /* Set MAC address */ | |
643 | writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], | |
644 | etha->addr + MRMAC1); | |
645 | ||
646 | writel((mac[0] << 8) | mac[1], etha->addr + MRMAC0); | |
647 | ||
648 | /* Set MIIx */ | |
649 | writel(MPIC_PIS_GMII | MPIC_LSC_1000, etha->addr + MPIC); | |
650 | ||
651 | writel(0x07E707E7, etha->addr + MRAFC); | |
652 | } | |
653 | ||
654 | static int rswitch_gwca_mcast_table_reset(struct rswitch_gwca *gwca) | |
655 | { | |
656 | u32 pval; | |
657 | ||
658 | writel(GWMTIRM_MTIOG, gwca->addr + GWMTIRM); | |
659 | ||
660 | return readl_poll_sleep_timeout(gwca->addr + GWMTIRM, pval, | |
661 | pval & GWMTIRM_MTR, | |
662 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
663 | } | |
664 | ||
665 | static int rswitch_gwca_axi_ram_reset(struct rswitch_gwca *gwca) | |
666 | { | |
667 | u32 pval; | |
668 | ||
669 | writel(GWARIRM_ARIOG, gwca->addr + GWARIRM); | |
670 | ||
671 | return readl_poll_sleep_timeout(gwca->addr + GWARIRM, pval, | |
672 | pval & GWARIRM_ARR, | |
673 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
674 | } | |
675 | ||
676 | static int rswitch_gwca_init(struct rswitch_port_priv *priv) | |
677 | { | |
678 | struct rswitch_gwca *gwca = &priv->gwca; | |
679 | int ret; | |
680 | ||
681 | ret = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE); | |
682 | if (ret) | |
683 | return ret; | |
684 | ||
685 | ret = rswitch_gwca_change_mode(priv, GWMC_OPC_CONFIG); | |
686 | if (ret) | |
687 | return ret; | |
688 | ||
689 | ret = rswitch_gwca_mcast_table_reset(gwca); | |
690 | if (ret) | |
691 | return ret; | |
692 | ||
693 | ret = rswitch_gwca_axi_ram_reset(gwca); | |
694 | if (ret) | |
695 | return ret; | |
696 | ||
697 | /* Setting flow */ | |
698 | writel(GWVCC_VEM_SC_TAG, gwca->addr + GWVCC); | |
699 | writel(0, gwca->addr + GWTTFC); | |
700 | writel(upper_32_bits((uintptr_t)priv->bat_desc) & GWDCBAC0_DCBAUP, gwca->addr + GWDCBAC0); | |
701 | writel(lower_32_bits((uintptr_t)priv->bat_desc), gwca->addr + GWDCBAC1); | |
702 | writel(GWDCC_DQT | GWDCC_BALR, gwca->addr + GWDCC(RSWITCH_TX_CHAIN_INDEX)); | |
703 | writel(GWDCC_BALR, gwca->addr + GWDCC(RSWITCH_RX_CHAIN_INDEX)); | |
704 | ||
705 | ret = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE); | |
706 | if (ret) | |
707 | return ret; | |
708 | ||
709 | ret = rswitch_gwca_change_mode(priv, GWMC_OPC_OPERATION); | |
710 | if (ret) | |
711 | return ret; | |
712 | ||
713 | return 0; | |
714 | } | |
715 | ||
716 | static int rswitch_etha_tas_ram_reset(struct rswitch_etha *etha) | |
717 | { | |
718 | u32 pval; | |
719 | ||
720 | writel(EATASRIRM_TASRIOG, etha->addr + EATASRIRM); | |
721 | ||
722 | return readl_poll_sleep_timeout(etha->addr + EATASRIRM, pval, | |
723 | pval & EATASRIRM_TASRR, | |
724 | RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); | |
725 | } | |
726 | ||
727 | static int rswitch_etha_init(struct rswitch_port_priv *priv) | |
728 | { | |
729 | struct rswitch_etha *etha = &priv->etha; | |
730 | int ret; | |
731 | u32 prio; | |
732 | ||
733 | ret = rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); | |
734 | if (ret) | |
735 | return ret; | |
736 | ||
737 | ret = rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG); | |
738 | if (ret) | |
739 | return ret; | |
740 | ||
741 | ret = rswitch_etha_tas_ram_reset(etha); | |
742 | if (ret) | |
743 | return ret; | |
744 | ||
745 | /* Setting flow */ | |
746 | writel(0, etha->addr + EATTFC); | |
747 | ||
748 | for (prio = 0; prio < RSWITCH_MAX_CTAG_PCP; prio++) | |
749 | writel(EATDQDC_DQD, etha->addr + EATDQDC(prio)); | |
750 | ||
751 | rswitch_rmac_init(etha); | |
752 | ||
753 | ret = rswitch_etha_change_mode(priv, EAMC_OPC_OPERATION); | |
754 | if (ret) | |
755 | return ret; | |
756 | ||
757 | /* Link Verification */ | |
758 | ret = rswitch_check_link(etha); | |
759 | if (ret) | |
760 | return ret; | |
761 | ||
762 | return 0; | |
763 | } | |
764 | ||
765 | static int rswitch_init(struct rswitch_port_priv *priv) | |
766 | { | |
767 | struct rswitch_etha *etha = &priv->etha; | |
768 | int ret; | |
769 | ||
770 | ret = rswitch_reset(priv); | |
771 | if (ret) | |
772 | return ret; | |
773 | ||
774 | ret = generic_phy_set_mode(&priv->serdes, PHY_MODE_ETHERNET, | |
775 | etha->phydev->interface); | |
776 | if (ret) | |
777 | return ret; | |
778 | ||
779 | ret = generic_phy_set_speed(&priv->serdes, etha->phydev->speed); | |
780 | if (ret) | |
781 | return ret; | |
782 | ||
783 | ret = generic_phy_init(&priv->serdes); | |
784 | if (ret) | |
785 | return ret; | |
786 | ||
787 | ret = generic_phy_power_on(&priv->serdes); | |
788 | if (ret) | |
789 | return ret; | |
790 | ||
791 | ret = phy_startup(etha->phydev); | |
792 | if (ret) | |
793 | return ret; | |
794 | ||
795 | rswitch_bat_desc_init(priv); | |
796 | rswitch_tx_desc_init(priv); | |
797 | rswitch_rx_desc_init(priv); | |
798 | ||
799 | rswitch_clock_enable(priv); | |
800 | ||
801 | ret = rswitch_bpool_init(priv); | |
802 | if (ret) | |
803 | return ret; | |
804 | ||
805 | rswitch_mfwd_init(priv); | |
806 | ||
807 | ret = rswitch_gwca_init(priv); | |
808 | if (ret) | |
809 | return ret; | |
810 | ||
811 | ret = rswitch_etha_init(priv); | |
812 | if (ret) | |
813 | return ret; | |
814 | ||
815 | return 0; | |
816 | } | |
817 | ||
818 | static int rswitch_start(struct udevice *dev) | |
819 | { | |
820 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
821 | int ret; | |
822 | ||
823 | ret = rswitch_init(priv); | |
824 | if (ret) | |
825 | return ret; | |
826 | ||
827 | return 0; | |
828 | } | |
829 | ||
830 | #define RSWITCH_TX_TIMEOUT_MS 1000 | |
831 | static int rswitch_send(struct udevice *dev, void *packet, int len) | |
832 | { | |
833 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
834 | struct rswitch_desc *desc = &priv->tx_desc[priv->tx_desc_index]; | |
835 | struct rswitch_gwca *gwca = &priv->gwca; | |
836 | u32 gwtrc_index, start; | |
837 | ||
838 | /* Update TX descriptor */ | |
839 | rswitch_flush_dcache((uintptr_t)packet, len); | |
840 | memset(desc, 0x0, sizeof(*desc)); | |
841 | desc->die_dt = DT_FSINGLE; | |
842 | desc->info_ds = len; | |
843 | desc->dptrl = lower_32_bits((uintptr_t)packet); | |
844 | desc->dptrh = upper_32_bits((uintptr_t)packet); | |
845 | rswitch_flush_dcache((uintptr_t)desc, sizeof(*desc)); | |
846 | ||
847 | /* Start transmission */ | |
848 | gwtrc_index = RSWITCH_TX_CHAIN_INDEX / 32; | |
849 | setbits_le32(gwca->addr + GWTRC(gwtrc_index), BIT(RSWITCH_TX_CHAIN_INDEX)); | |
850 | ||
851 | /* Wait until packet is transmitted */ | |
852 | start = get_timer(0); | |
853 | while (get_timer(start) < RSWITCH_TX_TIMEOUT_MS) { | |
854 | rswitch_invalidate_dcache((uintptr_t)desc, sizeof(*desc)); | |
855 | if ((desc->die_dt & DT_MASK) != DT_FSINGLE) | |
856 | break; | |
857 | udelay(10); | |
858 | } | |
859 | ||
860 | if (get_timer(start) >= RSWITCH_TX_TIMEOUT_MS) { | |
861 | dev_dbg(dev, "\n%s: Timeout", __func__); | |
862 | return -ETIMEDOUT; | |
863 | } | |
864 | ||
865 | priv->tx_desc_index = (priv->tx_desc_index + 1) % (RSWITCH_NUM_TX_DESC - 1); | |
866 | ||
867 | return 0; | |
868 | } | |
869 | ||
870 | static int rswitch_recv(struct udevice *dev, int flags, uchar **packetp) | |
871 | { | |
872 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
873 | struct rswitch_rxdesc *desc = &priv->rx_desc[priv->rx_desc_index]; | |
874 | u8 *packet; | |
875 | int len; | |
876 | ||
877 | /* Check if the rx descriptor is ready */ | |
878 | rswitch_invalidate_dcache((uintptr_t)desc, sizeof(*desc)); | |
879 | if ((desc->data.die_dt & DT_MASK) == DT_FEMPTY) | |
880 | return -EAGAIN; | |
881 | ||
882 | len = desc->data.info_ds & RX_DS; | |
883 | packet = (u8 *)(((uintptr_t)(desc->data.dptrh) << 32) | (uintptr_t)desc->data.dptrl); | |
884 | rswitch_invalidate_dcache((uintptr_t)packet, len); | |
885 | ||
886 | *packetp = packet; | |
887 | ||
888 | return len; | |
889 | } | |
890 | ||
891 | static int rswitch_free_pkt(struct udevice *dev, uchar *packet, int length) | |
892 | { | |
893 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
894 | struct rswitch_rxdesc *desc = &priv->rx_desc[priv->rx_desc_index]; | |
895 | ||
896 | /* Make current descritor available again */ | |
897 | desc->data.die_dt = DT_FEMPTY; | |
898 | desc->data.info_ds = PKTSIZE_ALIGN; | |
899 | rswitch_flush_dcache((uintptr_t)desc, sizeof(*desc)); | |
900 | ||
901 | /* Point to the next descriptor */ | |
902 | priv->rx_desc_index = (priv->rx_desc_index + 1) % RSWITCH_NUM_RX_DESC; | |
903 | desc = &priv->rx_desc[priv->rx_desc_index]; | |
904 | rswitch_invalidate_dcache((uintptr_t)desc, sizeof(*desc)); | |
905 | ||
906 | return 0; | |
907 | } | |
908 | ||
909 | static void rswitch_stop(struct udevice *dev) | |
910 | { | |
911 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
912 | ||
913 | phy_shutdown(priv->etha.phydev); | |
914 | ||
915 | generic_phy_power_off(&priv->serdes); | |
916 | } | |
917 | ||
918 | static int rswitch_write_hwaddr(struct udevice *dev) | |
919 | { | |
920 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
921 | struct rswitch_etha *etha = &priv->etha; | |
922 | struct eth_pdata *pdata = dev_get_plat(dev); | |
923 | unsigned char *mac = pdata->enetaddr; | |
924 | ||
925 | writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], | |
926 | etha->addr + MRMAC1); | |
927 | ||
928 | writel((mac[0] << 8) | mac[1], etha->addr + MRMAC0); | |
929 | ||
930 | return 0; | |
931 | } | |
932 | ||
933 | static int rswitch_phy_config(struct udevice *dev) | |
934 | { | |
935 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
936 | struct rswitch_etha *etha = &priv->etha; | |
937 | struct eth_pdata *pdata = dev_get_plat(dev); | |
938 | struct phy_device *phydev; | |
939 | int phy_addr; | |
940 | ||
941 | phy_addr = eth_phy_get_addr(dev); | |
942 | if (phy_addr < 0) | |
943 | return phy_addr; | |
944 | ||
945 | phydev = phy_connect(etha->bus, phy_addr, dev, pdata->phy_interface); | |
946 | if (!phydev) | |
947 | return -ENODEV; | |
948 | ||
949 | etha->phydev = phydev; | |
950 | phydev->speed = SPEED_1000; | |
951 | ||
952 | phy_config(phydev); | |
953 | ||
954 | return 0; | |
955 | } | |
956 | ||
957 | static int rswitch_port_probe(struct udevice *dev) | |
958 | { | |
959 | struct rswitch_priv *rpriv = | |
960 | (struct rswitch_priv *)dev_get_driver_data(dev); | |
961 | struct eth_pdata *pdata = dev_get_plat(dev); | |
962 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
963 | struct rswitch_etha *etha = &priv->etha; | |
964 | struct rswitch_gwca *gwca = &priv->gwca; | |
965 | struct mii_dev *mdiodev; | |
966 | int ret; | |
967 | ||
968 | priv->addr = rpriv->addr; | |
969 | ||
970 | etha->enetaddr = pdata->enetaddr; | |
971 | ||
972 | etha->index = dev_read_u32_default(dev, "reg", 0); | |
973 | etha->addr = priv->addr + RSWITCH_ETHA_OFFSET + etha->index * RSWITCH_ETHA_SIZE; | |
974 | ||
975 | gwca->index = 1; | |
976 | gwca->addr = priv->addr + RSWITCH_GWCA_OFFSET + gwca->index * RSWITCH_GWCA_SIZE; | |
977 | gwca->index = GWCA_TO_HW_INDEX(gwca->index); | |
978 | ||
979 | ret = generic_phy_get_by_index(dev, 0, &priv->serdes); | |
980 | if (ret) | |
981 | return ret; | |
982 | ||
983 | /* Toggle the reset so we can access the PHYs */ | |
984 | ret = rswitch_reset(priv); | |
985 | if (ret) | |
986 | return ret; | |
987 | ||
988 | mdiodev = mdio_alloc(); | |
989 | if (!mdiodev) | |
990 | return -ENOMEM; | |
991 | ||
992 | mdiodev->priv = priv; | |
993 | mdiodev->read = rswitch_mii_read_c45; | |
994 | mdiodev->write = rswitch_mii_write_c45; | |
995 | snprintf(mdiodev->name, sizeof(mdiodev->name), dev->name); | |
996 | ||
997 | ret = mdio_register(mdiodev); | |
998 | if (ret) | |
999 | goto err_mdio_register; | |
1000 | ||
1001 | priv->etha.bus = miiphy_get_dev_by_name(dev->name); | |
1002 | ||
1003 | ret = rswitch_phy_config(dev); | |
1004 | if (ret) | |
1005 | goto err_mdio_register; | |
1006 | ||
1007 | return 0; | |
1008 | ||
1009 | err_mdio_register: | |
1010 | mdio_free(mdiodev); | |
1011 | return ret; | |
1012 | } | |
1013 | ||
1014 | static int rswitch_port_remove(struct udevice *dev) | |
1015 | { | |
1016 | struct rswitch_port_priv *priv = dev_get_priv(dev); | |
1017 | ||
1018 | mdio_unregister(priv->etha.bus); | |
1019 | free(priv->etha.phydev); | |
1020 | ||
1021 | return 0; | |
1022 | } | |
1023 | ||
1024 | int rswitch_ofdata_to_platdata(struct udevice *dev) | |
1025 | { | |
1026 | struct eth_pdata *pdata = dev_get_plat(dev); | |
1027 | ||
1028 | pdata->phy_interface = dev_read_phy_mode(dev); | |
1029 | if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) | |
1030 | return -EINVAL; | |
1031 | ||
1032 | pdata->max_speed = dev_read_u32_default(dev, "max-speed", 1000); | |
1033 | ||
1034 | return 0; | |
1035 | } | |
1036 | ||
1037 | static const struct eth_ops rswitch_port_ops = { | |
1038 | .start = rswitch_start, | |
1039 | .send = rswitch_send, | |
1040 | .recv = rswitch_recv, | |
1041 | .free_pkt = rswitch_free_pkt, | |
1042 | .stop = rswitch_stop, | |
1043 | .write_hwaddr = rswitch_write_hwaddr, | |
1044 | }; | |
1045 | ||
1046 | U_BOOT_DRIVER(rswitch_port) = { | |
1047 | .name = "rswitch-port", | |
1048 | .id = UCLASS_ETH, | |
1049 | .of_to_plat = rswitch_ofdata_to_platdata, | |
1050 | .probe = rswitch_port_probe, | |
1051 | .remove = rswitch_port_remove, | |
1052 | .ops = &rswitch_port_ops, | |
1053 | .priv_auto = sizeof(struct rswitch_port_priv), | |
1054 | .plat_auto = sizeof(struct eth_pdata), | |
1055 | .flags = DM_FLAG_ALLOC_PRIV_DMA | DM_FLAG_OS_PREPARE, | |
1056 | }; | |
1057 | ||
1058 | static int rswitch_probe(struct udevice *dev) | |
1059 | { | |
1060 | struct rswitch_priv *priv = dev_get_plat(dev); | |
1061 | fdt_addr_t secure_base; | |
1062 | fdt_size_t size; | |
1063 | int ret; | |
1064 | ||
1065 | secure_base = dev_read_addr_size_name(dev, "secure_base", &size); | |
1066 | if (!secure_base) | |
1067 | return -EINVAL; | |
1068 | ||
1069 | priv->addr = map_physmem(secure_base, size, MAP_NOCACHE); | |
1070 | if (!priv->addr) | |
1071 | return -EINVAL; | |
1072 | ||
1073 | priv->rsw_clk = devm_clk_get(dev, NULL); | |
1074 | if (ret) | |
1075 | goto err_map; | |
1076 | ||
1077 | ret = clk_prepare_enable(priv->rsw_clk); | |
1078 | if (ret) | |
1079 | goto err_map; | |
1080 | ||
1081 | return 0; | |
1082 | ||
1083 | err_map: | |
1084 | unmap_physmem(priv->addr, MAP_NOCACHE); | |
1085 | return ret; | |
1086 | } | |
1087 | ||
1088 | static int rswitch_remove(struct udevice *dev) | |
1089 | { | |
1090 | struct rswitch_priv *priv = dev_get_plat(dev); | |
1091 | ||
1092 | clk_disable_unprepare(priv->rsw_clk); | |
1093 | unmap_physmem(priv->addr, MAP_NOCACHE); | |
1094 | ||
1095 | return 0; | |
1096 | } | |
1097 | ||
1098 | static int rswitch_bind(struct udevice *parent) | |
1099 | { | |
1100 | struct rswitch_port_priv *priv = dev_get_plat(parent); | |
1101 | ofnode ports_np, node; | |
1102 | struct udevice *dev; | |
1103 | struct driver *drv; | |
1104 | int ret; | |
1105 | ||
1106 | drv = lists_driver_lookup_name("rswitch-port"); | |
1107 | if (!drv) | |
1108 | return -ENOENT; | |
1109 | ||
1110 | ports_np = dev_read_subnode(parent, "ethernet-ports"); | |
1111 | if (!ofnode_valid(ports_np)) | |
1112 | return -ENOENT; | |
1113 | ||
1114 | ofnode_for_each_subnode(node, ports_np) { | |
1115 | ret = device_bind_with_driver_data(parent, drv, | |
1116 | ofnode_get_name(node), | |
1117 | (ulong)priv, node, &dev); | |
1118 | if (ret) | |
1119 | return ret; | |
1120 | } | |
1121 | ||
1122 | return 0; | |
1123 | } | |
1124 | ||
1125 | static const struct udevice_id rswitch_ids[] = { | |
1126 | { .compatible = "renesas,r8a779f0-ether-switch" }, | |
1127 | { } | |
1128 | }; | |
1129 | ||
1130 | U_BOOT_DRIVER(rswitch) = { | |
1131 | .name = "rswitch", | |
1132 | .id = UCLASS_NOP, | |
1133 | .of_match = rswitch_ids, | |
1134 | .bind = rswitch_bind, | |
1135 | .probe = rswitch_probe, | |
1136 | .remove = rswitch_remove, | |
1137 | .plat_auto = sizeof(struct rswitch_priv), | |
1138 | }; |