]> git.sur5r.net Git - freertos/blob - Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/mss_ethernet_mac/phy.c
dd1ca43b59ad46d75058f06a6b6f37fcbf5a486c
[freertos] / Demo / CORTEX_A2F200_SoftConsole / MicroSemi_Code / drivers / mss_ethernet_mac / phy.c
1 /***************************************************************************//**\r
2  * PHY access methods for DP83848C.\r
3  * The implementation in this file is specific to the DP83848C,\r
4  * If a different PHY support is required the PHY specific registers must\r
5  * be updated.\r
6  * (c) Copyright 2007 Actel Corporation\r
7  *\r
8  * SVN $Revision: 2324 $\r
9  * SVN $Date: 2010-02-26 10:47:36 +0000 (Fri, 26 Feb 2010) $\r
10  *\r
11  ******************************************************************************/\r
12 \r
13 #ifdef __cplusplus\r
14 extern "C" {\r
15 #endif \r
16 \r
17 \r
18 #include "mss_ethernet_mac.h"\r
19 #include "mss_ethernet_mac_regs.h"\r
20 \r
21 #include "phy.h"\r
22 \r
23 extern MAC_instance_t g_mss_mac;\r
24 \r
25 /***************************** MDIO FUNCTIONS *********************************/\r
26 \r
27 /* Defines ********************************************************************/\r
28 #define MDIO_START                              0x00004000UL\r
29 #define MDIO_READ                               0x00002000UL\r
30 #define MDIO_WRITE                              0x00001002UL\r
31 #define MDIO_ADDR_OFFSET                7UL\r
32 #define MDIO_ADDR_MASK                  0x00000f80UL\r
33 #define MDIO_REG_ADDR_OFFSET    2UL\r
34 #define MDIO_REG_ADDR_MASK              0x0000007cUL\r
35 #define PREAMBLECOUNT           32UL\r
36 #define ONEMICROSECOND          20UL\r
37 \r
38 typedef enum {\r
39         MDIO_CMD_READ,\r
40         MDIO_CMD_WRITE\r
41 }mdio_cmd_t;\r
42 \r
43 \r
44 \r
45 /***************************************************************************//**\r
46  * Set clock high or low.\r
47  */\r
48 static void\r
49 MDIO_management_clock\r
50 (\r
51     int32_t clock\r
52 )\r
53 {\r
54         int32_t volatile a;\r
55     \r
56     MAC_BITBAND->CSR9_MDC = (uint32_t)clock;\r
57     \r
58         /* delay for 1us */\r
59         for( a = 0; a < ONEMICROSECOND; a++ ){}\r
60 }\r
61 \r
62 \r
63 /***************************************************************************//**\r
64  * Send read or write command to PHY.\r
65  */\r
66 static void\r
67 MDIO_send_cmd\r
68 (\r
69     uint8_t regad,\r
70     mdio_cmd_t mdio_cmd\r
71 )\r
72 {\r
73     int32_t i;\r
74     uint16_t mask, data;\r
75 \r
76     /* enable MII output */\r
77     MAC_BITBAND->CSR9_MDEN = 1;\r
78 \r
79     /* send 32 1's preamble */\r
80     MAC_BITBAND->CSR9_MDO = 1;\r
81     for (i = 0; i < PREAMBLECOUNT; i++) {\r
82         MDIO_management_clock( 0 );\r
83         MDIO_management_clock( 1 );\r
84     }\r
85 \r
86     /* calculate data bits */\r
87     data = MDIO_START |\r
88         (( mdio_cmd == MDIO_CMD_READ ) ? MDIO_READ : MDIO_WRITE ) |\r
89         ((g_mss_mac.phy_address << MDIO_ADDR_OFFSET) & MDIO_ADDR_MASK) |\r
90         ((regad << MDIO_REG_ADDR_OFFSET) & MDIO_REG_ADDR_MASK);\r
91 \r
92     /* sent out */\r
93     for( mask = 0x00008000L; mask>0; mask >>= 1 )\r
94     {\r
95         if ((mask == 0x2) && (mdio_cmd == MDIO_CMD_READ)) {\r
96                 /* enable MII input */\r
97             MAC_BITBAND->CSR9_MDEN = 0;\r
98         }\r
99 \r
100         MDIO_management_clock( 0 );\r
101 \r
102         /* prepare MDO */\r
103         MAC_BITBAND->CSR9_MDO = (uint32_t)((mask & data) != 0 ? 1UL : 0UL);\r
104         \r
105         MDIO_management_clock( 1 );\r
106     }\r
107 }\r
108 \r
109 \r
110 /***************************************************************************//**\r
111  * Reads a PHY register.\r
112  */\r
113 static uint16_t\r
114 MDIO_read\r
115 (\r
116     uint8_t regad\r
117 )\r
118 {\r
119     uint16_t mask;\r
120     uint16_t data;\r
121 \r
122     MDIO_send_cmd( regad, MDIO_CMD_READ);\r
123 \r
124     /* read data */\r
125     data = 0;\r
126     for( mask = 0x00008000L; mask>0; mask >>= 1 )\r
127     {\r
128         MDIO_management_clock( 0 );\r
129 \r
130         /* read MDI */\r
131         if(MAC_BITBAND-> CSR9_MDI != 0){\r
132             data |= mask;\r
133         }\r
134 \r
135         MDIO_management_clock( 1 );\r
136     }\r
137 \r
138     MDIO_management_clock( 0 );\r
139 \r
140     return data;\r
141 }\r
142 \r
143 \r
144 /***************************************************************************//**\r
145  * Writes to a PHY register.\r
146  */\r
147 static void\r
148 MDIO_write\r
149 (\r
150     uint8_t regad,\r
151     uint16_t data\r
152 )\r
153 {\r
154     uint16_t mask;\r
155 \r
156     MDIO_send_cmd(regad, MDIO_CMD_WRITE);\r
157 \r
158     /* write data */\r
159     for( mask = 0x00008000L; mask>0; mask >>= 1 )\r
160     {\r
161         MDIO_management_clock( 0 );\r
162 \r
163         /* prepare MDO */\r
164         MAC_BITBAND->CSR9_MDO = (uint32_t)((mask & data) != 0 ? 1UL : 0UL);\r
165 \r
166         MDIO_management_clock( 1 );\r
167     }\r
168 \r
169     MDIO_management_clock( 0 );\r
170 }\r
171 \r
172 \r
173 /****************************** PHY FUNCTIONS *********************************/\r
174 \r
175 /* Defines ********************************************************************/\r
176 \r
177 /* Base registers */\r
178 #define PHYREG_MIIMCR           0x00    /**< MII Management Control Register */\r
179 #define MIIMCR_RESET                                    (1<<15)\r
180 #define MIIMCR_LOOPBACK                 (1<<14)\r
181 #define MIIMCR_SPEED_SELECT                             (1<<13)\r
182 #define MIIMCR_ENABLE_AUTONEGOTIATION   (1<<12)\r
183 #define MIIMCR_RESTART_AUTONEGOTIATION  (1<<9)\r
184 #define MIIMCR_DUPLEX_MODE                              (1<<8)\r
185 #define MIIMCR_COLLISION_TEST                   (1<<7)\r
186 \r
187 #define PHYREG_MIIMSR           0x01    /**< MII Management Status Register */\r
188 #define MIIMSR_ANC                      (1<<5)  /**< Auto-Negotiation Completed. */\r
189 #define MIIMSR_LINK                     (1<<2)  /**< Link is established. */\r
190 \r
191 #define PHYREG_PHYID1R          0x02    /**< PHY Identifier 1 Register */\r
192 #define PHYREG_PHYID2R          0x03    /**< PHY Identifier 2 Register */\r
193 \r
194 #define PHYREG_ANAR                     0x04    /**< Auto-Negotiation Advertisement Register */\r
195 #define ANAR_100FD                      (1<<8)\r
196 #define ANAR_100HD                      (1<<7)\r
197 #define ANAR_10FD                       (1<<6)\r
198 #define ANAR_10HD                       (1<<5)\r
199 \r
200 #define PHYREG_ANLPAR           0x05    /**< Auto-Negotiation Link Partner Ability Register */\r
201 #define PHYREG_ANER                     0x06    /**< Auto-Negotiation Expansion Register */\r
202 #define PHYREG_NPAR                     0x07    /**< Next Page Advertisement Register */\r
203 /*                      0x08-                   0x0F  Reserved */\r
204 #define PHYREG_MFR                      0x10    /**< Miscellaneous Features Register */\r
205 #define PHYREG_ICSR                     0x11    /**< Interrupt Control/Status Register */\r
206 \r
207 #define PHYREG_DR                       0x12    /**< Diagnostic Register */\r
208 #define DR_DPLX                         (1<<11)\r
209 #define DR_DATA_RATE            (1<<10)\r
210 \r
211 #define PHYREG_PMLR                     0x13    /**< Power Management & Loopback Register */\r
212 /*                      0x14 Reserved */\r
213 #define PHYREG_MCR                      0x15    /**< Mode Control Register */\r
214 #define MCR_LED_SEL                     (1<<9)\r
215 /*                      0x16 Reserved */\r
216 #define PHYREG_DCR                      0x17    /**< Disconnect Counter */\r
217 #define PHYREG_RECR                     0x18    /**< Receive Error Counter */\r
218 /*                         0x19-0x1F  Reserved */\r
219 \r
220 /***************************************************************************//**\r
221  * Probe used PHY.\r
222  *\r
223  * return       PHY address. If PHY don't fount, returns 255.\r
224  */\r
225 uint8_t PHY_probe( void )\r
226 {\r
227         uint8_t phy;\r
228         uint8_t phy_found;\r
229         uint16_t reg;\r
230 \r
231         phy_found = 0;\r
232         for (phy = MSS_PHY_ADDRESS_MIN; phy <= MSS_PHY_ADDRESS_MAX; phy++) {\r
233                 g_mss_mac.phy_address = phy;\r
234 \r
235         reg = MDIO_read( PHYREG_PHYID1R );\r
236 \r
237         if ((reg != 0x0000ffffUL) && (reg != 0x00000000UL)) {\r
238                 phy_found = 1;\r
239                 phy = MSS_PHY_ADDRESS_MAX + 1;\r
240         }\r
241     }\r
242 \r
243     if( phy_found == 0 ) {\r
244         g_mss_mac.phy_address = MSS_PHY_ADDRESS_AUTO_DETECT;\r
245     }\r
246     return g_mss_mac.phy_address;\r
247 }\r
248 \r
249 \r
250 /***************************************************************************//**\r
251  * Resets the PHY.\r
252  */\r
253 void PHY_reset( void )\r
254 {\r
255         MDIO_write( PHYREG_MIIMCR, MIIMCR_RESET );\r
256         MDIO_write( PHYREG_MIIMCR,\r
257                 MIIMCR_ENABLE_AUTONEGOTIATION |\r
258                 MIIMCR_RESTART_AUTONEGOTIATION |\r
259                 MIIMCR_COLLISION_TEST );\r
260 }\r
261 \r
262 \r
263 /***************************************************************************//**\r
264  * Restarts PHY auto-negotiation and wait until it's over.\r
265  */\r
266 void PHY_auto_negotiate( void )\r
267 {\r
268         int32_t a;\r
269         uint16_t reg;\r
270     int32_t exit = 1;\r
271 \r
272         reg = MDIO_read( PHYREG_MIIMCR );\r
273         MDIO_write( PHYREG_MIIMCR,\r
274                 (uint16_t)( MIIMCR_ENABLE_AUTONEGOTIATION |\r
275                 MIIMCR_RESTART_AUTONEGOTIATION |\r
276                 reg) );\r
277 \r
278         for(a=0; (a<1000) && (exit); a++) {\r
279                 reg = MDIO_read( PHYREG_MIIMSR );\r
280                 if( (reg & MIIMSR_ANC) != 0 ) {\r
281                         exit = 0;\r
282                 }\r
283         }\r
284 }\r
285 \r
286 \r
287 /***************************************************************************//**\r
288  * Returns link status.\r
289  *\r
290  * @return          #MAC_LINK_STATUS_LINK if link is up.\r
291  */\r
292 uint8_t PHY_link_status( void )\r
293 {\r
294         uint8_t retval = 0;\r
295         if(( MDIO_read( PHYREG_MIIMSR ) & MIIMSR_LINK ) != 0 ){\r
296                 retval = MSS_MAC_LINK_STATUS_LINK;\r
297         }\r
298         return retval;\r
299 }\r
300 \r
301 \r
302 /***************************************************************************//**\r
303  * Returns link type.\r
304  *\r
305  * @return          the logical OR of the following values:\r
306  *      #MAC_LINK_STATUS_100MB   - Connection is 100Mb\r
307  *      #MAC_LINK_STATUS_FDX     - Connection is full duplex\r
308  */\r
309 uint8_t PHY_link_type( void )\r
310 {\r
311         uint16_t diagnostic;\r
312         uint8_t type = 0;\r
313 \r
314         diagnostic = MDIO_read( PHYREG_DR );\r
315 \r
316     if( (diagnostic & DR_DPLX) != 0 ) {\r
317         type = MSS_MAC_LINK_STATUS_FDX;\r
318     }\r
319 \r
320     if( (diagnostic & DR_DATA_RATE) != 0 ) {\r
321         type |= MSS_MAC_LINK_STATUS_100MB;\r
322     }\r
323 \r
324     return type;\r
325 }\r
326 \r
327 \r
328 /***************************************************************************//**\r
329  * Sets link type.\r
330  */\r
331 void\r
332 PHY_set_link_type\r
333 (\r
334     uint8_t type\r
335 )\r
336 {\r
337         uint16_t reg;\r
338 \r
339         reg = MDIO_read( PHYREG_ANAR );\r
340         reg |= ANAR_100FD | ANAR_100HD | ANAR_10FD | ANAR_10HD;\r
341 \r
342         if( (type & MSS_MAC_LINK_STATUS_100MB) == 0 ) {\r
343                 reg &= ~(ANAR_100FD | ANAR_100HD);\r
344         }\r
345 \r
346         if( (type & MSS_MAC_LINK_STATUS_FDX) == 0 ) {\r
347                 reg &= ~(ANAR_100FD | ANAR_10FD);\r
348         }\r
349 \r
350         MDIO_write( PHYREG_ANAR, reg );\r
351 }\r
352 \r
353 \r
354 /***************************************************************************//**\r
355  * Puts the Phy in Loopback mode\r
356  */\r
357 uint16_t\r
358 PHY_set_loopback\r
359 (\r
360    uint8_t enable\r
361 )\r
362 {\r
363 \r
364         uint16_t reg = 0;   \r
365         \r
366 \r
367         reg = MDIO_read( PHYREG_MIIMCR );\r
368         // If set to one we need to set the LOCAL Phy loopback\r
369         if(enable == 1)\r
370                 reg |= MIIMCR_LOOPBACK;\r
371         else // else we want to clear the bit..\r
372                 reg ^= MIIMCR_LOOPBACK;\r
373         \r
374         \r
375         MDIO_write( PHYREG_MIIMCR,reg );\r
376         reg = MDIO_read( PHYREG_MIIMCR );\r
377         \r
378         return reg;\r
379         \r
380 }\r
381 \r
382 #ifdef __cplusplus\r
383 }\r
384 #endif\r
385 \r
386 /******************************** END OF FILE *********************************/\r
387 \r