ethernet: support phy addr auto detect

This commit is contained in:
morris 2019-12-23 17:06:02 +08:00
parent f687cedebe
commit 197d5d7378
9 changed files with 94 additions and 22 deletions

View file

@ -6,7 +6,7 @@ set(priv_requires)
# If Ethernet disabled in Kconfig, this is a config-only component
if(CONFIG_ETH_ENABLED)
set(srcs "src/esp_eth.c")
set(srcs "src/esp_eth.c" "src/esp_eth_phy.c")
set(include "include")
set(priv_requires "driver" "log") # require "driver" for using some GPIO APIs

View file

@ -206,6 +206,19 @@ typedef enum {
*/
ESP_EVENT_DECLARE_BASE(ETH_EVENT);
/**
* @brief Detect PHY address
*
* @param[in] eth: mediator of Ethernet driver
* @param[out] detected_addr: a valid address after detection
* @return
* - ESP_OK: detect phy address successfully
* - ESP_ERR_INVALID_ARG: invalid parameter
* - ESP_ERR_NOT_FOUND: can't detect any PHY device
* - ESP_FAIL: detect phy address failed because some error occurred
*/
esp_err_t esp_eth_detect_phy_addr(esp_eth_mediator_t *eth, uint32_t *detected_addr);
#ifdef __cplusplus
}
#endif

View file

@ -21,6 +21,8 @@ extern "C" {
#include "esp_eth_com.h"
#include "sdkconfig.h"
#define ESP_ETH_PHY_ADDR_AUTO (-1)
/**
* @brief Ethernet PHY
*
@ -176,7 +178,7 @@ struct esp_eth_phy_s {
*
*/
typedef struct {
uint32_t phy_addr; /*!< PHY address */
int32_t phy_addr; /*!< PHY address, set -1 to enable PHY address detection at initialization stage */
uint32_t reset_timeout_ms; /*!< Reset timeout value (Unit: ms) */
uint32_t autonego_timeout_ms; /*!< Auto-negotiation timeout value (Unit: ms) */
int reset_gpio_num; /*!< Reset GPIO number, -1 means no hardware reset */
@ -186,12 +188,12 @@ typedef struct {
* @brief Default configuration for Ethernet PHY object
*
*/
#define ETH_PHY_DEFAULT_CONFIG() \
{ \
.phy_addr = 1, \
.reset_timeout_ms = 100, \
.autonego_timeout_ms = 4000, \
.reset_gpio_num = 5, \
#define ETH_PHY_DEFAULT_CONFIG() \
{ \
.phy_addr = ESP_ETH_PHY_ADDR_AUTO, \
.reset_timeout_ms = 100, \
.autonego_timeout_ms = 4000, \
.reset_gpio_num = 5, \
}
/**

View file

@ -0,0 +1,44 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// 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 <string.h>
#include <stdlib.h>
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
static const char *TAG = "esp_eth.phy";
esp_err_t esp_eth_detect_phy_addr(esp_eth_mediator_t *eth, uint32_t *detected_addr)
{
if (!eth || !detected_addr) {
ESP_LOGE(TAG, "eth and detected_addr can't be null");
return ESP_ERR_INVALID_ARG;
}
uint32_t addr_try = 0;
uint32_t reg_value = 0;
for (; addr_try < 16; addr_try++) {
eth->phy_reg_read(eth, addr_try, ETH_PHY_IDR1_REG_ADDR, &reg_value);
if (reg_value != 0xFFFF && reg_value != 0x00) {
*detected_addr = addr_try;
break;
}
}
if (addr_try < 16) {
ESP_LOGD(TAG, "Found PHY address: %d", addr_try);
return ESP_OK;
} else {
ESP_LOGE(TAG, "No PHY device detected");
return ESP_ERR_NOT_FOUND;
}
}

View file

@ -285,6 +285,10 @@ static esp_err_t dm9051_init(esp_eth_phy_t *phy)
{
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
// Detect PHY address
if (dm9051->addr == ESP_ETH_PHY_ADDR_AUTO) {
PHY_CHECK(esp_eth_detect_phy_addr(eth, &dm9051->addr) == ESP_OK, "Detect PHY address failed", err);
}
/* Power on Ethernet PHY */
PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
@ -315,7 +319,6 @@ err:
esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err);
phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t));
PHY_CHECK(dm9051, "calloc dm9051 failed", err);
dm9051->addr = config->phy_addr;

View file

@ -41,7 +41,7 @@ static const char *TAG = "dp83848";
typedef union {
struct {
uint32_t link_status : 1; /* Link Status */
uint32_t speed_status : 1; /* Link Status */
uint32_t speed_status : 1; /* Speed Status */
uint32_t duplex_status : 1; /* Duplex Status */
uint32_t loopback_status : 1; /* MII Loopback */
uint32_t auto_nego_complete : 1; /* Auto-Negotiation Complete */
@ -98,17 +98,14 @@ static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
esp_eth_mediator_t *eth = dp83848->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
physts_reg_t physts;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
"read PHYSTS failed", err);
eth_link_t link = physts.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dp83848->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
"read PHYSTS failed", err);
if (physts.speed_status) {
speed = ETH_SPEED_10M;
} else {
@ -283,6 +280,10 @@ static esp_err_t dp83848_init(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
// Detect PHY address
if (dp83848->addr == ESP_ETH_PHY_ADDR_AUTO) {
PHY_CHECK(esp_eth_detect_phy_addr(eth, &dp83848->addr) == ESP_OK, "Detect PHY address failed", err);
}
/* Power on Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */

View file

@ -128,17 +128,14 @@ static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101)
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
cssr_reg_t cssr;
bmsr_reg_t bmsr;
PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page 16 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK,
"read CSSR failed", err);
eth_link_t link = cssr.link_up ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (ip101->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK,
"read CSSR failed", err);
switch (cssr.op_mode) {
case 1: //10M Half
speed = ETH_SPEED_10M;
@ -320,6 +317,10 @@ static esp_err_t ip101_init(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
// Detect PHY address
if (ip101->addr == ESP_ETH_PHY_ADDR_AUTO) {
PHY_CHECK(esp_eth_detect_phy_addr(eth, &ip101->addr) == ESP_OK, "Detect PHY address failed", err);
}
/* Power on Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */

View file

@ -364,6 +364,10 @@ static esp_err_t lan8720_init(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
// Detect PHY address
if (lan8720->addr == ESP_ETH_PHY_ADDR_AUTO) {
PHY_CHECK(esp_eth_detect_phy_addr(eth, &lan8720->addr) == ESP_OK, "Detect PHY address failed", err);
}
/* Power on Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */

View file

@ -271,6 +271,10 @@ static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
// Detect PHY address
if (rtl8201->addr == ESP_ETH_PHY_ADDR_AUTO) {
PHY_CHECK(esp_eth_detect_phy_addr(eth, &rtl8201->addr) == ESP_OK, "Detect PHY address failed", err);
}
/* Power on Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */