Merge branch 'refactor/using_generic_error_check_in_esp_eth' into 'master'

esp_eth: apply generic error check macros

Closes IDF-3030 and IDF-3031

See merge request espressif/esp-idf!13007
This commit is contained in:
David Čermák 2021-04-13 16:48:25 +00:00
commit 6d4b93c94e
13 changed files with 671 additions and 835 deletions

View File

@ -19,7 +19,7 @@ if(CONFIG_ETH_ENABLED)
endif()
if(CONFIG_ETH_USE_ESP32_EMAC)
list(APPEND srcs "src/esp_eth_mac_esp32.c"
list(APPEND srcs "src/esp_eth_mac_esp.c"
"src/esp_eth_phy_dp83848.c"
"src/esp_eth_phy_ip101.c"
"src/esp_eth_phy_ksz80xx.c"

View File

@ -14,6 +14,7 @@
#include <sys/cdefs.h>
#include <stdatomic.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "freertos/FreeRTOS.h"
@ -22,16 +23,6 @@
#include "esp_heap_caps.h"
static const char *TAG = "esp_eth";
#define ETH_CHECK(a, str, goto_tag, ret_value, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
ESP_EVENT_DEFINE_BASE(ETH_EVENT);
@ -108,48 +99,48 @@ static esp_err_t eth_on_state_changed(esp_eth_mediator_t *eth, esp_eth_state_t s
switch (state) {
case ETH_STATE_LLINIT: {
if (eth_driver->on_lowlevel_init_done) {
ETH_CHECK(eth_driver->on_lowlevel_init_done(eth_driver) == ESP_OK, "extra lowlevel init failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(eth_driver->on_lowlevel_init_done(eth_driver), err, TAG, "extra lowlevel init failed");
}
break;
}
case ETH_STATE_DEINIT: {
if (eth_driver->on_lowlevel_deinit_done) {
ETH_CHECK(eth_driver->on_lowlevel_deinit_done(eth_driver) == ESP_OK, "extra lowlevel deinit failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(eth_driver->on_lowlevel_deinit_done(eth_driver), err, TAG, "extra lowlevel deinit failed");
}
break;
}
case ETH_STATE_LINK: {
eth_link_t link = (eth_link_t)args;
ETH_CHECK(mac->set_link(mac, link) == ESP_OK, "ethernet mac set link failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->set_link(mac, link), err, TAG, "ethernet mac set link failed");
eth_driver->link = link;
if (link == ETH_LINK_UP) {
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_CONNECTED event failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &eth_driver, sizeof(esp_eth_driver_t *), 0), err,
TAG, "send ETHERNET_EVENT_CONNECTED event failed");
} else if (link == ETH_LINK_DOWN) {
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_DISCONNECTED event failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &eth_driver, sizeof(esp_eth_driver_t *), 0), err,
TAG, "send ETHERNET_EVENT_DISCONNECTED event failed");
}
break;
}
case ETH_STATE_SPEED: {
eth_speed_t speed = (eth_speed_t)args;
ETH_CHECK(mac->set_speed(mac, speed) == ESP_OK, "ethernet mac set speed failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->set_speed(mac, speed), err, TAG, "ethernet mac set speed failed");
eth_driver->speed = speed;
break;
}
case ETH_STATE_DUPLEX: {
eth_duplex_t duplex = (eth_duplex_t)args;
ETH_CHECK(mac->set_duplex(mac, duplex) == ESP_OK, "ethernet mac set duplex failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->set_duplex(mac, duplex), err, TAG, "ethernet mac set duplex failed");
eth_driver->duplex = duplex;
break;
}
case ETH_STATE_PAUSE: {
uint32_t peer_pause_ability = (uint32_t)args;
ETH_CHECK(mac->set_peer_pause_ability(mac, peer_pause_ability) == ESP_OK, "ethernet mac set peer pause ability failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->set_peer_pause_ability(mac, peer_pause_ability), err, TAG, "ethernet mac set peer pause ability failed");
break;
}
default:
ETH_CHECK(false, "unknown ethernet state: %d", err, ESP_ERR_INVALID_ARG, state);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown ethernet state: %d", state);
break;
}
return ESP_OK;
@ -175,14 +166,14 @@ static void eth_check_link_timer_cb(TimerHandle_t xTimer)
esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_t *out_hdl)
{
esp_err_t ret = ESP_OK;
ETH_CHECK(config, "eth config can't be null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(out_hdl, "eth handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(config, ESP_ERR_INVALID_ARG, err, TAG, "eth config can't be null");
ESP_GOTO_ON_FALSE(out_hdl, ESP_ERR_INVALID_ARG, err, TAG, "eth handle can't be null");
esp_eth_mac_t *mac = config->mac;
esp_eth_phy_t *phy = config->phy;
ETH_CHECK(mac && phy, "can't set eth->mac or eth->phy to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(mac && phy, ESP_ERR_INVALID_ARG, err, TAG, "can't set eth->mac or eth->phy to null");
// eth_driver contains an atomic variable, which should not be put in PSRAM
esp_eth_driver_t *eth_driver = heap_caps_calloc(1, sizeof(esp_eth_driver_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ETH_CHECK(eth_driver, "request memory for eth_driver failed", err, ESP_ERR_NO_MEM);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_NO_MEM, err, TAG, "request memory for eth_driver failed");
atomic_init(&eth_driver->ref_count, 1);
atomic_init(&eth_driver->fsm, ESP_ETH_FSM_STOP);
eth_driver->mac = mac;
@ -199,13 +190,13 @@ esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_
eth_driver->mediator.on_state_changed = eth_on_state_changed;
/* some PHY can't output RMII clock if in reset state, so hardware reset PHY chip firstly */
phy->reset_hw(phy);
ETH_CHECK(mac->set_mediator(mac, &eth_driver->mediator) == ESP_OK, "set mediator for mac failed", err_mediator, ESP_FAIL);
ETH_CHECK(phy->set_mediator(phy, &eth_driver->mediator) == ESP_OK, "set mediator for phy failed", err_mediator, ESP_FAIL);
ETH_CHECK(mac->init(mac) == ESP_OK, "init mac failed", err_init_mac, ESP_FAIL);
ETH_CHECK(phy->init(phy) == ESP_OK, "init phy failed", err_init_phy, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->set_mediator(mac, &eth_driver->mediator), err_mediator, TAG, "set mediator for mac failed");
ESP_GOTO_ON_ERROR(phy->set_mediator(phy, &eth_driver->mediator), err_mediator, TAG, "set mediator for phy failed");
ESP_GOTO_ON_ERROR(mac->init(mac), err_init_mac, TAG, "init mac failed");
ESP_GOTO_ON_ERROR(phy->init(phy), err_init_phy, TAG, "init phy failed");
eth_driver->check_link_timer = xTimerCreate("eth_link_timer", pdMS_TO_TICKS(config->check_link_period_ms), pdTRUE,
eth_driver, eth_check_link_timer_cb);
ETH_CHECK(eth_driver->check_link_timer, "create eth_link_timer failed", err_create_timer, ESP_FAIL);
ESP_GOTO_ON_FALSE(eth_driver->check_link_timer, ESP_FAIL, err_create_timer, TAG, "create eth_link_timer failed");
*out_hdl = (esp_eth_handle_t)eth_driver;
// for backward compatible to 4.0, and will get removed in 5.0
@ -230,7 +221,7 @@ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
// check if driver has started
esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP;
if (!atomic_compare_exchange_strong(&eth_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP)) {
@ -247,9 +238,9 @@ esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl)
}
esp_eth_mac_t *mac = eth_driver->mac;
esp_eth_phy_t *phy = eth_driver->phy;
ETH_CHECK(xTimerDelete(eth_driver->check_link_timer, 0) == pdPASS, "delete eth_link_timer failed", err, ESP_FAIL);
ETH_CHECK(phy->deinit(phy) == ESP_OK, "deinit phy failed", err, ESP_FAIL);
ETH_CHECK(mac->deinit(mac) == ESP_OK, "deinit mac failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(xTimerDelete(eth_driver->check_link_timer, 0) == pdPASS, ESP_FAIL, err, TAG, "delete eth_link_timer failed");
ESP_GOTO_ON_ERROR(phy->deinit(phy), err, TAG, "deinit phy failed");
ESP_GOTO_ON_ERROR(mac->deinit(mac), err, TAG, "deinit mac failed");
free(eth_driver);
return ESP_OK;
err:
@ -260,7 +251,7 @@ esp_err_t esp_eth_start(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
// check if driver has started
esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP;
if (!atomic_compare_exchange_strong(&eth_driver->fsm, &expected_fsm, ESP_ETH_FSM_START)) {
@ -268,11 +259,9 @@ esp_err_t esp_eth_start(esp_eth_handle_t hdl)
ret = ESP_ERR_INVALID_STATE;
goto err;
}
ETH_CHECK(eth_driver->phy->reset(eth_driver->phy) == ESP_OK, "reset phy failed", err, ESP_FAIL);
ETH_CHECK(xTimerStart(eth_driver->check_link_timer, 0) == pdPASS,
"start eth_link_timer failed", err, ESP_FAIL);
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_START event failed", err_event, ESP_FAIL);
ESP_GOTO_ON_ERROR(eth_driver->phy->reset(eth_driver->phy), err, TAG, "reset phy failed");
ESP_GOTO_ON_FALSE(xTimerStart(eth_driver->check_link_timer, 0), ESP_FAIL, err, TAG, "start eth_link_timer failed");
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, &eth_driver, sizeof(esp_eth_driver_t *), 0), err_event, TAG, "send ETHERNET_EVENT_START event failed");
return ESP_OK;
err_event:
xTimerStop(eth_driver->check_link_timer, 0);
@ -284,7 +273,7 @@ esp_err_t esp_eth_stop(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
// check if driver has started
esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_START;
if (!atomic_compare_exchange_strong(&eth_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP)) {
@ -293,11 +282,9 @@ esp_err_t esp_eth_stop(esp_eth_handle_t hdl)
goto err;
}
esp_eth_mac_t *mac = eth_driver->mac;
ETH_CHECK(mac->stop(mac) == ESP_OK, "stop mac failed", err, ESP_FAIL);
ETH_CHECK(xTimerStop(eth_driver->check_link_timer, 0) == pdPASS,
"stop eth_link_timer failed", err, ESP_FAIL);
ETH_CHECK(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, &eth_driver, sizeof(eth_driver), 0) == ESP_OK,
"send ETHERNET_EVENT_STOP event failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->stop(mac), err, TAG, "stop mac failed");
ESP_GOTO_ON_FALSE(xTimerStop(eth_driver->check_link_timer, 0), ESP_FAIL, err, TAG, "stop eth_link_timer failed");
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, &eth_driver, sizeof(esp_eth_driver_t *), 0), err, TAG, "send ETHERNET_EVENT_STOP event failed");
return ESP_OK;
err:
return ret;
@ -310,7 +297,7 @@ esp_err_t esp_eth_update_input_path(
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
eth_driver->priv = priv;
eth_driver->stack_input = stack_input;
return ESP_OK;
@ -322,9 +309,9 @@ esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, void *buf, size_t length)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(buf, "can't set buf to null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(length, "buf length can't be zero", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(buf, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf to null");
ESP_GOTO_ON_FALSE(length, ESP_ERR_INVALID_ARG, err, TAG, "buf length can't be zero");
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
esp_eth_mac_t *mac = eth_driver->mac;
return mac->transmit(mac, buf, length);
err:
@ -335,9 +322,9 @@ esp_err_t esp_eth_receive(esp_eth_handle_t hdl, uint8_t *buf, uint32_t *length)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(*length > 60, "length can't be less than 60", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(buf && length, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf and length to null");
ESP_GOTO_ON_FALSE(*length > 60, ESP_ERR_INVALID_ARG, err, TAG, "length can't be less than 60");
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
esp_eth_mac_t *mac = eth_driver->mac;
return mac->receive(mac, buf, length);
err:
@ -348,43 +335,43 @@ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
esp_eth_mac_t *mac = eth_driver->mac;
esp_eth_phy_t *phy = eth_driver->phy;
switch (cmd) {
case ETH_CMD_S_MAC_ADDR:
ETH_CHECK(data, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(mac->set_addr(mac, (uint8_t *)data) == ESP_OK, "set mac address failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
ESP_GOTO_ON_ERROR(mac->set_addr(mac, (uint8_t *)data), err, TAG, "set mac address failed");
break;
case ETH_CMD_G_MAC_ADDR:
ETH_CHECK(data, "no mem to store mac addr", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(mac->get_addr(mac, (uint8_t *)data) == ESP_OK, "get mac address failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store mac addr");
ESP_GOTO_ON_ERROR(mac->get_addr(mac, (uint8_t *)data), err, TAG, "get mac address failed");
break;
case ETH_CMD_S_PHY_ADDR:
ETH_CHECK(data, "can't set phy addr to null", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(phy->set_addr(phy, (uint32_t)data) == ESP_OK, "set phy address failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set phy addr to null");
ESP_GOTO_ON_ERROR(phy->set_addr(phy, (uint32_t)data), err, TAG, "set phy address failed");
break;
case ETH_CMD_G_PHY_ADDR:
ETH_CHECK(data, "no mem to store phy addr", err, ESP_ERR_INVALID_ARG);
ETH_CHECK(phy->get_addr(phy, (uint32_t *)data) == ESP_OK, "get phy address failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store phy addr");
ESP_GOTO_ON_ERROR(phy->get_addr(phy, (uint32_t *)data), err, TAG, "get phy address failed");
break;
case ETH_CMD_G_SPEED:
ETH_CHECK(data, "no mem to store speed value", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store speed value");
*(eth_speed_t *)data = eth_driver->speed;
break;
case ETH_CMD_S_PROMISCUOUS:
ETH_CHECK(mac->set_promiscuous(mac, (bool)data) == ESP_OK, "set promiscuous mode failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->set_promiscuous(mac, (bool)data), err, TAG, "set promiscuous mode failed");
break;
case ETH_CMD_S_FLOW_CTRL:
ETH_CHECK(mac->enable_flow_ctrl(mac, (bool)data) == ESP_OK, "enable mac flow control failed", err, ESP_FAIL);
ETH_CHECK(phy->advertise_pause_ability(phy, (uint32_t)data) == ESP_OK, "phy advertise pause ability failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->enable_flow_ctrl(mac, (bool)data), err, TAG, "enable mac flow control failed");
ESP_GOTO_ON_ERROR(phy->advertise_pause_ability(phy, (uint32_t)data), err, TAG, "phy advertise pause ability failed");
break;
case ETH_CMD_G_DUPLEX_MODE:
ETH_CHECK(data, "no mem to store duplex value", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store duplex value");
*(eth_duplex_t *)data = eth_driver->duplex;
break;
default:
ETH_CHECK(false, "unknown io command: %d", err, ESP_ERR_INVALID_ARG, cmd);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown io command: %d", cmd);
break;
}
return ESP_OK;
@ -396,7 +383,7 @@ esp_err_t esp_eth_increase_reference(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
atomic_fetch_add(&eth_driver->ref_count, 1);
return ESP_OK;
err:
@ -407,7 +394,7 @@ esp_err_t esp_eth_decrease_reference(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ETH_CHECK(eth_driver, "ethernet driver handle can't be null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
atomic_fetch_sub(&eth_driver->ref_count, 1);
return ESP_OK;
err:

View File

@ -18,6 +18,7 @@
#include "driver/spi_master.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "esp_system.h"
#include "esp_intr_alloc.h"
@ -31,17 +32,7 @@
#include "esp_rom_gpio.h"
#include "esp_rom_sys.h"
static const char *TAG = "emac_dm9051";
#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
static const char *TAG = "dm9051.mac";
#define DM9051_SPI_LOCK_TIMEOUT_MS (50)
#define DM9051_PHY_OPERATION_TIMEOUT_US (1000)
@ -206,7 +197,7 @@ static esp_err_t dm9051_get_mac_addr(emac_dm9051_t *emac)
{
esp_err_t ret = ESP_OK;
for (int i = 0; i < 6; i++) {
MAC_CHECK(dm9051_register_read(emac, DM9051_PAR + i, &emac->addr[i]) == ESP_OK, "read PAR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_PAR + i, &emac->addr[i]), err, TAG, "read PAR failed");
}
return ESP_OK;
err:
@ -220,7 +211,7 @@ static esp_err_t dm9051_set_mac_addr(emac_dm9051_t *emac)
{
esp_err_t ret = ESP_OK;
for (int i = 0; i < 6; i++) {
MAC_CHECK(dm9051_register_write(emac, DM9051_PAR + i, emac->addr[i]) == ESP_OK, "write PAR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_PAR + i, emac->addr[i]), err, TAG, "write PAR failed");
}
return ESP_OK;
err:
@ -234,12 +225,12 @@ static esp_err_t dm9051_clear_multicast_table(emac_dm9051_t *emac)
{
esp_err_t ret = ESP_OK;
/* rx broadcast packet control by bit7 of MAC register 1DH */
MAC_CHECK(dm9051_register_write(emac, DM9051_BCASTCR, 0x00) == ESP_OK, "write BCASTCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_BCASTCR, 0x00), err, TAG, "write BCASTCR failed");
for (int i = 0; i < 7; i++) {
MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + i, 0x00) == ESP_OK, "write MAR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MAR + i, 0x00), err, TAG, "write MAR failed");
}
/* enable receive broadcast paclets */
MAC_CHECK(dm9051_register_write(emac, DM9051_MAR + 7, 0x80) == ESP_OK, "write MAR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MAR + 7, 0x80), err, TAG, "write MAR failed");
return ESP_OK;
err:
return ret;
@ -252,21 +243,21 @@ static esp_err_t dm9051_reset(emac_dm9051_t *emac)
{
esp_err_t ret = ESP_OK;
/* power on phy */
MAC_CHECK(dm9051_register_write(emac, DM9051_GPR, 0x00) == ESP_OK, "write GPR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_GPR, 0x00), err, TAG, "write GPR failed");
/* mac and phy register won't be accesable within at least 1ms */
vTaskDelay(pdMS_TO_TICKS(10));
/* software reset */
uint8_t ncr = NCR_RST;
MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, ncr) == ESP_OK, "write NCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_NCR, ncr), err, TAG, "write NCR failed");
uint32_t to = 0;
for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_NCR, &ncr), err, TAG, "read NCR failed");
if (!(ncr & NCR_RST)) {
break;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(to < emac->sw_reset_timeout_ms / 10, ESP_ERR_TIMEOUT, err, TAG, "reset timeout");
return ESP_OK;
err:
return ret;
@ -279,12 +270,12 @@ static esp_err_t dm9051_verify_id(emac_dm9051_t *emac)
{
esp_err_t ret = ESP_OK;
uint8_t id[2];
MAC_CHECK(dm9051_register_read(emac, DM9051_VIDL, &id[0]) == ESP_OK, "read VIDL failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_read(emac, DM9051_VIDH, &id[1]) == ESP_OK, "read VIDH failed", err, ESP_FAIL);
MAC_CHECK(0x0A == id[1] && 0x46 == id[0], "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION);
MAC_CHECK(dm9051_register_read(emac, DM9051_PIDL, &id[0]) == ESP_OK, "read PIDL failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_read(emac, DM9051_PIDH, &id[1]) == ESP_OK, "read PIDH failed", err, ESP_FAIL);
MAC_CHECK(0x90 == id[1] && 0x51 == id[0], "wrong Product ID", err, ESP_ERR_INVALID_VERSION);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_VIDL, &id[0]), err, TAG, "read VIDL failed");
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_VIDH, &id[1]), err, TAG, "read VIDH failed");
ESP_GOTO_ON_FALSE(0x0A == id[1] && 0x46 == id[0], ESP_ERR_INVALID_VERSION, err, TAG, "wrong Vendor ID");
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_PIDL, &id[0]), err, TAG, "read PIDL failed");
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_PIDH, &id[1]), err, TAG, "read PIDH failed");
ESP_GOTO_ON_FALSE(0x90 == id[1] && 0x51 == id[0], ESP_ERR_INVALID_VERSION, err, TAG, "wrong Product ID");
return ESP_OK;
err:
return ret;
@ -297,36 +288,34 @@ static esp_err_t dm9051_setup_default(emac_dm9051_t *emac)
{
esp_err_t ret = ESP_OK;
/* disable wakeup */
MAC_CHECK(dm9051_register_write(emac, DM9051_NCR, 0x00) == ESP_OK, "write NCR failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_write(emac, DM9051_WCR, 0x00) == ESP_OK, "write WCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_NCR, 0x00), err, TAG, "write NCR failed");
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_WCR, 0x00), err, TAG, "write WCR failed");
/* stop transmitting, enable appending pad, crc for packets */
MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, 0x00) == ESP_OK, "write TCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_TCR, 0x00), err, TAG, "write TCR failed");
/* stop receiving, no promiscuous mode, no runt packet(size < 64bytes), not all multicast packets*/
/* discard long packet(size > 1522bytes) and crc error packet, enable watchdog */
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, RCR_DIS_LONG | RCR_DIS_CRC) == ESP_OK, "write RCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RCR, RCR_DIS_LONG | RCR_DIS_CRC), err, TAG, "write RCR failed");
/* retry late collision packet, at most two transmit command can be issued before transmit complete */
MAC_CHECK(dm9051_register_write(emac, DM9051_TCR2, TCR2_RLCP) == ESP_OK, "write TCR2 failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_TCR2, TCR2_RLCP), err, TAG, "write TCR2 failed");
/* enable auto transmit */
MAC_CHECK(dm9051_register_write(emac, DM9051_ATCR, ATCR_AUTO_TX) == ESP_OK, "write ATCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_ATCR, ATCR_AUTO_TX), err, TAG, "write ATCR failed");
/* generate checksum for UDP, TCP and IPv4 packets */
MAC_CHECK(dm9051_register_write(emac, DM9051_TCSCR, TCSCR_IPCSE | TCSCR_TCPCSE | TCSCR_UDPCSE) == ESP_OK,
"write TCSCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_TCSCR, TCSCR_IPCSE | TCSCR_TCPCSE | TCSCR_UDPCSE), err, TAG, "write TCSCR failed");
/* disable check sum for receive packets */
MAC_CHECK(dm9051_register_write(emac, DM9051_RCSCSR, 0x00) == ESP_OK, "write RCSCSR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RCSCSR, 0x00), err, TAG, "write RCSCSR failed");
/* interrupt pin config: push-pull output, active high */
MAC_CHECK(dm9051_register_write(emac, DM9051_INTCR, 0x00) == ESP_OK, "write INTCR failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_write(emac, DM9051_INTCKCR, 0x00) == ESP_OK, "write INTCKCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_INTCR, 0x00), err, TAG, "write INTCR failed");
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_INTCKCR, 0x00), err, TAG, "write INTCKCR failed");
/* no length limitation for rx packets */
MAC_CHECK(dm9051_register_write(emac, DM9051_RLENCR, 0x00) == ESP_OK, "write RLENCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RLENCR, 0x00), err, TAG, "write RLENCR failed");
/* 3K-byte for TX and 13K-byte for RX */
MAC_CHECK(dm9051_register_write(emac, DM9051_MEMSCR, 0x00) == ESP_OK, "write MEMSCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MEMSCR, 0x00), err, TAG, "write MEMSCR failed");
/* reset tx and rx memory pointer */
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX) == ESP_OK,
"write MPTRCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX | MPTRCR_RST_TX), err, TAG, "write MPTRCR failed");
/* clear network status: wakeup event, tx complete */
MAC_CHECK(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END) == ESP_OK, "write NSR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END), err, TAG, "write NSR failed");
/* clear interrupt status */
MAC_CHECK(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS) == ESP_OK, "write ISR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_ISR, ISR_CLR_STATUS), err, TAG, "write ISR failed");
return ESP_OK;
err:
return ret;
@ -337,14 +326,14 @@ static esp_err_t dm9051_enable_flow_ctrl(emac_dm9051_t *emac, bool enable)
esp_err_t ret = ESP_OK;
if (enable) {
/* send jam pattern (duration time = 1.15ms) when rx free space < 3k bytes */
MAC_CHECK(dm9051_register_write(emac, DM9051_BPTR, 0x3F) == ESP_OK, "write BPTR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_BPTR, 0x3F), err, TAG, "write BPTR failed");
/* flow control: high water threshold = 3k bytes, low water threshold = 8k bytes */
MAC_CHECK(dm9051_register_write(emac, DM9051_FCTR, 0x38) == ESP_OK, "write FCTR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_FCTR, 0x38), err, TAG, "write FCTR failed");
/* enable flow control */
MAC_CHECK(dm9051_register_write(emac, DM9051_FCR, FCR_FLOW_ENABLE) == ESP_OK, "write FCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_FCR, FCR_FLOW_ENABLE), err, TAG, "write FCR failed");
} else {
/* disable flow control */
MAC_CHECK(dm9051_register_write(emac, DM9051_FCR, 0) == ESP_OK, "write FCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_FCR, 0), err, TAG, "write FCR failed");
}
return ESP_OK;
err:
@ -359,12 +348,12 @@ static esp_err_t emac_dm9051_start(esp_eth_mac_t *mac)
esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
/* enable interrupt */
MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, IMR_ALL) == ESP_OK, "write IMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_IMR, IMR_ALL), err, TAG, "write IMR failed");
/* enable rx */
uint8_t rcr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_RCR, &rcr), err, TAG, "read RCR failed");
rcr |= RCR_RXEN;
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RCR, rcr), err, TAG, "write RCR failed");
return ESP_OK;
err:
return ret;
@ -378,12 +367,12 @@ static esp_err_t emac_dm9051_stop(esp_eth_mac_t *mac)
esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
/* disable interrupt */
MAC_CHECK(dm9051_register_write(emac, DM9051_IMR, 0x00) == ESP_OK, "write IMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_IMR, 0x00), err, TAG, "write IMR failed");
/* disable rx */
uint8_t rcr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_RCR, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_RCR, &rcr), err, TAG, "read RCR failed");
rcr &= ~RCR_RXEN;
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RCR, rcr), err, TAG, "write RCR failed");
return ESP_OK;
err:
return ret;
@ -438,7 +427,7 @@ static void emac_dm9051_task(void *arg)
static esp_err_t emac_dm9051_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac's mediator to null");
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
emac->eth = eth;
return ESP_OK;
@ -452,24 +441,21 @@ static esp_err_t emac_dm9051_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
/* check if phy access is in progress */
uint8_t epcr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_INVALID_STATE);
MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK,
"write EPAR failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRL, (uint8_t)(reg_value & 0xFF)) == ESP_OK,
"write EPDRL failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_write(emac, DM9051_EPDRH, (uint8_t)((reg_value >> 8) & 0xFF)) == ESP_OK,
"write EPDRH failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_EPCR, &epcr), err, TAG, "read EPCR failed");
ESP_GOTO_ON_FALSE(!(epcr & EPCR_ERRE), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)), err, TAG, "write EPAR failed");
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_EPDRL, (uint8_t)(reg_value & 0xFF)), err, TAG, "write EPDRL failed");
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_EPDRH, (uint8_t)((reg_value >> 8) & 0xFF)), err, TAG, "write EPDRH failed");
/* select PHY and select write operation */
MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, EPCR_EPOS | EPCR_ERPRW) == ESP_OK, "write EPCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_EPCR, EPCR_EPOS | EPCR_ERPRW), err, TAG, "write EPCR failed");
/* polling the busy flag */
uint32_t to = 0;
do {
esp_rom_delay_us(100);
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_EPCR, &epcr), err, TAG, "read EPCR failed");
to += 100;
} while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US);
MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(!(epcr & EPCR_ERRE), ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
return ESP_OK;
err:
return ret;
@ -478,28 +464,27 @@ err:
static esp_err_t emac_dm9051_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(reg_value, ESP_ERR_INVALID_ARG, err, TAG, "can't set reg_value to null");
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
/* check if phy access is in progress */
uint8_t epcr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
MAC_CHECK(!(epcr & 0x01), "phy is busy", err, ESP_ERR_INVALID_STATE);
MAC_CHECK(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)) == ESP_OK,
"write EPAR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_EPCR, &epcr), err, TAG, "read EPCR failed");
ESP_GOTO_ON_FALSE(!(epcr & 0x01), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_EPAR, (uint8_t)(((phy_addr << 6) & 0xFF) | phy_reg)), err, TAG, "write EPAR failed");
/* Select PHY and select read operation */
MAC_CHECK(dm9051_register_write(emac, DM9051_EPCR, 0x0C) == ESP_OK, "write EPCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_EPCR, 0x0C), err, TAG, "write EPCR failed");
/* polling the busy flag */
uint32_t to = 0;
do {
esp_rom_delay_us(100);
MAC_CHECK(dm9051_register_read(emac, DM9051_EPCR, &epcr) == ESP_OK, "read EPCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_EPCR, &epcr), err, TAG, "read EPCR failed");
to += 100;
} while ((epcr & EPCR_ERRE) && to < DM9051_PHY_OPERATION_TIMEOUT_US);
MAC_CHECK(!(epcr & EPCR_ERRE), "phy is busy", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(!(epcr & EPCR_ERRE), ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
uint8_t value_h = 0;
uint8_t value_l = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRH, &value_h) == ESP_OK, "read EPDRH failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &value_l) == ESP_OK, "read EPDRL failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_EPDRH, &value_h), err, TAG, "read EPDRH failed");
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_EPDRL, &value_l), err, TAG, "read EPDRL failed");
*reg_value = (value_h << 8) | value_l;
return ESP_OK;
err:
@ -509,10 +494,10 @@ err:
static esp_err_t emac_dm9051_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
memcpy(emac->addr, addr, 6);
MAC_CHECK(dm9051_set_mac_addr(emac) == ESP_OK, "set mac address failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_set_mac_addr(emac), err, TAG, "set mac address failed");
return ESP_OK;
err:
return ret;
@ -521,7 +506,7 @@ err:
static esp_err_t emac_dm9051_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
memcpy(addr, emac->addr, 6);
return ESP_OK;
@ -534,18 +519,18 @@ static esp_err_t emac_dm9051_set_link(esp_eth_mac_t *mac, eth_link_t link)
esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
uint8_t nsr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_NSR, &nsr), err, TAG, "read NSR failed");
switch (link) {
case ETH_LINK_UP:
MAC_CHECK(nsr & NSR_LINKST, "phy is not link up", err, ESP_ERR_INVALID_STATE);
MAC_CHECK(mac->start(mac) == ESP_OK, "dm9051 start failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(nsr & NSR_LINKST, ESP_ERR_INVALID_STATE, err, TAG, "phy is not link up");
ESP_GOTO_ON_ERROR(mac->start(mac), err, TAG, "dm9051 start failed");
break;
case ETH_LINK_DOWN:
MAC_CHECK(!(nsr & NSR_LINKST), "phy is not link down", err, ESP_ERR_INVALID_STATE);
MAC_CHECK(mac->stop(mac) == ESP_OK, "dm9051 stop failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(!(nsr & NSR_LINKST), ESP_ERR_INVALID_STATE, err, TAG, "phy is not link down");
ESP_GOTO_ON_ERROR(mac->stop(mac), err, TAG, "dm9051 stop failed");
break;
default:
MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown link status");
break;
}
return ESP_OK;
@ -558,18 +543,18 @@ static esp_err_t emac_dm9051_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
uint8_t nsr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_NSR, &nsr) == ESP_OK, "read NSR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_NSR, &nsr), err, TAG, "read NSR failed");
switch (speed) {
case ETH_SPEED_10M:
MAC_CHECK(nsr & NSR_SPEED, "phy speed is not at 10Mbps", err, ESP_ERR_INVALID_STATE);
ESP_GOTO_ON_FALSE(nsr & NSR_SPEED, ESP_ERR_INVALID_STATE, err, TAG, "phy speed is not at 10Mbps");
ESP_LOGD(TAG, "working in 10Mbps");
break;
case ETH_SPEED_100M:
MAC_CHECK(!(nsr & NSR_SPEED), "phy speed is not at 100Mbps", err, ESP_ERR_INVALID_STATE);
ESP_GOTO_ON_FALSE(!(nsr & NSR_SPEED), ESP_ERR_INVALID_STATE, err, TAG, "phy speed is not at 100Mbps");
ESP_LOGD(TAG, "working in 100Mbps");
break;
default:
MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown speed");
break;
}
return ESP_OK;
@ -582,18 +567,18 @@ static esp_err_t emac_dm9051_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
uint8_t ncr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_NCR, &ncr) == ESP_OK, "read NCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_NCR, &ncr), err, TAG, "read NCR failed");
switch (duplex) {
case ETH_DUPLEX_HALF:
ESP_LOGD(TAG, "working in half duplex");
MAC_CHECK(!(ncr & NCR_FDX), "phy is not at half duplex", err, ESP_ERR_INVALID_STATE);
ESP_GOTO_ON_FALSE(!(ncr & NCR_FDX), ESP_ERR_INVALID_STATE, err, TAG, "phy is not at half duplex");
break;
case ETH_DUPLEX_FULL:
ESP_LOGD(TAG, "working in full duplex");
MAC_CHECK(ncr & NCR_FDX, "phy is not at full duplex", err, ESP_ERR_INVALID_STATE);
ESP_GOTO_ON_FALSE(ncr & NCR_FDX, ESP_ERR_INVALID_STATE, err, TAG, "phy is not at full duplex");
break;
default:
MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown duplex");
break;
}
return ESP_OK;
@ -606,13 +591,13 @@ static esp_err_t emac_dm9051_set_promiscuous(esp_eth_mac_t *mac, bool enable)
esp_err_t ret = ESP_OK;
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
uint8_t rcr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_EPDRL, &rcr) == ESP_OK, "read RCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_EPDRL, &rcr), err, TAG, "read RCR failed");
if (enable) {
rcr |= RCR_PRMSC;
} else {
rcr &= ~RCR_PRMSC;
}
MAC_CHECK(dm9051_register_write(emac, DM9051_RCR, rcr) == ESP_OK, "write RCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_RCR, rcr), err, TAG, "write RCR failed");
return ESP_OK;
err:
return ret;
@ -645,16 +630,16 @@ static esp_err_t emac_dm9051_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
emac_dm9051_t *emac = __containerof(mac, emac_dm9051_t, parent);
/* Check if last transmit complete */
uint8_t tcr = 0;
MAC_CHECK(dm9051_register_read(emac, DM9051_TCR, &tcr) == ESP_OK, "read TCR failed", err, ESP_FAIL);
MAC_CHECK(!(tcr & TCR_TXREQ), "last transmit still in progress", err, ESP_ERR_INVALID_STATE);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_TCR, &tcr), err, TAG, "read TCR failed");
ESP_GOTO_ON_FALSE(!(tcr & TCR_TXREQ), ESP_ERR_INVALID_STATE, err, TAG, "last transmit still in progress");
/* set tx length */
MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLL, length & 0xFF) == ESP_OK, "write TXPLL failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_write(emac, DM9051_TXPLH, (length >> 8) & 0xFF) == ESP_OK, "write TXPLH failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_TXPLL, length & 0xFF), err, TAG, "write TXPLL failed");
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_TXPLH, (length >> 8) & 0xFF), err, TAG, "write TXPLH failed");
/* copy data to tx memory */
MAC_CHECK(dm9051_memory_write(emac, buf, length) == ESP_OK, "write memory failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_memory_write(emac, buf, length), err, TAG, "write memory failed");
/* issue tx polling command */
tcr |= TCR_TXREQ;
MAC_CHECK(dm9051_register_write(emac, DM9051_TCR, tcr) == ESP_OK, "write TCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_TCR, tcr), err, TAG, "write TCR failed");
return ESP_OK;
err:
return ret;
@ -669,20 +654,18 @@ static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
__attribute__((aligned(4))) dm9051_rx_header_t header; // SPI driver needs the rx buffer 4 byte align
emac->packets_remain = false;
/* dummy read, get the most updated data */
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte), err, TAG, "read MRCMDX failed");
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte), err, TAG, "read MRCMDX failed");
/* rxbyte must be 0xFF, 0 or 1 */
if (rxbyte > 1) {
MAC_CHECK(mac->stop(mac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->stop(mac), err, TAG, "stop dm9051 failed");
/* reset rx fifo pointer */
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK,
"write MPTRCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX), err, TAG, "write MPTRCR failed");
esp_rom_delay_us(10);
MAC_CHECK(mac->start(mac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL);
MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->start(mac), err, TAG, "start dm9051 failed");
ESP_GOTO_ON_FALSE(false, ESP_FAIL, err, TAG, "reset rx fifo pointer");
} else if (rxbyte) {
MAC_CHECK(dm9051_memory_peek(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK,
"peek rx header failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_memory_peek(emac, (uint8_t *)&header, sizeof(header)), err, TAG, "peek rx header failed");
rx_len = header.length_low + (header.length_high << 8);
/* check if the buffer can hold all the incoming data */
if (*length < rx_len - 4) {
@ -692,14 +675,13 @@ static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
ret = ESP_ERR_INVALID_SIZE;
goto err;
}
MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK,
"read rx header failed", err, ESP_FAIL);
MAC_CHECK(dm9051_memory_read(emac, buf, rx_len) == ESP_OK, "read rx data failed", err, ESP_FAIL);
MAC_CHECK(!(header.status & 0xBF), "receive status error: %xH", err, ESP_FAIL, header.status);
ESP_GOTO_ON_ERROR(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)), err, TAG, "read rx header failed");
ESP_GOTO_ON_ERROR(dm9051_memory_read(emac, buf, rx_len), err, TAG, "read rx data failed");
ESP_GOTO_ON_FALSE(!(header.status & 0xBF), ESP_FAIL, err, TAG, "receive status error: %xH", header.status);
*length = rx_len - 4; // substract the CRC length (4Bytes)
/* dummy read, get the most updated data */
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte) == ESP_OK, "read MRCMDX failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte), err, TAG, "read MRCMDX failed");
ESP_GOTO_ON_ERROR(dm9051_register_read(emac, DM9051_MRCMDX, &rxbyte), err, TAG, "read MRCMDX failed");
emac->packets_remain = rxbyte > 0;
}
return ESP_OK;
@ -718,17 +700,17 @@ static esp_err_t emac_dm9051_init(esp_eth_mac_t *mac)
gpio_set_intr_type(emac->int_gpio_num, GPIO_INTR_POSEDGE);
gpio_intr_enable(emac->int_gpio_num);
gpio_isr_handler_add(emac->int_gpio_num, dm9051_isr_handler, emac);
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed");
/* reset dm9051 */
MAC_CHECK(dm9051_reset(emac) == ESP_OK, "reset dm9051 failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_reset(emac), err, TAG, "reset dm9051 failed");
/* verify chip id */
MAC_CHECK(dm9051_verify_id(emac) == ESP_OK, "vefiry chip ID failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_verify_id(emac), err, TAG, "vefiry chip ID failed");
/* default setup of internal registers */
MAC_CHECK(dm9051_setup_default(emac) == ESP_OK, "dm9051 default setup failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_setup_default(emac), err, TAG, "dm9051 default setup failed");
/* clear multicast hash table */
MAC_CHECK(dm9051_clear_multicast_table(emac) == ESP_OK, "clear multicast table failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_clear_multicast_table(emac), err, TAG, "clear multicast table failed");
/* get emac address from eeprom */
MAC_CHECK(dm9051_get_mac_addr(emac) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(dm9051_get_mac_addr(emac), err, TAG, "fetch ethernet mac address failed");
return ESP_OK;
err:
gpio_isr_handler_remove(emac->int_gpio_num);
@ -761,12 +743,12 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config,
{
esp_eth_mac_t *ret = NULL;
emac_dm9051_t *emac = NULL;
MAC_CHECK(dm9051_config, "can't set dm9051 specific config to null", err, NULL);
MAC_CHECK(mac_config, "can't set mac config to null", err, NULL);
ESP_GOTO_ON_FALSE(dm9051_config, NULL, err, TAG, "can't set dm9051 specific config to null");
ESP_GOTO_ON_FALSE(mac_config, NULL, err, TAG, "can't set mac config to null");
emac = calloc(1, sizeof(emac_dm9051_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL);
ESP_GOTO_ON_FALSE(emac, NULL, err, TAG, "calloc emac failed");
/* dm9051 receive is driven by interrupt only for now*/
MAC_CHECK(dm9051_config->int_gpio_num >= 0, "error interrupt gpio number", err, NULL);
ESP_GOTO_ON_FALSE(dm9051_config->int_gpio_num >= 0, NULL, err, TAG, "error interrupt gpio number");
/* bind methods and attributes */
emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms;
emac->int_gpio_num = dm9051_config->int_gpio_num;
@ -791,7 +773,7 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config,
emac->parent.receive = emac_dm9051_receive;
/* create mutex */
emac->spi_lock = xSemaphoreCreateMutex();
MAC_CHECK(emac->spi_lock, "create lock failed", err, NULL);
ESP_GOTO_ON_FALSE(emac->spi_lock, NULL, err, TAG, "create lock failed");
/* create dm9051 task */
BaseType_t core_num = tskNO_AFFINITY;
if (mac_config->flags & ETH_MAC_FLAG_PIN_TO_CORE) {
@ -799,7 +781,7 @@ esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config,
}
BaseType_t xReturned = xTaskCreatePinnedToCore(emac_dm9051_task, "dm9051_tsk", mac_config->rx_task_stack_size, emac,
mac_config->rx_task_prio, &emac->rx_task_hdl, core_num);
MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err, NULL);
ESP_GOTO_ON_FALSE(xReturned == pdPASS, NULL, err, TAG, "create dm9051 task failed");
return &(emac->parent);
err:

View File

@ -18,6 +18,7 @@
#include "driver/gpio.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "esp_pm.h"
#include "esp_system.h"
@ -34,20 +35,9 @@
#include "esp_rom_gpio.h"
#include "esp_rom_sys.h"
static const char *TAG = "emac_esp32";
#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
static const char *TAG = "esp.emac";
#define PHY_OPERATION_TIMEOUT_US (1000)
#define FLOW_CONTROL_LOW_WATER_MARK (CONFIG_ETH_DMA_RX_BUFFER_NUM / 3)
#define FLOW_CONTROL_HIGH_WATER_MARK (FLOW_CONTROL_LOW_WATER_MARK * 2)
@ -78,7 +68,7 @@ typedef struct {
static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac's mediator to null");
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
emac->eth = eth;
return ESP_OK;
@ -90,7 +80,7 @@ static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
{
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
ESP_GOTO_ON_FALSE(!emac_hal_is_mii_busy(&emac->hal), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
emac_hal_set_phy_data(&emac->hal, reg_value);
emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, true);
/* polling the busy flag */
@ -101,7 +91,7 @@ static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
busy = emac_hal_is_mii_busy(&emac->hal);
to += 100;
} while (busy && to < PHY_OPERATION_TIMEOUT_US);
MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(!busy, ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
return ESP_OK;
err:
return ret;
@ -110,9 +100,9 @@ err:
static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(reg_value, ESP_ERR_INVALID_ARG, err, TAG, "can't set reg_value to null");
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(!emac_hal_is_mii_busy(&emac->hal), "phy is busy", err, ESP_ERR_INVALID_STATE);
ESP_GOTO_ON_FALSE(!emac_hal_is_mii_busy(&emac->hal), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, false);
/* polling the busy flag */
uint32_t to = 0;
@ -122,7 +112,7 @@ static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
busy = emac_hal_is_mii_busy(&emac->hal);
to += 100;
} while (busy && to < PHY_OPERATION_TIMEOUT_US);
MAC_CHECK(!busy, "phy is busy", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(!busy, ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
/* Store value */
*reg_value = emac_hal_get_phy_data(&emac->hal);
return ESP_OK;
@ -133,7 +123,7 @@ err:
static esp_err_t emac_esp32_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
memcpy(emac->addr, addr, 6);
emac_hal_set_address(&emac->hal, emac->addr);
@ -145,7 +135,7 @@ err:
static esp_err_t emac_esp32_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
memcpy(addr, emac->addr, 6);
return ESP_OK;
@ -159,15 +149,15 @@ static esp_err_t emac_esp32_set_link(esp_eth_mac_t *mac, eth_link_t link)
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
switch (link) {
case ETH_LINK_UP:
MAC_CHECK(esp_intr_enable(emac->intr_hdl) == ESP_OK, "enable interrupt failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(esp_intr_enable(emac->intr_hdl), err, TAG, "enable interrupt failed");
emac_hal_start(&emac->hal);
break;
case ETH_LINK_DOWN:
MAC_CHECK(esp_intr_disable(emac->intr_hdl) == ESP_OK, "disable interrupt failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(esp_intr_disable(emac->intr_hdl), err, TAG, "disable interrupt failed");
emac_hal_stop(&emac->hal);
break;
default:
MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown link status");
break;
}
return ESP_OK;
@ -189,7 +179,7 @@ static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
ESP_LOGD(TAG, "working in 100Mbps");
break;
default:
MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown speed");
break;
}
return ESP_OK;
@ -211,7 +201,7 @@ static esp_err_t emac_esp32_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
ESP_LOGD(TAG, "working in full duplex");
break;
default:
MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown duplex");
break;
}
return ESP_OK;
@ -254,7 +244,7 @@ static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
esp_err_t ret = ESP_OK;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
uint32_t sent_len = emac_hal_transmit_frame(&emac->hal, buf, length);
MAC_CHECK(sent_len == length, "insufficient TX buffer size", err, ESP_ERR_INVALID_SIZE);
ESP_GOTO_ON_FALSE(sent_len == length, ESP_ERR_INVALID_SIZE, err, TAG, "insufficient TX buffer size");
return ESP_OK;
err:
return ret;
@ -265,11 +255,11 @@ static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *
esp_err_t ret = ESP_OK;
uint32_t expected_len = *length;
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(buf && length, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf and length to null");
uint32_t receive_len = emac_hal_receive_frame(&emac->hal, buf, expected_len, &emac->frames_remain, &emac->free_rx_descriptor);
/* we need to check the return value in case the buffer size is not enough */
ESP_LOGD(TAG, "receive len= %d", receive_len);
MAC_CHECK(expected_len >= receive_len, "received buffer longer than expected", err, ESP_ERR_INVALID_SIZE);
ESP_GOTO_ON_FALSE(expected_len >= receive_len, ESP_ERR_INVALID_SIZE, err, TAG, "received buffer longer than expected");
*length = receive_len;
return ESP_OK;
err:
@ -341,7 +331,7 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
emac_hal_lowlevel_init(&emac->hal);
/* init gpio used by smi interface */
emac_esp32_init_smi_gpio(emac);
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed");
/* software reset */
emac_hal_reset(&emac->hal);
uint32_t to = 0;
@ -351,7 +341,7 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
}
vTaskDelay(pdMS_TO_TICKS(10));
}
MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(to < emac->sw_reset_timeout_ms / 10, ESP_ERR_TIMEOUT, err, TAG, "reset timeout");
/* set smi clock */
emac_hal_set_csr_clock_range(&emac->hal);
/* reset descriptor chain */
@ -361,7 +351,7 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
/* init dma registers by default */
emac_hal_init_dma_default(&emac->hal);
/* get emac address from efuse */
MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(esp_read_mac(emac->addr, ESP_MAC_ETH), err, TAG, "fetch ethernet mac address failed");
/* set MAC address to emac register */
emac_hal_set_address(&emac->hal, emac->addr);
#ifdef CONFIG_PM_ENABLE
@ -441,18 +431,18 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
esp_eth_mac_t *ret = NULL;
void *descriptors = NULL;
emac_esp32_t *emac = NULL;
MAC_CHECK(config, "can't set mac config to null", err, NULL);
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set mac config to null");
if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
emac = heap_caps_calloc(1, sizeof(emac_esp32_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
} else {
emac = calloc(1, sizeof(emac_esp32_t));
}
MAC_CHECK(emac, "calloc emac failed", err, NULL);
ESP_GOTO_ON_FALSE(emac, NULL, err, TAG, "calloc emac failed");
/* alloc memory for ethernet dma descriptor */
uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) +
CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t);
descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
MAC_CHECK(descriptors, "calloc descriptors failed", err, NULL);
ESP_GOTO_ON_FALSE(descriptors, NULL, err, TAG, "calloc descriptors failed");
int i = 0;
/* alloc memory for ethernet dma buffer */
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
@ -500,10 +490,9 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0,
emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl));
}
MAC_CHECK(ret_code == ESP_OK, "alloc emac interrupt failed", err, NULL);
ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc emac interrupt failed");
#ifdef CONFIG_PM_ENABLE
MAC_CHECK(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock) == ESP_OK,
"create pm lock failed", err, NULL);
ESP_GOTO_ON_FALSE(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock) == ESP_OK, NULL, err, TAG, "create pm lock failed");
#endif
/* create rx task */
BaseType_t core_num = tskNO_AFFINITY;
@ -512,7 +501,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
}
BaseType_t xReturned = xTaskCreatePinnedToCore(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac,
config->rx_task_prio, &emac->rx_task_hdl, core_num);
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err, NULL);
ESP_GOTO_ON_FALSE(xReturned == pdPASS, NULL, err, TAG, "create emac_rx task failed");
return &(emac->parent);
err:

View File

@ -26,6 +26,7 @@
#include <sys/cdefs.h>
#include <sys/param.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "esp_intr_alloc.h"
#include "freertos/FreeRTOS.h"
@ -34,18 +35,7 @@
#include "hal/cpu_hal.h"
#include "openeth.h"
static const char *TAG = "emac_opencores";
#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
static const char *TAG = "opencores.emac";
// Driver state structure
typedef struct {
@ -123,7 +113,7 @@ static void emac_opencores_rx_task(void *arg)
static esp_err_t emac_opencores_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac's mediator to null");
emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent);
emac->eth = eth;
return ESP_OK;
@ -144,7 +134,7 @@ static esp_err_t emac_opencores_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_a
static esp_err_t emac_opencores_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(reg_value, ESP_ERR_INVALID_ARG, err, TAG, "can't set reg_value to null");
REG_SET_FIELD(OPENETH_MIIADDRESS_REG, OPENETH_FIAD, phy_addr);
REG_SET_FIELD(OPENETH_MIIADDRESS_REG, OPENETH_RGAD, phy_reg);
REG_SET_BIT(OPENETH_MIICOMMAND_REG, OPENETH_RSTAT);
@ -159,7 +149,7 @@ static esp_err_t emac_opencores_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
ESP_LOGV(TAG, "%s: " MACSTR, __func__, MAC2STR(addr));
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent);
memcpy(emac->addr, addr, 6);
const uint8_t mac0[4] = {addr[5], addr[4], addr[3], addr[2]};
@ -178,7 +168,7 @@ static esp_err_t emac_opencores_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
ESP_LOGV(TAG, "%s: " MACSTR, __func__, MAC2STR(addr));
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "can't set mac addr to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent);
memcpy(addr, emac->addr, 6);
return ESP_OK;
@ -193,15 +183,15 @@ static esp_err_t emac_opencores_set_link(esp_eth_mac_t *mac, eth_link_t link)
emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent);
switch (link) {
case ETH_LINK_UP:
MAC_CHECK(esp_intr_enable(emac->intr_hdl) == ESP_OK, "enable interrupt failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(esp_intr_enable(emac->intr_hdl), err, TAG, "enable interrupt failed");
openeth_enable();
break;
case ETH_LINK_DOWN:
MAC_CHECK(esp_intr_disable(emac->intr_hdl) == ESP_OK, "disable interrupt failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(esp_intr_disable(emac->intr_hdl), err, TAG, "disable interrupt failed");
openeth_disable();
break;
default:
MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown link status");
break;
}
return ESP_OK;
@ -247,7 +237,7 @@ static esp_err_t emac_opencores_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint3
{
esp_err_t ret = ESP_OK;
emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent);
MAC_CHECK(length < DMA_BUF_SIZE * TX_BUF_COUNT, "insufficient TX buffer size", err, ESP_ERR_INVALID_SIZE);
ESP_GOTO_ON_FALSE(length < DMA_BUF_SIZE * TX_BUF_COUNT, ESP_ERR_INVALID_SIZE, err, TAG, "insufficient TX buffer size");
uint32_t bytes_remaining = length;
// In QEMU, there never is a TX operation in progress, so start with descriptor 0.
@ -287,7 +277,7 @@ static esp_err_t emac_opencores_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32
goto err;
}
size_t rx_length = desc_val.len;
MAC_CHECK(*length >= rx_length, "RX length too large", err, ESP_ERR_INVALID_SIZE);
ESP_GOTO_ON_FALSE(*length >= rx_length, ESP_ERR_INVALID_SIZE, err, TAG, "RX length too large");
*length = rx_length;
memcpy(buf, desc_val.rxpnt, *length);
desc_val.e = 1;
@ -304,8 +294,8 @@ static esp_err_t emac_opencores_init(esp_eth_mac_t *mac)
esp_err_t ret = ESP_OK;
emac_opencores_t *emac = __containerof(mac, emac_opencores_t, parent);
esp_eth_mediator_t *eth = emac->eth;
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
MAC_CHECK(esp_read_mac(emac->addr, ESP_MAC_ETH) == ESP_OK, "fetch ethernet mac address failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed");
ESP_GOTO_ON_ERROR(esp_read_mac(emac->addr, ESP_MAC_ETH), err, TAG, "fetch ethernet mac address failed");
// Sanity check
if (REG_READ(OPENETH_MODER_REG) != OPENETH_MODER_DEFAULT) {
@ -363,9 +353,9 @@ esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config)
{
esp_eth_mac_t *ret = NULL;
emac_opencores_t *emac = NULL;
MAC_CHECK(config, "can't set mac config to null", out, NULL);
ESP_GOTO_ON_FALSE(config, NULL, out, TAG, "can't set mac config to null");
emac = calloc(1, sizeof(emac_opencores_t));
MAC_CHECK(emac, "calloc emac failed", out, NULL);
ESP_GOTO_ON_FALSE(emac, NULL, out, TAG, "calloc emac failed");
// Allocate DMA buffers
for (int i = 0; i < RX_BUF_COUNT; i++) {
@ -408,9 +398,7 @@ esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config)
emac->parent.receive = emac_opencores_receive;
// Initialize the interrupt
MAC_CHECK(esp_intr_alloc(OPENETH_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_opencores_isr_handler,
emac, &(emac->intr_hdl)) == ESP_OK,
"alloc emac interrupt failed", out, NULL);
ESP_GOTO_ON_FALSE(esp_intr_alloc(OPENETH_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_opencores_isr_handler, emac, &(emac->intr_hdl)), NULL, out, TAG, "alloc emac interrupt failed");
// Create the RX task
BaseType_t core_num = tskNO_AFFINITY;
@ -419,7 +407,7 @@ esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config)
}
BaseType_t xReturned = xTaskCreatePinnedToCore(emac_opencores_rx_task, "emac_rx", config->rx_task_stack_size, emac,
config->rx_task_prio, &emac->rx_task_hdl, core_num);
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", out, NULL);
ESP_GOTO_ON_FALSE(xReturned == pdPASS, NULL, out, TAG, "create emac_rx task failed");
return &(emac->parent);
out:

View File

@ -18,6 +18,7 @@
#include "driver/spi_master.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "esp_system.h"
#include "esp_intr_alloc.h"
@ -30,15 +31,7 @@
#include "w5500.h"
#include "sdkconfig.h"
static const char *TAG = "w5500-mac";
#define MAC_CHECK(a, str, goto_tag, ret_value, ...) \
do { \
if (!(a)) { \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = ret_value; \
goto goto_tag; \
} \
} while (0)
static const char *TAG = "w5500.mac";
#define W5500_SPI_LOCK_TIMEOUT_MS (50)
#define W5500_TX_MEM_SIZE (0x4000)
@ -117,17 +110,17 @@ static esp_err_t w5500_read(emac_w5500_t *emac, uint32_t address, void *value, u
static esp_err_t w5500_send_command(emac_w5500_t *emac, uint8_t command, uint32_t timeout_ms)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_CR(0), &command, sizeof(command)) == ESP_OK, "write SCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_CR(0), &command, sizeof(command)), err, TAG, "write SCR failed");
// after W5500 accepts the command, the command register will be cleared automatically
uint32_t to = 0;
for (to = 0; to < timeout_ms / 10; to++) {
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_CR(0), &command, sizeof(command)) == ESP_OK, "read SCR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_CR(0), &command, sizeof(command)), err, TAG, "read SCR failed");
if (!command) {
break;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
MAC_CHECK(to < timeout_ms / 10, "send command timeout", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(to < timeout_ms / 10, ESP_ERR_TIMEOUT, err, TAG, "send command timeout");
err:
return ret;
@ -140,8 +133,8 @@ static esp_err_t w5500_get_tx_free_size(emac_w5500_t *emac, uint16_t *size)
// read TX_FSR register more than once, until we get the same value
// this is a trick because we might be interrupted between reading the high/low part of the TX_FSR register (16 bits in length)
do {
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_TX_FSR(0), &free0, sizeof(free0)) == ESP_OK, "read TX FSR failed", err, ESP_FAIL);
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_TX_FSR(0), &free1, sizeof(free1)) == ESP_OK, "read TX FSR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_TX_FSR(0), &free0, sizeof(free0)), err, TAG, "read TX FSR failed");
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_TX_FSR(0), &free1, sizeof(free1)), err, TAG, "read TX FSR failed");
} while (free0 != free1);
*size = __builtin_bswap16(free0);
@ -155,8 +148,8 @@ static esp_err_t w5500_get_rx_received_size(emac_w5500_t *emac, uint16_t *size)
esp_err_t ret = ESP_OK;
uint16_t received0, received1 = 0;
do {
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_RX_RSR(0), &received0, sizeof(received0)) == ESP_OK, "read RX RSR failed", err, ESP_FAIL);
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_RX_RSR(0), &received1, sizeof(received1)) == ESP_OK, "read RX RSR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_RX_RSR(0), &received0, sizeof(received0)), err, TAG, "read RX RSR failed");
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_RX_RSR(0), &received1, sizeof(received1)), err, TAG, "read RX RSR failed");
} while (received0 != received1);
*size = __builtin_bswap16(received0);
@ -173,11 +166,11 @@ static esp_err_t w5500_write_buffer(emac_w5500_t *emac, const void *buffer, uint
if (offset + len > W5500_TX_MEM_SIZE) {
remain = (offset + len) % W5500_TX_MEM_SIZE;
len = W5500_TX_MEM_SIZE - offset;
MAC_CHECK(w5500_write(emac, W5500_MEM_SOCK_TX(0, offset), buf, len) == ESP_OK, "write TX buffer failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_MEM_SOCK_TX(0, offset), buf, len), err, TAG, "write TX buffer failed");
offset += len;
buf += len;
}
MAC_CHECK(w5500_write(emac, W5500_MEM_SOCK_TX(0, offset), buf, remain) == ESP_OK, "write TX buffer failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_MEM_SOCK_TX(0, offset), buf, remain), err, TAG, "write TX buffer failed");
err:
return ret;
@ -192,11 +185,11 @@ static esp_err_t w5500_read_buffer(emac_w5500_t *emac, void *buffer, uint32_t le
if (offset + len > W5500_RX_MEM_SIZE) {
remain = (offset + len) % W5500_RX_MEM_SIZE;
len = W5500_RX_MEM_SIZE - offset;
MAC_CHECK(w5500_read(emac, W5500_MEM_SOCK_RX(0, offset), buf, len) == ESP_OK, "read RX buffer failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_MEM_SOCK_RX(0, offset), buf, len), err, TAG, "read RX buffer failed");
offset += len;
buf += len;
}
MAC_CHECK(w5500_read(emac, W5500_MEM_SOCK_RX(0, offset), buf, remain) == ESP_OK, "read RX buffer failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_MEM_SOCK_RX(0, offset), buf, remain), err, TAG, "read RX buffer failed");
err:
return ret;
@ -205,7 +198,7 @@ err:
static esp_err_t w5500_set_mac_addr(emac_w5500_t *emac)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(w5500_write(emac, W5500_REG_MAC, emac->addr, 6) == ESP_OK, "write MAC address register failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_MAC, emac->addr, 6), err, TAG, "write MAC address register failed");
err:
return ret;
@ -216,16 +209,16 @@ static esp_err_t w5500_reset(emac_w5500_t *emac)
esp_err_t ret = ESP_OK;
/* software reset */
uint8_t mr = W5500_MR_RST; // Set RST bit (auto clear)
MAC_CHECK(w5500_write(emac, W5500_REG_MR, &mr, sizeof(mr)) == ESP_OK, "write MR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_MR, &mr, sizeof(mr)), err, TAG, "write MR failed");
uint32_t to = 0;
for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
MAC_CHECK(w5500_read(emac, W5500_REG_MR, &mr, sizeof(mr)) == ESP_OK, "read MR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_MR, &mr, sizeof(mr)), err, TAG, "read MR failed");
if (!(mr & W5500_MR_RST)) {
break;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
MAC_CHECK(to < emac->sw_reset_timeout_ms / 10, "reset timeout", err, ESP_ERR_TIMEOUT);
ESP_GOTO_ON_FALSE(to < emac->sw_reset_timeout_ms / 10, ESP_ERR_TIMEOUT, err, TAG, "reset timeout");
err:
return ret;
@ -235,8 +228,7 @@ static esp_err_t w5500_verify_id(emac_w5500_t *emac)
{
esp_err_t ret = ESP_OK;
uint8_t version = 0;
MAC_CHECK(w5500_read(emac, W5500_REG_VERSIONR, &version, sizeof(version)) == ESP_OK,
"read VERSIONR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_VERSIONR, &version, sizeof(version)), err, TAG, "read VERSIONR failed");
// W5500 doesn't have chip ID, we just print the version number instead
ESP_LOGI(TAG, "version=%x", version);
@ -250,26 +242,26 @@ static esp_err_t w5500_setup_default(emac_w5500_t *emac)
uint8_t reg_value = 16;
// Only SOCK0 can be used as MAC RAW mode, so we give the whole buffer (16KB TX and 16KB RX) to SOCK0
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_RXBUF_SIZE(0), &reg_value, sizeof(reg_value)) == ESP_OK, "set rx buffer size failed", err, ESP_FAIL);
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_TXBUF_SIZE(0), &reg_value, sizeof(reg_value)) == ESP_OK, "set tx buffer size failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_RXBUF_SIZE(0), &reg_value, sizeof(reg_value)), err, TAG, "set rx buffer size failed");
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_TXBUF_SIZE(0), &reg_value, sizeof(reg_value)), err, TAG, "set tx buffer size failed");
reg_value = 0;
for (int i = 1; i < 8; i++) {
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_RXBUF_SIZE(i), &reg_value, sizeof(reg_value)) == ESP_OK, "set rx buffer size failed", err, ESP_FAIL);
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_TXBUF_SIZE(i), &reg_value, sizeof(reg_value)) == ESP_OK, "set tx buffer size failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_RXBUF_SIZE(i), &reg_value, sizeof(reg_value)), err, TAG, "set rx buffer size failed");
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_TXBUF_SIZE(i), &reg_value, sizeof(reg_value)), err, TAG, "set tx buffer size failed");
}
/* Enable ping block, disable PPPoE, WOL */
reg_value = W5500_MR_PB;
MAC_CHECK(w5500_write(emac, W5500_REG_MR, &reg_value, sizeof(reg_value)) == ESP_OK, "write MR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_MR, &reg_value, sizeof(reg_value)), err, TAG, "write MR failed");
/* Disable interrupt for all sockets by default */
reg_value = 0;
MAC_CHECK(w5500_write(emac, W5500_REG_SIMR, &reg_value, sizeof(reg_value)) == ESP_OK, "write SIMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SIMR, &reg_value, sizeof(reg_value)), err, TAG, "write SIMR failed");
/* Enable MAC RAW mode for SOCK0, enable MAC filter, no blocking broadcast and multicast */
reg_value = W5500_SMR_MAC_RAW | W5500_SMR_MAC_FILTER;
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_MR(0), &reg_value, sizeof(reg_value)) == ESP_OK, "write SMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_MR(0), &reg_value, sizeof(reg_value)), err, TAG, "write SMR failed");
/* Enable receive and send event for SOCK0 */
reg_value = W5500_SIR_RECV | W5500_SIR_SEND;
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_IMR(0), &reg_value, sizeof(reg_value)) == ESP_OK, "write SOCK0 IMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_IMR(0), &reg_value, sizeof(reg_value)), err, TAG, "write SOCK0 IMR failed");
err:
return ret;
@ -281,10 +273,10 @@ static esp_err_t emac_w5500_start(esp_eth_mac_t *mac)
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
uint8_t reg_value = 0;
/* open SOCK0 */
MAC_CHECK(w5500_send_command(emac, W5500_SCR_OPEN, 100) == ESP_OK, "issue OPEN command failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_send_command(emac, W5500_SCR_OPEN, 100), err, TAG, "issue OPEN command failed");
/* enable interrupt for SOCK0 */
reg_value = W5500_SIMR_SOCK0;
MAC_CHECK(w5500_write(emac, W5500_REG_SIMR, &reg_value, sizeof(reg_value)) == ESP_OK, "write SIMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SIMR, &reg_value, sizeof(reg_value)), err, TAG, "write SIMR failed");
err:
return ret;
@ -296,9 +288,9 @@ static esp_err_t emac_w5500_stop(esp_eth_mac_t *mac)
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
uint8_t reg_value = 0;
/* disable interrupt */
MAC_CHECK(w5500_write(emac, W5500_REG_SIMR, &reg_value, sizeof(reg_value)) == ESP_OK, "write SIMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SIMR, &reg_value, sizeof(reg_value)), err, TAG, "write SIMR failed");
/* close SOCK0 */
MAC_CHECK(w5500_send_command(emac, W5500_SCR_CLOSE, 100) == ESP_OK, "issue CLOSE command failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_send_command(emac, W5500_SCR_CLOSE, 100), err, TAG, "issue CLOSE command failed");
err:
return ret;
@ -356,7 +348,7 @@ static void emac_w5500_task(void *arg)
static esp_err_t emac_w5500_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(eth, "can't set mac's mediator to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac's mediator to null");
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
emac->eth = eth;
return ESP_OK;
@ -370,8 +362,8 @@ static esp_err_t emac_w5500_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
// PHY register and MAC registers are mixed together in W5500
// The only PHY register is PHYCFGR
MAC_CHECK(phy_reg == W5500_REG_PHYCFGR, "wrong PHY register", err, ESP_FAIL);
MAC_CHECK(w5500_write(emac, W5500_REG_PHYCFGR, &reg_value, sizeof(uint8_t)) == ESP_OK, "write PHY register failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(phy_reg == W5500_REG_PHYCFGR, ESP_FAIL, err, TAG, "wrong PHY register");
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_PHYCFGR, &reg_value, sizeof(uint8_t)), err, TAG, "write PHY register failed");
err:
return ret;
@ -380,12 +372,12 @@ err:
static esp_err_t emac_w5500_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(reg_value, "can't set reg_value to null", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(reg_value, ESP_ERR_INVALID_ARG, err, TAG, "can't set reg_value to null");
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
// PHY register and MAC registers are mixed together in W5500
// The only PHY register is PHYCFGR
MAC_CHECK(phy_reg == W5500_REG_PHYCFGR, "wrong PHY register", err, ESP_FAIL);
MAC_CHECK(w5500_read(emac, W5500_REG_PHYCFGR, reg_value, sizeof(uint8_t)) == ESP_OK, "read PHY register failed", err, ESP_FAIL);
ESP_GOTO_ON_FALSE(phy_reg == W5500_REG_PHYCFGR, ESP_FAIL, err, TAG, "wrong PHY register");
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_PHYCFGR, reg_value, sizeof(uint8_t)), err, TAG, "read PHY register failed");
err:
return ret;
@ -394,10 +386,10 @@ err:
static esp_err_t emac_w5500_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "invalid argument", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
memcpy(emac->addr, addr, 6);
MAC_CHECK(w5500_set_mac_addr(emac) == ESP_OK, "set mac address failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_set_mac_addr(emac), err, TAG, "set mac address failed");
err:
return ret;
@ -406,7 +398,7 @@ err:
static esp_err_t emac_w5500_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
{
esp_err_t ret = ESP_OK;
MAC_CHECK(addr, "invalid argument", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
memcpy(addr, emac->addr, 6);
@ -420,14 +412,14 @@ static esp_err_t emac_w5500_set_link(esp_eth_mac_t *mac, eth_link_t link)
switch (link) {
case ETH_LINK_UP:
ESP_LOGD(TAG, "link is up");
MAC_CHECK(mac->start(mac) == ESP_OK, "w5500 start failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->start(mac), err, TAG, "w5500 start failed");
break;
case ETH_LINK_DOWN:
ESP_LOGD(TAG, "link is down");
MAC_CHECK(mac->stop(mac) == ESP_OK, "w5500 stop failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(mac->stop(mac), err, TAG, "w5500 stop failed");
break;
default:
MAC_CHECK(false, "unknown link status", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown link status");
break;
}
@ -446,7 +438,7 @@ static esp_err_t emac_w5500_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
ESP_LOGD(TAG, "working in 100Mbps");
break;
default:
MAC_CHECK(false, "unknown speed", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown speed");
break;
}
@ -465,7 +457,7 @@ static esp_err_t emac_w5500_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
ESP_LOGD(TAG, "working in full duplex");
break;
default:
MAC_CHECK(false, "unknown duplex", err, ESP_ERR_INVALID_ARG);
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown duplex");
break;
}
@ -478,13 +470,13 @@ static esp_err_t emac_w5500_set_promiscuous(esp_eth_mac_t *mac, bool enable)
esp_err_t ret = ESP_OK;
emac_w5500_t *emac = __containerof(mac, emac_w5500_t, parent);
uint8_t smr = 0;
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_MR(0), &smr, sizeof(smr)) == ESP_OK, "read SMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_MR(0), &smr, sizeof(smr)), err, TAG, "read SMR failed");
if (enable) {
smr &= ~W5500_SMR_MAC_FILTER;
} else {
smr |= W5500_SMR_MAC_FILTER;
}
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_MR(0), &smr, sizeof(smr)) == ESP_OK, "write SMR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_MR(0), &smr, sizeof(smr)), err, TAG, "write SMR failed");
err:
return ret;
@ -520,32 +512,32 @@ static esp_err_t emac_w5500_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
// check if there're free memory to store this packet
uint16_t free_size = 0;
MAC_CHECK(w5500_get_tx_free_size(emac, &free_size) == ESP_OK, "get free size failed", err, ESP_FAIL);
MAC_CHECK(length <= free_size, "free size (%d) < send length (%d)", err, ESP_FAIL, free_size, length);
ESP_GOTO_ON_ERROR(w5500_get_tx_free_size(emac, &free_size), err, TAG, "get free size failed");
ESP_GOTO_ON_FALSE(length <= free_size, ESP_ERR_NO_MEM, err, TAG, "free size (%d) < send length (%d)", length, free_size);
// get current write pointer
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_TX_WR(0), &offset, sizeof(offset)) == ESP_OK, "read TX WR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_TX_WR(0), &offset, sizeof(offset)), err, TAG, "read TX WR failed");
offset = __builtin_bswap16(offset);
// copy data to tx memory
MAC_CHECK(w5500_write_buffer(emac, buf, length, offset) == ESP_OK, "write frame failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write_buffer(emac, buf, length, offset), err, TAG, "write frame failed");
// update write pointer
offset += length;
offset = __builtin_bswap16(offset);
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_TX_WR(0), &offset, sizeof(offset)) == ESP_OK, "write TX WR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_TX_WR(0), &offset, sizeof(offset)), err, TAG, "write TX WR failed");
// issue SEND command
MAC_CHECK(w5500_send_command(emac, W5500_SCR_SEND, 100) == ESP_OK, "issue SEND command failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_send_command(emac, W5500_SCR_SEND, 100), err, TAG, "issue SEND command failed");
// pooling the TX done event
int retry = 0;
uint8_t status = 0;
while (!(status & W5500_SIR_SEND)) {
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)) == ESP_OK, "read SOCK0 IR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)), err, TAG, "read SOCK0 IR failed");
if ((retry++ > 3 && !is_w5500_sane_for_rxtx(emac)) || retry > 10) {
return ESP_FAIL;
}
}
// clear the event bit
status = W5500_SIR_SEND;
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)) == ESP_OK, "write SOCK0 IR failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_IR(0), &status, sizeof(status)), err, TAG, "write SOCK0 IR failed");
err:
return ret;
@ -563,20 +555,20 @@ static esp_err_t emac_w5500_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *
w5500_get_rx_received_size(emac, &remain_bytes);
if (remain_bytes) {
// get current read pointer
MAC_CHECK(w5500_read(emac, W5500_REG_SOCK_RX_RD(0), &offset, sizeof(offset)) == ESP_OK, "read RX RD failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read(emac, W5500_REG_SOCK_RX_RD(0), &offset, sizeof(offset)), err, TAG, "read RX RD failed");
offset = __builtin_bswap16(offset);
// read head first
MAC_CHECK(w5500_read_buffer(emac, &rx_len, sizeof(rx_len), offset) == ESP_OK, "read frame header failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_read_buffer(emac, &rx_len, sizeof(rx_len), offset), err, TAG, "read frame header failed");
rx_len = __builtin_bswap16(rx_len) - 2; // data size includes 2 bytes of header
offset += 2;
// read the payload
MAC_CHECK(w5500_read_buffer(emac, buf, rx_len, offset) == ESP_OK, "read payload failed, len=%d, offset=%d", err, ESP_FAIL, rx_len, offset);
ESP_GOTO_ON_ERROR(w5500_read_buffer(emac, buf, rx_len, offset), err, TAG, "read payload failed, len=%d, offset=%d", rx_len, offset);
offset += rx_len;
// update read pointer
offset = __builtin_bswap16(offset);
MAC_CHECK(w5500_write(emac, W5500_REG_SOCK_RX_RD(0), &offset, sizeof(offset)) == ESP_OK, "write RX RD failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_write(emac, W5500_REG_SOCK_RX_RD(0), &offset, sizeof(offset)), err, TAG, "write RX RD failed");
/* issue RECV command */
MAC_CHECK(w5500_send_command(emac, W5500_SCR_RECV, 100) == ESP_OK, "issue RECV command failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_send_command(emac, W5500_SCR_RECV, 100), err, TAG, "issue RECV command failed");
// check if there're more data need to process
remain_bytes -= rx_len + 2;
emac->packets_remain = remain_bytes > 0;
@ -598,13 +590,13 @@ static esp_err_t emac_w5500_init(esp_eth_mac_t *mac)
gpio_set_intr_type(emac->int_gpio_num, GPIO_INTR_NEGEDGE); // active low
gpio_intr_enable(emac->int_gpio_num);
gpio_isr_handler_add(emac->int_gpio_num, w5500_isr_handler, emac);
MAC_CHECK(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL) == ESP_OK, "lowlevel init failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed");
/* reset w5500 */
MAC_CHECK(w5500_reset(emac) == ESP_OK, "reset w5500 failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_reset(emac), err, TAG, "reset w5500 failed");
/* verify chip id */
MAC_CHECK(w5500_verify_id(emac) == ESP_OK, "vefiry chip ID failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_verify_id(emac), err, TAG, "vefiry chip ID failed");
/* default setup of internal registers */
MAC_CHECK(w5500_setup_default(emac) == ESP_OK, "w5500 default setup failed", err, ESP_FAIL);
ESP_GOTO_ON_ERROR(w5500_setup_default(emac), err, TAG, "w5500 default setup failed");
return ESP_OK;
err:
gpio_isr_handler_remove(emac->int_gpio_num);
@ -637,11 +629,11 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con
{
esp_eth_mac_t *ret = NULL;
emac_w5500_t *emac = NULL;
MAC_CHECK(w5500_config && mac_config, "invalid argument", err, NULL);
ESP_GOTO_ON_FALSE(w5500_config && mac_config, NULL, err, TAG, "invalid argument");
emac = calloc(1, sizeof(emac_w5500_t));
MAC_CHECK(emac, "no mem for MAC instance", err, NULL);
ESP_GOTO_ON_FALSE(emac, NULL, err, TAG, "no mem for MAC instance");
/* w5500 driver is interrupt driven */
MAC_CHECK(w5500_config->int_gpio_num >= 0, "invalid interrupt gpio number", err, NULL);
ESP_GOTO_ON_FALSE(w5500_config->int_gpio_num >= 0, NULL, err, TAG, "invalid interrupt gpio number");
/* bind methods and attributes */
emac->sw_reset_timeout_ms = mac_config->sw_reset_timeout_ms;
emac->int_gpio_num = w5500_config->int_gpio_num;
@ -666,7 +658,7 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con
emac->parent.receive = emac_w5500_receive;
/* create mutex */
emac->spi_lock = xSemaphoreCreateMutex();
MAC_CHECK(emac->spi_lock, "create lock failed", err, NULL);
ESP_GOTO_ON_FALSE(emac->spi_lock, NULL, err, TAG, "create lock failed");
/* create w5500 task */
BaseType_t core_num = tskNO_AFFINITY;
if (mac_config->flags & ETH_MAC_FLAG_PIN_TO_CORE) {
@ -674,7 +666,7 @@ esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, con
}
BaseType_t xReturned = xTaskCreatePinnedToCore(emac_w5500_task, "w5500_tsk", mac_config->rx_task_stack_size, emac,
mac_config->rx_task_prio, &emac->rx_task_hdl, core_num);
MAC_CHECK(xReturned == pdPASS, "create w5500 task failed", err, NULL);
ESP_GOTO_ON_FALSE(xReturned == pdPASS, NULL, err, TAG, "create w5500 task failed");
return &(emac->parent);
err:

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
@ -23,16 +24,7 @@
#include "esp_rom_gpio.h"
#include "esp_rom_sys.h"
static const char *TAG = "dm9051";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
static const char *TAG = "dm9051.phy";
/***************Vendor Specific Register***************/
@ -91,6 +83,7 @@ typedef struct {
static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = dm9051->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
@ -101,19 +94,15 @@ static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051)
// BMSR is a latch low register
// after power up, the first latched value must be 0, which means down
// to speed up power up link speed, double read this register as a workaround
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
"read ANLPAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dm9051->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK,
"read DSCSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)), err, TAG, "read DSCSR failed");
if (dscsr.fdx100 || dscsr.hdx100) {
speed = ETH_SPEED_100M;
} else {
@ -124,78 +113,72 @@ static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051)
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
"change pause ability failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
dm9051->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator to null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mediator to null");
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
dm9051->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t dm9051_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
/* Updata information about link, speed, duplex */
PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(dm9051_update_link_duplex_speed(dm9051), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dm9051_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
dm9051->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = dm9051->eth;
dscr_reg_t dscr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK,
"read DSCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)), err, TAG, "read DSCR failed");
dscr.smrst = 1;
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK,
"write DSCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val), err, TAG, "write DSCR failed");
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK,
"read DSCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)), err, TAG, "read DSCR failed");
if (!bmcr.reset && !dscr.smrst) {
break;
}
}
PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "PHY reset timeout", err);
ESP_GOTO_ON_FALSE(to < dm9051->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "PHY reset timeout");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dm9051_reset_hw(esp_eth_phy_t *phy)
@ -214,6 +197,7 @@ static esp_err_t dm9051_reset_hw(esp_eth_phy_t *phy)
static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
/* Start auto negotiation */
@ -223,18 +207,15 @@ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
dscsr_reg_t dscsr;
uint32_t to = 0;
for (to = 0; to < dm9051->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)) == ESP_OK,
"read DSCSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCSR_REG_ADDR, &(dscsr.val)), err, TAG, "read DSCSR failed");
if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) {
break;
}
@ -243,19 +224,19 @@ static esp_err_t dm9051_negotiate(esp_eth_phy_t *phy)
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(dm9051_update_link_duplex_speed(dm9051), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -263,28 +244,25 @@ static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
if (!enable) {
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.power_down == 1, ESP_FAIL, err, TAG, "power down failed");
} else {
/* wait for power up complete */
uint32_t to = 0;
for (to = 0; to < dm9051->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.power_down == 0) {
break;
}
}
PHY_CHECK(to < dm9051->reset_timeout_ms / 10, "power up timeout", err);
ESP_GOTO_ON_FALSE(to < dm9051->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "power up timeout");
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr)
@ -296,12 +274,13 @@ static esp_err_t dm9051_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t dm9051_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
*addr = dm9051->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t dm9051_del(esp_eth_phy_t *phy)
@ -313,12 +292,12 @@ static esp_err_t dm9051_del(esp_eth_phy_t *phy)
static esp_err_t dm9051_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
esp_err_t ret = ESP_OK;
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
/* Set PAUSE function ability */
anar_reg_t anar;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
"read ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)), err, TAG, "read ANAR failed");
if (ability) {
anar.asymmetric_pause = 1;
anar.symmetric_pause = 1;
@ -326,53 +305,52 @@ static esp_err_t dm9051_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t abi
anar.asymmetric_pause = 0;
anar.symmetric_pause = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
"write ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_ANAR_REG_ADDR, anar.val), err, TAG, "write ANAR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dm9051_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
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);
ESP_GOTO_ON_ERROR(esp_eth_detect_phy_addr(eth, &dm9051->addr), err, TAG, "Detect PHY address failed");
}
/* Power on Ethernet PHY */
PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(dm9051_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset failed", err);
ESP_GOTO_ON_ERROR(dm9051_reset(phy), err, TAG, "reset failed");
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A,
"wrong chip ID", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)), err, TAG, "read ID1 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)), err, TAG, "read ID2 failed");
ESP_GOTO_ON_FALSE(id1.oui_msb == 0x0181 && id2.oui_lsb == 0x2E && id2.vendor_model == 0x0A, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dm9051_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(dm9051_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
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);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set phy config to null");
phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t));
PHY_CHECK(dm9051, "calloc dm9051 failed", err);
ESP_GOTO_ON_FALSE(dm9051, NULL, err, TAG, "calloc dm9051 failed");
dm9051->addr = config->phy_addr;
dm9051->reset_timeout_ms = config->reset_timeout_ms;
dm9051->reset_gpio_num = config->reset_gpio_num;
@ -392,5 +370,5 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
dm9051->parent.del = dm9051_del;
return &(dm9051->parent);
err:
return NULL;
return ret;
}

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
@ -24,15 +25,6 @@
#include "esp_rom_sys.h"
static const char *TAG = "dp83848";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
@ -97,16 +89,15 @@ typedef struct {
static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = dp83848->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
physts_reg_t physts;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
"read ANLPAR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
"read PHYSTS failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)), err, TAG, "read PHYSTS failed");
eth_link_t link = physts.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dp83848->link_status != link) {
@ -122,70 +113,67 @@ static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
"change pause ability failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
dp83848->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator to null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mediator to null");
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
dp83848->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t dp83848_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
/* Updata information about link, speed, duplex */
PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(dp83848_update_link_duplex_speed(dp83848), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dp83848_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
dp83848->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = dp83848->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "reset timeout", err);
ESP_GOTO_ON_FALSE(to < dp83848->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "reset timeout");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dp83848_reset_hw(esp_eth_phy_t *phy)
@ -203,6 +191,7 @@ static esp_err_t dp83848_reset_hw(esp_eth_phy_t *phy)
static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
/* Start auto negotiation */
@ -212,18 +201,15 @@ static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
physts_reg_t physts;
uint32_t to = 0;
for (to = 0; to < dp83848->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
"read PHYSTS failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)), err, TAG, "read PHYSTS failed");
if (bmsr.auto_nego_complete && physts.auto_nego_complete) {
break;
}
@ -233,19 +219,19 @@ static esp_err_t dp83848_negotiate(esp_eth_phy_t *phy)
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(dp83848_update_link_duplex_speed(dp83848), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -253,28 +239,25 @@ static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
if (!enable) {
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.power_down == 1, ESP_FAIL, err, TAG, "power down failed");
} else {
/* wait for power up complete */
uint32_t to = 0;
for (to = 0; to < dp83848->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.power_down == 0) {
break;
}
}
PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "power up timeout", err);
ESP_GOTO_ON_FALSE(to < dp83848->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "power up timeout");
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dp83848_set_addr(esp_eth_phy_t *phy, uint32_t addr)
@ -286,12 +269,13 @@ static esp_err_t dp83848_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t dp83848_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
*addr = dp83848->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t dp83848_del(esp_eth_phy_t *phy)
@ -303,12 +287,12 @@ static esp_err_t dp83848_del(esp_eth_phy_t *phy)
static esp_err_t dp83848_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
esp_err_t ret = ESP_OK;
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
/* Set PAUSE function ability */
anar_reg_t anar;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
"read ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)), err, TAG, "read ANAR failed");
if (ability) {
anar.asymmetric_pause = 1;
anar.symmetric_pause = 1;
@ -316,53 +300,52 @@ static esp_err_t dp83848_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ab
anar.asymmetric_pause = 0;
anar.symmetric_pause = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
"write ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_ANAR_REG_ADDR, anar.val), err, TAG, "write ANAR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dp83848_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
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);
ESP_GOTO_ON_ERROR(esp_eth_detect_phy_addr(eth, &dp83848->addr), err, TAG, "Detect PHY address failed");
}
/* Power on Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(dp83848_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset failed", err);
ESP_GOTO_ON_ERROR(dp83848_reset(phy), err, TAG, "reset failed");
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09,
"wrong chip ID", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)), err, TAG, "read ID1 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)), err, TAG, "read ID2 failed");
ESP_GOTO_ON_FALSE(id1.oui_msb == 0x2000 && id2.oui_lsb == 0x17 && id2.vendor_model == 0x09, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t dp83848_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(dp83848_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set phy config to null");
phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t));
PHY_CHECK(dp83848, "calloc dp83848 failed", err);
ESP_GOTO_ON_FALSE(dp83848, NULL, err, TAG, "calloc dp83848 failed");
dp83848->addr = config->phy_addr;
dp83848->reset_timeout_ms = config->reset_timeout_ms;
dp83848->link_status = ETH_LINK_DOWN;
@ -380,8 +363,7 @@ esp_eth_phy_t *esp_eth_phy_new_dp83848(const eth_phy_config_t *config)
dp83848->parent.set_addr = dp83848_set_addr;
dp83848->parent.advertise_pause_ability = dp83848_advertise_pause_ability;
dp83848->parent.del = dp83848_del;
return &(dp83848->parent);
err:
return NULL;
return ret;
}

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
@ -24,15 +25,6 @@
#include "esp_rom_sys.h"
static const char *TAG = "ip101";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
@ -114,29 +106,29 @@ typedef struct {
static esp_err_t ip101_page_select(phy_ip101_t *ip101, uint32_t page)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = ip101->eth;
pcr_reg_t pcr = {
.register_page_select = page
};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_PCR_REG_ADDR, pcr.val) == ESP_OK, "write PCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_PCR_REG_ADDR, pcr.val), err, TAG, "write PCR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = ip101->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t peer_pause_ability = false;
cssr_reg_t cssr;
anlpar_reg_t anlpar;
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_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK,
"read CSSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
"read ANLPAR failed", err);
ESP_GOTO_ON_ERROR(ip101_page_select(ip101, 16), err, TAG, "select page 16 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)), err, TAG, "read CSSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
eth_link_t link = cssr.link_up ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (ip101->link_status != link) {
@ -162,70 +154,67 @@ static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101)
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
"change pause ability failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"chagne link failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "chagne link failed");
ip101->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator to null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mediator to null");
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
ip101->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t ip101_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
/* Updata information about link, speed, duplex */
PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(ip101_update_link_duplex_speed(ip101), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
ip101->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = ip101->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* wait for reset complete */
uint32_t to = 0;
for (to = 0; to < ip101->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < ip101->reset_timeout_ms / 10, "reset timeout", err);
ESP_GOTO_ON_FALSE(to < ip101->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "reset timeout");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy)
@ -243,6 +232,7 @@ static esp_err_t ip101_reset_hw(esp_eth_phy_t *phy)
static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Restart auto negotiation */
@ -252,15 +242,13 @@ static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
uint32_t to = 0;
for (to = 0; to < ip101->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
if (bmsr.auto_nego_complete) {
break;
}
@ -270,19 +258,19 @@ static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(ip101_update_link_duplex_speed(ip101), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -290,28 +278,25 @@ static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
if (!enable) {
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.power_down == 1, ESP_FAIL, err, TAG, "power down failed");
} else {
/* wait for power up complete */
uint32_t to = 0;
for (to = 0; to < ip101->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.power_down == 0) {
break;
}
}
PHY_CHECK(to < ip101->reset_timeout_ms / 10, "power up timeout", err);
ESP_GOTO_ON_FALSE(to < ip101->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "power up timeout");
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr)
@ -323,12 +308,13 @@ static esp_err_t ip101_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t ip101_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
*addr = ip101->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t ip101_del(esp_eth_phy_t *phy)
@ -340,12 +326,12 @@ static esp_err_t ip101_del(esp_eth_phy_t *phy)
static esp_err_t ip101_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
esp_err_t ret = ESP_OK;
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Set PAUSE function ability */
anar_reg_t anar;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
"read ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)), err, TAG, "read ANAR failed");
if (ability) {
anar.asymmetric_pause = 1;
anar.symmetric_pause = 1;
@ -353,50 +339,52 @@ static esp_err_t ip101_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t abil
anar.asymmetric_pause = 0;
anar.symmetric_pause = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
"write ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_ANAR_REG_ADDR, anar.val), err, TAG, "write ANAR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
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);
ESP_GOTO_ON_ERROR(esp_eth_detect_phy_addr(eth, &ip101->addr), err, TAG, "Detect PHY address failed");
}
/* Power on Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(ip101_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset failed", err);
ESP_GOTO_ON_ERROR(ip101_reset(phy), err, TAG, "reset failed");
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK, "read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK, "read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong chip ID", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)), err, TAG, "read ID1 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)), err, TAG, "read ID2 failed");
ESP_GOTO_ON_FALSE(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ip101_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(ip101_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set phy config to null");
phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
PHY_CHECK(ip101, "calloc ip101 failed", err);
ESP_GOTO_ON_FALSE(ip101, NULL, err, TAG, "calloc ip101 failed");
ip101->addr = config->phy_addr;
ip101->reset_timeout_ms = config->reset_timeout_ms;
ip101->reset_gpio_num = config->reset_gpio_num;
@ -417,5 +405,5 @@ esp_eth_phy_t *esp_eth_phy_new_ip101(const eth_phy_config_t *config)
return &(ip101->parent);
err:
return NULL;
return ret;
}

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
@ -24,14 +25,6 @@
#include "esp_rom_sys.h"
static const char *TAG = "ksz80xx";
#define PHY_CHECK(a, str, goto_tag, ...) \
do { \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
#define KSZ8041_MODEL_ID (0x11)
#define KSZ8081_MODEL_ID (0x16)
@ -95,16 +88,15 @@ typedef struct {
static esp_err_t ksz80xx_update_link_duplex_speed(phy_ksz80xx_t *ksz80xx)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = ksz80xx->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
"read ANLPAR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (ksz80xx->link_status != link) {
@ -113,13 +105,11 @@ static esp_err_t ksz80xx_update_link_duplex_speed(phy_ksz80xx_t *ksz80xx)
int op_mode = 0;
if (ksz80xx->vendor_model == KSZ8041_MODEL_ID) {
ksz8041_pc2r_reg_t pc2r;
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, KSZ8041_PC2R_ERG_ADDR, &(pc2r.val)) == ESP_OK,
"read PC2R failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, KSZ8041_PC2R_ERG_ADDR, &(pc2r.val)), err, TAG, "read PC2R failed");
op_mode = pc2r.op_mode;
} else if (ksz80xx->vendor_model == KSZ8081_MODEL_ID) {
ksz8081_pc1r_reg_t pc1r;
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, KSZ8081_PC1R_REG_ADDR, &(pc1r.val)) == ESP_OK,
"read PC1R failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, KSZ8081_PC1R_REG_ADDR, &(pc1r.val)), err, TAG, "read PC1R failed");
op_mode = pc1r.op_mode;
}
switch (op_mode) {
@ -142,70 +132,67 @@ static esp_err_t ksz80xx_update_link_duplex_speed(phy_ksz80xx_t *ksz80xx)
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
"change pause ability failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
ksz80xx->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ksz80xx_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator to null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mediator to null");
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
ksz80xx->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t ksz80xx_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
/* Update information about link, speed, duplex */
PHY_CHECK(ksz80xx_update_link_duplex_speed(ksz80xx) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(ksz80xx_update_link_duplex_speed(ksz80xx), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ksz80xx_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
ksz80xx->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = ksz80xx->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* wait for reset complete */
uint32_t to = 0;
for (to = 0; to < ksz80xx->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < ksz80xx->reset_timeout_ms / 10, "reset timeout", err);
ESP_GOTO_ON_FALSE(to < ksz80xx->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "reset timeout");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ksz80xx_reset_hw(esp_eth_phy_t *phy)
@ -223,6 +210,7 @@ static esp_err_t ksz80xx_reset_hw(esp_eth_phy_t *phy)
static esp_err_t ksz80xx_negotiate(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
esp_eth_mediator_t *eth = ksz80xx->eth;
/* Restart auto negotiation */
@ -232,14 +220,13 @@ static esp_err_t ksz80xx_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
uint32_t to = 0;
for (to = 0; to < ksz80xx->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
if (bmsr.auto_nego_complete) {
break;
}
@ -249,19 +236,19 @@ static esp_err_t ksz80xx_negotiate(esp_eth_phy_t *phy)
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(ksz80xx_update_link_duplex_speed(ksz80xx) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(ksz80xx_update_link_duplex_speed(ksz80xx), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ksz80xx_pwrctl(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
esp_eth_mediator_t *eth = ksz80xx->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!enable) {
/* General Power Down Mode */
bmcr.power_down = 1;
@ -269,28 +256,25 @@ static esp_err_t ksz80xx_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Normal operation Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
if (!enable) {
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.power_down == 1, ESP_FAIL, err, TAG, "power down failed");
} else {
/* wait for power up complete */
uint32_t to = 0;
for (to = 0; to < ksz80xx->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.power_down == 0) {
break;
}
}
PHY_CHECK(to < ksz80xx->reset_timeout_ms / 10, "power up timeout", err);
ESP_GOTO_ON_FALSE(to < ksz80xx->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "power up timeout");
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ksz80xx_set_addr(esp_eth_phy_t *phy, uint32_t addr)
@ -302,12 +286,13 @@ static esp_err_t ksz80xx_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t ksz80xx_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
*addr = ksz80xx->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t ksz80xx_del(esp_eth_phy_t *phy)
@ -319,12 +304,12 @@ static esp_err_t ksz80xx_del(esp_eth_phy_t *phy)
static esp_err_t ksz80xx_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
esp_err_t ret = ESP_OK;
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
esp_eth_mediator_t *eth = ksz80xx->eth;
/* Set PAUSE function ability */
anar_reg_t anar;
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
"read ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)), err, TAG, "read ANAR failed");
if (ability) {
anar.asymmetric_pause = 1;
anar.symmetric_pause = 1;
@ -332,48 +317,48 @@ static esp_err_t ksz80xx_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ab
anar.asymmetric_pause = 0;
anar.symmetric_pause = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
"write ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, ksz80xx->addr, ETH_PHY_ANAR_REG_ADDR, anar.val), err, TAG, "write ANAR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ksz80xx_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_ksz80xx_t *ksz80xx = __containerof(phy, phy_ksz80xx_t, parent);
esp_eth_mediator_t *eth = ksz80xx->eth;
/* Power on Ethernet PHY */
PHY_CHECK(ksz80xx_pwrctl(phy, true) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(ksz80xx_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
PHY_CHECK(ksz80xx_reset(phy) == ESP_OK, "reset failed", err);
ESP_GOTO_ON_ERROR(ksz80xx_reset(phy), err, TAG, "reset failed");
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == ksz80xx->vendor_model, "wrong chip ID", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)), err, TAG, "read ID1 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, ksz80xx->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)), err, TAG, "read ID2 failed");
ESP_GOTO_ON_FALSE(id1.oui_msb == 0x22 && id2.oui_lsb == 0x5 && id2.vendor_model == ksz80xx->vendor_model, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t ksz80xx_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
PHY_CHECK(ksz80xx_pwrctl(phy, false) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(ksz80xx_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set phy config to null");
phy_ksz80xx_t *ksz8041 = calloc(1, sizeof(phy_ksz80xx_t));
PHY_CHECK(ksz8041, "calloc ksz80xx failed", err);
ESP_GOTO_ON_FALSE(ksz8041, NULL, err, TAG, "calloc ksz80xx failed");
ksz8041->vendor_model = KSZ8041_MODEL_ID;
ksz8041->addr = config->phy_addr;
ksz8041->reset_gpio_num = config->reset_gpio_num;
@ -392,17 +377,17 @@ esp_eth_phy_t *esp_eth_phy_new_ksz8041(const eth_phy_config_t *config)
ksz8041->parent.set_addr = ksz80xx_set_addr;
ksz8041->parent.advertise_pause_ability = ksz80xx_advertise_pause_ability;
ksz8041->parent.del = ksz80xx_del;
return &(ksz8041->parent);
err:
return NULL;
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_ksz8081(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set phy config to null");
phy_ksz80xx_t *ksz8081 = calloc(1, sizeof(phy_ksz80xx_t));
PHY_CHECK(ksz8081, "calloc ksz8081 failed", err);
ESP_GOTO_ON_FALSE(ksz8081, NULL, err, TAG, "calloc ksz8081 failed");
ksz8081->vendor_model = KSZ8081_MODEL_ID;
ksz8081->addr = config->phy_addr;
ksz8081->reset_gpio_num = config->reset_gpio_num;
@ -421,8 +406,7 @@ esp_eth_phy_t *esp_eth_phy_new_ksz8081(const eth_phy_config_t *config)
ksz8081->parent.set_addr = ksz80xx_set_addr;
ksz8081->parent.advertise_pause_ability = ksz80xx_advertise_pause_ability;
ksz8081->parent.del = ksz80xx_del;
return &(ksz8081->parent);
err:
return NULL;
return ret;
}

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
@ -24,15 +25,6 @@
#include "esp_rom_sys.h"
static const char *TAG = "lan8720";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
@ -169,6 +161,7 @@ typedef struct {
static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = lan8720->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
@ -176,17 +169,14 @@ static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720)
pscsr_reg_t pscsr;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
"read ANLPAR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (lan8720->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK,
"read PSCSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)), err, TAG, "read PSCSR failed");
switch (pscsr.speed_indication) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
@ -207,70 +197,67 @@ static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720)
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
"change pause ability failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
lan8720->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator to null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mediator to null");
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
lan8720->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t lan8720_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
/* Updata information about link, speed, duplex */
PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(lan8720_update_link_duplex_speed(lan8720), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t lan8720_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
lan8720->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = lan8720->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* wait for reset complete */
uint32_t to = 0;
for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "reset timeout", err);
ESP_GOTO_ON_FALSE(to < lan8720->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "reset timeout");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t lan8720_reset_hw(esp_eth_phy_t *phy)
@ -288,6 +275,7 @@ static esp_err_t lan8720_reset_hw(esp_eth_phy_t *phy)
static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Restart auto negotiation */
@ -297,17 +285,15 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK, "write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
pscsr_reg_t pscsr;
uint32_t to = 0;
for (to = 0; to < lan8720->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)) == ESP_OK,
"read PSCSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_PSCSR_REG_ADDR, &(pscsr.val)), err, TAG, "read PSCSR failed");
if (bmsr.auto_nego_complete && pscsr.auto_nego_done) {
break;
}
@ -317,19 +303,19 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(lan8720_update_link_duplex_speed(lan8720), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!enable) {
/* General Power Down Mode */
bmcr.power_down = 1;
@ -337,28 +323,25 @@ static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Normal operation Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
if (!enable) {
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.power_down == 1, ESP_FAIL, err, TAG, "power down failed");
} else {
/* wait for power up complete */
uint32_t to = 0;
for (to = 0; to < lan8720->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.power_down == 0) {
break;
}
}
PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "power up timeout", err);
ESP_GOTO_ON_FALSE(to < lan8720->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "power up timeout");
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t lan8720_set_addr(esp_eth_phy_t *phy, uint32_t addr)
@ -370,12 +353,13 @@ static esp_err_t lan8720_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t lan8720_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
*addr = lan8720->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t lan8720_del(esp_eth_phy_t *phy)
@ -387,12 +371,12 @@ static esp_err_t lan8720_del(esp_eth_phy_t *phy)
static esp_err_t lan8720_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
esp_err_t ret = ESP_OK;
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Set PAUSE function ability */
anar_reg_t anar;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
"read ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)), err, TAG, "read ANAR failed");
if (ability) {
anar.asymmetric_pause = 1;
anar.symmetric_pause = 1;
@ -400,52 +384,52 @@ static esp_err_t lan8720_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ab
anar.asymmetric_pause = 0;
anar.symmetric_pause = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
"write ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_ANAR_REG_ADDR, anar.val), err, TAG, "write ANAR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t lan8720_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
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);
ESP_GOTO_ON_ERROR(esp_eth_detect_phy_addr(eth, &lan8720->addr), err, TAG, "Detect PHY address failed");
}
/* Power on Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(lan8720_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset failed", err);
ESP_GOTO_ON_ERROR(lan8720_reset(phy), err, TAG, "reset failed");
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, "wrong chip ID", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)), err, TAG, "read ID1 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)), err, TAG, "read ID2 failed");
ESP_GOTO_ON_FALSE(id1.oui_msb == 0x7 && id2.oui_lsb == 0x30 && id2.vendor_model == 0xF, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t lan8720_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(lan8720_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set phy config to null");
phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t));
PHY_CHECK(lan8720, "calloc lan8720 failed", err);
ESP_GOTO_ON_FALSE(lan8720, NULL, err, TAG, "calloc lan8720 failed");
lan8720->addr = config->phy_addr;
lan8720->reset_gpio_num = config->reset_gpio_num;
lan8720->reset_timeout_ms = config->reset_timeout_ms;
@ -466,5 +450,5 @@ esp_eth_phy_t *esp_eth_phy_new_lan8720(const eth_phy_config_t *config)
return &(lan8720->parent);
err:
return NULL;
return ret;
}

View File

@ -16,6 +16,7 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
@ -25,15 +26,6 @@
#include "esp_rom_sys.h"
static const char *TAG = "rtl8201";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
/***************Vendor Specific Register***************/
@ -75,18 +67,20 @@ typedef struct {
static esp_err_t rtl8201_page_select(phy_rtl8201_t *rtl8201, uint32_t page)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = rtl8201->eth;
psr_reg_t psr = {
.page_select = page
};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_PSR_REG_ADDR, psr.val) == ESP_OK, "write PSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_PSR_REG_ADDR, psr.val), err, TAG, "write PSR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = rtl8201->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
@ -94,18 +88,15 @@ static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201)
bmsr_reg_t bmsr;
uint32_t peer_pause_ability = false;
anlpar_reg_t anlpar;
PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page 0 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)) == ESP_OK,
"read ANLPAR failed", err);
ESP_GOTO_ON_ERROR(rtl8201_page_select(rtl8201, 0), err, TAG, "select page 0 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed");
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (rtl8201->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.speed_select) {
speed = ETH_SPEED_100M;
} else {
@ -116,70 +107,67 @@ static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201)
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
/* if we're in duplex mode, and peer has the flow control ability */
if (duplex == ETH_DUPLEX_FULL && anlpar.symmetric_pause) {
peer_pause_ability = 1;
} else {
peer_pause_ability = 0;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability) == ESP_OK,
"change pause ability failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_PAUSE, (void *)peer_pause_ability), err, TAG, "change pause ability failed");
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
rtl8201->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator to null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mediator to null");
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
rtl8201->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
/* Updata information about link, speed, duplex */
PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(rtl8201_update_link_duplex_speed(rtl8201), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
rtl8201->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = rtl8201->eth;
bmcr_reg_t bmcr = {.reset = 1};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for reset complete */
uint32_t to = 0;
for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "reset timeout", err);
ESP_GOTO_ON_FALSE(to < rtl8201->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "reset timeout");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy)
@ -197,6 +185,7 @@ static esp_err_t rtl8201_reset_hw(esp_eth_phy_t *phy)
static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Restart auto negotiation */
@ -206,15 +195,13 @@ static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy)
.en_auto_nego = 1, /* Auto Negotiation */
.restart_auto_nego = 1 /* Restart Auto Negotiation */
};
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
/* Wait for auto negotiation complete */
bmsr_reg_t bmsr;
uint32_t to = 0;
for (to = 0; to < rtl8201->autonego_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed");
if (bmsr.auto_nego_complete) {
break;
}
@ -224,19 +211,19 @@ static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy)
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(rtl8201_update_link_duplex_speed(rtl8201), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable)
{
esp_err_t ret = ESP_OK;
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmcr_reg_t bmcr;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -244,28 +231,25 @@ static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable)
/* Disable IEEE Power Down Mode */
bmcr.power_down = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val), err, TAG, "write BMCR failed");
if (!enable) {
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
ESP_GOTO_ON_FALSE(bmcr.power_down == 1, ESP_FAIL, err, TAG, "power down failed");
} else {
/* wait for power up complete */
uint32_t to = 0;
for (to = 0; to < rtl8201->reset_timeout_ms / 10; to++) {
vTaskDelay(pdMS_TO_TICKS(10));
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed");
if (bmcr.power_down == 0) {
break;
}
}
PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "power up timeout", err);
ESP_GOTO_ON_FALSE(to < rtl8201->reset_timeout_ms / 10, ESP_FAIL, err, TAG, "power up timeout");
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_set_addr(esp_eth_phy_t *phy, uint32_t addr)
@ -277,12 +261,13 @@ static esp_err_t rtl8201_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t rtl8201_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
*addr = rtl8201->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t rtl8201_del(esp_eth_phy_t *phy)
@ -294,12 +279,12 @@ static esp_err_t rtl8201_del(esp_eth_phy_t *phy)
static esp_err_t rtl8201_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability)
{
esp_err_t ret = ESP_OK;
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Set PAUSE function ability */
anar_reg_t anar;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)) == ESP_OK,
"read ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_ANAR_REG_ADDR, &(anar.val)), err, TAG, "read ANAR failed");
if (ability) {
anar.asymmetric_pause = 1;
anar.symmetric_pause = 1;
@ -307,53 +292,52 @@ static esp_err_t rtl8201_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ab
anar.asymmetric_pause = 0;
anar.symmetric_pause = 0;
}
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_ANAR_REG_ADDR, anar.val) == ESP_OK,
"write ANAR failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_ANAR_REG_ADDR, anar.val), err, TAG, "write ANAR failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
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);
ESP_GOTO_ON_ERROR(esp_eth_detect_phy_addr(eth, &rtl8201->addr), err, TAG, "Detect PHY address failed");
}
/* Power on Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(rtl8201_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset failed", err);
ESP_GOTO_ON_ERROR(rtl8201_reset(phy), err, TAG, "reset failed");
/* Check PHY ID */
phyidr1_reg_t id1;
phyidr2_reg_t id2;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)) == ESP_OK,
"read ID1 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)) == ESP_OK,
"read ID2 failed", err);
PHY_CHECK(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1,
"wrong chip ID", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR1_REG_ADDR, &(id1.val)), err, TAG, "read ID1 failed");
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_IDR2_REG_ADDR, &(id2.val)), err, TAG, "read ID2 failed");
ESP_GOTO_ON_FALSE(id1.oui_msb == 0x1C && id2.oui_lsb == 0x32 && id2.vendor_model == 0x1, ESP_FAIL, err, TAG, "wrong chip ID");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t rtl8201_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(rtl8201_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
{
PHY_CHECK(config, "can't set phy config to null", err);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set phy config to null");
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
PHY_CHECK(rtl8201, "calloc rtl8201 failed", err);
ESP_GOTO_ON_FALSE(rtl8201, NULL, err, TAG, "calloc rtl8201 failed");
rtl8201->addr = config->phy_addr;
rtl8201->reset_gpio_num = config->reset_gpio_num;
rtl8201->reset_timeout_ms = config->reset_timeout_ms;
@ -374,5 +358,5 @@ esp_eth_phy_t *esp_eth_phy_new_rtl8201(const eth_phy_config_t *config)
return &(rtl8201->parent);
err:
return NULL;
return ret;
}

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <sys/cdefs.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -23,16 +24,7 @@
#include "esp_rom_sys.h"
#include "w5500.h"
static const char *TAG = "w5500-phy";
#define PHY_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
static const char *TAG = "w5500.phy";
/***************Vendor Specific Register***************/
/**
@ -64,12 +56,13 @@ typedef struct {
static esp_err_t w5500_update_link_duplex_speed(phy_w5500_t *w5500)
{
esp_err_t ret = ESP_OK;
esp_eth_mediator_t *eth = w5500->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
phycfg_reg_t phycfg;
PHY_CHECK(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)) == ESP_OK, "read PHYCFG failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
eth_link_t link = phycfg.link ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (w5500->link_status != link) {
@ -85,55 +78,55 @@ static esp_err_t w5500_update_link_duplex_speed(phy_w5500_t *w5500)
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK,
"change speed failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK,
"change duplex failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed), err, TAG, "change speed failed");
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex), err, TAG, "change duplex failed");
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link), err, TAG, "change link failed");
w5500->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t w5500_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator to null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mediator to null");
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
w5500->eth = eth;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t w5500_get_link(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
/* Updata information about link, speed, duplex */
PHY_CHECK(w5500_update_link_duplex_speed(w5500) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(w5500_update_link_duplex_speed(w5500), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t w5500_reset(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
w5500->link_status = ETH_LINK_DOWN;
esp_eth_mediator_t *eth = w5500->eth;
phycfg_reg_t phycfg;
PHY_CHECK(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)) == ESP_OK, "read PHYCFG failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
phycfg.reset = 0; // set to '0' will reset internal PHY
PHY_CHECK(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val) == ESP_OK, "write PHYCFG failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
vTaskDelay(pdMS_TO_TICKS(10));
phycfg.reset = 1; // set to '1' after reset
PHY_CHECK(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val) == ESP_OK, "write PHYCFG failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t w5500_reset_hw(esp_eth_phy_t *phy)
@ -152,20 +145,21 @@ static esp_err_t w5500_reset_hw(esp_eth_phy_t *phy)
static esp_err_t w5500_negotiate(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
esp_eth_mediator_t *eth = w5500->eth;
phycfg_reg_t phycfg;
PHY_CHECK(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)) == ESP_OK, "read PHYCFG failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, w5500->addr, W5500_REG_PHYCFGR, (uint32_t *) & (phycfg.val)), err, TAG, "read PHYCFG failed");
phycfg.opsel = 1; // PHY working mode configured by register
phycfg.opmode = 7; // all capable, auto-negotiation enabled
PHY_CHECK(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val) == ESP_OK, "write PHYCFG failed", err);
ESP_GOTO_ON_ERROR(eth->phy_reg_write(eth, w5500->addr, W5500_REG_PHYCFGR, phycfg.val), err, TAG, "write PHYCFG failed");
/* Update information about link, speed, duplex */
PHY_CHECK(w5500_update_link_duplex_speed(w5500) == ESP_OK, "update link duplex speed failed", err);
ESP_GOTO_ON_ERROR(w5500_update_link_duplex_speed(w5500), err, TAG, "update link duplex speed failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t w5500_pwrctl(esp_eth_phy_t *phy, bool enable)
@ -183,12 +177,13 @@ static esp_err_t w5500_set_addr(esp_eth_phy_t *phy, uint32_t addr)
static esp_err_t w5500_get_addr(esp_eth_phy_t *phy, uint32_t *addr)
{
PHY_CHECK(addr, "addr can't be null", err);
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "addr can't be null");
phy_w5500_t *w5500 = __containerof(phy, phy_w5500_t, parent);
*addr = w5500->addr;
return ESP_OK;
err:
return ESP_ERR_INVALID_ARG;
return ret;
}
static esp_err_t w5500_del(esp_eth_phy_t *phy)
@ -206,29 +201,32 @@ static esp_err_t w5500_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t abil
static esp_err_t w5500_init(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power on Ethernet PHY */
PHY_CHECK(w5500_pwrctl(phy, true) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(w5500_pwrctl(phy, true), err, TAG, "power control failed");
/* Reset Ethernet PHY */
PHY_CHECK(w5500_reset(phy) == ESP_OK, "reset failed", err);
ESP_GOTO_ON_ERROR(w5500_reset(phy), err, TAG, "reset failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
static esp_err_t w5500_deinit(esp_eth_phy_t *phy)
{
esp_err_t ret = ESP_OK;
/* Power off Ethernet PHY */
PHY_CHECK(w5500_pwrctl(phy, false) == ESP_OK, "power control failed", err);
ESP_GOTO_ON_ERROR(w5500_pwrctl(phy, false), err, TAG, "power control failed");
return ESP_OK;
err:
return ESP_FAIL;
return ret;
}
esp_eth_phy_t *esp_eth_phy_new_w5500(const eth_phy_config_t *config)
{
PHY_CHECK(config, "invalid arguments", err);
esp_eth_phy_t *ret = NULL;
ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "invalid arguments");
phy_w5500_t *w5500 = calloc(1, sizeof(phy_w5500_t));
PHY_CHECK(w5500, "no mem for PHY instance", err);
ESP_GOTO_ON_FALSE(w5500, NULL, err, TAG, "no mem for PHY instance");
w5500->addr = config->phy_addr;
w5500->reset_timeout_ms = config->reset_timeout_ms;
w5500->reset_gpio_num = config->reset_gpio_num;
@ -248,5 +246,5 @@ esp_eth_phy_t *esp_eth_phy_new_w5500(const eth_phy_config_t *config)
w5500->parent.del = w5500_del;
return &(w5500->parent);
err:
return NULL;
return ret;
}