summaryrefslogtreecommitdiff
path: root/bsp/CME_M7/drivers/app_phy.c
blob: 5fb210d2ea1888cab83aa25a3941d53782e2d6c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#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;
}