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