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