ethernet: Add convenience functions esp_eth_smi_wait_value() & esp_eth_smi_wait_set()

Covers the common case of waiting for a particular PHY register to have a particular value.
This commit is contained in:
Angus Gratton 2017-04-19 13:43:25 +10:00 committed by Angus Gratton
parent 453722ba54
commit 453b5ded1d
5 changed files with 68 additions and 33 deletions

View File

@ -204,6 +204,25 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
return value; return value;
} }
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)
{
unsigned start = xTaskGetTickCount();
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS;
uint16_t current_value = 0;
while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) {
current_value = esp_eth_smi_read(reg_num);
if ((current_value & value_mask) == (value & value_mask)) {
return ESP_OK;
}
vTaskDelay(1);
}
ESP_LOGE(TAG, "Timed out waiting for PHY register 0x%x to have value 0x%04x (mask 0x%04x). Current value 0x%04x",
reg_num, value, value_mask, current_value);
return ESP_ERR_TIMEOUT;
}
static void emac_set_user_config_data(eth_config_t *config ) static void emac_set_user_config_data(eth_config_t *config )
{ {
emac_config.phy_addr = config->phy_addr; emac_config.phy_addr = config->phy_addr;

View File

@ -18,14 +18,12 @@
#include "eth_phy/phy_lan8720.h" #include "eth_phy/phy_lan8720.h"
#include "eth_phy/phy_reg.h" #include "eth_phy/phy_reg.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
/* Value of MII_PHY_IDENTIFIER_REGs for Microchip LAN8720 /* Value of MII_PHY_IDENTIFIER_REGs for Microchip LAN8720
* (Except for bottom 4 bits of ID2, used for model revision) * (Except for bottom 4 bits of ID2, used for model revision)
*/ */
#define LAN8720_PHY_ID1 0x0007 #define LAN8720_PHY_ID1 0x0007
#define LAN8720_PHY_ID2 0xc0f0 #define LAN8720_PHY_ID2 0xc0f0
#define LAN8720_PHY_ID2_MASK 0xFFF0
/* LAN8720-specific registers */ /* LAN8720-specific registers */
#define SW_STRAP_CONTROL_REG (0x9) #define SW_STRAP_CONTROL_REG (0x9)
@ -55,12 +53,8 @@ void phy_lan8720_check_phy_init(void)
{ {
phy_lan8720_dump_registers(); phy_lan8720_dump_registers();
while((esp_eth_smi_read(MII_BASIC_MODE_STATUS_REG) & MII_AUTO_NEGOTIATION_COMPLETE ) == 0) { esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
vTaskDelay(1); esp_eth_smi_wait_set(PHY_SPECIAL_CONTROL_STATUS_REG, AUTO_NEGOTIATION_DONE, 0);
}
while((esp_eth_smi_read(PHY_SPECIAL_CONTROL_STATUS_REG) & AUTO_NEGOTIATION_DONE ) == 0) {
vTaskDelay(1);
}
} }
eth_speed_mode_t phy_lan8720_get_speed_mode(void) eth_speed_mode_t phy_lan8720_get_speed_mode(void)
@ -101,14 +95,12 @@ void phy_lan8720_init(void)
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, MII_SOFTWARE_RESET); esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, MII_SOFTWARE_RESET);
unsigned phy_id1, phy_id2; esp_err_t res1, res2;
do { do {
vTaskDelay(1); // Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically
phy_id1 = esp_eth_smi_read(MII_PHY_IDENTIFIER_1_REG); res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, LAN8720_PHY_ID1, UINT16_MAX, 1000);
phy_id2 = esp_eth_smi_read(MII_PHY_IDENTIFIER_2_REG); res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, LAN8720_PHY_ID2, LAN8720_PHY_ID2_MASK, 1000);
ESP_LOGD(TAG, "PHY ID 0x%04x 0x%04x", phy_id1, phy_id2); } while(res1 != ESP_OK || res2 != ESP_OK);
phy_id2 &= 0xFFF0; // Remove model revision code
} while (phy_id1 != LAN8720_PHY_ID1 && phy_id2 != LAN8720_PHY_ID2);
esp_eth_smi_write(SW_STRAP_CONTROL_REG, esp_eth_smi_write(SW_STRAP_CONTROL_REG,
DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE); DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);

View File

@ -26,6 +26,7 @@
*/ */
#define TLK110_PHY_ID1 0x2000 #define TLK110_PHY_ID1 0x2000
#define TLK110_PHY_ID2 0xa210 #define TLK110_PHY_ID2 0xa210
#define TLK110_PHY_ID2_MASK 0xFFF0
/* TLK110-specific registers */ /* TLK110-specific registers */
#define SW_STRAP_CONTROL_REG (0x9) #define SW_STRAP_CONTROL_REG (0x9)
@ -56,15 +57,9 @@ void phy_tlk110_check_phy_init(void)
{ {
phy_tlk110_dump_registers(); phy_tlk110_dump_registers();
while((esp_eth_smi_read(MII_BASIC_MODE_STATUS_REG) & MII_AUTO_NEGOTIATION_COMPLETE ) == 0) { esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
vTaskDelay(1); esp_eth_smi_wait_set(PHY_STATUS_REG, AUTO_NEGOTIATION_STATUS, 0);
} esp_eth_smi_wait_set(CABLE_DIAGNOSTIC_CONTROL_REG, DIAGNOSTIC_DONE, 0);
while((esp_eth_smi_read(PHY_STATUS_REG) & AUTO_NEGOTIATION_STATUS ) == 0) {
vTaskDelay(1);
}
while((esp_eth_smi_read(CABLE_DIAGNOSTIC_CONTROL_REG) & DIAGNOSTIC_DONE ) == 0) {
vTaskDelay(1);
}
} }
eth_speed_mode_t phy_tlk110_get_speed_mode(void) eth_speed_mode_t phy_tlk110_get_speed_mode(void)
@ -106,14 +101,12 @@ void phy_tlk110_init(void)
esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET); esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET);
unsigned phy_id1, phy_id2; esp_err_t res1, res2;
do { do {
vTaskDelay(1); // Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically
phy_id1 = esp_eth_smi_read(MII_PHY_IDENTIFIER_1_REG); res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, TLK110_PHY_ID1, UINT16_MAX, 1000);
phy_id2 = esp_eth_smi_read(MII_PHY_IDENTIFIER_2_REG); res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, TLK110_PHY_ID2, TLK110_PHY_ID2_MASK, 1000);
ESP_LOGD(TAG, "PHY ID 0x%04x 0x%04x", phy_id1, phy_id2); } while(res1 != ESP_OK || res2 != ESP_OK);
phy_id2 &= 0xFFF0; // Remove model revision code
} while (phy_id1 != TLK110_PHY_ID1 && phy_id2 != TLK110_PHY_ID2);
esp_eth_smi_write(SW_STRAP_CONTROL_REG, esp_eth_smi_write(SW_STRAP_CONTROL_REG,
DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE); DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);

View File

@ -175,7 +175,7 @@ void esp_eth_get_mac(uint8_t mac[6]);
void esp_eth_smi_write(uint32_t reg_num, uint16_t value); void esp_eth_smi_write(uint32_t reg_num, uint16_t value);
/** /**
* @brief Write phy reg with smi interface. * @brief Read phy reg with smi interface.
* *
* @note phy base addr must be right. * @note phy base addr must be right.
* *
@ -185,6 +185,35 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value);
*/ */
uint16_t esp_eth_smi_read(uint32_t reg_num); uint16_t esp_eth_smi_read(uint32_t reg_num);
/**
* @brief Continuously read a PHY register over SMI interface, wait until the register has the desired value.
*
* @note PHY base address must be right.
*
* @param reg_num: PHY register number
* @param value: Value to wait for (masked with value_mask)
* @param value_mask: Mask of bits to match in the register.
* @param timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout.
*
* @return ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out.
*/
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms);
/**
* @brief Continuously read a PHY register over SMI interface, wait until the register has all bits in a mask set.
*
* @note PHY base address must be right.
*
* @param reg_num: PHY register number
* @param value_mask: Value mask to wait for (all bits in this mask must be set)
* @param timeout_ms: Timeout to wait for this value (milliseconds). 0 means never timeout.
*
* @return ESP_OK if desired value matches, ESP_ERR_TIMEOUT if timed out.
*/
static inline esp_err_t esp_eth_smi_wait_set(uint32_t reg_num, uint16_t value_mask, int timeout_ms) {
return esp_eth_smi_wait_value(reg_num, value_mask, value_mask, timeout_ms);
}
/** /**
* @brief Free emac rx buf. * @brief Free emac rx buf.
* *

View File

@ -62,6 +62,8 @@ Functions
.. doxygenfunction:: esp_eth_get_mac .. doxygenfunction:: esp_eth_get_mac
.. doxygenfunction:: esp_eth_smi_write .. doxygenfunction:: esp_eth_smi_write
.. doxygenfunction:: esp_eth_smi_read .. doxygenfunction:: esp_eth_smi_read
.. doxygenfunction:: esp_eth_smi_wait_value
.. doxygenfunction:: esp_eth_smi_wait_set
.. doxygenfunction:: esp_eth_free_rx_buf .. doxygenfunction:: esp_eth_free_rx_buf