ethermac: reduce interrupt overhead
[nios2ecos.git] / eth_ocm / HAL / src / eth_ocm_phy.c
blob6f413aba8e215864c87d2ef25a871ba4219d1b8e
1 #include "eth_ocm_phy.h"
2 #include <stdio.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;
10 phyad |= reg;
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);
18 eth_ocm_wait(base);
21 int eth_ocm_read_phy_reg(int base, int phyad, int reg){
22 int result;
24 eth_ocm_set_phy_addr(base, phyad, reg);
25 IOWR_ETH_OCM_MIICOMMAND(base, ETH_OCM_MIICOMMAND_RSTAT_MSK);
26 eth_ocm_wait(base);
27 result = IORD_ETH_OCM_MIIRX_DATA(base);
28 return result;
31 static int eth_ocm_wait(int base){
32 int temp;
33 int i;
34 i = 0;
35 temp = 1;
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");
41 #endif
42 temp &= ETH_OCM_MIISTATUS_BUSY_MSK;
43 i++;
46 #if(ETH_OCM_DBG_LVL > 0)
47 if(i == 1000)
48 printf("[eth_ocm_set_phy_reg] Failed waiting for MII module to be ready!\n");
49 #endif
51 return temp;
55 #ifdef ETH_OCM_USE_INTERNAL_PHY_INIT
56 /**
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*/
66 int phyid;
67 int phyid2;
68 int dat;
69 int phyadd;
70 int base;
71 int found;
72 // determine PHY speed: This is PHY dependent and you need to change
73 // this according to your PHY's specifications
74 duplex = 1;
75 dat = 0;
76 phyadd = 0;
77 found = 0;
78 base = dev->base;
80 // ------------------------------
81 // PHY detection
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);
91 #endif
92 phyadd = dat;
93 dat = 0xff;
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))) {
102 found = 1;
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);
107 #endif
108 }else{
109 #if(ETH_OCM_DBG_LVL > 0)
110 printf("[eth_ocm_phy_init] LXT972A not found!\n");
111 #endif
113 #endif
115 #ifdef ETH_OCM_PHYID_MVL
116 // ***************
117 // Marvell 88E1111
118 // ***************
119 if (phyid == ETH_OCM_PHYID_MVL){
120 found = 1;
121 #if(ETH_OCM_DBG_LVL > 0)
122 printf("[eth_ocm_phy_init] Found Marvell 88E1111 PHY.\n");
123 #endif
124 // Disable 1000BASE-T Autonegotiation
125 dat = eth_ocm_read_phy_reg(base, phyadd, 0x09);
126 dat &= 0xFCFF;
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);
133 else{
134 #if(ETH_OCM_DBG_LVL > 0)
135 printf("[eth_ocm_phy_init] Marvell 88E1111 PHY not found!\n");
136 #endif
138 #endif //ifdef ETH_OCM_PHYID_MVL
140 #ifdef ETH_OCM_PHYID_DP83848C
141 // *****************
142 // National DP83848C
143 // *****************
144 if((phyid == (ETH_OCM_PHYID_DP83848C >> 16)) && (phyid2 == (ETH_OCM_PHYID_DP83848C & 0xFFFF))) {
145 found = 1;
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);
150 #endif
151 }else{
152 #if(ETH_OCM_DBG_LVL > 0)
153 printf("[eth_ocm_phy_init] DP83848C PHY not found!\n");
154 #endif
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))) {
160 found = 1;
161 #if(ETH_OCM_DBG_LVL > 0)
162 printf("[eth_ocm_phy_init] Found Vitesse VCS8641 PHY\n");
163 #endif
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);
198 dat &= 0xFCFF;
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
207 if(!found){
208 #if(ETH_OCM_DBG_LVL > 0)
209 printf("[eth_ocm_phy_init] NO PHY FOUND!\n");
210 #endif
211 return 0;
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...");
228 #endif
229 dat=0;
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");
234 #endif
235 break;
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));
240 #endif
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;
254 // End Intel LXT972A
255 #endif //ifdef ETH_OCM_PHYID_LXT972A
257 #ifdef ETH_OCM_PHYID_MVL
258 // ***************
259 // Marvell 88E1111
260 // ***************
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)
269 if(dat & (1 << 14))
270 printf("[eth_ocm_phy_init] WARNING: PHY operating in Gigabit mode\n");
271 #endif
273 // End Marvel 88E1111
274 #endif // ifdef ETH_OCM_PHY_ID_MVL
276 #ifdef ETH_OCM_PHYID_DP83848C
277 // *****************
278 // National DP83848C
279 // *****************
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;
284 #endif
286 #ifdef ETH_OCM_PHYID_VCS8641
287 // ***************
288 // Vitesse VCS8641
289 // ***************
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;
294 #endif
296 #if(ETH_OCM_DBG_LVL > 0)
297 printf("[eth_ocm_phy_init] Full Duplex is %d\n", duplex);
298 #endif
300 return duplex;
302 #endif // ifdef ETH_OCM_USE_INTERNAL_PHY_INIT