rt-thread/bsp/CME_M7/drivers/app_phy.c

126 lines
3.8 KiB
C

#include <stdio.h>
#include "app_phy.h"
#define PHY_BASE_ADDR 0x7
#define PHY_REG_CONTROL 0x0
#define PHY_REG_STATUS 0x1
#define PHY_REG_ANE 0x6
#define PHY_REG_SPEC_STATUS 0x11
#define PHY_REG_EXTEND_STATUS 0x1B
#define PHY_BIT_CONTROL_RESET 0x8000 /*!< Control reg : reset */
#define PHY_BIT_CONTROL_ANEN 0x1000 /*!< Control reg : auto-negotiation enable */
#define PHY_BIT_CONTROL_RSAN 0x0200 /*!< Control reg : auto-negotiation restart */
#define PHY_BIT_STATUS_ANC 0x0020 /*!< Status reg : auto-negotiation complete */
#define PHY_BIT_STATUS_LINK 0x0004 /*!< Status reg : link is up */
#define PHY_BIT_ANE_LPAN 0x0001 /*!< ANE reg : link partner can auto-neg */
#define PHY_BIT_SPEED 0xC000 /*!< specific status reg : speed */
#define PHY_BIT_DUPLEX 0x2000 /*!< specific status reg : duplex */
#define PHY_BIT_AUTO_MEDIA_DISABLE 0x8000 /*!< extended status reg : auto media select disable */
#define PHY_BIT_AUTO_MEDIA_REG_DISABLE 0x0200 /*!< extended status reg : auto media register select disable */
void phy_Reset() {
ETH_PhyWrite(PHY_BASE_ADDR, PHY_REG_CONTROL, PHY_BIT_CONTROL_RESET);
while (1) {
uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_CONTROL);
if ((ret & PHY_BIT_CONTROL_RESET) == 0) {
break;
}
}
}
void phy_AutoMediaSelect() {
uint32_t data;
// auto media and auto media register selection
data = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_EXTEND_STATUS);
data &= ~PHY_BIT_AUTO_MEDIA_DISABLE;
data &= ~PHY_BIT_AUTO_MEDIA_REG_DISABLE;
ETH_PhyWrite(PHY_BASE_ADDR, PHY_REG_EXTEND_STATUS, data);
}
void phy_AutoNeg()
{
uint32_t data;
data = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_CONTROL);
data |= (PHY_BIT_CONTROL_ANEN | PHY_BIT_CONTROL_RSAN);
ETH_PhyWrite(PHY_BASE_ADDR, PHY_REG_CONTROL, data);
while (1)
{
uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_STATUS);
if ((ret & PHY_BIT_STATUS_ANC) == PHY_BIT_STATUS_ANC)
{
break;
}
rt_thread_delay(1);
}
}
BOOL phy_IsLink() {
uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_STATUS);
return (ret & PHY_BIT_STATUS_LINK) ? TRUE : FALSE;
}
BOOL phy_PartnerCanAutoNeg() {
uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_ANE);
return (ret & PHY_BIT_ANE_LPAN) ? TRUE : FALSE;
}
uint32_t phy_GetSpeed() {
uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_SPEC_STATUS);
return ((ret & PHY_BIT_SPEED) >> 14);
}
uint32_t phy_GetDuplex() {
uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_SPEC_STATUS);
return ((ret & PHY_BIT_DUPLEX) >> 13);
}
BOOL phy_Init() {
phy_AutoMediaSelect();
phy_AutoNeg();
if (!phy_PartnerCanAutoNeg()) {
printf("Warning:: PHY's partner can't do auto-negotiation\n");
}
if (!phy_IsLink()) {
printf("link is down\n");
return FALSE;
}
{
uint32_t speed = phy_GetSpeed();
if (speed == PHY_SPEED_10) {
speed = 10;
} else if (speed == PHY_SPEED_100) {
speed = 100;
} else if (speed == PHY_SPEED_1000) {
speed = 1000;
}
printf("PHY runs in %uM speed %s duplex\n",
speed, (phy_GetDuplex() == PHY_DUPLEX_HALF) ? "half" : "full");
}
// After auto-negcioation, Mawell PHY need some
// time to initial itself.
// So we have to delay some time since different
// connection way, such as direct wire, hub, switch.
// If not to delay, the first several sent frame
// may be lost.
// Please according to actual environment to tune
// this delay.
udelay(200000);
return TRUE;
}