1 /*
2 * Copyright (c) 2017 Erwin Rol <erwin@erwinrol.com>
3 * Copyright (c) 2020 Alexander Kozhinov <ak.alexander.kozhinov@gmail.com>
4 * Copyright (c) 2021 Carbon Robotics
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT st_stm32_ethernet
9
10 #define LOG_MODULE_NAME eth_stm32_hal
11 #define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
15
16 #include <zephyr/kernel.h>
17 #include <zephyr/device.h>
18 #include <zephyr/sys/__assert.h>
19 #include <zephyr/sys/util.h>
20 #include <zephyr/sys/crc.h>
21 #include <errno.h>
22 #include <stdbool.h>
23 #include <zephyr/net/net_pkt.h>
24 #include <zephyr/net/net_if.h>
25 #include <zephyr/net/ethernet.h>
26 #include <zephyr/net/phy.h>
27 #include <ethernet/eth_stats.h>
28 #include <soc.h>
29 #include <zephyr/sys/printk.h>
30 #include <zephyr/drivers/clock_control.h>
31 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
32 #include <zephyr/drivers/pinctrl.h>
33 #include <zephyr/irq.h>
34 #include <zephyr/net/lldp.h>
35 #include <zephyr/drivers/hwinfo.h>
36
37 #if defined(CONFIG_NET_DSA)
38 #include <zephyr/net/dsa.h>
39 #endif
40
41 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
42 #include <zephyr/drivers/ptp_clock.h>
43 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
44
45 #include "eth.h"
46 #include "eth_stm32_hal_priv.h"
47
48 #if DT_INST_PROP(0, zephyr_random_mac_address)
49 #define ETH_STM32_RANDOM_MAC
50 #endif
51
52 #if defined(CONFIG_ETH_STM32_HAL_USE_DTCM_FOR_DMA_BUFFER) && \
53 !DT_NODE_HAS_STATUS_OKAY(DT_CHOSEN(zephyr_dtcm))
54 #error DTCM for DMA buffer is activated but zephyr,dtcm is not present in dts
55 #endif
56
57 #define PHY_ADDR CONFIG_ETH_STM32_HAL_PHY_ADDRESS
58
59 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_mdio)
60
61 #define DEVICE_PHY_BY_NAME(n) \
62 DEVICE_DT_GET(DT_CHILD(DT_INST_CHILD(n, mdio), _CONCAT(ethernet_phy_, PHY_ADDR)))
63
64 static const struct device *eth_stm32_phy_dev = DEVICE_PHY_BY_NAME(0);
65
66 #endif
67
68 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
69
70 #define PHY_BSR ((uint16_t)0x0001U) /*!< Transceiver Basic Status Register */
71 #define PHY_LINKED_STATUS ((uint16_t)0x0004U) /*!< Valid link established */
72
73 #define IS_ETH_DMATXDESC_OWN(dma_tx_desc) (dma_tx_desc->DESC3 & \
74 ETH_DMATXNDESCRF_OWN)
75
76 #define ETH_RXBUFNB ETH_RX_DESC_CNT
77 #define ETH_TXBUFNB ETH_TX_DESC_CNT
78
79 #define ETH_MEDIA_INTERFACE_MII HAL_ETH_MII_MODE
80 #define ETH_MEDIA_INTERFACE_RMII HAL_ETH_RMII_MODE
81
82 /* Only one tx_buffer is sufficient to pass only 1 dma_buffer */
83 #define ETH_TXBUF_DEF_NB 1U
84 #else
85
86 #define IS_ETH_DMATXDESC_OWN(dma_tx_desc) (dma_tx_desc->Status & \
87 ETH_DMATXDESC_OWN)
88
89 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
90
91 #define ETH_DMA_TX_TIMEOUT_MS 20U /* transmit timeout in milliseconds */
92
93 #if defined(CONFIG_ETH_STM32_HAL_USE_DTCM_FOR_DMA_BUFFER) && \
94 DT_NODE_HAS_STATUS_OKAY(DT_CHOSEN(zephyr_dtcm))
95 #define __eth_stm32_desc __dtcm_noinit_section
96 #define __eth_stm32_buf __dtcm_noinit_section
97 #elif defined(CONFIG_SOC_SERIES_STM32H7X)
98 #define __eth_stm32_desc __attribute__((section(".eth_stm32_desc")))
99 #define __eth_stm32_buf __attribute__((section(".eth_stm32_buf")))
100 #elif defined(CONFIG_NOCACHE_MEMORY)
101 #define __eth_stm32_desc __nocache __aligned(4)
102 #define __eth_stm32_buf __nocache __aligned(4)
103 #else
104 #define __eth_stm32_desc __aligned(4)
105 #define __eth_stm32_buf __aligned(4)
106 #endif
107
108 static ETH_DMADescTypeDef dma_rx_desc_tab[ETH_RXBUFNB] __eth_stm32_desc;
109 static ETH_DMADescTypeDef dma_tx_desc_tab[ETH_TXBUFNB] __eth_stm32_desc;
110 static uint8_t dma_rx_buffer[ETH_RXBUFNB][ETH_STM32_RX_BUF_SIZE] __eth_stm32_buf;
111 static uint8_t dma_tx_buffer[ETH_TXBUFNB][ETH_STM32_TX_BUF_SIZE] __eth_stm32_buf;
112
113 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
114
115 BUILD_ASSERT(ETH_STM32_RX_BUF_SIZE % 4 == 0, "Rx buffer size must be a multiple of 4");
116
117 struct eth_stm32_rx_buffer_header {
118 struct eth_stm32_rx_buffer_header *next;
119 uint16_t size;
120 bool used;
121 };
122
123 struct eth_stm32_tx_buffer_header {
124 ETH_BufferTypeDef tx_buff;
125 bool used;
126 };
127
128 struct eth_stm32_tx_context {
129 struct net_pkt *pkt;
130 uint16_t first_tx_buffer_index;
131 bool used;
132 };
133
134 static struct eth_stm32_rx_buffer_header dma_rx_buffer_header[ETH_RXBUFNB];
135 static struct eth_stm32_tx_buffer_header dma_tx_buffer_header[ETH_TXBUFNB];
136 static struct eth_stm32_tx_context dma_tx_context[ETH_TX_DESC_CNT];
137
HAL_ETH_RxAllocateCallback(uint8_t ** buf)138 void HAL_ETH_RxAllocateCallback(uint8_t **buf)
139 {
140 for (size_t i = 0; i < ETH_RXBUFNB; ++i) {
141 if (!dma_rx_buffer_header[i].used) {
142 dma_rx_buffer_header[i].next = NULL;
143 dma_rx_buffer_header[i].size = 0;
144 dma_rx_buffer_header[i].used = true;
145 *buf = dma_rx_buffer[i];
146 return;
147 }
148 }
149 *buf = NULL;
150 }
151
152 /* Pointer to an array of ETH_STM32_RX_BUF_SIZE uint8_t's */
153 typedef uint8_t (*RxBufferPtr)[ETH_STM32_RX_BUF_SIZE];
154
155 /* called by HAL_ETH_ReadData() */
HAL_ETH_RxLinkCallback(void ** pStart,void ** pEnd,uint8_t * buff,uint16_t Length)156 void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
157 {
158 /* buff points to the begin on one of the rx buffers,
159 * so we can compute the index of the given buffer
160 */
161 size_t index = (RxBufferPtr)buff - &dma_rx_buffer[0];
162 struct eth_stm32_rx_buffer_header *header = &dma_rx_buffer_header[index];
163
164 __ASSERT_NO_MSG(index < ETH_RXBUFNB);
165
166 header->size = Length;
167
168 if (!*pStart) {
169 /* first packet, set head pointer of linked list */
170 *pStart = header;
171 *pEnd = header;
172 } else {
173 __ASSERT_NO_MSG(*pEnd != NULL);
174 /* not the first packet, add to list and adjust tail pointer */
175 ((struct eth_stm32_rx_buffer_header *)*pEnd)->next = header;
176 *pEnd = header;
177 }
178 }
179
180 /* Called by HAL_ETH_ReleaseTxPacket */
HAL_ETH_TxFreeCallback(uint32_t * buff)181 void HAL_ETH_TxFreeCallback(uint32_t *buff)
182 {
183 __ASSERT_NO_MSG(buff != NULL);
184
185 /* buff is the user context in tx_config.pData */
186 struct eth_stm32_tx_context *ctx = (struct eth_stm32_tx_context *)buff;
187 struct eth_stm32_tx_buffer_header *buffer_header =
188 &dma_tx_buffer_header[ctx->first_tx_buffer_index];
189
190 while (buffer_header != NULL) {
191 buffer_header->used = false;
192 if (buffer_header->tx_buff.next != NULL) {
193 buffer_header = CONTAINER_OF(buffer_header->tx_buff.next,
194 struct eth_stm32_tx_buffer_header, tx_buff);
195 } else {
196 buffer_header = NULL;
197 }
198 }
199 ctx->used = false;
200 }
201
202 /* allocate a tx buffer and mark it as used */
allocate_tx_buffer(void)203 static inline uint16_t allocate_tx_buffer(void)
204 {
205 for (;;) {
206 for (uint16_t index = 0; index < ETH_TXBUFNB; index++) {
207 if (!dma_tx_buffer_header[index].used) {
208 dma_tx_buffer_header[index].used = true;
209 return index;
210 }
211 }
212 k_yield();
213 }
214 }
215
216 /* allocate a tx context and mark it as used, the first tx buffer is also allocated */
allocate_tx_context(struct net_pkt * pkt)217 static inline struct eth_stm32_tx_context *allocate_tx_context(struct net_pkt *pkt)
218 {
219 for (;;) {
220 for (uint16_t index = 0; index < ETH_TX_DESC_CNT; index++) {
221 if (!dma_tx_context[index].used) {
222 dma_tx_context[index].used = true;
223 dma_tx_context[index].pkt = pkt;
224 dma_tx_context[index].first_tx_buffer_index = allocate_tx_buffer();
225 return &dma_tx_context[index];
226 }
227 }
228 k_yield();
229 }
230 }
231 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
232
233 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
234 static ETH_TxPacketConfig tx_config;
235 #endif
236
read_eth_phy_register(ETH_HandleTypeDef * heth,uint32_t PHYAddr,uint32_t PHYReg,uint32_t * RegVal)237 static HAL_StatusTypeDef read_eth_phy_register(ETH_HandleTypeDef *heth,
238 uint32_t PHYAddr,
239 uint32_t PHYReg,
240 uint32_t *RegVal)
241 {
242 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_mdio)
243 return phy_read(eth_stm32_phy_dev, PHYReg, RegVal);
244 #elif defined(CONFIG_ETH_STM32_HAL_API_V2)
245 return HAL_ETH_ReadPHYRegister(heth, PHYAddr, PHYReg, RegVal);
246 #else
247 ARG_UNUSED(PHYAddr);
248 return HAL_ETH_ReadPHYRegister(heth, PHYReg, RegVal);
249 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
250 }
251
setup_mac_filter(ETH_HandleTypeDef * heth)252 static inline void setup_mac_filter(ETH_HandleTypeDef *heth)
253 {
254 __ASSERT_NO_MSG(heth != NULL);
255
256 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
257 ETH_MACFilterConfigTypeDef MACFilterConf;
258
259 HAL_ETH_GetMACFilterConfig(heth, &MACFilterConf);
260 #if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
261 MACFilterConf.HashMulticast = ENABLE;
262 MACFilterConf.PassAllMulticast = DISABLE;
263 #else
264 MACFilterConf.HashMulticast = DISABLE;
265 MACFilterConf.PassAllMulticast = ENABLE;
266 #endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
267 MACFilterConf.HachOrPerfectFilter = DISABLE;
268
269 HAL_ETH_SetMACFilterConfig(heth, &MACFilterConf);
270
271 k_sleep(K_MSEC(1));
272 #else
273 uint32_t tmp = heth->Instance->MACFFR;
274
275 /* clear all multicast filter bits, resulting in perfect filtering */
276 tmp &= ~(ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE |
277 ETH_MULTICASTFRAMESFILTER_HASHTABLE |
278 ETH_MULTICASTFRAMESFILTER_PERFECT |
279 ETH_MULTICASTFRAMESFILTER_NONE);
280
281 if (IS_ENABLED(CONFIG_ETH_STM32_MULTICAST_FILTER)) {
282 /* enable multicast hash receive filter */
283 tmp |= ETH_MULTICASTFRAMESFILTER_HASHTABLE;
284 } else {
285 /* enable receiving all multicast frames */
286 tmp |= ETH_MULTICASTFRAMESFILTER_NONE;
287 }
288
289 heth->Instance->MACFFR = tmp;
290
291 /* Wait until the write operation will be taken into account:
292 * at least four TX_CLK/RX_CLK clock cycles
293 */
294 tmp = heth->Instance->MACFFR;
295 k_sleep(K_MSEC(1));
296 heth->Instance->MACFFR = tmp;
297 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
298 }
299
300 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
eth_is_ptp_pkt(struct net_if * iface,struct net_pkt * pkt)301 static bool eth_is_ptp_pkt(struct net_if *iface, struct net_pkt *pkt)
302 {
303 if (ntohs(NET_ETH_HDR(pkt)->type) != NET_ETH_PTYPE_PTP) {
304 return false;
305 }
306
307 net_pkt_set_priority(pkt, NET_PRIORITY_CA);
308
309 return true;
310 }
311 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
HAL_ETH_TxPtpCallback(uint32_t * buff,ETH_TimeStampTypeDef * timestamp)312 void HAL_ETH_TxPtpCallback(uint32_t *buff, ETH_TimeStampTypeDef *timestamp)
313 {
314 struct eth_stm32_tx_context *ctx = (struct eth_stm32_tx_context *)buff;
315
316 ctx->pkt->timestamp.second = timestamp->TimeStampHigh;
317 ctx->pkt->timestamp.nanosecond = timestamp->TimeStampLow;
318
319 net_if_add_tx_timestamp(ctx->pkt);
320 }
321 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
322 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
323
eth_tx(const struct device * dev,struct net_pkt * pkt)324 static int eth_tx(const struct device *dev, struct net_pkt *pkt)
325 {
326 struct eth_stm32_hal_dev_data *dev_data = dev->data;
327 ETH_HandleTypeDef *heth;
328 int res;
329 size_t total_len;
330 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
331 size_t remaining_read;
332 struct eth_stm32_tx_context *ctx = NULL;
333 struct eth_stm32_tx_buffer_header *buf_header = NULL;
334 #else
335 uint8_t *dma_buffer;
336 __IO ETH_DMADescTypeDef *dma_tx_desc;
337 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
338 HAL_StatusTypeDef hal_ret = HAL_OK;
339 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
340 bool timestamped_frame;
341 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
342
343 __ASSERT_NO_MSG(pkt != NULL);
344 __ASSERT_NO_MSG(pkt->frags != NULL);
345 __ASSERT_NO_MSG(dev != NULL);
346 __ASSERT_NO_MSG(dev_data != NULL);
347
348 heth = &dev_data->heth;
349
350 total_len = net_pkt_get_len(pkt);
351 if (total_len > (ETH_STM32_TX_BUF_SIZE * ETH_TXBUFNB)) {
352 LOG_ERR("PKT too big");
353 return -EIO;
354 }
355
356 k_mutex_lock(&dev_data->tx_mutex, K_FOREVER);
357
358 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
359 ctx = allocate_tx_context(pkt);
360 buf_header = &dma_tx_buffer_header[ctx->first_tx_buffer_index];
361 #else
362 dma_tx_desc = heth->TxDesc;
363 while (IS_ETH_DMATXDESC_OWN(dma_tx_desc) != (uint32_t)RESET) {
364 k_yield();
365 }
366 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
367
368 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
369 timestamped_frame = eth_is_ptp_pkt(net_pkt_iface(pkt), pkt) ||
370 net_pkt_is_tx_timestamping(pkt);
371 if (timestamped_frame) {
372 /* Enable transmit timestamp */
373 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
374 HAL_ETH_PTP_InsertTxTimestamp(heth);
375 #else
376 dma_tx_desc->Status |= ETH_DMATXDESC_TTSE;
377 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
378 }
379 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
380
381 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
382 remaining_read = total_len;
383 /* fill and allocate buffer until remaining data fits in one buffer */
384 while (remaining_read > ETH_STM32_TX_BUF_SIZE) {
385 if (net_pkt_read(pkt, buf_header->tx_buff.buffer, ETH_STM32_TX_BUF_SIZE)) {
386 res = -ENOBUFS;
387 goto error;
388 }
389 const uint16_t next_buffer_id = allocate_tx_buffer();
390
391 buf_header->tx_buff.len = ETH_STM32_TX_BUF_SIZE;
392 /* append new buffer to the linked list */
393 buf_header->tx_buff.next = &dma_tx_buffer_header[next_buffer_id].tx_buff;
394 /* and adjust tail pointer */
395 buf_header = &dma_tx_buffer_header[next_buffer_id];
396 remaining_read -= ETH_STM32_TX_BUF_SIZE;
397 }
398 if (net_pkt_read(pkt, buf_header->tx_buff.buffer, remaining_read)) {
399 res = -ENOBUFS;
400 goto error;
401 }
402 buf_header->tx_buff.len = remaining_read;
403 buf_header->tx_buff.next = NULL;
404
405 #else
406 dma_buffer = (uint8_t *)(dma_tx_desc->Buffer1Addr);
407
408 if (net_pkt_read(pkt, dma_buffer, total_len)) {
409 res = -ENOBUFS;
410 goto error;
411 }
412 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
413
414 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
415 tx_config.Length = total_len;
416 tx_config.pData = ctx;
417 tx_config.TxBuffer = &dma_tx_buffer_header[ctx->first_tx_buffer_index].tx_buff;
418
419 /* Reset TX complete interrupt semaphore before TX request*/
420 k_sem_reset(&dev_data->tx_int_sem);
421
422 /* tx_buffer is allocated on function stack, we need */
423 /* to wait for the transfer to complete */
424 /* So it is not freed before the interrupt happens */
425 hal_ret = HAL_ETH_Transmit_IT(heth, &tx_config);
426
427 if (hal_ret != HAL_OK) {
428 LOG_ERR("HAL_ETH_Transmit: failed!");
429 res = -EIO;
430 goto error;
431 }
432
433 /* the tx context is now owned by the HAL */
434 ctx = NULL;
435
436 /* Wait for end of TX buffer transmission */
437 /* If the semaphore timeout breaks, it means */
438 /* an error occurred or IT was not fired */
439 if (k_sem_take(&dev_data->tx_int_sem,
440 K_MSEC(ETH_DMA_TX_TIMEOUT_MS)) != 0) {
441
442 LOG_ERR("HAL_ETH_TransmitIT tx_int_sem take timeout");
443 res = -EIO;
444
445 /* Check for errors */
446 /* Ethernet device was put in error state */
447 /* Error state is unrecoverable ? */
448 if (HAL_ETH_GetState(heth) == HAL_ETH_STATE_ERROR) {
449 LOG_ERR("%s: ETH in error state: errorcode:%x",
450 __func__,
451 HAL_ETH_GetError(heth));
452 /* TODO recover from error state by restarting eth */
453 }
454
455 /* Check for DMA errors */
456 if (HAL_ETH_GetDMAError(heth)) {
457 LOG_ERR("%s: ETH DMA error: dmaerror:%x",
458 __func__,
459 HAL_ETH_GetDMAError(heth));
460 /* DMA fatal bus errors are putting in error state*/
461 /* TODO recover from this */
462 }
463
464 /* Check for MAC errors */
465 if (HAL_ETH_GetMACError(heth)) {
466 LOG_ERR("%s: ETH MAC error: macerror:%x",
467 __func__,
468 HAL_ETH_GetMACError(heth));
469 /* MAC errors are putting in error state*/
470 /* TODO recover from this */
471 }
472
473 goto error;
474 }
475
476 #else
477 hal_ret = HAL_ETH_TransmitFrame(heth, total_len);
478
479 if (hal_ret != HAL_OK) {
480 LOG_ERR("HAL_ETH_Transmit: failed!");
481 res = -EIO;
482 goto error;
483 }
484
485 /* When Transmit Underflow flag is set, clear it and issue a
486 * Transmit Poll Demand to resume transmission.
487 */
488 if ((heth->Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET) {
489 /* Clear TUS ETHERNET DMA flag */
490 heth->Instance->DMASR = ETH_DMASR_TUS;
491 /* Resume DMA transmission*/
492 heth->Instance->DMATPDR = 0;
493 res = -EIO;
494 goto error;
495 }
496 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
497
498 #if defined(CONFIG_PTP_CLOCK_STM32_HAL) && !defined(CONFIG_ETH_STM32_HAL_API_V2)
499 if (timestamped_frame) {
500 /* Retrieve transmission timestamp from last DMA TX descriptor */
501 __IO ETH_DMADescTypeDef *last_dma_tx_desc = dma_tx_desc;
502
503 while (!(last_dma_tx_desc->Status & ETH_DMATXDESC_LS) &&
504 last_dma_tx_desc->Buffer2NextDescAddr) {
505 last_dma_tx_desc =
506 (ETH_DMADescTypeDef *)last_dma_tx_desc->Buffer2NextDescAddr;
507 }
508
509 while (IS_ETH_DMATXDESC_OWN(last_dma_tx_desc) != (uint32_t)RESET) {
510 /* Wait for transmission */
511 k_yield();
512 }
513
514 if (last_dma_tx_desc->Status & ETH_DMATXDESC_LS &&
515 last_dma_tx_desc->Status & ETH_DMATXDESC_TTSS) {
516 pkt->timestamp.second = last_dma_tx_desc->TimeStampHigh;
517 pkt->timestamp.nanosecond = last_dma_tx_desc->TimeStampLow;
518 } else {
519 /* Invalid value */
520 pkt->timestamp.second = UINT64_MAX;
521 pkt->timestamp.nanosecond = UINT32_MAX;
522 }
523 net_if_add_tx_timestamp(pkt);
524 }
525 #endif /* CONFIG_PTP_CLOCK_STM32_HAL && !CONFIG_ETH_STM32_HAL_API_V2 */
526
527 res = 0;
528 error:
529
530 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
531 if (!ctx) {
532 /* The HAL owns the tx context */
533 HAL_ETH_ReleaseTxPacket(heth);
534 } else {
535 /* We need to release the tx context and its buffers */
536 HAL_ETH_TxFreeCallback((uint32_t *)ctx);
537 }
538 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
539
540 k_mutex_unlock(&dev_data->tx_mutex);
541
542 return res;
543 }
544
get_iface(struct eth_stm32_hal_dev_data * ctx)545 static struct net_if *get_iface(struct eth_stm32_hal_dev_data *ctx)
546 {
547 return ctx->iface;
548 }
549
eth_rx(const struct device * dev)550 static struct net_pkt *eth_rx(const struct device *dev)
551 {
552 struct eth_stm32_hal_dev_data *dev_data;
553 ETH_HandleTypeDef *heth;
554 struct net_pkt *pkt;
555 size_t total_len = 0;
556 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
557 void *appbuf = NULL;
558 struct eth_stm32_rx_buffer_header *rx_header;
559 #else
560 __IO ETH_DMADescTypeDef *dma_rx_desc;
561 uint8_t *dma_buffer;
562 HAL_StatusTypeDef hal_ret = HAL_OK;
563 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
564 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
565 struct net_ptp_time timestamp;
566 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
567 ETH_TimeStampTypeDef ts_registers;
568 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
569 /* Default to invalid value. */
570 timestamp.second = UINT64_MAX;
571 timestamp.nanosecond = UINT32_MAX;
572 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
573
574 __ASSERT_NO_MSG(dev != NULL);
575
576 dev_data = dev->data;
577
578 __ASSERT_NO_MSG(dev_data != NULL);
579
580 heth = &dev_data->heth;
581
582 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
583 if (HAL_ETH_ReadData(heth, &appbuf) != HAL_OK) {
584 /* no frame available */
585 return NULL;
586 }
587
588 /* computing total length */
589 for (rx_header = (struct eth_stm32_rx_buffer_header *)appbuf;
590 rx_header; rx_header = rx_header->next) {
591 total_len += rx_header->size;
592 }
593 #else
594 hal_ret = HAL_ETH_GetReceivedFrame_IT(heth);
595 if (hal_ret != HAL_OK) {
596 /* no frame available */
597 return NULL;
598 }
599
600 total_len = heth->RxFrameInfos.length;
601 dma_buffer = (uint8_t *)heth->RxFrameInfos.buffer;
602 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
603
604 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
605 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
606
607 if (HAL_ETH_PTP_GetRxTimestamp(heth, &ts_registers) == HAL_OK) {
608 timestamp.second = ts_registers.TimeStampHigh;
609 timestamp.nanosecond = ts_registers.TimeStampLow;
610 }
611 #else
612 __IO ETH_DMADescTypeDef *last_dma_rx_desc;
613
614 last_dma_rx_desc = heth->RxFrameInfos.LSRxDesc;
615 if (last_dma_rx_desc->TimeStampHigh != UINT32_MAX ||
616 last_dma_rx_desc->TimeStampLow != UINT32_MAX) {
617 timestamp.second = last_dma_rx_desc->TimeStampHigh;
618 timestamp.nanosecond = last_dma_rx_desc->TimeStampLow;
619 }
620 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
621 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
622
623 pkt = net_pkt_rx_alloc_with_buffer(get_iface(dev_data),
624 total_len, AF_UNSPEC, 0, K_MSEC(100));
625 if (!pkt) {
626 LOG_ERR("Failed to obtain RX buffer");
627 goto release_desc;
628 }
629
630 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
631 for (rx_header = (struct eth_stm32_rx_buffer_header *)appbuf;
632 rx_header; rx_header = rx_header->next) {
633 const size_t index = rx_header - &dma_rx_buffer_header[0];
634
635 __ASSERT_NO_MSG(index < ETH_RXBUFNB);
636 if (net_pkt_write(pkt, dma_rx_buffer[index], rx_header->size)) {
637 LOG_ERR("Failed to append RX buffer to context buffer");
638 net_pkt_unref(pkt);
639 pkt = NULL;
640 goto release_desc;
641 }
642 }
643 #else
644 if (net_pkt_write(pkt, dma_buffer, total_len)) {
645 LOG_ERR("Failed to append RX buffer to context buffer");
646 net_pkt_unref(pkt);
647 pkt = NULL;
648 goto release_desc;
649 }
650 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
651
652 release_desc:
653 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
654 for (rx_header = (struct eth_stm32_rx_buffer_header *)appbuf;
655 rx_header; rx_header = rx_header->next) {
656 rx_header->used = false;
657 }
658 #else
659 /* Release descriptors to DMA */
660 /* Point to first descriptor */
661 dma_rx_desc = heth->RxFrameInfos.FSRxDesc;
662 /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
663 for (int i = 0; i < heth->RxFrameInfos.SegCount; i++) {
664 dma_rx_desc->Status |= ETH_DMARXDESC_OWN;
665 dma_rx_desc = (ETH_DMADescTypeDef *)
666 (dma_rx_desc->Buffer2NextDescAddr);
667 }
668
669 /* Clear Segment_Count */
670 heth->RxFrameInfos.SegCount = 0;
671
672 /* When Rx Buffer unavailable flag is set: clear it
673 * and resume reception.
674 */
675 if ((heth->Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
676 /* Clear RBUS ETHERNET DMA flag */
677 heth->Instance->DMASR = ETH_DMASR_RBUS;
678 /* Resume DMA reception */
679 heth->Instance->DMARPDR = 0;
680 }
681 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
682
683 if (!pkt) {
684 goto out;
685 }
686
687 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
688 pkt->timestamp.second = timestamp.second;
689 pkt->timestamp.nanosecond = timestamp.nanosecond;
690 if (timestamp.second != UINT64_MAX) {
691 net_pkt_set_rx_timestamping(pkt, true);
692 }
693 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
694
695 out:
696 if (!pkt) {
697 eth_stats_update_errors_rx(get_iface(dev_data));
698 }
699
700 return pkt;
701 }
702
rx_thread(void * arg1,void * unused1,void * unused2)703 static void rx_thread(void *arg1, void *unused1, void *unused2)
704 {
705 const struct device *dev;
706 struct eth_stm32_hal_dev_data *dev_data;
707 struct net_if *iface;
708 struct net_pkt *pkt;
709 int res;
710 uint32_t status;
711 HAL_StatusTypeDef hal_ret = HAL_OK;
712
713 __ASSERT_NO_MSG(arg1 != NULL);
714 ARG_UNUSED(unused1);
715 ARG_UNUSED(unused2);
716
717 dev = (const struct device *)arg1;
718 dev_data = dev->data;
719
720 __ASSERT_NO_MSG(dev_data != NULL);
721
722 while (1) {
723 res = k_sem_take(&dev_data->rx_int_sem,
724 K_MSEC(CONFIG_ETH_STM32_CARRIER_CHECK_RX_IDLE_TIMEOUT_MS));
725 if (res == 0) {
726 /* semaphore taken, update link status and receive packets */
727 if (dev_data->link_up != true) {
728 dev_data->link_up = true;
729 net_eth_carrier_on(get_iface(dev_data));
730 }
731 while ((pkt = eth_rx(dev)) != NULL) {
732 iface = net_pkt_iface(pkt);
733 #if defined(CONFIG_NET_DSA)
734 iface = dsa_net_recv(iface, &pkt);
735 #endif
736 res = net_recv_data(iface, pkt);
737 if (res < 0) {
738 eth_stats_update_errors_rx(
739 net_pkt_iface(pkt));
740 LOG_ERR("Failed to enqueue frame "
741 "into RX queue: %d", res);
742 net_pkt_unref(pkt);
743 }
744 }
745 } else if (res == -EAGAIN) {
746 /* semaphore timeout period expired, check link status */
747 hal_ret = read_eth_phy_register(&dev_data->heth,
748 PHY_ADDR, PHY_BSR, (uint32_t *) &status);
749 if (hal_ret == HAL_OK) {
750 if ((status & PHY_LINKED_STATUS) == PHY_LINKED_STATUS) {
751 if (dev_data->link_up != true) {
752 dev_data->link_up = true;
753 net_eth_carrier_on(
754 get_iface(dev_data));
755 }
756 } else {
757 if (dev_data->link_up != false) {
758 dev_data->link_up = false;
759 net_eth_carrier_off(
760 get_iface(dev_data));
761 }
762 }
763 }
764 }
765 }
766 }
767
eth_isr(const struct device * dev)768 static void eth_isr(const struct device *dev)
769 {
770 struct eth_stm32_hal_dev_data *dev_data;
771 ETH_HandleTypeDef *heth;
772
773 __ASSERT_NO_MSG(dev != NULL);
774
775 dev_data = dev->data;
776
777 __ASSERT_NO_MSG(dev_data != NULL);
778
779 heth = &dev_data->heth;
780
781 __ASSERT_NO_MSG(heth != NULL);
782
783 HAL_ETH_IRQHandler(heth);
784 }
785 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
HAL_ETH_TxCpltCallback(ETH_HandleTypeDef * heth_handle)786 void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth_handle)
787 {
788 __ASSERT_NO_MSG(heth_handle != NULL);
789
790 struct eth_stm32_hal_dev_data *dev_data =
791 CONTAINER_OF(heth_handle, struct eth_stm32_hal_dev_data, heth);
792
793 __ASSERT_NO_MSG(dev_data != NULL);
794
795 k_sem_give(&dev_data->tx_int_sem);
796
797 }
798 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
799
800 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
HAL_ETH_ErrorCallback(ETH_HandleTypeDef * heth)801 void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth)
802 {
803 /* Do not log errors. If errors are reported due to high traffic,
804 * logging errors will only increase traffic issues
805 */
806 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
807 __ASSERT_NO_MSG(heth != NULL);
808
809 uint32_t dma_error;
810 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
811 uint32_t mac_error;
812 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
813 const uint32_t error_code = HAL_ETH_GetError(heth);
814
815 struct eth_stm32_hal_dev_data *dev_data =
816 CONTAINER_OF(heth, struct eth_stm32_hal_dev_data, heth);
817
818 switch (error_code) {
819 case HAL_ETH_ERROR_DMA:
820 dma_error = HAL_ETH_GetDMAError(heth);
821
822 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
823 if ((dma_error & ETH_DMA_RX_WATCHDOG_TIMEOUT_FLAG) ||
824 (dma_error & ETH_DMA_RX_PROCESS_STOPPED_FLAG) ||
825 (dma_error & ETH_DMA_RX_BUFFER_UNAVAILABLE_FLAG)) {
826 eth_stats_update_errors_rx(dev_data->iface);
827 }
828 if ((dma_error & ETH_DMA_EARLY_TX_IT_FLAG) ||
829 (dma_error & ETH_DMA_TX_PROCESS_STOPPED_FLAG)) {
830 eth_stats_update_errors_tx(dev_data->iface);
831 }
832 #else
833 if ((dma_error & ETH_DMASR_RWTS) ||
834 (dma_error & ETH_DMASR_RPSS) ||
835 (dma_error & ETH_DMASR_RBUS)) {
836 eth_stats_update_errors_rx(dev_data->iface);
837 }
838 if ((dma_error & ETH_DMASR_ETS) ||
839 (dma_error & ETH_DMASR_TPSS) ||
840 (dma_error & ETH_DMASR_TJTS)) {
841 eth_stats_update_errors_tx(dev_data->iface);
842 }
843 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
844 break;
845
846 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
847 case HAL_ETH_ERROR_MAC:
848 mac_error = HAL_ETH_GetMACError(heth);
849
850 if (mac_error & ETH_RECEIVE_WATCHDOG_TIMEOUT) {
851 eth_stats_update_errors_rx(dev_data->iface);
852 }
853
854 if ((mac_error & ETH_EXECESSIVE_COLLISIONS) ||
855 (mac_error & ETH_LATE_COLLISIONS) ||
856 (mac_error & ETH_EXECESSIVE_DEFERRAL) ||
857 (mac_error & ETH_TRANSMIT_JABBR_TIMEOUT) ||
858 (mac_error & ETH_LOSS_OF_CARRIER) ||
859 (mac_error & ETH_NO_CARRIER)) {
860 eth_stats_update_errors_tx(dev_data->iface);
861 }
862 break;
863 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
864 }
865
866 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
867 dev_data->stats.error_details.rx_crc_errors = heth->Instance->MMCRCRCEPR;
868 dev_data->stats.error_details.rx_align_errors = heth->Instance->MMCRAEPR;
869 #else
870 dev_data->stats.error_details.rx_crc_errors = heth->Instance->MMCRFCECR;
871 dev_data->stats.error_details.rx_align_errors = heth->Instance->MMCRFAECR;
872 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
873
874 #endif /* CONFIG_NET_STATISTICS_ETHERNET */
875 }
876 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
877
HAL_ETH_RxCpltCallback(ETH_HandleTypeDef * heth_handle)878 void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth_handle)
879 {
880 __ASSERT_NO_MSG(heth_handle != NULL);
881
882 struct eth_stm32_hal_dev_data *dev_data =
883 CONTAINER_OF(heth_handle, struct eth_stm32_hal_dev_data, heth);
884
885 __ASSERT_NO_MSG(dev_data != NULL);
886
887 k_sem_give(&dev_data->rx_int_sem);
888 }
889
generate_mac(uint8_t * mac_addr)890 static void generate_mac(uint8_t *mac_addr)
891 {
892 #if defined(ETH_STM32_RANDOM_MAC)
893 /* "zephyr,random-mac-address" is set, generate a random mac address */
894 gen_random_mac(mac_addr, ST_OUI_B0, ST_OUI_B1, ST_OUI_B2);
895 #else /* Use user defined mac address */
896 mac_addr[0] = ST_OUI_B0;
897 mac_addr[1] = ST_OUI_B1;
898 mac_addr[2] = ST_OUI_B2;
899 #if NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(0))
900 mac_addr[3] = NODE_MAC_ADDR_OCTET(DT_DRV_INST(0), 3);
901 mac_addr[4] = NODE_MAC_ADDR_OCTET(DT_DRV_INST(0), 4);
902 mac_addr[5] = NODE_MAC_ADDR_OCTET(DT_DRV_INST(0), 5);
903 #else
904 uint8_t unique_device_ID_12_bytes[12];
905 uint32_t result_mac_32_bits;
906
907 /* Nothing defined by the user, use device id */
908 hwinfo_get_device_id(unique_device_ID_12_bytes, 12);
909 result_mac_32_bits = crc32_ieee((uint8_t *)unique_device_ID_12_bytes, 12);
910 memcpy(&mac_addr[3], &result_mac_32_bits, 3);
911
912 #endif /* NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(0))) */
913 #endif
914 }
915
eth_initialize(const struct device * dev)916 static int eth_initialize(const struct device *dev)
917 {
918 struct eth_stm32_hal_dev_data *dev_data;
919 const struct eth_stm32_hal_dev_cfg *cfg;
920 ETH_HandleTypeDef *heth;
921 HAL_StatusTypeDef hal_ret = HAL_OK;
922 int ret = 0;
923
924 __ASSERT_NO_MSG(dev != NULL);
925
926 dev_data = dev->data;
927 cfg = dev->config;
928
929 __ASSERT_NO_MSG(dev_data != NULL);
930 __ASSERT_NO_MSG(cfg != NULL);
931
932 dev_data->clock = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
933
934 if (!device_is_ready(dev_data->clock)) {
935 LOG_ERR("clock control device not ready");
936 return -ENODEV;
937 }
938
939 /* enable clock */
940 ret = clock_control_on(dev_data->clock,
941 (clock_control_subsys_t)&cfg->pclken);
942 ret |= clock_control_on(dev_data->clock,
943 (clock_control_subsys_t)&cfg->pclken_tx);
944 ret |= clock_control_on(dev_data->clock,
945 (clock_control_subsys_t)&cfg->pclken_rx);
946 #if DT_INST_CLOCKS_HAS_NAME(0, mac_clk_ptp)
947 ret |= clock_control_on(dev_data->clock,
948 (clock_control_subsys_t)&cfg->pclken_ptp);
949 #endif
950
951 if (ret) {
952 LOG_ERR("Failed to enable ethernet clock");
953 return -EIO;
954 }
955
956 /* configure pinmux */
957 ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
958 if (ret < 0) {
959 LOG_ERR("Could not configure ethernet pins");
960 return ret;
961 }
962
963 heth = &dev_data->heth;
964
965 generate_mac(dev_data->mac_addr);
966
967 heth->Init.MACAddr = dev_data->mac_addr;
968
969 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
970 heth->Init.TxDesc = dma_tx_desc_tab;
971 heth->Init.RxDesc = dma_rx_desc_tab;
972 heth->Init.RxBuffLen = ETH_STM32_RX_BUF_SIZE;
973 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
974
975 hal_ret = HAL_ETH_Init(heth);
976 if (hal_ret == HAL_TIMEOUT) {
977 /* HAL Init time out. This could be linked to */
978 /* a recoverable error. Log the issue and continue */
979 /* driver initialisation */
980 LOG_ERR("HAL_ETH_Init Timed out");
981 } else if (hal_ret != HAL_OK) {
982 LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
983 return -EINVAL;
984 }
985
986 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
987 /* Enable timestamping of RX packets. We enable all packets to be
988 * timestamped to cover both IEEE 1588 and gPTP.
989 */
990 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
991 heth->Instance->MACTSCR |= ETH_MACTSCR_TSENALL;
992 #else
993 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSARFE;
994 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
995 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
996
997 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
998 /* Tx config init: */
999 memset(&tx_config, 0, sizeof(ETH_TxPacketConfig));
1000 tx_config.Attributes = ETH_TX_PACKETS_FEATURES_CSUM |
1001 ETH_TX_PACKETS_FEATURES_CRCPAD;
1002 tx_config.ChecksumCtrl = IS_ENABLED(CONFIG_ETH_STM32_HW_CHECKSUM) ?
1003 ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC : ETH_CHECKSUM_DISABLE;
1004 tx_config.CRCPadCtrl = ETH_CRC_PAD_INSERT;
1005 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1006
1007 dev_data->link_up = false;
1008
1009 /* Initialize semaphores */
1010 k_mutex_init(&dev_data->tx_mutex);
1011 k_sem_init(&dev_data->rx_int_sem, 0, K_SEM_MAX_LIMIT);
1012 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
1013 k_sem_init(&dev_data->tx_int_sem, 0, K_SEM_MAX_LIMIT);
1014 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1015
1016 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
1017 /* Adjust MDC clock range depending on HCLK frequency: */
1018 HAL_ETH_SetMDIOClockRange(heth);
1019
1020 /* @TODO: read duplex mode and speed from PHY and set it to ETH */
1021
1022 ETH_MACConfigTypeDef mac_config;
1023
1024 HAL_ETH_GetMACConfig(heth, &mac_config);
1025 mac_config.DuplexMode = IS_ENABLED(CONFIG_ETH_STM32_MODE_HALFDUPLEX) ?
1026 ETH_HALFDUPLEX_MODE : ETH_FULLDUPLEX_MODE;
1027 mac_config.Speed = IS_ENABLED(CONFIG_ETH_STM32_SPEED_10M) ?
1028 ETH_SPEED_10M : ETH_SPEED_100M;
1029 hal_ret = HAL_ETH_SetMACConfig(heth, &mac_config);
1030 if (hal_ret != HAL_OK) {
1031 LOG_ERR("HAL_ETH_SetMACConfig: failed: %d", hal_ret);
1032 }
1033 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1034
1035 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
1036
1037 /* prepare tx buffer header */
1038 for (uint16_t i = 0; i < ETH_TXBUFNB; ++i) {
1039 dma_tx_buffer_header[i].tx_buff.buffer = dma_tx_buffer[i];
1040 }
1041
1042 hal_ret = HAL_ETH_Start_IT(heth);
1043 #else
1044 HAL_ETH_DMATxDescListInit(heth, dma_tx_desc_tab,
1045 &dma_tx_buffer[0][0], ETH_TXBUFNB);
1046 HAL_ETH_DMARxDescListInit(heth, dma_rx_desc_tab,
1047 &dma_rx_buffer[0][0], ETH_RXBUFNB);
1048
1049 hal_ret = HAL_ETH_Start(heth);
1050 #endif /* CONFIG_ETH_STM32_HAL_API_V2 */
1051
1052 if (hal_ret != HAL_OK) {
1053 LOG_ERR("HAL_ETH_Start{_IT} failed");
1054 }
1055
1056 setup_mac_filter(heth);
1057
1058
1059 LOG_DBG("MAC %02x:%02x:%02x:%02x:%02x:%02x",
1060 dev_data->mac_addr[0], dev_data->mac_addr[1],
1061 dev_data->mac_addr[2], dev_data->mac_addr[3],
1062 dev_data->mac_addr[4], dev_data->mac_addr[5]);
1063
1064 return 0;
1065 }
1066
1067 #if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
eth_stm32_mcast_filter(const struct device * dev,const struct ethernet_filter * filter)1068 static void eth_stm32_mcast_filter(const struct device *dev, const struct ethernet_filter *filter)
1069 {
1070 struct eth_stm32_hal_dev_data *dev_data = (struct eth_stm32_hal_dev_data *)dev->data;
1071 ETH_HandleTypeDef *heth;
1072 uint32_t crc;
1073 uint32_t hash_table[2];
1074 uint32_t hash_index;
1075
1076 heth = &dev_data->heth;
1077
1078 crc = __RBIT(crc32_ieee(filter->mac_address.addr, sizeof(struct net_eth_addr)));
1079 hash_index = (crc >> 26) & 0x3f;
1080
1081 __ASSERT_NO_MSG(hash_index < ARRAY_SIZE(dev_data->hash_index_cnt));
1082
1083 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1084 hash_table[0] = heth->Instance->MACHT0R;
1085 hash_table[1] = heth->Instance->MACHT1R;
1086 #else
1087 hash_table[0] = heth->Instance->MACHTLR;
1088 hash_table[1] = heth->Instance->MACHTHR;
1089 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1090
1091 if (filter->set) {
1092 dev_data->hash_index_cnt[hash_index]++;
1093 hash_table[hash_index / 32] |= (1 << (hash_index % 32));
1094 } else {
1095 if (dev_data->hash_index_cnt[hash_index] == 0) {
1096 __ASSERT_NO_MSG(false);
1097 return;
1098 }
1099
1100 dev_data->hash_index_cnt[hash_index]--;
1101 if (dev_data->hash_index_cnt[hash_index] == 0) {
1102 hash_table[hash_index / 32] &= ~(1 << (hash_index % 32));
1103 }
1104 }
1105
1106 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1107 heth->Instance->MACHT0R = hash_table[0];
1108 heth->Instance->MACHT1R = hash_table[1];
1109 #else
1110 heth->Instance->MACHTLR = hash_table[0];
1111 heth->Instance->MACHTHR = hash_table[1];
1112 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1113 }
1114
1115 #endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
1116
eth_iface_init(struct net_if * iface)1117 static void eth_iface_init(struct net_if *iface)
1118 {
1119 const struct device *dev;
1120 struct eth_stm32_hal_dev_data *dev_data;
1121 bool is_first_init = false;
1122
1123 __ASSERT_NO_MSG(iface != NULL);
1124
1125 dev = net_if_get_device(iface);
1126 __ASSERT_NO_MSG(dev != NULL);
1127
1128 dev_data = dev->data;
1129 __ASSERT_NO_MSG(dev_data != NULL);
1130
1131 if (dev_data->iface == NULL) {
1132 dev_data->iface = iface;
1133 is_first_init = true;
1134 }
1135
1136 /* Register Ethernet MAC Address with the upper layer */
1137 net_if_set_link_addr(iface, dev_data->mac_addr,
1138 sizeof(dev_data->mac_addr),
1139 NET_LINK_ETHERNET);
1140
1141 #if defined(CONFIG_NET_DSA)
1142 dsa_register_master_tx(iface, ð_tx);
1143 #endif
1144
1145 ethernet_init(iface);
1146
1147 net_if_carrier_off(iface);
1148
1149 net_lldp_set_lldpdu(iface);
1150
1151 if (is_first_init) {
1152 const struct eth_stm32_hal_dev_cfg *cfg = dev->config;
1153 /* Now that the iface is setup, we are safe to enable IRQs. */
1154 __ASSERT_NO_MSG(cfg->config_func != NULL);
1155 cfg->config_func();
1156
1157 /* Start interruption-poll thread */
1158 k_thread_create(&dev_data->rx_thread, dev_data->rx_thread_stack,
1159 K_KERNEL_STACK_SIZEOF(dev_data->rx_thread_stack),
1160 rx_thread, (void *) dev, NULL, NULL,
1161 IS_ENABLED(CONFIG_NET_TC_THREAD_PREEMPTIVE)
1162 ? K_PRIO_PREEMPT(CONFIG_ETH_STM32_HAL_RX_THREAD_PRIO)
1163 : K_PRIO_COOP(CONFIG_ETH_STM32_HAL_RX_THREAD_PRIO),
1164 0, K_NO_WAIT);
1165
1166 k_thread_name_set(&dev_data->rx_thread, "stm_eth");
1167 }
1168 }
1169
eth_stm32_hal_get_capabilities(const struct device * dev)1170 static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(const struct device *dev)
1171 {
1172 ARG_UNUSED(dev);
1173
1174 return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T
1175 #if defined(CONFIG_NET_VLAN)
1176 | ETHERNET_HW_VLAN
1177 #endif
1178 #if defined(CONFIG_NET_PROMISCUOUS_MODE)
1179 | ETHERNET_PROMISC_MODE
1180 #endif
1181 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
1182 | ETHERNET_PTP
1183 #endif
1184 #if defined(CONFIG_NET_LLDP)
1185 | ETHERNET_LLDP
1186 #endif
1187 #if defined(CONFIG_ETH_STM32_HW_CHECKSUM)
1188 | ETHERNET_HW_RX_CHKSUM_OFFLOAD
1189 | ETHERNET_HW_TX_CHKSUM_OFFLOAD
1190 #endif
1191 #if defined(CONFIG_NET_DSA)
1192 | ETHERNET_DSA_MASTER_PORT
1193 #endif
1194 #if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
1195 | ETHERNET_HW_FILTERING
1196 #endif
1197 ;
1198 }
1199
eth_stm32_hal_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)1200 static int eth_stm32_hal_set_config(const struct device *dev,
1201 enum ethernet_config_type type,
1202 const struct ethernet_config *config)
1203 {
1204 int ret = -ENOTSUP;
1205 struct eth_stm32_hal_dev_data *dev_data;
1206 ETH_HandleTypeDef *heth;
1207
1208 dev_data = dev->data;
1209 heth = &dev_data->heth;
1210
1211 switch (type) {
1212 case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
1213 memcpy(dev_data->mac_addr, config->mac_address.addr, 6);
1214 heth->Instance->MACA0HR = (dev_data->mac_addr[5] << 8) |
1215 dev_data->mac_addr[4];
1216 heth->Instance->MACA0LR = (dev_data->mac_addr[3] << 24) |
1217 (dev_data->mac_addr[2] << 16) |
1218 (dev_data->mac_addr[1] << 8) |
1219 dev_data->mac_addr[0];
1220 net_if_set_link_addr(dev_data->iface, dev_data->mac_addr,
1221 sizeof(dev_data->mac_addr),
1222 NET_LINK_ETHERNET);
1223 ret = 0;
1224 break;
1225 case ETHERNET_CONFIG_TYPE_PROMISC_MODE:
1226 #if defined(CONFIG_NET_PROMISCUOUS_MODE)
1227 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1228 if (config->promisc_mode) {
1229 heth->Instance->MACPFR |= ETH_MACPFR_PR;
1230 } else {
1231 heth->Instance->MACPFR &= ~ETH_MACPFR_PR;
1232 }
1233 #else
1234 if (config->promisc_mode) {
1235 heth->Instance->MACFFR |= ETH_MACFFR_PM;
1236 } else {
1237 heth->Instance->MACFFR &= ~ETH_MACFFR_PM;
1238 }
1239 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1240 ret = 0;
1241 #endif /* CONFIG_NET_PROMISCUOUS_MODE */
1242 break;
1243 #if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
1244 case ETHERNET_CONFIG_TYPE_FILTER:
1245 eth_stm32_mcast_filter(dev, &config->filter);
1246 break;
1247 #endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
1248 default:
1249 break;
1250 }
1251
1252 return ret;
1253 }
1254
1255 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
eth_stm32_get_ptp_clock(const struct device * dev)1256 static const struct device *eth_stm32_get_ptp_clock(const struct device *dev)
1257 {
1258 struct eth_stm32_hal_dev_data *dev_data = dev->data;
1259
1260 return dev_data->ptp_clock;
1261 }
1262 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
1263
1264 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
eth_stm32_hal_get_stats(const struct device * dev)1265 static struct net_stats_eth *eth_stm32_hal_get_stats(const struct device *dev)
1266 {
1267 struct eth_stm32_hal_dev_data *dev_data = dev->data;
1268
1269 return &dev_data->stats;
1270 }
1271 #endif /* CONFIG_NET_STATISTICS_ETHERNET */
1272
1273 static const struct ethernet_api eth_api = {
1274 .iface_api.init = eth_iface_init,
1275 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
1276 .get_ptp_clock = eth_stm32_get_ptp_clock,
1277 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
1278 .get_capabilities = eth_stm32_hal_get_capabilities,
1279 .set_config = eth_stm32_hal_set_config,
1280 #if defined(CONFIG_NET_DSA)
1281 .send = dsa_tx,
1282 #else
1283 .send = eth_tx,
1284 #endif
1285 #if defined(CONFIG_NET_STATISTICS_ETHERNET)
1286 .get_stats = eth_stm32_hal_get_stats,
1287 #endif /* CONFIG_NET_STATISTICS_ETHERNET */
1288 };
1289
eth0_irq_config(void)1290 static void eth0_irq_config(void)
1291 {
1292 IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), eth_isr,
1293 DEVICE_DT_INST_GET(0), 0);
1294 irq_enable(DT_INST_IRQN(0));
1295 }
1296
1297 PINCTRL_DT_INST_DEFINE(0);
1298
1299 static const struct eth_stm32_hal_dev_cfg eth0_config = {
1300 .config_func = eth0_irq_config,
1301 .pclken = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(0, stmmaceth, bus),
1302 .enr = DT_INST_CLOCKS_CELL_BY_NAME(0, stmmaceth, bits)},
1303 .pclken_tx = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(0, mac_clk_tx, bus),
1304 .enr = DT_INST_CLOCKS_CELL_BY_NAME(0, mac_clk_tx, bits)},
1305 .pclken_rx = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(0, mac_clk_rx, bus),
1306 .enr = DT_INST_CLOCKS_CELL_BY_NAME(0, mac_clk_rx, bits)},
1307 #if DT_INST_CLOCKS_HAS_NAME(0, mac_clk_ptp)
1308 .pclken_ptp = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(0, mac_clk_ptp, bus),
1309 .enr = DT_INST_CLOCKS_CELL_BY_NAME(0, mac_clk_ptp, bits)},
1310 #endif
1311 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
1312 };
1313
1314 static struct eth_stm32_hal_dev_data eth0_data = {
1315 .heth = {
1316 .Instance = (ETH_TypeDef *)DT_INST_REG_ADDR(0),
1317 .Init = {
1318 #if !defined(CONFIG_ETH_STM32_HAL_API_V2)
1319 #if defined(CONFIG_ETH_STM32_AUTO_NEGOTIATION_ENABLE)
1320 .AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE,
1321 #else
1322 .AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE,
1323 .Speed = IS_ENABLED(CONFIG_ETH_STM32_SPEED_10M) ?
1324 ETH_SPEED_10M : ETH_SPEED_100M,
1325 .DuplexMode = IS_ENABLED(CONFIG_ETH_STM32_MODE_HALFDUPLEX) ?
1326 ETH_MODE_HALFDUPLEX : ETH_MODE_FULLDUPLEX,
1327 #endif /* !CONFIG_ETH_STM32_AUTO_NEGOTIATION_ENABLE */
1328 .PhyAddress = PHY_ADDR,
1329 .RxMode = ETH_RXINTERRUPT_MODE,
1330 .ChecksumMode = IS_ENABLED(CONFIG_ETH_STM32_HW_CHECKSUM) ?
1331 ETH_CHECKSUM_BY_HARDWARE : ETH_CHECKSUM_BY_SOFTWARE,
1332 #endif /* !CONFIG_SOC_SERIES_STM32H7X */
1333 .MediaInterface = IS_ENABLED(CONFIG_ETH_STM32_HAL_MII) ?
1334 ETH_MEDIA_INTERFACE_MII : ETH_MEDIA_INTERFACE_RMII,
1335 },
1336 },
1337 };
1338
1339 ETH_NET_DEVICE_DT_INST_DEFINE(0, eth_initialize,
1340 NULL, ð0_data, ð0_config,
1341 CONFIG_ETH_INIT_PRIORITY, ð_api, ETH_STM32_HAL_MTU);
1342
1343 #if defined(CONFIG_PTP_CLOCK_STM32_HAL)
1344
1345 struct ptp_context {
1346 struct eth_stm32_hal_dev_data *eth_dev_data;
1347 };
1348
1349 static struct ptp_context ptp_stm32_0_context;
1350
ptp_clock_stm32_set(const struct device * dev,struct net_ptp_time * tm)1351 static int ptp_clock_stm32_set(const struct device *dev,
1352 struct net_ptp_time *tm)
1353 {
1354 struct ptp_context *ptp_context = dev->data;
1355 struct eth_stm32_hal_dev_data *eth_dev_data = ptp_context->eth_dev_data;
1356 ETH_HandleTypeDef *heth = ð_dev_data->heth;
1357 unsigned int key;
1358
1359 key = irq_lock();
1360
1361 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1362 heth->Instance->MACSTSUR = tm->second;
1363 heth->Instance->MACSTNUR = tm->nanosecond;
1364 heth->Instance->MACTSCR |= ETH_MACTSCR_TSINIT;
1365 while (heth->Instance->MACTSCR & ETH_MACTSCR_TSINIT_Msk) {
1366 /* spin lock */
1367 }
1368 #else
1369 heth->Instance->PTPTSHUR = tm->second;
1370 heth->Instance->PTPTSLUR = tm->nanosecond;
1371 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSTI;
1372 while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSSTI_Msk) {
1373 /* spin lock */
1374 }
1375 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1376
1377 irq_unlock(key);
1378
1379 return 0;
1380 }
1381
ptp_clock_stm32_get(const struct device * dev,struct net_ptp_time * tm)1382 static int ptp_clock_stm32_get(const struct device *dev,
1383 struct net_ptp_time *tm)
1384 {
1385 struct ptp_context *ptp_context = dev->data;
1386 struct eth_stm32_hal_dev_data *eth_dev_data = ptp_context->eth_dev_data;
1387 ETH_HandleTypeDef *heth = ð_dev_data->heth;
1388 unsigned int key;
1389 uint32_t second_2;
1390
1391 key = irq_lock();
1392
1393 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1394 tm->second = heth->Instance->MACSTSR;
1395 tm->nanosecond = heth->Instance->MACSTNR;
1396 second_2 = heth->Instance->MACSTSR;
1397 #else
1398 tm->second = heth->Instance->PTPTSHR;
1399 tm->nanosecond = heth->Instance->PTPTSLR;
1400 second_2 = heth->Instance->PTPTSHR;
1401 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1402
1403 irq_unlock(key);
1404
1405 if (tm->second != second_2 && tm->nanosecond < NSEC_PER_SEC / 2) {
1406 /* Second rollover has happened during first measurement: second register
1407 * was read before second boundary and nanosecond register was read after.
1408 * We will use second_2 as a new second value.
1409 */
1410 tm->second = second_2;
1411 }
1412
1413 return 0;
1414 }
1415
ptp_clock_stm32_adjust(const struct device * dev,int increment)1416 static int ptp_clock_stm32_adjust(const struct device *dev, int increment)
1417 {
1418 struct ptp_context *ptp_context = dev->data;
1419 struct eth_stm32_hal_dev_data *eth_dev_data = ptp_context->eth_dev_data;
1420 ETH_HandleTypeDef *heth = ð_dev_data->heth;
1421 int key, ret;
1422
1423 if ((increment <= (int32_t)(-NSEC_PER_SEC)) ||
1424 (increment >= (int32_t)NSEC_PER_SEC)) {
1425 ret = -EINVAL;
1426 } else {
1427 key = irq_lock();
1428
1429 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1430 heth->Instance->MACSTSUR = 0;
1431 if (increment >= 0) {
1432 heth->Instance->MACSTNUR = increment;
1433 } else {
1434 heth->Instance->MACSTNUR = ETH_MACSTNUR_ADDSUB | (NSEC_PER_SEC + increment);
1435 }
1436 heth->Instance->MACTSCR |= ETH_MACTSCR_TSUPDT;
1437 while (heth->Instance->MACTSCR & ETH_MACTSCR_TSUPDT_Msk) {
1438 /* spin lock */
1439 }
1440 #else
1441 heth->Instance->PTPTSHUR = 0;
1442 if (increment >= 0) {
1443 heth->Instance->PTPTSLUR = increment;
1444 } else {
1445 heth->Instance->PTPTSLUR = ETH_PTPTSLUR_TSUPNS | (-increment);
1446 }
1447 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSTU;
1448 while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSSTU_Msk) {
1449 /* spin lock */
1450 }
1451 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1452
1453 ret = 0;
1454 irq_unlock(key);
1455 }
1456
1457 return ret;
1458 }
1459
ptp_clock_stm32_rate_adjust(const struct device * dev,double ratio)1460 static int ptp_clock_stm32_rate_adjust(const struct device *dev, double ratio)
1461 {
1462 struct ptp_context *ptp_context = dev->data;
1463 struct eth_stm32_hal_dev_data *eth_dev_data = ptp_context->eth_dev_data;
1464 ETH_HandleTypeDef *heth = ð_dev_data->heth;
1465 int key, ret;
1466 uint32_t addend_val;
1467
1468 /* No change needed */
1469 if (ratio == 1.0L) {
1470 return 0;
1471 }
1472
1473 key = irq_lock();
1474
1475 ratio *= (double)eth_dev_data->clk_ratio_adj;
1476
1477 /* Limit possible ratio */
1478 if (ratio * 100 < CONFIG_ETH_STM32_HAL_PTP_CLOCK_ADJ_MIN_PCT ||
1479 ratio * 100 > CONFIG_ETH_STM32_HAL_PTP_CLOCK_ADJ_MAX_PCT) {
1480 ret = -EINVAL;
1481 goto error;
1482 }
1483
1484 /* Save new ratio */
1485 eth_dev_data->clk_ratio_adj = ratio;
1486
1487 /* Update addend register */
1488 addend_val = UINT32_MAX * (double)eth_dev_data->clk_ratio * ratio;
1489
1490 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1491 heth->Instance->MACTSAR = addend_val;
1492 heth->Instance->MACTSCR |= ETH_MACTSCR_TSADDREG;
1493 while (heth->Instance->MACTSCR & ETH_MACTSCR_TSADDREG_Msk) {
1494 /* spin lock */
1495 }
1496 #else
1497 heth->Instance->PTPTSAR = addend_val;
1498 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSARU;
1499 while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSARU_Msk) {
1500 /* spin lock */
1501 }
1502 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1503
1504 ret = 0;
1505
1506 error:
1507 irq_unlock(key);
1508
1509 return ret;
1510 }
1511
1512 static DEVICE_API(ptp_clock, api) = {
1513 .set = ptp_clock_stm32_set,
1514 .get = ptp_clock_stm32_get,
1515 .adjust = ptp_clock_stm32_adjust,
1516 .rate_adjust = ptp_clock_stm32_rate_adjust,
1517 };
1518
ptp_stm32_init(const struct device * port)1519 static int ptp_stm32_init(const struct device *port)
1520 {
1521 const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(mac));
1522 struct eth_stm32_hal_dev_data *eth_dev_data = dev->data;
1523 const struct eth_stm32_hal_dev_cfg *eth_cfg = dev->config;
1524 struct ptp_context *ptp_context = port->data;
1525 ETH_HandleTypeDef *heth = ð_dev_data->heth;
1526 int ret;
1527 uint32_t ptp_hclk_rate;
1528 uint32_t ss_incr_ns;
1529 uint32_t addend_val;
1530
1531 eth_dev_data->ptp_clock = port;
1532 ptp_context->eth_dev_data = eth_dev_data;
1533
1534 /* Mask the Timestamp Trigger interrupt */
1535 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1536 heth->Instance->MACIER &= ~(ETH_MACIER_TSIE);
1537 #else
1538 heth->Instance->MACIMR &= ~(ETH_MACIMR_TSTIM);
1539 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1540
1541 /* Enable timestamping */
1542 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1543 heth->Instance->MACTSCR |= ETH_MACTSCR_TSENA;
1544 #else
1545 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSE;
1546 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1547
1548 /* Query ethernet clock rate */
1549 ret = clock_control_get_rate(eth_dev_data->clock,
1550 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1551 (clock_control_subsys_t)ð_cfg->pclken,
1552 #else
1553 (clock_control_subsys_t)ð_cfg->pclken_ptp,
1554 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1555 &ptp_hclk_rate);
1556 if (ret) {
1557 LOG_ERR("Failed to query ethernet clock");
1558 return -EIO;
1559 }
1560
1561 /* Program the subsecond increment register based on the PTP clock freq */
1562 if (NSEC_PER_SEC % CONFIG_ETH_STM32_HAL_PTP_CLOCK_SRC_HZ != 0) {
1563 LOG_ERR("PTP clock period must be an integer nanosecond value");
1564 return -EINVAL;
1565 }
1566 ss_incr_ns = NSEC_PER_SEC / CONFIG_ETH_STM32_HAL_PTP_CLOCK_SRC_HZ;
1567 if (ss_incr_ns > UINT8_MAX) {
1568 LOG_ERR("PTP clock period is more than %d nanoseconds", UINT8_MAX);
1569 return -EINVAL;
1570 }
1571 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1572 heth->Instance->MACSSIR = ss_incr_ns << ETH_MACMACSSIR_SSINC_Pos;
1573 #else
1574 heth->Instance->PTPSSIR = ss_incr_ns;
1575 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1576
1577 /* Program timestamp addend register */
1578 eth_dev_data->clk_ratio =
1579 ((double)CONFIG_ETH_STM32_HAL_PTP_CLOCK_SRC_HZ) / ((double)ptp_hclk_rate);
1580 /*
1581 * clk_ratio is a ratio between desired PTP clock frequency and HCLK rate.
1582 * Because HCLK is defined by a physical oscillator, it might drift due
1583 * to manufacturing tolerances and environmental effects (e.g. temperature).
1584 * clk_ratio_adj compensates for such inaccuracies. It starts off as 1.0
1585 * and gets adjusted by calling ptp_clock_stm32_rate_adjust().
1586 */
1587 eth_dev_data->clk_ratio_adj = 1.0f;
1588 addend_val =
1589 UINT32_MAX * eth_dev_data->clk_ratio * eth_dev_data->clk_ratio_adj;
1590 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1591 heth->Instance->MACTSAR = addend_val;
1592 heth->Instance->MACTSCR |= ETH_MACTSCR_TSADDREG;
1593 while (heth->Instance->MACTSCR & ETH_MACTSCR_TSADDREG_Msk) {
1594 k_yield();
1595 }
1596 #else
1597 heth->Instance->PTPTSAR = addend_val;
1598 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSARU;
1599 while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSARU_Msk) {
1600 k_yield();
1601 }
1602 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1603
1604 /* Enable fine timestamp correction method */
1605 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1606 heth->Instance->MACTSCR |= ETH_MACTSCR_TSCFUPDT;
1607 #else
1608 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSFCU;
1609 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1610
1611 /* Enable nanosecond rollover into a new second */
1612 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1613 heth->Instance->MACTSCR |= ETH_MACTSCR_TSCTRLSSR;
1614 #else
1615 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSSR;
1616 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1617
1618 /* Initialize timestamp */
1619 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet)
1620 heth->Instance->MACSTSUR = 0;
1621 heth->Instance->MACSTNUR = 0;
1622 heth->Instance->MACTSCR |= ETH_MACTSCR_TSINIT;
1623 while (heth->Instance->MACTSCR & ETH_MACTSCR_TSINIT_Msk) {
1624 k_yield();
1625 }
1626 #else
1627 heth->Instance->PTPTSHUR = 0;
1628 heth->Instance->PTPTSLUR = 0;
1629 heth->Instance->PTPTSCR |= ETH_PTPTSCR_TSSTI;
1630 while (heth->Instance->PTPTSCR & ETH_PTPTSCR_TSSTI_Msk) {
1631 k_yield();
1632 }
1633 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_ethernet) */
1634
1635 #if defined(CONFIG_ETH_STM32_HAL_API_V2)
1636 /* Set PTP Configuration done */
1637 heth->IsPtpConfigured = ETH_STM32_PTP_CONFIGURED;
1638 #endif
1639
1640 return 0;
1641 }
1642
1643 DEVICE_DEFINE(stm32_ptp_clock_0, PTP_CLOCK_NAME, ptp_stm32_init,
1644 NULL, &ptp_stm32_0_context, NULL, POST_KERNEL,
1645 CONFIG_ETH_STM32_HAL_PTP_CLOCK_INIT_PRIO, &api);
1646
1647 #endif /* CONFIG_PTP_CLOCK_STM32_HAL */
1648