Merge with git://www.denx.de/git/u-boot.git
[platform/kernel/u-boot.git] / cpu / arm926ejs / davinci / dp83848.c
1 /*
2  * National Semiconductor DP83848 PHY Driver for TI DaVinci
3  * (TMS320DM644x) based boards.
4  *
5  * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
6  *
7  * --------------------------------------------------------
8  *
9  * See file CREDITS for list of people who contributed to this
10  * project.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25  * MA 02111-1307 USA
26  */
27
28 #include <common.h>
29 #include <net.h>
30 #include <dp83848.h>
31 #include <asm/arch/emac_defs.h>
32
33 #ifdef CONFIG_DRIVER_TI_EMAC
34
35 #ifdef CONFIG_CMD_NET
36
37 int dp83848_is_phy_connected(int phy_addr)
38 {
39         u_int16_t       id1, id2;
40
41         if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID1_REG, &id1))
42                 return(0);
43         if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID2_REG, &id2))
44                 return(0);
45
46         if ((id1 == DP83848_PHYID1_OUI) && (id2 == DP83848_PHYID2_OUI))
47                 return(1);
48
49         return(0);
50 }
51
52 int dp83848_get_link_speed(int phy_addr)
53 {
54         u_int16_t               tmp;
55         volatile emac_regs*     emac = (emac_regs *)EMAC_BASE_ADDR;
56
57         if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp))
58                 return(0);
59
60         if (!(tmp & DP83848_LINK_STATUS))       /* link up? */
61                 return(0);
62
63         if (!dm644x_eth_phy_read(phy_addr, DP83848_PHY_STAT_REG, &tmp))
64                 return(0);
65
66         /* Speed doesn't matter, there is no setting for it in EMAC... */
67         if (tmp & DP83848_SPEED) {
68                 if (tmp & DP83848_DUPLEX) {
69                         /* set DM644x EMAC for Full Duplex  */
70                         emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
71                 } else {
72                         /*set DM644x EMAC for Half Duplex  */
73                         emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
74                 }
75
76                 return(1);
77         } else {
78                 if (tmp & DP83848_DUPLEX) {
79                         /* set DM644x EMAC for Full Duplex  */
80                         emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
81                 } else {
82                         /*set DM644x EMAC for Half Duplex  */
83                         emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
84                 }
85
86                 return(1);
87         }
88
89         return(0);
90 }
91
92
93 int dp83848_init_phy(int phy_addr)
94 {
95         int     ret = 1;
96
97         if (!dp83848_get_link_speed(phy_addr)) {
98                 /* Try another time */
99                 udelay(100000);
100                 ret = dp83848_get_link_speed(phy_addr);
101         }
102
103         /* Disable PHY Interrupts */
104         dm644x_eth_phy_write(phy_addr, DP83848_PHY_INTR_CTRL_REG, 0);
105
106         return(ret);
107 }
108
109
110 int dp83848_auto_negotiate(int phy_addr)
111 {
112         u_int16_t       tmp;
113
114
115         if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp))
116                 return(0);
117
118         /* Restart Auto_negotiation  */
119         tmp &= ~DP83848_AUTONEG;        /* remove autonegotiation enable */
120         tmp |= DP83848_ISOLATE;         /* Electrically isolate PHY */
121         dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
122
123         /* Set the Auto_negotiation Advertisement Register
124          * MII advertising for Next page, 100BaseTxFD and HD,
125          * 10BaseTFD and HD, IEEE 802.3
126          */
127         tmp = DP83848_NP | DP83848_TX_FDX | DP83848_TX_HDX |
128                 DP83848_10_FDX | DP83848_10_HDX | DP83848_AN_IEEE_802_3;
129         dm644x_eth_phy_write(phy_addr, DP83848_ANA_REG, tmp);
130
131
132         /* Read Control Register */
133         if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp))
134                 return(0);
135
136         tmp |= DP83848_SPEED_SELECT | DP83848_AUTONEG | DP83848_DUPLEX_MODE;
137         dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
138
139         /* Restart Auto_negotiation  */
140         tmp |= DP83848_RESTART_AUTONEG;
141         dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
142
143         /*check AutoNegotiate complete */
144         udelay(10000);
145         if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp))
146                 return(0);
147
148         if (!(tmp & DP83848_AUTONEG_COMP))
149                 return(0);
150
151         return (dp83848_get_link_speed(phy_addr));
152 }
153
154 #endif  /* CONFIG_CMD_NET */
155
156 #endif  /* CONFIG_DRIVER_ETHER */