1 /*
2 * Copyright (c) 2020 DENX Software Engineering GmbH
3 * Lukasz Majewski <lukma@denx.de>
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define LOG_MODULE_NAME dsa
8
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_ETHERNET_LOG_LEVEL);
11
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/kernel.h>
15 #include <errno.h>
16 #include <zephyr/sys/util.h>
17 #include <zephyr/net/ethernet.h>
18 #include <zephyr/linker/sections.h>
19 #include <zephyr/toolchain/common.h>
20
21 #if defined(CONFIG_DSA_SPI)
22 #include <zephyr/drivers/spi.h>
23 #else
24 #error "No communication bus defined"
25 #endif
26
27 #if CONFIG_DSA_KSZ8863
28 #define DT_DRV_COMPAT microchip_ksz8863
29 #include "dsa_ksz8863.h"
30 #elif CONFIG_DSA_KSZ8794
31 #define DT_DRV_COMPAT microchip_ksz8794
32 #include "dsa_ksz8794.h"
33 #else
34 #error "Unsupported KSZ chipset"
35 #endif
36
37 struct ksz8xxx_data {
38 int iface_init_count;
39 bool is_init;
40 #if defined(CONFIG_DSA_SPI)
41 struct spi_dt_spec spi;
42 #endif
43 };
44
45 #define PRV_DATA(ctx) ((struct ksz8xxx_data *const)(ctx)->prv_data)
46
dsa_ksz8xxx_write_reg(const struct ksz8xxx_data * pdev,uint16_t reg_addr,uint8_t value)47 static void dsa_ksz8xxx_write_reg(const struct ksz8xxx_data *pdev,
48 uint16_t reg_addr, uint8_t value)
49 {
50 #if defined(CONFIG_DSA_SPI)
51 uint8_t buf[3];
52
53 const struct spi_buf tx_buf = {
54 .buf = buf,
55 .len = 3
56 };
57 const struct spi_buf_set tx = {
58 .buffers = &tx_buf,
59 .count = 1
60 };
61
62 buf[0] = KSZ8XXX_SPI_CMD_WR | ((reg_addr >> 7) & 0x1F);
63 buf[1] = (reg_addr << 1) & 0xFE;
64 buf[2] = value;
65
66 spi_write_dt(&pdev->spi, &tx);
67 #endif
68 }
69
dsa_ksz8xxx_read_reg(const struct ksz8xxx_data * pdev,uint16_t reg_addr,uint8_t * value)70 static void dsa_ksz8xxx_read_reg(const struct ksz8xxx_data *pdev,
71 uint16_t reg_addr, uint8_t *value)
72 {
73 #if defined(CONFIG_DSA_SPI)
74 uint8_t buf[3];
75
76 const struct spi_buf tx_buf = {
77 .buf = buf,
78 .len = 3
79 };
80 const struct spi_buf_set tx = {
81 .buffers = &tx_buf,
82 .count = 1
83 };
84 struct spi_buf rx_buf = {
85 .buf = buf,
86 .len = 3
87 };
88
89 const struct spi_buf_set rx = {
90 .buffers = &rx_buf,
91 .count = 1
92 };
93
94 buf[0] = KSZ8XXX_SPI_CMD_RD | ((reg_addr >> 7) & 0x1F);
95 buf[1] = (reg_addr << 1) & 0xFE;
96 buf[2] = 0x0;
97
98 if (!spi_transceive_dt(&pdev->spi, &tx, &rx)) {
99 *value = buf[2];
100 } else {
101 LOG_DBG("Failure while reading register 0x%04x", reg_addr);
102 *value = 0U;
103 }
104 #endif
105 }
106
dsa_ksz8xxx_port_link_status(struct ksz8xxx_data * pdev,uint8_t port)107 static bool dsa_ksz8xxx_port_link_status(struct ksz8xxx_data *pdev,
108 uint8_t port)
109 {
110 uint8_t tmp;
111
112 if (port < KSZ8XXX_FIRST_PORT || port > KSZ8XXX_LAST_PORT ||
113 port == KSZ8XXX_CPU_PORT) {
114 return false;
115 }
116
117 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_STAT2_PORTn(port), &tmp);
118
119 return tmp & KSZ8XXX_STAT2_LINK_GOOD;
120 }
121
122 #if !DT_INST_NODE_HAS_PROP(0, reset_gpios)
dsa_ksz8xxx_soft_reset(struct ksz8xxx_data * pdev)123 static void dsa_ksz8xxx_soft_reset(struct ksz8xxx_data *pdev)
124 {
125 /* reset switch */
126 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_RESET_REG,
127 KSZ8XXX_RESET_SET);
128 k_busy_wait(KSZ8XXX_SOFT_RESET_DURATION);
129 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_RESET_REG, KSZ8XXX_RESET_CLEAR);
130 }
131 #endif
132
dsa_ksz8xxx_probe(struct ksz8xxx_data * pdev)133 static int dsa_ksz8xxx_probe(struct ksz8xxx_data *pdev)
134 {
135 uint16_t timeout = 100;
136 uint8_t val[2], tmp;
137
138 /*
139 * Wait for SPI of KSZ8794 being fully operational - up to 10 ms
140 */
141 for (timeout = 100, tmp = 0;
142 tmp != KSZ8XXX_CHIP_ID0_ID_DEFAULT && timeout > 0; timeout--) {
143 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_CHIP_ID0, &tmp);
144 k_busy_wait(100);
145 }
146
147 if (timeout == 0) {
148 LOG_ERR("KSZ8794: No SPI communication!");
149 return -ENODEV;
150 }
151
152 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_CHIP_ID0, &val[0]);
153 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_CHIP_ID1, &val[1]);
154
155 if (val[0] != KSZ8XXX_CHIP_ID0_ID_DEFAULT ||
156 val[1] != KSZ8XXX_CHIP_ID1_ID_DEFAULT) {
157 LOG_ERR("Chip ID mismatch. "
158 "Expected %02x%02x but found %02x%02x",
159 KSZ8XXX_CHIP_ID0_ID_DEFAULT,
160 KSZ8XXX_CHIP_ID1_ID_DEFAULT,
161 val[0],
162 val[1]);
163 return -ENODEV;
164 }
165
166 LOG_DBG("KSZ8794: ID0: 0x%x ID1: 0x%x timeout: %d", val[1], val[0],
167 timeout);
168
169 return 0;
170 }
171
dsa_ksz8xxx_write_static_mac_table(struct ksz8xxx_data * pdev,uint16_t entry_addr,uint8_t * p)172 static int dsa_ksz8xxx_write_static_mac_table(struct ksz8xxx_data *pdev,
173 uint16_t entry_addr, uint8_t *p)
174 {
175 /*
176 * According to KSZ8794 manual - write to static mac address table
177 * requires write to indirect registers:
178 * Write register 0x71 (113)
179 * ....
180 * Write register 0x78 (120)
181 *
182 * Then:
183 * Write to Register 110 with 0x00 (write static table selected)
184 * Write to Register 111 with 0x0x (trigger the write operation, to
185 * table entry x)
186 */
187 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_7, p[7]);
188 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_6, p[6]);
189 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_5, p[5]);
190 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_4, p[4]);
191 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_3, p[3]);
192 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_2, p[2]);
193 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_1, p[1]);
194 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_DATA_0, p[0]);
195
196 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_CTRL_0, 0x00);
197 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_CTRL_1, entry_addr);
198
199 return 0;
200 }
201
dsa_ksz8xxx_set_static_mac_table(struct ksz8xxx_data * pdev,const uint8_t * mac,uint8_t fw_port,uint16_t entry_idx)202 static int dsa_ksz8xxx_set_static_mac_table(struct ksz8xxx_data *pdev,
203 const uint8_t *mac, uint8_t fw_port,
204 uint16_t entry_idx)
205 {
206 /*
207 * The data in uint8_t buf[] buffer is stored in the little endian
208 * format, as it eases programming proper KSZ8794 registers.
209 */
210 uint8_t buf[8];
211
212 buf[7] = 0;
213 /* Prepare entry for static MAC address table */
214 buf[5] = mac[0];
215 buf[4] = mac[1];
216 buf[3] = mac[2];
217 buf[2] = mac[3];
218 buf[1] = mac[4];
219 buf[0] = mac[5];
220
221 buf[6] = fw_port;
222 buf[6] |= KSZ8XXX_STATIC_MAC_TABLE_VALID;
223 buf[6] |= KSZ8XXX_STATIC_MAC_TABLE_OVRD;
224
225 dsa_ksz8xxx_write_static_mac_table(pdev, entry_idx, buf);
226
227 return 0;
228 }
229
dsa_ksz8xxx_read_static_mac_table(struct ksz8xxx_data * pdev,uint16_t entry_addr,uint8_t * p)230 static int dsa_ksz8xxx_read_static_mac_table(struct ksz8xxx_data *pdev,
231 uint16_t entry_addr, uint8_t *p)
232 {
233 /*
234 * According to KSZ8794 manual - read from static mac address table
235 * requires reads from indirect registers:
236 *
237 * Write to Register 110 with 0x10 (read static table selected)
238 * Write to Register 111 with 0x0x (trigger the read operation, to
239 * table entry x)
240 *
241 * Then:
242 * Write register 0x71 (113)
243 * ....
244 * Write register 0x78 (120)
245 *
246 */
247
248 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_CTRL_0, 0x10);
249 dsa_ksz8xxx_write_reg(pdev, KSZ8XXX_REG_IND_CTRL_1, entry_addr);
250
251 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_7, &p[7]);
252 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_6, &p[6]);
253 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_5, &p[5]);
254 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_4, &p[4]);
255 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_3, &p[3]);
256 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_2, &p[2]);
257 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_1, &p[1]);
258 dsa_ksz8xxx_read_reg(pdev, KSZ8XXX_REG_IND_DATA_0, &p[0]);
259
260 return 0;
261 }
262
263 #if CONFIG_DSA_KSZ8863
dsa_ksz8xxx_switch_setup(const struct ksz8xxx_data * pdev)264 static int dsa_ksz8xxx_switch_setup(const struct ksz8xxx_data *pdev)
265 {
266 uint8_t tmp, i;
267
268 /*
269 * Loop through ports - The same setup when tail tagging is enabled or
270 * disabled.
271 */
272 for (i = KSZ8XXX_FIRST_PORT; i <= KSZ8XXX_LAST_PORT; i++) {
273
274 /* Enable transmission, reception and switch address learning */
275 dsa_ksz8xxx_read_reg(pdev, KSZ8863_CTRL2_PORTn(i), &tmp);
276 tmp |= KSZ8863_CTRL2_TRANSMIT_EN;
277 tmp |= KSZ8863_CTRL2_RECEIVE_EN;
278 tmp &= ~KSZ8863_CTRL2_LEARNING_DIS;
279 dsa_ksz8xxx_write_reg(pdev, KSZ8863_CTRL2_PORTn(i), tmp);
280 }
281
282 #if defined(CONFIG_DSA_KSZ_TAIL_TAGGING)
283 /* Enable tail tag feature */
284 dsa_ksz8xxx_read_reg(pdev, KSZ8863_GLOBAL_CTRL1, &tmp);
285 tmp |= KSZ8863_GLOBAL_CTRL1_TAIL_TAG_EN;
286 dsa_ksz8xxx_write_reg(pdev, KSZ8863_GLOBAL_CTRL1, tmp);
287 #else
288 /* Disable tail tag feature */
289 dsa_ksz8xxx_read_reg(pdev, KSZ8863_GLOBAL_CTRL1, &tmp);
290 tmp &= ~KSZ8863_GLOBAL_CTRL1_TAIL_TAG_EN;
291 dsa_ksz8xxx_write_reg(pdev, KSZ8863_GLOBAL_CTRL1, tmp);
292 #endif
293
294 dsa_ksz8xxx_read_reg(pdev, KSZ8863_GLOBAL_CTRL2, &tmp);
295 tmp &= ~KSZ8863_GLOBAL_CTRL2_LEG_MAX_PKT_SIZ_CHK_ENA;
296 dsa_ksz8xxx_write_reg(pdev, KSZ8863_GLOBAL_CTRL2, tmp);
297
298 return 0;
299 }
300 #endif
301
302 #if CONFIG_DSA_KSZ8794
dsa_ksz8xxx_switch_setup(struct ksz8xxx_data * pdev)303 static int dsa_ksz8xxx_switch_setup(struct ksz8xxx_data *pdev)
304 {
305 uint8_t tmp, i;
306
307 /*
308 * Loop through ports - The same setup when tail tagging is enabled or
309 * disabled.
310 */
311 for (i = KSZ8XXX_FIRST_PORT; i <= KSZ8XXX_LAST_PORT; i++) {
312 /* Enable transmission, reception and switch address learning */
313 dsa_ksz8xxx_read_reg(pdev, KSZ8794_CTRL2_PORTn(i), &tmp);
314 tmp |= KSZ8794_CTRL2_TRANSMIT_EN;
315 tmp |= KSZ8794_CTRL2_RECEIVE_EN;
316 tmp &= ~KSZ8794_CTRL2_LEARNING_DIS;
317 dsa_ksz8xxx_write_reg(pdev, KSZ8794_CTRL2_PORTn(i), tmp);
318 }
319
320 #if defined(CONFIG_DSA_KSZ_TAIL_TAGGING)
321 /* Enable tail tag feature */
322 dsa_ksz8xxx_read_reg(pdev, KSZ8794_GLOBAL_CTRL10, &tmp);
323 tmp |= KSZ8794_GLOBAL_CTRL10_TAIL_TAG_EN;
324 dsa_ksz8xxx_write_reg(pdev, KSZ8794_GLOBAL_CTRL10, tmp);
325 #else
326 /* Disable tail tag feature */
327 dsa_ksz8xxx_read_reg(pdev, KSZ8794_GLOBAL_CTRL10, &tmp);
328 tmp &= ~KSZ8794_GLOBAL_CTRL10_TAIL_TAG_EN;
329 dsa_ksz8xxx_write_reg(pdev, KSZ8794_GLOBAL_CTRL10, tmp);
330 #endif
331
332 dsa_ksz8xxx_read_reg(pdev, KSZ8794_PORT4_IF_CTRL6, &tmp);
333 LOG_DBG("KSZ8794: CONTROL6: 0x%x port4", tmp);
334
335 dsa_ksz8xxx_read_reg(pdev, KSZ8794_PORT4_CTRL2, &tmp);
336 LOG_DBG("KSZ8794: CONTROL2: 0x%x port4", tmp);
337
338 dsa_ksz8xxx_read_reg(pdev, KSZ8794_GLOBAL_CTRL2, &tmp);
339 tmp |= KSZ8794_GLOBAL_CTRL2_LEG_MAX_PKT_SIZ_CHK_DIS;
340 dsa_ksz8xxx_write_reg(pdev, KSZ8794_GLOBAL_CTRL2, tmp);
341
342 return 0;
343 }
344
345 #if DT_INST_NODE_HAS_PROP(0, workaround)
346 /*
347 * Workaround 0x01
348 * Solution for Short Cable Problems with the KSZ8795 Family
349 *
350 * Title
351 * Solution for Short Cable Problems with the KSZ8795 Family
352 *
353 * https://microchipsupport.force.com/s/article/Solution-for-Short-Cable-
354 * Problems-with-the-KSZ8795-Family
355 *
356 * Problem Description:
357 * 1) The KSZ8795 family parts might be not link when connected through a few
358 * type of short cable (<3m).
359 * 2) There may be a link-up issue in the capacitor AC coupling mode for port
360 * to port or board to board cases.
361 *
362 * Answer
363 * Root Cause:
364 * KSZ8795 family switches with integrated Ethernet PHY that has a DSP based
365 * equalizer EQ that can balance the signal received to adapt various cable
366 * length characteristics. The equalizer default settings amplify the signal
367 * coming in to get more accurate readings from low amplitude signals.
368 * When using some type of short cable (for example, CAT-6 cable with low
369 * attenuation to high frequencies signal vs. CAT-5 cable) or board to board
370 * connection, or port to port with capacitor AC coupling connection, the signal
371 * is amplified too much and cause the link-up failed with same boost setting in
372 * the equalizer EQ.
373 *
374 * Solution/Workaround:
375 * Write a DSP control register that is indirect register (0x3c) to optimize the
376 * equalizer EQ to cover above corner cases.
377 * w 6e a0 //write the indirect register
378 * w 6f 3c //assign the indirect hidden register address (0x3c)
379 * w a0 15 //write 0x15 to REG (0x3c) to optimize the EQ. The default is 0x0a.
380 * Based on testing and practical application, this register setting above can
381 * solve the issue for all type of the short cables and the capacitor AC
382 * coupling mode.
383 *
384 * The indirect DSP register (0x3c) is an 8-bit register, the bits describe as
385 * follows,
386 *
387 * Bits Bit Name Description Mode Default Setting
388 * 0x0a 0x15
389 * 7-5 Reserved RO 000 000
390 * 4 Cpu_EQ_Done_Cond1 How to judge EQ is finished,
391 * there are two ways to judge
392 * if EQ is finished, can set
393 * either way R/W 0 1
394 * 3-1 Cpu_EQ_CP_Points Control of EQ training is
395 * over-boosted or
396 * [2:0] under-boosted, that means to
397 * compensate signal attenuation
398 * more or less. R/W 101 010
399 * 0 Cpu_STOP_RUN after EQ training completed,
400 * stop adaptation R/W 0 1
401 *
402 * Explanation:
403 * The above register change makes equalizer’s compensation range wider, and
404 * therefore cables with various characteristics can be tolerated. Adjust
405 * equalizer EQ training algorithm to cover a few type of short cables issue.
406 * Also is appropriate for the board to board connection and port to port
407 * connection with the capacitor AC coupling mode.
408 *
409 * Basically, it decides how much signal amplitude to compensate accurately
410 * to the different type of short cable’s characteristics. The current default
411 * value in the indirect register (0x3c) can cover all general standard
412 * Ethernet short cables like CAT-5, CAT-5e without any problem.
413 * Based on tests, a more optimized equalizer adjustment value 0x15 is better
414 * for all corner cases of the short cable and short distance connection for
415 * port to port or board to board cases.
416 */
dsa_ksz8794_phy_workaround_0x01(struct ksz8xxx_data * pdev)417 static int dsa_ksz8794_phy_workaround_0x01(struct ksz8xxx_data *pdev)
418 {
419 uint8_t indirect_type = 0x0a;
420 uint8_t indirect_addr = 0x3c;
421 uint8_t indirect_data = 0x15;
422
423 dsa_ksz8xxx_write_reg(pdev, KSZ8794_REG_IND_CTRL_0, indirect_type);
424 dsa_ksz8xxx_write_reg(pdev, KSZ8794_REG_IND_CTRL_1, indirect_addr);
425 dsa_ksz8xxx_write_reg(pdev, KSZ8794_IND_BYTE, indirect_data);
426 LOG_INF("apply workarkound 0x01 for short connections on KSZ8794");
427 return 0;
428 }
429
430 /*
431 * Workaround 0x02 and 0x4
432 * Solution for Using CAT-5E or CAT-6 Short Cable with a Link Issue for the
433 * KSZ8795 Family
434 *
435 * Title
436 * Solution for Using CAT-5E or CAT-6 Short Cable with a Link Issue for the
437 * KSZ8795 Family
438 * https://microchipsupport.force.com/s/article/Solution-for-Using-CAT-5E-or
439 * -CAT-6-Short-Cable- with-a-Link-Issue-for-the-KSZ8795-Family
440 *
441 * Question
442 * Possible Problem Description:
443 * 1) KSZ8795 family includes KSZ8795CLX, KSZ8775CLX, KSZ8765CLX and KSZ8794CNX.
444 * 2) The KSZ8795 family copper parts may not link well when connected through a
445 * short CAT-5E or CAT-6 cable (about <=30 meter). The failure rate may be about
446 * 2-5%.
447 *
448 * Answer
449 * Root Cause:
450 * Basically, KSZ8795 10/100 Ethernet switch family was designed based on CAT-5
451 * cable. With the application of more type of cables, specially two types
452 * cables of CAT-5E and CAT-6, both cables have wider bandwidth that has
453 * different frequency characteristics than CAT-5 cable. More higher frequency
454 * component of the CAT-5E or CAT-6 will be amplified in the receiving amplifier
455 * and will cause the received signal distortion due to too much high frequency
456 * components receiving signal amplitude and cause the link-up failure with
457 * short cables.
458 *
459 * Solution/Workaround:
460 * 1) dsa_ksz8794_phy_workaround_0x02()
461 * Based on the root cause above, adjust the receiver low pass filter to reduce
462 * the high frequency component to keep the receive signal within a reasonable
463 * range when using CAT-5E and CAT-6 cable.
464 *
465 * Set the indirect register as follows for the receiver low pass filter.
466 * Format is w [Register address] [8-bit data]
467 * w 6e a0 //write the indirect register
468 * w 6f 4c //write/assign the internal used indirect register address (0x4c)
469 * w a0 40 //write 0x40 to indirect register (0x4c) to reduce low pass filter
470 * bandwidth.
471 *
472 * The register 0x4c bits [7:6] for receiver low pass filter bandwidth control.
473 *
474 * The default value is ‘00’, change to ‘01’.
475 * Based on testing and practical application, this register setting above can
476 * solve the link issue if using CAT-5E and CAT-6 short cables.
477 *
478 * The indirect register (0x4C) is an 8-bit register. The bits [7:6] are
479 * described in the table below.
480 *
481 *
482 * Bits Bit Name Description Mode Default Setting
483 * 0x00 0x40
484 * 7-6 RX BW control Low pass filter bandwidth R/W 00 01
485 * 00 = 90MHz
486 * 01 = 62MHz
487 * 10 = 55MHz
488 * 11 = 44MHz
489 * 5 Enable Near-end loopback R/W 0 0
490 * 4-3 BTRT Additional reduce R/W 00 00
491 * 2 SD Ext register R/W 0 0
492 * 1-0 FXD reference setting 1.7V, 2V,
493 * 1.4V
494 * R/W 00 00
495 *
496 * Solution/Workaround:
497 * 2) dsa_ksz8794_phy_workaround_0x04()
498 * For the wider bandwidth cables or on-board capacitor AC coupling
499 * application, we recommend adding/setting the indirect register (0x08) from
500 * default 0x0f to 0x00 that means to change register (0x08) bits [5:0] from
501 * 0x0f to 0x00 to reduce equalizer’s (EQ) initial value to 0x00 for more
502 * short cable or on-board capacitors AC coupling application.
503 *
504 * Set the indirect register as follows for EQ with 0x00 initial value.
505 * Format is w [Register address] [8-bit data]
506 * w 6e a0 //write the indirect register
507 * w 6f 08 //write/assign the internal used indirect register address (0x08)
508 * w a0 00 //write 0x00 to indirect register (0x08) to make EQ initial value
509 * equal to 0x00 for very short cable (For example, 0.1m or less)
510 * or connect two ports directly through capacitors for a capacitor
511 * AC couple.
512 *
513 * The indirect DSP register (0x08) is an 8-bit register. The bits [5:0] are
514 * described in the table below.
515 *
516 * Bits Bit Name Description Mode Default Setting
517 * 0x0f 0x00
518 * 7 Park EQ Enable Park Equalizer function enable R/W 0 0
519 * 6 Reserved R 0 0
520 * 5-0 Cpu_EQ_Index Equalizer index control
521 * interface R/W 001111 000000
522 * from 0 to 55, set EQ initial value
523 * Conclusion:
524 * Due to CAT-5E and CAT-6 cable having wider bandwidth, more high frequency
525 * components will pass the low pass filter into the receiving amplifier and
526 * cause the received signal amplitude to be too high.
527 * Reducing the receiver low pass filter bandwidth will be the best way to
528 * reduce the high frequency components to meet CAT-5E and CAT-6 short cable
529 * link issue and doesn’t affect CAT-5 cable because CAT-5 is not a wider
530 * bandwidth cable.
531 *
532 * The DSP register (0X08) bits [5:0] are for EQ initial value. Its current
533 * default value is 0x0F, which assumes the need to equalize regardless of the
534 * cable length. This 0x0f initial equalize value in EQ isn’t needed when
535 * using very short cable or an on-board direct connection like capacitors AC
536 * coupling mode. As the cable length increases, the device will equalize
537 * automatic accordingly from 0x00 EQ initial value.
538 *
539 * So, it is better to set both register (0x4c) to 0x40 and register (0x08) to
540 * 0x00 for compatibility with all Ethernet cable types and Ethernet cable
541 * lengths.
542 */
543
dsa_ksz8794_phy_workaround_0x02(struct ksz8xxx_data * pdev)544 static int dsa_ksz8794_phy_workaround_0x02(struct ksz8xxx_data *pdev)
545 {
546 uint8_t indirect_type = 0x0a;
547 uint8_t indirect_addr = 0x4c;
548 uint8_t indirect_data = 0x40;
549
550 dsa_ksz8xxx_write_reg(pdev, KSZ8794_REG_IND_CTRL_0, indirect_type);
551 dsa_ksz8xxx_write_reg(pdev, KSZ8794_REG_IND_CTRL_1, indirect_addr);
552 dsa_ksz8xxx_write_reg(pdev, KSZ8794_IND_BYTE, indirect_data);
553 LOG_INF("apply workarkound 0x02 link issue CAT-5E/6 on KSZ8794");
554 return 0;
555 }
556
dsa_ksz8794_phy_workaround_0x04(struct ksz8xxx_data * pdev)557 static int dsa_ksz8794_phy_workaround_0x04(struct ksz8xxx_data *pdev)
558 {
559 uint8_t indirect_type = 0x0a;
560 uint8_t indirect_addr = 0x08;
561 uint8_t indirect_data = 0x00;
562
563 dsa_ksz8xxx_write_reg(pdev, KSZ8794_REG_IND_CTRL_0, indirect_type);
564 dsa_ksz8xxx_write_reg(pdev, KSZ8794_REG_IND_CTRL_1, indirect_addr);
565 dsa_ksz8xxx_write_reg(pdev, KSZ8794_IND_BYTE, indirect_data);
566 LOG_INF("apply workarkound 0x04 link issue CAT-5E/6 on KSZ8794");
567 return 0;
568 }
569
dsa_ksz8794_apply_workarounds(struct ksz8xxx_data * pdev)570 static int dsa_ksz8794_apply_workarounds(struct ksz8xxx_data *pdev)
571 {
572 int workaround = DT_INST_PROP(0, workaround);
573
574 if (workaround & 0x01) {
575 dsa_ksz8794_phy_workaround_0x01(pdev);
576 }
577 if (workaround & 0x02) {
578 dsa_ksz8794_phy_workaround_0x02(pdev);
579 }
580 if (workaround & 0x04) {
581 dsa_ksz8794_phy_workaround_0x04(pdev);
582 }
583 return 0;
584 }
585 #endif
586
587 #if DT_INST_NODE_HAS_PROP(0, mii_lowspeed_drivestrength)
dsa_ksz8794_set_lowspeed_drivestrength(struct ksz8xxx_data * pdev)588 static int dsa_ksz8794_set_lowspeed_drivestrength(struct ksz8xxx_data *pdev)
589 {
590 int mii_lowspeed_drivestrength =
591 DT_INST_PROP(0, mii_lowspeed_drivestrength);
592
593 uint8_t tmp, val;
594 int ret = 0;
595
596 switch (mii_lowspeed_drivestrength) {
597 case 2:
598 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_2MA;
599 break;
600 case 4:
601 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_4MA;
602 break;
603 case 8:
604 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_8MA;
605 break;
606 case 12:
607 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_12MA;
608 break;
609 case 16:
610 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_16MA;
611 break;
612 case 20:
613 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_20MA;
614 break;
615 case 24:
616 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_24MA;
617 break;
618 case 28:
619 val = KSZ8794_GLOBAL_CTRL20_LOWSPEED_28MA;
620 break;
621 default:
622 ret = -1;
623 LOG_ERR("KSZ8794: unsupported drive strength %dmA",
624 mii_lowspeed_drivestrength);
625 break;
626 }
627
628 if (ret == 0) {
629 /* set Low-Speed Interface Drive Strength for MII and RMMI */
630 dsa_ksz8xxx_read_reg(pdev, KSZ8794_GLOBAL_CTRL20, &tmp);
631 tmp &= ~KSZ8794_GLOBAL_CTRL20_LOWSPEED_MASK;
632 tmp |= val;
633 dsa_ksz8xxx_write_reg(pdev, KSZ8794_GLOBAL_CTRL20, tmp);
634 dsa_ksz8xxx_read_reg(pdev, KSZ8794_GLOBAL_CTRL20, &tmp);
635 LOG_INF("KSZ8794: set drive strength %dmA",
636 mii_lowspeed_drivestrength);
637 }
638 return ret;
639 }
640 #endif
641 #endif
642
643 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
dsa_ksz8xxx_gpio_reset(void)644 static int dsa_ksz8xxx_gpio_reset(void)
645 {
646 struct gpio_dt_spec reset_gpio = GPIO_DT_SPEC_INST_GET(0, reset_gpios);
647
648 if (!gpio_is_ready_dt(&reset_gpio)) {
649 LOG_ERR("Reset GPIO device not ready");
650 return -ENODEV;
651 }
652 gpio_pin_configure_dt(&reset_gpio, GPIO_OUTPUT_ACTIVE);
653 k_msleep(10);
654
655 gpio_pin_set_dt(&reset_gpio, 0);
656
657 return 0;
658 }
659 #endif
660
661 /* Low level initialization code for DSA PHY */
dsa_hw_init(struct ksz8xxx_data * pdev)662 int dsa_hw_init(struct ksz8xxx_data *pdev)
663 {
664 int rc;
665
666 if (pdev->is_init) {
667 return 0;
668 }
669
670 /* Hard reset */
671 #if DT_INST_NODE_HAS_PROP(0, reset_gpios)
672 dsa_ksz8xxx_gpio_reset();
673
674 /* Time needed for chip to completely power up (100ms) */
675 k_busy_wait(KSZ8XXX_HARD_RESET_WAIT);
676 #endif
677
678 #if defined(CONFIG_DSA_SPI)
679 if (!spi_is_ready_dt(&pdev->spi)) {
680 LOG_ERR("SPI bus %s is not ready",
681 pdev->spi.bus->name);
682 return -ENODEV;
683 }
684 #endif
685
686 /* Probe attached PHY */
687 rc = dsa_ksz8xxx_probe(pdev);
688 if (rc < 0) {
689 return rc;
690 }
691
692 #if !DT_INST_NODE_HAS_PROP(0, reset_gpios)
693 /* Soft reset */
694 dsa_ksz8xxx_soft_reset(pdev);
695 #endif
696
697 /* Setup KSZ8794 */
698 dsa_ksz8xxx_switch_setup(pdev);
699
700 #if DT_INST_NODE_HAS_PROP(0, mii_lowspeed_drivestrength)
701 dsa_ksz8794_set_lowspeed_drivestrength(pdev);
702 #endif
703
704 #if DT_INST_NODE_HAS_PROP(0, workaround)
705 /* apply workarounds */
706 dsa_ksz8794_apply_workarounds(pdev);
707 #endif
708
709 pdev->is_init = true;
710
711 return 0;
712 }
713
dsa_delayed_work(struct k_work * item)714 static void dsa_delayed_work(struct k_work *item)
715 {
716 struct k_work_delayable *dwork = k_work_delayable_from_work(item);
717 struct dsa_context *context =
718 CONTAINER_OF(dwork, struct dsa_context, dsa_work);
719 struct ksz8xxx_data *pdev = PRV_DATA(context);
720 bool link_state;
721 uint8_t i;
722
723 for (i = KSZ8XXX_FIRST_PORT; i <= KSZ8XXX_LAST_PORT; i++) {
724 /* Skip Switch <-> CPU Port */
725 if (i == KSZ8XXX_CPU_PORT) {
726 continue;
727 }
728
729 link_state = dsa_ksz8xxx_port_link_status(pdev, i);
730 if (link_state && !context->link_up[i]) {
731 LOG_INF("DSA port: %d link UP!", i);
732 net_eth_carrier_on(context->iface_slave[i]);
733 } else if (!link_state && context->link_up[i]) {
734 LOG_INF("DSA port: %d link DOWN!", i);
735 net_eth_carrier_off(context->iface_slave[i]);
736 }
737 context->link_up[i] = link_state;
738 }
739
740 k_work_reschedule(&context->dsa_work, DSA_STATUS_PERIOD_MS);
741 }
742
dsa_port_init(const struct device * dev)743 int dsa_port_init(const struct device *dev)
744 {
745 struct dsa_context *data = dev->data;
746 struct ksz8xxx_data *pdev = PRV_DATA(data);
747
748 dsa_hw_init(pdev);
749 return 0;
750 }
751
752 /* Generic implementation of writing value to DSA register */
dsa_ksz8xxx_sw_write_reg(const struct device * dev,uint16_t reg_addr,uint8_t value)753 static int dsa_ksz8xxx_sw_write_reg(const struct device *dev, uint16_t reg_addr,
754 uint8_t value)
755 {
756 struct dsa_context *data = dev->data;
757 struct ksz8xxx_data *pdev = PRV_DATA(data);
758
759 dsa_ksz8xxx_write_reg(pdev, reg_addr, value);
760 return 0;
761 }
762
763 /* Generic implementation of reading value from DSA register */
dsa_ksz8xxx_sw_read_reg(const struct device * dev,uint16_t reg_addr,uint8_t * value)764 static int dsa_ksz8xxx_sw_read_reg(const struct device *dev, uint16_t reg_addr,
765 uint8_t *value)
766 {
767 struct dsa_context *data = dev->data;
768 struct ksz8xxx_data *pdev = PRV_DATA(data);
769
770 dsa_ksz8xxx_read_reg(pdev, reg_addr, value);
771 return 0;
772 }
773
774 /**
775 * @brief Set entry to DSA MAC address table
776 *
777 * @param dev DSA device
778 * @param mac The MAC address to be set in the table
779 * @param fw_port Port number to forward packets
780 * @param tbl_entry_idx The index of entry in the table
781 * @param flags Flags to be set in the entry
782 *
783 * @return 0 if ok, < 0 if error
784 */
dsa_ksz8xxx_set_mac_table_entry(const struct device * dev,const uint8_t * mac,uint8_t fw_port,uint16_t tbl_entry_idx,uint16_t flags)785 static int dsa_ksz8xxx_set_mac_table_entry(const struct device *dev,
786 const uint8_t *mac,
787 uint8_t fw_port,
788 uint16_t tbl_entry_idx,
789 uint16_t flags)
790 {
791 struct dsa_context *data = dev->data;
792 struct ksz8xxx_data *pdev = PRV_DATA(data);
793
794 if (flags != 0) {
795 return -EINVAL;
796 }
797
798 dsa_ksz8xxx_set_static_mac_table(pdev, mac, fw_port,
799 tbl_entry_idx);
800
801 return 0;
802 }
803
804 /**
805 * @brief Get DSA MAC address table entry
806 *
807 * @param dev DSA device
808 * @param buf The buffer for data read from the table
809 * @param tbl_entry_idx The index of entry in the table
810 *
811 * @return 0 if ok, < 0 if error
812 */
dsa_ksz8xxx_get_mac_table_entry(const struct device * dev,uint8_t * buf,uint16_t tbl_entry_idx)813 static int dsa_ksz8xxx_get_mac_table_entry(const struct device *dev,
814 uint8_t *buf,
815 uint16_t tbl_entry_idx)
816 {
817 struct dsa_context *data = dev->data;
818 struct ksz8xxx_data *pdev = PRV_DATA(data);
819
820 dsa_ksz8xxx_read_static_mac_table(pdev, tbl_entry_idx, buf);
821
822 return 0;
823 }
824
825 #if defined(CONFIG_DSA_KSZ_TAIL_TAGGING)
826 #define DSA_KSZ8795_TAIL_TAG_OVRD BIT(6)
827 #define DSA_KSZ8795_TAIL_TAG_LOOKUP BIT(7)
828
829 #define DSA_KSZ8794_EGRESS_TAG_LEN 1
830 #define DSA_KSZ8794_INGRESS_TAG_LEN 1
831
832 #define DSA_MIN_L2_FRAME_SIZE 64
833 #define DSA_L2_FCS_SIZE 4
834
dsa_ksz8xxx_xmit_pkt(struct net_if * iface,struct net_pkt * pkt)835 struct net_pkt *dsa_ksz8xxx_xmit_pkt(struct net_if *iface, struct net_pkt *pkt)
836 {
837 struct ethernet_context *ctx = net_if_l2_data(iface);
838 struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
839 struct net_linkaddr lladst;
840 uint8_t port_idx, *dbuf;
841 struct net_buf *buf;
842 size_t len, pad = 0;
843
844 lladst.len = sizeof(hdr->dst.addr);
845 lladst.addr = &hdr->dst.addr[0];
846
847 len = net_pkt_get_len(pkt);
848 /*
849 * For KSZ8794 one needs to 'pad' the L2 frame to its minimal size
850 * (64B) before appending TAIL TAG and FCS
851 */
852 if (len < (DSA_MIN_L2_FRAME_SIZE - DSA_L2_FCS_SIZE)) {
853 /* Calculate number of bytes needed for padding */
854 pad = DSA_MIN_L2_FRAME_SIZE - DSA_L2_FCS_SIZE - len;
855 }
856
857 buf = net_buf_alloc_len(net_buf_pool_get(pkt->buffer->pool_id),
858 pad + DSA_KSZ8794_INGRESS_TAG_LEN, K_NO_WAIT);
859 if (!buf) {
860 LOG_ERR("DSA cannot allocate new data buffer");
861 return NULL;
862 }
863
864 /*
865 * Get the pointer to struct's net_buf_simple data and zero out the
866 * padding and tag byte placeholder
867 */
868 dbuf = net_buf_simple_tail(&(buf->b));
869 memset(dbuf, 0x0, pad + DSA_KSZ8794_INGRESS_TAG_LEN);
870
871 /*
872 * For master port (eth0) set the bit 7 to use look-up table to pass
873 * packet to correct interface (bits [0..6] _are_ ignored).
874 *
875 * For slave ports (lan1..3) just set the tag properly:
876 * bit 0 -> eth1, bit 1 -> eth2. bit 2 -> eth3
877 * It may be also necessary to set bit 6 to "anyhow send packets to
878 * specified port in Bits[3:0]". This may be needed for RSTP
879 * implementation (when the switch port is disabled, but shall handle
880 * LLDP packets).
881 */
882 if (dsa_is_port_master(iface)) {
883 port_idx = DSA_KSZ8795_TAIL_TAG_LOOKUP;
884 } else {
885 port_idx = (1 << (ctx->dsa_port_idx));
886 }
887
888 NET_DBG("TT - port: 0x%x[%p] LEN: %d 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
889 port_idx, iface, len, lladst.addr[0], lladst.addr[1],
890 lladst.addr[2], lladst.addr[3], lladst.addr[4], lladst.addr[5]);
891
892 /* The tail tag shall be placed after the padding (if present) */
893 dbuf[pad] = port_idx;
894
895 /* Set proper len member for the actual struct net_buf_simple */
896 net_buf_add(buf, pad + DSA_KSZ8794_INGRESS_TAG_LEN);
897
898 /* Append struct net_buf to packet data */
899 net_buf_frag_add(pkt->buffer, buf);
900
901 return pkt;
902 }
903
904 /**
905 * @brief DSA function to get proper interface
906 *
907 * This is the function for assigning proper slave interface after receiving
908 * the packet on master.
909 *
910 * @param iface Network interface
911 * @param pkt Network packet
912 *
913 * Returns:
914 * - Pointer to struct net_if
915 */
dsa_ksz8xxx_get_iface(struct net_if * iface,struct net_pkt * pkt)916 static struct net_if *dsa_ksz8xxx_get_iface(struct net_if *iface,
917 struct net_pkt *pkt)
918 {
919 struct ethernet_context *ctx;
920 struct net_if *iface_sw;
921 size_t plen;
922 uint8_t pnum;
923
924 if (!(net_eth_get_hw_capabilities(iface) &
925 (ETHERNET_DSA_SLAVE_PORT | ETHERNET_DSA_MASTER_PORT))) {
926 return iface;
927 }
928
929 net_pkt_set_overwrite(pkt, true);
930 net_pkt_cursor_init(pkt);
931 plen = net_pkt_get_len(pkt);
932
933 net_pkt_skip(pkt, plen - DSA_KSZ8794_EGRESS_TAG_LEN);
934 net_pkt_read_u8(pkt, &pnum);
935
936 net_pkt_update_length(pkt, plen - DSA_KSZ8794_EGRESS_TAG_LEN);
937
938 /*
939 * NOTE:
940 * The below approach is only for ip_k66f board as we do know
941 * that eth0 is on position (index) 1, then we do have lan1 with
942 * index 2, lan2 with 3 and lan3 with 4.
943 *
944 * This is caused by eth interfaces placing order by linker and
945 * may vary on other boards, where are for example two eth
946 * interfaces available.
947 */
948 iface_sw = net_if_get_by_index(pnum + 2);
949
950 ctx = net_if_l2_data(iface);
951 NET_DBG("TT - plen: %d pnum: %d pos: 0x%p dsa_port_idx: %d",
952 plen - DSA_KSZ8794_EGRESS_TAG_LEN, pnum,
953 net_pkt_cursor_get_pos(pkt), ctx->dsa_port_idx);
954
955 return iface_sw;
956 }
957 #endif
958
dsa_iface_init(struct net_if * iface)959 static void dsa_iface_init(struct net_if *iface)
960 {
961 struct dsa_slave_config *cfg = (struct dsa_slave_config *)
962 net_if_get_device(iface)->config;
963 struct ethernet_context *ctx = net_if_l2_data(iface);
964 const struct device *dm, *dev = net_if_get_device(iface);
965 struct dsa_context *context = dev->data;
966 struct ksz8xxx_data *pdev = PRV_DATA(context);
967 struct ethernet_context *ctx_master;
968 int i = pdev->iface_init_count;
969
970 /* Find master port for ksz8794 switch */
971 if (context->iface_master == NULL) {
972 dm = DEVICE_DT_GET(DT_INST_PHANDLE(0, dsa_master_port));
973 context->iface_master = net_if_lookup_by_dev(dm);
974 if (context->iface_master == NULL) {
975 LOG_ERR("DSA: Master iface NOT found!");
976 return;
977 }
978
979 /*
980 * Provide pointer to DSA context to master's eth interface
981 * struct ethernet_context
982 */
983 ctx_master = net_if_l2_data(context->iface_master);
984 ctx_master->dsa_ctx = context;
985 }
986
987 if (context->iface_slave[i] == NULL) {
988 context->iface_slave[i] = iface;
989 net_if_set_link_addr(iface, cfg->mac_addr,
990 sizeof(cfg->mac_addr),
991 NET_LINK_ETHERNET);
992 ctx->dsa_port_idx = i;
993 ctx->dsa_ctx = context;
994
995 /*
996 * Initialize ethernet context 'work' for this iface to
997 * be able to monitor the carrier status.
998 */
999 ethernet_init(iface);
1000 }
1001
1002 pdev->iface_init_count++;
1003 net_if_carrier_off(iface);
1004
1005 /*
1006 * Start DSA work to monitor status of ports (read from switch IC)
1007 * only when carrier_work is properly initialized for all slave
1008 * interfaces.
1009 */
1010 if (pdev->iface_init_count == context->num_slave_ports) {
1011 k_work_init_delayable(&context->dsa_work, dsa_delayed_work);
1012 k_work_reschedule(&context->dsa_work, DSA_STATUS_PERIOD_MS);
1013 }
1014 }
1015
dsa_port_get_capabilities(const struct device * dev)1016 static enum ethernet_hw_caps dsa_port_get_capabilities(const struct device *dev)
1017 {
1018 ARG_UNUSED(dev);
1019
1020 return ETHERNET_DSA_SLAVE_PORT | ETHERNET_LINK_10BASE_T |
1021 ETHERNET_LINK_100BASE_T;
1022 }
1023
1024 const struct ethernet_api dsa_eth_api_funcs = {
1025 .iface_api.init = dsa_iface_init,
1026 .get_capabilities = dsa_port_get_capabilities,
1027 .send = dsa_tx,
1028 };
1029
1030 static struct dsa_api dsa_api_f = {
1031 .switch_read = dsa_ksz8xxx_sw_read_reg,
1032 .switch_write = dsa_ksz8xxx_sw_write_reg,
1033 .switch_set_mac_table_entry = dsa_ksz8xxx_set_mac_table_entry,
1034 .switch_get_mac_table_entry = dsa_ksz8xxx_get_mac_table_entry,
1035 #if defined(CONFIG_DSA_KSZ_TAIL_TAGGING)
1036 .dsa_xmit_pkt = dsa_ksz8xxx_xmit_pkt,
1037 .dsa_get_iface = dsa_ksz8xxx_get_iface,
1038 #endif
1039 };
1040
1041 /*
1042 * The order of NET_DEVICE_INIT_INSTANCE() placement IS important.
1043 *
1044 * To make the code simpler - the special care needs to be put on
1045 * the proper placement of eth0, lan1, lan2, lan3, etc - to avoid
1046 * the need to search for proper interface when each packet is
1047 * received or sent.
1048 * The net_if.c has a very fast API to provide access to linked by
1049 * the linker struct net_if(s) via device or index. As it is already
1050 * available for use - let's use it.
1051 *
1052 * To do that one needs to check how linker places the interfaces.
1053 * To inspect:
1054 * objdump -dst ./zephyr/CMakeFiles/zephyr.dir/drivers/ethernet/eth_mcux.c.obj\
1055 * | grep "__net_if"
1056 * (The real problem is with eth0 and lanX order)
1057 *
1058 * If this approach is not enough for a simple system (like e.g. ip_k66f, one
1059 * can prepare dedicated linker script for the board to force the
1060 * order for complicated designs (like ones with eth0, eth1, and lanX).
1061 *
1062 * For simple cases it is just good enough.
1063 */
1064
1065 #define NET_SLAVE_DEVICE_INIT_INSTANCE(slave, n) \
1066 const struct dsa_slave_config dsa_0_slave_##slave##_config = { \
1067 .mac_addr = DT_PROP_OR(slave, local_mac_address, {0}) \
1068 }; \
1069 NET_DEVICE_INIT_INSTANCE(CONCAT(dsa_slave_port_, slave), \
1070 "lan" STRINGIFY(n), \
1071 n, \
1072 dsa_port_init, \
1073 NULL, \
1074 &dsa_context_##n, \
1075 &dsa_0_slave_##slave##_config, \
1076 CONFIG_ETH_INIT_PRIORITY, \
1077 &dsa_eth_api_funcs, \
1078 ETHERNET_L2, \
1079 NET_L2_GET_CTX_TYPE(ETHERNET_L2), \
1080 NET_ETH_MTU);
1081
1082 #define NET_SLAVE_DEVICE_0_INIT_INSTANCE(slave) \
1083 NET_SLAVE_DEVICE_INIT_INSTANCE(slave, 0)
1084 #define NET_SLAVE_DEVICE_1_INIT_INSTANCE(slave) \
1085 NET_SLAVE_DEVICE_INIT_INSTANCE(slave, 1)
1086 #define NET_SLAVE_DEVICE_2_INIT_INSTANCE(slave) \
1087 NET_SLAVE_DEVICE_INIT_INSTANCE(slave, 2)
1088 #define NET_SLAVE_DEVICE_3_INIT_INSTANCE(slave) \
1089 NET_SLAVE_DEVICE_INIT_INSTANCE(slave, 3)
1090 #define NET_SLAVE_DEVICE_4_INIT_INSTANCE(slave) \
1091 NET_SLAVE_DEVICE_INIT_INSTANCE(slave, 4)
1092
1093 #if defined(CONFIG_DSA_SPI)
1094 #define DSA_SPI_BUS_CONFIGURATION(n) \
1095 .spi = SPI_DT_SPEC_INST_GET(n, \
1096 SPI_WORD_SET(8), \
1097 0U)
1098 #else
1099 #define DSA_SPI_BUS_CONFIGURATION(n)
1100 #endif
1101
1102 #define DSA_DEVICE(n) \
1103 static struct ksz8xxx_data dsa_device_prv_data_##n = { \
1104 .iface_init_count = 0, \
1105 .is_init = false, \
1106 DSA_SPI_BUS_CONFIGURATION(n), \
1107 }; \
1108 static struct dsa_context dsa_context_##n = { \
1109 .num_slave_ports = DT_INST_PROP(0, dsa_slave_ports), \
1110 .dapi = &dsa_api_f, \
1111 .prv_data = (void *)&dsa_device_prv_data_##n, \
1112 }; \
1113 DT_INST_FOREACH_CHILD_VARGS(n, NET_SLAVE_DEVICE_INIT_INSTANCE, n);
1114
1115
1116 DT_INST_FOREACH_STATUS_OKAY(DSA_DEVICE);
1117