1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu/esp32: add support for IP101G Ethernet phy

As used in ESP32-Ethernet-Kit board:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit.html

Inspired by existing code for lan8720 PHY as well as latest ESP32 code:
https://github.com/espressif/esp-idf/blob/master/components/esp_eth/src/esp_eth_phy_ip101.c

Phy datasheet available: http://www.bdtic.com/ICplus/IP101G.html
This commit is contained in:
Erik Ekman 2020-07-09 23:09:48 +02:00
parent 7237e38436
commit f28de6a544
5 changed files with 233 additions and 2 deletions

View File

@ -1142,7 +1142,7 @@ ESP32 provides different built-in possibilities to realize network devices:
\anchor esp32_ethernet_network_interface
## <a name="esp32_ethernet_network_interface"> Ethernet MAC Network Interface </a> &nbsp;[[TOC](#esp32_toc)]
ESP32 provides an <b>Ethernet MAC layer module (EMAC)</b> according to the IEEE 802.3 standard which can be used together with an external physical layer chip (PHY) to realize a 100/10 Mbps Ethernet interface. Supported PHY chips are the Microchip LAN8710/LAN8720 and the Texas Instruments TLK110.
ESP32 provides an <b>Ethernet MAC layer module (EMAC)</b> according to the IEEE 802.3 standard which can be used together with an external physical layer chip (PHY) to realize a 100/10 Mbps Ethernet interface. Supported PHY chips are the Microchip LAN8710/LAN8720, the IC Plus 101G, and the Texas Instruments TLK110.
The RIOT port for ESP32 realizes with module ```esp_eth``` a ```netdev``` driver for the EMAC which uses RIOT's standard Ethernet interface.

View File

@ -16,7 +16,7 @@
*
* @author Gunar Schorcht <gunar@schorcht.net>
ESP32 provides an <b>Ethernet MAC layer module (EMAC)</b> according to the IEEE 802.3 standard which can be used together with an external physical layer chip (PHY) to realize a 100/10 Mbps Ethernet interface. Supported PHY chips are the Microchip LAN8710/LAN8720 and the Texas Instruments TLK110.
ESP32 provides an <b>Ethernet MAC layer module (EMAC)</b> according to the IEEE 802.3 standard which can be used together with an external physical layer chip (PHY) to realize a 100/10 Mbps Ethernet interface. Supported PHY chips are the Microchip LAN8710/LAN8720, the IC Plus 101G, and the Texas Instruments TLK110.
The RIOT port for ESP32 realizes with module ```esp_eth``` a ```netdev``` driver for the EMAC which uses RIOT's standard Ethernet interface.

View File

@ -56,6 +56,10 @@
#include "eth_phy/phy_lan8720.h"
#define EMAC_ETHERNET_PHY_CONFIG phy_lan8720_default_ethernet_config
#endif
#ifdef EMAC_PHY_IP101G
#include "eth_phy/phy_ip101g.h"
#define EMAC_ETHERNET_PHY_CONFIG phy_ip101g_default_ethernet_config
#endif
#ifdef EMAC_PHY_TLK110
#include "eth_phy/phy_tlk110.h"
#define EMAC_ETHERNET_PHY_CONFIG phy_tlk110_default_ethernet_config

View File

@ -0,0 +1,154 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy/phy_ip101g.h"
#include "eth_phy/phy_reg.h"
/* Value of MII_PHY_IDENTIFIER_REGs for IC Plus IP101G
* (Except for bottom 4 bits of ID2, used for model revision)
*/
#define IP101G_PHY_ID1 0x0243
#define IP101G_PHY_ID2 0x0C50
#define IP101G_PHY_ID2_MASK 0xFFF0
/* IP101G-specific registers */
#define PAGE_CONTROL_REG (0x14)
#define POWER_DOWN BIT(11)
#define PHY_SPECIAL_CONTROL_STATUS_REG (0x12)
#define AUTO_NEGOTIATION_DONE BIT(11)
#define PHY_CTRL_AND_SPECIFIC_STATUS_REG (0x1e)
#define SPEED_DUPLEX_INDICATION_MASK (0x7)
#define SPEED_DUPLEX_INDICATION_10T_HALF 0x01
#define SPEED_DUPLEX_INDICATION_10T_FULL 0x05
#define SPEED_DUPLEX_INDICATION_100T_HALF 0x02
#define SPEED_DUPLEX_INDICATION_100T_FULL 0x06
static const char *TAG = "ip101";
static void phy_ip101g_page_select(uint8_t page)
{
ESP_LOGD(TAG, "phy_ip101g_page_select(%u)", page);
esp_eth_smi_write(PAGE_CONTROL_REG, page);
}
void phy_ip101g_check_phy_init(void)
{
phy_ip101g_dump_registers();
esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
phy_ip101g_page_select(16);
esp_eth_smi_wait_set(PHY_SPECIAL_CONTROL_STATUS_REG, AUTO_NEGOTIATION_DONE, 0);
}
eth_speed_mode_t phy_ip101g_get_speed_mode(void)
{
phy_ip101g_page_select(16);
uint16_t speed = esp_eth_smi_read(PHY_CTRL_AND_SPECIFIC_STATUS_REG) & SPEED_DUPLEX_INDICATION_MASK;
if (speed == SPEED_DUPLEX_INDICATION_100T_HALF || speed == SPEED_DUPLEX_INDICATION_100T_FULL) {
ESP_LOGD(TAG, "phy_ip101g_get_speed_mode(100)");
return ETH_SPEED_MODE_100M;
}
ESP_LOGD(TAG, "phy_ip101g_get_speed_mode(10)");
return ETH_SPEED_MODE_10M;
}
eth_duplex_mode_t phy_ip101g_get_duplex_mode(void)
{
phy_ip101g_page_select(16);
uint16_t speed = esp_eth_smi_read(PHY_CTRL_AND_SPECIFIC_STATUS_REG) & SPEED_DUPLEX_INDICATION_MASK;
if (speed == SPEED_DUPLEX_INDICATION_10T_FULL || speed == SPEED_DUPLEX_INDICATION_100T_FULL) {
ESP_LOGD(TAG, "phy_ip101g_get_duplex_mode(FULL)");
return ETH_MODE_FULLDUPLEX;
}
ESP_LOGD(TAG, "phy_ip101g_get_duplex_mode(HALF)");
return ETH_MODE_HALFDUPLEX;
}
void phy_ip101g_power_enable(bool enable)
{
ESP_LOGD(TAG, "phy_ip101g_power_enable(%d)", enable);
uint16_t cfg = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
if (enable) {
cfg &= (UINT16_MAX ^ POWER_DOWN);
} else {
cfg |= POWER_DOWN;
}
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, cfg);
// TODO: only enable if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
void phy_ip101g_init(void)
{
ESP_LOGD(TAG, "phy_ip101g_init()");
phy_ip101g_dump_registers();
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, MII_SOFTWARE_RESET);
esp_err_t res1, res2;
do {
// Call esp_eth_smi_wait_value() with a timeout so it prints an error periodically
res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, IP101G_PHY_ID1, UINT16_MAX, 1000);
res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, IP101G_PHY_ID2, IP101G_PHY_ID2_MASK, 1000);
} while(res1 != ESP_OK || res2 != ESP_OK);
ets_delay_us(300);
// TODO: only enable if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
const eth_config_t phy_ip101g_default_ethernet_config = {
// By default, the PHY address is 0 or 1 based on PHYAD0
// pin. Can also be overriden in software. See datasheet
// for defaults.
.phy_addr = 1,
.mac_mode = ETH_MODE_RMII,
.clock_mode = ETH_CLOCK_GPIO0_IN,
//Only FULLDUPLEX mode support flow ctrl now!
.flow_ctrl_enable = true,
.phy_init = phy_ip101g_init,
.phy_check_init = phy_ip101g_check_phy_init,
.phy_power_enable = phy_ip101g_power_enable,
.phy_check_link = phy_mii_check_link_status,
.phy_get_speed_mode = phy_ip101g_get_speed_mode,
.phy_get_duplex_mode = phy_ip101g_get_duplex_mode,
.phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable,
};
void phy_ip101g_dump_registers(void)
{
ESP_LOGD(TAG, "IP101G Registers:");
ESP_LOGD(TAG, "BCR 0x%04x", esp_eth_smi_read(0x0));
ESP_LOGD(TAG, "BSR 0x%04x", esp_eth_smi_read(0x1));
ESP_LOGD(TAG, "PHY1 0x%04x", esp_eth_smi_read(0x2));
ESP_LOGD(TAG, "PHY2 0x%04x", esp_eth_smi_read(0x3));
ESP_LOGD(TAG, "ANAR 0x%04x", esp_eth_smi_read(0x4));
ESP_LOGD(TAG, "ANLPAR 0x%04x", esp_eth_smi_read(0x5));
ESP_LOGD(TAG, "ANER 0x%04x", esp_eth_smi_read(0x6));
phy_ip101g_page_select(16);
ESP_LOGD(TAG, "PSCR 0x%04x", esp_eth_smi_read(0x10));
ESP_LOGD(TAG, "PSMR 0x%04x", esp_eth_smi_read(0x18));
ESP_LOGD(TAG, "PMCSSR 0x%04x", esp_eth_smi_read(0x1e));
}

View File

@ -0,0 +1,73 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ETHERNET_ETH_PHY_PHY_IP101G_H
#define ETHERNET_ETH_PHY_PHY_IP101G_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef RIOT_VERSION
#include "eth_phy/phy.h"
#else
#include "phy.h"
#endif
/** @brief Dump all IP101G PHY SMI configuration registers
*
* @note These registers are dumped at 'debug' level, so output
* may not be visible depending on default log levels.
*/
void phy_ip101g_dump_registers(void);
/** @brief Default IP101G phy_check_init function.
*/
void phy_ip101g_check_phy_init(void);
/** @brief Default IP101G phy_get_speed_mode function.
*/
eth_speed_mode_t phy_ip101g_get_speed_mode(void);
/** @brief Default IP101G phy_get_duplex_mode function.
*/
eth_duplex_mode_t phy_ip101g_get_duplex_mode(void);
/** @brief Default IP101G phy_power_enable function.
*
* @note This function may need to be replaced with a custom function
* if the PHY has a GPIO to enable power or start a clock.
*
* Consult the ethernet example to see how this is done.
*/
void phy_ip101g_power_enable(bool);
/** @brief Default IP101G phy_init function.
*/
void phy_ip101g_init(void);
/** @brief Default IP101G PHY configuration
*
* This configuration is not suitable for use as-is, it will need
* to be modified for your particular PHY hardware setup.
*
* Consult the Ethernet example to see how this is done.
*/
extern const eth_config_t phy_ip101g_default_ethernet_config;
#ifdef __cplusplus
}
#endif
#endif /* ETHERNET_ETH_PHY_PHY_IP101G_H */