mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
feat(esp_eth): added ioctl option to read/write PHY registers
LAN87xx: Added extra delay after setting PHY speed
This commit is contained in:
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
@ -229,7 +229,7 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_
|
||||
ESP_GOTO_ON_ERROR(phy->init(phy), err, TAG, "init phy failed");
|
||||
// get default status of PHY autonegotiation (ultimately may also indicate if it is supported)
|
||||
ESP_GOTO_ON_ERROR(phy->autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, ð_driver->auto_nego_en),
|
||||
err, TAG, "get autonegotiation status failed");
|
||||
err, TAG, "get autonegotiation status failed");
|
||||
ESP_LOGD(TAG, "new ethernet driver @%p", eth_driver);
|
||||
*out_hdl = eth_driver;
|
||||
|
||||
@ -311,11 +311,11 @@ esp_err_t esp_eth_stop(esp_eth_handle_t hdl)
|
||||
ESP_GOTO_ON_ERROR(esp_timer_stop(eth_driver->check_link_timer), err, TAG, "stop link timer failed");
|
||||
|
||||
eth_link_t expected_link = ETH_LINK_UP;
|
||||
if (atomic_compare_exchange_strong(ð_driver->link, &expected_link, ETH_LINK_DOWN)){
|
||||
if (atomic_compare_exchange_strong(ð_driver->link, &expected_link, ETH_LINK_DOWN)) {
|
||||
// MAC is stopped by setting link down
|
||||
ESP_GOTO_ON_ERROR(mac->set_link(mac, ETH_LINK_DOWN), err, TAG, "ethernet mac set link failed");
|
||||
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, ð_driver, sizeof(esp_eth_driver_t *), 0), err,
|
||||
TAG, "send ETHERNET_EVENT_DISCONNECTED event failed");
|
||||
TAG, "send ETHERNET_EVENT_DISCONNECTED event failed");
|
||||
}
|
||||
|
||||
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, ð_driver, sizeof(esp_eth_driver_t *), 0),
|
||||
@ -466,8 +466,27 @@ 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(ð_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: {
|
||||
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_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(ð_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) {
|
||||
ret = phy->custom_ioctl(phy, cmd, data);
|
||||
|
@ -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:
|
||||
|
Reference in New Issue
Block a user