1 #include <stdio.h>
2 #include "app_phy.h"
3 
4 #define PHY_BASE_ADDR                           0x7
5 
6 #define PHY_REG_CONTROL             0x0
7 #define PHY_REG_STATUS              0x1
8 #define PHY_REG_ANE                 0x6
9 #define PHY_REG_SPEC_STATUS         0x11
10 #define PHY_REG_EXTEND_STATUS               0x1B
11 
12 #define PHY_BIT_CONTROL_RESET           0x8000          /*!< Control reg : reset */
13 #define PHY_BIT_CONTROL_ANEN            0x1000          /*!< Control reg : auto-negotiation enable */
14 #define PHY_BIT_CONTROL_RSAN            0x0200          /*!< Control reg : auto-negotiation restart */
15 
16 #define PHY_BIT_STATUS_ANC              0x0020          /*!< Status reg : auto-negotiation complete */
17 #define PHY_BIT_STATUS_LINK             0x0004          /*!< Status reg : link is up */
18 
19 #define PHY_BIT_ANE_LPAN                0x0001          /*!< ANE reg : link partner can auto-neg */
20 
21 #define PHY_BIT_SPEED                   0xC000      /*!< specific status reg : speed */
22 #define PHY_BIT_DUPLEX                  0x2000      /*!< specific status reg : duplex */
23 
24 #define PHY_BIT_AUTO_MEDIA_DISABLE      0x8000      /*!< extended status reg : auto media select disable */
25 #define PHY_BIT_AUTO_MEDIA_REG_DISABLE  0x0200      /*!< extended status reg : auto media register select disable */
26 
phy_Reset()27 void phy_Reset() {
28     ETH_PhyWrite(PHY_BASE_ADDR, PHY_REG_CONTROL, PHY_BIT_CONTROL_RESET);
29 
30     while (1) {
31         uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_CONTROL);
32       if ((ret & PHY_BIT_CONTROL_RESET) == 0) {
33             break;
34         }
35     }
36 }
37 
phy_AutoMediaSelect()38 void phy_AutoMediaSelect() {
39     uint32_t data;
40 
41     // auto media and auto media register selection
42     data = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_EXTEND_STATUS);
43     data &= ~PHY_BIT_AUTO_MEDIA_DISABLE;
44     data &= ~PHY_BIT_AUTO_MEDIA_REG_DISABLE;
45     ETH_PhyWrite(PHY_BASE_ADDR, PHY_REG_EXTEND_STATUS, data);
46 }
47 
phy_AutoNeg()48 void phy_AutoNeg()
49 {
50     uint32_t data;
51 
52     data = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_CONTROL);
53     data |= (PHY_BIT_CONTROL_ANEN | PHY_BIT_CONTROL_RSAN);
54     ETH_PhyWrite(PHY_BASE_ADDR, PHY_REG_CONTROL, data);
55 
56     while (1)
57     {
58         uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_STATUS);
59         if ((ret & PHY_BIT_STATUS_ANC) == PHY_BIT_STATUS_ANC)
60         {
61             break;
62         }
63         rt_thread_delay(1);
64     }
65 }
66 
phy_IsLink()67 BOOL phy_IsLink() {
68     uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_STATUS);
69     return (ret & PHY_BIT_STATUS_LINK) ? TRUE : FALSE;
70 }
71 
phy_PartnerCanAutoNeg()72 BOOL phy_PartnerCanAutoNeg() {
73     uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_ANE);
74     return (ret & PHY_BIT_ANE_LPAN) ? TRUE : FALSE;
75 }
76 
phy_GetSpeed()77 uint32_t phy_GetSpeed() {
78     uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_SPEC_STATUS);
79     return ((ret & PHY_BIT_SPEED) >> 14);
80 }
81 
phy_GetDuplex()82 uint32_t phy_GetDuplex() {
83     uint32_t ret = ETH_PhyRead(PHY_BASE_ADDR, PHY_REG_SPEC_STATUS);
84     return ((ret & PHY_BIT_DUPLEX) >> 13);
85 }
86 
phy_Init()87 BOOL phy_Init() {
88     phy_AutoMediaSelect();
89     phy_AutoNeg();
90 
91     if (!phy_PartnerCanAutoNeg()) {
92         printf("Warning:: PHY's partner can't do auto-negotiation\n");
93     }
94 
95     if (!phy_IsLink()) {
96         printf("link is down\n");
97         return FALSE;
98     }
99 
100     {
101         uint32_t speed = phy_GetSpeed();
102         if (speed == PHY_SPEED_10) {
103             speed = 10;
104         } else if (speed == PHY_SPEED_100) {
105             speed = 100;
106         } else if (speed == PHY_SPEED_1000) {
107             speed = 1000;
108         }
109 
110         printf("PHY runs in %uM speed %s duplex\n",
111             speed, (phy_GetDuplex() == PHY_DUPLEX_HALF) ? "half" : "full");
112     }
113 
114     // After auto-negcioation, Mawell PHY need some
115     // time to initial itself.
116     // So we have to delay some time since different
117     // connection way, such as direct wire, hub, switch.
118     // If not to delay, the first several sent frame
119     // may be lost.
120     // Please according to actual environment to tune
121     // this delay.
122     udelay(200000);
123 
124     return TRUE;
125 }
126