diff --git a/connectivity/drivers/emac/CMakeLists.txt b/connectivity/drivers/emac/CMakeLists.txt index 109a35bb0fa..fdedde4c50e 100644 --- a/connectivity/drivers/emac/CMakeLists.txt +++ b/connectivity/drivers/emac/CMakeLists.txt @@ -5,7 +5,12 @@ if(NOT "DEVICE_EMAC=1" IN_LIST MBED_TARGET_DEFINITIONS) return() endif() -add_library(mbed-emac STATIC EXCLUDE_FROM_ALL) +add_library(mbed-emac STATIC EXCLUDE_FROM_ALL + sources/CompositeEMAC.cpp + sources/GenericEthPhy.cpp + sources/PhyDrivers.cpp) + +target_include_directories(mbed-emac PUBLIC include) if("ARM_FM" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_ARM_FM) diff --git a/connectivity/drivers/emac/CompositeEMAC.md b/connectivity/drivers/emac/CompositeEMAC.md new file mode 100644 index 00000000000..fe459ee9bd6 --- /dev/null +++ b/connectivity/drivers/emac/CompositeEMAC.md @@ -0,0 +1,234 @@ +# Composite EMAC + +The original Mbed OS EMAC API was added in Mbed OS 5.9. That API grouped all EMAC functionality into a single abstract class that targets/vendors had to implement, the `EMAC` class. Since then, dozens of Mbed targets have received EMAC drivers, and the strengths and weaknesses of this API have become clear. The general structure is good, and the idea of abstracting the memory manager and the network stack from the EMAC driver works well. + +However, the [EMAC interface](https://github.com/mbed-ce/mbed-os/blob/0553c111850997d847dc6a3189ac0b7048304e57/connectivity/netsocket/include/netsocket/EMAC.h#L33) is difficult to implement, especially for people not intimately familiar with Mbed and its IP stacks. It requires EMAC implementations to implement the specifics of memory management, MAC address tracking, and DMA ring usage themselves, even though quite a bit of this logic is common to all MAC drivers. This has led to duplicated code, and quite often to half-assed code as well as chip vendors have struggled to conform to the (in some ways not very well defined) EMAC API. + +Couple that with inconsistent testing, and you have a recipe for inconsistent and buggy Ethernet drivers across the breadth of Mbed devices. For instance, Mbed supports zero-copy EMACs, where buffers can be passed directly to and from the Ethernet peripheral without being copied. This saves both memory and CPU time. However, this was only ever implemented for a few targets, because it's very difficult to get right. Even more egregiously, the EMAC driver implemented for STM32H7 for the past 6+ years has ignored the memory manager API and used LwIP directly, making it impossible to even test it with the EMAC tests (and hoo boy, were there a lot of things that would have failed). For extra fun, this driver also ignored the DMA functionality and sent packets _synchronously_, meaning the application is blocked while a packet is being transmitted! + +To address this situation, Mbed CE is implementing a new layer in the EMAC driver stack: CompositeEMAC. CompositeEMAC is a class which implements the `EMAC` API and breaks up the functionality into several subclasses. + +![Overview diagram](./doc/cemac-overview.svg) + +By implementing these four subclasses for each target MCU and board, high-performance Ethernet can be ported to any Mbed target much more easily than before. + +## Embedded Ethernet - An Overview + +Before we can get into the details of how CompositeEMAC works, we need to go over how embedded Ethernet works in general. + +![Embedded Ethernet diagram](./doc/embedded-ethernet.svg) + +To run an ethernet connection, two chips need to work together*: the microcontroller and an external Ethernet PHY (PHYsical layer transceiver) chip. The microcontroller sends and receives logic level Ethernet packets, while the PHY transforms those into Ethernet signals, which are decidedly *not* logic level (and actually have a lot in common with radio signals). The Ethernet signals, called MDI (Media Dependent Interface) pairs, are sent through an isolation transformer, which removes common mode interference and provides electrical isolation (e.g. so that the two ends of the connection can have different ground voltage levels). Then, they go into the ethernet jack and across the ethernet cable to the link partner! + +The PHY and the MCU are connected via a standard called [Reduced Media Independent Interface](https://en.wikipedia.org/wiki/Media-independent_interface#RMII) (RMII), which transfers the Ethernet packets as serialized bytes. This is an 8-wire bus with a 50MHz clock, four receive lines, and three transmit lines. The clock is traditionally either supplied by the PHY or by a dedicated clock generator chip, though some MCUs support supplying this clock as well. In addition to RMII, there's also a two-wire command and control bus called [Management Data IO](https://en.wikipedia.org/wiki/Management_Data_Input/Output) (MDIO) (though it can also be referred to Station Management Interface (SMI) or even "MiiM" for some reason). MDIO is used for talking directly to the PHY, not for sending Ethernet packets. MDIO is an open-drain bus similar to I2C, but with 16-bit words instead of bytes and a specific frame format (referred to as "Clause 22"). Unlike RMII, MDIO is a multi-drop bus, so you can actually connect up to 15 PHYs or other devices to one set of MDIO lines as long as they have different addresses! + +Inside the microcontroller, the bridge between the CPU and Ethernet is a peripheral called the Ethernet MAC. MAC stands for "Media Access Control" and refers to the second layer of the Ethernet protocol stack, the logic which encodes Ethernet packets and decides when to send them across the wire. The MAC has a number of moving parts inside, which are shown in the diagram above. The simplest is the block of configuration registers, which is accessible at a specific memory address and sets up operation of the MAC (e.g. what MAC addresses the hardware should accept and which checksums should be inserted/checked by the MAC). There is also an MDIO master interface, which controls the MDIO lines to talk to the PHY. And then, we have the DMA. + +Every Ethernet MAC I've seen also has DMA functionality. This means that the Ethernet peripheral can transmit and receive packets without direct CPU intervention. This is very important because it means your device can hit high network speeds without needing to have your CPU blocked for lots of time waiting on Ethernet packets to move through the hardware! For transmit, there will be a Tx DMA module which fetches data from the main RAM, and then enqueues the packet bytes plus control information into a FIFO (which is usually at least a couple thousand bytes long). Then, another block in the MAC, sometimes called the MTL (MAC Translation Layer) takes these bytes, applies any needed Ethernet framing, and shifts them out of the RMII Tx port. + +For reception, the process works the same but in reverse: the decoder and shifter block takes in packets and enqueues their bytes into the Rx FIFO. Then, the Rx DMA dequeues the packets and stores them into RAM at the right location. + +How does the DMA know where in RAM to read and write packets, though? On every embedded MAC I have seen so far, this is done through a ring of "DMA descriptors". Here's a diagram (that I stole from the STM32F2 datasheet): + +![DMA descriptor ring](doc/stm32f2-eth-dma-descriptors.png) + +A descriptor is a structure in memory that contains control information and one or more pointers to memory buffers (which contain the actual packet data). For Tx, the DMA will fetch the descriptor, then transmit the data in the buffers. For Rx, the DMA will fetch the descriptor, then write the packet to the descriptor's buffers. Either way, when the MAC is done with the descriptor, the DMA will write back status information (e.g. whether the checksum passed, or what timestamp the packet was sent at) to the descriptor, set a "done" flag, and then interrupt the CPU to tell it it has something to process. + +But we don't want the DMA to have to wait for the CPU, do we? To avoid this, each descriptor also specifies a "next descriptor", either via an offset or a pointer. The DMA can move to this next descriptor and start processing it right away to send or receive the next packet. The CPU will process the completed descriptor on its own time and give it back to the DMA. In this manner, as long as your ring of descriptors is big enough and your CPU can keep up with the processing them, the CPU and MAC never have to wait for each other! + +## Components of the Composite EMAC +Now that we've covered how an EMAC works in hardware, we can talk through how CompositeEMAC works, and what needs to be implemented for each MCU target. + +### MAC Driver + +The MAC driver (which must be implemented as a subclass of `CompositeEMAC::MACDriver`) is usually fairly simple. It provides an interface between Mbed and the MAC's configuration register block and MDIO master interface. Its responsibilities include: +- Initializing and muxing the RMII and MDIO pins +- Initializing all needed clocks +- Configuring all settings needed for MAC operation +- Configuring the unicast MAC address (as in, the MAC address that the device uses on the network) +- Adding and removing multicast subscriptions +- Configuring interrupts +- Talking to the PHY over MDIO + +### PHY Driver + +The PHY driver must be a subclass of `CompositeEMAC::PHYDriver`. It must: +- Confirm the existence of the PHY chip and initialize it +- Configure the selected Ethernet settings (autonegotiation, speed, duplex) into the PHY +- Check if link has been established and, if so, what kind + +Unlike the MAC driver and the DMA, the PHY driver does not need to be subclassed for each target device. Thankfully, the Ethernet standard imposes some order on the chaotic sea of PHY parts, and it mandates that the lower 16 registers are standardized and must work the same way on each part. Using this standard behavior, we have implemented the `mbed::GenericEthPhy` class, which should function as a driver for any 802.3u standard compliant PHY. All it needs is configuration, like the PHY's part number and its address on the MDIO bus. When porting to a new target, all you need to do is indicate the PHY model in `mbed-os/connectivity/netsocket/mbed_lib.json` like so: + +```json5 +"MY_TARGET": { + "nsapi.emac-phy-model": "LAN8742", + "nsapi.emac-phy-mdio-address": 0 +} +``` + +This will work out of the box, as long as `LAN8742` names a PHY driver defined in PhyDrivers.cpp. Individual PHY models will generally need their own drivers, since often PHYs have errata that need to be worked around or need other configuration that isn't defined in the standard. However, GenericEthPhy allows implementing the absolute minimum amount of logic per-phy as possible! + +Since user boards may want to use a different ethernet PHY, the driver can be customized in an application by overriding the `mbed::get_eth_phy_driver` weak function to return a different driver class. This might look something like + +```c++ +namespace MY_PHY { +inline constexpr GenericEthPhy::Config Config = { + // These are found in the PHY datasheet. See GenericEthPhy::Config for documentation. + .OUI = 0x123, + .model = 0x45, + .address = 0, +}; + +class Driver : public GenericEthPhy { +public: + explicit Driver(GenericEthPhy::Config const & config = DefaultConfig): + GenericEthPhy(config) + {} + + // You may override/replace any functions of `GenericEthPhy` here +}; +} + +namespace mbed { +CompositeEMAC::PHYDriver * get_eth_phy_driver() +{ + static MY_PHY::Driver(MY_PHY::Config) phyDriver; + return &phyDriver; +} +} +``` + +### Tx DMA + +The Rx and Tx DMAs are implemented as their own driver classes, instead of in the MAC driver, as they are somewhat complicated and generally don't interact with the other pieces of the EMAC very much. To work with CompositeEMAC, the Tx DMA must be implemented as a subclass of `CompositeEMAC::TxDMA`. However, since the large majority of microcontrollers implement Tx DMA in a very similar way, the `GenericTxDMARing` class has been provided which provides most of the needed functionality. + +#### Generic Tx DMA Ring Operation + +`GenericTxDMARing` assumes the basics: there is a ring of descriptors which are processed in sequence. The Ethernet DMA may transmit a packet once it is marked as "owned by DMA" in the ring (usually via a bitfield in the descriptor). Once the packet is done transmitting, the Ethernet DMA gives it back to the application by clearing the own flag and delivering an interrupt. + +Mbed's generic Tx DMA ring driver uses two indexes to manage the ring of descriptors: `txSendIndex`, the index of the next Tx descriptor that can be filled with data, and `txReclaimIndex`, the index of the next descriptor that can be reclaimed by the driver. Together, these indexes, plus a count variable, describe the state of the descriptor ring. + +To explain how this works, let's go through an example of transmitting some packets via the descriptors. + +##### Initial State +When the driver starts, both indexes point to descriptor 0. No data is in the DMA ring. + +![Initial DMA ring state](doc/tx-ring-initial-state.svg) + + +##### Packet 0 Enqueued +Now suppose we enqueue a packet to be transmitted into the ring. The packet will go into desc 0, since that is where `txSendIndex` is pointing. The driver will give desc 0 to the DMA, so it will start being transmitted out of the Ethernet port. + +![DMA ring with packet 0](doc/tx-ring-step-1.svg) + +##### Packet 1 Enqueued +Now, very soon after the first packet, we enqueue another packet to be transmitted. This packet is split between two buffers (common when using zero-copy transmission), so it takes up two descriptors. These two descriptors are then given to the DMA to send. + +![DMA ring with packet 1](doc/tx-ring-step-2.svg) + +##### Packet 0 Completes +Soon after, the MAC completes the transmission of packet 0. It sets the DMA own flag in the descriptor back to false, and delivers a Tx interrupt to the application. The below picture shows the state of the descriptors when the interrupt fires. + +![DMA ring after packet 0 completes](doc/tx-ring-step-3.svg) + +##### After Packet 0 Tx Interrupt +The Tx interrupt* will detect that the descriptor pointed to by `txReclaimIndex` has completed. It can then deallocate the memory for Packet 0, collect any needed status information (e.g. the timestamp) from the descriptor, and advance `txReclaimIndex` forward. Last but not least, it sets a thread flag to unblock any threads which are waiting for a Tx descriptor in order to send a packet. + +![DMA ring after packet 0 deallocated](doc/tx-ring-step-4.svg) + +*Actually, interrupts cannot deallocate memory in Mbed, so the Tx interrupt handler actually signals the MAC thread to wake up and process the completed descriptor. + +##### Final State +Eventually, after a couple hundred microseconds, the second packet will be transmitted, and its descriptors will also be reclaimed. The Tx descriptor ring is now empty, except that the descriptor pointers are now both pointing to Desc 3. + +![DMA ring after packet 1 deallocated](doc/tx-ring-step-5.svg) + +Note that in most cases, once the ring is empty like this, the Tx DMA in the hardware will simply sit and wait until dmaOwn is set on Desc 3. However, this depends a bit on the hardware -- some MACs need an additional "poke" command to make them recheck the descriptor, and yet others simply need to be told which descriptor address to transmit once a new one is made available. + +##### Descriptor Exhaustion +You might notice a slight problem with the send and reclaim indexes, as described so far. When the Tx descriptor ring is totally full, they both end up pointing to the same descriptor: + +![DMA ring with all descs allocated](doc/tx-ring-exhausted.svg) + +This is a problem because, earlier, we said that the initial state of the DMA ring, with no packets enqueued, also has both indices pointing to the same descriptor. This might cause us to naively calculate that the descriptor ring is empty! + +This is a classic problem with circular FIFOs, and to solve it, we go for the classic solution. An additional count variable, `txDescsOwnedByApplication`, counts how many descriptors are known to be NOT owned by DMA. It's decremented each time we give a descriptor to DMA, and incremented each time we reclaim one back. We can then use this count variable to dis-ambiguate the situation where `txSendIndex == txReclaimIndex`. + +#### Target-Specific Tx DMA Implementation + +For each target, the `GenericTxDMARing` class needs to be extended. The subclass must provide a couple functions: + +- Allocating the actual DMA descriptors (since this often has special requirements on alignment or memory banks) +- Initializing and deinitializing the Tx DMA +- Checking the dmaOwn flag on a descriptor +- Checking if a given buffer address is accessible by the DMA controller (since, on many MCUs, certain areas of memory are not OK and the buffer will need to be copied) +- Giving a descriptor to DMA after populating it with a given buffer + +Everything else, including the descriptor tracking and memory management, is done by the superclass. This should let target implementations focus only on the low level descriptor format while relying on common code for everything else. + +### Rx DMA + +The Rx DMA works similarly to the Tx DMA. To instantiate a `CompositeEMAC`, you must provide an instance of `CompositeEMAC::RxDMA`. Mbed provides a generic superclass (`GenericRxDMARing`) which implements most of TxDMA, but must be extended for each target to add the last pieces of functionality. + +#### Generic Rx DMA Ring Operation + +Like the Tx DMA, the Rx DMA works using a descriptor ring and two indexes that track where we are in the descriptor ring. `rxNextIndex` tracks the next descriptor index that we expect the Ethernet DMA to receive into, while `rxBuildIndex` tracks the next descriptor that we are going to give back to the DMA when possible. + +##### Initial State + +Unlike the Tx DMA, the initial state of the Rx DMA ring is for all the descriptors to be given to DMA and have their buffer pointers populated with blank network stack buffers. This makes them all available for the MAC to receive into. + +![Rx ring initial state](doc/rx-ring-initial-state.svg) + +Note that, for now, we always leave one un-filled descriptor in the ring. This is needed because certain target ethernet MACs (e.g. STM32 Eth IP v2) cannot have every Rx descriptor enqueued at the same time or they get confused and think there are *no* Rx descs enqueued! So, for now, we always need to have one extra Rx desc in the ring. + +##### After Packet Rx + +Let's now see what it looks like after we receive a large Ethernet packet (1500 bytes). With the default setting for `nsapi.emac-rx-pool-buf-size`, each of the blank buffers is 592 bytes, so packets <= 592 bytes only need one buffer, while a 1500 byte packet needs three buffers. + +Slight tangent: We could set `nsapi.emac-rx-pool-buf-size` to >=1500 bytes so that each packet always fits in one descriptor, and this would make receiving large packets more efficient (in terms of CPU and descriptors used). However, this would mean we would need ~3x the RAM to allocate our 6 descriptor ring, and that extra RAM is wasted when we receive a small packet that only needs a fraction of that 1500 byte buffer. So, this setting is a tradeoff, and may be customized if you know you are dealing with only small or only large packets. + +Anyway, when the packet is received, the MAC will write it into the next three available descriptors, then clear the own flags and mark which descriptors contain the start and end of the packet. Then, it delievers an Rx ISR to the driver. This is the state of the DMA ring when the Rx ISR fires: + +![Rx ring after Rx](doc/rx-ring-after-rx.svg) + +##### Packet Dequeued + +The Rx ISR checks the DMA ring to make sure we have at least one complete packet. Then, it signals the MAC thread to dequeue the packet and pass it off to the IP stack. + +When the packet is dequeued, the buffers will be removed from the descriptors and, for now, they stay in the "owned by application" region of the descriptor ring (between `rxNextIndex` and `rxBuildIndex`). + +![Rx ring after dequeue](doc/rx-ring-after-dequeue.svg) + +##### Descriptors Rebuilt + +The final step is to "rebuild" the descriptors, which means attaching a fresh buffer* to them and giving them back to the DMA. This is done by the `rebuildDescriptors()` function, and basically keeps rebuilding descriptors until `rxBuildIndex` is one behind `rxNextIndex`, or until we run out of memory in the Rx memory pool. + +Ideally, we will immediately rebuild all the descriptors right after dequeuing the packet. However, if we don't have enough memory, we will rebuild the descs later when we do. + +Once the descriptors have been rebuilt, we will basically be back in the initial state, except moved three descriptors along the Rx ring. + +![Rx ring after rebuild](doc/rx-ring-after-rebuild.svg) + +*In most EMAC drivers, you would just copy the Rx packet out of the DMA buffer, then re-enqueue the descriptor without changing the buffer. However, since this is a zero-copy EMAC, we give the original DMA buffer to the network stack, so we then need to get a fresh buffer before we can re-enqueue the descriptor. + +##### Memory Exhaustion + +Running out of Rx pool memory is a problem for zero-copy Rx drivers in particular -- if the driver cannot rebuild an Rx descriptor when a packet is dequeued, it has to rebuild it at some later date. If this never happens, no reception can occur. + +Until CompositeEMAC was added, Mbed didn't have a good way to solve this problem. Some zero-copy drivers (e.g. LPC1768) would at least try and rebuild unbuilt descriptors the next time a packet was received, but none of them could handle the case where all Rx memory was exhausted -- there would be no built descriptors in the ring, so no packets could be received, and the MAC would be stuck forever. + +To solve this problem, the CompositeEMAC PR series added a new hook in both of the IP stacks for when a pool buffer is deallocated. This then triggers a callback to the memory manager, then to the MAC. This way, the MAC will know when Rx memory is available again and can unstick itself! + +#### Target-Specific Rx DMA Implementation + +For each target, the `GenericRxDMARing` class needs to be extended. The subclass must provide a couple functions: + +- Allocating the actual DMA descriptors (since this often has special requirements on alignment or memory banks) +- Initializing and deinitializing the Rx DMA +- Checking the dmaOwn flag on a descriptor +- Checking the flags (first, last, error) on a descriptor +- Getting the total length of a packet received into a series of descriptors +- Returning a rebuilt descriptor to the DMA controller, with a given buffer address + +Everything else, including the descriptor tracking and memory management, is done by the superclass. This should let target implementations focus only on the low level descriptor format while relying on common code for everything else. diff --git a/connectivity/drivers/emac/TARGET_STM/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/CMakeLists.txt index bc7b057676e..dc12b1d4cdb 100644 --- a/connectivity/drivers/emac/TARGET_STM/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/CMakeLists.txt @@ -9,6 +9,8 @@ elseif("STM32F7" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_STM32F7) elseif("STM32H7" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_STM32H7) +elseif("STM32H5" IN_LIST MBED_TARGET_LABELS) + add_subdirectory(TARGET_STM32H5) endif() target_include_directories(mbed-emac @@ -16,7 +18,19 @@ target_include_directories(mbed-emac . ) -target_sources(mbed-emac - PRIVATE - stm32xx_emac.cpp -) +if("STM32H7" IN_LIST MBED_TARGET_LABELS OR "STM32H5" IN_LIST MBED_TARGET_LABELS) + target_sources(mbed-emac + PRIVATE + STM32EthMACv2.cpp + ) +endif() + +if("STM32F2" IN_LIST MBED_TARGET_LABELS OR "STM32F4" IN_LIST MBED_TARGET_LABELS OR "STM32F7" IN_LIST MBED_TARGET_LABELS) + target_sources(mbed-emac + PRIVATE + STM32EthMACv1.cpp + ) +endif() + + +target_compile_options(mbed-emac PRIVATE -Wno-packed-bitfield-compat) diff --git a/connectivity/drivers/emac/TARGET_STM/STM32EthMACCommon.h b/connectivity/drivers/emac/TARGET_STM/STM32EthMACCommon.h new file mode 100644 index 00000000000..28d9e6b3e4c --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/STM32EthMACCommon.h @@ -0,0 +1,84 @@ +/* Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "device.h" +#include "CompositeEMAC.h" +#include "MbedCRC.h" + +// Figure out the Ethernet IP version in use +#if defined(TARGET_STM32H5) || defined(TARGET_STM32H7) +#define ETH_IP_VERSION_V2 +#else +#define ETH_IP_VERSION_V1 +#endif + +namespace mbed +{ +constexpr auto MDIO_TRANSACTION_TIMEOUT = std::chrono::milliseconds(1); // used by STMicro HAL + +inline constexpr size_t NUM_PERFECT_FILTER_REGS = 3; +static const std::pair MAC_ADDR_PERF_FILTER_REGS[NUM_PERFECT_FILTER_REGS] = { + {Ð->MACA1HR, Ð->MACA1LR}, + {Ð->MACA2HR, Ð->MACA2LR}, + {Ð->MACA3HR, Ð->MACA3LR} +}; + +/// Write a MAC address into the given registers with the needed encoding +static inline void writeMACAddress(const CompositeEMAC::MACAddress & mac, volatile uint32_t *addrHighReg, volatile uint32_t *addrLowReg) +{ + /* Set MAC addr bits 32 to 47 */ + *addrHighReg = (static_cast(mac[5]) << 8) | static_cast(mac[4]) | ETH_MACA1HR_AE_Msk; + /* Set MAC addr bits 0 to 31 */ + *addrLowReg = (static_cast(mac[3]) << 24) | (static_cast(mac[2]) << 16) | + (static_cast(mac[1]) << 8) | static_cast(mac[0]); +} + +/// Add a MAC address to the multicast hash filter. +void addHashFilterMAC(ETH_TypeDef * base, const CompositeEMAC::MACAddress & mac) { +#if defined(ETH_IP_VERSION_V2) + uint32_t volatile * hashRegs[] = { + &base->MACHT0R, + &base->MACHT1R + }; +#else + uint32_t volatile * hashRegs[] = { + &base->MACHTLR, + &base->MACHTHR + }; +#endif + + // Note: as always, the datasheet description of how to do this CRC was vague and slightly wrong. + // This forum thread figured it out: https://community.st.com/t5/stm32-mcus-security/calculating-ethernet-multicast-filter-hash-value/td-p/416984 + // What the datasheet SHOULD say is: + // 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 + // Then, take the upper 6 bits and use that to index the hash table. + + mbed::MbedCRC crcCalc(0xFFFFFFFF, 0xFFFFFFFF, true, false); + + // Compute Ethernet CRC-32 of the MAC address + uint32_t crc; + crcCalc.compute(mac.data(), mac.size(), &crc); + + // Take upper 6 bits + uint32_t hashVal = crc >> 26; + + // Set correct bit in hash filter + *hashRegs[hashVal >> 5] |= (1 << (hashVal & 0x1F)); +} + +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.cpp b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.cpp new file mode 100644 index 00000000000..a2cc5580c5c --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.cpp @@ -0,0 +1,559 @@ +/* Copyright (c) 2025 Jamie Smith +* SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "STM32EthMACv1.h" +#include "STM32EthMACCommon.h" + +#include +#include +#include +#include "mbed_error.h" +#include "mbed_events.h" +#include "CriticalSectionLock.h" + +#define TRACE_GROUP "STEMACv1" + +using namespace std::chrono_literals; + +// Defined in stm32_eth_init.c +extern "C" void EthInitPinmappings(); +extern "C" void EthDeinitPinmappings(); +extern "C" PinName EthGetPhyResetPin(); + +namespace mbed { +void STM32EthMACv1::TxDMA::startDMA() { + // Zero all the Tx descriptors + memset(txDescs.data(), 0, sizeof(stm32_ethv1::TxDescriptor) * TX_NUM_DESCS); + + // Set the end-of-ring bit on the last descriptor + txDescs[TX_NUM_DESCS - 1].endOfRing = true; + + // Set descriptor list address register + base->DMATDLAR = reinterpret_cast(&txDescs[0]); + + // Start Tx DMA + base->DMAOMR |= ETH_DMAOMR_ST_Msk; +} + +void STM32EthMACv1::TxDMA::stopDMA() { + base->DMAOMR &= ~ETH_DMAOMR_ST_Msk; +} + +#if __DCACHE_PRESENT +void STM32EthMACv1::TxDMA::cacheInvalidateDescriptor(const size_t descIdx) { + SCB_InvalidateDCache_by_Addr(&txDescs[descIdx], sizeof(stm32_ethv1::TxDescriptor)); +} +#endif + +bool STM32EthMACv1::TxDMA::descOwnedByDMA(size_t descIdx) { + return txDescs[descIdx].dmaOwn; +} + +bool STM32EthMACv1::TxDMA::isDMAReadableBuffer(uint8_t const *start, size_t size) const { +#ifdef TARGET_STM32F7 + if(bufferTouchesMemoryBank(start, size, 0, 1024*16)) { + // In ITCM memory, not accessible by DMA. Note that ITCM is not included in the CMSIS memory map (yet). + return false; + } +#endif + +#if TARGET_STM32F2 || TARGET_STM32F4 + // On STM32F2 and F2, ethernet DMA cannot access the flash memory. + if(bufferTouchesMemoryBank(start, size, MBED_ROM_START, MBED_ROM_SIZE)) { + return false; + } +#endif + + return true; +} + +void STM32EthMACv1::TxDMA::giveToDMA(size_t descIdx, uint8_t const *buffer, size_t len, bool firstDesc, bool lastDesc) { + // Configure descriptor with buffer and size + txDescs[descIdx].buffer1 = buffer; + txDescs[descIdx].buffer1Size = len; + txDescs[descIdx].firstSegment = firstDesc; + txDescs[descIdx].lastSegment = lastDesc; + txDescs[descIdx].intrOnComplete = true; + + // Return to DMA + txDescs[descIdx].dmaOwn = true; + + // Flush back to main memory +#ifdef __DCACHE_PRESENT + SCB_CleanDCache_by_Addr(&txDescs[descIdx], sizeof(stm32_ethv1::TxDescriptor)); +#else + __DMB(); // Make sure descriptor is written before the below lines +#endif + + // Clear buffer unavailable flag (I think this is for information only though) + base->DMASR = ETH_DMASR_TBUS_Msk; + + // Demand (good sir!) a Tx descriptor poll + base->DMATPDR = 1; +} + +void STM32EthMACv1::RxDMA::startDMA() { + + // Rx buffer size must be a multiple of 4, per the descriptor definition + MBED_ASSERT(rxPoolPayloadSize % sizeof(uint32_t) == 0); + + // Zero all the Rx descriptors + memset(rxDescs.data(), 0, sizeof(stm32_ethv1::RxDescriptor) * RX_NUM_DESCS); + + // Set the end-of-ring bit on the last descriptor + rxDescs[RX_NUM_DESCS - 1].endOfRing = true; + + // Set descriptor list address register + base->DMARDLAR = reinterpret_cast(&rxDescs[0]); + + // Start Rx DMA + base->DMAOMR |= ETH_DMAOMR_SR_Msk; +} + +void STM32EthMACv1::RxDMA::stopDMA() { + base->DMAOMR &= ~ETH_DMAOMR_SR_Msk; +} + +#if __DCACHE_PRESENT +void STM32EthMACv1::RxDMA::cacheInvalidateDescriptor(const size_t descIdx) { + SCB_InvalidateDCache_by_Addr(&rxDescs[descIdx], sizeof(stm32_ethv1::RxDescriptor)); +} +#endif + +bool STM32EthMACv1::RxDMA::descOwnedByDMA(const size_t descIdx) { + return rxDescs[descIdx].dmaOwn; +} + +bool STM32EthMACv1::RxDMA::isFirstDesc(const size_t descIdx) { + return rxDescs[descIdx].firstDescriptor; +} + +bool STM32EthMACv1::RxDMA::isLastDesc(const size_t descIdx) { + return rxDescs[descIdx].lastDescriptor; +} + +bool STM32EthMACv1::RxDMA::isErrorDesc(const size_t descIdx) { + return rxDescs[descIdx].errSummary; +} + +void STM32EthMACv1::RxDMA::returnDescriptor(const size_t descIdx, uint8_t *buffer) +{ + // Configure descriptor + rxDescs[descIdx].buffer1 = buffer; + rxDescs[descIdx].buffer1Size = rxPoolPayloadSize; + rxDescs[descIdx].dmaOwn = true; + + // Flush back to main memory +#ifdef __DCACHE_PRESENT + SCB_CleanDCache_by_Addr(&rxDescs[descIdx], sizeof(stm32_ethv1::RxDescriptor)); +#else + __DMB(); // Make sure descriptor is written before the below lines +#endif + + // Clear buffer unavailable flag (I think this is for information only though) + base->DMASR = ETH_DMASR_RBUS_Msk; + + // Demand (good sir!) an Rx descriptor poll + base->DMARPDR = 1; +} + +size_t STM32EthMACv1::RxDMA::getTotalLen(const size_t firstDescIdx, const size_t lastDescIdx) { + // Total length of the packet is in the last descriptor + return rxDescs[lastDescIdx].frameLen; +} + +void STM32EthMACv1::MACDriver::ETH_SetMDIOClockRange(ETH_TypeDef * const base) { + /* Get the ETHERNET MACMIIAR value */ + uint32_t tempreg = base->MACMIIAR; + /* Clear CSR Clock Range CR[2:0] bits */ + tempreg &= ETH_MACMIIAR_CR_Msk; + + /* Get hclk frequency value */ + uint32_t hclk = HAL_RCC_GetHCLKFreq(); + + /* Set CR bits depending on hclk value */ + if((hclk >= 20000000)&&(hclk < 35000000)) + { + /* CSR Clock Range between 20-35 MHz */ + tempreg |= (uint32_t)ETH_MACMIIAR_CR_Div16; + } + else if((hclk >= 35000000)&&(hclk < 60000000)) + { + /* CSR Clock Range between 35-60 MHz */ + tempreg |= (uint32_t)ETH_MACMIIAR_CR_Div26; + } + else if((hclk >= 60000000)&&(hclk < 100000000)) + { + /* CSR Clock Range between 60-100 MHz */ + tempreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; + } + else if((hclk >= 100000000)&&(hclk < 150000000)) + { + /* CSR Clock Range between 100-150 MHz */ + tempreg |= (uint32_t)ETH_MACMIIAR_CR_Div62; + } +#ifdef ETH_MACMIIAR_CR_Div102 + else if((hclk >= 150000000)&&(hclk <= 216000000)) + { + /* CSR Clock Range between 150-216 MHz */ + tempreg |= (uint32_t)ETH_MACMIIAR_CR_Div102; + } +#endif + else { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_ETHERNET, EIO), \ + "STM32 EMAC v1: Unsupported HCLK range\n"); + } + + /* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */ + base->MACMIIAR = (uint32_t)tempreg; + } + +#if ENABLE_ERRATA_2_21_6_WORKAROUND +void STM32EthMACv1::MACDriver::rmiiWatchdog() { + // mbed_event_queue() is not ISR safe, so get the pointer before entering the critical section + auto * const equeue = mbed_event_queue(); + + CriticalSectionLock lock; + + if(!rmiiWatchdogRunning) { + // Already canceled by main thread, bail + return; + } + + /* some good packets are received */ + if (base->MMCRGUFCR > 0) { + /* RMII Init is OK - cancel watchdog task */ + equeue->cancel(rmiiWatchdogHandle); + rmiiWatchdogRunning = false; + } else if (base->MMCRFCECR > 10) { + /* ETH received too many packets with CRC errors, resetting RMII */ + SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL; + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; + base->MMCCR |= ETH_MMCCR_CR; + } +} +#endif + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::init() { + sleep_manager_lock_deep_sleep(); + + // Note: Following code is based on HAL_Eth_Init() from the HAL + + /* Enable SYSCFG Clock */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + /* Select RMII Mode*/ + SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; + + /* Init the low level hardware : GPIO, CLOCK, NVIC. */ + EthInitPinmappings(); + + /* Ethernet Software reset */ + /* Set the SWR bit: resets all MAC subsystem internal registers and logic */ + /* After reset all the registers holds their respective reset values */ + base->DMABMR |= ETH_DMABMR_SR; + + const auto ETH_SW_RESET_TIMEOUT = 500us; // used by STM32 HAL + Timer timeoutTimer; + timeoutTimer.start(); + while(timeoutTimer.elapsed_time() < ETH_SW_RESET_TIMEOUT && (base->DMABMR & ETH_DMABMR_SR)) {} + if(base->DMABMR & ETH_DMABMR_SR) { + // Reset failed to complete within expected timeout. + // Note: This is usually because of a missing RMII clock from the PHY. + return ErrCode::TIMEOUT; + } + + // Configure MDIO clock + ETH_SetMDIOClockRange(base); + + // Configure MAC settings + base->MACCR |= (1 << 25); // Strip CRC from frames. CSTF bit definition missing from CMSIS header for some reason? + base->MACFFR = ETH_MACFFR_HPF_Msk | ETH_MACFFR_HM_Msk; // Use perfect and hash filters for multicast + + // Configure DMA settings. Default STM32CubeHAL settings used. + base->DMAOMR = ETH_DMAOMR_RSF_Msk | + ETH_DMAOMR_TSF_Msk; + + base->DMABMR = ETH_DMABMR_AAB_Msk | + ETH_DMABMR_USP_Msk | + ETH_DMABMR_RDP_32Beat | + ETH_DMABMR_FB_Msk | + ETH_DMABMR_PBL_32Beat | + ETH_DMABMR_EDE_Msk; + + // Set up interrupt handler + NVIC_SetVector(ETH_IRQn, reinterpret_cast(&STM32EthMACv1::irqHandler)); + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); + + // Enable Tx, Rx, and fatal bus error interrupts. + // However, don't enable receive buffer unavailable interrupt, because that can + // trigger if we run out of Rx descriptors, and we don't want to fatal error + // in that case. + base->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE | ETH_DMAIER_FBEIE | ETH_DMAIER_AISE; + +#if ENABLE_ERRATA_2_21_6_WORKAROUND + // Start RMII watchdog task + rmiiWatchdogHandle = mbed_event_queue()->call_every(std::chrono::milliseconds(MBED_CONF_NSAPI_EMAC_PHY_POLL_PERIOD), + callback(this, &STM32EthMACv1::MACDriver::rmiiWatchdog)); + rmiiWatchdogRunning = true; +#endif + + return CompositeEMAC::ErrCode::SUCCESS; +} + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::deinit() { + // Disable interrupt + HAL_NVIC_DisableIRQ(ETH_IRQn); + +#if ENABLE_ERRATA_2_21_6_WORKAROUND + // Disable RMII watchdog if still running + if(rmiiWatchdogRunning) { + // mbed_event_queue() is not ISR safe, so get the pointer before entering the critical section + auto * const equeue = mbed_event_queue(); + + CriticalSectionLock lock; + if(rmiiWatchdogRunning) { // Recheck flag inside critical section + equeue->cancel(rmiiWatchdogHandle); + rmiiWatchdogRunning = false; + } + } +#endif + + // Unlock deep sleep + sleep_manager_unlock_deep_sleep(); + + // Unmap pins and turn off clock + EthDeinitPinmappings(); + + return ErrCode::SUCCESS; +} + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::enable(LinkSpeed speed, Duplex duplex) { + if(speed == LinkSpeed::LINK_1GBIT) { + return ErrCode::INVALID_ARGUMENT; + } + + auto maccrVal = base->MACCR; + if(speed == LinkSpeed::LINK_100MBIT) { + maccrVal |= ETH_MACCR_FES_Msk; + } + else { + maccrVal &= ~ETH_MACCR_FES_Msk; + } + if(duplex == Duplex::FULL) { + maccrVal |= ETH_MACCR_DM_Msk; + } + else { + maccrVal &= ~ETH_MACCR_DM_Msk; + } + + // Enable the MAC transmission & reception + maccrVal |= ETH_MACCR_TE | ETH_MACCR_RE; + base->MACCR = maccrVal; + return ErrCode::SUCCESS; +} + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::disable() { + base->MACCR &= ~(ETH_MACCR_TE | ETH_MACCR_RE); + + // Note: Don't flush Tx FIFO because of STM32F7 errata 2.21.3, which can cause + // the MAC to get stuck if the Tx FIFO is flushed at the wrong time + + return ErrCode::SUCCESS; +} + +void STM32EthMACv1::MACDriver::setOwnMACAddr(const MACAddress &ownAddress) { + // Set MAC address + writeMACAddress(ownAddress, &base->MACA0HR, &base->MACA0LR); +} + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::mdioRead(uint8_t devAddr, uint8_t regAddr, uint16_t &result) { + // This code based on HAL_ETH_ReadPHYRegister() + if(base->MACMIIAR & ETH_MACMIIAR_MB_Msk) { + // MDIO operation already in progress + return ErrCode::INVALID_USAGE; + } + + uint32_t tmpreg = base->MACMIIAR; + + /* Prepare the MDIO Address Register value + - Set the PHY device address + - Set the PHY register address + - Set the read mode + - Set the MII Busy bit */ + tmpreg &= ~(ETH_MACMIIAR_MW_Msk | ETH_MACMIIAR_PA_Msk | ETH_MACMIIAR_MR_Msk); + tmpreg |= (devAddr << ETH_MACMIIAR_PA_Pos) | (regAddr << ETH_MACMIIAR_MR_Pos) | ETH_MACMIIAR_MB_Msk; + base->MACMIIAR = tmpreg; + + Timer timeoutTimer; + timeoutTimer.start(); + while(timeoutTimer.elapsed_time() < MDIO_TRANSACTION_TIMEOUT && (base->MACMIIAR & ETH_MACMIIAR_MB_Msk)) {} + if(base->MACMIIAR & ETH_MACMIIAR_MB_Msk) { + // Transaction failed to complete within expected timeout + return ErrCode::TIMEOUT; + } + + // Get result + result = base->MACMIIDR; + + tr_debug("MDIO read devAddr %" PRIu8 ", regAddr 0x%" PRIx8 " -> 0x%" PRIx16, devAddr, regAddr, result); + + return ErrCode::SUCCESS; +} + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::mdioWrite(uint8_t devAddr, uint8_t regAddr, uint16_t data) { + // This code based on HAL_ETH_WritePHYRegister() + if(base->MACMIIAR & ETH_MACMIIAR_MB_Msk) { + // MDIO operation already in progress + return ErrCode::INVALID_USAGE; + } + + /* Give the value to the MII data register */ + base->MACMIIDR = data; + + uint32_t tmpreg = base->MACMIIAR; + + /* Prepare the MDIO Address Register value + - Set the PHY device address + - Set the PHY register address + - Set the write mode + - Set the MII Busy bit */ + tmpreg &= ~(ETH_MACMIIAR_MW_Msk | ETH_MACMIIAR_PA_Msk | ETH_MACMIIAR_MR_Msk); + tmpreg |= (devAddr << ETH_MACMIIAR_PA_Pos) | (regAddr << ETH_MACMIIAR_MR_Pos) | ETH_MACMIIAR_MB_Msk | ETH_MACMIIAR_MW_Msk; + base->MACMIIAR = tmpreg; + + Timer timeoutTimer; + timeoutTimer.start(); + while(timeoutTimer.elapsed_time() < MDIO_TRANSACTION_TIMEOUT && (base->MACMIIAR & ETH_MACMIIAR_MB_Msk)) {} + if(base->MACMIIAR & ETH_MACMIIAR_MB_Msk) { + // Transaction failed to complete within expected timeout + return ErrCode::TIMEOUT; + } + + tr_debug("MDIO write devAddr %" PRIu8 ", regAddr 0x%" PRIx8 " <- 0x%" PRIx16, devAddr, regAddr, data); + + return ErrCode::SUCCESS; +} + +PinName STM32EthMACv1::MACDriver::getPhyResetPin() { + return EthGetPhyResetPin(); +} + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::addMcastMAC(MACAddress mac) { + if(numPerfectFilterRegsUsed < NUM_PERFECT_FILTER_REGS) { + size_t perfFiltIdx = numPerfectFilterRegsUsed; + ++numPerfectFilterRegsUsed; + + tr_debug("Using perfect filtering for %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + writeMACAddress(mac, MAC_ADDR_PERF_FILTER_REGS[perfFiltIdx].first, MAC_ADDR_PERF_FILTER_REGS[perfFiltIdx].second); + } + else { + // Out of spaces in perfect filter, use hash filter instead + tr_debug("Using hash filtering for %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + addHashFilterMAC(base, mac); + } + return ErrCode::SUCCESS; +} + +CompositeEMAC::ErrCode STM32EthMACv1::MACDriver::clearMcastFilter() { + // Reset perfect filter registers + for(auto regPair : MAC_ADDR_PERF_FILTER_REGS) { + *regPair.first = 0; + *regPair.second = 0; + } + numPerfectFilterRegsUsed = 0; + + // Reset hash filter + base->MACHTLR = 0; + base->MACHTHR = 0; + + return ErrCode::SUCCESS; +} + +void STM32EthMACv1::MACDriver::setPassAllMcast(bool pass) { + if(pass) + { + base->MACFFR |= ETH_MACFFR_PAM_Msk; + } + else + { + base->MACFFR &= ~ETH_MACFFR_PAM_Msk; + } +} + +void STM32EthMACv1::MACDriver::setPromiscuous(bool enable) { + if(enable) + { + base->MACFFR |= ETH_MACFFR_PM_Msk; + } + else + { + base->MACFFR &= ~ETH_MACFFR_PM_Msk; + } +} + +STM32EthMACv1 * STM32EthMACv1::instance = nullptr; + +STM32EthMACv1::STM32EthMACv1(): +CompositeEMAC(txDMA, rxDMA, macDriver), +base(ETH), +txDMA(base), +rxDMA(base), +macDriver(base) +{ + instance = this; +} + +void STM32EthMACv1::irqHandler() { + const auto emacInst = instance; + uint32_t dma_flag = emacInst->base->DMASR; + + /* Packet received */ + if ((dma_flag & ETH_DMASR_RS_Msk) != 0U) + { + /* Clear the Eth DMA Rx IT pending bits */ + ETH->DMASR = ETH_DMASR_RS_Msk | ETH_DMASR_NIS_Msk; + + emacInst->rxISR(); + } + + /* Packet transmitted */ + if ((dma_flag & ETH_DMASR_TS_Msk) != 0U) + { + /* Clear the Eth DMA Tx IT pending bits */ + ETH->DMASR = ETH_DMASR_TS_Msk | ETH_DMASR_NIS_Msk; + + emacInst->txISR(); + } + + /* ETH DMA Error */ + if(dma_flag & ETH_DMASR_FBES_Msk) + { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_ETHERNET, EIO), \ + "STM32 EMAC v1: Hardware reports fatal DMA error\n"); + } +} +} + +// Provide default EMAC driver +MBED_WEAK EMAC &EMAC::get_default_instance() +{ + static mbed::STM32EthMACv1 emac; + return emac; +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.h b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.h new file mode 100644 index 00000000000..fca6fef9405 --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.h @@ -0,0 +1,163 @@ +/* Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "CompositeEMAC.h" +#include "STM32EthV1Descriptors.h" +#include "CacheAlignedBuffer.h" +#include "GenericEthDMA.h" + +#if TARGET_STM32F7 +#define ENABLE_ERRATA_2_21_6_WORKAROUND 1 +#endif + +namespace mbed +{ + +/** + * @brief EMAC implementation for STM32 MCUs with Ethernet IP v2 + */ +class STM32EthMACv1 : public CompositeEMAC +{ + class TxDMA : public GenericTxDMARing + { + protected: + ETH_TypeDef * const base; // Base address of Ethernet peripheral + StaticCacheAlignedBuffer txDescs; // Tx descriptors + + void startDMA() override; + + void stopDMA() override; + +#if __DCACHE_PRESENT + void cacheInvalidateDescriptor(size_t descIdx) override; +#endif + + bool descOwnedByDMA(size_t descIdx) override; + + bool isDMAReadableBuffer(uint8_t const * start, size_t size) const override; + + void giveToDMA(size_t descIdx, uint8_t const * buffer, size_t len, bool firstDesc, bool lastDesc) override; + public: + explicit TxDMA(ETH_TypeDef * const base): + base(base) + {} + }; + + class RxDMA : public GenericRxDMARing { + protected: + ETH_TypeDef * const base; // Base address of Ethernet peripheral + StaticCacheAlignedBuffer rxDescs; // Rx descriptors + + void startDMA() override; + + void stopDMA() override; + +#if __DCACHE_PRESENT + void cacheInvalidateDescriptor(size_t descIdx) override; +#endif + + bool descOwnedByDMA(size_t descIdx) override; + + bool isFirstDesc(size_t descIdx) override; + + bool isLastDesc(size_t descIdx) override; + + bool isErrorDesc(size_t descIdx) override; + + void returnDescriptor(size_t descIdx, uint8_t * buffer) override; + + size_t getTotalLen(size_t firstDescIdx, size_t lastDescIdx) override; + + public: + explicit RxDMA(ETH_TypeDef * const base): + base(base) + {} + }; + + class MACDriver : public CompositeEMAC::MACDriver { + ETH_TypeDef * const base; // Base address of Ethernet peripheral + + // Number of MAC address perfect filter registers used + size_t numPerfectFilterRegsUsed = 0; + + /** + * @brief Configures the Clock range of ETH MDIO interface. + * + * Copied from STM32CubeHAL. + * + * @param base Base address of Ethernet peripheral + */ + static void ETH_SetMDIOClockRange(ETH_TypeDef * const base); + +#if ENABLE_ERRATA_2_21_6_WORKAROUND + // Workaround for ETH errata 2.21.6 from the STM32F7 errata sheet + int rmiiWatchdogHandle; + std::atomic rmiiWatchdogRunning = false; + void rmiiWatchdog(); +#endif + + public: + explicit MACDriver(ETH_TypeDef * const base): + base(base) + {} + + ErrCode init() override; + + ErrCode deinit() override; + + ErrCode enable(LinkSpeed speed, Duplex duplex) override; + + ErrCode disable() override; + + void setOwnMACAddr(const MACAddress &ownAddress) override; + + ErrCode mdioRead(uint8_t devAddr, uint8_t regAddr, uint16_t &result) override; + + ErrCode mdioWrite(uint8_t devAddr, uint8_t regAddr, uint16_t data) override; + + PinName getPhyResetPin() override; + + ErrCode addMcastMAC(MACAddress mac) override; + + ErrCode clearMcastFilter() override; + + void setPassAllMcast(bool pass) override; + + void setPromiscuous(bool enable) override; + }; + + // Pointer to global instance, for ISR to use. + // TODO if we support more than 1 EMAC per MCU, this will need to be an array + static STM32EthMACv1 * instance; + + ETH_TypeDef * const base; // Base address of Ethernet peripheral + + // Components of the ethernet MAC + TxDMA txDMA; + RxDMA rxDMA; + MACDriver macDriver; + +public: + STM32EthMACv1(); + + // Interrupt callback + static void irqHandler(); +}; + + +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.cpp b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.cpp new file mode 100644 index 00000000000..3201ca3cff9 --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.cpp @@ -0,0 +1,571 @@ +/* Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "STM32EthMACv2.h" +#include "STM32EthMACCommon.h" + +#include "mbed_power_mgmt.h" +#include "Timer.h" +#include "mbed_error.h" + +using namespace std::chrono_literals; + +#define TRACE_GROUP "STEMACv2" + +// Defined in stm32_eth_init.c +extern "C" void EthInitPinmappings(); +extern "C" void EthDeinitPinmappings(); +extern "C" PinName EthGetPhyResetPin(); + +namespace mbed { + void STM32EthMACv2::TxDMA::startDMA() { + // Configure Tx descriptor ring + base->DMACTDRLR = MBED_CONF_NSAPI_EMAC_TX_NUM_DESCS - 1; // Ring size + base->DMACTDLAR = reinterpret_cast(&txDescs[0]); // Ring base address + base->DMACTDTPR = reinterpret_cast(&txDescs[0]); // Next descriptor (tail) pointer + + // Enable Tx DMA + // NOTE: Typo in C++ headers, should be called "DMACTXCR" + base->DMACTCR |= ETH_DMACTCR_ST; + + // Clear Tx process stopped flag + base->DMACSR = ETH_DMACSR_TPS; + } + + void STM32EthMACv2::TxDMA::stopDMA() { + // Disable Tx DMA + base->DMACTCR &= ~ETH_DMACTCR_ST; + } + +#if __DCACHE_PRESENT + void STM32EthMACv2::TxDMA::cacheInvalidateDescriptor(size_t descIdx) { + SCB_InvalidateDCache_by_Addr(&txDescs[descIdx], sizeof(stm32_ethv2::EthTxDescriptor)); + } +#endif + + bool STM32EthMACv2::TxDMA::descOwnedByDMA(size_t descIdx) { + return txDescs[descIdx].formats.fromDMA.dmaOwn; + } + + bool STM32EthMACv2::TxDMA::isDMAReadableBuffer(uint8_t const *start, const size_t size) const + { +#ifdef TARGET_STM32H7 + // On STM32H7, the Ethernet DMA cannot access data in DTCM. So, if someone sends + // a packet with a data pointer in DTCM (e.g. a stack allocated payload), everything + // will break if we don't copy it first. + if(bufferTouchesMemoryBank(start, size, MBED_RAM_BANK_SRAM_DTC_START, MBED_RAM_BANK_SRAM_DTC_SIZE)) { + return false; + } +#endif + +#ifdef TARGET_STM32H5 + // On STM32H5, the Ethernet DMA cannot access data in backup SRAM. + if(bufferTouchesMemoryBank(start, size, MBED_RAM_BANK_SRAM_BKUP_START, MBED_RAM_BANK_SRAM_BKUP_SIZE)) { + return false; + } +#endif + + return true; + } + + void STM32EthMACv2::TxDMA::giveToDMA(const size_t descIdx, uint8_t const * const buffer, const size_t len, const bool firstDesc, const bool lastDesc) { + auto & desc = txDescs[descIdx]; + + // Set buffer + desc.formats.toDMA.buffer1Addr = buffer; + desc.formats.toDMA.buffer1Len = len; + + // Note that we have to configure these every time as + // they get wiped away when the DMA gives back the descriptor + desc.formats.toDMA._reserved = 0; + desc.formats.toDMA.checksumInsertionCtrl = 0; // Mbed does not do checksum offload for now + desc.formats.toDMA.tcpSegmentationEnable = false; // No TCP offload + desc.formats.toDMA.tcpUDPHeaderLen = 0; // No TCP offload + desc.formats.toDMA.srcMACInsertionCtrl = 0; // No MAC insertion + desc.formats.toDMA.crcPadCtrl = 0; // Insert CRC and padding + desc.formats.toDMA.lastDescriptor = lastDesc; + desc.formats.toDMA.firstDescriptor = firstDesc; + desc.formats.toDMA.isContext = false; + desc.formats.toDMA.vlanTagCtrl = 0; // No VLAN tag + desc.formats.toDMA.intrOnCompletion = true; + desc.formats.toDMA.timestampEnable = false; + desc.formats.toDMA.dmaOwn = true; + + // Write descriptor back to main memory +#if __DCACHE_PRESENT + SCB_CleanDCache_by_Addr(&desc, sizeof(stm32_ethv2::EthTxDescriptor)); +#else + __DMB(); // Make sure descriptor is written before the below lines +#endif + + // Move tail pointer register to point to the descriptor after this descriptor. + // This tells the MAC to transmit until it reaches the given descriptor, then stop. + const auto nextDescIdx = (descIdx + 1) % MBED_CONF_NSAPI_EMAC_TX_NUM_DESCS; + base->DMACTDTPR = reinterpret_cast(&txDescs[nextDescIdx]); + } + + void STM32EthMACv2::RxDMA::startDMA() + { + // Configure Rx buffer size. Per the datasheet and HAL code, we need to round this down to + // the nearest multiple of 4. + MBED_ASSERT(rxPoolPayloadSize % sizeof(uint32_t) == 0); + base->DMACRCR |= rxPoolPayloadSize << ETH_DMACRCR_RBSZ_Pos; + + // Configure Rx descriptor ring + base->DMACRDRLR = RX_NUM_DESCS - 1; // Ring size + base->DMACRDLAR = reinterpret_cast(&rxDescs[0]); // Ring base address + base->DMACRDTPR = reinterpret_cast(&rxDescs[0]); // Next descriptor (tail) pointer + + // Enable Rx DMA. + base->DMACRCR |= ETH_DMACRCR_SR; + + // Clear Rx process stopped flag + base->DMACSR = ETH_DMACSR_RPS; + } + + void STM32EthMACv2::RxDMA::stopDMA() { + // Disable Rx DMA + base->DMACRCR &= ~ETH_DMACRCR_SR; + } + +#if __DCACHE_PRESENT + void STM32EthMACv2::RxDMA::cacheInvalidateDescriptor(size_t descIdx) { + SCB_InvalidateDCache_by_Addr(&rxDescs[descIdx], sizeof(stm32_ethv2::EthRxDescriptor)); + } +#endif + + bool STM32EthMACv2::RxDMA::descOwnedByDMA(size_t descIdx) { + return rxDescs[descIdx].formats.toDMA.dmaOwn; + } + + bool STM32EthMACv2::RxDMA::isFirstDesc(size_t descIdx) { + return rxDescs[descIdx].formats.fromDMA.firstDescriptor; + } + + bool STM32EthMACv2::RxDMA::isLastDesc(size_t descIdx) { + return rxDescs[descIdx].formats.fromDMA.lastDescriptor; + } + + bool STM32EthMACv2::RxDMA::isErrorDesc(size_t descIdx) { + // For right now, we treat context descriptors equivalent to error descs. + // Currently we do not use them, so if we did get one, we just want to get rid of it. + return rxDescs[descIdx].formats.fromDMA.errorSummary || rxDescs[descIdx].formats.fromDMA.context; + } + + void STM32EthMACv2::RxDMA::returnDescriptor(const size_t descIdx, uint8_t * const buffer) { + auto & desc = rxDescs[descIdx]; + + // Clear out any bits previously set in the descriptor (from when the DMA gave it back to us) + memset(&desc, 0, sizeof(stm32_ethv2::EthRxDescriptor)); + + // Store buffer address + desc.formats.toDMA.buffer1Addr = buffer; + + // Configure descriptor + desc.formats.toDMA.buffer1Valid = true; + desc.formats.toDMA.intrOnCompletion = true; + desc.formats.toDMA.dmaOwn = true; + +#if __DCACHE_PRESENT + // Flush to main memory + SCB_CleanDCache_by_Addr(&desc, __SCB_DCACHE_LINE_SIZE); +#else + __DMB(); // Make sure descriptor is written before the below lines +#endif + + // Update tail ptr to issue "rx poll demand" and mark this descriptor for receive. + // Rx stops when the current and tail pointers are equal, so we want to set the tail pointer + // to one location after the last DMA-owned descriptor in the FIFO. + const auto nextDescIdx = (descIdx + 1) % RX_NUM_DESCS; + base->DMACRDTPR = reinterpret_cast(&rxDescs[nextDescIdx]); + } + + size_t STM32EthMACv2::RxDMA::getTotalLen(const size_t firstDescIdx, const size_t lastDescIdx) { + // Total length of the packet is in the last descriptor + return rxDescs[lastDescIdx].formats.fromDMA.pktLength; + } + + void STM32EthMACv2::MACDriver::ETH_SetMDIOClockRange(ETH_TypeDef * const base) + { + uint32_t hclk; + uint32_t tmpreg; + + /* Get the ETHERNET MACMDIOAR value */ + tmpreg = base->MACMDIOAR; + + /* Clear CSR Clock Range bits */ + tmpreg &= ~ETH_MACMDIOAR_CR; + + /* Get hclk frequency value */ + hclk = HAL_RCC_GetHCLKFreq(); + + /* Set CR bits depending on hclk value */ + if (hclk < 35000000U) + { + /* CSR Clock Range between 0-35 MHz */ + tmpreg |= (uint32_t)ETH_MACMDIOAR_CR_DIV16; + } + else if (hclk < 60000000U) + { + /* CSR Clock Range between 35-60 MHz */ + tmpreg |= (uint32_t)ETH_MACMDIOAR_CR_DIV26; + } + else if (hclk < 100000000U) + { + /* CSR Clock Range between 60-100 MHz */ + tmpreg |= (uint32_t)ETH_MACMDIOAR_CR_DIV42; + } + else if (hclk < 150000000U) + { + /* CSR Clock Range between 100-150 MHz */ + tmpreg |= (uint32_t)ETH_MACMDIOAR_CR_DIV62; + } + else if (hclk < 250000000U) + { + /* CSR Clock Range between 150-250 MHz */ + tmpreg |= (uint32_t)ETH_MACMDIOAR_CR_DIV102; + } + else /* (hclk >= 250000000U) */ + { + /* CSR Clock >= 250 MHz */ + tmpreg |= (uint32_t)(ETH_MACMDIOAR_CR_DIV124); + } + + /* Configure the CSR Clock Range */ + base->MACMDIOAR = (uint32_t)tmpreg; + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::init() { + sleep_manager_lock_deep_sleep(); + + // Note: Following code is based on HAL_Eth_Init() from the HAL + /* Init the low level hardware : GPIO, CLOCK, NVIC. */ + EthInitPinmappings(); +#ifdef TARGET_STM32H7 + // Use RMII + HAL_SYSCFG_ETHInterfaceSelect(SYSCFG_ETH_RMII); + + /* Dummy read to sync with ETH */ + (void)SYSCFG->PMCR; +#else + __HAL_RCC_SBS_CLK_ENABLE(); + HAL_SBS_ETHInterfaceSelect(SBS_ETH_RMII); + + /* Dummy read to sync with ETH */ + (void)SBS->PMCR; +#endif + + /* Ethernet Software reset */ + /* Set the SWR bit: resets all MAC subsystem internal registers and logic */ + /* After reset all the registers holds their respective reset values */ + base->DMAMR |= ETH_DMAMR_SWR; + + const auto ETH_SW_RESET_TIMEOUT = 500us; // used by STM32 HAL + Timer timeoutTimer; + timeoutTimer.start(); + while(timeoutTimer.elapsed_time() < ETH_SW_RESET_TIMEOUT && (base->DMAMR & ETH_DMAMR_SWR)) {} + if(base->DMAMR & ETH_DMAMR_SWR) { + // Reset failed to complete within expected timeout. + // Note: This is usually because of a missing RMII clock from the PHY. + return ErrCode::TIMEOUT; + } + + /*------------------ MDIO CSR Clock Range Configuration --------------------*/ + ETH_SetMDIOClockRange(base); + + /*------------------ MAC LPI 1US Tic Counter Configuration --------------------*/ + base->MAC1USTCR = (HAL_RCC_GetHCLKFreq() / 1000000U) - 1U; + + // MAC configuration + base->MACCR = ETH_MACCR_SARC_REPADDR0 | // Replace the SA field in Tx packets with the configured source address + ETH_MACCR_CST_Msk; // Don't include the CRC when forwarding Rx packets to the application + base->MTLTQOMR |= ETH_MTLTQOMR_TSF_Msk; // Enable store and forward mode for transmission (default in the HAL) + + // Enable multicast hash and perfect filter + base->MACPFR = ETH_MACPFR_HMC | ETH_MACPFR_HPF; + + // Default CubeHAL DMA settings + base->DMASBMR = ETH_DMASBMR_AAL_Msk | ETH_DMASBMR_FB_Msk; + base->DMACTCR = ETH_DMACTCR_TPBL_32PBL; + base->DMACRCR = ETH_DMACRCR_RPBL_32PBL; + + // Configure spacing between DMA descriptors. This will be different depending on + // cache line sizes. + // NOTE: Cast pointers to uint8_t so that the difference will be returned in bytes instead + // of elements. + const size_t rxSpacing = sizeof(stm32_ethv2::EthRxDescriptor); + + // Check that spacing seems valid +#ifndef NDEBUG + const size_t txSpacing = sizeof(stm32_ethv2::EthTxDescriptor); + MBED_ASSERT(rxSpacing == txSpacing); + MBED_ASSERT(rxSpacing % sizeof(uint32_t) == 0); +#endif + + // The spacing bitfield is configured as the number of 32-bit words to skip between descriptors. + // The descriptors have a default size of 16 bytes. + const size_t wordsToSkip = (rxSpacing - 16) / sizeof(uint32_t); + MBED_ASSERT(wordsToSkip <= 7); + base->DMACCR &= ~ETH_DMACCR_DSL_Msk; + base->DMACCR |= wordsToSkip << ETH_DMACCR_DSL_Pos; + + // Set up interrupt handler + NVIC_SetVector(ETH_IRQn, reinterpret_cast(&STM32EthMACv2::irqHandler)); + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); + + // Enable Tx, Rx, and fatal bus error interrupts. + // However, don't enable receive buffer unavailable interrupt, because that can + // trigger if we run out of Rx descriptors, and we don't want to fatal error + // in that case. + base->DMACIER = ETH_DMACIER_NIE | ETH_DMACIER_RIE | ETH_DMACIER_TIE | ETH_DMACIER_FBEE | ETH_DMACIER_AIE; + + + return ErrCode::SUCCESS; + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::deinit() + { + // Disable interrupt + HAL_NVIC_DisableIRQ(ETH_IRQn); + + // Unlock deep sleep + sleep_manager_unlock_deep_sleep(); + + // Unmap pins and turn off clock + EthDeinitPinmappings(); + + return ErrCode::SUCCESS; + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::enable(LinkSpeed speed, Duplex duplex) + { + if(speed == LinkSpeed::LINK_1GBIT) { + return ErrCode::INVALID_ARGUMENT; + } + + auto maccrVal = base->MACCR; + if(speed == LinkSpeed::LINK_100MBIT) { + maccrVal |= ETH_MACCR_FES_Msk; + } + else { + maccrVal &= ~ETH_MACCR_FES_Msk; + } + if(duplex == Duplex::FULL) { + maccrVal |= ETH_MACCR_DM_Msk; + } + else { + maccrVal &= ~ETH_MACCR_DM_Msk; + } + + // Enable the MAC transmission & reception + maccrVal |= ETH_MACCR_TE | ETH_MACCR_RE; + base->MACCR = maccrVal; + return ErrCode::SUCCESS; + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::disable() + { + base->MACCR &= ~(ETH_MACCR_TE | ETH_MACCR_RE); + + // Get rid of any packets still in the transmit FIFO + base->MTLTQOMR |= ETH_MTLTQOMR_FTQ; + + return ErrCode::SUCCESS; + } + + void STM32EthMACv2::MACDriver::setOwnMACAddr(const MACAddress &ownAddress) { + // Set MAC address + writeMACAddress(ownAddress, &base->MACA0HR, &base->MACA0LR); + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::mdioRead(uint8_t devAddr, uint8_t regAddr, uint16_t &result) { + // This code based on HAL_ETH_ReadPHYRegister() + if(base->MACMDIOAR & ETH_MACMDIOAR_MB_Msk) { + // MDIO operation already in progress + return ErrCode::INVALID_USAGE; + } + + uint32_t tmpreg = base->MACMDIOAR; + + /* Prepare the MDIO Address Register value + - Set the PHY device address + - Set the PHY register address + - Set the read mode + - Set the MII Busy bit */ + tmpreg &= ~(ETH_MACMDIOAR_PA_Msk | ETH_MACMDIOAR_RDA_Msk | ETH_MACMDIOAR_MOC_Msk); + tmpreg |= (devAddr << ETH_MACMDIOAR_PA_Pos) | (regAddr << ETH_MACMDIOAR_RDA_Pos) | ETH_MACMDIOAR_MOC_RD | ETH_MACMDIOAR_MB_Msk; + base->MACMDIOAR = tmpreg; + + Timer timeoutTimer; + timeoutTimer.start(); + while(timeoutTimer.elapsed_time() < MDIO_TRANSACTION_TIMEOUT && (base->MACMDIOAR & ETH_MACMDIOAR_MB_Msk)) {} + if(base->MACMDIOAR & ETH_MACMDIOAR_MB_Msk) { + // Transaction failed to complete within expected timeout + return ErrCode::TIMEOUT; + } + + // Get result + result = base->MACMDIODR & ETH_MACMDIODR_MD_Msk; + + tr_debug("MDIO read devAddr %" PRIu8 ", regAddr 0x%" PRIx8 " -> 0x%" PRIx16, devAddr, regAddr, result); + + return ErrCode::SUCCESS; + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::mdioWrite(uint8_t devAddr, uint8_t regAddr, uint16_t data) { + // This code based on HAL_ETH_WritePHYRegister() + if(base->MACMDIOAR & ETH_MACMDIOAR_MB_Msk) { + // MDIO operation already in progress + return ErrCode::INVALID_USAGE; + } + + /* Give the value to the MII data register */ + base->MACMDIODR = data << ETH_MACMDIODR_MD_Pos; + + uint32_t tmpreg = base->MACMDIOAR; + + /* Prepare the MDIO Address Register value + - Set the PHY device address + - Set the PHY register address + - Set the write mode + - Set the MII Busy bit */ + tmpreg &= ~(ETH_MACMDIOAR_PA_Msk | ETH_MACMDIOAR_RDA_Msk | ETH_MACMDIOAR_MOC_Msk); + tmpreg |= (devAddr << ETH_MACMDIOAR_PA_Pos) | (regAddr << ETH_MACMDIOAR_RDA_Pos) | ETH_MACMDIOAR_MOC_WR | ETH_MACMDIOAR_MB_Msk; + base->MACMDIOAR = tmpreg; + + Timer timeoutTimer; + timeoutTimer.start(); + while(timeoutTimer.elapsed_time() < MDIO_TRANSACTION_TIMEOUT && (base->MACMDIOAR & ETH_MACMDIOAR_MB_Msk)) {} + if(base->MACMDIOAR & ETH_MACMDIOAR_MB_Msk) { + // Transaction failed to complete within expected timeout + return ErrCode::TIMEOUT; + } + + tr_debug("MDIO write devAddr %" PRIu8 ", regAddr 0x%" PRIx8 " <- 0x%" PRIx16, devAddr, regAddr, data); + + return ErrCode::SUCCESS; + } + + PinName STM32EthMACv2::MACDriver::getPhyResetPin() { + return EthGetPhyResetPin(); + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::addMcastMAC(MACAddress mac) { + if(numPerfectFilterRegsUsed < NUM_PERFECT_FILTER_REGS) { + size_t perfFiltIdx = numPerfectFilterRegsUsed; + ++numPerfectFilterRegsUsed; + + tr_debug("Using perfect filtering for %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + writeMACAddress(mac, MAC_ADDR_PERF_FILTER_REGS[perfFiltIdx].first, MAC_ADDR_PERF_FILTER_REGS[perfFiltIdx].second); + } + else { + // Out of spaces in perfect filter, use hash filter instead + tr_debug("Using hash filtering for %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + addHashFilterMAC(base, mac); + } + return ErrCode::SUCCESS; + } + + CompositeEMAC::ErrCode STM32EthMACv2::MACDriver::clearMcastFilter() { + // Reset perfect filter registers + for(auto regPair : MAC_ADDR_PERF_FILTER_REGS) { + *regPair.first = 0; + *regPair.second = 0; + } + numPerfectFilterRegsUsed = 0; + + // Reset hash filter + base->MACHT0R = 0; + base->MACHT1R = 0; + + return ErrCode::SUCCESS; + } + + void STM32EthMACv2::MACDriver::setPassAllMcast(bool pass) { + if(pass) + { + base->MACPFR |= ETH_MACPFR_PM; + } + else + { + base->MACPFR &= ~ETH_MACPFR_PM; + } + } + + void STM32EthMACv2::MACDriver::setPromiscuous(bool enable) { + if(enable) + { + base->MACPFR |= ETH_MACPFR_PR; + } + else + { + base->MACPFR &= ~ETH_MACPFR_PR; + } + } + + STM32EthMACv2 * STM32EthMACv2::instance = nullptr; + + STM32EthMACv2::STM32EthMACv2(): + CompositeEMAC(txDMA, rxDMA, macDriver), + base(ETH), + txDMA(base), + rxDMA(base), + macDriver(base) + { + instance = this; + } + + void STM32EthMACv2::irqHandler() + { + const auto emacInst = instance; + uint32_t dma_flag = emacInst->base->DMACSR; + + /* Packet received */ + if ((dma_flag & ETH_DMACSR_RI) != 0U) + { + /* Clear the Eth DMA Rx IT pending bits */ + ETH->DMACSR = ETH_DMACSR_RI | ETH_DMACSR_NIS; + + emacInst->rxISR(); + } + + /* Packet transmitted */ + if ((dma_flag & ETH_DMACSR_TI) != 0U) + { + /* Clear the Eth DMA Tx IT pending bits */ + ETH->DMACSR = ETH_DMACSR_TI | ETH_DMACSR_NIS; + + emacInst->txISR(); + } + + /* ETH DMA Error */ + if(dma_flag & ETH_DMACSR_FBE) + { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_ETHERNET, EIO), \ + "STM32 EMAC v2: Hardware reports fatal DMA error\n"); + } + } +} + +// Provide default EMAC driver +MBED_WEAK EMAC &EMAC::get_default_instance() +{ + static mbed::STM32EthMACv2 emac; + return emac; +} diff --git a/connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.h b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.h new file mode 100644 index 00000000000..75fda1823f4 --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.h @@ -0,0 +1,153 @@ +/* Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_OS_STM32ETHMACV2_H +#define MBED_OS_STM32ETHMACV2_H + +#include "CompositeEMAC.h" +#include "GenericEthDMA.h" +#include "STM32EthV2Descriptors.h" + +namespace mbed { + /** + * @brief EMAC implementation for STM32 MCUs with Ethernet IP v2 + */ + class STM32EthMACv2 : public CompositeEMAC { + + class TxDMA : public GenericTxDMARing + { + protected: + ETH_TypeDef * const base; // Base address of Ethernet peripheral + StaticCacheAlignedBuffer txDescs; // Tx descriptors + + void startDMA() override; + + void stopDMA() override; + +#if __DCACHE_PRESENT + void cacheInvalidateDescriptor(size_t descIdx) override; +#endif + + bool descOwnedByDMA(size_t descIdx) override; + + bool isDMAReadableBuffer(uint8_t const * start, size_t size) const override; + + void giveToDMA(size_t descIdx, uint8_t const * buffer, size_t len, bool firstDesc, bool lastDesc) override; + public: + explicit TxDMA(ETH_TypeDef * const base): + GenericTxDMARing(1), // Request that 1 Tx descriptor is always left unfilled + base(base) + {} + }; + + class RxDMA : public GenericRxDMARing { + protected: + ETH_TypeDef * const base; // Base address of Ethernet peripheral + StaticCacheAlignedBuffer rxDescs; // Rx descriptors + + void startDMA() override; + + void stopDMA() override; + +#if __DCACHE_PRESENT + void cacheInvalidateDescriptor(size_t descIdx) override; +#endif + + bool descOwnedByDMA(size_t descIdx) override; + + bool isFirstDesc(size_t descIdx) override; + + bool isLastDesc(size_t descIdx) override; + + bool isErrorDesc(size_t descIdx) override; + + void returnDescriptor(size_t descIdx, uint8_t *buffer) override; + + size_t getTotalLen(size_t firstDescIdx, size_t lastDescIdx) override; + + public: + explicit RxDMA(ETH_TypeDef * const base): + base(base) + {} + }; + + class MACDriver : public CompositeEMAC::MACDriver { + ETH_TypeDef * const base; // Base address of Ethernet peripheral + + // Number of MAC address perfect filter registers used + size_t numPerfectFilterRegsUsed = 0; + + /** + * @brief Configures the Clock range of ETH MDIO interface. + * + * Copied from STM32CubeHAL. + * + * @param base Base address of Ethernet peripheral + */ + static void ETH_SetMDIOClockRange(ETH_TypeDef * const base); + + public: + explicit MACDriver(ETH_TypeDef * const base): + base(base) + {} + + ErrCode init() override; + + ErrCode deinit() override; + + ErrCode enable(LinkSpeed speed, Duplex duplex) override; + + ErrCode disable() override; + + void setOwnMACAddr(const MACAddress &ownAddress) override; + + ErrCode mdioRead(uint8_t devAddr, uint8_t regAddr, uint16_t &result) override; + + ErrCode mdioWrite(uint8_t devAddr, uint8_t regAddr, uint16_t data) override; + + PinName getPhyResetPin() override; + + ErrCode addMcastMAC(MACAddress mac) override; + + ErrCode clearMcastFilter() override; + + void setPassAllMcast(bool pass) override; + + void setPromiscuous(bool enable) override; + }; + + // Pointer to global instance, for ISR to use. + // TODO if we support more than 1 EMAC per MCU, this will need to be an array + static STM32EthMACv2 * instance; + + ETH_TypeDef * const base; // Base address of Ethernet peripheral + + // Components of the ethernet MAC + TxDMA txDMA; + RxDMA rxDMA; + STM32EthMACv2::MACDriver macDriver; + + public: + STM32EthMACv2(); + + // Interrupt callback + static void irqHandler(); + }; +} + + + +#endif // MBED_OS_STM32ETHMACV2_H \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/STM32EthV1Descriptors.h b/connectivity/drivers/emac/TARGET_STM/STM32EthV1Descriptors.h new file mode 100644 index 00000000000..c715c5fc3ab --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/STM32EthV1Descriptors.h @@ -0,0 +1,154 @@ +/* Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef STM32ETHV1DESCRIPTORS_H +#define STM32ETHV1DESCRIPTORS_H + +#include + +namespace mbed { +namespace stm32_ethv1 { + /// Struct for an enhanced Tx descriptor in the STM32 Eth IP v1. + /// From STM32F7 Reference Manual, section 42.6.7. + /// Note that even when there is no CPU cache, descriptors must be 32 bit aligned. + struct __attribute__((packed, aligned(4))) TxDescriptor + { + // TDES0 fields + bool deferred : 1; + bool underflowErr : 1; + bool excessiveDeferral : 1; + uint8_t collisionCount : 4; + bool vlanFrame : 1; + bool excessiveCollision : 1; + bool lateCollision : 1; + bool noCarrier : 1; + bool lossOfCarrier : 1; + bool ipPayloadErr : 1; + bool frameFlushed : 1; + bool jabberTimeout : 1; + bool errorSummary : 1; + bool ipHeaderError : 1; + bool txTimestampStatus : 1; + uint8_t : 2; // reserved + bool secAddressChained : 1; + bool endOfRing : 1; + uint8_t checksumInsCtrl : 2; + uint8_t : 1; // reserved + bool txTimestampEn : 1; + bool disablePad : 1; + bool disableCRC : 1; + bool firstSegment : 1; + bool lastSegment : 1; + bool intrOnComplete : 1; + bool dmaOwn : 1; + + // TDES1 fields + uint16_t buffer1Size : 13; + uint8_t : 3; + uint16_t buffer2Size : 13; + uint8_t : 3; + + // TDES2 fields + uint8_t const * buffer1; + + // TDES3 fields + uint8_t const * buffer2OrNextDesc; + + // TDES4 fields + uint32_t : 32; + + // TDES5 fields + uint32_t : 32; + + // TDES6 fields + uint32_t timestampLow; + + // TDES7 fields + uint32_t timestampHigh; + }; + + /// Struct for an enhanced Rx descriptor in the STM32 Eth IP v1. + /// From STM32F7 Reference Manual, section 42.6.8 + /// Note that even when there is no CPU cache, descriptors must be 32 bit aligned. + struct __attribute__((packed, aligned(4))) RxDescriptor + { + // RDES0 fields + bool extStatusAvail : 1; + bool crcErr : 1; + bool dribbleErr : 1; + bool rxErr : 1; + bool rxWatchdogTimeout : 1; + bool isEthernetFrame : 1; + bool lateCollision : 1; + bool timestampValid : 1; + bool lastDescriptor : 1; + bool firstDescriptor : 1; + bool hasVLANTag : 1; + bool overflowErr : 1; + bool lengthErr : 1; + bool saFilterFail : 1; + bool frameTruncated : 1; + bool errSummary : 1; + uint16_t frameLen : 14; + bool daFilterFail : 1; + bool dmaOwn : 1; + + // RDES1 fields + uint16_t buffer1Size : 13; + bool : 1; + bool secAddressChained : 1; + bool endOfRing : 1; + uint16_t buffer2Size : 13; + uint8_t : 2; + bool disableInterruptOnComplete : 1; + + // RDES2 fields + uint8_t const * buffer1; + + // RDES3 fields + uint8_t const * buffer2OrNextDesc; + + // RDES4 fields + uint8_t ipPayloadType : 3; + bool ipHeaderErr : 1; + bool ipPayloadErr : 1; + bool ipChksumBypassed : 1; + bool ipv4Pkt : 1; + bool ipv6Pkt : 1; + uint8_t ptpMsgType : 4; + bool ptpLayer2 : 1; + bool ptpv2: 1; + uint32_t : 18; + + // RDES5 fields + uint32_t : 32; + + // RDES6 fields + uint32_t timestampLow; + + // RDES7 fields + uint32_t timestampHigh; + }; + +#if __DCACHE_PRESENT + static_assert(sizeof(RxDescriptor) == __SCB_DCACHE_LINE_SIZE, "Rx descriptor size must equal cache line size"); + static_assert(sizeof(TxDescriptor) == __SCB_DCACHE_LINE_SIZE, "Tx descriptor size must equal cache line size"); +#endif + +} +} + +#endif //STM32ETHV1DESCRIPTORS_H diff --git a/connectivity/drivers/emac/TARGET_STM/STM32EthV2Descriptors.h b/connectivity/drivers/emac/TARGET_STM/STM32EthV2Descriptors.h new file mode 100644 index 00000000000..e8b94f5b055 --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/STM32EthV2Descriptors.h @@ -0,0 +1,193 @@ +/* Copyright (c) 2024 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_OS_STM32ETHV2DESCRIPTORS_H +#define MBED_OS_STM32ETHV2DESCRIPTORS_H + +#include +#include + +namespace mbed { + namespace stm32_ethv2 + { + + // Tx descriptor ------------------------------------------------------------------------------------------ + + // Descriptor format written by the application to queue a packet for transmission. + // Note: Datasheet calls this the "read format" which is just nuts... + struct __attribute__((packed)) EthTxDescriptorToDMAFmt + { + uint8_t const * buffer1Addr; + uint8_t const * buffer2Addr; + // TDES2 fields + uint16_t buffer1Len : 14; + uint8_t vlanTagCtrl : 2; + uint16_t buffer2Len : 14; + bool timestampEnable : 1; + bool intrOnCompletion : 1; + // TDES3 fields (not dealing with TCP offload for now) + uint16_t _reserved : 16; + uint8_t checksumInsertionCtrl : 2; + bool tcpSegmentationEnable : 1; + uint8_t tcpUDPHeaderLen : 4; + uint8_t srcMACInsertionCtrl : 3; + uint8_t crcPadCtrl : 2; + bool lastDescriptor : 1; + bool firstDescriptor: 1; + bool isContext : 1; + bool dmaOwn : 1; + }; + + // Write-back descriptor (DMA updates the desc with this format when complete) + struct __attribute__((packed)) EthTxDescriptorFromDMAFmt + { + uint32_t timestampLow; + uint32_t timestampHigh; + uint32_t _reserved; + // TDES3 fields + bool ipHeaderError : 1; + bool deferred : 1; + bool underflowError : 1; + bool excessiveDeferral : 1; + uint8_t collisionCount : 4; + bool excessiveCollisions : 1; + bool lateCollision : 1; + bool noCarrier : 1; + bool lossOfCarrier : 1; + bool payloadChecksumError : 1; + bool packetFlushed : 1; + bool jabberTimeout : 1; + bool errorSummary: 1; + uint8_t _reserved0: 1; + bool txTimestampCaptured : 1; + uint16_t _reserved1 : 10; + bool lastDescriptor: 1; + bool firstDescriptor : 1; + bool context : 1; + bool dmaOwn : 1; + }; + + // Top-level descriptor type + // Note that per the datasheet, Tx descriptors must be word aligned. + struct alignas(uint32_t) EthTxDescriptor { + union { + EthTxDescriptorToDMAFmt toDMA; + EthTxDescriptorFromDMAFmt fromDMA; + } formats; + + // If we have a data cache, we need each descriptor to be in its own cache line. So, + // pad up to 32 byte cache line size +#if __DCACHE_PRESENT + uint8_t _padding[__SCB_DCACHE_LINE_SIZE - sizeof(decltype(formats))]; +#endif + }; +#if __DCACHE_PRESENT + static_assert(sizeof(EthTxDescriptor) == __SCB_DCACHE_LINE_SIZE, "Tx descriptor size must equal cache line size"); +#endif + + // Rx descriptor ------------------------------------------------------------------------------------------ + + // Format when an Rx descriptor is returned to the DMA. + // This is called the "read format" in the datasheet. + struct __attribute__((packed)) EthRxDescriptorToDMAFmt + { + uint8_t * buffer1Addr; + uint32_t _reserved0; + uint8_t * buffer2Addr; + uint32_t _reserved1: 24; + bool buffer1Valid: 1; + bool buffer2Valid: 1; + uint8_t _reserved2: 4; + bool intrOnCompletion: 1; + bool dmaOwn: 1; + }; + + // Format when an Rx descriptor is given to the application + // This is called the "write-back format" in the datasheet. + struct __attribute__((packed)) EthRxDescriptorFromDMAFmt + { + // RDES0 fields + uint16_t outerVLANTag; + uint16_t innerVLANTag; + + // RDES1 fields + uint8_t payloadType: 3; + bool ipHeaderError: 1; + bool ipv4HeaderPresent: 1; + bool ipv6HeaderPresent: 1; + bool checksumOffloadBypassed: 1; + bool ipPayloadError: 1; + uint8_t ptpMsgType: 4; + bool ptpType: 1; + bool isPTPv2: 1; + bool tsAvailable: 1; + bool tsDropped: 1; + uint16_t oamOrMacCtrl; + + // RDES2 fields + uint16_t _reserved0: 10; + bool arpNotGenerated: 1; + uint8_t _reserved1: 4; + bool vlanFiltPassed : 1; + bool sourceAddrFail: 1; + bool destAddrFail: 1; + bool hashFilterStatus: 1; + uint8_t hashValOrMatchIdx: 8; + bool l3FiltMatch: 1; + bool l4FiltMatch: 1; + uint8_t filterMatchNo: 3; + + // RDES3 fields + uint16_t pktLength: 15; + bool errorSummary: 1; + uint8_t lengthType: 3; + bool dribbleError: 1; + bool phyRxErr: 1; + bool overflowErr: 1; + bool rxWdogTimeout: 1; + bool giantPkt: 1; + bool crcErr: 1; + bool rdes0Valid: 1; + bool rdes1Valid: 1; + bool rdes2Valid: 1; + bool lastDescriptor: 1; + bool firstDescriptor: 1; + bool context: 1; + bool dmaOwn: 1; + }; + + struct alignas(uint32_t) EthRxDescriptor { + union { + EthRxDescriptorToDMAFmt toDMA; + EthRxDescriptorFromDMAFmt fromDMA; + } formats; + + // If we have a data cache, we need each descriptor to be in its own cache line. So, + // pad up to 32 byte cache line size +#if __DCACHE_PRESENT + uint8_t _padding[__SCB_DCACHE_LINE_SIZE - sizeof(decltype(formats))]; +#endif + }; + +#if __DCACHE_PRESENT + static_assert(sizeof(EthRxDescriptor) == __SCB_DCACHE_LINE_SIZE, "Rx descriptor size must equal cache line size"); +#endif + + + } +} + +#endif diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/CMakeLists.txt index 9a33dc74536..a161f155481 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/CMakeLists.txt @@ -3,14 +3,4 @@ if("NUCLEO_F207ZG" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_NUCLEO_F207ZG) -endif() - -target_include_directories(mbed-emac - PUBLIC - . -) - -target_sources(mbed-emac - PRIVATE - stm32f2_eth_conf.c -) +endif() \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/TARGET_NUCLEO_F207ZG/stm32f2_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/TARGET_NUCLEO_F207ZG/stm32f2_eth_init.c index 0e1c5776708..22f365067cd 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/TARGET_NUCLEO_F207ZG/stm32f2_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/TARGET_NUCLEO_F207ZG/stm32f2_eth_init.c @@ -29,98 +29,87 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - #include "stm32f2xx_hal.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PB13 */ - GPIO_InitStructure.Pin = GPIO_PIN_13; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + /* Configure PB13 */ + GPIO_InitStructure.Pin = GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Configure PG11 and PG13 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PG11 and PG13 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /* Disable the Ethernet global Interrupt */ + NVIC_DisableIRQ(ETH_IRQn); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/stm32f2_eth_conf.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/stm32f2_eth_conf.c deleted file mode 100644 index 24b5fb7b7ce..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/stm32f2_eth_conf.c +++ /dev/null @@ -1,61 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "stm32f2xx_hal.h" - -void _eth_config_mac(ETH_HandleTypeDef *heth) -{ - ETH_MACInitTypeDef macconf = { - .Watchdog = ETH_WATCHDOG_ENABLE, - .Jabber = ETH_JABBER_ENABLE, - .InterFrameGap = ETH_INTERFRAMEGAP_96BIT, - .CarrierSense = ETH_CARRIERSENCE_ENABLE, - .ReceiveOwn = ETH_RECEIVEOWN_ENABLE, - .LoopbackMode = ETH_LOOPBACKMODE_DISABLE, - .ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE, - .RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE, - .AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE, - .BackOffLimit = ETH_BACKOFFLIMIT_10, - .DeferralCheck = ETH_DEFFERRALCHECK_DISABLE, - .ReceiveAll = ETH_RECEIVEAll_DISABLE, - .SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE, - .PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL, - .BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE, - .DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL, - .PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE, - .MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE, - .UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT, - .HashTableHigh = 0x0U, - .HashTableLow = 0x0U, - .PauseTime = 0x0U, - .ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE, - .PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4, - .UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE, - .ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE, - .TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE, - .VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT, - .VLANTagIdentifier = 0x0U - }; - - if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; - } else { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; - } - - (void) HAL_ETH_ConfigMAC(heth, &macconf); -} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/stm32xx_emac_config.h b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/stm32xx_emac_config.h deleted file mode 100644 index c4fe5e7a013..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F2/stm32xx_emac_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef STM32XX_EMAC_CONFIG_H__ -#define STM32XX_EMAC_CONFIG_H__ - -#define ETH_IP_VERSION_V1 - -#endif // #define STM32XX_EMAC_CONFIG_H__ diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/CMakeLists.txt index d952229bba9..eb70c149ce4 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/CMakeLists.txt @@ -1,15 +1,8 @@ # Copyright (c) 2020 ARM Limited. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -if("ARCH_MAX" IN_LIST MBED_TARGET_LABELS) - add_subdirectory(TARGET_ARCH_MAX) -elseif("NUCLEO_F429ZI" IN_LIST MBED_TARGET_LABELS) +if("NUCLEO_F429ZI" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_NUCLEO_F429ZI) elseif("NUCLEO_F439ZI" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_NUCLEO_F439ZI) -endif() - -target_include_directories(mbed-emac - PUBLIC - . -) +endif() \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/CMakeLists.txt deleted file mode 100644 index 07d2f1d1b26..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2020 ARM Limited. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -target_include_directories(mbed-emac - PUBLIC - . -) - -target_sources(mbed-emac - PRIVATE - stm32f4_eth_conf.c - stm32f4_eth_init.c -) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/stm32f4_eth_conf.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/stm32f4_eth_conf.c deleted file mode 100644 index f41db94ac67..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/stm32f4_eth_conf.c +++ /dev/null @@ -1,61 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "stm32f4xx_hal.h" - -void _eth_config_mac(ETH_HandleTypeDef *heth) -{ - ETH_MACInitTypeDef macconf = { - .Watchdog = ETH_WATCHDOG_ENABLE, - .Jabber = ETH_JABBER_ENABLE, - .InterFrameGap = ETH_INTERFRAMEGAP_96BIT, - .CarrierSense = ETH_CARRIERSENCE_ENABLE, - .ReceiveOwn = ETH_RECEIVEOWN_ENABLE, - .LoopbackMode = ETH_LOOPBACKMODE_DISABLE, - .ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE, - .RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE, - .AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE, - .BackOffLimit = ETH_BACKOFFLIMIT_10, - .DeferralCheck = ETH_DEFFERRALCHECK_DISABLE, - .ReceiveAll = ETH_RECEIVEAll_DISABLE, - .SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE, - .PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL, - .BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE, - .DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL, - .PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE, - .MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE, - .UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT, - .HashTableHigh = 0x0U, - .HashTableLow = 0x0U, - .PauseTime = 0x0U, - .ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE, - .PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4, - .UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE, - .ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE, - .TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE, - .VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT, - .VLANTagIdentifier = 0x0U, - }; - - if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; - } else { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; - } - - (void) HAL_ETH_ConfigMAC(heth, &macconf); -} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/stm32f4_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/stm32f4_eth_init.c deleted file mode 100644 index 59c233e7890..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_ARCH_MAX/stm32f4_eth_init.c +++ /dev/null @@ -1,115 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2022, STMicroelectronics - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "stm32f4xx_hal.h" - -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) -{ - GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PB11 - RMII_MII_TXD0 ---------------------> PB12 - RMII_MII_TXD1 ---------------------> PB13 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - - /* Configure PB11, PB12 and PB13 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); - - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } -} - -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) -{ - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); - - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PB11 - RMII_MII_TXD0 ---------------------> PB12 - RMII_MII_TXD1 ---------------------> PB13 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } -} - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/CMakeLists.txt index 07d2f1d1b26..a550c5b5ada 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/CMakeLists.txt @@ -8,6 +8,5 @@ target_include_directories(mbed-emac target_sources(mbed-emac PRIVATE - stm32f4_eth_conf.c stm32f4_eth_init.c ) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/stm32f4_eth_conf.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/stm32f4_eth_conf.c deleted file mode 100644 index f41db94ac67..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/stm32f4_eth_conf.c +++ /dev/null @@ -1,61 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "stm32f4xx_hal.h" - -void _eth_config_mac(ETH_HandleTypeDef *heth) -{ - ETH_MACInitTypeDef macconf = { - .Watchdog = ETH_WATCHDOG_ENABLE, - .Jabber = ETH_JABBER_ENABLE, - .InterFrameGap = ETH_INTERFRAMEGAP_96BIT, - .CarrierSense = ETH_CARRIERSENCE_ENABLE, - .ReceiveOwn = ETH_RECEIVEOWN_ENABLE, - .LoopbackMode = ETH_LOOPBACKMODE_DISABLE, - .ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE, - .RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE, - .AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE, - .BackOffLimit = ETH_BACKOFFLIMIT_10, - .DeferralCheck = ETH_DEFFERRALCHECK_DISABLE, - .ReceiveAll = ETH_RECEIVEAll_DISABLE, - .SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE, - .PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL, - .BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE, - .DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL, - .PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE, - .MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE, - .UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT, - .HashTableHigh = 0x0U, - .HashTableLow = 0x0U, - .PauseTime = 0x0U, - .ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE, - .PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4, - .UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE, - .ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE, - .TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE, - .VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT, - .VLANTagIdentifier = 0x0U, - }; - - if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; - } else { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; - } - - (void) HAL_ETH_ConfigMAC(heth, &macconf); -} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/stm32f4_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/stm32f4_eth_init.c index 6423a3f92d2..68ad1aee8df 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/stm32f4_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F429ZI/stm32f4_eth_init.c @@ -29,98 +29,87 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - #include "stm32f4xx_hal.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PB13 */ - GPIO_InitStructure.Pin = GPIO_PIN_13; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + /* Configure PB13 */ + GPIO_InitStructure.Pin = GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Configure PG11 and PG13 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PG11 and PG13 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /* Disable the Ethernet global Interrupt */ + NVIC_DisableIRQ(ETH_IRQn); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/CMakeLists.txt index 07d2f1d1b26..a550c5b5ada 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/CMakeLists.txt @@ -8,6 +8,5 @@ target_include_directories(mbed-emac target_sources(mbed-emac PRIVATE - stm32f4_eth_conf.c stm32f4_eth_init.c ) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/stm32f4_eth_conf.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/stm32f4_eth_conf.c deleted file mode 100644 index f41db94ac67..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/stm32f4_eth_conf.c +++ /dev/null @@ -1,61 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "stm32f4xx_hal.h" - -void _eth_config_mac(ETH_HandleTypeDef *heth) -{ - ETH_MACInitTypeDef macconf = { - .Watchdog = ETH_WATCHDOG_ENABLE, - .Jabber = ETH_JABBER_ENABLE, - .InterFrameGap = ETH_INTERFRAMEGAP_96BIT, - .CarrierSense = ETH_CARRIERSENCE_ENABLE, - .ReceiveOwn = ETH_RECEIVEOWN_ENABLE, - .LoopbackMode = ETH_LOOPBACKMODE_DISABLE, - .ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE, - .RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE, - .AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE, - .BackOffLimit = ETH_BACKOFFLIMIT_10, - .DeferralCheck = ETH_DEFFERRALCHECK_DISABLE, - .ReceiveAll = ETH_RECEIVEAll_DISABLE, - .SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE, - .PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL, - .BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE, - .DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL, - .PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE, - .MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE, - .UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT, - .HashTableHigh = 0x0U, - .HashTableLow = 0x0U, - .PauseTime = 0x0U, - .ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE, - .PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4, - .UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE, - .ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE, - .TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE, - .VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT, - .VLANTagIdentifier = 0x0U, - }; - - if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; - } else { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; - } - - (void) HAL_ETH_ConfigMAC(heth, &macconf); -} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/stm32f4_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/stm32f4_eth_init.c index 6423a3f92d2..b8958960c51 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/stm32f4_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F439ZI/stm32f4_eth_init.c @@ -29,98 +29,86 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT #include "stm32f4xx_hal.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { - GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PB13 */ - GPIO_InitStructure.Pin = GPIO_PIN_13; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + /* Configure PB13 */ + GPIO_InitStructure.Pin = GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Configure PG11 and PG13 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PG11 and PG13 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /* Disable the Ethernet global Interrupt */ + NVIC_DisableIRQ(ETH_IRQn); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/stm32xx_emac_config.h b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/stm32xx_emac_config.h deleted file mode 100644 index c4fe5e7a013..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F4/stm32xx_emac_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef STM32XX_EMAC_CONFIG_H__ -#define STM32XX_EMAC_CONFIG_H__ - -#define ETH_IP_VERSION_V1 - -#endif // #define STM32XX_EMAC_CONFIG_H__ diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/CMakeLists.txt index 46dc00c7ffb..bbb58b9239c 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/CMakeLists.txt @@ -12,13 +12,3 @@ elseif("NUCLEO_F756ZG" IN_LIST MBED_TARGET_LABELS) elseif("NUCLEO_F767ZI" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_NUCLEO_F767ZI) endif() - -target_include_directories(mbed-emac - PUBLIC - . -) - -target_sources(mbed-emac - PRIVATE - stm32f7_eth_conf.c -) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F746NG/stm32f7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F746NG/stm32f7_eth_init.c index 25f8bf61aeb..a4112a8a62f 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F746NG/stm32f7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F746NG/stm32f7_eth_init.c @@ -29,97 +29,79 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - #include "stm32f7xx_hal.h" -#include "platform/mbed_critical.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { - GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - /* Disable DCache for STM32F7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PG14 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PG14 + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Configure PG11, PG13 and PG14 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PG11, PG13 and PG14 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PG14 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PG14 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /* Disable the Ethernet global Interrupt */ + NVIC_DisableIRQ(ETH_IRQn); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F769NI/stm32f7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F769NI/stm32f7_eth_init.c index b66ca2c60cc..b735f5e208b 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F769NI/stm32f7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_DISCO_F769NI/stm32f7_eth_init.c @@ -29,97 +29,81 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - #include "stm32f7xx_hal.h" -#include "platform/mbed_critical.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - /* Disable DCache for STM32F7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PG14 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PG14 + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Configure PG11, PG13 and PG14 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PG11, PG13 and PG14 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PG14 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PG14 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /* Disable the Ethernet global Interrupt */ + NVIC_DisableIRQ(ETH_IRQn); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F746ZG/stm32f7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F746ZG/stm32f7_eth_init.c index ebc2d0448e8..41a44fb8120 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F746ZG/stm32f7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F746ZG/stm32f7_eth_init.c @@ -29,103 +29,86 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT #include "stm32f7xx_hal.h" -#include "platform/mbed_critical.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { - GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - /* Disable DCache for STM32F7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PB13 */ - GPIO_InitStructure.Pin = GPIO_PIN_13; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + /* Configure PB13 */ + GPIO_InitStructure.Pin = GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Configure PG11 and PG13 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PG11 and PG13 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /* Disable the Ethernet global Interrupt */ + NVIC_DisableIRQ(ETH_IRQn); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F756ZG/stm32f7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F756ZG/stm32f7_eth_init.c index aa1287139d6..41a44fb8120 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F756ZG/stm32f7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F756ZG/stm32f7_eth_init.c @@ -29,103 +29,86 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT #include "stm32f7xx_hal.h" -#include "platform/mbed_critical.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { - GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - /* Disable DCache for STM32F7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PB13 */ - GPIO_InitStructure.Pin = GPIO_PIN_13; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + /* Configure PB13 */ + GPIO_InitStructure.Pin = GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Configure PG11 and PG13 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PG11 and PG13 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Enable the Ethernet global Interrupt */ + HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); + HAL_NVIC_EnableIRQ(ETH_IRQn); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /* Disable the Ethernet global Interrupt */ + NVIC_DisableIRQ(ETH_IRQn); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F767ZI/stm32f7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F767ZI/stm32f7_eth_init.c index 70eef691701..57242048401 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F767ZI/stm32f7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/TARGET_NUCLEO_F767ZI/stm32f7_eth_init.c @@ -28,103 +28,84 @@ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT #include "stm32f7xx_hal.h" -#include "platform/mbed_critical.h" +#include "PinNames.h" -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStructure; - if (heth->Instance == ETH) { - /* Disable DCache for STM32F7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - /* Enable GPIOs clocks */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + /* Enable GPIOs clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - /* Configure PA1, PA2 and PA7 */ - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Alternate = GPIO_AF11_ETH; - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; - HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 - /* Configure PB13 */ - GPIO_InitStructure.Pin = GPIO_PIN_13; - HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + NOTE: Must install JP6 and JP7 on board to use Ethernet. + */ + /* Configure PA1, PA2 and PA7 */ + GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Alternate = GPIO_AF11_ETH; + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); - /* Configure PC1, PC4 and PC5 */ - GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; - HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + /* Configure PB13 */ + GPIO_InitStructure.Pin = GPIO_PIN_13; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); - /* Configure PG11 and PG13 */ - GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; - HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + /* Configure PC1, PC4 and PC5 */ + GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); - /* Enable the Ethernet global Interrupt */ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); + /* Configure PG11 and PG13 */ + GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); - /* Enable ETHERNET clock */ - __HAL_RCC_ETH_CLK_ENABLE(); - } + /* Enable ETHERNET clock */ + __HAL_RCC_ETH_CLK_ENABLE(); } -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH_CLK_DISABLE(); - - /** ETH GPIO Configuration - RMII_REF_CLK ----------------------> PA1 - RMII_MDIO -------------------------> PA2 - RMII_MDC --------------------------> PC1 - RMII_MII_CRS_DV -------------------> PA7 - RMII_MII_RXD0 ---------------------> PC4 - RMII_MII_RXD1 ---------------------> PC5 - RMII_MII_RXER ---------------------> none - RMII_MII_TX_EN --------------------> PG11 - RMII_MII_TXD0 ---------------------> PG13 - RMII_MII_TXD1 ---------------------> PB13 - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); - HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); - /* Disable the Ethernet global Interrupt */ - NVIC_DisableIRQ(ETH_IRQn); - } + /** ETH GPIO Configuration + RMII_REF_CLK ----------------------> PA1 + RMII_MDIO -------------------------> PA2 + RMII_MDC --------------------------> PC1 + RMII_MII_CRS_DV -------------------> PA7 + RMII_MII_RXD0 ---------------------> PC4 + RMII_MII_RXD1 ---------------------> PC5 + RMII_MII_RXER ---------------------> none + RMII_MII_TX_EN --------------------> PG11 + RMII_MII_TXD0 ---------------------> PG13 + RMII_MII_TXD1 ---------------------> PB13 + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7); + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13); + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11 | GPIO_PIN_13); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/stm32f7_eth_conf.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/stm32f7_eth_conf.c deleted file mode 100644 index bf725b6b6a1..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/stm32f7_eth_conf.c +++ /dev/null @@ -1,65 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "stm32f7xx_hal.h" - -#if defined ETH - -void _eth_config_mac(ETH_HandleTypeDef *heth) -{ - ETH_MACInitTypeDef macconf = { - .Watchdog = ETH_WATCHDOG_ENABLE, - .Jabber = ETH_JABBER_ENABLE, - .InterFrameGap = ETH_INTERFRAMEGAP_96BIT, - .CarrierSense = ETH_CARRIERSENCE_ENABLE, - .ReceiveOwn = ETH_RECEIVEOWN_ENABLE, - .LoopbackMode = ETH_LOOPBACKMODE_DISABLE, - .ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE, - .RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE, - .AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE, - .BackOffLimit = ETH_BACKOFFLIMIT_10, - .DeferralCheck = ETH_DEFFERRALCHECK_DISABLE, - .ReceiveAll = ETH_RECEIVEAll_DISABLE, - .SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE, - .PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL, - .BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE, - .DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL, - .PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE, - .MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE, - .UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT, - .HashTableHigh = 0x0, - .HashTableLow = 0x0, - .PauseTime = 0x0, - .ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE, - .PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4, - .UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE, - .ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE, - .TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE, - .VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT, - .VLANTagIdentifier = 0x0 - }; - - if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; - } else { - macconf.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; - } - - (void) HAL_ETH_ConfigMAC(heth, &macconf); -} - -#endif // defined ETH diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/stm32xx_emac_config.h b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/stm32xx_emac_config.h deleted file mode 100644 index c4fe5e7a013..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32F7/stm32xx_emac_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef STM32XX_EMAC_CONFIG_H__ -#define STM32XX_EMAC_CONFIG_H__ - -#define ETH_IP_VERSION_V1 - -#endif // #define STM32XX_EMAC_CONFIG_H__ diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/CMakeLists.txt new file mode 100644 index 00000000000..4d5bb6aeb92 --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Jamie Smith +# SPDX-License-Identifier: Apache-2.0 + +if("NUCLEO_H563ZI" IN_LIST MBED_TARGET_LABELS) + add_subdirectory(TARGET_NUCLEO_H563ZI) +endif() \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/TARGET_NUCLEO_H563ZI/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/TARGET_NUCLEO_H563ZI/CMakeLists.txt new file mode 100644 index 00000000000..48a8fc06595 --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/TARGET_NUCLEO_H563ZI/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Jamie Smith +# SPDX-License-Identifier: Apache-2.0 + +target_sources(mbed-emac + PRIVATE + stm32h5_eth_init.c +) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/TARGET_NUCLEO_H563ZI/stm32h5_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/TARGET_NUCLEO_H563ZI/stm32h5_eth_init.c new file mode 100644 index 00000000000..c936a6886cf --- /dev/null +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H5/TARGET_NUCLEO_H563ZI/stm32h5_eth_init.c @@ -0,0 +1,127 @@ +/* mbed Microcontroller Library + * Copyright (c) 2025, STMicroelectronics + * All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stm32h5xx_hal.h" +#include "platform/mbed_critical.h" +#include "PinNames.h" + +/** + * Override HAL Eth Init function. + * + * Note: This was copied from HAL_ETH_MspInit() in a project for the NUCLEO-H563ZI in STM32CubeIDE + */ +void EthInitPinmappings(void) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* Peripheral clock enable */ + __HAL_RCC_ETH_CLK_ENABLE(); + __HAL_RCC_ETHTX_CLK_ENABLE(); + __HAL_RCC_ETHRX_CLK_ENABLE(); + + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + /**ETH GPIO Configuration + PC1 ------> ETH_MDC + PA1 ------> ETH_REF_CLK + PA2 ------> ETH_MDIO + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + PB15 ------> ETH_TXD1 + PG11 ------> ETH_TX_EN + PG13 ------> ETH_TXD0 + */ + GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_15; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); +} + +/** + * Override HAL Eth DeInit function + */ +void EthDeinitPinmappings() +{ + /* Peripheral clock disable */ + __HAL_RCC_ETH_CLK_DISABLE(); + __HAL_RCC_ETHTX_CLK_DISABLE(); + __HAL_RCC_ETHRX_CLK_DISABLE(); + + /**ETH GPIO Configuration + PC1 ------> ETH_MDC + PA1 ------> ETH_REF_CLK + PA2 ------> ETH_MDIO + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + PB15 ------> ETH_TXD1 + PG11 ------> ETH_TX_EN + PG13 ------> ETH_TXD0 + */ + HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5); + + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7); + + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_15); + + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11|GPIO_PIN_13); +} + +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/CMakeLists.txt index f4271f1b683..9181cace75d 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/CMakeLists.txt @@ -5,21 +5,8 @@ if("DISCO_H747I" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_DISCO_H747I) elseif("PORTENTA_H7" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_PORTENTA_H7) -elseif("NUCLEO_H743ZI" IN_LIST MBED_TARGET_LABELS) - add_subdirectory(TARGET_NUCLEO_H743ZI) elseif("NUCLEO_H743ZI2" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_NUCLEO_H743ZI2) elseif("NUCLEO_H723ZG" IN_LIST MBED_TARGET_LABELS) add_subdirectory(TARGET_NUCLEO_H723ZG) endif() - -target_include_directories(mbed-emac - PUBLIC - . - ./lan8742 -) - -target_sources(mbed-emac - PRIVATE - lan8742/lan8742.c -) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_DISCO_H747I/stm32h7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_DISCO_H747I/stm32h7_eth_init.c index a7d1444d7c8..2b239110804 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_DISCO_H747I/stm32h7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_DISCO_H747I/stm32h7_eth_init.c @@ -35,10 +35,9 @@ #endif #endif -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - #include "stm32h7xx_hal.h" #include "platform/mbed_critical.h" +#include "PinNames.h" #define ETH_TX_EN_Pin GPIO_PIN_11 #define ETH_TX_EN_GPIO_Port GPIOG @@ -63,96 +62,84 @@ /** * Override HAL Eth Init function */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStruct; - if (heth->Instance == ETH) { -#if defined(CORE_CM7) - /* Disable DCache for STM32H7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); -#endif - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - // __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - // __HAL_RCC_GPIOH_CLK_ENABLE(); - - /* Enable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_ENABLE(); - __HAL_RCC_ETH1TX_CLK_ENABLE(); - __HAL_RCC_ETH1RX_CLK_ENABLE(); - - /**ETH GPIO Configuration - PG11 ------> ETH_TX_EN - PG12 ------> ETH_TXD1 - PG13 ------> ETH_TXD0 - PC1 ------> ETH_MDC - PA2 ------> ETH_MDIO - PA1 ------> ETH_REF_CLK - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - */ - GPIO_InitStruct.Pin = ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - } + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + // __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + // __HAL_RCC_GPIOH_CLK_ENABLE(); + + /* Enable Peripheral clock */ + __HAL_RCC_ETH1MAC_CLK_ENABLE(); + __HAL_RCC_ETH1TX_CLK_ENABLE(); + __HAL_RCC_ETH1RX_CLK_ENABLE(); + + /**ETH GPIO Configuration + PG11 ------> ETH_TX_EN + PG12 ------> ETH_TXD1 + PG13 ------> ETH_TXD0 + PC1 ------> ETH_MDC + PA2 ------> ETH_MDIO + PA1 ------> ETH_REF_CLK + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + */ + GPIO_InitStruct.Pin = ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } /** * Override HAL Eth DeInit function */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH1MAC_CLK_DISABLE(); - __HAL_RCC_ETH1TX_CLK_DISABLE(); - __HAL_RCC_ETH1RX_CLK_DISABLE(); - - /**ETH GPIO Configuration - PG11 ------> ETH_TX_EN - PG12 ------> ETH_TXD1 - PG13 ------> ETH_TXD0 - PC1 ------> ETH_MDC - PA2 ------> ETH_MDIO - PA1 ------> ETH_REF_CLK - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - */ - HAL_GPIO_DeInit(GPIOG, ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin); - - HAL_GPIO_DeInit(GPIOC, ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin); - - HAL_GPIO_DeInit(GPIOA, ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin); - } + /* Peripheral clock disable */ + __HAL_RCC_ETH1MAC_CLK_DISABLE(); + __HAL_RCC_ETH1TX_CLK_DISABLE(); + __HAL_RCC_ETH1RX_CLK_DISABLE(); + + /**ETH GPIO Configuration + PG11 ------> ETH_TX_EN + PG12 ------> ETH_TXD1 + PG13 ------> ETH_TXD0 + PC1 ------> ETH_MDC + PA2 ------> ETH_MDIO + PA1 ------> ETH_REF_CLK + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + */ + HAL_GPIO_DeInit(GPIOG, ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin); + + HAL_GPIO_DeInit(GPIOC, ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin); + + HAL_GPIO_DeInit(GPIOA, ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/CMakeLists.txt index 5e6c9d6be72..09efa30253f 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/CMakeLists.txt @@ -2,6 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 target_sources(mbed-emac - INTERFACE + PRIVATE stm32h7_eth_init.c ) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/stm32h7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/stm32h7_eth_init.c index b0fc3347124..66cbd3ae5b7 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/stm32h7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H723ZG/stm32h7_eth_init.c @@ -28,10 +28,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - #include "stm32h7xx_hal.h" #include "platform/mbed_critical.h" +#include "PinNames.h" #define MCO_Pin GPIO_PIN_0 #define MCO_GPIO_Port GPIOH @@ -61,109 +60,100 @@ /** * Override HAL Eth Init function */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStruct; - if (heth->Instance == ETH) { - /* Disable DCache for STM32H7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOH_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - - /* Enable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_ENABLE(); - __HAL_RCC_ETH1TX_CLK_ENABLE(); - __HAL_RCC_ETH1RX_CLK_ENABLE(); - - /**ETH GPIO Configuration - PC1 ------> ETH_MDC - PA1 ------> ETH_REF_CLK - PA2 ------> ETH_MDIO - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - PB13 ------> ETH_TXD1 - PG11 ------> ETH_TX_EN - PG13 ------> ETH_TXD0 - */ - GPIO_InitStruct.Pin = RMII_MDC_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(RMII_MDC_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_RXD0_Pin | RMII_RXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_TXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_TX_EN_Pin | RMII_TXD0_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); - } + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Enable Peripheral clock */ + __HAL_RCC_ETH1MAC_CLK_ENABLE(); + __HAL_RCC_ETH1TX_CLK_ENABLE(); + __HAL_RCC_ETH1RX_CLK_ENABLE(); + + /**ETH GPIO Configuration + PC1 ------> ETH_MDC + PA1 ------> ETH_REF_CLK + PA2 ------> ETH_MDIO + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + PB13 ------> ETH_TXD1 + PG11 ------> ETH_TX_EN + PG13 ------> ETH_TXD0 + */ + GPIO_InitStruct.Pin = RMII_MDC_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(RMII_MDC_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_RXD0_Pin | RMII_RXD1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_TXD1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_TX_EN_Pin | RMII_TXD0_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); } /** * Override HAL Eth DeInit function */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Disable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_DISABLE(); - __HAL_RCC_ETH1TX_CLK_DISABLE(); - __HAL_RCC_ETH1RX_CLK_DISABLE(); - - /**ETH GPIO Configuration - PC1 ------> ETH_MDC - PA1 ------> ETH_REF_CLK - PA2 ------> ETH_MDIO - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - PB13 ------> ETH_TXD1 - PG11 ------> ETH_TX_EN - PG13 ------> ETH_TXD0 - */ - HAL_GPIO_DeInit(GPIOC, RMII_MDC_Pin | RMII_RXD0_Pin | RMII_RXD1_Pin); - - HAL_GPIO_DeInit(GPIOA, RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin); - - HAL_GPIO_DeInit(RMII_TXD1_GPIO_Port, RMII_TXD1_Pin); - - HAL_GPIO_DeInit(GPIOG, RMII_TX_EN_Pin | RMII_TXD0_Pin); - } + /* Disable Peripheral clock */ + __HAL_RCC_ETH1MAC_CLK_DISABLE(); + __HAL_RCC_ETH1TX_CLK_DISABLE(); + __HAL_RCC_ETH1RX_CLK_DISABLE(); + + /**ETH GPIO Configuration + PC1 ------> ETH_MDC + PA1 ------> ETH_REF_CLK + PA2 ------> ETH_MDIO + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + PB13 ------> ETH_TXD1 + PG11 ------> ETH_TX_EN + PG13 ------> ETH_TXD0 + */ + HAL_GPIO_DeInit(GPIOC, RMII_MDC_Pin | RMII_RXD0_Pin | RMII_RXD1_Pin); + + HAL_GPIO_DeInit(GPIOA, RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin); + + HAL_GPIO_DeInit(RMII_TXD1_GPIO_Port, RMII_TXD1_Pin); + + HAL_GPIO_DeInit(GPIOG, RMII_TX_EN_Pin | RMII_TXD0_Pin); } -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} - -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI/CMakeLists.txt deleted file mode 100644 index 09efa30253f..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) 2020 ARM Limited. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -target_sources(mbed-emac - PRIVATE - stm32h7_eth_init.c -) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI/stm32h7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI/stm32h7_eth_init.c deleted file mode 100644 index 81be13b3c5b..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI/stm32h7_eth_init.c +++ /dev/null @@ -1,169 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2022, STMicroelectronics - * All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - -#include "stm32h7xx_hal.h" -#include "platform/mbed_critical.h" - -#define MCO_Pin GPIO_PIN_0 -#define MCO_GPIO_Port GPIOH -#define RMII_MDC_Pin GPIO_PIN_1 -#define RMII_MDC_GPIO_Port GPIOC -#define RMII_REF_CLK_Pin GPIO_PIN_1 -#define RMII_REF_CLK_GPIO_Port GPIOA -#define RMII_MDIO_Pin GPIO_PIN_2 -#define RMII_MDIO_GPIO_Port GPIOA -#define RMII_CRS_DV_Pin GPIO_PIN_7 -#define RMII_CRS_DV_GPIO_Port GPIOA -#define RMII_RXD0_Pin GPIO_PIN_4 -#define RMII_RXD0_GPIO_Port GPIOC -#define RMII_RXD1_Pin GPIO_PIN_5 -#define RMII_RXD1_GPIO_Port GPIOC -#define RMII_TXD1_Pin GPIO_PIN_13 -#define RMII_TXD1_GPIO_Port GPIOB -#define TMS_Pin GPIO_PIN_13 -#define TMS_GPIO_Port GPIOA -#define TCK_Pin GPIO_PIN_14 -#define TCK_GPIO_Port GPIOA -#define RMII_TX_EN_Pin GPIO_PIN_11 -#define RMII_TX_EN_GPIO_Port GPIOG -#define RMII_TXD0_Pin GPIO_PIN_13 -#define RMII_TXD0_GPIO_Port GPIOG - -/** - * Override HAL Eth Init function - */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) -{ - GPIO_InitTypeDef GPIO_InitStruct; - if (heth->Instance == ETH) { - /* Disable DCache for STM32H7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOH_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - - /* Enable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_ENABLE(); - __HAL_RCC_ETH1TX_CLK_ENABLE(); - __HAL_RCC_ETH1RX_CLK_ENABLE(); - - /**ETH GPIO Configuration - PC1 ------> ETH_MDC - PA1 ------> ETH_REF_CLK - PA2 ------> ETH_MDIO - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - PB13 ------> ETH_TXD1 - PG11 ------> ETH_TX_EN - PG13 ------> ETH_TXD0 - */ - GPIO_InitStruct.Pin = RMII_MDC_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(RMII_MDC_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_RXD0_Pin | RMII_RXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_TXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_TX_EN_Pin | RMII_TXD0_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); - } -} - -/** - * Override HAL Eth DeInit function - */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) -{ - if (heth->Instance == ETH) { - /* Disable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_DISABLE(); - __HAL_RCC_ETH1TX_CLK_DISABLE(); - __HAL_RCC_ETH1RX_CLK_DISABLE(); - - /**ETH GPIO Configuration - PC1 ------> ETH_MDC - PA1 ------> ETH_REF_CLK - PA2 ------> ETH_MDIO - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - PB13 ------> ETH_TXD1 - PG11 ------> ETH_TX_EN - PG13 ------> ETH_TXD0 - */ - HAL_GPIO_DeInit(GPIOC, RMII_MDC_Pin | RMII_RXD0_Pin | RMII_RXD1_Pin); - - HAL_GPIO_DeInit(GPIOA, RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin); - - HAL_GPIO_DeInit(RMII_TXD1_GPIO_Port, RMII_TXD1_Pin); - - HAL_GPIO_DeInit(GPIOG, RMII_TX_EN_Pin | RMII_TXD0_Pin); - } -} - -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/CMakeLists.txt index 635a02bd7a3..09efa30253f 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/CMakeLists.txt @@ -2,6 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 target_sources(mbed-emac - PUBLIC + PRIVATE stm32h7_eth_init.c ) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/stm32h7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/stm32h7_eth_init.c index a06114909c6..5a77f1cdc08 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/stm32h7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_NUCLEO_H743ZI2/stm32h7_eth_init.c @@ -28,13 +28,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT - #include "stm32h7xx_hal.h" #include "platform/mbed_critical.h" +#include "PinNames.h" -#define MCO_Pin GPIO_PIN_0 -#define MCO_GPIO_Port GPIOH #define RMII_MDC_Pin GPIO_PIN_1 #define RMII_MDC_GPIO_Port GPIOC #define RMII_REF_CLK_Pin GPIO_PIN_1 @@ -49,10 +46,6 @@ #define RMII_RXD1_GPIO_Port GPIOC #define RMII_TXD1_Pin GPIO_PIN_13 #define RMII_TXD1_GPIO_Port GPIOB -#define TMS_Pin GPIO_PIN_13 -#define TMS_GPIO_Port GPIOA -#define TCK_Pin GPIO_PIN_14 -#define TCK_GPIO_Port GPIOA #define RMII_TX_EN_Pin GPIO_PIN_11 #define RMII_TX_EN_GPIO_Port GPIOG #define RMII_TXD0_Pin GPIO_PIN_13 @@ -61,109 +54,101 @@ /** * Override HAL Eth Init function */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStruct; - if (heth->Instance == ETH) { - /* Disable DCache for STM32H7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOH_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - - /* Enable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_ENABLE(); - __HAL_RCC_ETH1TX_CLK_ENABLE(); - __HAL_RCC_ETH1RX_CLK_ENABLE(); - - /**ETH GPIO Configuration - PC1 ------> ETH_MDC - PA1 ------> ETH_REF_CLK - PA2 ------> ETH_MDIO - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - PB13 ------> ETH_TXD1 - PG11 ------> ETH_TX_EN - PG13 ------> ETH_TXD0 - */ - GPIO_InitStruct.Pin = RMII_MDC_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(RMII_MDC_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_RXD0_Pin | RMII_RXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_TXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = RMII_TX_EN_Pin | RMII_TXD0_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); - } + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Enable Peripheral clock */ + __HAL_RCC_ETH1MAC_CLK_ENABLE(); + __HAL_RCC_ETH1TX_CLK_ENABLE(); + __HAL_RCC_ETH1RX_CLK_ENABLE(); + + /**ETH GPIO Configuration + PC1 ------> ETH_MDC + PA1 ------> ETH_REF_CLK + PA2 ------> ETH_MDIO + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + PB13 ------> ETH_TXD1 + PG11 ------> ETH_TX_EN + PG13 ------> ETH_TXD0 + */ + GPIO_InitStruct.Pin = RMII_MDC_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(RMII_MDC_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_RXD0_Pin | RMII_RXD1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_TXD1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(RMII_TXD1_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = RMII_TX_EN_Pin | RMII_TXD0_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); } /** * Override HAL Eth DeInit function */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Disable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_DISABLE(); - __HAL_RCC_ETH1TX_CLK_DISABLE(); - __HAL_RCC_ETH1RX_CLK_DISABLE(); - - /**ETH GPIO Configuration - PC1 ------> ETH_MDC - PA1 ------> ETH_REF_CLK - PA2 ------> ETH_MDIO - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - PB13 ------> ETH_TXD1 - PG11 ------> ETH_TX_EN - PG13 ------> ETH_TXD0 - */ - HAL_GPIO_DeInit(GPIOC, RMII_MDC_Pin | RMII_RXD0_Pin | RMII_RXD1_Pin); - - HAL_GPIO_DeInit(GPIOA, RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin); - - HAL_GPIO_DeInit(RMII_TXD1_GPIO_Port, RMII_TXD1_Pin); - - HAL_GPIO_DeInit(GPIOG, RMII_TX_EN_Pin | RMII_TXD0_Pin); - } + /* Disable Peripheral clock */ + __HAL_RCC_ETH1MAC_CLK_DISABLE(); + __HAL_RCC_ETH1TX_CLK_DISABLE(); + __HAL_RCC_ETH1RX_CLK_DISABLE(); + + /**ETH GPIO Configuration + PC1 ------> ETH_MDC + PA1 ------> ETH_REF_CLK + PA2 ------> ETH_MDIO + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + PB13 ------> ETH_TXD1 + PG11 ------> ETH_TX_EN + PG13 ------> ETH_TXD0 + */ + HAL_GPIO_DeInit(GPIOC, RMII_MDC_Pin | RMII_RXD0_Pin | RMII_RXD1_Pin); + + HAL_GPIO_DeInit(GPIOA, RMII_REF_CLK_Pin | RMII_MDIO_Pin | RMII_CRS_DV_Pin); + + HAL_GPIO_DeInit(RMII_TXD1_GPIO_Port, RMII_TXD1_Pin); + + HAL_GPIO_DeInit(GPIOG, RMII_TX_EN_Pin | RMII_TXD0_Pin); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return NC; // Not connected on this board +} diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/CMakeLists.txt b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/CMakeLists.txt index 635a02bd7a3..09efa30253f 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/CMakeLists.txt +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/CMakeLists.txt @@ -2,6 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 target_sources(mbed-emac - PUBLIC + PRIVATE stm32h7_eth_init.c ) diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/stm32h7_eth_init.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/stm32h7_eth_init.c index f9891ff757e..bf5f85156a3 100644 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/stm32h7_eth_init.c +++ b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/TARGET_PORTENTA_H7/stm32h7_eth_init.c @@ -30,11 +30,11 @@ #define ETHERNET 1 -#ifndef USE_USER_DEFINED_HAL_ETH_MSPINIT #include "stm32h7xx_hal.h" #include "portenta_power.h" #include "platform/mbed_critical.h" +#include "PinNames.h" #define ETH_TX_EN_Pin GPIO_PIN_11 #define ETH_TX_EN_GPIO_Port GPIOG @@ -58,124 +58,113 @@ /** * Override HAL Eth Init function */ -void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +void EthInitPinmappings(void) { GPIO_InitTypeDef GPIO_InitStruct; - if (heth->Instance == ETH) { - enableEthPowerSupply(); - -#if !(defined(DUAL_CORE) && defined(CORE_CM4)) - /* Disable DCache for STM32H7 family */ - core_util_critical_section_enter(); - SCB_DisableDCache(); - core_util_critical_section_exit(); -#endif - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOA_CLK_ENABLE(); - // __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); - // __HAL_RCC_GPIOH_CLK_ENABLE(); - - /* Enable Peripheral clock */ - __HAL_RCC_ETH1MAC_CLK_ENABLE(); - __HAL_RCC_ETH1TX_CLK_ENABLE(); - __HAL_RCC_ETH1RX_CLK_ENABLE(); - - /* Set pinstrap for 100mbit */ - // TODO - - /* Reset ETH Phy */ - __HAL_RCC_GPIOJ_CLK_ENABLE(); - GPIO_InitTypeDef gpio_eth_rst_init_structure; - gpio_eth_rst_init_structure.Pin = GPIO_PIN_15; - gpio_eth_rst_init_structure.Mode = GPIO_MODE_OUTPUT_PP; - gpio_eth_rst_init_structure.Pull = GPIO_NOPULL; - gpio_eth_rst_init_structure.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(GPIOJ, &gpio_eth_rst_init_structure); - - gpio_eth_rst_init_structure.Pin = ETH_RXD0_Pin | ETH_RXD1_Pin; - HAL_GPIO_Init(GPIOC, &gpio_eth_rst_init_structure); - HAL_GPIO_WritePin(GPIOC, ETH_RXD0_Pin, 1); - HAL_GPIO_WritePin(GPIOC, ETH_RXD1_Pin, 1); - gpio_eth_rst_init_structure.Pin = ETH_CRS_DV_Pin; - HAL_GPIO_Init(GPIOA, &gpio_eth_rst_init_structure); - HAL_GPIO_WritePin(GPIOA, ETH_CRS_DV_Pin, 1); - - HAL_Delay(25); - HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, 0); - HAL_Delay(100); - HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, 1); - - /**ETH GPIO Configuration - PG11 ------> ETH_TX_EN - PG12 ------> ETH_TXD1 - PG13 ------> ETH_TXD0 - PC1 ------> ETH_MDC - PA2 ------> ETH_MDIO - PA1 ------> ETH_REF_CLK - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - */ - GPIO_InitStruct.Pin = ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - GPIO_InitStruct.Pin = ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF11_ETH; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - } + enableEthPowerSupply(); + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + // __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + // __HAL_RCC_GPIOH_CLK_ENABLE(); + + /* Enable Peripheral clock */ + __HAL_RCC_ETH1MAC_CLK_ENABLE(); + __HAL_RCC_ETH1TX_CLK_ENABLE(); + __HAL_RCC_ETH1RX_CLK_ENABLE(); + + /* Set pinstrap for 100mbit */ + // TODO + + /* Reset ETH Phy */ + __HAL_RCC_GPIOJ_CLK_ENABLE(); + GPIO_InitTypeDef gpio_eth_rst_init_structure; + gpio_eth_rst_init_structure.Pin = GPIO_PIN_15; + gpio_eth_rst_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_eth_rst_init_structure.Pull = GPIO_NOPULL; + gpio_eth_rst_init_structure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOJ, &gpio_eth_rst_init_structure); + + gpio_eth_rst_init_structure.Pin = ETH_RXD0_Pin | ETH_RXD1_Pin; + HAL_GPIO_Init(GPIOC, &gpio_eth_rst_init_structure); + HAL_GPIO_WritePin(GPIOC, ETH_RXD0_Pin, 1); + HAL_GPIO_WritePin(GPIOC, ETH_RXD1_Pin, 1); + gpio_eth_rst_init_structure.Pin = ETH_CRS_DV_Pin; + HAL_GPIO_Init(GPIOA, &gpio_eth_rst_init_structure); + HAL_GPIO_WritePin(GPIOA, ETH_CRS_DV_Pin, 1); + + HAL_Delay(25); + HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, 0); + HAL_Delay(100); + HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, 1); + + /**ETH GPIO Configuration + PG11 ------> ETH_TX_EN + PG12 ------> ETH_TXD1 + PG13 ------> ETH_TXD0 + PC1 ------> ETH_MDC + PA2 ------> ETH_MDIO + PA1 ------> ETH_REF_CLK + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + */ + GPIO_InitStruct.Pin = ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF11_ETH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } /** * Override HAL Eth DeInit function */ -void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +void EthDeinitPinmappings() { - if (heth->Instance == ETH) { - /* Peripheral clock disable */ - __HAL_RCC_ETH1MAC_CLK_DISABLE(); - __HAL_RCC_ETH1TX_CLK_DISABLE(); - __HAL_RCC_ETH1RX_CLK_DISABLE(); - - /**ETH GPIO Configuration - PG11 ------> ETH_TX_EN - PG12 ------> ETH_TXD1 - PG13 ------> ETH_TXD0 - PC1 ------> ETH_MDC - PA2 ------> ETH_MDIO - PA1 ------> ETH_REF_CLK - PA7 ------> ETH_CRS_DV - PC4 ------> ETH_RXD0 - PC5 ------> ETH_RXD1 - */ - HAL_GPIO_DeInit(GPIOG, ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin); - - HAL_GPIO_DeInit(GPIOC, ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin); - - HAL_GPIO_DeInit(GPIOA, ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin); - - HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, 0); - } + /* Peripheral clock disable */ + __HAL_RCC_ETH1MAC_CLK_DISABLE(); + __HAL_RCC_ETH1TX_CLK_DISABLE(); + __HAL_RCC_ETH1RX_CLK_DISABLE(); + + /**ETH GPIO Configuration + PG11 ------> ETH_TX_EN + PG12 ------> ETH_TXD1 + PG13 ------> ETH_TXD0 + PC1 ------> ETH_MDC + PA2 ------> ETH_MDIO + PA1 ------> ETH_REF_CLK + PA7 ------> ETH_CRS_DV + PC4 ------> ETH_RXD0 + PC5 ------> ETH_RXD1 + */ + HAL_GPIO_DeInit(GPIOG, ETH_TX_EN_Pin | ETH_TXD1_Pin | ETH_TXD0_Pin); + + HAL_GPIO_DeInit(GPIOC, ETH_MDC_SAI4_D1_Pin | ETH_RXD0_Pin | ETH_RXD1_Pin); + + HAL_GPIO_DeInit(GPIOA, ETH_MDIO_Pin | ETH_REF_CLK_Pin | ETH_CRS_DV_Pin); + + HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, 0); } -#endif /* USE_USER_DEFINED_HAL_ETH_MSPINIT */ - -// Blank, non-weak-override function to make sure the linker pulls in this file -void stm32_eth_init_weak_symbol_helper() -{} \ No newline at end of file +// Get Ethernet PHY reset pin +PinName EthGetPhyResetPin(void) +{ + return PJ_15; +} \ No newline at end of file diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/lan8742/lan8742.c b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/lan8742/lan8742.c deleted file mode 100644 index 0fd341cdc46..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/lan8742/lan8742.c +++ /dev/null @@ -1,590 +0,0 @@ -/** - ****************************************************************************** - * @file lan8742.c - * @author MCD Application Team - * @version V1.0.0 - * @date 08-March-2017 - * @brief This file provides a set of functions needed to manage the LAN742 - * PHY devices. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2017 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Includes ------------------------------------------------------------------*/ -#include "lan8742.h" - -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup Component - * @{ - */ - -/** @defgroup LAN8742 LAN8742 - * @{ - */ - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/** @defgroup LAN8742_Private_Defines LAN8742 Private Defines - * @{ - */ -#define LAN8742_SW_RESET_TO ((uint32_t)500U) -#define LAN8742_INIT_TO ((uint32_t)2000U) -#define LAN8742_MAX_DEV_ADDR ((uint32_t)31U) -/** - * @} - */ - -/* Private macro -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Private function prototypes -----------------------------------------------*/ -/* Private functions ---------------------------------------------------------*/ -/** @defgroup LAN8742_Private_Functions LAN8742 Private Functions - * @{ - */ - -/** - * @brief Register IO functions to component object - * @param pObj: device object of LAN8742_Object_t. - * @param ioctx: holds device IO functions. - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_ERROR if missing mandatory function - */ -int32_t LAN8742_RegisterBusIO(lan8742_Object_t *pObj, lan8742_IOCtx_t *ioctx) -{ - if (!pObj || !ioctx->ReadReg || !ioctx->WriteReg || !ioctx->GetTick) { - return LAN8742_STATUS_ERROR; - } - - pObj->IO.Init = ioctx->Init; - pObj->IO.DeInit = ioctx->DeInit; - pObj->IO.ReadReg = ioctx->ReadReg; - pObj->IO.WriteReg = ioctx->WriteReg; - pObj->IO.GetTick = ioctx->GetTick; - - return LAN8742_STATUS_OK; -} - -/** - * @brief Initialize the lan8742 and configure the needed hardware resources - * @param pObj: device object LAN8742_Object_t. - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_ADDRESS_ERROR if cannot find device address - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - * LAN8742_STATUS_RESET_TIMEOUT if cannot perform a software reset - */ -int32_t LAN8742_Init(lan8742_Object_t *pObj) -{ - uint32_t tickstart = 0, regvalue = 0, addr = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->Is_Initialized == 0) { - if (pObj->IO.Init != 0) { - /* GPIO and Clocks initialization */ - pObj->IO.Init(); - } - - /* for later check */ - pObj->DevAddr = LAN8742_MAX_DEV_ADDR + 1; - - /* Get the device address from special mode register */ - for (addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr ++) { - if (pObj->IO.ReadReg(addr, LAN8742_SMR, ®value) < 0) { - status = LAN8742_STATUS_READ_ERROR; - /* Can't read from this device address - continue with next address */ - continue; - } - - if ((regvalue & LAN8742_SMR_PHY_ADDR) == addr) { - pObj->DevAddr = addr; - status = LAN8742_STATUS_OK; - break; - } - } - - if (pObj->DevAddr > LAN8742_MAX_DEV_ADDR) { - status = LAN8742_STATUS_ADDRESS_ERROR; - } - - /* if device address is matched */ - if (status == LAN8742_STATUS_OK) { - /* set a software reset */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_SOFT_RESET) >= 0) { - /* get software reset status */ - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, ®value) >= 0) { - tickstart = pObj->IO.GetTick(); - - /* wait until software reset is done or timeout occured */ - while (regvalue & LAN8742_BCR_SOFT_RESET) { - if ((pObj->IO.GetTick() - tickstart) <= LAN8742_SW_RESET_TO) { - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, ®value) < 0) { - status = LAN8742_STATUS_READ_ERROR; - break; - } - } else { - status = LAN8742_STATUS_RESET_TIMEOUT; - } - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - } else { - status = LAN8742_STATUS_WRITE_ERROR; - } - } - } - - if (status == LAN8742_STATUS_OK) { - tickstart = pObj->IO.GetTick(); - - /* Wait for 2s to perform initialization */ - while ((pObj->IO.GetTick() - tickstart) <= LAN8742_INIT_TO) { - } - pObj->Is_Initialized = 1; - } - - return status; -} - -/** - * @brief De-Initialize the lan8742 and it's hardware resources - * @param pObj: device object LAN8742_Object_t. - * @retval None - */ -int32_t LAN8742_DeInit(lan8742_Object_t *pObj) -{ - if (pObj->Is_Initialized) { - if (pObj->IO.DeInit != 0) { - if (pObj->IO.DeInit() < 0) { - return LAN8742_STATUS_ERROR; - } - } - - pObj->Is_Initialized = 0; - } - - return LAN8742_STATUS_OK; -} - -/** - * @brief Disable the LAN8742 power down mode. - * @param pObj: device object LAN8742_Object_t. - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_DisablePowerDownMode(lan8742_Object_t *pObj) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0) { - readval &= ~LAN8742_BCR_POWER_DOWN; - - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Enable the LAN8742 power down mode. - * @param pObj: device object LAN8742_Object_t. - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_EnablePowerDownMode(lan8742_Object_t *pObj) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0) { - readval |= LAN8742_BCR_POWER_DOWN; - - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Start the auto negotiation process. - * @param pObj: device object LAN8742_Object_t. - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_StartAutoNego(lan8742_Object_t *pObj) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0) { - readval |= LAN8742_BCR_AUTONEGO_EN; - - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Get the link state of LAN8742 device. - * @param pObj: Pointer to device object. - * @param pLinkState: Pointer to link state - * @retval LAN8742_STATUS_LINK_DOWN if link is down - * LAN8742_STATUS_AUTONEGO_NOTDONE if Auto nego not completed - * LAN8742_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD - * LAN8742_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD - * LAN8742_STATUS_10MBITS_FULLDUPLEX if 10Mb/s FD - * LAN8742_STATUS_10MBITS_HALFDUPLEX if 10Mb/s HD - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj) -{ - uint32_t readval = 0; - - /* Read Status register */ - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0) { - return LAN8742_STATUS_READ_ERROR; - } - - /* Read Status register again */ - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0) { - return LAN8742_STATUS_READ_ERROR; - } - - if ((readval & LAN8742_BSR_LINK_STATUS) == 0) { - /* Return Link Down status */ - return LAN8742_STATUS_LINK_DOWN; - } - - /* Check Auto negotiaition */ - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) < 0) { - return LAN8742_STATUS_READ_ERROR; - } - - if ((readval & LAN8742_BCR_AUTONEGO_EN) != LAN8742_BCR_AUTONEGO_EN) { - if (((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT) && ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE)) { - return LAN8742_STATUS_100MBITS_FULLDUPLEX; - } else if ((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT) { - return LAN8742_STATUS_100MBITS_HALFDUPLEX; - } else if ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE) { - return LAN8742_STATUS_10MBITS_FULLDUPLEX; - } else { - return LAN8742_STATUS_10MBITS_HALFDUPLEX; - } - } else { /* Auto Nego enabled */ - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_PHYSCSR, &readval) < 0) { - return LAN8742_STATUS_READ_ERROR; - } - - /* Check if auto nego not done */ - if ((readval & LAN8742_PHYSCSR_AUTONEGO_DONE) == 0) { - return LAN8742_STATUS_AUTONEGO_NOTDONE; - } - - if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_FD) { - return LAN8742_STATUS_100MBITS_FULLDUPLEX; - } else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_HD) { - return LAN8742_STATUS_100MBITS_HALFDUPLEX; - } else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_10BT_FD) { - return LAN8742_STATUS_10MBITS_FULLDUPLEX; - } else { - return LAN8742_STATUS_10MBITS_HALFDUPLEX; - } - } -} - -/** - * @brief Set the link state of LAN8742 device. - * @param pObj: Pointer to device object. - * @param pLinkState: link state can be one of the following - * LAN8742_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD - * LAN8742_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD - * LAN8742_STATUS_10MBITS_FULLDUPLEX if 10Mb/s FD - * LAN8742_STATUS_10MBITS_HALFDUPLEX if 10Mb/s HD - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_ERROR if parameter error - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_SetLinkState(lan8742_Object_t *pObj, uint32_t LinkState) -{ - uint32_t bcrvalue = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &bcrvalue) >= 0) { - /* Disable link config (Auto nego, speed and duplex) */ - bcrvalue &= ~(LAN8742_BCR_AUTONEGO_EN | LAN8742_BCR_SPEED_SELECT | LAN8742_BCR_DUPLEX_MODE); - - if (LinkState == LAN8742_STATUS_100MBITS_FULLDUPLEX) { - bcrvalue |= (LAN8742_BCR_SPEED_SELECT | LAN8742_BCR_DUPLEX_MODE); - } else if (LinkState == LAN8742_STATUS_100MBITS_HALFDUPLEX) { - bcrvalue |= LAN8742_BCR_SPEED_SELECT; - } else if (LinkState == LAN8742_STATUS_10MBITS_FULLDUPLEX) { - bcrvalue |= LAN8742_BCR_DUPLEX_MODE; - } else { - /* Wrong link status parameter */ - status = LAN8742_STATUS_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - if (status == LAN8742_STATUS_OK) { - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, bcrvalue) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } - - return status; -} - -/** - * @brief Enable loopback mode. - * @param pObj: Pointer to device object. - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_EnableLoopbackMode(lan8742_Object_t *pObj) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0) { - readval |= LAN8742_BCR_LOOPBACK; - - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Disable loopback mode. - * @param pObj: Pointer to device object. - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_DisableLoopbackMode(lan8742_Object_t *pObj) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) >= 0) { - readval &= ~LAN8742_BCR_LOOPBACK; - - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, readval) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Enable IT source. - * @param pObj: Pointer to device object. - * @param Interrupt: IT source to be enabled - * should be a value or a combination of the following: - * LAN8742_WOL_IT - * LAN8742_ENERGYON_IT - * LAN8742_AUTONEGO_COMPLETE_IT - * LAN8742_REMOTE_FAULT_IT - * LAN8742_LINK_DOWN_IT - * LAN8742_AUTONEGO_LP_ACK_IT - * LAN8742_PARALLEL_DETECTION_FAULT_IT - * LAN8742_AUTONEGO_PAGE_RECEIVED_IT - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_EnableIT(lan8742_Object_t *pObj, uint32_t Interrupt) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_IMR, &readval) >= 0) { - readval |= Interrupt; - - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_IMR, readval) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Disable IT source. - * @param pObj: Pointer to device object. - * @param Interrupt: IT source to be disabled - * should be a value or a combination of the following: - * LAN8742_WOL_IT - * LAN8742_ENERGYON_IT - * LAN8742_AUTONEGO_COMPLETE_IT - * LAN8742_REMOTE_FAULT_IT - * LAN8742_LINK_DOWN_IT - * LAN8742_AUTONEGO_LP_ACK_IT - * LAN8742_PARALLEL_DETECTION_FAULT_IT - * LAN8742_AUTONEGO_PAGE_RECEIVED_IT - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - * LAN8742_STATUS_WRITE_ERROR if connot write to register - */ -int32_t LAN8742_DisableIT(lan8742_Object_t *pObj, uint32_t Interrupt) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_IMR, &readval) >= 0) { - readval &= ~Interrupt; - - /* Apply configuration */ - if (pObj->IO.WriteReg(pObj->DevAddr, LAN8742_IMR, readval) < 0) { - status = LAN8742_STATUS_WRITE_ERROR; - } - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Clear IT flag. - * @param pObj: Pointer to device object. - * @param Interrupt: IT flag to be cleared - * should be a value or a combination of the following: - * LAN8742_WOL_IT - * LAN8742_ENERGYON_IT - * LAN8742_AUTONEGO_COMPLETE_IT - * LAN8742_REMOTE_FAULT_IT - * LAN8742_LINK_DOWN_IT - * LAN8742_AUTONEGO_LP_ACK_IT - * LAN8742_PARALLEL_DETECTION_FAULT_IT - * LAN8742_AUTONEGO_PAGE_RECEIVED_IT - * @retval LAN8742_STATUS_OK if OK - * LAN8742_STATUS_READ_ERROR if connot read register - */ -int32_t LAN8742_ClearIT(lan8742_Object_t *pObj, uint32_t Interrupt) -{ - uint32_t readval = 0; - int32_t status = LAN8742_STATUS_OK; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_ISFR, &readval) < 0) { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @brief Get IT Flag status. - * @param pObj: Pointer to device object. - * @param Interrupt: IT Flag to be checked, - * should be a value or a combination of the following: - * LAN8742_WOL_IT - * LAN8742_ENERGYON_IT - * LAN8742_AUTONEGO_COMPLETE_IT - * LAN8742_REMOTE_FAULT_IT - * LAN8742_LINK_DOWN_IT - * LAN8742_AUTONEGO_LP_ACK_IT - * LAN8742_PARALLEL_DETECTION_FAULT_IT - * LAN8742_AUTONEGO_PAGE_RECEIVED_IT - * @retval 1 IT flag is SET - * 0 IT flag is RESET - * LAN8742_STATUS_READ_ERROR if connot read register - */ -int32_t LAN8742_GetITStatus(lan8742_Object_t *pObj, uint32_t Interrupt) -{ - uint32_t readval = 0; - int32_t status = 0; - - if (pObj->IO.ReadReg(pObj->DevAddr, LAN8742_ISFR, &readval) >= 0) { - status = ((readval & Interrupt) == Interrupt); - } else { - status = LAN8742_STATUS_READ_ERROR; - } - - return status; -} - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/lan8742/lan8742.h b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/lan8742/lan8742.h deleted file mode 100644 index 0214cffdea4..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/lan8742/lan8742.h +++ /dev/null @@ -1,464 +0,0 @@ -/** - ****************************************************************************** - * @file lan8742.h - * @author MCD Application Team - * @version V1.0.0 - * @date 08-March-2017 - * @brief This file contains all the functions prototypes for the - * lan8742.c PHY driver. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2017 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __LAN8742_H -#define __LAN8742_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include - -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup Component - * @{ - */ - -/** @defgroup LAN8742 - * @{ - */ -/* Exported constants --------------------------------------------------------*/ -/** @defgroup LAN8742_Exported_Constants LAN8742 Exported Constants - * @{ - */ - -/** @defgroup LAN8742_Registers_Mapping LAN8742 Registers Mapping - * @{ - */ -#define LAN8742_BCR ((uint16_t)0x0000U) -#define LAN8742_BSR ((uint16_t)0x0001U) -#define LAN8742_PHYI1R ((uint16_t)0x0002U) -#define LAN8742_PHYI2R ((uint16_t)0x0003U) -#define LAN8742_ANAR ((uint16_t)0x0004U) -#define LAN8742_ANLPAR ((uint16_t)0x0005U) -#define LAN8742_ANER ((uint16_t)0x0006U) -#define LAN8742_ANNPTR ((uint16_t)0x0007U) -#define LAN8742_ANNPRR ((uint16_t)0x0008U) -#define LAN8742_MMDACR ((uint16_t)0x000DU) -#define LAN8742_MMDAADR ((uint16_t)0x000EU) -#define LAN8742_ENCTR ((uint16_t)0x0010U) -#define LAN8742_MCSR ((uint16_t)0x0011U) -#define LAN8742_SMR ((uint16_t)0x0012U) -#define LAN8742_TPDCR ((uint16_t)0x0018U) -#define LAN8742_TCSR ((uint16_t)0x0019U) -#define LAN8742_SECR ((uint16_t)0x001AU) -#define LAN8742_SCSIR ((uint16_t)0x001BU) -#define LAN8742_CLR ((uint16_t)0x001CU) -#define LAN8742_ISFR ((uint16_t)0x001DU) -#define LAN8742_IMR ((uint16_t)0x001EU) -#define LAN8742_PHYSCSR ((uint16_t)0x001FU) -/** - * @} - */ - -/** @defgroup LAN8742_BCR_Bit_Definition LAN8742 BCR Bit Definition - * @{ - */ -#define LAN8742_BCR_SOFT_RESET ((uint16_t)0x8000U) -#define LAN8742_BCR_LOOPBACK ((uint16_t)0x4000U) -#define LAN8742_BCR_SPEED_SELECT ((uint16_t)0x2000U) -#define LAN8742_BCR_AUTONEGO_EN ((uint16_t)0x1000U) -#define LAN8742_BCR_POWER_DOWN ((uint16_t)0x0800U) -#define LAN8742_BCR_ISOLATE ((uint16_t)0x0400U) -#define LAN8742_BCR_RESTART_AUTONEGO ((uint16_t)0x0200U) -#define LAN8742_BCR_DUPLEX_MODE ((uint16_t)0x0100U) -/** - * @} - */ - -/** @defgroup LAN8742_BSR_Bit_Definition LAN8742 BSR Bit Definition - * @{ - */ -#define LAN8742_BSR_100BASE_T4 ((uint16_t)0x8000U) -#define LAN8742_BSR_100BASE_TX_FD ((uint16_t)0x4000U) -#define LAN8742_BSR_100BASE_TX_HD ((uint16_t)0x2000U) -#define LAN8742_BSR_10BASE_T_FD ((uint16_t)0x1000U) -#define LAN8742_BSR_10BASE_T_HD ((uint16_t)0x0800U) -#define LAN8742_BSR_100BASE_T2_FD ((uint16_t)0x0400U) -#define LAN8742_BSR_100BASE_T2_HD ((uint16_t)0x0200U) -#define LAN8742_BSR_EXTENDED_STATUS ((uint16_t)0x0100U) -#define LAN8742_BSR_AUTONEGO_CPLT ((uint16_t)0x0020U) -#define LAN8742_BSR_REMOTE_FAULT ((uint16_t)0x0010U) -#define LAN8742_BSR_AUTONEGO_ABILITY ((uint16_t)0x0008U) -#define LAN8742_BSR_LINK_STATUS ((uint16_t)0x0004U) -#define LAN8742_BSR_JABBER_DETECT ((uint16_t)0x0002U) -#define LAN8742_BSR_EXTENDED_CAP ((uint16_t)0x0001U) -/** - * @} - */ - -/** @defgroup LAN8742_PHYI1R_Bit_Definition LAN8742 PHYI1R Bit Definition - * @{ - */ -#define LAN8742_PHYI1R_OUI_3_18 ((uint16_t)0xFFFFU) -/** - * @} - */ - -/** @defgroup LAN8742_PHYI2R_Bit_Definition LAN8742 PHYI2R Bit Definition - * @{ - */ -#define LAN8742_PHYI2R_OUI_19_24 ((uint16_t)0xFC00U) -#define LAN8742_PHYI2R_MODEL_NBR ((uint16_t)0x03F0U) -#define LAN8742_PHYI2R_REVISION_NBR ((uint16_t)0x000FU) -/** - * @} - */ - -/** @defgroup LAN8742_ANAR_Bit_Definition LAN8742 ANAR Bit Definition - * @{ - */ -#define LAN8742_ANAR_NEXT_PAGE ((uint16_t)0x8000U) -#define LAN8742_ANAR_REMOTE_FAULT ((uint16_t)0x2000U) -#define LAN8742_ANAR_PAUSE_OPERATION ((uint16_t)0x0C00U) -#define LAN8742_ANAR_PO_NOPAUSE ((uint16_t)0x0000U) -#define LAN8742_ANAR_PO_SYMMETRIC_PAUSE ((uint16_t)0x0400U) -#define LAN8742_ANAR_PO_ASYMMETRIC_PAUSE ((uint16_t)0x0800U) -#define LAN8742_ANAR_PO_ADVERTISE_SUPPORT ((uint16_t)0x0C00U) -#define LAN8742_ANAR_100BASE_TX_FD ((uint16_t)0x0100U) -#define LAN8742_ANAR_100BASE_TX ((uint16_t)0x0080U) -#define LAN8742_ANAR_10BASE_T_FD ((uint16_t)0x0040U) -#define LAN8742_ANAR_10BASE_T ((uint16_t)0x0020U) -#define LAN8742_ANAR_SELECTOR_FIELD ((uint16_t)0x000FU) -/** - * @} - */ - -/** @defgroup LAN8742_ANLPAR_Bit_Definition LAN8742 ANLPAR Bit Definition - * @{ - */ -#define LAN8742_ANLPAR_NEXT_PAGE ((uint16_t)0x8000U) -#define LAN8742_ANLPAR_REMOTE_FAULT ((uint16_t)0x2000U) -#define LAN8742_ANLPAR_PAUSE_OPERATION ((uint16_t)0x0C00U) -#define LAN8742_ANLPAR_PO_NOPAUSE ((uint16_t)0x0000U) -#define LAN8742_ANLPAR_PO_SYMMETRIC_PAUSE ((uint16_t)0x0400U) -#define LAN8742_ANLPAR_PO_ASYMMETRIC_PAUSE ((uint16_t)0x0800U) -#define LAN8742_ANLPAR_PO_ADVERTISE_SUPPORT ((uint16_t)0x0C00U) -#define LAN8742_ANLPAR_100BASE_TX_FD ((uint16_t)0x0100U) -#define LAN8742_ANLPAR_100BASE_TX ((uint16_t)0x0080U) -#define LAN8742_ANLPAR_10BASE_T_FD ((uint16_t)0x0040U) -#define LAN8742_ANLPAR_10BASE_T ((uint16_t)0x0020U) -#define LAN8742_ANLPAR_SELECTOR_FIELD ((uint16_t)0x000FU) -/** - * @} - */ - -/** @defgroup LAN8742_ANER_Bit_Definition LAN8742 ANER Bit Definition - * @{ - */ -#define LAN8742_ANER_RX_NP_LOCATION_ABLE ((uint16_t)0x0040U) -#define LAN8742_ANER_RX_NP_STORAGE_LOCATION ((uint16_t)0x0020U) -#define LAN8742_ANER_PARALLEL_DETECT_FAULT ((uint16_t)0x0010U) -#define LAN8742_ANER_LP_NP_ABLE ((uint16_t)0x0008U) -#define LAN8742_ANER_NP_ABLE ((uint16_t)0x0004U) -#define LAN8742_ANER_PAGE_RECEIVED ((uint16_t)0x0002U) -#define LAN8742_ANER_LP_AUTONEG_ABLE ((uint16_t)0x0001U) -/** - * @} - */ - -/** @defgroup LAN8742_ANNPTR_Bit_Definition LAN8742 ANNPTR Bit Definition - * @{ - */ -#define LAN8742_ANNPTR_NEXT_PAGE ((uint16_t)0x8000U) -#define LAN8742_ANNPTR_MESSAGE_PAGE ((uint16_t)0x2000U) -#define LAN8742_ANNPTR_ACK2 ((uint16_t)0x1000U) -#define LAN8742_ANNPTR_TOGGLE ((uint16_t)0x0800U) -#define LAN8742_ANNPTR_MESSAGGE_CODE ((uint16_t)0x07FFU) -/** - * @} - */ - -/** @defgroup LAN8742_ANNPRR_Bit_Definition LAN8742 ANNPRR Bit Definition - * @{ - */ -#define LAN8742_ANNPTR_NEXT_PAGE ((uint16_t)0x8000U) -#define LAN8742_ANNPRR_ACK ((uint16_t)0x4000U) -#define LAN8742_ANNPRR_MESSAGE_PAGE ((uint16_t)0x2000U) -#define LAN8742_ANNPRR_ACK2 ((uint16_t)0x1000U) -#define LAN8742_ANNPRR_TOGGLE ((uint16_t)0x0800U) -#define LAN8742_ANNPRR_MESSAGGE_CODE ((uint16_t)0x07FFU) -/** - * @} - */ - -/** @defgroup LAN8742_MMDACR_Bit_Definition LAN8742 MMDACR Bit Definition - * @{ - */ -#define LAN8742_MMDACR_MMD_FUNCTION ((uint16_t)0xC000U) -#define LAN8742_MMDACR_MMD_FUNCTION_ADDR ((uint16_t)0x0000U) -#define LAN8742_MMDACR_MMD_FUNCTION_DATA ((uint16_t)0x4000U) -#define LAN8742_MMDACR_MMD_DEV_ADDR ((uint16_t)0x001FU) -/** - * @} - */ - -/** @defgroup LAN8742_ENCTR_Bit_Definition LAN8742 ENCTR Bit Definition - * @{ - */ -#define LAN8742_ENCTR_TX_ENABLE ((uint16_t)0x8000U) -#define LAN8742_ENCTR_TX_TIMER ((uint16_t)0x6000U) -#define LAN8742_ENCTR_TX_TIMER_1S ((uint16_t)0x0000U) -#define LAN8742_ENCTR_TX_TIMER_768MS ((uint16_t)0x2000U) -#define LAN8742_ENCTR_TX_TIMER_512MS ((uint16_t)0x4000U) -#define LAN8742_ENCTR_TX_TIMER_265MS ((uint16_t)0x6000U) -#define LAN8742_ENCTR_RX_ENABLE ((uint16_t)0x1000U) -#define LAN8742_ENCTR_RX_MAX_INTERVAL ((uint16_t)0x0C00U) -#define LAN8742_ENCTR_RX_MAX_INTERVAL_64MS ((uint16_t)0x0000U) -#define LAN8742_ENCTR_RX_MAX_INTERVAL_256MS ((uint16_t)0x0400U) -#define LAN8742_ENCTR_RX_MAX_INTERVAL_512MS ((uint16_t)0x0800U) -#define LAN8742_ENCTR_RX_MAX_INTERVAL_1S ((uint16_t)0x0C00U) -#define LAN8742_ENCTR_EX_CROSS_OVER ((uint16_t)0x0002U) -#define LAN8742_ENCTR_EX_MANUAL_CROSS_OVER ((uint16_t)0x0001U) -/** - * @} - */ - -/** @defgroup LAN8742_MCSR_Bit_Definition LAN8742 MCSR Bit Definition - * @{ - */ -#define LAN8742_MCSR_EDPWRDOWN ((uint16_t)0x2000U) -#define LAN8742_MCSR_FARLOOPBACK ((uint16_t)0x0200U) -#define LAN8742_MCSR_ALTINT ((uint16_t)0x0040U) -#define LAN8742_MCSR_ENERGYON ((uint16_t)0x0002U) -/** - * @} - */ - -/** @defgroup LAN8742_SMR_Bit_Definition LAN8742 SMR Bit Definition - * @{ - */ -#define LAN8742_SMR_MODE ((uint16_t)0x00E0U) -#define LAN8742_SMR_PHY_ADDR ((uint16_t)0x001FU) -/** - * @} - */ - -/** @defgroup LAN8742_TPDCR_Bit_Definition LAN8742 TPDCR Bit Definition - * @{ - */ -#define LAN8742_TPDCR_DELAY_IN ((uint16_t)0x8000U) -#define LAN8742_TPDCR_LINE_BREAK_COUNTER ((uint16_t)0x7000U) -#define LAN8742_TPDCR_PATTERN_HIGH ((uint16_t)0x0FC0U) -#define LAN8742_TPDCR_PATTERN_LOW ((uint16_t)0x003FU) -/** - * @} - */ - -/** @defgroup LAN8742_TCSR_Bit_Definition LAN8742 TCSR Bit Definition - * @{ - */ -#define LAN8742_TCSR_TDR_ENABLE ((uint16_t)0x8000U) -#define LAN8742_TCSR_TDR_AD_FILTER_ENABLE ((uint16_t)0x4000U) -#define LAN8742_TCSR_TDR_CH_CABLE_TYPE ((uint16_t)0x0600U) -#define LAN8742_TCSR_TDR_CH_CABLE_DEFAULT ((uint16_t)0x0000U) -#define LAN8742_TCSR_TDR_CH_CABLE_SHORTED ((uint16_t)0x0200U) -#define LAN8742_TCSR_TDR_CH_CABLE_OPEN ((uint16_t)0x0400U) -#define LAN8742_TCSR_TDR_CH_CABLE_MATCH ((uint16_t)0x0600U) -#define LAN8742_TCSR_TDR_CH_STATUS ((uint16_t)0x0100U) -#define LAN8742_TCSR_TDR_CH_LENGTH ((uint16_t)0x00FFU) -/** - * @} - */ - -/** @defgroup LAN8742_SCSIR_Bit_Definition LAN8742 SCSIR Bit Definition - * @{ - */ -#define LAN8742_SCSIR_AUTO_MDIX_ENABLE ((uint16_t)0x8000U) -#define LAN8742_SCSIR_CHANNEL_SELECT ((uint16_t)0x2000U) -#define LAN8742_SCSIR_SQE_DISABLE ((uint16_t)0x0800U) -#define LAN8742_SCSIR_XPOLALITY ((uint16_t)0x0010U) -/** - * @} - */ - -/** @defgroup LAN8742_CLR_Bit_Definition LAN8742 CLR Bit Definition - * @{ - */ -#define LAN8742_CLR_CABLE_LENGTH ((uint16_t)0xF000U) -/** - * @} - */ - -/** @defgroup LAN8742_IMR_ISFR_Bit_Definition LAN8742 IMR ISFR Bit Definition - * @{ - */ -#define LAN8742_INT_8 ((uint16_t)0x0100U) -#define LAN8742_INT_7 ((uint16_t)0x0080U) -#define LAN8742_INT_6 ((uint16_t)0x0040U) -#define LAN8742_INT_5 ((uint16_t)0x0020U) -#define LAN8742_INT_4 ((uint16_t)0x0010U) -#define LAN8742_INT_3 ((uint16_t)0x0008U) -#define LAN8742_INT_2 ((uint16_t)0x0004U) -#define LAN8742_INT_1 ((uint16_t)0x0002U) -/** - * @} - */ - -/** @defgroup LAN8742_PHYSCSR_Bit_Definition LAN8742 PHYSCSR Bit Definition - * @{ - */ -#define LAN8742_PHYSCSR_AUTONEGO_DONE ((uint16_t)0x1000U) -#define LAN8742_PHYSCSR_HCDSPEEDMASK ((uint16_t)0x001CU) -#define LAN8742_PHYSCSR_10BT_HD ((uint16_t)0x0004U) -#define LAN8742_PHYSCSR_10BT_FD ((uint16_t)0x0014U) -#define LAN8742_PHYSCSR_100BTX_HD ((uint16_t)0x0008U) -#define LAN8742_PHYSCSR_100BTX_FD ((uint16_t)0x0018U) -/** - * @} - */ - -/** @defgroup LAN8742_Status LAN8742 Status - * @{ - */ - -#define LAN8742_STATUS_READ_ERROR ((int32_t)-5) -#define LAN8742_STATUS_WRITE_ERROR ((int32_t)-4) -#define LAN8742_STATUS_ADDRESS_ERROR ((int32_t)-3) -#define LAN8742_STATUS_RESET_TIMEOUT ((int32_t)-2) -#define LAN8742_STATUS_ERROR ((int32_t)-1) -#define LAN8742_STATUS_OK ((int32_t) 0) -#define LAN8742_STATUS_LINK_DOWN ((int32_t) 1) -#define LAN8742_STATUS_100MBITS_FULLDUPLEX ((int32_t) 2) -#define LAN8742_STATUS_100MBITS_HALFDUPLEX ((int32_t) 3) -#define LAN8742_STATUS_10MBITS_FULLDUPLEX ((int32_t) 4) -#define LAN8742_STATUS_10MBITS_HALFDUPLEX ((int32_t) 5) -#define LAN8742_STATUS_AUTONEGO_NOTDONE ((int32_t) 6) -/** - * @} - */ - -/** @defgroup LAN8742_IT_Flags LAN8742 IT Flags - * @{ - */ -#define LAN8742_WOL_IT LAN8742_INT_8 -#define LAN8742_ENERGYON_IT LAN8742_INT_7 -#define LAN8742_AUTONEGO_COMPLETE_IT LAN8742_INT_6 -#define LAN8742_REMOTE_FAULT_IT LAN8742_INT_5 -#define LAN8742_LINK_DOWN_IT LAN8742_INT_4 -#define LAN8742_AUTONEGO_LP_ACK_IT LAN8742_INT_3 -#define LAN8742_PARALLEL_DETECTION_FAULT_IT LAN8742_INT_2 -#define LAN8742_AUTONEGO_PAGE_RECEIVED_IT LAN8742_INT_1 -/** - * @} - */ - -/** - * @} - */ - -/* Exported types ------------------------------------------------------------*/ -/** @defgroup LAN8742_Exported_Types LAN8742 Exported Types - * @{ - */ -typedef int32_t (*lan8742_Init_Func)(void); -typedef int32_t (*lan8742_DeInit_Func)(void); -typedef int32_t (*lan8742_ReadReg_Func)(uint32_t, uint32_t, uint32_t *); -typedef int32_t (*lan8742_WriteReg_Func)(uint32_t, uint32_t, uint32_t); -typedef int32_t (*lan8742_GetTick_Func)(void); - -typedef struct { - lan8742_Init_Func Init; - lan8742_DeInit_Func DeInit; - lan8742_WriteReg_Func WriteReg; - lan8742_ReadReg_Func ReadReg; - lan8742_GetTick_Func GetTick; -} lan8742_IOCtx_t; - - -typedef struct { - uint32_t DevAddr; - uint32_t Is_Initialized; - lan8742_IOCtx_t IO; - void *pData; -} lan8742_Object_t; -/** - * @} - */ - -/* Exported macro ------------------------------------------------------------*/ -/* Exported functions --------------------------------------------------------*/ -/** @defgroup LAN8742_Exported_Functions LAN8742 Exported Functions - * @{ - */ -int32_t LAN8742_RegisterBusIO(lan8742_Object_t *pObj, lan8742_IOCtx_t *ioctx); -int32_t LAN8742_Init(lan8742_Object_t *pObj); -int32_t LAN8742_DeInit(lan8742_Object_t *pObj); -int32_t LAN8742_DisablePowerDownMode(lan8742_Object_t *pObj); -int32_t LAN8742_EnablePowerDownMode(lan8742_Object_t *pObj); -int32_t LAN8742_StartAutoNego(lan8742_Object_t *pObj); -int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj); -int32_t LAN8742_SetLinkState(lan8742_Object_t *pObj, uint32_t LinkState); -int32_t LAN8742_EnableLoopbackMode(lan8742_Object_t *pObj); -int32_t LAN8742_DisableLoopbackMode(lan8742_Object_t *pObj); -int32_t LAN8742_EnableIT(lan8742_Object_t *pObj, uint32_t Interrupt); -int32_t LAN8742_DisableIT(lan8742_Object_t *pObj, uint32_t Interrupt); -int32_t LAN8742_ClearIT(lan8742_Object_t *pObj, uint32_t Interrupt); -int32_t LAN8742_GetITStatus(lan8742_Object_t *pObj, uint32_t Interrupt); -/** - * @} - */ - -#ifdef __cplusplus -} -#endif -#endif /* __LAN8742_H */ - - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/stm32xx_emac_config.h b/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/stm32xx_emac_config.h deleted file mode 100644 index cd943ccc85b..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/TARGET_STM32H7/stm32xx_emac_config.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2017 ARM Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef STM32XX_EMAC_CONFIG_H__ -#define STM32XX_EMAC_CONFIG_H__ - -#define ETH_IP_VERSION_V2 - -#endif // #define STM32XX_EMAC_CONFIG_H__ diff --git a/connectivity/drivers/emac/TARGET_STM/mbed_lib.json b/connectivity/drivers/emac/TARGET_STM/mbed_lib.json deleted file mode 100644 index 1875925cf6c..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/mbed_lib.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "stm32-emac", - "config": { - "eth-rxbufnb": 4, - "eth-txbufnb": 4, - "thread-stacksize": { - "help": "Stack size for stm32_emac_thread", - "value": 1024 - }, - "eth-phy-address": { - "help" : "Configures actual PHY address according to pullup/down status of PHYAD pin(s)", - "value" : 0 - }, - "eth-phy-media-interface": { - "help" : "Selects Connection to PHY Chip: ETH_MEDIA_INTERFACE_RMII / ETH_MEDIA_INTERFACE_MII", - "value" : "ETH_MEDIA_INTERFACE_RMII" - }, - "eth-phy-AutoNegotiation": { - "help" : "Selects AutoNegotiation mode : ETH_AUTONEGOTIATION_ENABLE / ETH_AUTONEGOTIATION_DISABLE", - "value" : "ETH_AUTONEGOTIATION_ENABLE" - }, - "eth-phy-DuplexMode": { - "help" : "Selects DuplexMode mode : ETH_MODE_FULLDUPLEX / ETH_MODE_HALFDUPLEX", - "value" : "ETH_MODE_FULLDUPLEX" - }, - "eth-phy-Speed": { - "help" : "Selects Speed mode : ETH_SPEED_100M / ETH_SPEED_10M", - "value" : "ETH_SPEED_100M" - }, - "eth-phy-reset-delay": { - "help" : "Reset process time - Default value: 0.5s as specified in LAN8742A datasheet", - "value" : "500" - }, - "eth-phy-status-register": { - "help" : "PHY register Offset with auto-negotiation result - Default value is LAN8742A PHY Special Control/Status Register", - "value" : "31" - }, - "eth-phy-speed-status": { - "help" : "Speed mask information in eth-phy-status-register", - "value" : "0x0004" - }, - "eth-phy-duplex-status": { - "help" : "Duplex mask information in eth-phy-status-register", - "value" : "0x0010" - }, - "max-mcast-subscribes": { - "help" : "Maximum supported number of multicast addresses that the application can subscribe to", - "value" : "8" - } - }, - "target_overrides": { - "NUCLEO_F207ZG": { - "eth-rxbufnb": 2, - "eth-txbufnb": 4 - }, - "STM32H7": { - "eth-txbufnb": 10 - }, - "ARCH_MAX": { - "eth-phy-address": 1 - } - } -} diff --git a/connectivity/drivers/emac/TARGET_STM/stm32xx_emac.cpp b/connectivity/drivers/emac/TARGET_STM/stm32xx_emac.cpp deleted file mode 100644 index bcb6086bfd0..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/stm32xx_emac.cpp +++ /dev/null @@ -1,1268 +0,0 @@ -/* Copyright (c) 2017-2019 ARM Limited - * Copyright (c) 2017-2019 STMicroelectronics - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#if DEVICE_EMAC - -#include -#include - -#include "cmsis_os.h" - -#include "mbed_interface.h" -#include "mbed_assert.h" -#include "events/mbed_shared_queues.h" -#include "netsocket/nsapi_types.h" -#include "platform/mbed_power_mgmt.h" -#include "platform/mbed_error.h" -#include "CacheAlignedBuffer.h" -#include "MbedCRC.h" - -#include "stm32xx_emac_config.h" -#include "stm32xx_emac.h" - - -#include "mbed-trace/mbed_trace.h" - -#if defined(ETH_IP_VERSION_V2) -#define TRACE_GROUP "STE2" -#else -#define TRACE_GROUP "STE1" -#endif - -/* mbed trace feature is supported */ -/* ex in mbed_app.json */ -/* "mbed-trace.enable": "1" */ - -/* mbed_trace: debug traces (tr_debug) can be disabled here with no change in mbed_app.json */ -// #undef TRACE_LEVEL_DEBUG -// #define TRACE_LEVEL_DEBUG 0 - -/* To get trace from every packet, enable deep trace macro */ -// #define STM32xx_DEEP_TRACE -#ifdef STM32xx_DEEP_TRACE -#define tr_debug_deep(...) tr_debug(__VA_ARGS__) -#else -#define tr_debug_deep(...) -#endif - -#if defined(ETH_IP_VERSION_V2) -#include "lan8742/lan8742.h" -#include "lwip/memp.h" -#include "lwip/api.h" -#include "linker_scripts/stm32_eth_region_size_calcs.h" -#endif - -using namespace std::chrono; - -/* \brief Flags for worker thread */ -#define FLAG_RX 1 - -/** \brief Driver thread priority */ -#define THREAD_PRIORITY (osPriorityHigh) - -#define PHY_TASK_PERIOD 200ms - -#define STM_HWADDR_SIZE (6) -#define STM_ETH_MTU_SIZE 1500 -#define STM_ETH_IF_NAME "st" - -#define ETH_RX_DESC_CNT MBED_CONF_STM32_EMAC_ETH_RXBUFNB -#define ETH_TX_DESC_CNT MBED_CONF_STM32_EMAC_ETH_TXBUFNB - -ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".EthDescriptors"))); /* Ethernet Rx DMA Descriptors */ -ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".EthDescriptors"))); /* Ethernet Tx DMA Descriptors */ - -// Rx buffer addresses need to be aligned 4 bytes and to cache lines because we cache invalidate the buffers after receiving them. -mbed::StaticCacheAlignedBuffer Rx_Buff[ETH_RX_DESC_CNT] __attribute__((section(".EthBuffers"))); /* Ethernet Receive Buffers */ - -// Tx buffers just need to be aligned to the nearest 4 bytes. -uint32_t Tx_Buff[ETH_TX_DESC_CNT][ETH_MAX_PACKET_SIZE / sizeof(uint32_t)] __attribute__((section(".EthBuffers"))); - -#if defined(ETH_IP_VERSION_V2) - -static lan8742_Object_t LAN8742; - -static int32_t ETH_PHY_IO_Init(void); -static int32_t ETH_PHY_IO_DeInit(void); -static int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal); -static int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal); -static int32_t ETH_PHY_IO_GetTick(void); - -static lan8742_IOCtx_t LAN8742_IOCtx = { - ETH_PHY_IO_Init, - ETH_PHY_IO_DeInit, - ETH_PHY_IO_WriteReg, - ETH_PHY_IO_ReadReg, - ETH_PHY_IO_GetTick -}; - -static ETH_TxPacketConfig TxConfig; - -#endif // ETH_IP_VERSION_V2 - -MBED_WEAK uint8_t mbed_otp_mac_address(char *mac); -void mbed_default_mac_address(char *mac); - -#ifdef __cplusplus -extern "C" { -#endif - -void _eth_config_mac(ETH_HandleTypeDef *heth); -void ETH_IRQHandler(void); - -// We need to give the linker a reason to pull in the stmxx_eth_init.c files, since they only contain -// weak symbol overrides and would otherwise be ignored. -void stm32_eth_init_weak_symbol_helper(); - -#ifdef USE_USER_DEFINED_HAL_ETH_IRQ_CALLBACK -MBED_WEAK void STM_HAL_ETH_Handler(); -#else -void STM_HAL_ETH_Handler(); -#endif - -#ifdef __cplusplus -} -#endif - -#ifdef ETH_IP_VERSION_V2 -bool _phy_init() -{ - /* Set PHY IO functions */ - LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx); - - /* Initialize the LAN8742 ETH PHY */ - return LAN8742_Init(&LAN8742) == LAN8742_STATUS_OK; -} - -int32_t _phy_get_state() -{ - return LAN8742_GetLinkState(&LAN8742); -} - -bool _phy_get_duplex_and_speed(int32_t phy_state, uint32_t *duplex, uint32_t *speed) -{ - switch (phy_state) { - case LAN8742_STATUS_100MBITS_FULLDUPLEX: - *duplex = ETH_FULLDUPLEX_MODE; - *speed = ETH_SPEED_100M; - break; - case LAN8742_STATUS_100MBITS_HALFDUPLEX: - *duplex = ETH_HALFDUPLEX_MODE; - *speed = ETH_SPEED_100M; - break; - case LAN8742_STATUS_10MBITS_FULLDUPLEX: - *duplex = ETH_FULLDUPLEX_MODE; - *speed = ETH_SPEED_10M; - break; - case LAN8742_STATUS_10MBITS_HALFDUPLEX: - *duplex = ETH_HALFDUPLEX_MODE; - *speed = ETH_SPEED_10M; - break; - default: - return false; - } - - return true; -} - -bool _phy_is_up(int32_t phy_state) -{ - return phy_state > LAN8742_STATUS_LINK_DOWN; -} - -// Integer log2 of an integer. -// from https://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c -static inline uint32_t log2i(uint32_t x) { - return sizeof(uint32_t) * 8 - __builtin_clz(x) - 1; -} - -static void MPU_Config(void) -{ - MPU_Region_InitTypeDef MPU_InitStruct; - - /* Disable the MPU */ - HAL_MPU_Disable(); - - /* Configure the MPU attributes as Device not cacheable - for ETH DMA descriptors. The linker script puts these into their own - cordoned off, power-of-2 sized region. */ - MPU_InitStruct.Enable = MPU_REGION_ENABLE; - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; - MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; - MPU_InitStruct.Number = 4; // Mbed OS MPU config can use regions 0 through 3 - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; - MPU_InitStruct.SubRegionDisable = 0x00; - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; - - extern uint8_t __eth_descriptors_start[0]; // <-- defined in linker script - MPU_InitStruct.BaseAddress = reinterpret_cast(__eth_descriptors_start); - - // Use a logarithm to calculate the region size - MPU_InitStruct.Size = log2i(STM32_DMA_DESCRIP_REGION_SIZE) - 1; - - HAL_MPU_ConfigRegion(&MPU_InitStruct); - - /* Enable the MPU */ - HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); -} - -#endif - -/** - * Ethernet IRQ Handler - * - * @param None - * @retval None - */ -void ETH_IRQHandler(void) -{ - STM_HAL_ETH_Handler(); -} - -STM32_EMAC::STM32_EMAC() - : thread(0) -#ifdef ETH_IP_VERSION_V2 - , phy_status(0) -#endif -{ -} - -static osThreadId_t create_new_thread(const char *threadName, void (*thread)(void *arg), void *arg, int stacksize, osPriority_t priority, mbed_rtos_storage_thread_t *thread_cb) -{ - osThreadAttr_t attr = {0}; - attr.name = threadName; - attr.stack_mem = malloc(stacksize); - attr.cb_mem = thread_cb; - attr.stack_size = stacksize; - attr.cb_size = sizeof(mbed_rtos_storage_thread_t); - attr.priority = priority; - return osThreadNew(thread, arg, &attr); -} - -/** - * In this function, the hardware should be initialized. - */ -bool STM32_EMAC::low_level_init_successful() -#ifndef ETH_IP_VERSION_V2 -{ - // Generate a reference to this empty function so the linker pulls it in. - stm32_eth_init_weak_symbol_helper(); - - uint32_t PHY_ID; - - /* Init ETH */ - uint8_t MACAddr[6]; - EthHandle.Instance = ETH; - EthHandle.Init.AutoNegotiation = MBED_CONF_STM32_EMAC_ETH_PHY_AUTONEGOTIATION; - EthHandle.Init.Speed = MBED_CONF_STM32_EMAC_ETH_PHY_SPEED; - EthHandle.Init.DuplexMode = MBED_CONF_STM32_EMAC_ETH_PHY_DUPLEXMODE; - EthHandle.Init.PhyAddress = MBED_CONF_STM32_EMAC_ETH_PHY_ADDRESS; -#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) - MACAddr[0] = MBED_MAC_ADDR_0; - MACAddr[1] = MBED_MAC_ADDR_1; - MACAddr[2] = MBED_MAC_ADDR_2; - MACAddr[3] = MBED_MAC_ADDR_3; - MACAddr[4] = MBED_MAC_ADDR_4; - MACAddr[5] = MBED_MAC_ADDR_5; -#else - mbed_mac_address((char *)MACAddr); -#endif - EthHandle.Init.MACAddr = &MACAddr[0]; - EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE; - EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE; - EthHandle.Init.MediaInterface = MBED_CONF_STM32_EMAC_ETH_PHY_MEDIA_INTERFACE; - tr_info("power_up: PHY Addr %u AutoNeg %u", EthHandle.Init.PhyAddress, EthHandle.Init.AutoNegotiation); - tr_debug("MAC Addr %02x:%02x:%02x:%02x:%02x:%02x", MACAddr[0], MACAddr[1], MACAddr[2], MACAddr[3], MACAddr[4], MACAddr[5]); - tr_info("ETH buffers : %u Rx %u Tx", ETH_RXBUFNB, ETH_TXBUFNB); - - if (HAL_ETH_Init(&EthHandle) != HAL_OK) { - tr_error("HAL_ETH_Init issue"); - /* HAL_ETH_Init returns TIMEOUT when Ethernet cable is not plugged */; - } - - // Set MAC address - writeMACAddress(MACAddr, &EthHandle.Instance->MACA0HR, &EthHandle.Instance->MACA0LR); - - uint32_t TempRegisterValue; - if (HAL_ETH_ReadPHYRegister(&EthHandle, 2, &TempRegisterValue) != HAL_OK) { - tr_error("HAL_ETH_ReadPHYRegister 2 issue"); - } - PHY_ID = (TempRegisterValue << 16); - if (HAL_ETH_ReadPHYRegister(&EthHandle, 3, &TempRegisterValue) != HAL_OK) { - tr_error("HAL_ETH_ReadPHYRegister 3 issue"); - } - PHY_ID |= (TempRegisterValue & 0XFFF0); - tr_info("PHY ID %#X", PHY_ID); - - /* Initialize Tx Descriptors list: Chain Mode */ - if (HAL_ETH_DMATxDescListInit(&EthHandle, DMATxDscrTab, reinterpret_cast(&Tx_Buff[0][0]), ETH_TXBUFNB) != HAL_OK) { - tr_error("HAL_ETH_DMATxDescListInit issue"); - return false; - } - - /* Initialize Rx Descriptors list: Chain Mode */ - if (HAL_ETH_DMARxDescListInit(&EthHandle, DMARxDscrTab, reinterpret_cast(Rx_Buff[0].data()), ETH_RXBUFNB) != HAL_OK) { - tr_error("HAL_ETH_DMARxDescListInit issue"); - return false; - } - - /* Configure MAC */ - _eth_config_mac(&EthHandle); - - /* Enable MAC and DMA transmission and reception */ - if (HAL_ETH_Start(&EthHandle) != HAL_OK) { - tr_error("HAL_ETH_Start issue"); - return false; - } - - tr_info("low_level_init_successful"); - return true; -} -#else // ETH_IP_VERSION_V2 -{ - uint32_t idx; - - // Generate a reference to this empty function so the linker pulls it in. - stm32_eth_init_weak_symbol_helper(); - - MPU_Config(); - - /* Init ETH */ - uint8_t MACAddr[6]; - EthHandle.Instance = ETH; -#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) - MACAddr[0] = MBED_MAC_ADDR_0; - MACAddr[1] = MBED_MAC_ADDR_1; - MACAddr[2] = MBED_MAC_ADDR_2; - MACAddr[3] = MBED_MAC_ADDR_3; - MACAddr[4] = MBED_MAC_ADDR_4; - MACAddr[5] = MBED_MAC_ADDR_5; -#else - mbed_mac_address((char *)MACAddr); -#endif - EthHandle.Init.MACAddr = &MACAddr[0]; - EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE; - EthHandle.Init.RxDesc = DMARxDscrTab; - EthHandle.Init.TxDesc = DMATxDscrTab; - EthHandle.Init.RxBuffLen = 1524; - - tr_debug("MAC Addr %02x:%02x:%02x:%02x:%02x:%02x", MACAddr[0], MACAddr[1], MACAddr[2], MACAddr[3], MACAddr[4], MACAddr[5]); - tr_info("ETH buffers : %u Rx %u Tx", ETH_RX_DESC_CNT, ETH_TX_DESC_CNT); - - if (HAL_ETH_Init(&EthHandle) != HAL_OK) { - return false; - } - - // Set MAC address - writeMACAddress(MACAddr, &EthHandle.Instance->MACA0HR, &EthHandle.Instance->MACA0LR); - - // Enable multicast hash and perfect filter - EthHandle.Instance->MACPFR = ETH_MACPFR_HMC | ETH_MACPFR_HPF; - - memset(&TxConfig, 0, sizeof(ETH_TxPacketConfig)); - TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD; - TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC; - TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT; - - for (idx = 0; idx < ETH_RX_DESC_CNT; idx++) { - HAL_ETH_DescAssignMemory(&EthHandle, idx, reinterpret_cast(Rx_Buff[idx].data()), NULL); - } - - tr_info("low_level_init_successful"); - return _phy_init(); -} -#endif // ETH_IP_VERSION_V2 - -/** - * This function should do the actual transmission of the packet. The packet is - * contained in the memory buffer chain that is passed to the function. - * - * @param buf the MAC packet to send (e.g. IP packet including MAC addresses and type) - * @return true if the packet could be sent - * false value if the packet couldn't be sent - * - * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to - * strange results. You might consider waiting for space in the DMA queue - * to become availale since the stack doesn't retry to send a packet - * dropped because of memory failure (except for the TCP timers). - */ -bool STM32_EMAC::link_out(emac_mem_buf_t *buf) -#ifndef ETH_IP_VERSION_V2 -{ - bool success = true; - emac_mem_buf_t *q; - uint8_t *buffer = reinterpret_cast(EthHandle.TxDesc->Buffer1Addr); - __IO ETH_DMADescTypeDef *DmaTxDesc; - uint32_t framelength = 0; - uint32_t bufferoffset = 0; - uint32_t byteslefttocopy = 0; - uint32_t payloadoffset = 0; - DmaTxDesc = EthHandle.TxDesc; - - /* Get exclusive access */ - TXLockMutex.lock(); - - /* copy frame from pbufs to driver buffers */ - for (q = buf; q != NULL; q = memory_manager->get_next(q)) { - /* Is this buffer available? If not, goto error */ - if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) { - success = false; - goto error; - } - - /* Get bytes in current lwIP buffer */ - byteslefttocopy = memory_manager->get_len(q); - payloadoffset = 0; - - /* Check if the length of data to copy is bigger than Tx buffer size*/ - while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE) { - /* Copy data to Tx buffer*/ - memcpy(static_cast(buffer) + bufferoffset, static_cast(memory_manager->get_ptr(q)) + payloadoffset, (ETH_TX_BUF_SIZE - bufferoffset)); - - /* Point to next descriptor */ - DmaTxDesc = reinterpret_cast(DmaTxDesc->Buffer2NextDescAddr); - - /* Check if the buffer is available */ - if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET) { - success = false; - goto error; - } - - buffer = reinterpret_cast(DmaTxDesc->Buffer1Addr); - - byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset); - payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset); - framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset); - bufferoffset = 0; - } - - /* Copy the remaining bytes */ - memcpy(static_cast(buffer) + bufferoffset, static_cast(memory_manager->get_ptr(q)) + payloadoffset, byteslefttocopy); - bufferoffset = bufferoffset + byteslefttocopy; - framelength = framelength + byteslefttocopy; - } - - /* Prepare transmit descriptors to give to DMA */ - if (HAL_ETH_TransmitFrame(&EthHandle, framelength) != HAL_OK) { - tr_error("HAL_ETH_TransmitFrame issue"); - success = false; - } - -error: - - /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */ - if ((EthHandle.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t)RESET) { - /* Clear TUS ETHERNET DMA flag */ - EthHandle.Instance->DMASR = ETH_DMASR_TUS; - - /* Resume DMA transmission*/ - EthHandle.Instance->DMATPDR = 0; - } - - memory_manager->free(buf); - - /* Restore access */ - TXLockMutex.unlock(); - - return success; -} -#else // ETH_IP_VERSION_V2 -{ - bool success = false; - uint32_t i = 0; - uint32_t frameLength = 0; - struct pbuf *q; - ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT]; - HAL_StatusTypeDef status; - struct pbuf *p = NULL; - p = (struct pbuf *)buf; - /* Get exclusive access */ - TXLockMutex.lock(); - - memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef)); - - /* copy frame from pbufs to driver buffers */ - for (q = p; q != NULL; q = q->next) { - if (i >= ETH_TX_DESC_CNT) { - tr_error("Error : ETH_TX_DESC_CNT not sufficient"); - goto error; - } - - Txbuffer[i].buffer = (uint8_t *)q->payload; - Txbuffer[i].len = q->len; - frameLength += q->len; - - if (i > 0) { - Txbuffer[i - 1].next = &Txbuffer[i]; - } - - if (q->next == NULL) { - Txbuffer[i].next = NULL; - } - -#if defined(__DCACHE_PRESENT) - // For chips with a cache, we need to evict the Tx data from cache to main memory. - // This ensures that the DMA controller can see the most up-to-date copy of the data. - SCB_CleanDCache_by_Addr(Txbuffer[i].buffer, Txbuffer[i].len); -#endif - - i++; - } - - TxConfig.Length = frameLength; - TxConfig.TxBuffer = Txbuffer; - - status = HAL_ETH_Transmit(&EthHandle, &TxConfig, 50); - if (status == HAL_OK) { - success = 1; - } else { - tr_error("Error returned by HAL_ETH_Transmit (%d)", status); - success = 0; - } - -error: - - if (p->ref > 1) { - pbuf_free(p); - } - - /* Restore access */ - TXLockMutex.unlock(); - - return success; -} -#endif // ETH_IP_VERSION_V2 - -/** - * Should allocate a contiguous memory buffer and transfer the bytes of the incoming - * packet to the buffer. - * - * @param buf If a frame was received and the memory buffer allocation was successful, a memory - * buffer filled with the received packet (including MAC header) - * @return negative value when no more frames, - * zero when frame is received - */ -int STM32_EMAC::low_level_input(emac_mem_buf_t **buf) -#ifndef ETH_IP_VERSION_V2 -{ - uint32_t len = 0; - uint8_t *buffer; - __IO ETH_DMADescTypeDef *dmarxdesc; - uint32_t bufferoffset = 0; - uint32_t byteslefttocopy = 0; - emac_mem_buf_t *q; - uint32_t payloadoffset = 0; - - /* get received frame */ - if (HAL_ETH_GetReceivedFrame_IT(&EthHandle) != HAL_OK) { - tr_debug_deep("low_level_input no frame"); - return -1; - } - - /* Obtain the size of the packet and put it into the "len" variable. */ - len = EthHandle.RxFrameInfos.length; - buffer = reinterpret_cast(EthHandle.RxFrameInfos.buffer); - byteslefttocopy = len; - - dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc; - - if (len > 0 && len <= ETH_RX_BUF_SIZE) { - tr_debug_deep("low_level_input len %u", len); - /* Allocate a memory buffer chain from buffer pool */ - *buf = memory_manager->alloc_pool(len, 0); - } - - if (*buf != NULL) { - dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc; - bufferoffset = 0; - for (q = *buf; q != NULL; q = memory_manager->get_next(q)) { - byteslefttocopy = memory_manager->get_len(q); - payloadoffset = 0; - - /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/ - while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE) { - /* Copy data to pbuf */ - memcpy(static_cast(memory_manager->get_ptr(q)) + payloadoffset, static_cast(buffer) + bufferoffset, ETH_RX_BUF_SIZE - bufferoffset); - - /* Point to next descriptor */ - dmarxdesc = reinterpret_cast(dmarxdesc->Buffer2NextDescAddr); - buffer = reinterpret_cast(dmarxdesc->Buffer1Addr); - - byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset); - payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset); - bufferoffset = 0; - } - /* Copy remaining data in pbuf */ - memcpy(static_cast(memory_manager->get_ptr(q)) + payloadoffset, static_cast(buffer) + bufferoffset, byteslefttocopy); - bufferoffset = bufferoffset + byteslefttocopy; - } - } - - /* Release descriptors to DMA */ - /* Point to first descriptor */ - dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc; - /* Set Own bit in Rx descriptors: gives the buffers back to DMA */ - for (uint32_t i = 0; i < EthHandle.RxFrameInfos.SegCount; i++) { - dmarxdesc->Status |= ETH_DMARXDESC_OWN; - dmarxdesc = reinterpret_cast(dmarxdesc->Buffer2NextDescAddr); - } - - /* Clear Segment_Count */ - EthHandle.RxFrameInfos.SegCount = 0; - - /* When Rx Buffer unavailable flag is set: clear it and resume reception */ - if ((EthHandle.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) { - /* Clear RBUS ETHERNET DMA flag */ - EthHandle.Instance->DMASR = ETH_DMASR_RBUS; - /* Resume DMA reception */ - EthHandle.Instance->DMARPDR = 0; - } - return 0; -} -#else // ETH_IP_VERSION_V2 -{ - ETH_BufferTypeDef RxBuff; - uint32_t frameLength = 0; - - if (HAL_ETH_GetRxDataBuffer(&EthHandle, &RxBuff) == HAL_OK) { - if (HAL_ETH_GetRxDataLength(&EthHandle, &frameLength) != HAL_OK) { - tr_error("Error: returned by HAL_ETH_GetRxDataLength"); - return -1; - } - - /* Build Rx descriptor to be ready for next data reception */ - HAL_ETH_BuildRxDescriptors(&EthHandle); - -#if defined(__DCACHE_PRESENT) - /* Invalidate data cache for ETH Rx Buffers */ - SCB_InvalidateDCache_by_Addr((uint32_t *)RxBuff.buffer, frameLength); -#endif - - *buf = pbuf_alloc(PBUF_RAW, frameLength, PBUF_POOL); - if (*buf) { - pbuf_take((struct pbuf *)*buf, RxBuff.buffer, frameLength); - } - } else { - return -1; - } - - return 0; -} -#endif // ETH_IP_VERSION_V2 - -/** \brief Attempt to read a packet from the EMAC interface. - * - */ -void STM32_EMAC::packet_rx() -{ - /* move received packet into a new buf */ - while (1) { - emac_mem_buf_t *p = NULL; - RXLockMutex.lock(); - if (low_level_input(&p) < 0) { - RXLockMutex.unlock(); - break; - } - if (p) { - emac_link_input_cb(p); - } - RXLockMutex.unlock(); - } -} - -/** \brief Worker thread. - * - * Woken by thread flags to receive packets or clean up transmit - * - * \param[in] pvParameters pointer to the interface data - */ -void STM32_EMAC::thread_function(void *pvParameters) -{ - static struct STM32_EMAC *stm32_enet = static_cast(pvParameters); - - for (;;) { - uint32_t flags = osThreadFlagsWait(FLAG_RX, osFlagsWaitAny, osWaitForever); - - if (flags & FLAG_RX) { - stm32_enet->packet_rx(); - } - } -} - -/** - * This task checks phy link status and updates net status - */ -void STM32_EMAC::phy_task() -#ifndef ETH_IP_VERSION_V2 -{ - uint32_t status; - - if (HAL_ETH_ReadPHYRegister(&EthHandle, PHY_BSR, &status) == HAL_OK) { - if ((emac_link_state_cb) && (status != 0xFFFF)) { - if ((status & PHY_LINKED_STATUS) && !(phy_status & PHY_LINKED_STATUS)) { - tr_info("emac_link_state_cb set to true"); - emac_link_state_cb(true); - } else if (!(status & PHY_LINKED_STATUS) && (phy_status & PHY_LINKED_STATUS)) { - tr_info("emac_link_state_cb set to false"); - emac_link_state_cb(false); - } - } - phy_status = status; - } else { - tr_error("HAL_ETH_ReadPHYRegister issue"); - } - -} -#else // ETH_IP_VERSION_V2 -{ - const int32_t status = _phy_get_state(); - const int32_t old_status = (int32_t)phy_status; - const bool is_up = _phy_is_up(status); - const bool was_up = _phy_is_up(old_status); - - if (is_up && !was_up) { - uint32_t duplex, speed; - ETH_MACConfigTypeDef MACConf; - - if (!_phy_get_duplex_and_speed(status, &speed, &duplex)) { - // Default - duplex = ETH_FULLDUPLEX_MODE; - speed = ETH_SPEED_10M; - } - - /* Get MAC Config MAC */ - HAL_ETH_GetMACConfig(&EthHandle, &MACConf); - MACConf.DuplexMode = duplex; - MACConf.Speed = speed; - HAL_ETH_SetMACConfig(&EthHandle, &MACConf); - HAL_ETH_Start_IT(&EthHandle); - } else if (was_up && !is_up) { - // Stop ETH - disable_interrupts(); - HAL_ETH_Stop(&EthHandle); - enable_interrupts(); - } - - if (emac_link_state_cb) { - if (is_up && !was_up) { - emac_link_state_cb(true); - tr_info("emac_link_state_cb set to true"); - } else if (!is_up && was_up) { - emac_link_state_cb(false); - tr_info("emac_link_state_cb set to false"); - } - } - - phy_status = (uint32_t)status; -} -#endif // ETH_IP_VERSION_V2 - -#if defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx)\ - || defined (STM32F779xx) -/** - * workaround for the ETH RMII bug in STM32F76x and STM32F77x revA - * - * \param[in] netif the lwip network interface structure - */ - -/** \brief Worker thread. - * - * Woken by thread flags to receive packets or clean up transmit - * - * \param[in] pvParameters pointer to the interface data - */ -void STM32_EMAC::rmii_watchdog_thread_function(void *pvParameters) -{ - struct STM32_EMAC *stm32_enet = static_cast(pvParameters); - - while (1) { - /* some good packets are received */ - if (stm32_enet->EthHandle.Instance->MMCRGUFCR > 0) { - /* RMII Init is OK - would need service to terminate or suspend - * the thread */ - while (1) { - /* don't do anything anymore */ - osDelay(0xFFFFFFFF); - } - } else if (stm32_enet->EthHandle.Instance->MMCRFCECR > 10) { - /* ETH received too many packets with CRC errors, resetting RMII */ - SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL; - SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL; - stm32_enet->EthHandle.Instance->MMCCR |= ETH_MMCCR_CR; - } else { - osDelay(100); - } - } -} -#endif - -void STM32_EMAC::enable_interrupts(void) -{ - HAL_NVIC_SetPriority(ETH_IRQn, 0x7, 0); - HAL_NVIC_EnableIRQ(ETH_IRQn); -} - -void STM32_EMAC::disable_interrupts(void) -{ - NVIC_DisableIRQ(ETH_IRQn); -} - -/** This returns a unique 6-byte MAC address, based on the device UID -* This function overrides hal/common/mbed_interface.c function -* @param mac A 6-byte array to write the MAC address -*/ - -void mbed_mac_address(char *mac) -{ - if (mbed_otp_mac_address(mac)) { - return; - } else { - mbed_default_mac_address(mac); - } - return; -} - -MBED_WEAK uint8_t mbed_otp_mac_address(char *mac) -{ - return 0; -} - -void mbed_default_mac_address(char *mac) -{ - unsigned char ST_mac_addr[3] = {0x00, 0x80, 0xe1}; // default STMicro mac address - - // Read unic id -#if defined (TARGET_STM32F2) - uint32_t word0 = *(uint32_t *)0x1FFF7A10; -#elif defined (TARGET_STM32F4) - uint32_t word0 = *(uint32_t *)0x1FFF7A10; -#elif defined (TARGET_STM32F7) - uint32_t word0 = *(uint32_t *)0x1FF0F420; -#elif defined (TARGET_STM32H7) - uint32_t word0 = *(uint32_t *)0x1FF1E800; -#else -#error MAC address can not be derived from target unique Id -#endif - - mac[0] = ST_mac_addr[0]; - mac[1] = ST_mac_addr[1]; - mac[2] = ST_mac_addr[2]; - mac[3] = (word0 & 0x00ff0000) >> 16; - mac[4] = (word0 & 0x0000ff00) >> 8; - mac[5] = (word0 & 0x000000ff); - - return; -} - -bool STM32_EMAC::power_up() -{ - sleep_manager_lock_deep_sleep(); - - /* Initialize the hardware */ - if (!low_level_init_successful()) { - return false; - } - - /* Worker thread */ -#if MBED_CONF_MBED_TRACE_ENABLE - thread = create_new_thread("stm32_emac_thread", &STM32_EMAC::thread_function, this, MBED_CONF_STM32_EMAC_THREAD_STACKSIZE * 2, THREAD_PRIORITY, &thread_cb); -#else - thread = create_new_thread("stm32_emac_thread", &STM32_EMAC::thread_function, this, MBED_CONF_STM32_EMAC_THREAD_STACKSIZE, THREAD_PRIORITY, &thread_cb); -#endif - - - phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD, mbed::callback(this, &STM32_EMAC::phy_task)); - -#if defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx)\ - || defined (STM32F779xx) - rmii_watchdog_thread = create_new_thread("stm32_rmii_watchdog", &STM32_EMAC::rmii_watchdog_thread_function, this, 128, THREAD_PRIORITY, &rmii_watchdog_thread_cb); -#endif - - /* Allow the PHY task to detect the initial link state and set up the proper flags */ - osDelay(10); - - enable_interrupts(); - - return true; -} - -uint32_t STM32_EMAC::get_mtu_size() const -{ - return STM_ETH_MTU_SIZE; -} - -uint32_t STM32_EMAC::get_align_preference() const -{ - return 0; -} - -void STM32_EMAC::get_ifname(char *name, uint8_t size) const -{ - memcpy(name, STM_ETH_IF_NAME, (size < sizeof(STM_ETH_IF_NAME)) ? size : sizeof(STM_ETH_IF_NAME)); -} - -uint8_t STM32_EMAC::get_hwaddr_size() const -{ - return STM_HWADDR_SIZE; -} - -bool STM32_EMAC::get_hwaddr(uint8_t *addr) const -{ - mbed_mac_address((char *)addr); - return true; -} - -void STM32_EMAC::set_hwaddr(const uint8_t *addr) -{ - /* No-op at this stage */ -} - -void STM32_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb) -{ - emac_link_input_cb = input_cb; -} - -void STM32_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) -{ - emac_link_state_cb = state_cb; -} - -void STM32_EMAC::add_multicast_group(const uint8_t *addr) -{ - if(numSubscribedMcastMacs >= MBED_CONF_STM32_EMAC_MAX_MCAST_SUBSCRIBES) - { - tr_error("Out of multicast group entries (currently have %d). Increase the 'stm32-emac.max-mcast-subscribes' JSON option!", MBED_CONF_STM32_EMAC_MAX_MCAST_SUBSCRIBES); - return; - } - - memcpy(mcastMacs[numSubscribedMcastMacs++].data(), addr, 6); - populateMcastFilterRegs(); -} - -void STM32_EMAC::remove_multicast_group(const uint8_t *addr) -{ - // Find MAC address in the subscription list - auto macsEndIter = std::begin(mcastMacs) + numSubscribedMcastMacs; - auto toRemoveIter = std::find_if(std::begin(mcastMacs), macsEndIter, [&](auto element) { - return memcmp(element.data(), addr, 6) == 0; - }); - - if(toRemoveIter == macsEndIter) - { - tr_warning("Tried to remove mcast group that was not added"); - return; - } - - // Swap the MAC addr to be removed to the end of the list, if it is not there already - auto lastElementIter = macsEndIter - 1; - if(toRemoveIter != std::begin(mcastMacs) && toRemoveIter != lastElementIter) - { - std::swap(*toRemoveIter, *lastElementIter); - } - - // 'remove' the last element by changing the length - numSubscribedMcastMacs--; - - // Rebuild the MAC registers with that MAC removed. - // Technically it would be more performance efficient to remove just this MAC address, but that gets complex - // once you throw the hash filter into the mix. Unless you are subscribed to insane numbers of mcast addrs, - // it's easier to just rebuild it all. - populateMcastFilterRegs(); -} - -void STM32_EMAC::set_all_multicast(bool all) -{ -#if defined(ETH_IP_VERSION_V2) - if(all) - { - EthHandle.Instance->MACPFR |= ETH_MACPFR_PM; - } - else - { - EthHandle.Instance->MACPFR &= ~ETH_MACPFR_PM; - } -#else - if(all) - { - EthHandle.Instance->MACFFR |= ETH_MACFFR_PM; - } - else - { - EthHandle.Instance->MACFFR &= ~ETH_MACFFR_PM; - } -#endif -} - -void STM32_EMAC::power_down() -{ - tr_info("power_down"); - - /* No-op at this stage */ - sleep_manager_unlock_deep_sleep(); -} - -void STM32_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr) -{ - memory_manager = &mem_mngr; -} - -STM32_EMAC &STM32_EMAC::get_instance() -{ - static STM32_EMAC emac; - return emac; -} - -void STM32_EMAC::populateMcastFilterRegs() { - const size_t NUM_PERFECT_FILTER_REGS = 3; - - const size_t numPerfectFilterMacs = std::min(NUM_PERFECT_FILTER_REGS, numSubscribedMcastMacs); - const size_t numHashFilterMacs = numSubscribedMcastMacs - numPerfectFilterMacs; - - for(size_t perfFiltIdx = 0; perfFiltIdx < NUM_PERFECT_FILTER_REGS; ++perfFiltIdx) - { - // Find MAC addr registers (they aren't in an array :/) - uint32_t volatile * highReg; - uint32_t volatile * lowReg; - - if(perfFiltIdx == 0) - { - highReg = &EthHandle.Instance->MACA1HR; - lowReg = &EthHandle.Instance->MACA1LR; - } - else if(perfFiltIdx == 1) - { - highReg = &EthHandle.Instance->MACA2HR; - lowReg = &EthHandle.Instance->MACA2LR; - } - else - { - highReg = &EthHandle.Instance->MACA3HR; - lowReg = &EthHandle.Instance->MACA3LR; - } - - if(perfFiltIdx < numPerfectFilterMacs) - { - tr_debug("Using perfect filtering for %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, - mcastMacs[perfFiltIdx][0], mcastMacs[perfFiltIdx][1], mcastMacs[perfFiltIdx][2], - mcastMacs[perfFiltIdx][3], mcastMacs[perfFiltIdx][4], mcastMacs[perfFiltIdx][5]); - writeMACAddress(mcastMacs[perfFiltIdx].data(), highReg, lowReg); - } - else - { - // Write zeroes to disable this mac addr entry - *highReg = 0; - *lowReg = 0; - } - } - -#if defined(ETH_IP_VERSION_V2) - uint32_t volatile * hashRegs[] = { - &EthHandle.Instance->MACHT0R, - &EthHandle.Instance->MACHT1R - }; -#else - uint32_t volatile * hashRegs[] = { - &EthHandle.Instance->MACHTLR, - &EthHandle.Instance->MACHTHR - }; -#endif - - // Reset hash filter regs - *hashRegs[0] = 0; - *hashRegs[1] = 0; - - // Note: as always, the datasheet description of how to do this CRC was vague and slightly wrong. - // This forum thread figured it out: https://community.st.com/t5/stm32-mcus-security/calculating-ethernet-multicast-filter-hash-value/td-p/416984 - // What the datasheet SHOULD say is: - // 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 - // Then, take the upper 6 bits and use that to index the hash table. - - mbed::MbedCRC crcCalc(0xFFFFFFFF, 0xFFFFFFFF, true, false); - for(size_t hashFiltIdx = 0; hashFiltIdx < numHashFilterMacs; ++hashFiltIdx) - { - auto & currMacAddr = mcastMacs[hashFiltIdx + numPerfectFilterMacs]; - - tr_debug("Using hash filtering for %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8, - currMacAddr[0], currMacAddr[1], currMacAddr[2], - currMacAddr[3], currMacAddr[4], currMacAddr[5]); - - // Compute Ethernet CRC-32 of the MAC address - uint32_t crc; - crcCalc.compute(currMacAddr.data(), currMacAddr.size(), &crc); - - // Take upper 6 bits - uint32_t hashVal = crc >> 26; - - // Set correct bit in hash filter - *hashRegs[hashVal >> 5] |= (1 << (hashVal & 0x1F)); - } -} - -void STM32_EMAC::writeMACAddress(const uint8_t *MAC, volatile uint32_t *addrHighReg, volatile uint32_t *addrLowReg) { - /* Set MAC addr bits 32 to 47 */ - *addrHighReg = (static_cast(MAC[5]) << 8) | static_cast(MAC[4]) | ETH_MACA1HR_AE_Msk; - /* Set MAC addr bits 0 to 31 */ - *addrLowReg = (static_cast(MAC[3]) << 24) | (static_cast(MAC[2]) << 16) | - (static_cast(MAC[1]) << 8) | static_cast(MAC[0]); -} - -// Weak so a module can override -MBED_WEAK EMAC &EMAC::get_default_instance() -{ - return STM32_EMAC::get_instance(); -} - -#if defined(ETH_IP_VERSION_V2) -/******************************************************************************* - PHI IO Functions -*******************************************************************************/ - -/** - * @brief Initializes the MDIO interface GPIO and clocks. - * @param None - * @retval 0 if OK, -1 if ERROR - */ -static int32_t ETH_PHY_IO_Init(void) -{ - /* We assume that MDIO GPIO configuration is already done - in the ETH_MspInit() else it should be done here - */ - STM32_EMAC &emac = STM32_EMAC::get_instance(); - - /* Configure the MDIO Clock */ - HAL_ETH_SetMDIOClockRange(&emac.EthHandle); - - return 0; -} - -/** - * @brief De-Initializes the MDIO interface . - * @param None - * @retval 0 if OK, -1 if ERROR - */ -static int32_t ETH_PHY_IO_DeInit(void) -{ - return 0; -} - -/** - * @brief Read a PHY register through the MDIO interface. - * @param DevAddr: PHY port address - * @param RegAddr: PHY register address - * @param pRegVal: pointer to hold the register value - * @retval 0 if OK -1 if Error - */ -static int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal) -{ - STM32_EMAC &emac = STM32_EMAC::get_instance(); - if (HAL_ETH_ReadPHYRegister(&emac.EthHandle, DevAddr, RegAddr, pRegVal) != HAL_OK) { - return -1; - } - - return 0; -} - -/** - * @brief Write a value to a PHY register through the MDIO interface. - * @param DevAddr: PHY port address - * @param RegAddr: PHY register address - * @param RegVal: Value to be written - * @retval 0 if OK -1 if Error - */ -static int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal) -{ - STM32_EMAC &emac = STM32_EMAC::get_instance(); - if (HAL_ETH_WritePHYRegister(&emac.EthHandle, DevAddr, RegAddr, RegVal) != HAL_OK) { - return -1; - } - - return 0; -} - -/** - * @brief Get the time in millisecons used for internal PHY driver process. - * @retval Time value - */ -static int32_t ETH_PHY_IO_GetTick(void) -{ - return HAL_GetTick(); -} - -/** - * Ethernet DMA transfer error callbacks - */ -void HAL_ETH_DMAErrorCallback(ETH_HandleTypeDef *heth) -{ - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_ETHERNET, EIO), \ - "Error from ethernet HAL (HAL_ETH_DMAErrorCallback)\n"); -} - -/** - * Ethernet MAC transfer error callbacks - */ -void HAL_ETH_MACErrorCallback(ETH_HandleTypeDef *heth) -{ - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_ETHERNET, EIO), \ - "Error from ethernet HAL (HAL_ETH_MACErrorCallback)\n"); -} -#endif // ETH_IP_VERSION_V2 - -#ifndef USE_USER_DEFINED_HAL_ETH_IRQ_CALLBACK - -#define FLAG_RX 1 - -/** - * Override Ethernet Rx Transfer completed callback - * @param heth: ETH handle - * @retval None - */ -void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) -{ - STM32_EMAC &emac = STM32_EMAC::get_instance(); - if (emac.thread) { - osThreadFlagsSet(emac.thread, FLAG_RX); - } -} - -/** - * Override the IRQ Handler - * @param None - * @retval None - */ -void STM_HAL_ETH_Handler() -{ - STM32_EMAC &emac = STM32_EMAC::get_instance(); - HAL_ETH_IRQHandler(&emac.EthHandle); -} - -#else /* USE_USER_DEFINED_HAL_ETH_IRQ_CALLBACK */ - -/** - * IRQ Handler - * - * @param heth: ETH handle - * @retval None - */ -MBED_WEAK void STM_HAL_ETH_Handler() -{ -} - -#endif /* USE_USER_DEFINED_HAL_ETH_IRQ_CALLBACK */ - -#endif /* DEVICE_EMAC */ diff --git a/connectivity/drivers/emac/TARGET_STM/stm32xx_emac.h b/connectivity/drivers/emac/TARGET_STM/stm32xx_emac.h deleted file mode 100644 index e4c81646a45..00000000000 --- a/connectivity/drivers/emac/TARGET_STM/stm32xx_emac.h +++ /dev/null @@ -1,192 +0,0 @@ -/* Copyright (c) 2017 ARM Limited - * Copyright (c) 2017 STMicroelectronics - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef STM32_EMAC_H_ -#define STM32_EMAC_H_ - -#include "EMAC.h" -#include "rtos/Mutex.h" - -class STM32_EMAC : public EMAC { -public: - STM32_EMAC(); - - static STM32_EMAC &get_instance(); - - /** - * Return maximum transmission unit - * - * @return MTU in bytes - */ - virtual uint32_t get_mtu_size() const; - - /** - * Gets memory buffer alignment preference - * - * Gets preferred memory buffer alignment of the Emac device. IP stack may or may not - * align link out memory buffer chains using the alignment. - * - * @return Memory alignment requirement in bytes - */ - virtual uint32_t get_align_preference() const; - - /** - * Return interface name - * - * @param name Pointer to where the name should be written - * @param size Maximum number of character to copy - */ - virtual void get_ifname(char *name, uint8_t size) const; - - /** - * Returns size of the underlying interface HW address size. - * - * @return HW address size in bytes - */ - virtual uint8_t get_hwaddr_size() const; - - /** - * Return interface-supplied HW address - * - * Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size - * - * HW address need not be provided if this interface does not have its own HW - * address configuration; stack will choose address from central system - * configuration if the function returns false and does not write to addr. - * - * @param addr HW address for underlying interface - * @return true if HW address is available - */ - virtual bool get_hwaddr(uint8_t *addr) const; - - /** - * Set HW address for interface - * - * Provided address has to be of correct size, see @a get_hwaddr_size - * - * Called to set the MAC address to actually use - if @a get_hwaddr is provided - * the stack would normally use that, but it could be overridden, eg for test - * purposes. - * - * @param addr Address to be set - */ - virtual void set_hwaddr(const uint8_t *addr); - - /** - * Sends the packet over the link - * - * That can not be called from an interrupt context. - * - * @param buf Packet to be send - * @return True if the packet was send successfully, False otherwise - */ - virtual bool link_out(emac_mem_buf_t *buf); - - /** - * Initializes the HW - * - * @return True on success, False in case of an error. - */ - virtual bool power_up(); - - /** - * Deinitializes the HW - * - */ - virtual void power_down(); - - /** - * Sets a callback that needs to be called for packets received for that interface - * - * @param input_cb Function to be register as a callback - */ - virtual void set_link_input_cb(emac_link_input_cb_t input_cb); - - /** - * Sets a callback that needs to be called on link status changes for given interface - * - * @param state_cb Function to be register as a callback - */ - virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb); - - /** Add device to a multicast group - * - * @param address A multicast group hardware address - */ - virtual void add_multicast_group(const uint8_t *address); - - /** Remove device from a multicast group - * - * @param address A multicast group hardware address - */ - virtual void remove_multicast_group(const uint8_t *address); - - /** Request reception of all multicast packets - * - * @param all True to receive all multicasts - * False to receive only multicasts addressed to specified groups - */ - virtual void set_all_multicast(bool all); - - /** Sets memory manager that is used to handle memory buffers - * - * @param mem_mngr Pointer to memory manager - */ - virtual void set_memory_manager(EMACMemoryManager &mem_mngr); - - // Called from driver functions - ETH_HandleTypeDef EthHandle; - osThreadId_t thread; /**< Processing thread */ - -private: - bool low_level_init_successful(); - void packet_rx(); - int low_level_input(emac_mem_buf_t **buf); - static void thread_function(void *pvParameters); - static void rmii_watchdog_thread_function(void *pvParameters); - void phy_task(); - void enable_interrupts(); - void disable_interrupts(); - - // Populate multicast filter registers with the contents of mcastMacs. - // Uses the perfect filter registers first, then the hash filter. - void populateMcastFilterRegs(); - - // Write a MAC address into a high and low register pair on the MAC. - static void writeMACAddress(uint8_t const * MAC, uint32_t volatile * addrHighReg, uint32_t volatile * addrLowReg); - - mbed_rtos_storage_thread_t thread_cb; -#if defined (STM32F767xx) || defined (STM32F769xx) || defined (STM32F777xx)\ - || defined (STM32F779xx) - mbed_rtos_storage_thread_t rmii_watchdog_thread_cb; - osThreadId_t rmii_watchdog_thread; /**< Watchdog processing thread */ -#endif - rtos::Mutex TXLockMutex;/**< TX critical section mutex */ - rtos::Mutex RXLockMutex;/**< RX critical section mutex */ - emac_link_input_cb_t emac_link_input_cb; /**< Callback for incoming data */ - emac_link_state_change_cb_t emac_link_state_cb; /**< Link state change callback */ - EMACMemoryManager *memory_manager; /**< Memory manager */ - - uint32_t phy_status; - int phy_task_handle; /**< Handle for phy task event */ - - // Multicast subscribe information - std::array mcastMacs[MBED_CONF_STM32_EMAC_MAX_MCAST_SUBSCRIBES]; - size_t numSubscribedMcastMacs; -}; - -#endif /* STM32_EMAC_H_ */ diff --git a/connectivity/drivers/emac/doc/cemac-overview.svg b/connectivity/drivers/emac/doc/cemac-overview.svg new file mode 100644 index 00000000000..caae85731ad --- /dev/null +++ b/connectivity/drivers/emac/doc/cemac-overview.svg @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Implements + Has References + EMAC API + CompositeEMAC +- Implements EMAC API +- Implements locking & the EMAC thread +- Delegates Ethernet functionality to subclasses + MACDriver +- Inits MAC hardware +- Sets up interrupts +- Does MDIO transactions +- Manages the MAC addr +- controls MAC filtering + PHYDriver +- Inits Eth PHY chip +- Configures Eth settings (duplex, speed, autonegotiation) +- Checks link status + TxDMARing +- Enqueues packets into the Ethernet transmit DMA +- Reclaims their memory once they're transmitted + RxDMARing +- Sets up Rx DMA with buffers to receive into +- Detects when packets have been received +- Dequeues pkts for EMAC + + + + diff --git a/connectivity/drivers/emac/doc/embedded-ethernet.svg b/connectivity/drivers/emac/doc/embedded-ethernet.svg new file mode 100644 index 00000000000..36bbcc750d7 --- /dev/null +++ b/connectivity/drivers/emac/doc/embedded-ethernet.svg @@ -0,0 +1,1276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Microcontroller + PHY + + + + + + + + + + + + RMII + MDIO + + Packet Encode and Shift + + + + Packet Shiftand Decode + MDIO MasterInterface + MAC ConfigRegisters + + Tx FIFO + + Tx DMA + + Rx FIFO + + Rx DMA + + + + + + + + + Ethernet MACPeripheral + + + + + + + System Bus + + Main RAM + + ARM CPU Core + EthernetJack + EthernetTransformer + + + + + + + + + MDI + Tx Pair + Rx Pair + + diff --git a/connectivity/drivers/emac/doc/rx-ring-after-dequeue.svg b/connectivity/drivers/emac/doc/rx-ring-after-dequeue.svg new file mode 100644 index 00000000000..b82fd62ade8 --- /dev/null +++ b/connectivity/drivers/emac/doc/rx-ring-after-dequeue.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + dmaOwn = true + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + flags = none + flags = none + flags = none + flags = none + + + rxBuildIndex + + + rxNextIndex + Empty + Empty + Empty + dmaOwn = true + Points to Blank Buffer + Points to Blank Buffer + Empty + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + flags = none + flags = none + + diff --git a/connectivity/drivers/emac/doc/rx-ring-after-rebuild.svg b/connectivity/drivers/emac/doc/rx-ring-after-rebuild.svg new file mode 100644 index 00000000000..00bc648e5e0 --- /dev/null +++ b/connectivity/drivers/emac/doc/rx-ring-after-rebuild.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + dmaOwn = true + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + flags = none + flags = none + flags = none + flags = none + + + rxBuildIndex + + + rxNextIndex + Empty + dmaOwn = true + Points to Blank Buffer + Points to Blank Buffer + dmaOwn = false + flags = none + flags = none + Points to Blank Buffer + Points to Blank Buffer + Points to Blank Buffer + dmaOwn = true + dmaOwn = true + dmaOwn = true + + diff --git a/connectivity/drivers/emac/doc/rx-ring-after-rx.svg b/connectivity/drivers/emac/doc/rx-ring-after-rx.svg new file mode 100644 index 00000000000..271916c0cc0 --- /dev/null +++ b/connectivity/drivers/emac/doc/rx-ring-after-rx.svg @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + dmaOwn = true + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + flags = firstDesc + flags = none + flags = lastDesc + flags = none + flags = none + flags = none + + + rxBuildIndex + + + rxNextIndex + Points to Packet 0 Buf 0 + Points to Packet 0 Buf 1 + Points to Packet 0 Buf 2 + dmaOwn = true + Points to Blank Buffer + Points to Blank Buffer + Empty + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + + diff --git a/connectivity/drivers/emac/doc/rx-ring-initial-state.svg b/connectivity/drivers/emac/doc/rx-ring-initial-state.svg new file mode 100644 index 00000000000..241c1735ccb --- /dev/null +++ b/connectivity/drivers/emac/doc/rx-ring-initial-state.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + dmaOwn = true + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = true + flags = none + flags = none + flags = none + flags = none + flags = none + flags = none + dmaOwn = true + dmaOwn = true + + + rxBuildIndex + + + rxNextIndex + Points to Blank Buffer + Points to Blank Buffer + dmaOwn = true + Points to Blank Buffer + Points to Blank Buffer + Points to Blank Buffer + Empty + dmaOwn = false + + diff --git a/connectivity/drivers/emac/doc/stm32f2-eth-dma-descriptors.png b/connectivity/drivers/emac/doc/stm32f2-eth-dma-descriptors.png new file mode 100644 index 00000000000..f5a298dae73 Binary files /dev/null and b/connectivity/drivers/emac/doc/stm32f2-eth-dma-descriptors.png differ diff --git a/connectivity/drivers/emac/doc/tx-ring-exhausted.svg b/connectivity/drivers/emac/doc/tx-ring-exhausted.svg new file mode 100644 index 00000000000..f5e2b1b9e46 --- /dev/null +++ b/connectivity/drivers/emac/doc/tx-ring-exhausted.svg @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + dmaOwn = true + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = true + dmaOwn = true + dmaOwn = true + + + rxBuildIndex + + + rxNextIndex + Points to Blank Buffer + Points to Blank Buffer + dmaOwn = true + dmaOwn = true + Points to Blank Buffer + Points to Blank Buffer + Points to Blank Buffer + + diff --git a/connectivity/drivers/emac/doc/tx-ring-initial-state.svg b/connectivity/drivers/emac/doc/tx-ring-initial-state.svg new file mode 100644 index 00000000000..def0f29f215 --- /dev/null +++ b/connectivity/drivers/emac/doc/tx-ring-initial-state.svg @@ -0,0 +1,445 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + dmaOwn = false + + Desc 1 + + Desc 2 + + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + + txReclaimIndex + + txSendIndex + Empty + Empty + Empty + Empty + Empty + Empty + + diff --git a/connectivity/drivers/emac/doc/tx-ring-step-1.svg b/connectivity/drivers/emac/doc/tx-ring-step-1.svg new file mode 100644 index 00000000000..2261f6b989a --- /dev/null +++ b/connectivity/drivers/emac/doc/tx-ring-step-1.svg @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = true + + + txReclaimIndex + + + txSendIndex + + Packet being Txed + Points to Packet 0 + Empty + Empty + Empty + Empty + Empty + + diff --git a/connectivity/drivers/emac/doc/tx-ring-step-2.svg b/connectivity/drivers/emac/doc/tx-ring-step-2.svg new file mode 100644 index 00000000000..a36050d2009 --- /dev/null +++ b/connectivity/drivers/emac/doc/tx-ring-step-2.svg @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = true + dmaOwn = true + dmaOwn = true + + + txReclaimIndex + + + txSendIndex + + Packet being Txed + Points to Packet 0 + Points to Packet 1 buf 0 + Points to Packet 1 buf 1 + Empty + Empty + Empty + + diff --git a/connectivity/drivers/emac/doc/tx-ring-step-3.svg b/connectivity/drivers/emac/doc/tx-ring-step-3.svg new file mode 100644 index 00000000000..225ca44e8cc --- /dev/null +++ b/connectivity/drivers/emac/doc/tx-ring-step-3.svg @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = true + dmaOwn = true + + + txReclaimIndex + + + txSendIndex + + Packet being Txed + Points to Packet 0 + Points to Packet 1 buf 0 + Points to Packet 1 buf 1 + Empty + Empty + Empty + + diff --git a/connectivity/drivers/emac/doc/tx-ring-step-4.svg b/connectivity/drivers/emac/doc/tx-ring-step-4.svg new file mode 100644 index 00000000000..0da1b3f25cf --- /dev/null +++ b/connectivity/drivers/emac/doc/tx-ring-step-4.svg @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = true + dmaOwn = true + + + txReclaimIndex + + + txSendIndex + + Packet being Txed + Empty + Points to Packet 1 buf 0 + Points to Packet 1 buf 1 + Empty + Empty + Empty + + diff --git a/connectivity/drivers/emac/doc/tx-ring-step-5.svg b/connectivity/drivers/emac/doc/tx-ring-step-5.svg new file mode 100644 index 00000000000..dde083b59cf --- /dev/null +++ b/connectivity/drivers/emac/doc/tx-ring-step-5.svg @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Desc 0 + + Desc 1 + + Desc 2 + + Desc 3 + + Desc 4 + + Desc 5 + + + + + + + + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + dmaOwn = false + + + txReclaimIndex + + + txSendIndex + Empty + Empty + Empty + Empty + Empty + Empty + + diff --git a/connectivity/drivers/emac/include/CompositeEMAC.h b/connectivity/drivers/emac/include/CompositeEMAC.h new file mode 100644 index 00000000000..f1cb84a602d --- /dev/null +++ b/connectivity/drivers/emac/include/CompositeEMAC.h @@ -0,0 +1,481 @@ +/* Copyright (c) 2024 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_OS_COMPOSITEETHMAC_H +#define MBED_OS_COMPOSITEETHMAC_H + +#include "EMAC.h" +#include "NonCopyable.h" +#include "Thread.h" + +#include + +namespace mbed +{ + +/** + * @brief Implementation of the EMAC API built up from several components implemented by device-specific classes. + * + * \par Motivation + * Originally, Mbed interfaced with the Ethernet hardware on an MCU via a single class, an implementation of the + * EMAC interface. However, EMAC is a large interface, encompassing many responsibilities: setting up the pins, + * managing the Ethernet peripheral, controlling the phy chip, and putting data into and out of DMA. Many of these + * pieces, such as PHY control and managing memory buffers, are common, but others are unique to each MCU family. + * To better divide responsibility into common and target-specific parts, and to allow Ethernet drivers to + * be organized more logically, the CompositeEMAC class was created. + * + * \par Division + * CompositeEMAC divides Ethernet functionality up into several different classes, each with different + * responsibilities: + *
    + *
  • \c MACDriver : Driver for the MAC peripheral itself. Provides functionality to map MAC pins, start up and + * configure the MAC, configure interrupts, and communicate with the phy over MDIO.
  • + *
  • \c PHYDriver : Communicates with the phy. Responsible for configuring it and setting its status.
  • + *
  • \c TxDMA : Driver for the Tx DMA ring. Takes in Tx packets and queues them for transmission in the + * hardware.
  • + *
  • \c RxDMA : Driver for the Rx DMA ring. Sets up Rx descriptors and dequeues them once packets are received.
  • + *
+ * + * \note CompositeEMAC itself does not use any global data and supports multiple instances for MCUs that have + * multiple EMACs. However, the implementation for a specific MCU may or may not use global data -- if + * there's only one EMAC on the MCU, there isn't really a reason not to. + */ +class CompositeEMAC : public EMAC +{ +public: + enum class ErrCode + { + SUCCESS = 0, + TIMEOUT = 1, + HW_ERROR = 2, + PHY_NOT_RESPONDING = 3, + OUT_OF_MEMORY = 4, + INVALID_ARGUMENT = 5, + INVALID_USAGE = 6, + NEGOTIATION_FAILED = 7, + }; + + /// Enumeration of possible Ethernet link speeds + enum class LinkSpeed + { + LINK_10MBIT, + LINK_100MBIT, + LINK_1GBIT + }; + + /// Enumeration of possible Ethernet link duplexes + enum class Duplex + { + HALF, + FULL + }; + + /// Basic MAC address type + static constexpr size_t MAC_ADDR_SIZE = 6; + typedef std::array MACAddress; + + /** + * @brief Abstract interface for a driver for the low level ethernet MAC hardware. + * + * Thread safety: CompositeEMAC will guarantee only one thread is interacting with this class at a time. + */ + class MACDriver : NonCopyable + { + public: + virtual ~MACDriver() = default; + + /** + * @brief Initialize the MAC, map pins, and prepare it to send and receive packets. + * It should not be enabled yet. + * + * Implementations of this method should: + * - Lock deep sleep (unless the MAC functions in deep sleep) + * - Enable clock to the MAC + * - Mux all MAC and PHY pins appropriately + * - Configure MAC registers for operation (but NOT enable tx or rx, yet) + * + * @return Error code or SUCCESS + */ + virtual ErrCode init() = 0; + + /** + * @brief Deinit the MAC so that it's not using any clock/power. Should prepare for init() to be called + * again. + * + * After this function is called (from EMAC::power_down()), the MAC will not be used again + * until power_up() is called and the process starts again. + * + * @return Error code or SUCCESS + */ + virtual ErrCode deinit() = 0; + + /** + * @brief Enable the MAC so that it can send and receive packets + * + * @param speed Speed of the link + * @param duplex Duplex of the link + * + * @return Error code or SUCCESS + */ + virtual ErrCode enable(LinkSpeed speed, Duplex duplex) = 0; + + /** + * @brief Disable the MAC so that it will not send or receive packets + * + * @return Error code or SUCCESS + */ + virtual ErrCode disable() = 0; + + /** + * @brief Set the own address of this MAC. + * + * \note This shall be called by CompositeEMAC after init but before enable. + * + * @param ownAddress Address this MAC will use for itself on the network. + */ + virtual void setOwnMACAddr(MACAddress const & ownAddress) = 0; + + /** + * @brief Read a register from the PHY over the MDIO bus. + * + * @param devAddr PHY device address to read. This will usually be set via the phy strapping pins. + * @param regAddr Register address from 0-31 to read. + * @param result Result is returned here. Note that because MDIO is an open drain bus, a result of + * 0xFFFF usually means the phy didn't respond at all. + * + * @return Error code or success. + */ + virtual ErrCode mdioRead(uint8_t devAddr, uint8_t regAddr, uint16_t & result) = 0; + + /** + * @brief Write a register to the PHY over the MDIO bus. + * + * @param devAddr PHY device address to write. This will usually be set via the phy strapping pins. + * @param regAddr Register address from 0-31 to write. + * @param data Data to write + * + * @return Error code or success. + */ + virtual ErrCode mdioWrite(uint8_t devAddr, uint8_t regAddr, uint16_t data) = 0; + + /** + * @brief Get the reset pin for the Ethernet PHY. + * + * @return Reset pin, or NC if the reset pin is not mapped + */ + virtual PinName getPhyResetPin() = 0; + + /** + * @brief Add a multicast MAC address that should be accepted by the MAC. + * + * \note Only a maximum of \c nsapi.emac-max-mcast-subscribes multicast addresses will be subscribed to + * at once by the upper layer. If the application tried to subscribe to more than that, CEMAC will fall + * back to enabling pass all mcast. + * + * @param mac MAC address to accept + * + * @return Error code or success + */ + virtual ErrCode addMcastMAC(MACAddress mac) = 0; + + /** + * @brief Clear the MAC multicast filter, removing all multicast subscriptions + * + * @return Error code or success + */ + virtual ErrCode clearMcastFilter() = 0; + + /** + * @brief Set whether the MAC passes all multicast traffic up to the application. + * + * CompositeEMAC will ensure this is called only after init(). It will call this either if + * the network stack requests it, or if it can no longer track the mcast addresses that have + * been added and wants to fall back to enabling all multicasts. + * + * @param pass True to pass all mcasts, false otherwise + */ + virtual void setPassAllMcast(bool pass) = 0; + + /** + * @brief Set promiscuous mode (where the Eth MAC passes all traffic up to the application, regardless + * of its destination address). + * + * CompositeEMAC will ensure this is called only after init(). + * + * @param enable True to pass all traffic, false otherwise + */ + virtual void setPromiscuous(bool enable) = 0; + }; + + /** + * @brief Interface for a driver for the Ethernet PHY. + * + * Thread safety: CompositeEMAC will guarantee only one thread is utilizing this class at a time. + */ + class PHYDriver : NonCopyable + { + protected: + /// MAC driver. Shall be set in init(). + MACDriver * mac = nullptr; + + public: + virtual ~PHYDriver() = default; + + /// Set the MAC driver of this PHY. Will be called by CompositeEMAC before init(). + void setMAC(MACDriver * mac) { this->mac = mac; } + + /** + * @brief Initialize the PHY and set it up for Ethernet operation. + * + * @return Error code or success + */ + virtual ErrCode init() = 0; + + /** + * @brief Check whether the link is up or down + * + * @param[out] status Set to true or false depending on whether the link is up or down + * + * @return Error code or success + */ + virtual ErrCode checkLinkStatus(bool & status) = 0; + + /** + * @brief Get the negotiated (or preset) Ethernet speed and duplex, given that the link is up + * + * \note Result speed and duplex undefined if the link is not up. + * + * @param[out] speed Link speed + * @param[out] duplex Link duplex + * + * @return Error code or success + */ + virtual ErrCode checkLinkType(LinkSpeed & speed, Duplex & duplex) = 0; + }; + + /** + * @brief Abstract interface for a driver for the Tx DMA ring in the Ethernet MAC. + * + * Thread safety: CompositeEMAC will guarantee only one thread is utilizing this class at a time. + */ + class TxDMA { + protected: + /// Pointer to memory manager for the EMAC + EMACMemoryManager * memory_manager = nullptr; + + public: + virtual ~TxDMA() = default; + + /// Set the mem manager of this DMA ring. Will be called by CompositeEMAC before init(). + void setMemoryManager(EMACMemoryManager * memory_manager) { this->memory_manager = memory_manager; } + + /// Initialize this Tx DMA ring. + virtual ErrCode init() = 0; + + /// Stop the DMA running. + /// init() should be able to be called again after this function completes to restart DMA. + /// This shall be called after the MAC is disabled but before it is powered down. + virtual ErrCode deinit() = 0; + + /// Reclaims the Tx buffers for any transmitted packets and frees their memory. + /// Invoked by the CompositeEMAC internal thread after a Tx interrupt happens. + /// Returns true if any descriptors became available, false otherwise + virtual bool reclaimTxDescs() = 0; + + /// Transmit a packet out of the Tx DMA ring. Note that this function + /// *takes ownership of* the passed packet and must free it either now or after + /// it's been transmitted. + /// Should block until there is space to transmit the packet. + virtual ErrCode txPacket(net_stack_mem_buf_t * buf) = 0; + }; + + /** + * @brief Abstract interface for a driver for the Rx DMA ring in the Ethernet MAC. + * + * Thread safety: CompositeEMAC will guarantee only one thread is utilizing this class at a time. + */ + class RxDMA { + protected: + /// Pointer to memory manager for the EMAC + EMACMemoryManager * memory_manager = nullptr; + + public: + virtual ~RxDMA() = default; + + /// Set the mem manager of this DMA ring. Will be called by CompositeEMAC before init(). + void setMemoryManager(EMACMemoryManager * memory_manager) { this->memory_manager = memory_manager; } + + /// Initialize this Rx DMA ring. + virtual ErrCode init() = 0; + + /// Stop the DMA running. init() should be able to be called again after this function completes to restart DMA. + /// This shall be called after the MAC is disabled but before it is powered down. + virtual ErrCode deinit() = 0; + + /** + * @brief Check if the MAC may have a packet to receive. Called from the Rx ISR. + * + * This function is called to provide a hint to CompositeEMAC about whether it needs to call + * dequeuePacket() after an Rx ISR is received. + * + * @return True if the MAC might have a descriptor to receive. False if there is definitely no complete packet yet. + */ + virtual bool rxHasPackets_ISR() = 0; + + /** + * @brief Dequeue a packet, if one is ready to be received. + * + * This function should also dequeue and dispose of any error or incomplete DMA descriptors. + * After rxHasPackets_ISR() returns true, the MAC thread will call this it over and over again + * until it returns nullptr. + * + * @return Packet pointer, or nullptr if there were no packets. + */ + virtual net_stack_mem_buf_t * dequeuePacket() = 0; + + /** + * @brief Rebuild DMA descriptors, if there are descriptors that need building and there is free pool memory. + * + * This function is called by the MAC thread after a packet has been dequeued, and also when memory in the Rx + * pool becomes free. + */ + virtual void rebuildDescriptors() = 0; + }; + +protected: + + /// Pointer to memory manager for the EMAC + EMACMemoryManager * memory_manager = nullptr; + + // Callbacks to the MAC + emac_link_state_change_cb_t linkStateCallback{}; + emac_link_input_cb_t linkInputCallback{}; + + // Instances of each of the 4 component classes + PHYDriver * phy = nullptr; + RxDMA & rxDMA; + TxDMA & txDMA; + MACDriver & mac; + + // Event queue handle for phy task + int phyTaskHandle; + + // Thread running inside the MAC. Processes interrupts (both Tx and Rx) and receives packets. + rtos::Thread * macThread = nullptr; + + // State of the MAC + enum class PowerState { + OFF = 0, + ON_NO_LINK, + ON_LINK_UP + }; + + std::atomic state = PowerState::OFF; + + // State of the link + enum class LinkState { + DOWN, + UP + }; + + std::atomic linkState = LinkState::DOWN; + + // Multicast subscribe information + MACAddress mcastMacs[MBED_CONF_NSAPI_EMAC_MAX_MCAST_SUBSCRIBES]; + + // Note: if this variable becomes >= MBED_CONF_NSAPI_EMAC_MAX_MCAST_SUBSCRIBES, we are in multicast + // fallback mode and are accepting all multicasts. The only way to get out of this mode is to power down + // and power up the MAC. + size_t numSubscribedMcastMacs; + + // Mutex that must be acquired before interacting with the MAC. This is used to protect against, for example, + // one thread calling power_down() while the phy task is still running. + rtos::Mutex macOpsMutex; + + /// Subclass should call this when a receive interrupt is detected + void rxISR(); + + /// Subclass should call this when a transmit complete interrupt is detected + void txISR(); + + /// Called periodically to poll the phy and bring link up/down + void phyTask(); + + /// Run in its own thread to service the MAC. + void macTask(); + + /// Callback from memory manager when Rx pool space frees up + void onRxPoolSpaceAvail(); + + /// Constructor. Should be called by subclass. + CompositeEMAC(TxDMA & txDMA, RxDMA & rxDMA, MACDriver & macDriver): + rxDMA(rxDMA), + txDMA(txDMA), + mac(macDriver) + {} + +public: + uint32_t get_mtu_size() const override { + // Regular Ethernet has an MTU of 1500. + // Some MACs support Jumbo Frames of up to 9000 bytes; this might be worth adding at some point + return 1500; + } + + uint32_t get_align_preference() const override { + // Most DMAs require or work best with word-aligned buffers. + // NOTE: As of Feb 2025, nothing in Mbed actually uses this value. + return 4; + } + + void get_ifname(char *name, uint8_t size) const override; + + uint8_t get_hwaddr_size() const override { + return MAC_ADDR_SIZE; + } + + bool get_hwaddr(uint8_t *addr) const override { + // Return false to tell upper layer code to use mbed_mac_address() to get the MAC address. + // TODO once we support more than 1 ethernet port per device, this will need to be updated + // to make sure each interface has a different MAC address. + return false; + } + + void set_hwaddr(const uint8_t *addr) override; + + bool link_out(emac_mem_buf_t *buf) override; + + bool power_up() override; + + void power_down() override; + + void set_link_input_cb(emac_link_input_cb_t input_cb) override; + + void set_link_state_cb(emac_link_state_change_cb_t state_cb) override; + + void add_multicast_group(const uint8_t *address) override; + + void remove_multicast_group(const uint8_t *address) override; + + void set_all_multicast(bool all) override; + + void set_memory_manager(EMACMemoryManager &mem_mngr) override { + MBED_ASSERT(state == PowerState::OFF); + memory_manager = &mem_mngr; + } +}; + +} +#endif //MBED_OS_COMPOSITEETHMAC_H diff --git a/connectivity/drivers/emac/include/GenericEthDMA.h b/connectivity/drivers/emac/include/GenericEthDMA.h new file mode 100644 index 00000000000..05cb0c08635 --- /dev/null +++ b/connectivity/drivers/emac/include/GenericEthDMA.h @@ -0,0 +1,647 @@ +/* Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_OS_GENERICETHDMA_H +#define MBED_OS_GENERICETHDMA_H + +#include "CompositeEMAC.h" +#include "mbed_trace.h" +#include "CacheAlignedBuffer.h" +#include "mbed_critical.h" +#include +#include + +#define TRACE_GROUP "GEDMA" + +namespace mbed { + /** + * @brief Generic transmit DMA loop + * + * This implementation of Tx DMA should work for the large majority of embedded MCUs that use a DMA ring-based + * ethernet MAC. + */ + class GenericTxDMARing : public CompositeEMAC::TxDMA + { + protected: + /// Number of entries in the Tx descriptor ring + static constexpr size_t TX_NUM_DESCS = MBED_CONF_NSAPI_EMAC_TX_NUM_DESCS; + + /// Extra, unfilled Tx descs to leave in the DMA ring at all times. + /// This is used to support Eth MACs that don't allow enqueuing every single descriptor at a time. + const size_t extraTxDescsToLeave; + + /// Pointer to first memory buffer in the chain associated with descriptor n. + /// The buffer address shall only be set for the *last* descriptor, so that the entire chain is freed + /// when the last descriptor is returned. + std::array descStackBuffers{}; + + /// EventFlag used to signal when a Tx descriptor becomes available + rtos::EventFlags txDescAvailFlag; + + // Indexes for descriptor rings. + // NOTE: when working with these indices, it's important to consider the case where e.g. the send and reclaim indexes are + // equal. This could mean *either* that the Tx ring is completely full of data, or that the Tx ring is empty. + // To resolve this ambiguity, we maintain separate count variables that track how many entries are in the ring at present. + size_t txSendIndex; ///< Index of the next Tx descriptor that can be filled with data + std::atomic txDescsOwnedByApplication; ///< Number of Tx descriptors owned by the application. Decremented by txPacket() and incremented by reclaimTxDescs() + size_t txReclaimIndex; ///< Index of the next Tx descriptor that will be reclaimed by the mac thread calling reclaimTxDescs(). + + /// Construct, passing a value for extraTxDescsToLeave + GenericTxDMARing(size_t extraTxDescsToLeave = 0): + extraTxDescsToLeave(extraTxDescsToLeave) + {} + + /// Configure DMA registers to point to the DMA ring, + /// and enable DMA. This is done before the MAC itself is enabled. + virtual void startDMA() = 0; + + /// Stop the DMA running. This is done after MAC transmit & recieve are disabled. + virtual void stopDMA() = 0; + +#if __DCACHE_PRESENT + /// Invalidate cache for the descriptor at the given index so it gets reloaded from main memory + virtual void cacheInvalidateDescriptor(size_t descIdx) = 0; +#endif + + /// Is the given descriptor owned by DMA? + /// Note that the descriptor will already have been invalidated in cache if needed. + virtual bool descOwnedByDMA(size_t descIdx) = 0; + + /// Get whether the given buffer is in a memory region readable by the Ethernet DMA. + /// If this returns false for a buffer being transmitted, the buffer will be copied into a new + /// heap-allocated buffer. + virtual bool isDMAReadableBuffer(uint8_t const * start, size_t size) const = 0; + + /// Give the descriptor at the given index to DMA to be transmitted with the given buffer. + /// Note: if the descriptor needs to be flushed from CPU cache, you need to do that + /// at the correct point in the implementation of this method! + /// Also, if the DMA ran out of data to transmit, you may need to do a "poke"/"wake" operation + /// to tell it to start running again. + virtual void giveToDMA(size_t descIdx, uint8_t const * buffer, size_t len, bool firstDesc, bool lastDesc) = 0; + + // Utility function for implementing isDMAReadableBuffer(). + // 1D intersection test between a buffer and a memory bank. + static bool bufferTouchesMemoryBank(uint8_t const * start, const size_t size, const uint32_t bankStartAddr, const uint32_t bankSize) { + const auto startAddrInt = reinterpret_cast(start); + + if(startAddrInt < bankStartAddr) { + // Case 1: buffer begins before bank + return (startAddrInt + size) > bankStartAddr; + } + else if(startAddrInt >= bankStartAddr && startAddrInt < (bankStartAddr + bankSize)) { + // Case 2: buffer begins inside bank + return true; + } + else { + // Case 3: buffer begins after bank + return false; + } + } + + public: + CompositeEMAC::ErrCode init() override { + // At the start, we own all the descriptors + txDescsOwnedByApplication = TX_NUM_DESCS; + + // Next descriptor will be descriptor 0 + txSendIndex = 0; + txReclaimIndex = 0; + + startDMA(); + + return CompositeEMAC::ErrCode::SUCCESS; + } + + CompositeEMAC::ErrCode deinit() override { + stopDMA(); + + // Deallocate all buffers currently assigned to the DMA ring + for(auto & buf_addr : descStackBuffers) { + if(buf_addr != nullptr) { + memory_manager->free(buf_addr); + buf_addr = nullptr; + } + } + + return CompositeEMAC::ErrCode::SUCCESS; + } + + bool reclaimTxDescs() override { + bool returnedAnyDescriptors = false; + while (true) + { + if (txReclaimIndex == txSendIndex && txDescsOwnedByApplication > 0) { + // If we have reached the Tx send index, we want to stop iterating as this is + // the next descriptor that has not been populated by the application yet. + // The only exception is if the Tx ring is completely full, in which case we want + // to process the entire ring. In the case where the Tx ring is full, + // txDescsOwnedByApplication will be 0. + // Note that txSendIndex and txDescsOwnedByApplication are updated in a critical + // section so their values will always be in sync with each other. + break; + } + + +#if __DCACHE_PRESENT + cacheInvalidateDescriptor(txReclaimIndex); +#endif + + if (descOwnedByDMA(txReclaimIndex)) { + // This desc is owned by the DMA, so we have reached the part of the ring buffer + // that is still being transmitted. + // Done for now! + break; + } + + // Free any buffers associated with the descriptor + if (descStackBuffers[txReclaimIndex] != nullptr) { + memory_manager->free(descStackBuffers[txReclaimIndex]); + descStackBuffers[txReclaimIndex] = nullptr; + } + + // Update counters + txReclaimIndex = (txReclaimIndex + 1) % TX_NUM_DESCS; + ++txDescsOwnedByApplication; + + tr_debug("Reclaimed descriptor %zu", txReclaimIndex); + + returnedAnyDescriptors = true; + } + + if(returnedAnyDescriptors) { + txDescAvailFlag.set(1); + } + + return returnedAnyDescriptors; + } + + CompositeEMAC::ErrCode txPacket(net_stack_mem_buf_t * buf) { + // Step 1: Figure out if we can send this zero-copy, or if we need to copy it. + size_t packetDescsUsed = memory_manager->count_buffers(buf); + size_t neededFreeDescs = packetDescsUsed + extraTxDescsToLeave; + bool needToCopy = false; + if(neededFreeDescs >= TX_NUM_DESCS) + { + // Packet uses too many buffers, we have to copy it into a continuous buffer. + // Note: Some Eth DMAs (e.g. STM32 v2) cannot enqueue all the descs in the ring at the same time + // so we can't use every single descriptor to send the packet. + needToCopy = true; + } + + if(!needToCopy && (neededFreeDescs > txDescsOwnedByApplication && txDescsOwnedByApplication > extraTxDescsToLeave)) { + // Packet uses more buffers than we have descriptors, but we can send it immediately if we copy + // it into a single buffer. + needToCopy = true; + } + + if(!needToCopy) { + net_stack_mem_buf_t * currBuf = buf; + while(currBuf != nullptr) { + // If this buffer is passed down direct from the application, we will need to + // copy the packet. + if(memory_manager->get_lifetime(currBuf) == NetStackMemoryManager::Lifetime::VOLATILE) + { + needToCopy = true; + break; + } + + // Or, if the buffer is in DMA-inaccessible RAM, we will need to copy it + if(!isDMAReadableBuffer(static_cast(memory_manager->get_ptr(currBuf)), memory_manager->get_len(currBuf))) { + needToCopy = true; + break; + } + + currBuf = memory_manager->get_next(currBuf); + } + } + + tr_debug("Transmitting packet of length %lu in %zu buffers and %zu descs\n", + memory_manager->get_total_len(buf), memory_manager->count_buffers(buf), neededDescs); + + // Step 2: Copy packet if needed + if(needToCopy) + { + auto * newBuf = memory_manager->alloc_heap(memory_manager->get_total_len(buf), 0); + if(newBuf == nullptr) + { + // No free memory, drop packet + return CompositeEMAC::ErrCode::OUT_OF_MEMORY; + } + + // We should have gotten just one contiguous buffer + MBED_ASSERT(memory_manager->get_next(newBuf) == nullptr); + packetDescsUsed = 1; + neededFreeDescs = packetDescsUsed + extraTxDescsToLeave; + + // Copy data over + memory_manager->copy_from_buf(static_cast(memory_manager->get_ptr(newBuf)), memory_manager->get_len(newBuf), buf); + memory_manager->free(buf); + buf = newBuf; + } + + // Step 3: Wait for needed amount of buffers to be available. + // Note that, in my experience, it's better to block here, as dropping the packet + // due to not having enough buffers can create weird effects when the application sends + // lots of packets at once. + while(txDescsOwnedByApplication < neededFreeDescs) + { + txDescAvailFlag.wait_any_for(1, rtos::Kernel::wait_for_u32_forever); + } + + // Step 4: Load buffer into descriptors and send + net_stack_mem_buf_t * currBuf = buf; + for(size_t descCount = 0; descCount < packetDescsUsed; descCount++) + { +#if __DCACHE_PRESENT + // Write buffer back to main memory + SCB_CleanDCache_by_Addr(memory_manager->get_ptr(currBuf), memory_manager->get_len(currBuf)); +#endif + + // Get next buffer + const auto nextBuf = memory_manager->get_next(currBuf); + if(nextBuf == nullptr) + { + // Last descriptor, store head buffer address for freeing + descStackBuffers[txSendIndex] = buf; + } + else + { + descStackBuffers[txSendIndex] = nullptr; + } + + // Get the pointer and length of the packet because this might not be doable in a critical section + const auto bufferPtr = static_cast(memory_manager->get_ptr(currBuf)); + const auto bufferLen = memory_manager->get_len(currBuf); + + // Enter a critical section, because we could run into weird corner cases if the + // interrupt executes while we are half done configuring this descriptor and updating + // the counters. + core_util_critical_section_enter(); + + // Configure settings. + giveToDMA(txSendIndex, bufferPtr, bufferLen, descCount == 0, nextBuf == nullptr); + + // Update descriptor count and index + --txDescsOwnedByApplication; + txSendIndex = (txSendIndex + 1) % MBED_CONF_NSAPI_EMAC_TX_NUM_DESCS; + + core_util_critical_section_exit(); + + // Move to next buffer + currBuf = nextBuf; + } + + return CompositeEMAC::ErrCode::SUCCESS; + } + + }; + + /** + * @brief Generic receive DMA loop + * + * This implementation of Rx DMA should work for the large majority of embedded MCUs that use a DMA ring-based + * ethernet MAC. + * + * The subclass must allocate the DMA descriptors, and all access to them is done through virtual functions + * that the subclass must override. + */ + class GenericRxDMARing : public CompositeEMAC::RxDMA { + protected: + /// How many extra buffers to leave in the Rx pool, relative to how many we keep assigned to Rx descriptors. + /// We want to keep some amount of extra buffers because constantly hitting the network stack with failed pool + /// allocations can produce some negative consequences in some cases. + static constexpr size_t RX_POOL_EXTRA_BUFFERS = 3; + + /// Number of entries in the Rx descriptor ring + /// Note: + 1 because for some EMACs (STM32 v2) we have to always keep one descriptor owned by the application + // TODO: When we add multiple Ethernet support, this calculation may need to be changed, because the pool buffers will be split between multiple EMACs + static constexpr size_t RX_NUM_DESCS = MBED_CONF_NSAPI_EMAC_RX_POOL_NUM_BUFS - RX_POOL_EXTRA_BUFFERS + 1; + + /// Pointer to the network stack buffer associated with the corresponding Rx descriptor. + net_stack_mem_buf_t * rxDescStackBufs[RX_NUM_DESCS]; + + // Indexes for descriptor rings. + size_t rxBuildIndex; ///< Index of the next Rx descriptor that needs to be built. Updated by application and used by ISR. + size_t rxDescsOwnedByApplication; ///< Number of Rx descriptors owned by the application and needing buffers allocated. + std::atomic rxNextIndex; ///< Index of the next descriptor that the DMA will populate. Updated by application but used by ISR. + + // Alignment required for Rx memory buffers. Normally they don't need more than word alignment but + // if we are doing cache operations they need to be cache aligned. +#if __DCACHE_PRESENT + static constexpr size_t RX_BUFFER_ALIGN = __SCB_DCACHE_LINE_SIZE; +#else + static constexpr size_t RX_BUFFER_ALIGN = sizeof(uint32_t); +#endif + + /// Payload size of buffers allocated from the Rx pool. This is the allocation unit size + /// of the pool minus any overhead needed for alignment. + size_t rxPoolPayloadSize; + + /// Constructor. Subclass must allocate descriptor array of size RX_NUM_DESCS + GenericRxDMARing() = default; + + /// Configure DMA registers to point to the DMA ring, + /// and enable DMA. This is done before the MAC itself is enabled, and before any descriptors + /// are given to DMA. + virtual void startDMA() = 0; + + /// Stop the DMA running. This is done after MAC transmit & receive are disabled. + virtual void stopDMA() = 0; + +#if __DCACHE_PRESENT + /// Invalidate cache for the descriptor at the given index so it gets reloaded from main memory + virtual void cacheInvalidateDescriptor(size_t descIdx) = 0; +#endif + + /// Is the given descriptor owned by DMA? + /// Note that the descriptor will already have been invalidated in cache if needed. + virtual bool descOwnedByDMA(size_t descIdx) = 0; + + /// Does the given descriptor contain the start of a packet? + /// Note that the descriptor will already have been invalidated in cache if needed. + virtual bool isFirstDesc(size_t descIdx) = 0; + + /// Does the given descriptor contain the end of a packet? + /// /// Note that the descriptor will already have been invalidated in cache if needed. + virtual bool isLastDesc(size_t descIdx) = 0; + + /// Is the given descriptor an error descriptor? + /// /// Note that the descriptor will already have been invalidated in cache if needed. + virtual bool isErrorDesc(size_t descIdx) = 0; + + /// Return a descriptor to DMA so that DMA can receive into it. + /// Is passed the buffer address (fixed size equal to rxPoolPayloadSize) to attach to this descriptor. + /// Note: if the descriptor needs to be flushed from CPU cache, you need to do that + /// at the correct point in the implementation of this method! + /// Also, if the DMA ran out of data to transmit, you may need to do a "poke"/"wake" operation + /// to tell it to start running again. + virtual void returnDescriptor(size_t descIdx, uint8_t * buffer) = 0; + + /// Get the length of the packet starting at firstDescIdx and continuing until + /// lastDescIdx (which might or might not be the same as firstDescIdx). Descriptors have already been + /// validated to contain a complete packet at this point. + virtual size_t getTotalLen(size_t firstDescIdx, size_t lastDescIdx) = 0; + + public: + CompositeEMAC::ErrCode init() override { + rxPoolPayloadSize = memory_manager->get_pool_alloc_unit(RX_BUFFER_ALIGN); + rxBuildIndex = 0; + rxNextIndex = 0; + + // At the start, we own all the descriptors + rxDescsOwnedByApplication = RX_NUM_DESCS; + + // init DMA peripheral + startDMA(); + + // Build all descriptors + rebuildDescriptors(); + + return CompositeEMAC::ErrCode::SUCCESS; + } + + CompositeEMAC::ErrCode deinit() override { + stopDMA(); + + // Deallocate buffers associated with all descriptors + for(size_t descIdx = 0; descIdx < RX_NUM_DESCS; ++descIdx) { + if(rxDescStackBufs[descIdx] != nullptr) { + memory_manager->free(rxDescStackBufs[descIdx]); + } + } + + return CompositeEMAC::ErrCode::SUCCESS; + } + + void rebuildDescriptors() override { + const size_t origRxDescsOwnedByApplication [[maybe_unused]] = rxDescsOwnedByApplication; + + // Note: With some Ethernet peripherals, you can never give back every single descriptor to + // the hardware, because then it thinks there are 0 descriptors left. + while (rxDescsOwnedByApplication > 1) { + // Allocate new buffer + auto *const buffer = memory_manager->alloc_pool(rxPoolPayloadSize, RX_BUFFER_ALIGN); + if (buffer == nullptr) { + // No memory, cannot return any more descriptors. + return; + } + + // Store buffer address + rxDescStackBufs[rxBuildIndex] = buffer; + + // Send descriptor to DMA + returnDescriptor(rxBuildIndex, static_cast(memory_manager->get_ptr(buffer))); + + // Move to next descriptor + --rxDescsOwnedByApplication; + rxBuildIndex = (rxBuildIndex + 1) % RX_NUM_DESCS; + } + + tr_debug("buildRxDescriptors(): Returned %zu descriptors.", origRxDescsOwnedByApplication - rxDescsOwnedByApplication); + } + + bool rxHasPackets_ISR() override { + // First, we need to check if at least one DMA descriptor that is owned by the application + // has its last descriptor flag or error flag set, indicating we have received at least one complete packet + // or there is an error descriptor that can be reclaimed by the application. + // Note that we want to bias towards false positives here, because false positives just waste CPU time, + // while false negatives would cause packets to be dropped. + // So, for simplicity, we just check every descriptor currently owned by the application until we + // find one with the FS bit set or the error bits set. + // This could potentially produce a false positive if we do this in the middle of receiving + // an existing packet, but that is unlikely and will not cause anything bad to happen if it does. + + bool seenFirstDesc = false; + + for(size_t descCount = 0; descCount < RX_NUM_DESCS; descCount++) + { + size_t descIdx = (rxNextIndex + descCount) % RX_NUM_DESCS; + +#if __DCACHE_PRESENT + cacheInvalidateDescriptor(descIdx); +#endif + + if(descOwnedByDMA(descIdx)) + { + // Descriptor owned by DMA. We are out of descriptors to process. + return false; + } + if(isFirstDesc(descIdx)) + { + if(seenFirstDesc) + { + // First desc seen after another first desc. + // Some MACs do this if they run out of Rx descs when halfway through a packet. + // dequeuePacket() can clean this up and reclaim the partial packet desc(s). + return true; + } + else + { + seenFirstDesc = true; + } + } + if(isErrorDesc(descIdx) || isLastDesc(descIdx)) + { + // Reclaimable descriptor or complete packet detected. + return true; + } + } + + // Processed all descriptors. + return false; + } + + private: + + /// Helper function: Discard received Rx descriptors from a given start index (inclusive) to stop index (exclusive) + void discardRxDescs(size_t startIdx, size_t stopIdx) + { + for(size_t descToCleanIdx = startIdx; descToCleanIdx != stopIdx; descToCleanIdx = (descToCleanIdx + 1) % RX_NUM_DESCS) { + // Free Rx buffer attached to this desc + memory_manager->free(rxDescStackBufs[descToCleanIdx]); + rxDescStackBufs[descToCleanIdx] = nullptr; + + // Allow desc to be rebuilt + ++rxDescsOwnedByApplication; + ++rxNextIndex; + } + } + + public: + + net_stack_mem_buf_t * dequeuePacket() override { + // Indices of the first and last descriptors for the packet will be saved here + std::optional firstDescIdx, lastDescIdx; + + // Packet length is stored here once we check it + size_t pktLen; + + // Prevent looping around into descriptors waiting for rebuild by limiting how many + // we can process. + const size_t maxDescsToProcess = RX_NUM_DESCS - rxDescsOwnedByApplication; + + const size_t startIdx = rxNextIndex; + + for (size_t descCount = 0; descCount < maxDescsToProcess && !lastDescIdx.has_value(); descCount++) { + size_t descIdx = (startIdx + descCount) % RX_NUM_DESCS; + +#if __DCACHE_PRESENT + cacheInvalidateDescriptor(descIdx); +#endif + + if (descOwnedByDMA(descIdx)) { + // Descriptor owned by DMA and has not been filled in yet. We are out of descriptors to process. + break; + } + + const bool isError = isErrorDesc(descIdx); + const bool isFirst = isFirstDesc(descIdx); + const bool isLast = isLastDesc(descIdx); + + if (!firstDescIdx.has_value() && (isError || !isFirst)) { + // Error or non-first-descriptor before a first descriptor + // (could be caused by incomplete packets/junk in the DMA buffer). + // Ignore, free associated memory, and schedule for rebuild. + discardRxDescs(descIdx, (descIdx + 1) % RX_NUM_DESCS); + continue; + } + else if(firstDescIdx.has_value() && isError) + { + // Already seen a first descriptor, but we have an error descriptor. + // So, delete the in-progress packet up to this point. + discardRxDescs(*firstDescIdx, (descIdx + 1) % RX_NUM_DESCS); + firstDescIdx.reset(); + continue; + } + else if(firstDescIdx.has_value() && isFirst) + { + // Already seen a first descriptor, but we have another first descriptor. + // Some MACs do this if they run out of Rx descs when halfway through a packet. + // Delete the in-progress packet up to this point and start over from descIdx. + discardRxDescs(*firstDescIdx, descIdx); + firstDescIdx = descIdx; + } + else if(isFirst) + { + // Normal first descriptor. + firstDescIdx = descIdx; + } + + if(isLast) { + pktLen = getTotalLen(*firstDescIdx, descIdx); + lastDescIdx = descIdx; + } + } + + if (!lastDescIdx.has_value()) { + // No complete packet identified. + // Take the chance to rebuild any available descriptors, then return. + rebuildDescriptors(); + tr_debug("No complete packets in Rx descs\n"); + return nullptr; + } + + // We will receive next into the descriptor after this one. + // Update this now to tell the ISR to search for descriptors after lastDescIdx only. + rxNextIndex = (*lastDescIdx + 1) % RX_NUM_DESCS; + + // Set length of first buffer + net_stack_mem_buf_t *const headBuffer = rxDescStackBufs[*firstDescIdx]; + + memory_manager->set_len(headBuffer, std::min(pktLen, rxPoolPayloadSize)); + size_t lenRemaining = pktLen - std::min(pktLen, rxPoolPayloadSize); + + // Iterate through the subsequent descriptors in this packet and link the buffers + // Note that this also transfers ownership of subsequent buffers to the first buffer, + // so if the first buffer is deleted, the others will be as well. + + ++rxDescsOwnedByApplication; // for first buffer + rxDescStackBufs[*firstDescIdx] = nullptr; + for (size_t descIdx = (*firstDescIdx + 1) % RX_NUM_DESCS; + descIdx != (*lastDescIdx + 1) % RX_NUM_DESCS; + descIdx = (descIdx + 1) % RX_NUM_DESCS) { + + // We have to set the buffer length first before concatenating it to the chain + MBED_ASSERT(lenRemaining > 0); + memory_manager->set_len(rxDescStackBufs[descIdx], std::min(lenRemaining, rxPoolPayloadSize)); + lenRemaining -= std::min(lenRemaining, rxPoolPayloadSize); + + memory_manager->cat(headBuffer, rxDescStackBufs[descIdx]); + rxDescStackBufs[descIdx] = nullptr; + ++rxDescsOwnedByApplication; + } + + // Invalidate cache for all data buffers, as these were written by the DMA to main memory +#if __DCACHE_PRESENT + auto * bufToInvalidate = headBuffer; + while(bufToInvalidate != nullptr) + { + SCB_InvalidateDCache_by_Addr(memory_manager->get_ptr(bufToInvalidate), rxPoolPayloadSize); + bufToInvalidate = memory_manager->get_next(bufToInvalidate); + } +#endif + + tr_debug("Returning packet of length %lu, start %p from Rx descriptors %zu-%zu\n", + memory_manager->get_total_len(headBuffer), memory_manager->get_ptr(headBuffer), *firstDescIdx, *lastDescIdx); + + return headBuffer; + } + }; +} + +#undef TRACE_GROUP + +#endif //MBED_OS_GENERICETHDMA_H diff --git a/connectivity/drivers/emac/include/GenericEthPhy.h b/connectivity/drivers/emac/include/GenericEthPhy.h new file mode 100644 index 00000000000..a05aea62313 --- /dev/null +++ b/connectivity/drivers/emac/include/GenericEthPhy.h @@ -0,0 +1,149 @@ +/* Copyright (c) 2024 Jamie Smith +* SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_OS_GENERICETHPHY_H +#define MBED_OS_GENERICETHPHY_H + +#include "CompositeEMAC.h" +#include "DigitalOut.h" + +#include + +namespace mbed { + +namespace GenPhyRegs { + /// Generic Ethernet phy register definitions + /// @{ + inline constexpr uint8_t BMCR = 0; ///< Basic Mode Control Register + + inline constexpr size_t BMCR_SW_RST_Pos = 15; + inline constexpr uint16_t BMCR_SW_RST_Msk = 1 << BMCR_SW_RST_Pos; + + inline constexpr size_t BMCR_SPEED_100M_Pos = 13; + inline constexpr uint16_t BMCR_SPEED_100M_Msk = 1 << BMCR_SPEED_100M_Pos; + + inline constexpr size_t BMCR_ANEG_EN_Pos = 12; + inline constexpr uint16_t BMCR_ANEG_EN_Msk = 1 << BMCR_ANEG_EN_Pos; + + inline constexpr size_t BMCR_ANEG_RESTART_Pos = 9; + inline constexpr uint16_t BMCR_ANEG_RESTART_Msk = 1 << BMCR_ANEG_RESTART_Pos; + + inline constexpr size_t BMCR_DUPLEX_FULL_Pos = 8; + inline constexpr uint16_t BMCR_DUPLEX_FULL_Msk = 1 << BMCR_DUPLEX_FULL_Pos; + + inline constexpr uint8_t BMSR = 1; ///< Basic Mode Status Register + + inline constexpr size_t BMCR_LINK_UP_Pos = 2; + inline constexpr uint16_t BMCR_LINK_UP_Msk = 1 << BMCR_LINK_UP_Pos; + + inline constexpr uint8_t PHYIDR1 = 2; ///< PHY ID Register 1 + inline constexpr uint8_t PHYIDR2 = 3; ///< PHY ID Register 2 + inline constexpr uint8_t ANAR = 4; ///< AutoNegotiation Advertisement Register + + inline constexpr size_t ANAR_100BTX_FD_Pos = 8; + inline constexpr uint16_t ANAR_100BTX_FD_Msk = 1 << ANAR_100BTX_FD_Pos; + + inline constexpr size_t ANAR_100BTX_Pos = 7; + inline constexpr uint16_t ANAR_100BTX_Msk = 1 << ANAR_100BTX_Pos; + + inline constexpr size_t ANAR_10BT_FD_Pos = 6; + inline constexpr uint16_t ANAR_10BT_FD_Msk = 1 << ANAR_10BT_FD_Pos; + + inline constexpr size_t ANAR_10BT_Pos = 5; + inline constexpr uint16_t ANAR_10BT_Msk = 1 << ANAR_10BT_Pos; + + /// Value for ANAR[4:0] that specifies Ethernet as the protocol + inline constexpr uint16_t ANAR_PROTOCOL_IEE_802_3U_Val = 1; + + inline constexpr uint8_t ANLPAR = 5; ///< AutoNegotiation Link Partner Advertisement Register + /// @} +} + +/** + * @brief Driver for a generic, Ethernet-standard compliant PHY chip. + * + * Passed a configuration which sets most attributes of the phy. + * May be extended to handle chip-specific quirks. + */ +class GenericEthPhy : public mbed::CompositeEMAC::PHYDriver { +public: + /// Configuration structure for a generic Ethernet PHY + struct Config { + /// 24-bit OUI of the organization that produced the ethernet PHY. + uint32_t OUI; + + /// 5-bit model number of the phy. This plus the OUI is used to verify that the + /// chip in hardware matches what's expected. + uint8_t model; + + /// MDIO address of the phy chip. + /// NOTE: 0 is *supposed* to be reserved as the general call address but lots of phy chips use + /// it anyway. + uint8_t address; + + /// Time to hold reset low on this phy + std::chrono::microseconds resetLowTime = std::chrono::microseconds(100); + + /// Time to wait after resetting the phy before trying to talk to it. + /// Also used as the time to wait for power on reset if there is no reset pin. + /// Note that standards compliant PHYs must reset in <500ms. + std::chrono::microseconds resetHighTime = std::chrono::milliseconds(500); + + /// Whether autonegotiation shall be enabled on the phy. + /// NOTE: If this is set to false, the other end of the connection MUST be manually configured to match. + /// Otherwise you will get sporadic data loss due to an Ethernet duplex mismatch! + /// However, setting this to false will make the Ethernet link come up much faster (milliseconds instead of seconds, at least if you don't do DHCP) + bool autonegEnabled = true; + + /// Whether the PHY should advertise full duplex modes + bool advertiseFullDuplex = true; + + /// Whether the PHY should advertise half duplex modes. + /// Half duplex allows running only over 1 or 2 twisted pairs, but introduces the possibility of collisions. + bool advertiseHalfDuplex = true; + + /// Whether the PHY should advertise 100Mbit modes + bool advertise100M = true; + + /// Whether the PHY should advertise 10Mbit modes. + /// 10Mbit can be a fallback if signal conditions are poor, but this fallback may not be desired. + bool advertise10M = true; + + /// If autonegEnabled is false, this gives the fixed link settings to advertise. + std::pair fixedEthSettings = {CompositeEMAC::LinkSpeed::LINK_100MBIT, CompositeEMAC::Duplex::FULL}; + }; + +protected: + + Config const & config; + + std::optional resetDigitalOut; + +public: + GenericEthPhy(Config const & config): + config(config) + {} + + CompositeEMAC::ErrCode init() override; + + CompositeEMAC::ErrCode checkLinkStatus(bool &status) override; + + CompositeEMAC::ErrCode checkLinkType(CompositeEMAC::LinkSpeed &speed, CompositeEMAC::Duplex &duplex) override; +}; + +}; + +#endif //MBED_OS_GENERICETHPHY_H diff --git a/connectivity/drivers/emac/sources/CompositeEMAC.cpp b/connectivity/drivers/emac/sources/CompositeEMAC.cpp new file mode 100644 index 00000000000..ac723d04660 --- /dev/null +++ b/connectivity/drivers/emac/sources/CompositeEMAC.cpp @@ -0,0 +1,394 @@ +/* Copyright (c) 2024 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "CompositeEMAC.h" + +#include +#include +#include + +#include + +#define TRACE_GROUP "CEMAC" + +// Flags for the MAC thread +static uint32_t THREAD_FLAG_TX_DESC_AVAILABLE = 1 << 0; +static uint32_t THREAD_FLAG_RX_DESC_AVAILABLE = 1 << 1; +static uint32_t THREAD_FLAG_RX_MEM_AVAILABLE = 1 << 2; +static uint32_t THREAD_FLAG_SHUTDOWN = 1 << 3; + +namespace mbed { + // Defined in PhyDrivers.cpp + CompositeEMAC::PHYDriver * get_eth_phy_driver(); + + void CompositeEMAC::rxISR() { + // Note: Not locking mutex here as this is an ISR and should be able to run while the MAC thread is executing. + if(rxDMA.rxHasPackets_ISR()) { + // Reclaimable descriptor or complete packet detected. + macThread->flags_set(THREAD_FLAG_RX_DESC_AVAILABLE); + } + } + + void CompositeEMAC::txISR() { + // Reclaimable Tx descriptor detected + macThread->flags_set(THREAD_FLAG_TX_DESC_AVAILABLE); + } + + void CompositeEMAC::phyTask() { + rtos::ScopedMutexLock lock(macOpsMutex); + + // If the MAC has been powered off, bail immediately (this event is about to be canceled) + if(state == PowerState::OFF) { + return; + } + + bool phyLinkState = false; + if(phy->checkLinkStatus(phyLinkState) != ErrCode::SUCCESS) { + tr_error("phyTask(): Phy failed to check link status"); + } + + if(linkState == LinkState::UP) { + if(!phyLinkState) { + tr_info("Link down"); + linkState = LinkState::DOWN; + + if(mac.disable() != ErrCode::SUCCESS) { + tr_error("phyTask(): Mac failed to disable"); + } + + linkStateCallback(false); + } + } + else { // LinkState::DOWN + if(phyLinkState) { + Duplex duplex; + LinkSpeed speed; + if(phy->checkLinkType(speed, duplex)!= ErrCode::SUCCESS) { + tr_error("phyTask(): Phy failed to check link type"); + return; + } + + char const * speedStr; + if(speed == LinkSpeed::LINK_10MBIT) { + speedStr = "10Mbps"; + } + else if(speed == LinkSpeed::LINK_100MBIT) { + speedStr = "100Mbps"; + } + else { + speedStr = "1Gbps"; + } + + tr_info("Link up at %s %s duplex", speedStr, duplex == Duplex::FULL ? "full" : "half"); + + linkState = LinkState::UP; + if(mac.enable(speed, duplex) != ErrCode::SUCCESS) { + tr_error("phyTask(): Mac failed to enable"); + } + + linkStateCallback(true); + } + } + } + + void CompositeEMAC::macTask() { + while(true) + { + // Wait for something to happen + uint32_t flags = rtos::ThisThread::flags_wait_any(THREAD_FLAG_TX_DESC_AVAILABLE | THREAD_FLAG_SHUTDOWN | THREAD_FLAG_RX_DESC_AVAILABLE | THREAD_FLAG_RX_MEM_AVAILABLE); + if(flags & THREAD_FLAG_SHUTDOWN) + { + return; + } + + // Now lock the mutex for the other cases + rtos::ScopedMutexLock lock(macOpsMutex); + + if(flags & THREAD_FLAG_RX_DESC_AVAILABLE) + { + // Receive any available packets. + // Note that if the ISR was delayed, we might get multiple packets per ISR, so we need to loop. + while(true) + { + auto * packet = rxDMA.dequeuePacket(); + if(!packet) { + break; + } + + linkInputCallback(packet); + + // Rebuild descriptors if possible + rxDMA.rebuildDescriptors(); + } + } + if(flags & THREAD_FLAG_TX_DESC_AVAILABLE) + { + txDMA.reclaimTxDescs(); + } + if(flags & THREAD_FLAG_RX_MEM_AVAILABLE) { + rxDMA.rebuildDescriptors(); + } + } + } + + void CompositeEMAC::onRxPoolSpaceAvail() { + rtos::ScopedMutexLock lock(macOpsMutex); + + if(state == PowerState::OFF) { + // MAC is off, not interested in callbacks + return; + } + + macThread->flags_set(THREAD_FLAG_RX_MEM_AVAILABLE); + } + + void CompositeEMAC::get_ifname(char *name, uint8_t size) const { + // Note that LwIP only supports a two character interface name prefix. + // So, no point in going longer than that. + // Also note that we don't want to copy the terminating null if it doesn't fit. + const char * const ifPrefix = "en"; + memcpy(name, ifPrefix, (size < strlen(ifPrefix) + 1) ? size : strlen(ifPrefix) + 1); + } + + void CompositeEMAC::set_hwaddr(const uint8_t *addr) { + rtos::ScopedMutexLock lock(macOpsMutex); + + if(state != PowerState::ON_NO_LINK) { + tr_err("MAC address can only be set after power up, before link up!"); + return; + } + + MACAddress macAddr; + memcpy(macAddr.data(), addr, MAC_ADDR_SIZE); + mac.setOwnMACAddr(macAddr); + } + + bool CompositeEMAC::link_out(emac_mem_buf_t *buf) + { + rtos::ScopedMutexLock lock(macOpsMutex); + const auto ret = txDMA.txPacket(buf); + + if(ret != ErrCode::SUCCESS) { + tr_warn("link_out(): Tx failed."); + } + return ret == ErrCode::SUCCESS; + } + + bool CompositeEMAC::power_up() + { + rtos::ScopedMutexLock lock(macOpsMutex); + + if(state != PowerState::OFF) { + tr_err("power_up(): Already powered up!"); + return false; + } + + // Get phy + phy = get_eth_phy_driver(); + if(phy == nullptr) { + tr_err("power_up(): No Ethernet PHY driver configured! Either set nsapi.emac-phy-model or override mbed::get_eth_phy_driver()."); + return false; + } + + // Set memory manager everywhere + if(memory_manager == nullptr) { + tr_err("power_up(): Memory manager not set yet!"); + return false; + } + txDMA.setMemoryManager(memory_manager); + rxDMA.setMemoryManager(memory_manager); + + // Register memory available callback + memory_manager->set_on_pool_space_avail_cb(callback(this, &CompositeEMAC::onRxPoolSpaceAvail)); + + // Power up the MAC + if(mac.init() != ErrCode::SUCCESS) { + tr_err("power_up(): Failed to init MAC!"); + return false; + } + + // Init DMA rings + if(txDMA.init() != ErrCode::SUCCESS || rxDMA.init() != ErrCode::SUCCESS) { + tr_err("power_up(): Failed to init DMA!"); + return false; + } + + // Initialize the PHY + phy->setMAC(&mac); + if(phy->init() != ErrCode::SUCCESS) { + tr_err("power_up(): Failed to init PHY!"); + return false; + } + + state = PowerState::ON_NO_LINK; + + // Start phy task + phyTaskHandle = mbed_event_queue()->call_every(std::chrono::milliseconds(MBED_CONF_NSAPI_EMAC_PHY_POLL_PERIOD), + callback(this, &CompositeEMAC::phyTask)); + + // Start MAC thread. + // We want to run this thread at high priority since reclaiming descriptors generally needs to happen quickly + // for the application to use the network at full speed. + macThread = new rtos::Thread(osPriorityHigh, 2048, nullptr, "EMAC Thread"); + macThread->start(callback(this, &CompositeEMAC::macTask)); + + return true; + } + + void CompositeEMAC::power_down() { + // Stop MAC thread (don't need to lock mutex for this) + macThread->flags_set(THREAD_FLAG_SHUTDOWN); + macThread->join(); + delete macThread; + + rtos::ScopedMutexLock lock(macOpsMutex); + + mbed_event_queue()->cancel(phyTaskHandle); + + state = PowerState::OFF; + linkState = LinkState::DOWN; + + // Clear multicast filter, so that we start with a clean slate next time + if(mac.clearMcastFilter() != ErrCode::SUCCESS) { + tr_err("power_down(): Failed to clear mcast filter"); + return; + } + + // Disable tx & rx + if(mac.disable() != ErrCode::SUCCESS) { + tr_err("power_down(): Failed to disable MAC"); + return; + } + + // Disable DMA + if(txDMA.deinit() != ErrCode::SUCCESS || rxDMA.deinit() != ErrCode::SUCCESS) { + tr_err("power_down(): Failed to disable DMA"); + return; + } + + // Finally, disable the MAC itself + if(mac.deinit() != ErrCode::SUCCESS) { + tr_err("power_down(): Failed to disable MAC"); + } + } + + void CompositeEMAC::set_link_input_cb(emac_link_input_cb_t input_cb) { + if(state != PowerState::OFF) { + tr_err("Not available while MAC is on!"); + return; + } + linkInputCallback = input_cb; + } + + void CompositeEMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) { + if(state != PowerState::OFF) { + tr_err("Not available while MAC is on!"); + return; + } + linkStateCallback = state_cb; + } + + void CompositeEMAC::add_multicast_group(const uint8_t *address) + { + rtos::ScopedMutexLock lock(macOpsMutex); + + if(state == PowerState::OFF) { + tr_err("Not available while MAC is off!"); + return; + } + + ++numSubscribedMcastMacs; + + if(numSubscribedMcastMacs >= MBED_CONF_NSAPI_EMAC_MAX_MCAST_SUBSCRIBES) + { + tr_warn("Out of multicast group entries (currently have %d). Increase the 'nsapi.emac-max-mcast-subscribes' JSON option!", MBED_CONF_NSAPI_EMAC_MAX_MCAST_SUBSCRIBES); + // Fall back to accepting all multicasts + set_all_multicast(true); + return; + } + + memcpy(mcastMacs[numSubscribedMcastMacs - 1].data(), address, 6); + + if(mac.addMcastMAC(mcastMacs[numSubscribedMcastMacs - 1]) != ErrCode::SUCCESS) { + tr_err("addMcastMAC() failed!"); + } + } + + void CompositeEMAC::remove_multicast_group(const uint8_t *address) { + rtos::ScopedMutexLock lock(macOpsMutex); + + if(state == PowerState::OFF) { + tr_err("Not available while MAC is off!"); + return; + } + + if(numSubscribedMcastMacs >= MBED_CONF_NSAPI_EMAC_MAX_MCAST_SUBSCRIBES) { + // We are in fallback mode, so we can no longer unsusbscribe at the MAC level because we don't know + // which MACs are subscribed anymore. + return; + } + + // Find MAC address in the subscription list + auto macsEndIter = std::begin(mcastMacs) + numSubscribedMcastMacs; + auto toRemoveIter = std::find_if(std::begin(mcastMacs), macsEndIter, [&](auto element) { + return memcmp(element.data(), address, 6) == 0; + }); + + if(toRemoveIter == macsEndIter) + { + tr_warning("Tried to remove mcast group that was not added"); + return; + } + + // Swap the MAC addr to be removed to the end of the list, if it is not there already + auto lastElementIter = macsEndIter - 1; + if(toRemoveIter != std::begin(mcastMacs) && toRemoveIter != lastElementIter) + { + std::swap(*toRemoveIter, *lastElementIter); + } + + // 'remove' the last element by changing the length + numSubscribedMcastMacs--; + + // Clear the filter and re-add all the addresses except the desired one + if(mac.clearMcastFilter() != ErrCode::SUCCESS) { + tr_err("clearMcastFilter() failed!"); + return; + } + for(size_t macIdx = 0; macIdx < numSubscribedMcastMacs; ++macIdx) { + if(mac.addMcastMAC(mcastMacs[macIdx]) != ErrCode::SUCCESS) { + tr_err("addMcastMAC() failed!"); + } + } + } + + void CompositeEMAC::set_all_multicast(bool all) { + rtos::ScopedMutexLock lock(macOpsMutex); + + if(state == PowerState::OFF) { + tr_err("Not available while MAC is off!"); + return; + } + + if(numSubscribedMcastMacs >= MBED_CONF_NSAPI_EMAC_MAX_MCAST_SUBSCRIBES && !all) { + // Don't allow setting pass all multicast to off while we are in fallback mode + return; + } + + mac.setPassAllMcast(all); + } +} \ No newline at end of file diff --git a/connectivity/drivers/emac/sources/GenericEthPhy.cpp b/connectivity/drivers/emac/sources/GenericEthPhy.cpp new file mode 100644 index 00000000000..b1873e0be13 --- /dev/null +++ b/connectivity/drivers/emac/sources/GenericEthPhy.cpp @@ -0,0 +1,194 @@ +/* Copyright (c) 2025 Jamie Smith +* SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "GenericEthPhy.h" +#include "CompositeEMAC.h" + +#include +#include +#include +#include + +#define TRACE_GROUP "GEPHY" + +namespace mbed { + +using namespace std::chrono_literals; + +#define FORWARD_ERR(call) {auto const err_code = call; if(err_code != CompositeEMAC::ErrCode::SUCCESS) { return err_code; }} + +CompositeEMAC::ErrCode GenericEthPhy::init() { + + // If we have a hardware reset pin, reset the PHY in hardware + if(mac->getPhyResetPin() != NC) { + // Output low on the reset pin, then bring high and wait + resetDigitalOut.emplace(mac->getPhyResetPin(), 0); + wait_us(config.resetLowTime); + resetDigitalOut->write(1); + } + + // Wait for the reset time to expire. Even if we didn't just actuate the hardware reset line, + // this is important because some PHYs need a long power on reset time, and the board may have + // just powered on. + wait_us(config.resetHighTime); + + // Try and detect the phy. + // ID1 should be the upper 18 MSBits of the OUI, with the two MSBits chopped off. + const uint16_t expectedID1 = config.OUI >> 6; + // Bits 10-15 of ID2 are the 6 LSBits of the OUI. Bits 4-9 are the model number. Bits 0-3 are the revision and may be anything. + const uint16_t expectedID2 = (config.OUI << 10) | (config.model << 4); + const uint16_t expectedID2Mask = 0xFFF0; + + // Read IDs + uint16_t actualID1; + uint16_t actualID2; + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::PHYIDR1, actualID1)); + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::PHYIDR2, actualID2)); + + if(actualID1 == expectedID1 && (actualID2 & expectedID2Mask) == expectedID2) { + // OK + tr_info("Detected ethernet PHY at MDIO addr %" PRIu8 " with OUI 0x%" PRIx32 ", model 0x%" PRIx8 ", and revision number %" PRIu8, config.address, config.OUI, config.model, actualID2 % 0xF); + } + else if(actualID1 == std::numeric_limits::max() && actualID2 == std::numeric_limits::max()) { + tr_error("Got all 0xFFs when reading Ethernet PHY. Since MDIO is an open drain bus, this means the phy is not connected or not responding."); + return CompositeEMAC::ErrCode::PHY_NOT_RESPONDING; + } + else { + tr_error("Ethernet phy model number verification mismatch. Expected PHYIDR1 = %" PRIu16 ", PHYIDR2 = %" PRIu16 ", got PHYIDR1 = %" PRIu16 ", PHYIDR2 = %" PRIu16 " [note: bottom 4 bits of PHYIDR2 ignored]", expectedID1, expectedID2, actualID1, actualID2); + return CompositeEMAC::ErrCode::PHY_NOT_RESPONDING; + } + + // Software reset, if we couldn't use the hardware reset line earlier + if(mac->getPhyResetPin() == NC) { + uint16_t bmcrVal; + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::BMCR, bmcrVal)); + FORWARD_ERR(mac->mdioWrite(config.address, GenPhyRegs::BMCR, bmcrVal | GenPhyRegs::BMCR_SW_RST_Msk)); + + // Wait for SW reset bit to clear + Timer timer; + timer.start(); + do { + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::BMCR, bmcrVal)); + rtos::ThisThread::sleep_for(1ms); + } + while(timer.elapsed_time() < config.resetHighTime && (bmcrVal & GenPhyRegs::BMCR_SW_RST_Msk)); + + // If the reset bit has not cleared yet, we have hit a timeout. Check one more time to avoid race condition. + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::BMCR, bmcrVal)); + if(bmcrVal & GenPhyRegs::BMCR_SW_RST_Msk) { + return CompositeEMAC::ErrCode::TIMEOUT; + } + } + + // If using autonegotiation, program ANAR and then restart autonegotiation + if(config.autonegEnabled) { + uint16_t anarVal = GenPhyRegs::ANAR_PROTOCOL_IEE_802_3U_Val; + if(config.advertise100M && config.advertiseFullDuplex) { + anarVal |= GenPhyRegs::ANAR_100BTX_FD_Msk; + } + if(config.advertise100M && config.advertiseHalfDuplex) { + anarVal |= GenPhyRegs::ANAR_100BTX_Msk; + } + if(config.advertise10M && config.advertiseFullDuplex) { + anarVal |= GenPhyRegs::ANAR_10BT_FD_Msk; + } + if(config.advertise10M && config.advertiseHalfDuplex) { + anarVal |= GenPhyRegs::ANAR_10BT_Msk; + } + FORWARD_ERR(mac->mdioWrite(config.address, GenPhyRegs::ANAR, anarVal)); + + // Now restart and enable autoneg + uint16_t bmcrVal; + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::BMCR, bmcrVal)); + bmcrVal |= GenPhyRegs::BMCR_ANEG_EN_Msk | GenPhyRegs::BMCR_ANEG_RESTART_Msk; + FORWARD_ERR(mac->mdioWrite(config.address, GenPhyRegs::BMCR, bmcrVal)); + } + else { + // Set fixed speed and duplex + uint16_t bmcrVal; + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::BMCR, bmcrVal)); + + // Disable autonegotiation + bmcrVal &= ~GenPhyRegs::BMCR_ANEG_EN_Msk; + + if(config.fixedEthSettings.first == CompositeEMAC::LinkSpeed::LINK_100MBIT) { + bmcrVal |= GenPhyRegs::BMCR_SPEED_100M_Msk; + } + else { // 10Mbit. TODO handle 1Gbit + bmcrVal &= ~GenPhyRegs::BMCR_SPEED_100M_Msk; + } + if(config.fixedEthSettings.second == CompositeEMAC::Duplex::FULL) { + bmcrVal |= GenPhyRegs::BMCR_DUPLEX_FULL_Msk; + } + else { // half duplex + bmcrVal &= ~GenPhyRegs::BMCR_DUPLEX_FULL_Msk; + } + FORWARD_ERR(mac->mdioWrite(config.address, GenPhyRegs::BMCR, bmcrVal)); + } + + return CompositeEMAC::ErrCode::SUCCESS; +} + +CompositeEMAC::ErrCode GenericEthPhy::checkLinkStatus(bool &status) { + // Note: PHYs latch the link state bit as low, so if the link has ever gone down here since the + // last poll, we will read 0 for the link status. + uint16_t bmsrVal; + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::BMSR, bmsrVal)); + status = bmsrVal & GenPhyRegs::BMCR_LINK_UP_Msk; + + return CompositeEMAC::ErrCode::SUCCESS; +} + +CompositeEMAC::ErrCode GenericEthPhy::checkLinkType(CompositeEMAC::LinkSpeed &speed, CompositeEMAC::Duplex &duplex) { + + if(config.autonegEnabled) { + // What a lot of people don't know is, you can actually get the link type of a phy just by reading its + // ANLPAR register! You don't need to read implementation specific registers. + // I got this trick from the Linux kernel: https://github.com/torvalds/linux/blob/d79bc8f79baacdd2549ec4af6d963ce3e69d7330/drivers/net/phy/phy-core.c#L475 + uint16_t anlparVal; + FORWARD_ERR(mac->mdioRead(config.address, GenPhyRegs::ANLPAR, anlparVal)); + + // Check settings in order of priority. This mirrors the logic done inside the PHY to determine the + // negotiated link type. + if((anlparVal & GenPhyRegs::ANAR_100BTX_FD_Msk) && config.advertise100M && config.advertiseFullDuplex) { + speed = CompositeEMAC::LinkSpeed::LINK_100MBIT; + duplex = CompositeEMAC::Duplex::FULL; + } + else if((anlparVal & GenPhyRegs::ANAR_100BTX_Msk) && config.advertise100M && config.advertiseHalfDuplex) { + speed = CompositeEMAC::LinkSpeed::LINK_100MBIT; + duplex = CompositeEMAC::Duplex::HALF; + } + else if((anlparVal & GenPhyRegs::ANAR_10BT_FD_Msk) && config.advertise10M && config.advertiseFullDuplex) { + speed = CompositeEMAC::LinkSpeed::LINK_10MBIT; + duplex = CompositeEMAC::Duplex::FULL; + } + else if((anlparVal & GenPhyRegs::ANAR_10BT_Msk) && config.advertise10M && config.advertiseHalfDuplex) { + speed = CompositeEMAC::LinkSpeed::LINK_10MBIT; + duplex = CompositeEMAC::Duplex::HALF; + } + else { + // No matching duplex settings + return CompositeEMAC::ErrCode::NEGOTIATION_FAILED; + } + } + else { + // Use configured setting + speed = config.fixedEthSettings.first; + duplex = config.fixedEthSettings.second; + } + return CompositeEMAC::ErrCode::SUCCESS; +} +} diff --git a/connectivity/drivers/emac/sources/PhyDrivers.cpp b/connectivity/drivers/emac/sources/PhyDrivers.cpp new file mode 100644 index 00000000000..75bc001b62f --- /dev/null +++ b/connectivity/drivers/emac/sources/PhyDrivers.cpp @@ -0,0 +1,70 @@ +/* Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "GenericEthPhy.h" + +namespace mbed { + +using namespace std::chrono_literals; + +namespace LAN8742 { + +/// Driver for the Microchip LAN8742 PHY +/// Datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/DS_LAN8742_00001989A.pdf +/// @{ + +inline constexpr GenericEthPhy::Config DefaultConfig = { + .OUI = 0x1F0, + .model = 0x13, + .address = 0, // Address set via PHYAD[0] strap. +}; + +class Driver : public GenericEthPhy { +public: + explicit Driver(GenericEthPhy::Config const & config = DefaultConfig): + GenericEthPhy(config) + {} +}; + + +/// @} + +} + +/** + * @brief Obtains the PHY driver for Ethernet port 0. + * + * The default implementation constructs a built-in driver (given by \c nsapi.emac-phy-model ) using the + * configured MDIO address ( \c nsapi.emac-phy-mdio-address ). However, it can be overridden by the + * application if it wishes to use another phy driver class! + * + * @return Phy driver class instance, or nullptr if none is configured. + */ +MBED_WEAK CompositeEMAC::PHYDriver * get_eth_phy_driver() +{ +#ifdef MBED_CONF_NSAPI_EMAC_PHY_MODEL + static GenericEthPhy::Config driverConfig = MBED_CONF_NSAPI_EMAC_PHY_MODEL::DefaultConfig; +#ifdef MBED_CONF_NSAPI_EMAC_PHY_MDIO_ADDRESS + driverConfig.address = MBED_CONF_NSAPI_EMAC_PHY_MDIO_ADDRESS; +#endif + static MBED_CONF_NSAPI_EMAC_PHY_MODEL::Driver driver(driverConfig); + return &driver; +#else + return nullptr; +#endif +}; + +} \ No newline at end of file diff --git a/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h b/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h index 64f4f4eddd3..5e38a4320b9 100644 --- a/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h +++ b/connectivity/lwipstack/include/lwipstack/LWIPMemoryManager.h @@ -31,8 +31,6 @@ class LWIPMemoryManager final : public EMACMemoryManager { uint32_t get_pool_alloc_unit(uint32_t align) const override; - uint32_t get_pool_size() const override; - void free(net_stack_mem_buf_t *buf) override; uint32_t get_total_len(const net_stack_mem_buf_t *buf) const override; diff --git a/connectivity/lwipstack/mbed_lib.json5 b/connectivity/lwipstack/mbed_lib.json5 index 5ea4a99ec98..0de4f1750a2 100644 --- a/connectivity/lwipstack/mbed_lib.json5 +++ b/connectivity/lwipstack/mbed_lib.json5 @@ -207,6 +207,10 @@ }, "MTS_DRAGONFLY_F411RE": { "tcpip-thread-stacksize": 1600 + }, + "STM32H7": { + // On STM32H7, we have lots of RAM, so we can make the pool size relatively large + "pbuf-pool-size": 16, } } } diff --git a/connectivity/lwipstack/source/LWIPMemoryManager.cpp b/connectivity/lwipstack/source/LWIPMemoryManager.cpp index ede74916329..054b84b4d21 100644 --- a/connectivity/lwipstack/source/LWIPMemoryManager.cpp +++ b/connectivity/lwipstack/source/LWIPMemoryManager.cpp @@ -51,11 +51,6 @@ uint32_t LWIPMemoryManager::get_pool_alloc_unit(uint32_t align) const return alloc_unit; } -uint32_t LWIPMemoryManager::get_pool_size() const -{ - return PBUF_POOL_SIZE; -} - void LWIPMemoryManager::free(net_stack_mem_buf_t *buf) { pbuf_free(static_cast(buf)); diff --git a/connectivity/nanostack/mbed-mesh-api/mbed_lib.json b/connectivity/nanostack/mbed-mesh-api/mbed_lib.json index 59db804a0c1..e053940ec26 100644 --- a/connectivity/nanostack/mbed-mesh-api/mbed_lib.json +++ b/connectivity/nanostack/mbed-mesh-api/mbed_lib.json @@ -236,6 +236,14 @@ "radius-retry-count": { "help": "RADIUS retry trickle count; default 3", "value": 3 + }, + "emac-rx-pool-size": { + "help": "Number of Rx buffers that will allocated to the EMAC receive buffer pool when using an Ethernet MAC interface", + "value": 5 + }, + "emac-rx-pool-bufsize": { + "help": "Size of each buffer in the EMAC receive pool.", + "value": 512 } }, "target_overrides": { diff --git a/connectivity/nanostack/mbed-mesh-api/source/NanostackMemoryManager.cpp b/connectivity/nanostack/mbed-mesh-api/source/NanostackMemoryManager.cpp index 1e2a71fe435..dcb93b1cbe1 100644 --- a/connectivity/nanostack/mbed-mesh-api/source/NanostackMemoryManager.cpp +++ b/connectivity/nanostack/mbed-mesh-api/source/NanostackMemoryManager.cpp @@ -65,11 +65,6 @@ uint32_t NanostackMemoryManager::get_pool_alloc_unit(uint32_t align) const return MBED_CONF_NSAPI_EMAC_RX_POOL_BUF_SIZE; } -uint32_t NanostackMemoryManager::get_pool_size() const -{ - return MBED_CONF_NSAPI_EMAC_RX_POOL_NUM_BUFS; -} - void NanostackMemoryManager::free(emac_mem_buf_t *mem) { ns_dyn_mem_free(mem); diff --git a/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h b/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h index cd426b50909..1589e166f3e 100644 --- a/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h +++ b/connectivity/nanostack/mbed-mesh-api/source/include/NanostackMemoryManager.h @@ -35,8 +35,6 @@ class NanostackMemoryManager final : public EMACMemoryManager { uint32_t get_pool_alloc_unit(uint32_t align) const override; - uint32_t get_pool_size() const override; - void free(emac_mem_buf_t *buf) override; uint32_t get_total_len(const emac_mem_buf_t *buf) const override; diff --git a/connectivity/netsocket/CMakeLists.txt b/connectivity/netsocket/CMakeLists.txt index 0069c22d4a5..ae2a36b741e 100644 --- a/connectivity/netsocket/CMakeLists.txt +++ b/connectivity/netsocket/CMakeLists.txt @@ -90,7 +90,9 @@ if("DEVICE_EMAC=1" IN_LIST MBED_TARGET_DEFINITIONS) ) endif() -add_library(mbed-netsocket INTERFACE) +add_library(mbed-netsocket INTERFACE + tests/TESTS/common/greentea_network_stack_nanostack.cpp + tests/TESTS/common/greentea_network_stack_lwipstack.cpp) target_link_libraries(mbed-netsocket INTERFACE diff --git a/connectivity/netsocket/include/netsocket/EMAC.h b/connectivity/netsocket/include/netsocket/EMAC.h index 9adf83143d1..4bd384aa320 100644 --- a/connectivity/netsocket/include/netsocket/EMAC.h +++ b/connectivity/netsocket/include/netsocket/EMAC.h @@ -118,10 +118,10 @@ class EMAC { /** * Sends the packet over the link * - * That can not be called from an interrupt context. + * Will not be called from an interrupt context. * - * @param buf Packet to be send - * @return True if the packet was send successfully, False otherwise + * @param buf Packet to be sent. This packet is now owned by the MAC and must be freed in all cases. + * @return True if the packet was sent successfully, False otherwise */ virtual bool link_out(emac_mem_buf_t *buf) = 0; @@ -139,16 +139,24 @@ class EMAC { virtual void power_down() = 0; /** - * Sets a callback that needs to be called for packets received for that interface + * Sets a callback that needs to be called for packets received for this interface. * - * @param input_cb Function to be register as a callback + * Note that the callback function will contain appropriate locking such that it may be called from any OS thread. + * However, it shall not be called from an interrupt. + * + * Also note that the callback will take ownership of the passed packet and must free it in all cases. + * + * @param input_cb Function to be registered as a callback */ virtual void set_link_input_cb(emac_link_input_cb_t input_cb) = 0; /** * Sets a callback that needs to be called on link status changes for given interface * - * @param state_cb Function to be register as a callback + * Note that the callback function will contain appropriate locking such that it may be called from any OS thread. + * However, it shall not be called from an interrupt. + * + * @param state_cb Function to be registered as a callback */ virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb) = 0; @@ -184,11 +192,4 @@ class EMAC { virtual void set_memory_manager(EMACMemoryManager &mem_mngr) = 0; }; - -/** These need to be defined by targets wishing to provide an Ethernet driver using EMAC interface. It will - * be used by the EMACInterface class's default constructor to initialize the networking subsystem. - */ -//extern const emac_interface_ops_t mbed_emac_eth_ops_default; -//extern void *mbed_emac_eth_hw_default; - #endif /* EMAC_H */ diff --git a/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h b/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h index c58397b736f..cc04f15976e 100644 --- a/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h +++ b/connectivity/netsocket/include/netsocket/NetStackMemoryManager.h @@ -100,9 +100,16 @@ class NetStackMemoryManager { /** * Get memory buffer pool size. * - * @return The maximum size of contiguous memory that can be allocated from a pool. + * @return The number of pool buffers that can be allocated at any one time */ - virtual uint32_t get_pool_size() const = 0; + uint32_t get_pool_size() + { +#if UNITTEST + return 0; +#else + return MBED_CONF_NSAPI_EMAC_RX_POOL_NUM_BUFS; +#endif + } /** * Free memory buffer chain diff --git a/connectivity/netsocket/mbed_lib.json5 b/connectivity/netsocket/mbed_lib.json5 index 09041a195e8..3b1097f8ab9 100644 --- a/connectivity/netsocket/mbed_lib.json5 +++ b/connectivity/netsocket/mbed_lib.json5 @@ -83,13 +83,38 @@ "value": 592 // LwIP default value (assuming default TCP MSS) }, "emac-rx-pool-num-bufs": { - "help": "Number of buffers (of size netsocket.emac-rx-pool-buf-size) in the EMAC receive pool. This controls how much memory is preallocated for Ethernet reception. A larger number means that more Ethernet packets can be received per second without dropping any. Some EMACs need up to 4 extra buffers, so this should be set such that this value minus 4 times the buffer size is at least 1514 (so we can receive one full Ethernet frame).", + "help": "Number of buffers (of size netsocket.emac-rx-pool-buf-size) in the EMAC receive pool. This controls how much memory is preallocated for Ethernet reception. A larger number means that more Ethernet packets can be received per second without dropping any. Some EMACs need up to 4 extra buffers, so this should be set such that (this value minus 4) times the buffer size is at least 1514 (so we can receive one full Ethernet frame).", "value": 7 + }, + "emac-tx-num-descs": { + "help": "Number of Tx descriptors in the Ethernet MAC DMA ring. This affects how much data can be queued for Tx at one time", + "value": 8 + }, + "emac-max-mcast-subscribes": { + "help" : "Maximum supported number of multicast addresses that the application can subscribe to. If this limit is reached, we give up and enable all mcast groups.", + "value" : 8 + }, + "emac-phy-model": { + "help": "Model of the Ethernet PHY on the board. Should correspond to a driver defined in PhyDrivers.cpp", + "value": null + }, + "emac-phy-mdio-address": { + "help": "MDIO address of the phy chip. Usually set with strapping pins. NOTE: 0 is *supposed* to be reserved as the general call address but lots of phy chips use it anyway.", + "value": null + }, + "emac-phy-poll-period": { + "help": "How often (in ms) to poll the Ethernet PHY and check for link status changes.", + "value": 100 } }, "target_overrides": { "TB_SENSE_12": { "nsapi.default-mesh-type": "LOWPAN" + }, + "MCU_STM32": { + // First-party STM32 boards generally use a LAN8742 PHY at MDIO address 0 + "nsapi.emac-phy-model": "LAN8742", + "nsapi.emac-phy-mdio-address": 0 } } } diff --git a/connectivity/netsocket/tests/TESTS/CMakeLists.txt b/connectivity/netsocket/tests/TESTS/CMakeLists.txt index 1e8b234db06..6ab74e044ad 100644 --- a/connectivity/netsocket/tests/TESTS/CMakeLists.txt +++ b/connectivity/netsocket/tests/TESTS/CMakeLists.txt @@ -5,12 +5,6 @@ if(DEFAULT_IFC_IDX EQUAL -1) set(TEST_SKIPPED "No default network interface on this target") endif() -# TEMPORARY: netsocket tests will not compile on STM32H7 until new EMAC driver is merged because the old EMAC driver -# pulls in a dependency on lwip -if("TARGET_STM32H7" IN_LIST MBED_TARGET_DEFINITIONS) - set(TEST_SKIPPED "Will not compile on STM32H7") -endif() - add_subdirectory(common) # List of libraries for all netsocket tests to link. diff --git a/connectivity/netsocket/tests/TESTS/netsocket/tcp/tcpsocket_send_timeout.cpp b/connectivity/netsocket/tests/TESTS/netsocket/tcp/tcpsocket_send_timeout.cpp index 962ff316e7e..e7ecaae1c46 100644 --- a/connectivity/netsocket/tests/TESTS/netsocket/tcp/tcpsocket_send_timeout.cpp +++ b/connectivity/netsocket/tests/TESTS/netsocket/tcp/tcpsocket_send_timeout.cpp @@ -47,7 +47,7 @@ void TCPSOCKET_SEND_TIMEOUT() (timer.elapsed_time() <= 800ms)) { continue; } - tr_error("send: err %d, time %d", err, timer.read_ms()); + tr_error("send: err %d, time %" PRIi64, err, std::chrono::duration_cast(timer.elapsed_time()).count()); TEST_FAIL(); break; } diff --git a/connectivity/netsocket/tests/TESTS/netsocket/tls/tlssocket_recv_timeout.cpp b/connectivity/netsocket/tests/TESTS/netsocket/tls/tlssocket_recv_timeout.cpp index 222198acaa6..18f1b3572bf 100644 --- a/connectivity/netsocket/tests/TESTS/netsocket/tls/tlssocket_recv_timeout.cpp +++ b/connectivity/netsocket/tests/TESTS/netsocket/tls/tlssocket_recv_timeout.cpp @@ -69,7 +69,7 @@ void TLSSOCKET_RECV_TIMEOUT() TEST_FAIL(); goto CLEANUP; } - tr_info("MBED: recv() took: %dus\n", timer.read_us()); + tr_info("MBED: recv() took: %" PRIi64 "us\n", std::chrono::duration_cast(timer.elapsed_time()).count()); continue; } else if (recvd < 0) { tr_error("[pkt#%02d] network error %d\n", i, recvd); diff --git a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp index 5fe7b4535d1..1a271821067 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp +++ b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_initialize.cpp @@ -36,10 +36,6 @@ void test_emac_initialize() worker_loop_init(); mbed_trace_init(); - // Set memory manager parameters - EmacTestMemoryManager::get_instance().set_alloc_unit(256); // Use a relatively small allocation unit size so packets have to be split up into a lot of buffers - EmacTestMemoryManager::get_instance().set_pool_size(10); // Start with 10 buffers in the Rx pool. One max-len Eth packet uses 6 256-byte buffers, and some MACs need up to 4 extra ones. - static NetworkInterface *network_interface = get_network_interface(); // Power up the interface and emac driver @@ -48,4 +44,24 @@ void test_emac_initialize() worker_loop_link_up_wait(); } +/* + * Test which powers the EMAC down and then up again + */ +void test_emac_power_down_and_power_up() +{ + EmacTestNetworkStack::get_instance().get_emac()->power_down(); + + // Note: Currently the EMAC does not deliver a link state change to down callback when powered down. + // Might change that in the future but for now we need to deliver the callback manually. + emac_if_link_state_change_cb(false); + + TEST_ASSERT_TRUE(EmacTestNetworkStack::get_instance().get_emac()->power_up()); + + // Currently EMACs may expect set_hwaddr() to be called after power up as this API is not well defined. + EmacTestNetworkStack::get_instance().get_emac()->set_hwaddr(EmacTestNetworkStack::get_instance().get_mac_addr()); + + // Wait for link to come back up before continuing + worker_loop_link_up_wait(); +} + #endif // defined(MBED_CONF_RTOS_PRESENT) diff --git a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_memory.cpp b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_memory.cpp index e093b581e48..b6115392af9 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_memory.cpp +++ b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_memory.cpp @@ -30,7 +30,8 @@ using namespace utest::v1; void test_emac_memory_cb(int opt) { static bool send_request = true; - static bool echo_should_work = true; + static bool echo_may_fail = false; + static bool echo_may_succeed = true; static int no_response_cnt = 0; static int retries = 0; static int msg_len = 0; @@ -38,57 +39,93 @@ void test_emac_memory_cb(int opt) static bool next_step = true; static int options = CTP_OPT_NON_ALIGNED; + static int successful_pkts_this_step = 0; + static int failed_pkts_this_step = 0; + // Defines test step if (next_step) { next_step = false; + + // Verify that, if this was a test step where allocations were supposed to fail, they actually did fail. + // We can accept a couple of successful packets due to buffers that had been allocated earlier, but the + // *majority* of the packets should have failed. + if (test_step > 0 && !echo_may_succeed) { + if (successful_pkts_this_step >= failed_pkts_this_step) { + printf("Too many successful packets (%d) vs failed packets (%d). This was supposed to be a failure test!\r\n", + successful_pkts_this_step, failed_pkts_this_step); + SET_ERROR_FLAGS(TEST_FAILED); + END_TEST_LOOP; + } + } + successful_pkts_this_step = 0; + failed_pkts_this_step = 0; + switch (test_step) { case 0: printf("STEP 0: memory available\r\n\r\n"); emac_if_set_output_memory(true); emac_if_set_input_memory(true); - echo_should_work = true; + emac_if_check_memory(false); + echo_may_fail = false; + echo_may_succeed = true; break; case 1: printf("STEP 1: no input memory buffer memory available\r\n\r\n"); emac_if_set_output_memory(true); emac_if_set_input_memory(false); - echo_should_work = false; + emac_if_check_memory(false); + echo_may_fail = true; + echo_may_succeed = false; break; case 2: printf("STEP 2: memory available\r\n\r\n"); emac_if_set_output_memory(true); emac_if_set_input_memory(true); - echo_should_work = true; + emac_if_check_memory(false); + echo_may_fail = false; + echo_may_succeed = true; break; case 3: printf("STEP 3: no output memory buffer memory available\r\n\r\n"); emac_if_set_output_memory(false); emac_if_set_input_memory(true); - echo_should_work = false; + emac_if_check_memory(false); + + // For this test, zero-copy implementations can still successfully work because + // they don't need to allocate anything to send a packet. + // So we allow either success or failure. + echo_may_fail = true; + echo_may_succeed = true; break; case 4: printf("STEP 4: memory available\r\n\r\n"); emac_if_set_output_memory(true); emac_if_set_input_memory(true); - echo_should_work = true; + emac_if_check_memory(false); + echo_may_fail = false; + echo_may_succeed = true; break; case 5: printf("STEP 5: no output or input memory buffer memory available\r\n\r\n"); emac_if_set_output_memory(false); emac_if_set_input_memory(false); - echo_should_work = false; + emac_if_check_memory(false); + echo_may_fail = true; + echo_may_succeed = false; break; case 6: printf("STEP 6: memory available\r\n\r\n"); emac_if_set_output_memory(true); emac_if_set_input_memory(true); - echo_should_work = true; + emac_if_check_memory(false); + echo_may_fail = false; + echo_may_succeed = true; break; case 7: @@ -107,8 +144,9 @@ void test_emac_memory_cb(int opt) } else if (opt == TIMEOUT) { if (++no_response_cnt > 3) { if (++retries > 1) { + failed_pkts_this_step += 1; // If echo replies should be received fails the test case - if (echo_should_work) { + if (!echo_may_fail) { printf("too many retries\r\n\r\n"); SET_ERROR_FLAGS(TEST_FAILED); END_TEST_LOOP; @@ -124,6 +162,10 @@ void test_emac_memory_cb(int opt) } } + if (opt == INPUT) { + successful_pkts_this_step += 1; + } + // Echo response received or retry count exceeded for memory buffers are not available if (opt == INPUT || next_len) { if (msg_len == ETH_MAX_LEN) { diff --git a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_unicast.cpp b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_unicast.cpp index b78e609789d..a8f5cb9a877 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/emac_test_unicast.cpp +++ b/connectivity/netsocket/tests/TESTS/network/emac/emac_test_unicast.cpp @@ -27,13 +27,13 @@ using namespace utest::v1; +static bool send_request; +static int no_response_cnt; +static int retries; +static int test_step = 0; + void test_emac_unicast_cb(int opt) { - static bool send_request = true; - static int no_response_cnt = 0; - static int retries = 0; - static int test_step = 0; - // Timeout if (opt == TIMEOUT && send_request) { CTP_MSG_SEND(100, emac_if_get_echo_server_addr(0), emac_if_get_own_addr(), emac_if_get_own_addr(), 0); @@ -41,7 +41,7 @@ void test_emac_unicast_cb(int opt) no_response_cnt = 0; } else if (opt == TIMEOUT) { if (++no_response_cnt > 5) { - if (++retries > 3) { + if (++retries > 300) { printf("too many retries\r\n\r\n"); SET_ERROR_FLAGS(TEST_FAILED); END_TEST_LOOP; @@ -65,6 +65,12 @@ void test_emac_unicast_cb(int opt) void test_emac_unicast() { + // Reset flags + send_request = true; + no_response_cnt = 0; + retries = 0; + test_step = 0; + RESET_ALL_ERROR_FLAGS; SET_TRACE_LEVEL(TRACE_SEND | TRACE_ETH_FRAMES | TRACE_SUCCESS | TRACE_FAILURE); diff --git a/connectivity/netsocket/tests/TESTS/network/emac/emac_tests.h b/connectivity/netsocket/tests/TESTS/network/emac/emac_tests.h index 6dbcd340a32..900f406f5cf 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/emac_tests.h +++ b/connectivity/netsocket/tests/TESTS/network/emac/emac_tests.h @@ -19,6 +19,7 @@ #define EMAC_TESTS_H void test_emac_initialize(); +void test_emac_power_down_and_power_up(); void test_emac_broadcast(); void test_emac_unicast(); void test_emac_unicast_frame_len(); diff --git a/connectivity/netsocket/tests/TESTS/network/emac/main.cpp b/connectivity/netsocket/tests/TESTS/network/emac/main.cpp index b6bd7a5c3f2..6cea89d148b 100644 --- a/connectivity/netsocket/tests/TESTS/network/emac/main.cpp +++ b/connectivity/netsocket/tests/TESTS/network/emac/main.cpp @@ -55,7 +55,9 @@ Case cases[] = { (MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI)) Case("EMAC multicast filter", test_emac_multicast_filter), #endif // !(MBED_CONF_NETWORK_EMAC_NO_SUPPORT_FOR_MULTICAST_FILTER == 1) - Case("EMAC memory", test_emac_memory) + Case("EMAC memory", test_emac_memory), + Case("EMAC power down and power up", test_emac_power_down_and_power_up), + Case("EMAC unicast again after power cycle", test_emac_unicast), }; Specification specification(test_setup, cases); diff --git a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp index bdbc26ff29e..b75355c8cb2 100644 --- a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp +++ b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.cpp @@ -73,8 +73,8 @@ EmacTestMemoryManager::EmacTestMemoryManager() : m_mem_mutex(), m_mem_buffers(), m_alloc_unit(MBED_CONF_NSAPI_EMAC_RX_POOL_BUF_SIZE), - m_pool_size(MBED_CONF_NSAPI_EMAC_RX_POOL_NUM_BUFS), - m_memory_available(true) + m_memory_available(true), + m_pool_memory_available(true) { #ifdef ETHMEM_SECTION static bool ns_heap_init = false; @@ -172,7 +172,7 @@ emac_mem_buf_t *EmacTestMemoryManager::alloc_pool(uint32_t size, uint32_t align, check_align(align); - if ((opt & MEM_CHECK) && !m_memory_available) { + if ((opt & MEM_CHECK) && (!m_memory_available || !m_pool_memory_available)) { return NULL; } @@ -181,7 +181,7 @@ emac_mem_buf_t *EmacTestMemoryManager::alloc_pool(uint32_t size, uint32_t align, // Contiguous allocation if (size + align <= m_alloc_unit) { - if (m_pool_bufs_used > m_pool_size) { + if (m_pool_bufs_used > MBED_CONF_NSAPI_EMAC_RX_POOL_NUM_BUFS) { return nullptr; } @@ -214,7 +214,7 @@ emac_mem_buf_t *EmacTestMemoryManager::alloc_pool(uint32_t size, uint32_t align, size_left = 0; } - if (m_pool_bufs_used > m_pool_size) { + if (m_pool_bufs_used > MBED_CONF_NSAPI_EMAC_RX_POOL_NUM_BUFS) { // No simulated pool space left, free and return nullptr if (first_buf != nullptr) { free(first_buf); @@ -326,7 +326,7 @@ uint32_t EmacTestMemoryManager::get_total_len(const emac_mem_buf_t *buf) const validate_list(); if (!validate_ptr(buf)) { - CHECK_ASSERT(0, "get_total_len(): %p invalid buffer", buf); + CHECK_ASSERT(0, "get_total_len(): %p invalid buffer\n", buf); return 0; } @@ -344,17 +344,17 @@ void EmacTestMemoryManager::copy(emac_mem_buf_t *to_buf, const emac_mem_buf_t *f validate_list(); if (!validate_ptr(to_buf)) { - CHECK_ASSERT(0, "copy(): %p invalid to buffer", to_buf); + CHECK_ASSERT(0, "copy(): %p invalid to buffer\n", to_buf); return; } if (!validate_ptr(from_buf)) { - CHECK_ASSERT(0, "copy(): %p invalid from buffer", from_buf); + CHECK_ASSERT(0, "copy(): %p invalid from buffer\n", from_buf); return; } if (get_total_len(to_buf) != get_total_len(from_buf)) { - CHECK_ASSERT(0, "copy(): %p to and %p from buffer total lengths not same", to_buf, from_buf); + CHECK_ASSERT(0, "copy(): %p to and %p from buffer total lengths not same\n", to_buf, from_buf); return; } @@ -397,19 +397,19 @@ void EmacTestMemoryManager::cat(emac_mem_buf_t *to_buf, emac_mem_buf_t *cat_buf) validate_list(); if (!validate_ptr(to_buf)) { - CHECK_ASSERT(0, "cat(): %p invalid to buffer", to_buf); + CHECK_ASSERT(0, "cat(): %p invalid to buffer\n", to_buf); return; } if (!validate_ptr(cat_buf)) { - CHECK_ASSERT(0, "cat(): %p invalid cat buffer", cat_buf); + CHECK_ASSERT(0, "cat(): %p invalid cat buffer\n", cat_buf); return; } emac_memory_t *cat_mem_buf = static_cast(cat_buf); if (!cat_mem_buf->first) { - CHECK_ASSERT(0, "cat(): %p cat buffer does not point to head of chain", cat_buf); + CHECK_ASSERT(0, "cat(): %p cat buffer does not point to head of chain\n", cat_buf); return; } @@ -428,7 +428,7 @@ emac_mem_buf_t *EmacTestMemoryManager::get_next(const emac_mem_buf_t *buf) const validate_list(); if (!validate_ptr(buf)) { - CHECK_ASSERT(0, "get_next(): %p invalid buffer", buf); + CHECK_ASSERT(0, "get_next(): %p invalid buffer\n", buf); return NULL; } @@ -441,7 +441,7 @@ void *EmacTestMemoryManager::get_ptr(const emac_mem_buf_t *buf) const validate_list(); if (!validate_ptr(buf)) { - CHECK_ASSERT(0, "get_ptr(): %p invalid buffer", buf); + CHECK_ASSERT(0, "get_ptr(): %p invalid buffer\n", buf); return NULL; } @@ -454,7 +454,7 @@ uint32_t EmacTestMemoryManager::get_len(const emac_mem_buf_t *buf) const validate_list(); if (!validate_ptr(buf)) { - CHECK_ASSERT(0, "get_len(): %p invalid buffer", buf); + CHECK_ASSERT(0, "get_len(): %p invalid buffer\n", buf); return 0; } @@ -467,30 +467,25 @@ void EmacTestMemoryManager::set_len(emac_mem_buf_t *buf, uint32_t len) validate_list(); if (!validate_ptr(buf)) { - CHECK_ASSERT(0, "set_len(): %p invalid buffer", buf); + CHECK_ASSERT(0, "set_len(): %p invalid buffer\n", buf); return; } emac_memory_t *mem_buf = static_cast(buf); if (len > mem_buf->orig_len) { - CHECK_ASSERT(0, "set_len(): %p new length %i must be less or equal allocated size %i", buf, len, mem_buf->orig_len); + CHECK_ASSERT(0, "set_len(): %p new length %i must be less or equal allocated size %i\n", buf, len, mem_buf->orig_len); return; } if (!mem_buf->first) { - CHECK_ASSERT(0, "set_len(): %p buffer does not point to head of chain", buf); + CHECK_ASSERT(0, "set_len(): %p buffer does not point to head of chain\n", buf); return; } mem_buf->len = len; } -uint32_t EmacTestMemoryManager::get_pool_size() const -{ - return m_pool_size; -} - NetStackMemoryManager::Lifetime EmacTestMemoryManager::get_lifetime(const net_stack_mem_buf_t *buf) const { return static_cast(buf)->lifetime; @@ -503,11 +498,6 @@ void EmacTestMemoryManager::set_alloc_unit(uint32_t alloc_unit) m_alloc_unit = alloc_unit; } -void EmacTestMemoryManager::set_pool_size(size_t size) -{ - m_pool_size = size; -} - void EmacTestMemoryManager::set_memory_available(bool memory) { m_memory_available = memory; @@ -518,6 +508,16 @@ void EmacTestMemoryManager::set_memory_available(bool memory) } } +void EmacTestMemoryManager::set_pool_memory_available(bool memory) +{ + m_pool_memory_available = memory; + + // Poke the EMAC in case it can allocate buffers + if (m_pool_memory_available && m_memory_available && onPoolSpaceAvailCallback) { + onPoolSpaceAvailCallback(); + } +} + void EmacTestMemoryManager::get_memory_statistics(int *buffers, int *memory) { if (!buffers || !memory) { @@ -546,7 +546,7 @@ template void EmacTestMemoryManager::check_value(TYPE value, con va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); - assert(false); + MBED_ASSERT(false); va_end(ap); } } diff --git a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h index 741a1b3b7a6..70beb00c533 100644 --- a/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h +++ b/connectivity/netsocket/tests/emac_test_utils/EmacTestMemoryManager.h @@ -70,8 +70,6 @@ class EmacTestMemoryManager : public EMACMemoryManager { void set_len(emac_mem_buf_t *buf, uint32_t len) override; - uint32_t get_pool_size() const override; - Lifetime get_lifetime(const net_stack_mem_buf_t *buf) const override; /** @@ -110,23 +108,22 @@ class EmacTestMemoryManager : public EMACMemoryManager { virtual void set_alloc_unit(uint32_t alloc_unit); /** - * Sets memory buffer pool size + * Sets whether memory (heap or pool) is available * - * Sets the number of buffers that may be allocated from the pool. If the number of buffers currently - * in use is >= this number, new pool allocations will fail. + * Can be used to disable memory allocation request from emac. * - * @param size Pool size + * @param memory True if memory is available */ - virtual void set_pool_size(size_t size); + void set_memory_available(bool memory); /** - * Sets whether memory is available + * Sets whether pool memory is available. * - * Can be used to disable memory allocation request from emac. + * Can be used to disable memory allocation request for the pool from emac. * * @param memory True if memory is available */ - void set_memory_available(bool memory); + void set_pool_memory_available(bool memory); /** * Gets memory statistics @@ -146,9 +143,9 @@ class EmacTestMemoryManager : public EMACMemoryManager { mutable rtos::Mutex m_mem_mutex; std::list m_mem_buffers; unsigned int m_alloc_unit; - size_t m_pool_size; size_t m_pool_bufs_used = 0; bool m_memory_available; + bool m_pool_memory_available; }; #endif /* EMAC_TEST_MEMORY_MANAGER_H */ diff --git a/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp b/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp index 2b071471219..62a1ffe8c0c 100644 --- a/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp +++ b/connectivity/netsocket/tests/emac_test_utils/emac_util.cpp @@ -384,25 +384,15 @@ void emac_if_set_output_memory(bool memory) void emac_if_set_input_memory(bool memory) { allow_input_memory_allocs = memory; - - emac_if_set_memory(memory); + EmacTestMemoryManager::get_instance().set_pool_memory_available(allow_input_memory_allocs); } void emac_if_check_memory(bool output) { if (output) { - emac_if_set_memory(allow_output_memory_allocs); + EmacTestMemoryManager::get_instance().set_memory_available(allow_output_memory_allocs); } else { - emac_if_set_memory(allow_input_memory_allocs); - } -} - -void emac_if_set_memory(bool memory) -{ - static bool memory_value = true; - if (memory_value != memory) { - memory_value = memory; - EmacTestMemoryManager::get_instance().set_memory_available(memory); + EmacTestMemoryManager::get_instance().set_memory_available(allow_input_memory_allocs); } } diff --git a/connectivity/netsocket/tests/emac_test_utils/emac_util.h b/connectivity/netsocket/tests/emac_test_utils/emac_util.h index 82f0825fc76..21a88654fed 100644 --- a/connectivity/netsocket/tests/emac_test_utils/emac_util.h +++ b/connectivity/netsocket/tests/emac_test_utils/emac_util.h @@ -113,10 +113,17 @@ void emac_if_set_all_multicast(bool all); void emac_if_add_multicast_group(uint8_t *address); void emac_if_remove_multicast_group(uint8_t *address); +/// If called with false as the arg, disables memory allocation +/// (a) from the pool at all times, and +/// (b) from the heap when not actively transmitting a packet void emac_if_set_output_memory(bool memory); + +/// If called with true as the arg, disables memory allocation from the pool and heap during packet Tx. void emac_if_set_input_memory(bool memory); + +/// Switches between input (false) and output (true) mode for the memory allocation disable. +/// Called by the CTP code when it's sending a packet. void emac_if_check_memory(bool output); -void emac_if_set_memory(bool memory); void emac_if_set_ctp_server_enabled(bool enabled); diff --git a/platform/include/platform/mbed_wait_api.h b/platform/include/platform/mbed_wait_api.h index a6f85be326c..23a7fb1bbcb 100644 --- a/platform/include/platform/mbed_wait_api.h +++ b/platform/include/platform/mbed_wait_api.h @@ -150,6 +150,24 @@ inline void _wait_us_inline(unsigned int us) } #endif +#ifdef __cplusplus +#include + +// Override of wait_us() allowing a std::chrono type convertible to microseconds to be passed in. +#if defined US_TICKER_PERIOD_NUM +static inline void _wait_us_inline(std::chrono::microseconds const us) +{ + _wait_us_inline(us.count()); +} +#else +static inline void wait_us(std::chrono::microseconds const us) +{ + wait_us(us.count()); +} +#endif + +#endif + #endif /** @}*/ diff --git a/platform/mbed-trace/include/mbed-trace/mbed_trace.h b/platform/mbed-trace/include/mbed-trace/mbed_trace.h index 80666f91195..c6015e26d47 100644 --- a/platform/mbed-trace/include/mbed-trace/mbed_trace.h +++ b/platform/mbed-trace/include/mbed-trace/mbed_trace.h @@ -404,7 +404,7 @@ char *mbed_trace_array(const uint8_t *buf, uint16_t len); #elif !defined(MBED_TRACE_DUMMIES_DEFINED) // define dummies, hiding the real functions #define MBED_TRACE_DUMMIES_DEFINED -#define mbed_trace_init(...) ((int) 0) +#define mbed_trace_init(...) ((void) 0) #define mbed_trace_free(...) ((void) 0) #define mbed_trace_buffer_sizes(...) ((void) 0) #define mbed_trace_config_set(...) ((void) 0) diff --git a/rtos/include/rtos/Mutex.h b/rtos/include/rtos/Mutex.h index 6071bf697c9..7dd7af2cdae 100644 --- a/rtos/include/rtos/Mutex.h +++ b/rtos/include/rtos/Mutex.h @@ -67,8 +67,8 @@ typedef mbed::ScopedLock ScopedMutexLock; * \par * Mbed Mutexes are recursive. So, if you call the \c lock() function multiple times, * you must call \c unlock() the same number of times to unlock the mutex. This means that it's okay to lock - * a mutex, then call another function that also locks and unlocks the mutex, and the mutex won't actually - * get unlocked until your function unlocks it. + * a mutex, then call another function that also locks and unlocks the mutex. The mutex won't actually + * get unlocked until the top level function unlocks it. * * @note You cannot use member functions of this class in ISR context. If you require Mutex functionality within ISR handler, consider using @a Semaphore. * diff --git a/targets/TARGET_STM/README.md b/targets/TARGET_STM/README.md index 88639ebccc8..57513f45587 100644 --- a/targets/TARGET_STM/README.md +++ b/targets/TARGET_STM/README.md @@ -504,21 +504,6 @@ https://github.com/ARMmbed/mbed-os/blob/master/connectivity/drivers/emac/TARGET_ Option is also to define your own `HAL_ETH_MspInit` function, you then have to add **USE_USER_DEFINED_HAL_ETH_MSPINIT** macro. -#### Custom IRQ Handler and Callback from user application -To use the custom IRQ Handler and the callbacks, you need to add -**USE_USER_DEFINED_HAL_ETH_IRQ_CALLBACK** macro -inside any of the JASON file in either targets.json or in mbed_app.json file. - -For example in the targets.json, -you need to add this line in your target: -```"macros_add": ["USE_USER_DEFINED_HAL_ETH_IRQ_CALLBACK"],``` -or for example in the mbed_app.json, you need to add: -``` "macros": ["USE_USER_DEFINED_HAL_ETH_IRQ_CALLBACK"]``` - -By doing the any of the above json files, the corresponding user defined custom apis like -HAL_ETH_RxCpltCallback() and STM_HAL_ETH_Handler() can be called from -the user application. - #### Changing default MAC address in STM32 To change the default MAC address in STM32, If we have the function mbed_otp_mac_address() in the user application,the default ethernet address diff --git a/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/CMakeLists.txt index 891564cf7e2..621a8cee239 100644 --- a/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/CMakeLists.txt @@ -19,7 +19,6 @@ target_sources(mbed-stm32f2cube-fw STM32F2xx_HAL_Driver/stm32f2xx_hal_dcmi_ex.c STM32F2xx_HAL_Driver/stm32f2xx_hal_dma.c STM32F2xx_HAL_Driver/stm32f2xx_hal_dma_ex.c - STM32F2xx_HAL_Driver/stm32f2xx_hal_eth.c STM32F2xx_HAL_Driver/stm32f2xx_hal_exti.c STM32F2xx_HAL_Driver/stm32f2xx_hal_flash.c STM32F2xx_HAL_Driver/stm32f2xx_hal_flash_ex.c diff --git a/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/stm32f2xx_hal_conf.h b/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/stm32f2xx_hal_conf.h index 1f7a6e44ca2..e5678eb5aff 100644 --- a/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/stm32f2xx_hal_conf.h +++ b/targets/TARGET_STM/TARGET_STM32F2/STM32Cube_FW/stm32f2xx_hal_conf.h @@ -43,7 +43,10 @@ #define HAL_DAC_MODULE_ENABLED #define HAL_DCMI_MODULE_ENABLED #define HAL_DMA_MODULE_ENABLED -#define HAL_ETH_MODULE_ENABLED + +// Mbed uses a handwritten driver for Ethernet +// #define HAL_ETH_MODULE_ENABLED + #define HAL_EXTI_MODULE_ENABLED #define HAL_FLASH_MODULE_ENABLED #define HAL_NAND_MODULE_ENABLED diff --git a/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/CMakeLists.txt index ae0a4b831bd..c8f7524f42e 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/CMakeLists.txt @@ -24,7 +24,6 @@ target_sources(mbed-stm32f4cube-fw STM32F4xx_HAL_Driver/stm32f4xx_hal_dma2d.c STM32F4xx_HAL_Driver/stm32f4xx_hal_dma_ex.c STM32F4xx_HAL_Driver/stm32f4xx_hal_dsi.c - STM32F4xx_HAL_Driver/stm32f4xx_hal_eth.c STM32F4xx_HAL_Driver/stm32f4xx_hal_exti.c STM32F4xx_HAL_Driver/stm32f4xx_hal_flash.c STM32F4xx_HAL_Driver/stm32f4xx_hal_flash_ex.c diff --git a/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/stm32f4xx_hal_conf.h b/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/stm32f4xx_hal_conf.h index af2a9cc2e83..6e9354f719e 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/stm32f4xx_hal_conf.h +++ b/targets/TARGET_STM/TARGET_STM32F4/STM32Cube_FW/stm32f4xx_hal_conf.h @@ -43,7 +43,10 @@ #define HAL_DCMI_MODULE_ENABLED #define HAL_DMA_MODULE_ENABLED #define HAL_DMA2D_MODULE_ENABLED -#define HAL_ETH_MODULE_ENABLED + +// Mbed uses a handwritten driver for Ethernet +// #define HAL_ETH_MODULE_ENABLED + #define HAL_FLASH_MODULE_ENABLED #define HAL_NAND_MODULE_ENABLED #define HAL_NOR_MODULE_ENABLED diff --git a/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/CMakeLists.txt index 95653610e25..cd708d41dd1 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/CMakeLists.txt @@ -26,7 +26,6 @@ target_sources(mbed-stm32f7cube-fw STM32F7xx_HAL_Driver/stm32f7xx_hal_dma2d.c STM32F7xx_HAL_Driver/stm32f7xx_hal_dma_ex.c STM32F7xx_HAL_Driver/stm32f7xx_hal_dsi.c - STM32F7xx_HAL_Driver/stm32f7xx_hal_eth.c STM32F7xx_HAL_Driver/stm32f7xx_hal_exti.c STM32F7xx_HAL_Driver/stm32f7xx_hal_flash.c STM32F7xx_HAL_Driver/stm32f7xx_hal_flash_ex.c diff --git a/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/stm32f7xx_hal_conf.h b/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/stm32f7xx_hal_conf.h index e4ef4b02ef8..154496c71c8 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/stm32f7xx_hal_conf.h +++ b/targets/TARGET_STM/TARGET_STM32F7/STM32Cube_FW/stm32f7xx_hal_conf.h @@ -44,7 +44,10 @@ #define HAL_DCMI_MODULE_ENABLED #define HAL_DMA_MODULE_ENABLED #define HAL_DMA2D_MODULE_ENABLED -#define HAL_ETH_MODULE_ENABLED + +// Mbed uses a handwritten driver for Ethernet +// #define HAL_ETH_MODULE_ENABLED + #define HAL_EXTI_MODULE_ENABLED #define HAL_FLASH_MODULE_ENABLED #define HAL_NAND_MODULE_ENABLED diff --git a/targets/TARGET_STM/TARGET_STM32H5/STM32Cube_FW/stm32h5xx_hal_conf.h b/targets/TARGET_STM/TARGET_STM32H5/STM32Cube_FW/stm32h5xx_hal_conf.h index 5161c4110f6..3bb4424f36a 100644 --- a/targets/TARGET_STM/TARGET_STM32H5/STM32Cube_FW/stm32h5xx_hal_conf.h +++ b/targets/TARGET_STM/TARGET_STM32H5/STM32Cube_FW/stm32h5xx_hal_conf.h @@ -47,7 +47,10 @@ extern "C" { #define HAL_DMA_MODULE_ENABLED #define HAL_DTS_MODULE_ENABLED #define HAL_EXTI_MODULE_ENABLED -#define HAL_ETH_MODULE_ENABLED + +// Mbed uses a handwritten driver for Eth V2 +// #define HAL_ETH_MODULE_ENABLED + #define HAL_FDCAN_MODULE_ENABLED #define HAL_FLASH_MODULE_ENABLED #define HAL_FMAC_MODULE_ENABLED diff --git a/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/CMakeLists.txt b/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/CMakeLists.txt index 7ef51581452..e7f395df3bc 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/CMakeLists.txt +++ b/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/CMakeLists.txt @@ -26,11 +26,8 @@ target_sources(mbed-stm32h7cube-fw STM32H7xx_HAL_Driver/stm32h7xx_hal_dma_ex.c STM32H7xx_HAL_Driver/stm32h7xx_hal_dsi.c STM32H7xx_HAL_Driver/stm32h7xx_hal_dts.c - - # Temporary: using legacy Ethernet driver for now - STM32H7xx_HAL_Driver/Legacy/stm32h7xx_hal_eth.c - STM32H7xx_HAL_Driver/Legacy/stm32h7xx_hal_eth_ex.c - + STM32H7xx_HAL_Driver/stm32h7xx_hal_eth.c + STM32H7xx_HAL_Driver/stm32h7xx_hal_eth_ex.c STM32H7xx_HAL_Driver/stm32h7xx_hal_exti.c STM32H7xx_HAL_Driver/stm32h7xx_hal_fdcan.c STM32H7xx_HAL_Driver/stm32h7xx_hal_flash.c diff --git a/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/stm32h7xx_hal_conf.h b/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/stm32h7xx_hal_conf.h index a37776edf7e..e8ab7e968b7 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/stm32h7xx_hal_conf.h +++ b/targets/TARGET_STM/TARGET_STM32H7/STM32Cube_FW/stm32h7xx_hal_conf.h @@ -50,9 +50,8 @@ #define HAL_DTS_MODULE_ENABLED #define HAL_DSI_MODULE_ENABLED -// Temporary: using legacy Ethernet driver for now +// Mbed uses a handwritten driver for Eth V2 // #define HAL_ETH_MODULE_ENABLED -#define HAL_ETH_LEGACY_MODULE_ENABLED #define HAL_EXTI_MODULE_ENABLED #define HAL_FDCAN_MODULE_ENABLED diff --git a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H743_STM32H72x_FAMILIES/STM32H743_H72x.ld b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H743_STM32H72x_FAMILIES/STM32H743_H72x.ld index 33988534985..2ffdfe63eea 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H743_STM32H72x_FAMILIES/STM32H743_H72x.ld +++ b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H743_STM32H72x_FAMILIES/STM32H743_H72x.ld @@ -16,7 +16,6 @@ */ #include "cmsis_nvic.h" -#include "../stm32_eth_region_size_calcs.h" M_CRASH_DATA_RAM_SIZE = 0x100; @@ -212,20 +211,6 @@ SECTIONS __StackLimit = __StackTop - MBED_CONF_TARGET_BOOT_STACK_SIZE; PROVIDE(__stack = __StackTop); - /* Ethernet DMA descriptors should be at the start of SRAM_D2 because they need an MPU region - and because the CM4 and CM7 have to agree on their location.*/ - .eth_descriptors (NOLOAD) : { - ASSERT(. == ORIGIN(SRAM_D2), "Eth Descriptors region must be at the start of SRAM_D2"); - PROVIDE(__eth_descriptors_start = .); - *(.EthDescriptors) - . = __eth_descriptors_start + STM32_DMA_DESCRIP_REGION_SIZE; - } >SRAM_D2 - - /* Ethernet buffers are recommended to be in SRAM_D2 but don't need any special MPU region. */ - .eth_buffers (NOLOAD) : { - *(.EthBuffers) - } >SRAM_D2 - /* Use SRAM_D2 as additional heap */ .heap (NOLOAD): { diff --git a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM4/STM32H745_H747_CM4.ld b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM4/STM32H745_H747_CM4.ld index 0d5afd00959..6b999870b7e 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM4/STM32H745_H747_CM4.ld +++ b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM4/STM32H745_H747_CM4.ld @@ -16,7 +16,6 @@ */ #include "cmsis_nvic.h" -#include "../../stm32_eth_region_size_calcs.h" M_CRASH_DATA_RAM_SIZE = 0x100; @@ -111,15 +110,6 @@ SECTIONS __etext = .; - /* Ethernet DMA descriptors should be at the start of SRAM_D2 because they need an MPU region - and because the CM4 and CM7 have to agree on their location.*/ - .eth_descriptors (NOLOAD) : { - ASSERT(. == ORIGIN(SRAM_D2), "Eth Descriptors region must be at the start of SRAM_D2"); - PROVIDE(__eth_descriptors_start = .); - *(.EthDescriptors) - . = __eth_descriptors_start + STM32_DMA_DESCRIP_REGION_SIZE; - } >SRAM_D2 - _sidata = .; .data : AT (__etext) @@ -222,9 +212,4 @@ SECTIONS . = ALIGN(8); __CRASH_DATA_RAM_END__ = .; /* Define a global symbol at data end */ } > SRAM_D3 - - /* Ethernet buffers are recommended to be in SRAM_D2 but don't need any special MPU region. */ - .eth_buffers (NOLOAD) : { - *(.EthBuffers) - } >SRAM_D2 } diff --git a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM7/STM32H745_H747_CM7.ld b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM7/STM32H745_H747_CM7.ld index 144b0fdf3e8..dadb368cb41 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM7/STM32H745_H747_CM7.ld +++ b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H745_47_FAMILY/CM7/STM32H745_H747_CM7.ld @@ -16,7 +16,6 @@ */ #include "cmsis_nvic.h" -#include "../../stm32_eth_region_size_calcs.h" M_CRASH_DATA_RAM_SIZE = 0x100; @@ -203,21 +202,6 @@ SECTIONS /* Check if data + heap + stack exceeds SRAM limit */ ASSERT(__StackLimit >= __HeapLimit, "region SRAM overflowed with stack") - /* Ethernet DMA descriptors should be at the start of SRAM_D2 because they need an MPU region - and because the CM4 and CM7 have to agree on their location.*/ - .eth_descriptors (NOLOAD) : { - ASSERT(. == ORIGIN(SRAM_D2), "Eth Descriptors region must be at the start of SRAM_D2"); - PROVIDE(__eth_descriptors_start = .); - *(.EthDescriptors) - . = __eth_descriptors_start + STM32_DMA_DESCRIP_REGION_SIZE; - } >SRAM_D2 - - /* Ethernet buffers are recommended to be in SRAM_D2 but not required to be, so we will - put them in SRAM since SRAM2 is used by the CM4 */ - .eth_buffers (NOLOAD) : { - *(.EthBuffers) - } >SRAM - /* Put crash data in the otherwise unused D3 SRAM */ .crash_data_ram : { diff --git a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H7Ax_FAMILY/STM32H7Ax.ld b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H7Ax_FAMILY/STM32H7Ax.ld index 07a4d5039ee..f930e0e28c7 100644 --- a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H7Ax_FAMILY/STM32H7Ax.ld +++ b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/STM32H7Ax_FAMILY/STM32H7Ax.ld @@ -16,7 +16,6 @@ */ #include "cmsis_nvic.h" -#include "../stm32_eth_region_size_calcs.h" M_CRASH_DATA_RAM_SIZE = 0x100; @@ -212,19 +211,6 @@ SECTIONS __CRASH_DATA_RAM_END__ = .; /* Define a global symbol at data end */ } > SRAM_D3 - /* Ethernet DMA descriptors should be at the start of SRAM_AXI because they need an MPU region.*/ - .eth_descriptors (NOLOAD) : { - ASSERT(. == ORIGIN(SRAM_AXI), "Eth Descriptors region must be at the start of SRAM_D2"); - PROVIDE(__eth_descriptors_start = .); - *(.EthDescriptors) - . = __eth_descriptors_start + STM32_DMA_DESCRIP_REGION_SIZE; - } >SRAM_AXI - - /* Ethernet buffers are recommended to be in SRAM_AXI but don't need any special MPU region. */ - .eth_buffers (NOLOAD) : { - *(.EthBuffers) - } >SRAM_AXI - /* Use SRAM_AXI as additional heap */ .heap (NOLOAD): { diff --git a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/stm32_eth_region_size_calcs.h b/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/stm32_eth_region_size_calcs.h deleted file mode 100644 index 16f3499be33..00000000000 --- a/targets/TARGET_STM/TARGET_STM32H7/linker_scripts/stm32_eth_region_size_calcs.h +++ /dev/null @@ -1,51 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2024 Jamie Smith - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This file contains calculations for the size of the memory region used for the Ethernet buffer descriptors. - * This region must be a power-of-2 size so that it can be used as an MPU region. Also, in dual core - * CPUs, the CM4 and CM7 have to agree on its size so they don't define conflicting memory regions. - * - * So, this header has some fancy math to calculate it. Note that this header is included by - * linker scripts so it can only contain preprocessor code. - */ - -/* from here: https://stackoverflow.com/questions/22925016/rounding-up-to-powers-of-2-with-preprocessor-constants */ -#define POW2_CEIL(v) (1 + \ -(((((((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) | \ - ((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) >> 0x04))) | \ - ((((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) | \ - ((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) >> 0x04))) >> 0x02))) | \ - ((((((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) | \ - ((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) >> 0x04))) | \ - ((((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) | \ - ((((v) - 1) | (((v) - 1) >> 0x10) | \ - (((v) - 1) | (((v) - 1) >> 0x10) >> 0x08)) >> 0x04))) >> 0x02))) >> 0x01)))) - -/* Size of an ETH_DMADescTypeDef structure in bytes*/ -#define STM32_SIZEOF_ETH_DMA_DESCRIPTOR 24 - -/* Calculation of RAM size */ -#define STM32_TOTAL_DMA_DESCRIPTOR_RAM_NEEDED (STM32_SIZEOF_ETH_DMA_DESCRIPTOR * (MBED_CONF_STM32_EMAC_ETH_RXBUFNB + MBED_CONF_STM32_EMAC_ETH_TXBUFNB)) -#define STM32_DMA_DESCRIP_REGION_SIZE POW2_CEIL(STM32_TOTAL_DMA_DESCRIPTOR_RAM_NEEDED) \ No newline at end of file diff --git a/targets/TARGET_STM/mbed_overrides.c b/targets/TARGET_STM/mbed_overrides.c index 62ce3af0753..74748cdefec 100644 --- a/targets/TARGET_STM/mbed_overrides.c +++ b/targets/TARGET_STM/mbed_overrides.c @@ -299,3 +299,34 @@ void mbed_sdk_init() mbed_sdk_inited = 1; } + +// Override MAC default MAC address based on chip unique ID +#if defined (TARGET_STM32F2) || defined (TARGET_STM32F4) || defined (TARGET_STM32F7) || defined (TARGET_STM32H7) || defined(TARGET_STM32H5) +void mbed_mac_address(char *mac) +{ + unsigned char ST_mac_addr[3] = {0x00, 0x80, 0xe1}; // default STMicro mac address + + // Read unic id +#if defined (TARGET_STM32F2) + uint32_t word0 = *(uint32_t *)0x1FFF7A10; +#elif defined (TARGET_STM32F4) + uint32_t word0 = *(uint32_t *)0x1FFF7A10; +#elif defined (TARGET_STM32F7) + uint32_t word0 = *(uint32_t *)0x1FF0F420; +#elif defined (TARGET_STM32H7) || defined(TARGET_STM32H5) + uint32_t word0 = *(uint32_t *)UID_BASE; +#else +#error MAC address can not be derived from target unique Id +#endif + + mac[0] = ST_mac_addr[0]; + mac[1] = ST_mac_addr[1]; + mac[2] = ST_mac_addr[2]; + + // TODO this code is only using 24 bits of the 96 bit unique identifier, so collisions are possible. + // It should be updated to use a hash. + mac[3] = (word0 & 0x00ff0000) >> 16; + mac[4] = (word0 & 0x0000ff00) >> 8; + mac[5] = (word0 & 0x000000ff); +} +#endif diff --git a/targets/cmsis_mcu_descriptions.json5 b/targets/cmsis_mcu_descriptions.json5 index 9467a53617e..9122b6d93cc 100644 --- a/targets/cmsis_mcu_descriptions.json5 +++ b/targets/cmsis_mcu_descriptions.json5 @@ -7704,7 +7704,8 @@ "start": 134217728, "startup": true }, - "SRAM1_2": { + // Combined SRAMs 1, 2, and 3 + "SRAM1_2_3": { "access": { "execute": true, "non_secure": false, @@ -7716,13 +7717,16 @@ }, "default": true, "p_name": null, - "size": 327680, - "start": 536870912, + "size": 0xA0000, // 640 kiB + "start": 0x20000000, "startup": false }, - "SRAM3": { + // Backup SRAM. This is mentioned in the datasheet but neither the reference manual nor the CMSIS pack + // gives its address... + // Got this info from a forum post: https://community.st.com/t5/stm32-mcus-products/backup-sram-on-stm32h563/td-p/580633 + "SRAM_BKUP": { "access": { - "execute": true, + "execute": false, "non_secure": false, "non_secure_callable": false, "peripheral": false, @@ -7730,10 +7734,8 @@ "secure": false, "write": true }, - "default": false, - "p_name": null, - "size": 327680, - "start": 537198592, + "size": 0x1000, + "start": 0x40036400, "startup": false } }, diff --git a/targets/targets.json5 b/targets/targets.json5 index 1c0a9172d9e..499e3c18e9a 100644 --- a/targets/targets.json5 +++ b/targets/targets.json5 @@ -3111,9 +3111,7 @@ mode is recommended for target MCUs with small amounts of flash and RAM.", "LPTICKER", "CAN", "SERIAL_FC", - "WATCHDOG", - "ETHERNET", - "EMAC" + "WATCHDOG" ], "is_mcu_family_target": true }, @@ -3141,7 +3139,7 @@ mode is recommended for target MCUs with small amounts of flash and RAM.", // ADC reference voltage is same as MCU VDD. // MCU VDD defaults to 3.3V though can be changed to 1.8V based on JP2 setting on nucleo board. - "default-adc-vref": 3.3 + "default-adc-vref": 3.3, }, "device_has_remove": [ "ANALOGOUT" // both DAC pins are in conflict with LED1 and STDIO_UART_TX @@ -3166,6 +3164,12 @@ mode is recommended for target MCUs with small amounts of flash and RAM.", ], "macros_add": [ "STM32H563xx" + ], + "overrides": { + "network-default-interface-type": "ETHERNET" + }, + "device_has_add": [ + "EMAC" ] }, "NUCLEO_H563ZI": { diff --git a/tools/cmake/toolchains/GCC_ARM.cmake b/tools/cmake/toolchains/GCC_ARM.cmake index 8669f03eed2..ae807b01be7 100644 --- a/tools/cmake/toolchains/GCC_ARM.cmake +++ b/tools/cmake/toolchains/GCC_ARM.cmake @@ -61,6 +61,7 @@ list(APPEND common_options "-Wno-unused-parameter" "-Wno-missing-field-initializers" "-Wno-psabi" # Disable "parameter passing changed in GCC 7.1" warning + "-Wno-packed-bitfield-compat" # Disable "offset of packed bitfield changed in GCC 4.4" warning "-fmessage-length=0" "-fno-exceptions" "-ffunction-sections"