1+ /* Copyright (c) 2025 Jamie Smith
2+ * SPDX-License-Identifier: Apache-2.0
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ #pragma once
18+
19+ #include " device.h"
20+ #include " CompositeEMAC.h"
21+ #include " MbedCRC.h"
22+
23+ // Figure out the Ethernet IP version in use
24+ #ifdef TARGET_STM32H5 || TARGET_STM32H7
25+ #define ETH_IP_VERSION_V2
26+ #else
27+ #define ETH_IP_VERSION_V1
28+ #endif
29+
30+ namespace mbed
31+ {
32+ constexpr auto MDIO_TRANSACTION_TIMEOUT = std::chrono::milliseconds(1 ); // used by STMicro HAL
33+
34+ inline constexpr size_t NUM_PERFECT_FILTER_REGS = 3 ;
35+ static const std::pair<volatile uint32_t *, volatile uint32_t *> MAC_ADDR_PERF_FILTER_REGS[NUM_PERFECT_FILTER_REGS] = {
36+ {Ð->MACA1HR , Ð->MACA1LR },
37+ {Ð->MACA2HR , Ð->MACA2LR },
38+ {Ð->MACA3HR , Ð->MACA3LR }
39+ };
40+
41+ // / Write a MAC address into the given registers with the needed encoding
42+ static inline void writeMACAddress (const CompositeEMAC::MACAddress & mac, volatile uint32_t *addrHighReg, volatile uint32_t *addrLowReg)
43+ {
44+ /* Set MAC addr bits 32 to 47 */
45+ *addrHighReg = (static_cast <uint32_t >(mac[5 ]) << 8 ) | static_cast <uint32_t >(mac[4 ]) | ETH_MACA1HR_AE_Msk;
46+ /* Set MAC addr bits 0 to 31 */
47+ *addrLowReg = (static_cast <uint32_t >(mac[3 ]) << 24 ) | (static_cast <uint32_t >(mac[2 ]) << 16 ) |
48+ (static_cast <uint32_t >(mac[1 ]) << 8 ) | static_cast <uint32_t >(mac[0 ]);
49+ }
50+
51+ // / Add a MAC address to the multicast hash filter.
52+ void addHashFilterMAC (ETH_TypeDef * base, const CompositeEMAC::MACAddress & mac) {
53+ #if defined(ETH_IP_VERSION_V2)
54+ uint32_t volatile * hashRegs[] = {
55+ &base->MACHT0R ,
56+ &base->MACHT1R
57+ };
58+ #else
59+ uint32_t volatile * hashRegs[] = {
60+ &base->MACHTLR ,
61+ &base->MACHTHR
62+ };
63+ #endif
64+
65+ // Note: as always, the datasheet description of how to do this CRC was vague and slightly wrong.
66+ // This forum thread figured it out: https://community.st.com/t5/stm32-mcus-security/calculating-ethernet-multicast-filter-hash-value/td-p/416984
67+ // What the datasheet SHOULD say is:
68+ // Compute the Ethernet CRC-32 of the MAC address, with initial value of 1s, final XOR of ones, and input reflection on but output reflection off
69+ // Then, take the upper 6 bits and use that to index the hash table.
70+
71+ mbed::MbedCRC<POLY_32BIT_ANSI> crcCalc (0xFFFFFFFF , 0xFFFFFFFF , true , false );
72+
73+ // Compute Ethernet CRC-32 of the MAC address
74+ uint32_t crc;
75+ crcCalc.compute (mac.data (), mac.size (), &crc);
76+
77+ // Take upper 6 bits
78+ uint32_t hashVal = crc >> 26 ;
79+
80+ // Set correct bit in hash filter
81+ *hashRegs[hashVal >> 5 ] |= (1 << (hashVal & 0x1F ));
82+ }
83+
84+ }
0 commit comments