1 #include "eth_ocm_phy.h"
4 static int eth_ocm_wait(int base
);
6 void eth_ocm_set_phy_addr(int base
, int phyad
, int reg
){
7 phyad
&= ETH_OCM_MIIADDRESS_FIAD_MSK
;
8 reg
= reg
<< ETH_OCM_MIIADDRESS_RGAD_OFST
;
9 reg
&= ETH_OCM_MIIADDRESS_RGAD_MSK
;
11 IOWR_ETH_OCM_MIIADDRESS(base
, phyad
);
14 void eth_ocm_write_phy_reg(int base
, int phyad
, int reg
, int data
){
15 eth_ocm_set_phy_addr(base
, phyad
, reg
);
16 IOWR_ETH_OCM_MIITX_DATA(base
, data
);
17 IOWR_ETH_OCM_MIICOMMAND(base
, ETH_OCM_MIICOMMAND_WCTRLDATA_MSK
);
21 int eth_ocm_read_phy_reg(int base
, int phyad
, int reg
){
24 eth_ocm_set_phy_addr(base
, phyad
, reg
);
25 IOWR_ETH_OCM_MIICOMMAND(base
, ETH_OCM_MIICOMMAND_RSTAT_MSK
);
27 result
= IORD_ETH_OCM_MIIRX_DATA(base
);
31 static int eth_ocm_wait(int base
){
36 while(temp
&& i
<1000){
37 temp
= IORD_ETH_OCM_MIISTATUS(base
);
38 #if(ETH_OCM_DBG_LVL > 0)
39 if(temp
& ETH_OCM_MIISTATUS_NVALID_MSK
)
40 printf("Invalid bit set in MII Status register\n");
42 temp
&= ETH_OCM_MIISTATUS_BUSY_MSK
;
46 #if(ETH_OCM_DBG_LVL > 0)
48 printf("[eth_ocm_set_phy_reg] Failed waiting for MII module to be ready!\n");
55 #ifdef ETH_OCM_USE_INTERNAL_PHY_INIT
57 * Performs PHY initialization and determines link duplex.
58 * This is fully vendor specific depending on the PHY you are using.
60 * @param dev Pointer to eth_ocm_dev struct which contains needed base address
61 * @return 1 if Link is established in Full duplex.
62 * 0 if Link is established in Half duplex.
64 int eth_ocm_phy_init(eth_ocm_dev
*dev
){
65 int duplex
; /* 1 = full ; 0 = half*/
72 // determine PHY speed: This is PHY dependent and you need to change
73 // this according to your PHY's specifications
80 // ------------------------------
82 // ------------------------------
83 phyid
= eth_ocm_read_phy_reg(base
, dat
, ETH_OCM_PHY_ADDR_PHY_ID1
);
84 for (dat
= 0x00; dat
< 0xff; dat
++){
85 phyid
= eth_ocm_read_phy_reg(base
, dat
, ETH_OCM_PHY_ADDR_PHY_ID1
);
86 phyid2
= eth_ocm_read_phy_reg(base
, dat
, ETH_OCM_PHY_ADDR_PHY_ID2
);
88 if (phyid
!= phyid2
&& (phyid2
!= 0xffff)){
89 #if(ETH_OCM_DBG_LVL > 0)
90 printf("[eth_ocm_phy_init] PHY ID 0x%x %x %x\n", dat
, phyid
, phyid2
);
97 #ifdef ETH_OCM_PHYID_LXT972A
98 // ********************
99 // Intel LXT972A 10/100
100 // ********************
101 if((phyid
== (ETH_OCM_PHYID_LXT972A
>> 16)) && (phyid2
== (ETH_OCM_PHYID_LXT972A
& 0xFFFF))) {
103 dat
= eth_ocm_read_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_ADV
);
104 #if(ETH_OCM_DBG_LVL > 0)
105 printf("[eth_ocm_phy_init] Found LXT972A PHY\n");
106 printf("[eth_ocm_phy_init] LXT972A Auto-neg capabilities: 0x%x\n",dat
);
109 #if(ETH_OCM_DBG_LVL > 0)
110 printf("[eth_ocm_phy_init] LXT972A not found!\n");
115 #ifdef ETH_OCM_PHYID_MVL
119 if (phyid
== ETH_OCM_PHYID_MVL
){
121 #if(ETH_OCM_DBG_LVL > 0)
122 printf("[eth_ocm_phy_init] Found Marvell 88E1111 PHY.\n");
124 // Disable 1000BASE-T Autonegotiation
125 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 0x09);
127 eth_ocm_write_phy_reg(base
, phyadd
, 0x09, dat
);
128 // Restart autonegotiation
129 dat
= eth_ocm_read_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_CONTROL
);
130 dat
|= PCS_CTL_an_restart
;
131 eth_ocm_write_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_CONTROL
, dat
);
134 #if(ETH_OCM_DBG_LVL > 0)
135 printf("[eth_ocm_phy_init] Marvell 88E1111 PHY not found!\n");
138 #endif //ifdef ETH_OCM_PHYID_MVL
140 #ifdef ETH_OCM_PHYID_DP83848C
144 if((phyid
== (ETH_OCM_PHYID_DP83848C
>> 16)) && (phyid2
== (ETH_OCM_PHYID_DP83848C
& 0xFFFF))) {
146 dat
= eth_ocm_read_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_ADV
);
147 #if(ETH_OCM_DBG_LVL > 0)
148 printf("[eth_ocm_phy_init] Found DP83848C PHY\n");
149 printf("[eth_ocm_phy_init] DP83848C Auto-neg capabilities: 0x%x\n",dat
);
152 #if(ETH_OCM_DBG_LVL > 0)
153 printf("[eth_ocm_phy_init] DP83848C PHY not found!\n");
156 #endif // ifdef ETH_OCM_PHYID_DP83848C
158 #ifdef ETH_OCM_PHYID_VCS8641
159 if((phyid
== (ETH_OCM_PHYID_VCS8641
>> 16)) && (phyid2
== (ETH_OCM_PHYID_VCS8641
& 0xFFFF))) {
161 #if(ETH_OCM_DBG_LVL > 0)
162 printf("[eth_ocm_phy_init] Found Vitesse VCS8641 PHY\n");
164 // Run required script (Vitesse screw-up)
165 eth_ocm_write_phy_reg(base
, phyadd
, 31, 0x52B5);
166 eth_ocm_write_phy_reg(base
, phyadd
, 16, 0xAF8A);
168 eth_ocm_write_phy_reg(base
, phyadd
, 18, 0x0000);
170 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 17);
171 dat
= (dat
& ~0x000C) | 0x0008;
172 eth_ocm_write_phy_reg(base
, phyadd
, 17, dat
);
174 eth_ocm_write_phy_reg(base
, phyadd
, 16, 0x8F8A);
175 eth_ocm_write_phy_reg(base
, phyadd
, 16, 0xAF86);
177 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 18);
178 dat
= (dat
& ~0x000C) | 0x0008;
179 eth_ocm_write_phy_reg(base
, phyadd
, 18, dat
);
181 eth_ocm_write_phy_reg(base
, phyadd
, 17, 0x0000);
183 eth_ocm_write_phy_reg(base
, phyadd
, 16, 0x8F86);
184 eth_ocm_write_phy_reg(base
, phyadd
, 16, 0xAF82);
186 eth_ocm_write_phy_reg(base
, phyadd
, 18, 0x0000);
188 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 17);
189 dat
= (dat
& ~0x0180) | 0x0100;
190 eth_ocm_write_phy_reg(base
, phyadd
, 17, dat
);
192 eth_ocm_write_phy_reg(base
, phyadd
, 16, 0x8F82);
193 eth_ocm_write_phy_reg(base
, phyadd
, 31, 0x0000);
194 //End of Vitesse screw-up script
196 // Disable 1000BASE-T Autonegotiation
197 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 0x09);
199 eth_ocm_write_phy_reg(base
, phyadd
, 0x09, dat
);
200 // Restart autonegotiation
201 dat
= eth_ocm_read_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_CONTROL
);
202 dat
|= PCS_CTL_an_restart
;
203 eth_ocm_write_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_CONTROL
, dat
);
205 #endif // ifdef ETH_OCM_PHYID_VCS8641
208 #if(ETH_OCM_DBG_LVL > 0)
209 printf("[eth_ocm_phy_init] NO PHY FOUND!\n");
213 // Issue a PHY reset here and wait for the link
214 // autonegotiation complete again... this takes several SECONDS(!)
215 // so be very careful not to do it frequently
217 // perform this when PHY is configured in loopback or has no link yet.
218 if( ((eth_ocm_read_phy_reg(base, phyadd, ETH_OCM_PHY_ADDR_CONTROL)& PCS_CTL_rx_slpbk) != 0) ||
219 ((eth_ocm_read_phy_reg(base, phyadd, ETH_OCM_PHY_ADDR_STATUS) & PCS_ST_an_done) == 0) ) {
220 eth_ocm_write_phy_reg(base, phyadd, ETH_OCM_PHY_ADDR_CONTROL,PCS_CTL_an_enable | PCS_CTL_sw_reset); // send PHY reset command
221 dprintf("[eth_ocm_phy_init] PHY Reset\n" );
225 if(!(eth_ocm_read_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_STATUS
)& PCS_ST_an_done
)) {
226 #if(ETH_OCM_DBG_LVL > 0)
227 printf("[eth_ocm_phy_init] Waiting on PHY link...");
230 while( (eth_ocm_read_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_STATUS
) & PCS_ST_an_done
) == 0 ){
231 if( dat
++ > ETH_OCM_PHY_TIMEOUT_THRESHOLD
) {
232 #if(ETH_OCM_DBG_LVL > 0)
233 printf(" Autoneg FAILED, continuing anyway ...\n");
238 #if(ETH_OCM_DBG_LVL > 0)
239 printf("OK. x=%d, PHY STATUS=%04x\n",dat
, eth_ocm_read_phy_reg(base
, phyadd
, ETH_OCM_PHY_ADDR_STATUS
));
243 #ifdef ETH_OCM_PHYID_LXT972A
244 // ********************
245 // Intel LXT972A 10/100
246 // ********************
248 if((phyid
== (ETH_OCM_PHYID_LXT972A
>> 16)) && (phyid2
== (ETH_OCM_PHYID_LXT972A
& 0xFFFF))) {
249 // retrieve link speed from PHY
250 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 0x11);
251 duplex
= (dat
>> 9) & 0x01;
255 #endif //ifdef ETH_OCM_PHYID_LXT972A
257 #ifdef ETH_OCM_PHYID_MVL
261 if (phyid
== ETH_OCM_PHYID_MVL
){
262 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 0x11);
264 //duplex bit is not valid until resolved bit is set
265 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 0x11);
267 duplex
= (dat
>> 13) & 0x01;
268 #if(ETH_OCM_DBG_LVL > 0)
270 printf("[eth_ocm_phy_init] WARNING: PHY operating in Gigabit mode\n");
273 // End Marvel 88E1111
274 #endif // ifdef ETH_OCM_PHY_ID_MVL
276 #ifdef ETH_OCM_PHYID_DP83848C
280 if((phyid
== (ETH_OCM_PHYID_DP83848C
>> 16)) && (phyid2
== (ETH_OCM_PHYID_DP83848C
& 0xFFFF))) {
281 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 0x10);
282 duplex
= (dat
>> 2) & 0x01;
286 #ifdef ETH_OCM_PHYID_VCS8641
290 if((phyid
== (ETH_OCM_PHYID_VCS8641
>> 16)) && (phyid2
== (ETH_OCM_PHYID_DP83848C
& 0xFFFF))) {
291 dat
= eth_ocm_read_phy_reg(base
, phyadd
, 0x1C);
292 duplex
= (dat
>> 5) & 0x01;
296 #if(ETH_OCM_DBG_LVL > 0)
297 printf("[eth_ocm_phy_init] Full Duplex is %d\n", duplex
);
302 #endif // ifdef ETH_OCM_USE_INTERNAL_PHY_INIT