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