2021-11-04 09:10:19 +01:00
/*
2023-08-02 12:28:18 +02:00
* SPDX - FileCopyrightText : 2019 - 2023 Espressif Systems ( Shanghai ) CO LTD
2021-11-04 09:10:19 +01:00
*
* SPDX - License - Identifier : Apache - 2.0
*/
2019-04-10 16:24:50 +08:00
# include <string.h>
# include <stdlib.h>
# include <sys/cdefs.h>
# include "esp_log.h"
2021-04-01 20:00:54 +08:00
# include "esp_check.h"
2022-05-13 12:03:56 +02:00
# include "esp_eth_phy_802_3.h"
2019-04-10 16:24:50 +08:00
static const char * TAG = " dp83848 " ;
/***************Vendor Specific Register***************/
/**
* @ brief PHYSTS ( PHY Status Register )
*
*/
typedef union {
struct {
uint32_t link_status : 1 ; /* Link Status */
2019-12-23 17:06:02 +08:00
uint32_t speed_status : 1 ; /* Speed Status */
2019-04-10 16:24:50 +08:00
uint32_t duplex_status : 1 ; /* Duplex Status */
uint32_t loopback_status : 1 ; /* MII Loopback */
uint32_t auto_nego_complete : 1 ; /* Auto-Negotiation Complete */
uint32_t jabber_detect : 1 ; /* Jabber Detect */
uint32_t remote_fault : 1 ; /* Remote Fault */
uint32_t mii_interrupt : 1 ; /* MII Interrupt Pending */
uint32_t page_received : 1 ; /* Link Code Word Page Received */
uint32_t descrambler_lock : 1 ; /* Descrambler Lock */
uint32_t signal_detect : 1 ; /* Signal Detect */
uint32_t false_carrier_sense_latch : 1 ; /* False Carrier Sense Latch */
uint32_t polarity_status : 1 ; /* Polarity Status */
uint32_t receive_error_latch : 1 ; /* Receive Error Latch */
uint32_t mdix_mode : 1 ; /* MDI-X mode reported by auto-negotiation */
uint32_t reserved : 1 ; /* Reserved */
} ;
uint32_t val ;
} physts_reg_t ;
# define ETH_PHY_STS_REG_ADDR (0x10)
/**
* @ brief PHYCR ( PHY Control Register )
*
*/
typedef union {
struct {
uint32_t phy_addr : 5 ; /* PHY Address */
uint32_t led_cfg : 2 ; /* LED Configuration Modes */
uint32_t bypass_led_stretching : 1 ; /* Bypass LED Stretching */
uint32_t bist_start : 1 ; /* BIST Start */
uint32_t bist_status : 1 ; /* BIST Test Status */
uint32_t psr_15 : 1 ; /* BIST Sequence select */
uint32_t bist_force_error : 1 ; /* BIST Force Error */
uint32_t pause_trans_negotiate : 1 ; /* Pause Transmit Negotiated Status */
uint32_t pause_receive_negotiat : 1 ; /* Pause Receive Negotiated Status */
uint32_t force_mdix : 1 ; /* Force MDIX */
uint32_t en_auto_mdix : 1 ; /* Auto-MDIX Enable */
} ;
uint32_t val ;
} phycr_reg_t ;
# define ETH_PHY_CR_REG_ADDR (0x19)
typedef struct {
2022-05-13 12:03:56 +02:00
phy_802_3_t phy_802_3 ;
2019-04-10 16:24:50 +08:00
} phy_dp83848_t ;
2019-09-19 11:27:42 +08:00
static esp_err_t dp83848_update_link_duplex_speed ( phy_dp83848_t * dp83848 )
{
2021-04-01 20:00:54 +08:00
esp_err_t ret = ESP_OK ;
2022-05-13 12:03:56 +02:00
esp_eth_mediator_t * eth = dp83848 - > phy_802_3 . eth ;
uint32_t addr = dp83848 - > phy_802_3 . addr ;
2019-09-19 11:27:42 +08:00
eth_speed_t speed = ETH_SPEED_10M ;
eth_duplex_t duplex = ETH_DUPLEX_HALF ;
2020-07-20 20:42:52 +08:00
uint32_t peer_pause_ability = false ;
anlpar_reg_t anlpar ;
2019-09-19 11:27:42 +08:00
physts_reg_t physts ;
2023-12-15 10:57:53 +00:00
bmsr_reg_t bmsr ;
ESP_GOTO_ON_ERROR ( eth - > phy_reg_read ( eth , 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 ;
2019-09-19 11:27:42 +08:00
/* check if link status changed */
2022-05-13 12:03:56 +02:00
if ( dp83848 - > phy_802_3 . link_status ! = link ) {
2019-09-19 11:27:42 +08:00
/* when link up, read negotiation result */
if ( link = = ETH_LINK_UP ) {
2023-12-15 10:57:53 +00:00
ESP_GOTO_ON_ERROR ( eth - > phy_reg_read ( eth , addr , ETH_PHY_ANLPAR_REG_ADDR , & ( anlpar . val ) ) , err , TAG , " read ANLPAR failed " ) ;
ESP_GOTO_ON_ERROR ( eth - > phy_reg_read ( eth , addr , ETH_PHY_STS_REG_ADDR , & ( physts . val ) ) , err , TAG , " read PHYSTS failed " ) ;
2019-09-19 11:27:42 +08:00
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 ;
}
2021-04-01 20:00:54 +08:00
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 " ) ;
2020-07-20 20:42:52 +08:00
/* 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 ;
}
2021-04-01 20:00:54 +08:00
ESP_GOTO_ON_ERROR ( eth - > on_state_changed ( eth , ETH_STATE_PAUSE , ( void * ) peer_pause_ability ) , err , TAG , " change pause ability failed " ) ;
2019-09-19 11:27:42 +08:00
}
2021-04-01 20:00:54 +08:00
ESP_GOTO_ON_ERROR ( eth - > on_state_changed ( eth , ETH_STATE_LINK , ( void * ) link ) , err , TAG , " change link failed " ) ;
2022-05-13 12:03:56 +02:00
dp83848 - > phy_802_3 . link_status = link ;
2019-09-19 11:27:42 +08:00
}
return ESP_OK ;
err :
2021-04-01 20:00:54 +08:00
return ret ;
2019-09-19 11:27:42 +08:00
}
2019-04-10 16:24:50 +08:00
static esp_err_t dp83848_get_link ( esp_eth_phy_t * phy )
{
2021-04-01 20:00:54 +08:00
esp_err_t ret = ESP_OK ;
2022-05-13 12:03:56 +02:00
phy_dp83848_t * dp83848 = __containerof ( esp_eth_phy_into_phy_802_3 ( phy ) , phy_dp83848_t , phy_802_3 ) ;
2021-11-04 09:10:19 +01:00
/* Update information about link, speed, duplex */
2021-04-01 20:00:54 +08:00
ESP_GOTO_ON_ERROR ( dp83848_update_link_duplex_speed ( dp83848 ) , err , TAG , " update link duplex speed failed " ) ;
2019-04-10 16:24:50 +08:00
return ESP_OK ;
err :
2021-04-01 20:00:54 +08:00
return ret ;
2019-04-10 16:24:50 +08:00
}
2023-08-02 12:28:18 +02:00
static esp_err_t dp83848_autonego_ctrl ( esp_eth_phy_t * phy , eth_phy_autoneg_cmd_t cmd , bool * autonego_en_stat )
{
esp_err_t ret = ESP_OK ;
phy_802_3_t * phy_802_3 = esp_eth_phy_into_phy_802_3 ( phy ) ;
esp_eth_mediator_t * eth = phy_802_3 - > eth ;
if ( cmd = = ESP_ETH_PHY_AUTONEGO_EN ) {
bmcr_reg_t bmcr ;
ESP_GOTO_ON_ERROR ( eth - > phy_reg_read ( eth , phy_802_3 - > addr , ETH_PHY_BMCR_REG_ADDR , & ( bmcr . val ) ) , err , TAG , " read BMCR failed " ) ;
ESP_GOTO_ON_FALSE ( bmcr . en_loopback = = 0 , ESP_ERR_INVALID_STATE , err , TAG , " Autonegotiation can't be enabled while in loopback operation " ) ;
}
return esp_eth_phy_802_3_autonego_ctrl ( phy_802_3 , cmd , autonego_en_stat ) ;
err :
return ret ;
}
static esp_err_t dp83848_loopback ( esp_eth_phy_t * phy , bool enable )
{
esp_err_t ret = ESP_OK ;
phy_802_3_t * phy_802_3 = esp_eth_phy_into_phy_802_3 ( phy ) ;
bool auto_nego_en = true ;
ESP_GOTO_ON_ERROR ( dp83848_autonego_ctrl ( phy , ESP_ETH_PHY_AUTONEGO_G_STAT , & auto_nego_en ) , err , TAG , " get status of autonegotiation failed " ) ;
ESP_GOTO_ON_FALSE ( ! ( auto_nego_en & & enable ) , ESP_ERR_INVALID_STATE , err , TAG , " Unable to set loopback while autonegotiation is enabled. Disable it to use loopback " ) ;
return esp_eth_phy_802_3_loopback ( phy_802_3 , enable ) ;
err :
return ret ;
}
2022-05-13 12:03:56 +02:00
static esp_err_t dp83848_init ( esp_eth_phy_t * phy )
2021-11-04 09:10:19 +01:00
{
esp_err_t ret = ESP_OK ;
2022-05-13 12:03:56 +02:00
phy_802_3_t * phy_802_3 = esp_eth_phy_into_phy_802_3 ( phy ) ;
2021-11-04 09:10:19 +01:00
2022-05-13 12:03:56 +02:00
/* Basic PHY init */
ESP_GOTO_ON_ERROR ( esp_eth_phy_802_3_basic_phy_init ( phy_802_3 ) , err , TAG , " failed to init PHY " ) ;
2021-11-04 09:10:19 +01:00
2019-04-10 16:24:50 +08:00
/* Check PHY ID */
2022-05-13 12:03:56 +02:00
uint32_t oui ;
uint8_t model ;
ESP_GOTO_ON_ERROR ( esp_eth_phy_802_3_read_oui ( phy_802_3 , & oui ) , err , TAG , " read OUI failed " ) ;
ESP_GOTO_ON_ERROR ( esp_eth_phy_802_3_read_manufac_info ( phy_802_3 , & model , NULL ) , err , TAG , " read manufacturer's info failed " ) ;
ESP_GOTO_ON_FALSE ( oui = = 0x80017 & & model = = 0x09 , ESP_FAIL , err , TAG , " wrong chip ID " ) ;
2019-04-10 16:24:50 +08:00
return ESP_OK ;
err :
2021-04-01 20:00:54 +08:00
return ret ;
2019-04-10 16:24:50 +08:00
}
esp_eth_phy_t * esp_eth_phy_new_dp83848 ( const eth_phy_config_t * config )
{
2021-04-01 20:00:54 +08:00
esp_eth_phy_t * ret = NULL ;
2019-04-10 16:24:50 +08:00
phy_dp83848_t * dp83848 = calloc ( 1 , sizeof ( phy_dp83848_t ) ) ;
2021-04-01 20:00:54 +08:00
ESP_GOTO_ON_FALSE ( dp83848 , NULL , err , TAG , " calloc dp83848 failed " ) ;
2022-05-13 12:03:56 +02:00
ESP_GOTO_ON_FALSE ( esp_eth_phy_802_3_obj_config_init ( & dp83848 - > phy_802_3 , config ) = = ESP_OK ,
NULL , err , TAG , " configuration initialization of PHY 802.3 failed " ) ;
// redefine functions which need to be customized for sake of dp83848
dp83848 - > phy_802_3 . parent . init = dp83848_init ;
dp83848 - > phy_802_3 . parent . get_link = dp83848_get_link ;
2023-08-02 12:28:18 +02:00
dp83848 - > phy_802_3 . parent . autonego_ctrl = dp83848_autonego_ctrl ;
dp83848 - > phy_802_3 . parent . loopback = dp83848_loopback ;
2022-05-13 12:03:56 +02:00
return & dp83848 - > phy_802_3 . parent ;
2019-04-10 16:24:50 +08:00
err :
2022-05-13 12:03:56 +02:00
if ( dp83848 ! = NULL ) {
free ( dp83848 ) ;
}
2021-04-01 20:00:54 +08:00
return ret ;
2019-04-10 16:24:50 +08:00
}