126 lines
3.5 KiB
C
126 lines
3.5 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 %dM 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;
|
|
}
|