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