diff --git a/ARM.CMSIS-Driver.pdsc b/ARM.CMSIS-Driver.pdsc index 357f85a..0a53bc0 100644 --- a/ARM.CMSIS-Driver.pdsc +++ b/ARM.CMSIS-Driver.pdsc @@ -14,6 +14,7 @@ Active development ... + - Added RTL8211F PHY driver - Added LAN8741A PHY driver - Updated Inventek ISM43362 WiFi driver (version 1.16.0): - Eliminated usage of sscanf (to enable driver to work with GCC newlib-nano) @@ -219,6 +220,17 @@ + + Ethernet PHY RTL8211F Driver + + #define RTE_Drivers_PHY_RTL8211F /* Driver PHY RTL8211F */ + + + + + + + Ethernet PHY ST802RT1 Driver diff --git a/Documentation/Doxygen/src/ethernet.md b/Documentation/Doxygen/src/ethernet.md index 33d9ace..8d619e3 100644 --- a/Documentation/Doxygen/src/ethernet.md +++ b/Documentation/Doxygen/src/ethernet.md @@ -15,6 +15,7 @@ The \ref pack_content provides implementations of **[CMSIS-Ethernet drivers](htt | **LAN8720** | Ethernet PHY interface for the Microchip **[LAN8720A](https://www.microchip.com/LAN8720A)**. | | **LAN8740A** | Ethernet PHY interface for the Microchip **[LAN8740A](https://www.microchip.com/LAN8740A)**. | | **LAN8742A** | Ethernet PHY interface for the Microchip **[LAN8742A](https://www.microchip.com/LAN8742A)**. | +| **RTL8211F** | Ethernet PHY interface for the Realtek **[RTL8211F](https://www.realtek.com/Product/Index?id=3975&cate_id=786)**. | | **ST802RT1** | Ethernet PHY interface for the STMicroelectronics **[ST802RT1](http://www.st.com/content/ccc/resource/technical/document/data_brief/37/8e/14/c7/84/39/4d/61/CD00263138.pdf/files/CD00263138.pdf/jcr:content/translations/en.CD00263138.pdf)**. | ## Multiple Driver Instances diff --git a/Documentation/OVERVIEW.md b/Documentation/OVERVIEW.md index 56e8352..d037770 100644 --- a/Documentation/OVERVIEW.md +++ b/Documentation/OVERVIEW.md @@ -3,7 +3,7 @@ This pack contains: - Driver implementations that work across many different microcontroller. - - [Ethernet drivers](https://arm-software.github.io/CMSIS-Driver/latest/driver_eth.html): KSZ8851, LAN9220, DP83848C, KSZ8061RNB, KSZ8081RNA, LAN8710A, LAN8720, LAN8740A, LAN8742A, ST802RT1 + - [Ethernet drivers](https://arm-software.github.io/CMSIS-Driver/latest/driver_eth.html): KSZ8851, LAN9220, DP83848C, KSZ8061RNB, KSZ8081RNA, LAN8710A, LAN8720, LAN8740A, LAN8742A, RTL8211F, ST802RT1 - [USB drivers](https://arm-software.github.io/CMSIS-Driver/latest/driver_USB.html): EHCI and OHCI - [WiFi drivers](https://arm-software.github.io/CMSIS-Driver/latest/driver_WiFi.html#driver_wifi_devices): DA16200, ESP32, ESP8266, ISM43362, WizFi360 - [Flash drivers](https://arm-software.github.io/CMSIS-Driver/latest/driver_WiFi.html#driver_wifi_devices): AM29x800BB, AT45DB641E, AT45DB642D, M29EW28F128, M29W640FB, N25Q032A, S29GL064Nx2 diff --git a/Ethernet_PHY/RTL8211F/PHY_RTL8211F.c b/Ethernet_PHY/RTL8211F/PHY_RTL8211F.c new file mode 100644 index 0000000..e8a728e --- /dev/null +++ b/Ethernet_PHY/RTL8211F/PHY_RTL8211F.c @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2026 Arm Limited. All rights reserved. + * + * 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 + * + * 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. + * + * ----------------------------------------------------------------------- + * + * $Date: 29. June 2026 + * $Revision: V1.0 + * + * Driver: Driver_ETH_PHYn (default: Driver_ETH_PHY0) + * Project: Ethernet Physical Layer Transceiver (PHY) + * Driver for PHY_RTL8211F + * ----------------------------------------------------------------------- + * Use the following configuration settings in the middleware component + * to connect to this driver. + * + * Configuration Setting Value + * --------------------- ----- + * Connect to hardware via Driver_ETH_PHY# = n (default: 0) + * -------------------------------------------------------------------- */ + +/* History: + * Version 1.0 + * Initial release + */ + +#include "PHY_RTL8211F.h" + +#define ARM_ETH_PHY_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0) + +#ifndef ETH_PHY_NUM +#define ETH_PHY_NUM 0 /* Default driver number */ +#endif + +/* Driver Version */ +static const ARM_DRIVER_VERSION DriverVersion = { + ARM_ETH_PHY_API_VERSION, + ARM_ETH_PHY_DRV_VERSION +}; + +static PHY_CTRL PHY = { NULL, NULL, 0U, 0U, 0U }; + +/** + \fn int32_t phy_read (uint8_t reg_addr, uint16_t *data) + \brief Read a PHY register at the active device address. +*/ +static int32_t phy_read (uint8_t reg_addr, uint16_t *data) { + return PHY.reg_rd(PHY.addr, reg_addr, data); +} + +/** + \fn int32_t phy_write (uint8_t reg_addr, uint16_t data) + \brief Write a PHY register at the active device address. +*/ +static int32_t phy_write (uint8_t reg_addr, uint16_t data) { + return PHY.reg_wr(PHY.addr, reg_addr, data); +} + +/** + \fn int32_t SetPage (uint16_t page) + \brief Select an RTL8211 register page. +*/ +static int32_t SetPage (uint16_t page) { + return phy_write(RTL8211_PAGSR, page); +} + +/** + \fn int32_t ReadPhysr (uint16_t *data) + \brief Read the PHY Specific Status Register (page 0xA43). +*/ +static int32_t ReadPhysr (uint16_t *data) { + int32_t status; + int32_t restore; + + status = SetPage(RTL8211_PAGE_A43); + if (status != ARM_DRIVER_OK) { + return status; + } + + status = phy_read(RTL8211_PHYSR1_PA43, data); + restore = SetPage(RTL8211_PAGE_DEFAULT); + if (status == ARM_DRIVER_OK) { + status = restore; + } + + return status; +} + +/** + \fn int32_t ScanPhyAddress (void) + \brief Find and identify the RTL8211 on the MDIO bus. + \details Mirrors the address scan performed by the ST reference driver: + the first address returning a valid (non 0xFFFF) PHY ID 1 is + used; the device is then verified to be an RTL8211. +*/ +static int32_t ScanPhyAddress (void) { + uint16_t id1; + uint16_t id2; + uint8_t addr; + int32_t status; + + for (addr = 0U; addr <= RTL8211_PHY_ADDR_MAX; addr++) { + id1 = RTL8211_PHYID_INVALID; + if (PHY.reg_rd(addr, RTL8211_PHYID1, &id1) != ARM_DRIVER_OK) { + continue; + } + if (id1 == RTL8211_PHYID_INVALID) { + continue; + } + + status = PHY.reg_rd(addr, RTL8211_PHYID2, &id2); + if (status != ARM_DRIVER_OK) { + return status; + } + + if ((id1 == RTL8211_PHYID1_DEFAULT) && + ((id2 & RTL8211_PHYID2_MASK) == RTL8211_PHYID2_DEFAULT)) { + PHY.addr = addr; + return ARM_DRIVER_OK; + } + } + + return ARM_DRIVER_ERROR_UNSUPPORTED; +} + +/** + \fn int32_t ResetPhy (void) + \brief Software-reset the RTL8211 and wait until it is ready. + \details After the reset bit self-clears the RTL8211 needs a + stabilization period (datasheet minimum 30 ms) before its + registers and the RGMII interface are reliable. The ST + reference driver waits explicitly here; with no system tick + available the delay is produced by counted MDIO reads. +*/ +static int32_t ResetPhy (void) { + uint16_t val; + uint32_t count; + int32_t status; + + status = SetPage(RTL8211_PAGE_DEFAULT); + if (status != ARM_DRIVER_OK) { + return status; + } + + status = phy_write(RTL8211_BMCR, RTL8211_BMCR_RESET); + if (status != ARM_DRIVER_OK) { + return status; + } + + for (count = RTL8211_RESET_TIMEOUT; count > 0U; count--) { + status = phy_read(RTL8211_BMCR, &val); + if (status != ARM_DRIVER_OK) { + return status; + } + if ((val & RTL8211_BMCR_RESET) == 0U) { + break; + } + } + + if (count == 0U) { + return ARM_DRIVER_ERROR_TIMEOUT; + } + + for (count = RTL8211_INIT_SETTLE; count > 0U; count--) { + status = phy_read(RTL8211_BMSR, &val); + if (status != ARM_DRIVER_OK) { + return status; + } + } + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t ConfigureRgmiiDelay (void) + \brief Configure the RTL8211 RGMII internal TX/RX clock delays. + \details Same register sequence as the ST reference driver: page 0xD08, + MIICR1[8] for the TX delay and MIICR2[3] for the RX delay. +*/ +static int32_t ConfigureRgmiiDelay (void) { + uint16_t val; + int32_t status; + + status = SetPage(RTL8211_PAGE_D08); + if (status != ARM_DRIVER_OK) { return status; } + + /* TX delay: reg 0x11 bit 8 */ + status = phy_read(RTL8211_MIICR1_PD08, &val); + if (status != ARM_DRIVER_OK) { (void)SetPage(RTL8211_PAGE_DEFAULT); return status; } +#if (RTL8211_TX_DELAY_ENABLE != 0U) + val |= RTL8211_MIICR1_TXDLY_ENABLE; +#else + val &= (uint16_t)~RTL8211_MIICR1_TXDLY_ENABLE; +#endif + status = phy_write(RTL8211_MIICR1_PD08, val); + if (status != ARM_DRIVER_OK) { (void)SetPage(RTL8211_PAGE_DEFAULT); return status; } + + /* RX delay: reg 0x15 bit 3 */ + status = phy_read(RTL8211_MIICR2_PD08, &val); + if (status != ARM_DRIVER_OK) { (void)SetPage(RTL8211_PAGE_DEFAULT); return status; } +#if (RTL8211_RX_DELAY_ENABLE != 0U) + val |= RTL8211_MIICR2_RXDLY_ENABLE; +#else + val &= (uint16_t)~RTL8211_MIICR2_RXDLY_ENABLE; +#endif + status = phy_write(RTL8211_MIICR2_PD08, val); + if (status != ARM_DRIVER_OK) { (void)SetPage(RTL8211_PAGE_DEFAULT); return status; } + + return SetPage(RTL8211_PAGE_DEFAULT); +} + +/** + \fn int32_t DisableEee (void) + \brief Disable Energy-Efficient Ethernet (EEE/LPI). + \details Reproduces the ST reference driver DISABLE_RTL8211F_EEE + sequence. In the LPI idle state the MAC drops frames that + arrive after an idle gap (such as the DHCP OFFER), which leaves + the host stranded on a 169.254.x.x address. +*/ +static int32_t DisableEee (void) { + int32_t status; + + /* Clear the EEE LED control bits on page 0xA4B. */ + status = SetPage(RTL8211_PAGE_A4B); + if (status != ARM_DRIVER_OK) { + return status; + } + status = phy_write(RTL8211_EEELCR_PA4B, RTL8211_EEELCR_DISABLE_VAL); + if (status != ARM_DRIVER_OK) { + (void)SetPage(RTL8211_PAGE_DEFAULT); + return status; + } + status = SetPage(RTL8211_PAGE_DEFAULT); + if (status != ARM_DRIVER_OK) { + return status; + } + + /* Clear the EEE advertisement via MMD register 7.60. */ + status = phy_write(RTL8211_MACR, RTL8211_MMD_AN_DEVICE); + if (status != ARM_DRIVER_OK) { + return status; + } + status = phy_write(RTL8211_MAADR, RTL8211_MMD_EEE_ADV_ADDR); + if (status != ARM_DRIVER_OK) { + return status; + } + status = phy_write(RTL8211_MACR, + (uint16_t)(RTL8211_MMD_FUNC_DATA | RTL8211_MMD_AN_DEVICE)); + if (status != ARM_DRIVER_OK) { + return status; + } + + return phy_write(RTL8211_MAADR, 0U); +} + +/** + \fn int32_t ConfigureAutoNegotiation (void) + \brief Program the RTL8211 advertisement registers. +*/ +static int32_t ConfigureAutoNegotiation (void) { + uint16_t val; + int32_t status; + + status = SetPage(RTL8211_PAGE_DEFAULT); + if (status != ARM_DRIVER_OK) { + return status; + } + + val = RTL8211_ANAR_SELECTOR_802_3 | + RTL8211_ANAR_10BT_HD | + RTL8211_ANAR_10BT_FD | + RTL8211_ANAR_100BTX_HD | + RTL8211_ANAR_100BTX_FD; + + status = phy_write(RTL8211_ANAR, val); + if (status != ARM_DRIVER_OK) { + return status; + } + +#if (RTL8211_ADVERTISE_1000 != 0U) + val = RTL8211_GBCR_1000BT_FD; +#else + val = 0U; +#endif + + return phy_write(RTL8211_GBCR, val); +} + +/** + \fn ARM_DRIVER_VERSION GetVersion (void) + \brief Get driver version. + \return \ref ARM_DRIVER_VERSION +*/ +static ARM_DRIVER_VERSION GetVersion (void) { + return DriverVersion; +} + +/** + \fn int32_t Initialize (ARM_ETH_PHY_Read_t fn_read, + ARM_ETH_PHY_Write_t fn_write) + \brief Initialize Ethernet PHY Device. + \param[in] fn_read Pointer to \ref ARM_ETH_MAC_PHY_Read + \param[in] fn_write Pointer to \ref ARM_ETH_MAC_PHY_Write + \return \ref execution_status +*/ +static int32_t Initialize (ARM_ETH_PHY_Read_t fn_read, ARM_ETH_PHY_Write_t fn_write) { + + if ((fn_read == NULL) || (fn_write == NULL)) { + return ARM_DRIVER_ERROR_PARAMETER; + } + + if ((PHY.flags & PHY_INIT) == 0U) { + PHY.reg_rd = fn_read; + PHY.reg_wr = fn_write; + PHY.bcr = 0U; + PHY.addr = 0U; + PHY.flags = PHY_INIT; + } + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t Uninitialize (void) + \brief De-initialize Ethernet PHY Device. + \return \ref execution_status +*/ +static int32_t Uninitialize (void) { + + PHY.reg_rd = NULL; + PHY.reg_wr = NULL; + PHY.bcr = 0U; + PHY.addr = 0U; + PHY.flags = 0U; + + return ARM_DRIVER_OK; +} + +/** + \fn int32_t PowerControl (ARM_POWER_STATE state) + \brief Control Ethernet PHY Device Power. + \param[in] state Power state + \return \ref execution_status +*/ +static int32_t PowerControl (ARM_POWER_STATE state) { + uint16_t val; + int32_t status; + + switch ((int32_t)state) { + case ARM_POWER_OFF: + if ((PHY.flags & PHY_INIT) == 0U) { + return ARM_DRIVER_ERROR; + } + + status = SetPage(RTL8211_PAGE_DEFAULT); + if (status != ARM_DRIVER_OK) { + return status; + } + + status = phy_read(RTL8211_BMCR, &val); + if (status != ARM_DRIVER_OK) { + val = PHY.bcr; + } + + PHY.bcr = val | RTL8211_BMCR_POWER_DOWN; + PHY.flags &= ~PHY_POWER; + + return phy_write(RTL8211_BMCR, PHY.bcr); + + case ARM_POWER_FULL: + if ((PHY.flags & PHY_INIT) == 0U) { + return ARM_DRIVER_ERROR; + } + if ((PHY.flags & PHY_POWER) != 0U) { + return ARM_DRIVER_OK; + } + + /* Locate and identify the RTL8211 on the MDIO bus. */ + status = ScanPhyAddress(); + if (status != ARM_DRIVER_OK) { + return status; + } + + /* Software reset and mandatory post-reset stabilization. */ + status = ResetPhy(); + if (status != ARM_DRIVER_OK) { + return status; + } + + /* Take the PHY out of power-down / isolate. */ + status = phy_read(RTL8211_BMCR, &val); + if (status != ARM_DRIVER_OK) { + return status; + } + PHY.bcr = val & (uint16_t)~(RTL8211_BMCR_POWER_DOWN | RTL8211_BMCR_ISOLATE); + status = phy_write(RTL8211_BMCR, PHY.bcr); + if (status != ARM_DRIVER_OK) { + return status; + } + + /* RGMII internal clock delays. */ + status = ConfigureRgmiiDelay(); + if (status != ARM_DRIVER_OK) { + return status; + } + +#if (RTL8211_DISABLE_EEE != 0U) + status = DisableEee(); + if (status != ARM_DRIVER_OK) { + return status; + } +#endif + + /* Advertise the supported modes and start auto-negotiation so the + copper link is established (link LED on) regardless of how the MAC + subsequently calls SetMode. Auto-negotiation is also the only valid + way to bring up a 1000BASE-T link. */ + status = ConfigureAutoNegotiation(); + if (status != ARM_DRIVER_OK) { + return status; + } + + PHY.bcr |= (RTL8211_BMCR_AN_EN | RTL8211_BMCR_RESTART_AN); + status = phy_write(RTL8211_BMCR, PHY.bcr); + if (status != ARM_DRIVER_OK) { + return status; + } + + PHY.flags |= PHY_POWER; + return ARM_DRIVER_OK; + + case ARM_POWER_LOW: + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } +} + +/** + \fn int32_t SetInterface (uint32_t interface) + \brief Set Ethernet Media Interface. + \param[in] interface Media Interface type + \return \ref execution_status +*/ +static int32_t SetInterface (uint32_t interface) { + + if ((PHY.flags & PHY_POWER) == 0U) { + return ARM_DRIVER_ERROR; + } + + switch (interface) { + case ARM_ETH_INTERFACE_MII: + case ARM_ETH_INTERFACE_RGMII: + return ARM_DRIVER_OK; + case ARM_ETH_INTERFACE_RMII: + case ARM_ETH_INTERFACE_SMII: + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } +} + +/** + \fn int32_t SetMode (uint32_t mode) + \brief Set Ethernet PHY Device Operation mode. + \param[in] mode Operation Mode + \return \ref execution_status +*/ +static int32_t SetMode (uint32_t mode) { + uint16_t val; + uint32_t autoneg; + int32_t status; + + if ((PHY.flags & PHY_POWER) == 0U) { + return ARM_DRIVER_ERROR; + } + + val = PHY.bcr & RTL8211_BMCR_POWER_DOWN; + autoneg = (mode & ARM_ETH_PHY_AUTO_NEGOTIATE); + + switch (mode & ARM_ETH_PHY_SPEED_Msk) { + case ARM_ETH_PHY_SPEED_10M: + break; + case ARM_ETH_PHY_SPEED_100M: + val |= RTL8211_BMCR_SPEED_SEL_LSB; + break; + case ARM_ETH_PHY_SPEED_1G: + if ((mode & ARM_ETH_PHY_DUPLEX_Msk) == ARM_ETH_PHY_DUPLEX_HALF) { + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + /* 1000BASE-T can only be established through auto-negotiation (the + master/slave relationship is resolved during negotiation); it cannot + be force-set, so enable auto-negotiation for any gigabit request. */ + autoneg = ARM_ETH_PHY_AUTO_NEGOTIATE; + val |= RTL8211_BMCR_SPEED_SEL_MSB; + break; + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + switch (mode & ARM_ETH_PHY_DUPLEX_Msk) { + case ARM_ETH_PHY_DUPLEX_HALF: + break; + case ARM_ETH_PHY_DUPLEX_FULL: + val |= RTL8211_BMCR_DUPLEX_MODE; + break; + default: + return ARM_DRIVER_ERROR_UNSUPPORTED; + } + + if (autoneg != 0U) { + val |= (RTL8211_BMCR_AN_EN | RTL8211_BMCR_RESTART_AN); + } + if ((mode & ARM_ETH_PHY_LOOPBACK) != 0U) { + val |= RTL8211_BMCR_LOOPBACK; + } + if ((mode & ARM_ETH_PHY_ISOLATE) != 0U) { + val |= RTL8211_BMCR_ISOLATE; + } + + status = SetPage(RTL8211_PAGE_DEFAULT); + if (status != ARM_DRIVER_OK) { + return status; + } + + if (autoneg != 0U) { + status = ConfigureAutoNegotiation(); + if (status != ARM_DRIVER_OK) { + return status; + } + } + + PHY.bcr = val; + return phy_write(RTL8211_BMCR, PHY.bcr); +} + +/** + \fn ARM_ETH_LINK_STATE GetLinkState (void) + \brief Get Ethernet PHY Device Link state. + \return current link status \ref ARM_ETH_LINK_STATE +*/ +static ARM_ETH_LINK_STATE GetLinkState (void) { + uint16_t val; + + val = 0U; + + if ((PHY.flags & PHY_POWER) != 0U) { + /* Read BMSR twice: the link status bit latches low, so the second read + reflects the current state (same approach as the ST reference driver). */ + if (phy_read(RTL8211_BMSR, &val) != ARM_DRIVER_OK) { + val = 0U; + } + else if (phy_read(RTL8211_BMSR, &val) != ARM_DRIVER_OK) { + val = 0U; + } + } + + if ((val & RTL8211_BMSR_LINK_STATUS) != 0U) { + return ARM_ETH_LINK_UP; + } + + return ARM_ETH_LINK_DOWN; +} + +/** + \fn ARM_ETH_LINK_INFO GetLinkInfo (void) + \brief Get Ethernet PHY Device Link information. + \return current link parameters \ref ARM_ETH_LINK_INFO +*/ +static ARM_ETH_LINK_INFO GetLinkInfo (void) { + ARM_ETH_LINK_INFO info; + uint16_t val; + + info.speed = ARM_ETH_SPEED_10M; + info.duplex = ARM_ETH_DUPLEX_HALF; + info.reserved = 0U; + val = 0U; + + if ((PHY.flags & PHY_POWER) != 0U) { + if (ReadPhysr(&val) != ARM_DRIVER_OK) { + val = 0U; + } + } + + switch (val & RTL8211_PHYSR1_SPEED_MASK) { + case RTL8211_PHYSR1_SPEED_1000M: + info.speed = ARM_ETH_SPEED_1G; + break; + case RTL8211_PHYSR1_SPEED_100M: + info.speed = ARM_ETH_SPEED_100M; + break; + default: + info.speed = ARM_ETH_SPEED_10M; + break; + } + + if ((val & RTL8211_PHYSR1_DUPLEX) != 0U) { + info.duplex = ARM_ETH_DUPLEX_FULL; + } + + return info; +} + +/* PHY Driver Control Block */ +extern +ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(ETH_PHY_NUM); +ARM_DRIVER_ETH_PHY ARM_Driver_ETH_PHY_(ETH_PHY_NUM) = { + GetVersion, + Initialize, + Uninitialize, + PowerControl, + SetInterface, + SetMode, + GetLinkState, + GetLinkInfo +}; diff --git a/Ethernet_PHY/RTL8211F/PHY_RTL8211F.h b/Ethernet_PHY/RTL8211F/PHY_RTL8211F.h new file mode 100644 index 0000000..81a99f4 --- /dev/null +++ b/Ethernet_PHY/RTL8211F/PHY_RTL8211F.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2026 Arm Limited. All rights reserved. + * + * 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 + * + * 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. + * + * ----------------------------------------------------------------------- + * + * $Date: 29. June 2026 + * $Revision: V1.0 + * + * Project: Ethernet Physical Layer Transceiver (PHY) + * Definitions for TL8211F-CG + * -------------------------------------------------------------------- */ + +#ifndef __PHY_RTL8211F_H +#define __PHY_RTL8211F_H + +#include "Driver_ETH_PHY.h" + +#ifndef ARM_ETH_INTERFACE_RGMII +#define ARM_ETH_INTERFACE_RGMII 3U /* CMSIS-Driver 2.x has no RGMII ID */ +#endif + +/* --------------------------------------------------------------------------- + * Build-time configuration. These mirror the switches used by the ST + * reference driver (ENABLE_RTL8211F_TXDELAY / ENABLE_RTL8211F_RXDELAY / + * DISABLE_RTL8211F_EEE). + * ------------------------------------------------------------------------- */ +#ifndef RTL8211_TX_DELAY_ENABLE +#define RTL8211_TX_DELAY_ENABLE 1U /* Enable RGMII TX internal clock delay */ +#endif + +#ifndef RTL8211_RX_DELAY_ENABLE +#define RTL8211_RX_DELAY_ENABLE 1U /* Enable RGMII RX internal clock delay */ +#endif + +#ifndef RTL8211_DISABLE_EEE +#define RTL8211_DISABLE_EEE 1U /* Disable Energy-Efficient Ethernet */ +#endif + +#ifndef RTL8211_ADVERTISE_1000 +#define RTL8211_ADVERTISE_1000 1U /* Advertise 1000BASE-T full duplex */ +#endif + +/* =========================================================================== + * RTL8211 register map and bit definitions + * (values taken from the ST "stm32-rtl8211" component driver, rtl8211.h) + * ======================================================================== */ + +/* IEEE standard registers (page independent) */ +#define RTL8211_BMCR 0x00U /* Basic Mode Control Register */ +#define RTL8211_BMSR 0x01U /* Basic Mode Status Register */ +#define RTL8211_PHYID1 0x02U /* PHY Identifier 1 */ +#define RTL8211_PHYID2 0x03U /* PHY Identifier 2 */ +#define RTL8211_ANAR 0x04U /* Auto-Negotiation Advertisement */ +#define RTL8211_ANLPAR 0x05U /* AN Link Partner Ability */ +#define RTL8211_GBCR 0x09U /* 1000Base-T Control Register */ +#define RTL8211_GBSR 0x0AU /* 1000Base-T Status Register */ +#define RTL8211_MACR 0x0DU /* MMD Access Control Register */ +#define RTL8211_MAADR 0x0EU /* MMD Access Address/Data Register */ +#define RTL8211_GBESR 0x0FU /* 1000Base-T Extended Status */ + +/* Paged registers */ +#define RTL8211_PHYSR1_PA43 0x1AU /* PHY Specific Status (page 0xA43) */ +#define RTL8211_PAGSR 0x1FU /* Page Select Register */ +#define RTL8211_EEELCR_PA4B 0x11U /* EEE LED Control (page 0xA4B) */ +#define RTL8211_MIICR1_PD08 0x11U /* MII Control 1 / TXDLY (page 0xD08)*/ +#define RTL8211_MIICR2_PD08 0x15U /* MII Control 2 / RXDLY (page 0xD08)*/ + +/* Register pages */ +#define RTL8211_PAGE_DEFAULT 0x0000U +#define RTL8211_PAGE_A43 0x0A43U +#define RTL8211_PAGE_A4B 0x0A4BU +#define RTL8211_PAGE_D08 0x0D08U + +/* Basic Mode Control Register (BMCR) bits */ +#define RTL8211_BMCR_RESET 0x8000U +#define RTL8211_BMCR_LOOPBACK 0x4000U +#define RTL8211_BMCR_SPEED_SEL_LSB 0x2000U /* 100M when set (LSB) */ +#define RTL8211_BMCR_AN_EN 0x1000U +#define RTL8211_BMCR_POWER_DOWN 0x0800U +#define RTL8211_BMCR_ISOLATE 0x0400U +#define RTL8211_BMCR_RESTART_AN 0x0200U +#define RTL8211_BMCR_DUPLEX_MODE 0x0100U +#define RTL8211_BMCR_SPEED_SEL_MSB 0x0040U /* 1000M when set (MSB) */ + +/* Basic Mode Status Register (BMSR) bits */ +#define RTL8211_BMSR_AN_COMPLETE 0x0020U +#define RTL8211_BMSR_LINK_STATUS 0x0004U + +/* PHY identifier expected values (RTL8211F) */ +#define RTL8211_PHYID1_DEFAULT 0x001CU +#define RTL8211_PHYID2_DEFAULT 0xC910U +#define RTL8211_PHYID2_MASK 0xFFF0U /* Ignore revision nibble */ +#define RTL8211_PHYID_INVALID 0xFFFFU /* No PHY at this address */ + +/* Auto-Negotiation Advertisement Register (ANAR) bits */ +#define RTL8211_ANAR_100BTX_FD 0x0100U +#define RTL8211_ANAR_100BTX_HD 0x0080U +#define RTL8211_ANAR_10BT_FD 0x0040U +#define RTL8211_ANAR_10BT_HD 0x0020U +#define RTL8211_ANAR_SELECTOR_802_3 0x0001U + +/* 1000Base-T Control Register (GBCR) bits */ +#define RTL8211_GBCR_1000BT_FD 0x0200U + +/* PHY Specific Status Register 1 (page 0xA43) bits */ +#define RTL8211_PHYSR1_SPEED_MASK 0x0030U +#define RTL8211_PHYSR1_SPEED_1000M 0x0020U +#define RTL8211_PHYSR1_SPEED_100M 0x0010U +#define RTL8211_PHYSR1_SPEED_10M 0x0000U +#define RTL8211_PHYSR1_DUPLEX 0x0008U +#define RTL8211_PHYSR1_LINK_RT 0x0004U + +/* MII Control Register bits (page 0xD08) */ +#define RTL8211_MIICR1_TXDLY_ENABLE 0x0100U +#define RTL8211_MIICR2_RXDLY_ENABLE 0x0008U + +/* EEE disable sequence constants (matches ST DISABLE_RTL8211F_EEE) */ +#define RTL8211_EEELCR_DISABLE_VAL 0x1110U +#define RTL8211_MMD_AN_DEVICE 0x0007U /* MMD device 7 (AN) */ +#define RTL8211_MMD_FUNC_DATA 0x4000U /* MMD function: data access */ +#define RTL8211_MMD_EEE_ADV_ADDR 0x003CU /* MMD 7.60 EEE advertisement */ + +/* Polling limits. The CMSIS PHY API provides no system tick, so MDIO + transactions are counted instead (one MDIO access is ~13 us @ 2.5 MHz). */ +#define RTL8211_RESET_TIMEOUT 100000U /* Software reset poll count */ +#define RTL8211_INIT_SETTLE 4000U /* Post-reset settle (>=30 ms) */ +#define RTL8211_PHY_ADDR_MAX 31U /* Highest valid PHY address */ + +/* PHY Driver State Flags */ +#define PHY_INIT 0x01U /* Driver initialized */ +#define PHY_POWER 0x02U /* Driver power is on */ + +/* PHY Driver Control Structure */ +typedef struct phy_ctrl { + ARM_ETH_PHY_Read_t reg_rd; /* PHY register read function */ + ARM_ETH_PHY_Write_t reg_wr; /* PHY register write function */ + uint16_t bcr; /* Cached BMCR value */ + uint8_t addr; /* Discovered PHY device address */ + uint8_t flags; /* Control flags */ +} PHY_CTRL; + +#endif /* __PHY_RTL8211F_H */ diff --git a/README.md b/README.md index 55f5b49..7fac033 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ All drivers refer the API Interface header file definitions published in the CMS - PHY_LAN8740A - PHY_LAN8741A - PHY_LAN8742A +- PHY_RTL8211F - PHY_ST802RT1 ## Flash - Flash device drivers