ethernet:a bunch of bugfix from master

This commit is contained in:
morris 2019-11-28 16:00:18 +08:00
parent 96e6049dab
commit 97defec6cd
9 changed files with 517 additions and 382 deletions

View File

@ -40,7 +40,6 @@ static const char *TAG = "emac_dm9051";
} \
} while (0)
#define RX_QUEUE_WAIT_MS (100)
#define DM9051_SPI_LOCK_TIMEOUT_MS (50)
#define DM9051_PHY_OPERATION_TIMEOUT_US (1000)
@ -172,6 +171,30 @@ static esp_err_t dm9051_memory_read(emac_dm9051_t *emac, uint8_t *buffer, uint32
return ret;
}
/**
* @brief peek buffer from dm9051 internal memory (without internal cursor moved)
*/
static esp_err_t dm9051_memory_peek(emac_dm9051_t *emac, uint8_t *buffer, uint32_t len)
{
esp_err_t ret = ESP_OK;
spi_transaction_t trans = {
.cmd = DM9051_SPI_RD,
.addr = DM9051_MRCMDX1,
.length = len * 8,
.rx_buffer = buffer
};
if (dm9051_lock(emac)) {
if (spi_device_polling_transmit(emac->spi_hdl, &trans) != ESP_OK) {
ESP_LOGE(TAG, "%s(%d): spi transmit failed", __FUNCTION__, __LINE__);
ret = ESP_FAIL;
}
dm9051_unlock(emac);
} else {
ret = ESP_ERR_TIMEOUT;
}
return ret;
}
/**
* @brief read mac address from internal registers
*/
@ -254,10 +277,10 @@ static esp_err_t dm9051_verify_id(emac_dm9051_t *emac)
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(0x0A46 == *(uint16_t *)id, "wrong Vendor ID", err, ESP_ERR_INVALID_VERSION);
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(0x9051 == *(uint16_t *)id, "wrong Product ID", err, ESP_ERR_INVALID_VERSION);
MAC_CHECK(0x90 == id[1] && 0x51 == id[0], "wrong Product ID", err, ESP_ERR_INVALID_VERSION);
return ESP_OK;
err:
return ret;
@ -365,26 +388,27 @@ static void emac_dm9051_task(void *arg)
uint8_t *buffer = NULL;
uint32_t length = 0;
while (1) {
if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) {
/* clear interrupt status */
dm9051_register_read(emac, DM9051_ISR, &status);
dm9051_register_write(emac, DM9051_ISR, status);
/* packet received */
if (status & ISR_PR) {
do {
buffer = (uint8_t *)heap_caps_malloc(ETH_MAX_PACKET_SIZE, MALLOC_CAP_DMA);
if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
// block indefinitely until some task notifies me
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
/* clear interrupt status */
dm9051_register_read(emac, DM9051_ISR, &status);
dm9051_register_write(emac, DM9051_ISR, status);
/* packet received */
if (status & ISR_PR) {
do {
length = ETH_MAX_PACKET_SIZE;
buffer = (uint8_t *)heap_caps_malloc(length, MALLOC_CAP_DMA);
if (emac->parent.receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
} while (emac->packets_remain);
}
} else {
free(buffer);
}
} while (emac->packets_remain);
}
}
vTaskDelete(NULL);
@ -608,13 +632,26 @@ static esp_err_t emac_dm9051_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t
if (rxbyte > 1) {
MAC_CHECK(dm9051_stop(emac) == ESP_OK, "stop dm9051 failed", err, ESP_FAIL);
/* reset rx fifo pointer */
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK, "write MPTRCR failed", err, ESP_FAIL);
MAC_CHECK(dm9051_register_write(emac, DM9051_MPTRCR, MPTRCR_RST_RX) == ESP_OK,
"write MPTRCR failed", err, ESP_FAIL);
ets_delay_us(10);
MAC_CHECK(dm9051_start(emac) == ESP_OK, "start dm9051 failed", err, ESP_FAIL);
MAC_CHECK(false, "reset rx fifo pointer", err, ESP_FAIL);
} else if (rxbyte) {
MAC_CHECK(dm9051_memory_read(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK, "read rx header failed", err, ESP_FAIL);
MAC_CHECK(dm9051_memory_peek(emac, (uint8_t *)&header, sizeof(header)) == ESP_OK,
"peek rx header failed", err, ESP_FAIL);
rx_len = header.length_low + (header.length_high << 8);
/* check if the buffer can hold all the incoming data */
if (*length < rx_len - 4) {
ESP_LOGE(TAG, "buffer size too small");
/* tell upper layer the size we need */
*length = rx_len - 4;
ret = ESP_ERR_INVALID_SIZE;
goto err;
}
MAC_CHECK(*length >= rx_len - 4, "buffer size too small", err, ESP_ERR_INVALID_SIZE);
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);
*length = rx_len - 4; // substract the CRC length (4Bytes)
@ -681,9 +718,10 @@ static esp_err_t emac_dm9051_del(esp_eth_mac_t *mac)
esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_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);
emac_dm9051_t *emac = calloc(1, sizeof(emac_dm9051_t));
emac = calloc(1, sizeof(emac_dm9051_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL);
/* dm9051 receive is driven by interrupt only for now*/
MAC_CHECK(dm9051_config->int_gpio_num >= 0, "error interrupt gpio number", err, NULL);
@ -707,16 +745,22 @@ 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_lock, NULL);
MAC_CHECK(emac->spi_lock, "create lock failed", err, NULL);
/* create dm9051 task */
BaseType_t xReturned = xTaskCreate(emac_dm9051_task, "dm9051_tsk", mac_config->rx_task_stack_size, emac,
mac_config->rx_task_prio, &emac->rx_task_hdl);
MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err_tsk, NULL);
MAC_CHECK(xReturned == pdPASS, "create dm9051 task failed", err, NULL);
return &(emac->parent);
err_tsk:
vSemaphoreDelete(emac->spi_lock);
err_lock:
free(emac);
err:
if (emac) {
if (emac->rx_task_hdl) {
vTaskDelete(emac->rx_task_hdl);
}
if (emac->spi_lock) {
vSemaphoreDelete(emac->spi_lock);
}
free(emac);
}
return ret;
}

View File

@ -41,7 +41,6 @@ static const char *TAG = "emac_esp32";
} \
} while (0)
#define RX_QUEUE_WAIT_MS (20)
#define PHY_OPERATION_TIMEOUT_US (1000)
typedef struct {
@ -227,7 +226,16 @@ static esp_err_t emac_esp32_receive(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);
MAC_CHECK(buf && length, "can't set buf and length to null", err, ESP_ERR_INVALID_ARG);
*length = emac_hal_receive_frame(&emac->hal, buf, &emac->frames_remain);
uint32_t receive_len = emac_hal_receive_frame(&emac->hal, buf, *length, &emac->frames_remain);
/* we need to check the return value in case the buffer size is not enough */
if (*length < receive_len) {
ESP_LOGE(TAG, "buffer size too small");
/* tell upper layer the size we need */
*length = receive_len;
ret = ESP_ERR_INVALID_SIZE;
goto err;
}
*length = receive_len;
return ESP_OK;
err:
return ret;
@ -239,21 +247,22 @@ static void emac_esp32_rx_task(void *arg)
uint8_t *buffer = NULL;
uint32_t length = 0;
while (1) {
if (ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(RX_QUEUE_WAIT_MS))) {
do {
buffer = (uint8_t *)malloc(ETH_MAX_PACKET_SIZE);
if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
// block indefinitely until some task notifies me
ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
do {
length = ETH_MAX_PACKET_SIZE;
buffer = (uint8_t *)malloc(length);
if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
/* pass the buffer to stack (e.g. TCP/IP layer) */
if (length) {
emac->eth->stack_input(emac->eth, buffer, length);
} else {
free(buffer);
}
} while (emac->frames_remain);
}
} else {
free(buffer);
}
} while (emac->frames_remain);
}
vTaskDelete(NULL);
}
@ -353,43 +362,30 @@ IRAM_ATTR void emac_esp32_isr_handler(void *args)
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);
emac_esp32_t *emac = calloc(1, sizeof(emac_esp32_t));
emac = calloc(1, sizeof(emac_esp32_t));
MAC_CHECK(emac, "calloc emac failed", err, NULL);
/* 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);
void *descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
MAC_CHECK(descriptors, "calloc descriptors failed", err_desc, NULL);
descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
MAC_CHECK(descriptors, "calloc descriptors failed", err, NULL);
int i = 0;
/* alloc memory for ethernet dma buffer */
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
if (!(emac->rx_buf[i])) {
break;
goto err;
}
}
if (i != CONFIG_ETH_DMA_RX_BUFFER_NUM) {
for (--i; i >= 0; i--) {
free(emac->rx_buf[i]);
}
goto err_buffer;
}
for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
if (!(emac->tx_buf[i])) {
break;
goto err;
}
}
if (i != CONFIG_ETH_DMA_TX_BUFFER_NUM) {
for (--i; i >= 0; i--) {
free(emac->tx_buf[i]);
}
for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->rx_buf[i]);
}
goto err_buffer;
}
/* initialize hal layer driver */
emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf);
emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
@ -412,26 +408,32 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
/* Interrupt configuration */
MAC_CHECK(esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM, emac_esp32_isr_handler,
&emac->hal, &(emac->intr_hdl)) == ESP_OK,
"alloc emac interrupt failed", err_intr, NULL);
"alloc emac interrupt failed", err, NULL);
/* create rx task */
BaseType_t xReturned = xTaskCreate(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac,
config->rx_task_prio, &emac->rx_task_hdl);
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err_task, NULL);
MAC_CHECK(xReturned == pdPASS, "create emac_rx task failed", err, NULL);
return &(emac->parent);
err_task:
esp_intr_free(emac->intr_hdl);
err_intr:
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->tx_buf[i]);
}
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->rx_buf[i]);
}
err_buffer:
free(descriptors);
err_desc:
free(emac);
err:
if (emac) {
if (emac->rx_task_hdl) {
vTaskDelete(emac->rx_task_hdl);
}
if (emac->intr_hdl) {
esp_intr_free(emac->intr_hdl);
}
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
free(emac->tx_buf[i]);
}
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
free(emac->rx_buf[i]);
}
free(emac);
}
if (descriptors) {
free(descriptors);
}
return ret;
}

View File

@ -80,7 +80,6 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
@ -88,9 +87,49 @@ typedef struct {
int reset_gpio_num;
} phy_dm9051_t;
static esp_err_t dm9051_update_link_duplex_speed(phy_dm9051_t *dm9051)
{
esp_eth_mediator_t *eth = dm9051->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
dscsr_reg_t dscsr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* 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);
if (dscsr.fdx100 || dscsr.hdx100) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (dscsr.fdx100 || dscsr.fdx10) {
duplex = ETH_DUPLEX_FULL;
} 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);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
dm9051->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dm9051_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for dm9051 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
dm9051->eth = eth;
return ESP_OK;
@ -101,19 +140,8 @@ err:
static esp_err_t dm9051_get_link(esp_eth_phy_t *phy)
{
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (dm9051->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dm9051->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -125,17 +153,22 @@ static esp_err_t dm9051_reset(esp_eth_phy_t *phy)
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);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, &(dscr.val)) == ESP_OK,
"read DSCR failed", err);
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);
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_DSCR_REG_ADDR, dscr.val) == ESP_OK,
"write DSCR failed", err);
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);
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
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);
if (!bmcr.reset && !dscr.smrst) {
break;
}
@ -170,15 +203,18 @@ 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);
PHY_CHECK(eth->phy_reg_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
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);
if (bmsr.auto_nego_complete && dscsr.anmb & 0x08) {
break;
}
@ -187,27 +223,7 @@ 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(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);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (dscsr.fdx100 || dscsr.hdx100) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (dscsr.fdx100 || dscsr.fdx10) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (dm9051->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dm9051->link_status = link;
}
PHY_CHECK(dm9051_update_link_duplex_speed(dm9051) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -218,7 +234,8 @@ static esp_err_t dm9051_pwrctl(esp_eth_phy_t *phy, bool enable)
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);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -226,8 +243,10 @@ 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);
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_write(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dm9051->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@ -247,7 +266,7 @@ 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, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
*addr = dm9051->addr;
return ESP_OK;
@ -267,15 +286,18 @@ static esp_err_t dm9051_init(esp_eth_phy_t *phy)
phy_dm9051_t *dm9051 = __containerof(phy, phy_dm9051_t, parent);
esp_eth_mediator_t *eth = dm9051->eth;
/* Power on Ethernet PHY */
PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(dm9051_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(dm9051_reset(phy) == ESP_OK, "reset failed", err);
/* 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 PHY chip ID", err);
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);
return ESP_OK;
err:
return ESP_FAIL;
@ -284,7 +306,7 @@ err:
static esp_err_t dm9051_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(dm9051_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -295,8 +317,7 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
PHY_CHECK(config, "can't set phy config to null", err);
PHY_CHECK(config->phy_addr == 1, "dm9051's phy address can only set to 1", err);
phy_dm9051_t *dm9051 = calloc(1, sizeof(phy_dm9051_t));
PHY_CHECK(dm9051, "calloc dm9051 object failed", err);
dm9051->name = "dm9051";
PHY_CHECK(dm9051, "calloc dm9051 failed", err);
dm9051->addr = config->phy_addr;
dm9051->reset_timeout_ms = config->reset_timeout_ms;
dm9051->reset_gpio_num = config->reset_gpio_num;
@ -313,7 +334,6 @@ esp_eth_phy_t *esp_eth_phy_new_dm9051(const eth_phy_config_t *config)
dm9051->parent.get_addr = dm9051_get_addr;
dm9051->parent.set_addr = dm9051_set_addr;
dm9051->parent.del = dm9051_del;
return &(dm9051->parent);
err:
return NULL;

View File

@ -86,7 +86,6 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
@ -94,9 +93,49 @@ typedef struct {
int reset_gpio_num;
} phy_dp83848_t;
static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848)
{
esp_eth_mediator_t *eth = dp83848->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
physts_reg_t physts;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (dp83848->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_STS_REG_ADDR, &(physts.val)) == ESP_OK,
"read PHYSTS failed", err);
if (physts.speed_status) {
speed = ETH_SPEED_10M;
} else {
speed = ETH_SPEED_100M;
}
if (physts.duplex_status) {
duplex = ETH_DUPLEX_FULL;
} 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);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
dp83848->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t dp83848_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for dp83848 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
dp83848->eth = eth;
return ESP_OK;
@ -107,19 +146,8 @@ err:
static esp_err_t dp83848_get_link(esp_eth_phy_t *phy)
{
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (dp83848->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dp83848->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -131,17 +159,19 @@ static esp_err_t dp83848_reset(esp_eth_phy_t *phy)
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);
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < dp83848->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -170,45 +200,28 @@ 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);
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
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);
if (bmsr.auto_nego_complete && physts.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= dp83848->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
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);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (physts.speed_status) {
speed = ETH_SPEED_10M;
} else {
speed = ETH_SPEED_100M;
}
if (physts.duplex_status) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (dp83848->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
dp83848->link_status = link;
}
PHY_CHECK(dp83848_update_link_duplex_speed(dp83848) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -219,7 +232,8 @@ static esp_err_t dp83848_pwrctl(esp_eth_phy_t *phy, bool enable)
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);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -227,8 +241,10 @@ 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);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, dp83848->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@ -248,7 +264,7 @@ 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, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
*addr = dp83848->addr;
return ESP_OK;
@ -268,15 +284,18 @@ static esp_err_t dp83848_init(esp_eth_phy_t *phy)
phy_dp83848_t *dp83848 = __containerof(phy, phy_dp83848_t, parent);
esp_eth_mediator_t *eth = dp83848->eth;
/* Power on Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(dp83848_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(dp83848_reset(phy) == ESP_OK, "reset failed", err);
/* 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 PHY chip ID", err);
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);
return ESP_OK;
err:
return ESP_FAIL;
@ -285,7 +304,7 @@ err:
static esp_err_t dp83848_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(dp83848_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -295,8 +314,7 @@ 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);
phy_dp83848_t *dp83848 = calloc(1, sizeof(phy_dp83848_t));
PHY_CHECK(dp83848, "calloc dp83848 object failed", err);
dp83848->name = "dp83848";
PHY_CHECK(dp83848, "calloc dp83848 failed", err);
dp83848->addr = config->phy_addr;
dp83848->reset_timeout_ms = config->reset_timeout_ms;
dp83848->link_status = ETH_LINK_DOWN;

View File

@ -103,7 +103,6 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
@ -123,9 +122,62 @@ err:
return ESP_FAIL;
}
static esp_err_t ip101_update_link_duplex_speed(phy_ip101_t *ip101)
{
esp_eth_mediator_t *eth = ip101->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
cssr_reg_t cssr;
bmsr_reg_t bmsr;
PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page 16 failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* check if link status changed */
if (ip101->link_status != link) {
/* when link up, read negotiation result */
if (link == ETH_LINK_UP) {
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_CSSR_REG_ADDR, &(cssr.val)) == ESP_OK,
"read CSSR failed", err);
switch (cssr.op_mode) {
case 1: //10M Half
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100M Half
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10M Full
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100M Full
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
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);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"chagne link failed", err);
ip101->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t ip101_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for ip101 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
ip101->eth = eth;
return ESP_OK;
@ -136,19 +188,8 @@ err:
static esp_err_t ip101_get_link(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (ip101->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
ip101->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -160,17 +201,19 @@ static esp_err_t ip101_reset(esp_eth_phy_t *phy)
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);
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < ip101->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < ip101->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -192,65 +235,32 @@ static esp_err_t ip101_negotiate(esp_eth_phy_t *phy)
{
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Start auto negotiation */
/* Restart auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.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);
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
if (bmsr.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= ip101->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
PHY_CHECK(ip101_page_select(ip101, 16) == ESP_OK, "select page failed", err);
/* Updata information about link, speed, duplex */
cssr_reg_t cssr;
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_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
switch (cssr.op_mode) {
case 0: //Link off
link = ETH_LINK_DOWN;
break;
case 1: //10M Half
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100M Half
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10M Full
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100M Full
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (ip101->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
ip101->link_status = link;
}
PHY_CHECK(ip101_update_link_duplex_speed(ip101) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -261,7 +271,8 @@ static esp_err_t ip101_pwrctl(esp_eth_phy_t *phy, bool enable)
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);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -269,8 +280,10 @@ 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);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, ip101->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@ -290,7 +303,7 @@ 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, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
*addr = ip101->addr;
return ESP_OK;
@ -310,15 +323,15 @@ static esp_err_t ip101_init(esp_eth_phy_t *phy)
phy_ip101_t *ip101 = __containerof(phy, phy_ip101_t, parent);
esp_eth_mediator_t *eth = ip101->eth;
/* Power on Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(ip101_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(ip101_reset(phy) == ESP_OK, "reset failed", err);
/* 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 PHY chip ID", err);
PHY_CHECK(id1.oui_msb == 0x243 && id2.oui_lsb == 0x3 && id2.vendor_model == 0x5, "wrong chip ID", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -327,7 +340,7 @@ err:
static esp_err_t ip101_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(ip101_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -337,8 +350,7 @@ 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);
phy_ip101_t *ip101 = calloc(1, sizeof(phy_ip101_t));
PHY_CHECK(ip101, "calloc ip101 object failed", err);
ip101->name = "ip101";
PHY_CHECK(ip101, "calloc ip101 failed", err);
ip101->addr = config->phy_addr;
ip101->reset_timeout_ms = config->reset_timeout_ms;
ip101->reset_gpio_num = config->reset_gpio_num;

View File

@ -158,7 +158,6 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
@ -166,9 +165,59 @@ typedef struct {
int reset_gpio_num;
} phy_lan8720_t;
static esp_err_t lan8720_update_link_duplex_speed(phy_lan8720_t *lan8720)
{
esp_eth_mediator_t *eth = lan8720->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmsr_reg_t bmsr;
pscsr_reg_t pscsr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
/* 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);
switch (pscsr.speed_indication) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100Base-TX half-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10Base-T full-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100Base-TX full-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
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);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
lan8720->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t lan8720_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for lan8720 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
lan8720->eth = eth;
return ESP_OK;
@ -179,19 +228,8 @@ err:
static esp_err_t lan8720_get_link(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (lan8720->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
lan8720->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -203,17 +241,19 @@ static esp_err_t lan8720_reset(esp_eth_phy_t *phy)
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);
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < lan8720->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -235,7 +275,7 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
{
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Start auto negotiation */
/* Restart auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
@ -249,48 +289,20 @@ static esp_err_t lan8720_negotiate(esp_eth_phy_t *phy)
int32_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);
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);
if (bmsr.auto_nego_complete && pscsr.auto_nego_done) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= lan8720->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
/* Updata information about link, speed, duplex */
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);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
switch (pscsr.speed_indication) {
case 1: //10Base-T half-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_HALF;
break;
case 2: //100Base-TX half-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_HALF;
break;
case 5: //10Base-T full-duplex
speed = ETH_SPEED_10M;
duplex = ETH_DUPLEX_FULL;
break;
case 6: //100Base-TX full-duplex
speed = ETH_SPEED_100M;
duplex = ETH_DUPLEX_FULL;
break;
default:
break;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (lan8720->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
lan8720->link_status = link;
}
PHY_CHECK(lan8720_update_link_duplex_speed(lan8720) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -301,7 +313,8 @@ static esp_err_t lan8720_pwrctl(esp_eth_phy_t *phy, bool enable)
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);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* General Power Down Mode */
bmcr.power_down = 1;
@ -309,8 +322,10 @@ 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);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, lan8720->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@ -330,7 +345,7 @@ 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, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
*addr = lan8720->addr;
return ESP_OK;
@ -350,15 +365,17 @@ static esp_err_t lan8720_init(esp_eth_phy_t *phy)
phy_lan8720_t *lan8720 = __containerof(phy, phy_lan8720_t, parent);
esp_eth_mediator_t *eth = lan8720->eth;
/* Power on Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(lan8720_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(lan8720_reset(phy) == ESP_OK, "reset failed", err);
/* 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 PHY chip ID", err);
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);
return ESP_OK;
err:
return ESP_FAIL;
@ -367,7 +384,7 @@ err:
static esp_err_t lan8720_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(lan8720_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -377,8 +394,7 @@ 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);
phy_lan8720_t *lan8720 = calloc(1, sizeof(phy_lan8720_t));
PHY_CHECK(lan8720, "calloc lan8720 object failed", err);
lan8720->name = "lan8720";
PHY_CHECK(lan8720, "calloc lan8720 failed", err);
lan8720->addr = config->phy_addr;
lan8720->reset_gpio_num = config->reset_gpio_num;
lan8720->reset_timeout_ms = config->reset_timeout_ms;

View File

@ -64,7 +64,6 @@ typedef union {
typedef struct {
esp_eth_phy_t parent;
esp_eth_mediator_t *eth;
const char *name;
uint32_t addr;
uint32_t reset_timeout_ms;
uint32_t autonego_timeout_ms;
@ -84,9 +83,50 @@ err:
return ESP_FAIL;
}
static esp_err_t rtl8201_update_link_duplex_speed(phy_rtl8201_t *rtl8201)
{
esp_eth_mediator_t *eth = rtl8201->eth;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
bmcr_reg_t bmcr;
bmsr_reg_t bmsr;
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);
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);
if (bmcr.speed_select) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (bmcr.duplex_mode) {
duplex = ETH_DUPLEX_FULL;
} 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);
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK,
"change link failed", err);
rtl8201->link_status = link;
}
return ESP_OK;
err:
return ESP_FAIL;
}
static esp_err_t rtl8201_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth)
{
PHY_CHECK(eth, "can't set mediator for rtl8201 to null", err);
PHY_CHECK(eth, "can't set mediator to null", err);
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
rtl8201->eth = eth;
return ESP_OK;
@ -97,19 +137,8 @@ err:
static esp_err_t rtl8201_get_link(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
bmsr_reg_t bmsr;
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
if (rtl8201->link_status != link) {
if (link == ETH_LINK_UP) {
phy->negotiate(phy);
} else {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
rtl8201->link_status = link;
}
}
/* Updata information about link, speed, duplex */
PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -121,17 +150,19 @@ static esp_err_t rtl8201_reset(esp_eth_phy_t *phy)
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);
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!bmcr.reset) {
break;
}
}
PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "PHY reset timeout", err);
PHY_CHECK(to < rtl8201->reset_timeout_ms / 10, "reset timeout", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -153,51 +184,32 @@ static esp_err_t rtl8201_negotiate(esp_eth_phy_t *phy)
{
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Start auto negotiation */
/* Restart auto negotiation */
bmcr_reg_t bmcr = {
.speed_select = 1, /* 100Mbps */
.duplex_mode = 1, /* Full Duplex */
.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);
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
/* 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);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK,
"read BMSR failed", err);
if (bmsr.auto_nego_complete) {
break;
}
}
/* Auto negotiation failed, maybe no network cable plugged in, so output a warning */
if (to >= rtl8201->autonego_timeout_ms / 10) {
ESP_LOGW(TAG, "Ethernet PHY auto negotiation timeout");
ESP_LOGW(TAG, "auto negotiation timeout");
}
PHY_CHECK(rtl8201_page_select(rtl8201, 0) == ESP_OK, "select page failed", err);
/* Updata information about link, speed, duplex */
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)) == ESP_OK, "read BMSR failed", err);
eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN;
eth_speed_t speed = ETH_SPEED_10M;
eth_duplex_t duplex = ETH_DUPLEX_HALF;
if (bmcr.speed_select) {
speed = ETH_SPEED_100M;
} else {
speed = ETH_SPEED_10M;
}
if (bmcr.duplex_mode) {
duplex = ETH_DUPLEX_FULL;
} else {
duplex = ETH_DUPLEX_HALF;
}
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_SPEED, (void *)speed) == ESP_OK, "send speed event failed", err);
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_DUPLEX, (void *)duplex) == ESP_OK, "send duplex event failed", err);
if (rtl8201->link_status != link) {
PHY_CHECK(eth->on_state_changed(eth, ETH_STATE_LINK, (void *)link) == ESP_OK, "send link event failed", err);
rtl8201->link_status = link;
}
PHY_CHECK(rtl8201_update_link_duplex_speed(rtl8201) == ESP_OK, "update link duplex speed failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -208,7 +220,8 @@ static esp_err_t rtl8201_pwrctl(esp_eth_phy_t *phy, bool enable)
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);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
/* Enable IEEE Power Down Mode */
bmcr.power_down = 1;
@ -216,8 +229,10 @@ 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);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK, "read BMCR failed", err);
PHY_CHECK(eth->phy_reg_write(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, bmcr.val) == ESP_OK,
"write BMCR failed", err);
PHY_CHECK(eth->phy_reg_read(eth, rtl8201->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)) == ESP_OK,
"read BMCR failed", err);
if (!enable) {
PHY_CHECK(bmcr.power_down == 1, "power down failed", err);
} else {
@ -237,7 +252,7 @@ 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, "get phy address failed", err);
PHY_CHECK(addr, "addr can't be null", err);
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
*addr = rtl8201->addr;
return ESP_OK;
@ -257,15 +272,18 @@ static esp_err_t rtl8201_init(esp_eth_phy_t *phy)
phy_rtl8201_t *rtl8201 = __containerof(phy, phy_rtl8201_t, parent);
esp_eth_mediator_t *eth = rtl8201->eth;
/* Power on Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power on Ethernet PHY failed", err);
PHY_CHECK(rtl8201_pwrctl(phy, true) == ESP_OK, "power control failed", err);
/* Reset Ethernet PHY */
PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset Ethernet PHY failed", err);
PHY_CHECK(rtl8201_reset(phy) == ESP_OK, "reset failed", err);
/* 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 PHY chip ID", err);
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);
return ESP_OK;
err:
return ESP_FAIL;
@ -274,7 +292,7 @@ err:
static esp_err_t rtl8201_deinit(esp_eth_phy_t *phy)
{
/* Power off Ethernet PHY */
PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power off Ethernet PHY failed", err);
PHY_CHECK(rtl8201_pwrctl(phy, false) == ESP_OK, "power control failed", err);
return ESP_OK;
err:
return ESP_FAIL;
@ -284,8 +302,7 @@ 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);
phy_rtl8201_t *rtl8201 = calloc(1, sizeof(phy_rtl8201_t));
PHY_CHECK(rtl8201, "calloc rtl8201 object failed", err);
rtl8201->name = "rtl8201";
PHY_CHECK(rtl8201, "calloc rtl8201 failed", err);
rtl8201->addr = config->phy_addr;
rtl8201->reset_gpio_num = config->reset_gpio_num;
rtl8201->reset_timeout_ms = config->reset_timeout_ms;

View File

@ -482,7 +482,7 @@ void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t len
hal->dma_regs->dmatxpolldemand = 0;
}
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain)
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain)
{
eth_dma_rx_descriptor_t *desc_iter = NULL;
eth_dma_rx_descriptor_t *first_desc = NULL;
@ -501,6 +501,12 @@ uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t
if (desc_iter->RDES0.LastDescriptor) {
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH;
/* check if the buffer can store the whole frame */
if (len > size) {
/* return the real size that we want */
/* user need to compare the return value to the size they prepared when this function returned */
return len;
}
/* update unhandled frame count */
frame_count++;
}

View File

@ -380,7 +380,7 @@ uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal);
void emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length);
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t *frames_remain);
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain);
void emac_hal_isr(void *arg);