feat(esp_eth): added ioctl option to read/write PHY registers

LAN87xx: Added extra delay after setting PHY speed
This commit is contained in:
Ondrej Kosta 2023-11-06 14:43:26 +01:00
parent 294c2bd70d
commit 78f791d4d5
3 changed files with 46 additions and 3 deletions

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -121,6 +121,15 @@ typedef struct {
esp_err_t (*write_phy_reg)(esp_eth_handle_t eth_handle, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value);
} esp_eth_config_t;
/**
* @brief Data structure to Read/Write PHY register via ioctl API
*
*/
typedef struct {
uint32_t reg_addr; /*!< PHY register address */
uint32_t *reg_value_p; /*!< Pointer to a memory where the register value is read/written */
} esp_eth_phy_reg_rw_data_t;
/**
* @brief Command list for ioctl API
*
@ -139,6 +148,8 @@ typedef enum {
ETH_CMD_G_DUPLEX_MODE, /*!< Get Duplex mode */
ETH_CMD_S_DUPLEX_MODE, /*!< Set Duplex mode */
ETH_CMD_S_PHY_LOOPBACK, /*!< Set PHY loopback */
ETH_CMD_READ_PHY_REG, /*!< Read PHY register */
ETH_CMD_WRITE_PHY_REG, /*!< Write PHY register */
ETH_CMD_CUSTOM_MAC_CMDS = 0x0FFF, // Offset for start of MAC custom commands
ETH_CMD_CUSTOM_PHY_CMDS = 0x1FFF, // Offset for start of PHY custom commands

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -466,7 +466,23 @@ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data)
case ETH_CMD_S_PHY_LOOPBACK:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set loopback to null");
ESP_GOTO_ON_ERROR(phy->loopback(phy, *(bool *)data), err, TAG, "configuration of phy loopback mode failed");
break;
case ETH_CMD_READ_PHY_REG:
uint32_t phy_addr;
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info");
esp_eth_phy_reg_rw_data_t *phy_r_data = (esp_eth_phy_reg_rw_data_t *)data;
ESP_GOTO_ON_FALSE(phy_r_data->reg_value_p, ESP_ERR_INVALID_ARG, err, TAG, "can't read registers to null");
ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed");
ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_read(&eth_driver->mediator,
phy_addr, phy_r_data->reg_addr, phy_r_data->reg_value_p), err, TAG, "failed to read PHY register");
break;
case ETH_CMD_WRITE_PHY_REG:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info");
esp_eth_phy_reg_rw_data_t *phy_w_data = (esp_eth_phy_reg_rw_data_t *)data;
ESP_GOTO_ON_FALSE(phy_w_data->reg_value_p, ESP_ERR_INVALID_ARG, err, TAG, "can't write registers from null");
ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed");
ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_write(&eth_driver->mediator,
phy_addr, phy_w_data->reg_addr, *(phy_w_data->reg_value_p)), err, TAG, "failed to write PHY register");
break;
default:
if (phy->custom_ioctl != NULL && cmd >= ETH_CMD_CUSTOM_PHY_CMDS) {

View File

@ -6,6 +6,8 @@
#include <string.h>
#include <stdlib.h>
#include <sys/cdefs.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_phy_802_3.h"
@ -317,6 +319,19 @@ err:
return ret;
}
static esp_err_t lan87xx_set_speed(esp_eth_phy_t *phy, eth_speed_t speed)
{
esp_err_t ret = ESP_OK;
phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy);
/* It was observed that a delay needs to be introduced after setting speed and prior driver's start.
Otherwise, the very first read of PHY registers is not valid data (0xFFFF's). */
ESP_GOTO_ON_ERROR(esp_eth_phy_802_3_set_speed(phy_802_3, speed), err, TAG, "set speed failed");
vTaskDelay(pdMS_TO_TICKS(10));
err:
return ret;
}
static esp_err_t lan87xx_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
@ -359,6 +374,7 @@ esp_eth_phy_t *esp_eth_phy_new_lan87xx(const eth_phy_config_t *config)
lan87xx->phy_802_3.parent.get_link = lan87xx_get_link;
lan87xx->phy_802_3.parent.autonego_ctrl = lan87xx_autonego_ctrl;
lan87xx->phy_802_3.parent.loopback = lan87xx_loopback;
lan87xx->phy_802_3.parent.set_speed = lan87xx_set_speed;
return &lan87xx->phy_802_3.parent;
err: