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