1 /*
2  * Copyright (c) 2023 DENX Software Engineering GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT microchip_lan865x
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(eth_lan865x, CONFIG_ETHERNET_LOG_LEVEL);
11 
12 #include <zephyr/net/ethernet.h>
13 #include <zephyr/net/phy.h>
14 
15 #include <string.h>
16 #include <errno.h>
17 
18 #include <zephyr/net/net_if.h>
19 #include <zephyr/net/ethernet.h>
20 #include <zephyr/net/phy.h>
21 #include <zephyr/drivers/ethernet/eth_lan865x.h>
22 
23 #include "eth_lan865x_priv.h"
24 
eth_lan865x_mdio_c22_read(const struct device * dev,uint8_t prtad,uint8_t regad,uint16_t * data)25 int eth_lan865x_mdio_c22_read(const struct device *dev, uint8_t prtad, uint8_t regad,
26 			      uint16_t *data)
27 {
28 	struct lan865x_data *ctx = dev->data;
29 
30 	return oa_tc6_mdio_read(ctx->tc6, prtad, regad, data);
31 }
32 
eth_lan865x_mdio_c22_write(const struct device * dev,uint8_t prtad,uint8_t regad,uint16_t data)33 int eth_lan865x_mdio_c22_write(const struct device *dev, uint8_t prtad, uint8_t regad,
34 			       uint16_t data)
35 {
36 	struct lan865x_data *ctx = dev->data;
37 
38 	return oa_tc6_mdio_write(ctx->tc6, prtad, regad, data);
39 }
40 
eth_lan865x_mdio_c45_read(const struct device * dev,uint8_t prtad,uint8_t devad,uint16_t regad,uint16_t * data)41 int eth_lan865x_mdio_c45_read(const struct device *dev, uint8_t prtad, uint8_t devad,
42 			      uint16_t regad, uint16_t *data)
43 {
44 	struct lan865x_data *ctx = dev->data;
45 
46 	return oa_tc6_mdio_read_c45(ctx->tc6, prtad, devad, regad, data);
47 }
48 
eth_lan865x_mdio_c45_write(const struct device * dev,uint8_t prtad,uint8_t devad,uint16_t regad,uint16_t data)49 int eth_lan865x_mdio_c45_write(const struct device *dev, uint8_t prtad, uint8_t devad,
50 			       uint16_t regad, uint16_t data)
51 {
52 	struct lan865x_data *ctx = dev->data;
53 
54 	return oa_tc6_mdio_write_c45(ctx->tc6, prtad, devad, regad, data);
55 }
56 
lan865x_mac_rxtx_control(const struct device * dev,bool en)57 static int lan865x_mac_rxtx_control(const struct device *dev, bool en)
58 {
59 	struct lan865x_data *ctx = dev->data;
60 	uint32_t ctl = 0;
61 
62 	if (en) {
63 		ctl = LAN865x_MAC_NCR_TXEN | LAN865x_MAC_NCR_RXEN;
64 	}
65 
66 	return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCR, ctl);
67 }
68 
lan865x_enable_sync(const struct device * dev)69 static int lan865x_enable_sync(const struct device *dev)
70 {
71 	struct lan865x_data *ctx = dev->data;
72 	uint32_t val;
73 	int ret;
74 
75 	ret = oa_tc6_reg_read(ctx->tc6, OA_CONFIG0, &val);
76 	if (ret) {
77 		return ret;
78 	}
79 	val |= OA_CONFIG0_SYNC | OA_CONFIG0_RFA_ZARFE;
80 	ret = oa_tc6_reg_write(ctx->tc6, OA_CONFIG0, val);
81 	if (ret) {
82 		return ret;
83 	}
84 
85 	return lan865x_mac_rxtx_control(dev, LAN865x_MAC_TXRX_ON);
86 }
87 
lan865x_iface_init(struct net_if * iface)88 static void lan865x_iface_init(struct net_if *iface)
89 {
90 	const struct device *dev = net_if_get_device(iface);
91 	struct lan865x_data *ctx = dev->data;
92 	int ret;
93 
94 	ret = lan865x_enable_sync(dev);
95 	if (ret) {
96 		LOG_ERR("LAN865x sync enable failed: %d\n", ret);
97 		return;
98 	}
99 
100 	net_if_set_link_addr(iface, ctx->mac_address, sizeof(ctx->mac_address), NET_LINK_ETHERNET);
101 
102 	if (ctx->iface == NULL) {
103 		ctx->iface = iface;
104 	}
105 
106 	ethernet_init(iface);
107 
108 	net_eth_carrier_on(iface);
109 	ctx->iface_initialized = true;
110 }
111 
lan865x_port_get_capabilities(const struct device * dev)112 static enum ethernet_hw_caps lan865x_port_get_capabilities(const struct device *dev)
113 {
114 	ARG_UNUSED(dev);
115 	return ETHERNET_LINK_10BASE_T | ETHERNET_PROMISC_MODE;
116 }
117 
118 static int lan865x_gpio_reset(const struct device *dev);
119 static void lan865x_write_macaddress(const struct device *dev);
lan865x_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)120 static int lan865x_set_config(const struct device *dev, enum ethernet_config_type type,
121 			      const struct ethernet_config *config)
122 {
123 	const struct lan865x_config *cfg = dev->config;
124 	struct lan865x_data *ctx = dev->data;
125 	struct phy_plca_cfg plca_cfg;
126 
127 	if (type == ETHERNET_CONFIG_TYPE_PROMISC_MODE) {
128 		return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCFGR, LAN865x_MAC_NCFGR_CAF);
129 	}
130 
131 	if (type == ETHERNET_CONFIG_TYPE_MAC_ADDRESS) {
132 		memcpy(ctx->mac_address, config->mac_address.addr, sizeof(ctx->mac_address));
133 
134 		lan865x_write_macaddress(dev);
135 
136 		return net_if_set_link_addr(ctx->iface, ctx->mac_address, sizeof(ctx->mac_address),
137 					    NET_LINK_ETHERNET);
138 	}
139 
140 	if (type == ETHERNET_CONFIG_TYPE_T1S_PARAM) {
141 		if (config->t1s_param.type == ETHERNET_T1S_PARAM_TYPE_PLCA_CONFIG) {
142 			plca_cfg.enable = config->t1s_param.plca.enable;
143 			plca_cfg.node_id = config->t1s_param.plca.node_id;
144 			plca_cfg.node_count = config->t1s_param.plca.node_count;
145 			plca_cfg.burst_count = config->t1s_param.plca.burst_count;
146 			plca_cfg.burst_timer = config->t1s_param.plca.burst_timer;
147 			plca_cfg.to_timer = config->t1s_param.plca.to_timer;
148 
149 			return phy_set_plca_cfg(cfg->phy, &plca_cfg);
150 		}
151 	}
152 
153 	return -ENOTSUP;
154 }
155 
lan865x_wait_for_reset(const struct device * dev)156 static int lan865x_wait_for_reset(const struct device *dev)
157 {
158 	struct lan865x_data *ctx = dev->data;
159 	uint8_t i;
160 
161 	/* Wait for end of LAN865x reset */
162 	for (i = 0; !ctx->reset && i < LAN865X_RESET_TIMEOUT; i++) {
163 		k_msleep(1);
164 	}
165 
166 	if (i == LAN865X_RESET_TIMEOUT) {
167 		LOG_ERR("LAN865x reset timeout reached!");
168 		return -ENODEV;
169 	}
170 
171 	return 0;
172 }
173 
lan865x_gpio_reset(const struct device * dev)174 static int lan865x_gpio_reset(const struct device *dev)
175 {
176 	const struct lan865x_config *cfg = dev->config;
177 	struct lan865x_data *ctx = dev->data;
178 
179 	ctx->reset = false;
180 	ctx->tc6->protected = false;
181 
182 	/* Perform (GPIO based) HW reset */
183 	/* assert RESET_N low for 10 µs (5 µs min) */
184 	gpio_pin_set_dt(&cfg->reset, 1);
185 	k_busy_wait(10U);
186 	/* deassert - end of reset indicated by IRQ_N low  */
187 	gpio_pin_set_dt(&cfg->reset, 0);
188 
189 	return lan865x_wait_for_reset(dev);
190 }
191 
lan865x_check_spi(const struct device * dev)192 static int lan865x_check_spi(const struct device *dev)
193 {
194 	struct lan865x_data *ctx = dev->data;
195 	uint32_t val;
196 	int ret;
197 
198 	ret = oa_tc6_reg_read(ctx->tc6, LAN865x_DEVID, &val);
199 	if (ret < 0) {
200 		return -ENODEV;
201 	}
202 
203 	ctx->silicon_rev = val & LAN865X_REV_MASK;
204 	if (ctx->silicon_rev != 1 && ctx->silicon_rev != 2) {
205 		return -ENODEV;
206 	}
207 
208 	ctx->chip_id = (val >> 4) & 0xFFFF;
209 	if (ctx->chip_id != LAN8650_DEVID && ctx->chip_id != LAN8651_DEVID) {
210 		return -ENODEV;
211 	}
212 
213 	return ret;
214 }
215 
lan865x_write_macaddress(const struct device * dev)216 static void lan865x_write_macaddress(const struct device *dev)
217 {
218 	struct lan865x_data *ctx = dev->data;
219 	uint8_t *mac = &ctx->mac_address[0];
220 	uint32_t val;
221 
222 	/* SPEC_ADD2_BOTTOM */
223 	val = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0];
224 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB2, val);
225 
226 	/* SPEC_ADD2_TOP */
227 	val = (mac[5] << 8) | mac[4];
228 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAT2, val);
229 
230 	/*
231 	 * SPEC_ADD1_BOTTOM - setting unique lower MAC address, back off time is
232 	 * generated out of it.
233 	 */
234 	val = (mac[5] << 24) | (mac[4] << 16) | (mac[3] << 8) | mac[2];
235 	oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_SAB1, val);
236 }
237 
lan865x_set_specific_multicast_addr(const struct device * dev)238 static int lan865x_set_specific_multicast_addr(const struct device *dev)
239 {
240 	struct lan865x_data *ctx = dev->data;
241 	uint32_t mac_h_hash = 0xffffffff;
242 	uint32_t mac_l_hash = 0xffffffff;
243 	int ret;
244 
245 	/* Enable hash for all multicast addresses */
246 	ret = oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_HRT, mac_h_hash);
247 	if (ret) {
248 		return ret;
249 	}
250 
251 	ret = oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_HRB, mac_l_hash);
252 	if (ret) {
253 		return ret;
254 	}
255 
256 	return oa_tc6_reg_write(ctx->tc6, LAN865x_MAC_NCFGR, LAN865x_MAC_NCFGR_MTIHEN);
257 }
258 
lan865x_default_config(const struct device * dev)259 static int lan865x_default_config(const struct device *dev)
260 {
261 	struct lan865x_data *ctx = dev->data;
262 	int ret;
263 
264 	/* Enable protected control RW */
265 	oa_tc6_set_protected_ctrl(ctx->tc6, true);
266 
267 	ret = oa_tc6_reg_write(ctx->tc6, LAN865X_FIXUP_REG, LAN865X_FIXUP_VALUE);
268 	if (ret) {
269 		return ret;
270 	}
271 
272 	lan865x_write_macaddress(dev);
273 	lan865x_set_specific_multicast_addr(dev);
274 
275 	return 0;
276 }
277 
lan865x_int_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)278 static void lan865x_int_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
279 {
280 	ARG_UNUSED(dev);
281 	ARG_UNUSED(pins);
282 
283 	struct lan865x_data *ctx = CONTAINER_OF(cb, struct lan865x_data, gpio_int_callback);
284 
285 	k_sem_give(&ctx->int_sem);
286 }
287 
lan865x_read_chunks(const struct device * dev)288 static void lan865x_read_chunks(const struct device *dev)
289 {
290 	const struct lan865x_config *cfg = dev->config;
291 	struct lan865x_data *ctx = dev->data;
292 	struct oa_tc6 *tc6 = ctx->tc6;
293 	struct net_pkt *pkt;
294 	int ret;
295 
296 	pkt = net_pkt_rx_alloc(K_MSEC(cfg->timeout));
297 	if (!pkt) {
298 		LOG_ERR("OA RX: Could not allocate packet!");
299 		return;
300 	}
301 
302 	k_sem_take(&ctx->tx_rx_sem, K_FOREVER);
303 	ret = oa_tc6_read_chunks(tc6, pkt);
304 	if (ret < 0) {
305 		eth_stats_update_errors_rx(ctx->iface);
306 		net_pkt_unref(pkt);
307 		k_sem_give(&ctx->tx_rx_sem);
308 		return;
309 	}
310 
311 	/* Feed buffer frame to IP stack */
312 	ret = net_recv_data(ctx->iface, pkt);
313 	if (ret < 0) {
314 		LOG_ERR("OA RX: Could not process packet (%d)!", ret);
315 		net_pkt_unref(pkt);
316 	}
317 	k_sem_give(&ctx->tx_rx_sem);
318 }
319 
lan865x_int_thread(const struct device * dev)320 static void lan865x_int_thread(const struct device *dev)
321 {
322 	struct lan865x_data *ctx = dev->data;
323 	struct oa_tc6 *tc6 = ctx->tc6;
324 	uint32_t sts, ftr;
325 	int ret;
326 
327 	while (true) {
328 		k_sem_take(&ctx->int_sem, K_FOREVER);
329 		if (!ctx->reset) {
330 			oa_tc6_reg_read(tc6, OA_STATUS0, &sts);
331 			if (sts & OA_STATUS0_RESETC) {
332 				oa_tc6_reg_write(tc6, OA_STATUS0, sts);
333 
334 				lan865x_default_config(dev);
335 
336 				ctx->reset = true;
337 				/*
338 				 * According to OA T1S standard - it is mandatory to
339 				 * read chunk of data to get the IRQ_N negated (deasserted).
340 				 */
341 				oa_tc6_read_status(tc6, &ftr);
342 				continue;
343 			}
344 		}
345 
346 		/*
347 		 * The IRQ_N is asserted when RCA becomes > 0. As described in
348 		 * OPEN Alliance 10BASE-T1x standard it is deasserted when first
349 		 * data header is received by LAN865x.
350 		 *
351 		 * Hence, it is mandatory to ALWAYS read at least one data chunk!
352 		 */
353 		do {
354 			lan865x_read_chunks(dev);
355 		} while (tc6->rca > 0);
356 
357 		ret = oa_tc6_check_status(tc6);
358 		if (ret == -EIO) {
359 			lan865x_gpio_reset(dev);
360 		}
361 	}
362 }
363 
lan865x_init(const struct device * dev)364 static int lan865x_init(const struct device *dev)
365 {
366 	const struct lan865x_config *cfg = dev->config;
367 	struct lan865x_data *ctx = dev->data;
368 	int ret;
369 
370 	__ASSERT(cfg->spi.config.frequency <= LAN865X_SPI_MAX_FREQUENCY,
371 		 "SPI frequency exceeds supported maximum\n");
372 
373 	if (!spi_is_ready_dt(&cfg->spi)) {
374 		LOG_ERR("SPI bus %s not ready", cfg->spi.bus->name);
375 		return -ENODEV;
376 	}
377 
378 	if (!gpio_is_ready_dt(&cfg->interrupt)) {
379 		LOG_ERR("Interrupt GPIO device %s is not ready", cfg->interrupt.port->name);
380 		return -ENODEV;
381 	}
382 
383 	/* Check SPI communication after reset */
384 	ret = lan865x_check_spi(dev);
385 	if (ret < 0) {
386 		LOG_ERR("SPI communication not working, %d", ret);
387 		return ret;
388 	}
389 
390 	/*
391 	 * Configure interrupt service routine for LAN865x IRQ
392 	 */
393 	ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT);
394 	if (ret < 0) {
395 		LOG_ERR("Failed to configure interrupt GPIO, %d", ret);
396 		return ret;
397 	}
398 
399 	gpio_init_callback(&(ctx->gpio_int_callback), lan865x_int_callback,
400 			   BIT(cfg->interrupt.pin));
401 
402 	ret = gpio_add_callback(cfg->interrupt.port, &ctx->gpio_int_callback);
403 	if (ret < 0) {
404 		LOG_ERR("Failed to add INT callback, %d", ret);
405 		return ret;
406 	}
407 
408 	gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE);
409 
410 	/* Start interruption-poll thread */
411 	ctx->tid_int = k_thread_create(
412 		&ctx->thread, ctx->thread_stack, CONFIG_ETH_LAN865X_IRQ_THREAD_STACK_SIZE,
413 		(k_thread_entry_t)lan865x_int_thread, (void *)dev, NULL, NULL,
414 		K_PRIO_COOP(CONFIG_ETH_LAN865X_IRQ_THREAD_PRIO), 0, K_NO_WAIT);
415 	k_thread_name_set(ctx->tid_int, "lan865x_interrupt");
416 
417 	/* Perform HW reset - 'rst-gpios' required property set in DT */
418 	if (!gpio_is_ready_dt(&cfg->reset)) {
419 		LOG_ERR("Reset GPIO device %s is not ready", cfg->reset.port->name);
420 		return -ENODEV;
421 	}
422 
423 	ret = gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE);
424 	if (ret < 0) {
425 		LOG_ERR("Failed to configure reset GPIO, %d", ret);
426 		return ret;
427 	}
428 
429 	return lan865x_gpio_reset(dev);
430 }
431 
lan865x_port_send(const struct device * dev,struct net_pkt * pkt)432 static int lan865x_port_send(const struct device *dev, struct net_pkt *pkt)
433 {
434 	struct lan865x_data *ctx = dev->data;
435 	struct oa_tc6 *tc6 = ctx->tc6;
436 	int ret;
437 
438 	k_sem_take(&ctx->tx_rx_sem, K_FOREVER);
439 	ret = oa_tc6_send_chunks(tc6, pkt);
440 
441 	/* Check if rca > 0 during half-duplex TX transmission */
442 	if (tc6->rca > 0) {
443 		k_sem_give(&ctx->int_sem);
444 	}
445 
446 	k_sem_give(&ctx->tx_rx_sem);
447 	if (ret < 0) {
448 		LOG_ERR("TX transmission error, %d", ret);
449 		eth_stats_update_errors_tx(net_pkt_iface(pkt));
450 		return ret;
451 	}
452 
453 	return 0;
454 }
455 
456 static const struct ethernet_api lan865x_api_func = {
457 	.iface_api.init = lan865x_iface_init,
458 	.get_capabilities = lan865x_port_get_capabilities,
459 	.set_config = lan865x_set_config,
460 	.send = lan865x_port_send,
461 };
462 
463 #define LAN865X_DEFINE(inst)                                                                       \
464 	static const struct lan865x_config lan865x_config_##inst = {                               \
465 		.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 0),                             \
466 		.interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios),                               \
467 		.reset = GPIO_DT_SPEC_INST_GET(inst, rst_gpios),                                   \
468 		.timeout = CONFIG_ETH_LAN865X_TIMEOUT,                                             \
469 		.phy = DEVICE_DT_GET(                                                              \
470 			DT_CHILD(DT_INST_CHILD(inst, lan865x_mdio), ethernet_phy_##inst))};        \
471                                                                                                    \
472 	struct oa_tc6 oa_tc6_##inst = {                                                            \
473 		.cps = 64, .protected = 0, .spi = &lan865x_config_##inst.spi};                     \
474 	static struct lan865x_data lan865x_data_##inst = {                                         \
475 		.mac_address = DT_INST_PROP(inst, local_mac_address),                              \
476 		.tx_rx_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).tx_rx_sem, 1, 1),             \
477 		.int_sem = Z_SEM_INITIALIZER((lan865x_data_##inst).int_sem, 0, 1),                 \
478 		.tc6 = &oa_tc6_##inst};                                                            \
479                                                                                                    \
480 	ETH_NET_DEVICE_DT_INST_DEFINE(inst, lan865x_init, NULL, &lan865x_data_##inst,              \
481 				      &lan865x_config_##inst, CONFIG_ETH_INIT_PRIORITY,            \
482 				      &lan865x_api_func, NET_ETH_MTU);
483 
484 DT_INST_FOREACH_STATUS_OKAY(LAN865X_DEFINE);
485