From 8c9657063a78082297afe4d005a5966bbd5d0306 Mon Sep 17 00:00:00 2001 From: Bogdan Kolendovskyy Date: Tue, 30 Jan 2024 11:56:01 +0100 Subject: [PATCH] esp_eth: Add functions to access PHY using MDIO Specifically: - Set/get address - Read/write data at address with specified MDIO access function - Read/write both address and data with a single call --- .../esp_eth/include/esp_eth_phy_802_3.h | 95 +++++++++++++++- .../esp_eth/include/eth_phy_802_3_regs.h | 28 ++++- components/esp_eth/src/esp_eth_phy_802_3.c | 104 +++++++++++++++++- 3 files changed, 224 insertions(+), 3 deletions(-) diff --git a/components/esp_eth/include/esp_eth_phy_802_3.h b/components/esp_eth/include/esp_eth_phy_802_3.h index 5eabdba53d..3689d415c9 100644 --- a/components/esp_eth/include/esp_eth_phy_802_3.h +++ b/components/esp_eth/include/esp_eth_phy_802_3.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,6 +28,17 @@ typedef struct { int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */ } phy_802_3_t; +/** + * @brief IEEE 802.3 MMD modes enumeration + * + */ +typedef enum { + MMD_FUNC_ADDRESS = 0, + MMD_FUNC_DATA_NOINCR = 1, + MMD_FUNC_DATA_RWINCR = 2, + MMD_FUNC_DATA_WINCR = 3 +} esp_eth_phy_802_3_mmd_func_t; + /** * @brief Set Ethernet mediator * @@ -247,6 +258,88 @@ esp_err_t esp_eth_phy_802_3_read_oui(phy_802_3_t *phy_802_3, uint32_t *oui); */ esp_err_t esp_eth_phy_802_3_read_manufac_info(phy_802_3_t *phy_802_3, uint8_t *model, uint8_t *rev); +/** + * @brief Reads MDIO device's internal address register + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param devaddr Address of MDIO device + * @param[out] mmd_addr Current address stored in device's register + * @return + * - ESP_OK: Address register read successfuly + * - ESP_FAIL: Address register read failed because of some error occured + * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) + */ +esp_err_t esp_eth_phy_802_3_get_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t *mmd_addr); + +/** + * @brief Write to DIO device's internal address register + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param devaddr Address of MDIO device + * @param[out] mmd_addr New value of MDIO device's address register value + * @return + * - ESP_OK: Address register written to successfuly + * - ESP_FAIL: Address register write failed because of some error occured + * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) + */ +esp_err_t esp_eth_phy_802_3_set_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr); + +/** + * @brief Read data of MDIO device's memory at address register + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param devaddr Address of MDIO device + * @param function MMD function + * @param[out] data Data read from the device's memory + * @return + * - ESP_OK: Memory read successfuly + * - ESP_FAIL: Memory read failed because of some error occured + * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) or MMD access function is invalid + */ +esp_err_t esp_eth_phy_802_3_read_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t *data); + +/** + * @brief Write data to MDIO device's memory at address register + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param devaddr Address of MDIO device + * @param function MMD function + * @param[out] data Data to write to the device's memory + * @return + * - ESP_OK: Memory written successfuly + * - ESP_FAIL: Memory write failed because of some error occured + * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) or MMD access function is invalid + */ +esp_err_t esp_eth_phy_802_3_write_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t data); + +/** + * @brief Set MMD address to mmd_addr with function MMD_FUNC_NOINCR and read contents to *data + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param devaddr Address of MDIO device + * @param mmd_addr Address of MDIO device register + * @param[out] data Data read from the device's memory + * @return + * - ESP_OK: Memory read successfuly + * - ESP_FAIL: Memory read failed because of some error occured + * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) + */ +esp_err_t esp_eth_phy_802_3_read_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t *data); + +/** + * @brief Set MMD address to mmd_addr with function MMD_FUNC_NOINCR and write data + * + * @param phy_802_3 IEEE 802.3 PHY object infostructure + * @param devaddr Address of MDIO device + * @param mmd_addr Address of MDIO device register + * @param[out] data Data to write to the device's memory + * @return + * - ESP_OK: Memory written to successfuly + * - ESP_FAIL: Memory write failed because of some error occured + * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) + */ +esp_err_t esp_eth_phy_802_3_write_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t data); + /** * @brief Returns address to parent IEEE 802.3 PHY object infostructure * diff --git a/components/esp_eth/include/eth_phy_802_3_regs.h b/components/esp_eth/include/eth_phy_802_3_regs.h index bdecddf0c4..1995f992ec 100644 --- a/components/esp_eth/include/eth_phy_802_3_regs.h +++ b/components/esp_eth/include/eth_phy_802_3_regs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -154,6 +154,32 @@ typedef union { } aner_reg_t; #define ETH_PHY_ANER_REG_ADDR (0x06) +/** + * @brief MMD Access control register + * + */ +typedef union { + struct { + uint32_t devaddr : 5; /*!< MMD address */ + uint32_t reserved0 : 9; /*!< Reserved */ + uint32_t function : 2; /*!< MMD function */ + }; + uint32_t val; +} mmdctrl_reg_t; +#define ETH_PHY_MMDCTRL_REG_ADDR (0x0D) + +/** + * @brief MMD Access address register + * + */ +typedef union { + struct { + uint32_t adrdata : 16; /*!< MMD address/data */ + }; + uint32_t val; +} mmdad_reg_t; +#define ETH_PHY_MMDAD_REG_ADDR (0x0E) + #ifdef __cplusplus } #endif diff --git a/components/esp_eth/src/esp_eth_phy_802_3.c b/components/esp_eth/src/esp_eth_phy_802_3.c index 785a0c0feb..36ad732c19 100644 --- a/components/esp_eth/src/esp_eth_phy_802_3.c +++ b/components/esp_eth/src/esp_eth_phy_802_3.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -469,6 +469,108 @@ err: return ret; } +esp_err_t esp_eth_phy_802_3_get_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t *mmd_addr) +{ + esp_err_t ret = ESP_OK; + esp_eth_mediator_t *eth = phy_802_3->eth; + + ESP_GOTO_ON_FALSE(devaddr <= 31, ESP_ERR_INVALID_ARG, err, TAG, "MMD device address can not be greater then 31 (0x1F)"); + + mmdctrl_reg_t mmdctrl; + mmdad_reg_t mmdad; + mmdctrl.function = MMD_FUNC_ADDRESS; + mmdctrl.devaddr = devaddr; + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_MMDCTRL_REG_ADDR, mmdctrl.val), err, TAG, "write MMDCTRL failed"); + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_MMDAD_REG_ADDR, &mmdad.val), err, TAG, "read MMDAD failed"); + *mmd_addr = mmdad.adrdata; + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_eth_phy_802_3_set_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr) +{ + esp_err_t ret = ESP_OK; + esp_eth_mediator_t *eth = phy_802_3->eth; + + ESP_GOTO_ON_FALSE(devaddr <= 31, ESP_ERR_INVALID_ARG, err, TAG, "MMD device address can not be greater then 31 (0x1F)"); + + mmdctrl_reg_t mmdctrl; + mmdad_reg_t mmdad; + mmdctrl.function = MMD_FUNC_ADDRESS; + mmdctrl.devaddr = devaddr; + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_MMDCTRL_REG_ADDR, mmdctrl.val), err, TAG, "write MMDCTRL failed"); + mmdad.adrdata = mmd_addr; + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_MMDAD_REG_ADDR, mmdad.val), err, TAG, "write MMDAD failed"); + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_eth_phy_802_3_read_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t *data) +{ + esp_err_t ret = ESP_OK; + esp_eth_mediator_t *eth = phy_802_3->eth; + + ESP_GOTO_ON_FALSE(devaddr <= 31, ESP_ERR_INVALID_ARG, err, TAG, "MMD device address can not be greater then 31 (0x1F)"); + ESP_GOTO_ON_FALSE(function != MMD_FUNC_ADDRESS, ESP_ERR_INVALID_ARG, err, TAG, "Invalid MMD mode for accessing data"); + + mmdctrl_reg_t mmdctrl; + mmdad_reg_t mmdad; + mmdctrl.devaddr = devaddr; + mmdctrl.function = function; + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_MMDCTRL_REG_ADDR, mmdctrl.val), err, TAG, "write MMDCTRL failed"); + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_MMDAD_REG_ADDR, &mmdad.val), err, TAG, "read MMDAD failed"); + *data = mmdad.adrdata; + + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_eth_phy_802_3_write_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t data) +{ + esp_err_t ret = ESP_OK; + esp_eth_mediator_t *eth = phy_802_3->eth; + + ESP_GOTO_ON_FALSE(devaddr <= 31, ESP_ERR_INVALID_ARG, err, TAG, "MMD device address can not be greater then 31 (0x1F)"); + ESP_GOTO_ON_FALSE(function != MMD_FUNC_ADDRESS, ESP_ERR_INVALID_ARG, err, TAG, "Invalid MMD function for accessing data"); + + mmdctrl_reg_t mmdctrl; + mmdad_reg_t mmdad; + mmdctrl.devaddr = devaddr; + mmdctrl.function = function; + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_MMDCTRL_REG_ADDR, mmdctrl.val), err, TAG, "write MMDCTRL failed"); + mmdad.adrdata = data; + ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, phy_802_3->addr, ETH_PHY_MMDAD_REG_ADDR, mmdad.val), err, TAG, "read MMDAD failed"); + + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_eth_phy_802_3_read_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t *data){ + esp_err_t ret = ESP_OK; + + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_set_mmd_addr(phy_802_3, devaddr, mmd_addr), err, TAG, "Set MMD address failed"); + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_read_mmd_data(phy_802_3, devaddr, MMD_FUNC_DATA_NOINCR, data), err, TAG, "Read MMD data failed"); + + return ESP_OK; +err: + return ret; +} + +esp_err_t esp_eth_phy_802_3_write_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t data){ + esp_err_t ret = ESP_OK; + + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_set_mmd_addr(phy_802_3, devaddr, mmd_addr), err, TAG, "Set MMD address failed"); + ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_write_mmd_data(phy_802_3, devaddr, MMD_FUNC_DATA_NOINCR, data), err, TAG, "Write MMD data failed"); + + return ESP_OK; +err: + return ret; +} + esp_err_t esp_eth_phy_802_3_obj_config_init(phy_802_3_t *phy_802_3, const eth_phy_config_t *config) { esp_err_t ret = ESP_OK;