esp-idf/components/ethernet/eth_phy/phy_tlk110.c

175 lines
6.7 KiB
C

// 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.
#include "esp_attr.h"
#include "esp_log.h"
#include "esp_eth.h"
#include "eth_phy/phy_tlk110.h"
#include "eth_phy/phy_reg.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
/* Value of MII_PHY_IDENTIFIER_REG for TI TLK110,
Excluding bottom 4 bytes of ID2, used for model revision
*/
#define TLK110_PHY_ID1 0x2000
#define TLK110_PHY_ID2 0xa210
#define TLK110_PHY_ID2_MASK 0xFFF0
/* TLK110-specific registers */
#define SW_STRAP_CONTROL_REG (0x9)
#define SW_STRAP_CONFIG_DONE BIT(15)
#define AUTO_MDIX_ENABLE BIT(14)
#define AUTO_NEGOTIATION_ENABLE BIT(13)
#define AN_1 BIT(12)
#define AN_0 BIT(11)
#define LED_CFG BIT(10)
#define RMII_ENHANCED_MODE BIT(9)
#define DEFAULT_STRAP_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG)
#define PHY_STATUS_REG (0x10)
#define AUTO_NEGOTIATION_STATUS BIT(4)
#define DUPLEX_STATUS BIT(2)
#define SPEED_STATUS BIT(1)
#define CABLE_DIAGNOSTIC_CONTROL_REG (0x1e)
#define DIAGNOSTIC_DONE BIT(1)
#define PHY_RESET_CONTROL_REG (0x1f)
#define SOFTWARE_RESET BIT(15)
static const char *TAG = "tlk110";
void phy_tlk110_check_phy_init(void)
{
phy_tlk110_dump_registers();
esp_eth_smi_wait_set(MII_BASIC_MODE_STATUS_REG, MII_AUTO_NEGOTIATION_COMPLETE, 0);
esp_eth_smi_wait_set(PHY_STATUS_REG, AUTO_NEGOTIATION_STATUS, 0);
esp_eth_smi_wait_set(CABLE_DIAGNOSTIC_CONTROL_REG, DIAGNOSTIC_DONE, 0);
}
eth_speed_mode_t phy_tlk110_get_speed_mode(void)
{
if((esp_eth_smi_read(PHY_STATUS_REG) & SPEED_STATUS ) != SPEED_STATUS) {
ESP_LOGD(TAG, "phy_tlk110_get_speed_mode(100)");
return ETH_SPEED_MODE_100M;
} else {
ESP_LOGD(TAG, "phy_tlk110_get_speed_mode(10)");
return ETH_SPEED_MODE_10M;
}
}
eth_duplex_mode_t phy_tlk110_get_duplex_mode(void)
{
if((esp_eth_smi_read(PHY_STATUS_REG) & DUPLEX_STATUS ) == DUPLEX_STATUS) {
ESP_LOGD(TAG, "phy_tlk110_get_duplex_mode(FULL)");
return ETH_MODE_FULLDUPLEX;
} else {
ESP_LOGD(TAG, "phy_tlk110_get_duplex_mode(HALF)");
return ETH_MODE_HALFDUPLEX;
}
}
void phy_tlk110_power_enable(bool enable)
{
if (enable) {
esp_eth_smi_write(SW_STRAP_CONTROL_REG, DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
// TODO: only do this if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
}
void phy_tlk110_init(void)
{
ESP_LOGD(TAG, "phy_tlk110_init()");
phy_tlk110_dump_registers();
esp_eth_smi_write(PHY_RESET_CONTROL_REG, 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, TLK110_PHY_ID1, UINT16_MAX, 1000);
res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, TLK110_PHY_ID2, TLK110_PHY_ID2_MASK, 1000);
} while(res1 != ESP_OK || res2 != ESP_OK);
esp_eth_smi_write(SW_STRAP_CONTROL_REG,
DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
ets_delay_us(300);
// TODO: only do this if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
const eth_config_t phy_tlk110_default_ethernet_config = {
// PHY address configured by PHYADx pins. Default value of 0x1
// is used if all pins are unconnected.
.phy_addr = 0x1,
.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_tlk110_init,
.phy_check_init = phy_tlk110_check_phy_init,
.phy_check_link = phy_mii_check_link_status,
.phy_get_speed_mode = phy_tlk110_get_speed_mode,
.phy_get_duplex_mode = phy_tlk110_get_duplex_mode,
.phy_get_partner_pause_enable = phy_mii_get_partner_pause_enable,
.phy_power_enable = phy_tlk110_power_enable,
};
void phy_tlk110_dump_registers()
{
ESP_LOGD(TAG, "TLK110 Registers:");
ESP_LOGD(TAG, "BMCR 0x%04x", esp_eth_smi_read(0x0));
ESP_LOGD(TAG, "BMSR 0x%04x", esp_eth_smi_read(0x1));
ESP_LOGD(TAG, "PHYIDR1 0x%04x", esp_eth_smi_read(0x2));
ESP_LOGD(TAG, "PHYIDR2 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));
ESP_LOGD(TAG, "ANNPTR 0x%04x", esp_eth_smi_read(0x7));
ESP_LOGD(TAG, "ANLNPTR 0x%04x", esp_eth_smi_read(0x8));
ESP_LOGD(TAG, "SWSCR1 0x%04x", esp_eth_smi_read(0x9));
ESP_LOGD(TAG, "SWSCR2 0x%04x", esp_eth_smi_read(0xa));
ESP_LOGD(TAG, "SWSCR3 0x%04x", esp_eth_smi_read(0xb));
ESP_LOGD(TAG, "REGCR 0x%04x", esp_eth_smi_read(0xd));
ESP_LOGD(TAG, "ADDAR 0x%04x", esp_eth_smi_read(0xe));
ESP_LOGD(TAG, "PHYSTS 0x%04x", esp_eth_smi_read(0x10));
ESP_LOGD(TAG, "PHYSCR 0x%04x", esp_eth_smi_read(0x11));
ESP_LOGD(TAG, "MISR1 0x%04x", esp_eth_smi_read(0x12));
ESP_LOGD(TAG, "MISR2 0x%04x", esp_eth_smi_read(0x13));
ESP_LOGD(TAG, "FCSCR 0x%04x", esp_eth_smi_read(0x14));
ESP_LOGD(TAG, "RECR 0x%04x", esp_eth_smi_read(0x15));
ESP_LOGD(TAG, "BISCR 0x%04x", esp_eth_smi_read(0x16));
ESP_LOGD(TAG, "RBR 0x%04x", esp_eth_smi_read(0x17));
ESP_LOGD(TAG, "LEDCR 0x%04x", esp_eth_smi_read(0x18));
ESP_LOGD(TAG, "PHYCR 0x%04x", esp_eth_smi_read(0x19));
ESP_LOGD(TAG, "10BTSCR 0x%04x", esp_eth_smi_read(0x1a));
ESP_LOGD(TAG, "BICSR1 0x%04x", esp_eth_smi_read(0x1b));
ESP_LOGD(TAG, "BICSR2 0x%04x", esp_eth_smi_read(0x1c));
ESP_LOGD(TAG, "CDCR 0x%04x", esp_eth_smi_read(0x1e));
ESP_LOGD(TAG, "TRXCPSR 0x%04x", esp_eth_smi_read(0x42));
ESP_LOGD(TAG, "PWRBOCR 0x%04x", esp_eth_smi_read(0xae));
ESP_LOGD(TAG, "VRCR 0x%04x", esp_eth_smi_read(0xD0));
ESP_LOGD(TAG, "ALCDRR1 0x%04x", esp_eth_smi_read(0x155));
ESP_LOGD(TAG, "CDSCR1 0x%04x", esp_eth_smi_read(0x170));
ESP_LOGD(TAG, "CDSCR2 0x%04x", esp_eth_smi_read(0x171));
}