]> git.sur5r.net Git - freertos/blob
790f9dfb948b514299fac92b9358207678383135
[freertos] /
1  /**\r
2  * \file\r
3  *\r
4  * \brief API driver for KSZ8051MNL PHY component.\r
5  *\r
6  * Copyright (c) 2013 Atmel Corporation. All rights reserved.\r
7  *\r
8  * \asf_license_start\r
9  *\r
10  * \page License\r
11  *\r
12  * Redistribution and use in source and binary forms, with or without\r
13  * modification, are permitted provided that the following conditions are met:\r
14  *\r
15  * 1. Redistributions of source code must retain the above copyright notice,\r
16  *    this list of conditions and the following disclaimer.\r
17  *\r
18  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
19  *    this list of conditions and the following disclaimer in the documentation\r
20  *    and/or other materials provided with the distribution.\r
21  *\r
22  * 3. The name of Atmel may not be used to endorse or promote products derived\r
23  *    from this software without specific prior written permission.\r
24  *\r
25  * 4. This software may only be redistributed and used in connection with an\r
26  *    Atmel microcontroller product.\r
27  *\r
28  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED\r
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
31  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR\r
32  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
36  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
37  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
38  * POSSIBILITY OF SUCH DAMAGE.\r
39  *\r
40  * \asf_license_stop\r
41  *\r
42  */\r
43 \r
44 #include "ethernet_phy.h"\r
45 #include "gmac.h"\r
46 #include "conf_eth.h"\r
47 \r
48 /// @cond 0\r
49 /**INDENT-OFF**/\r
50 #ifdef __cplusplus\r
51 extern "C" {\r
52 #endif\r
53 /**INDENT-ON**/\r
54 /// @endcond\r
55 \r
56 /**\r
57  * \defgroup ksz8051mnl_ethernet_phy_group PHY component (KSZ8051MNL)\r
58  *\r
59  * Driver for the ksz8051mnl component. This driver provides access to the main\r
60  * features of the PHY.\r
61  *\r
62  * \section dependencies Dependencies\r
63  * This driver depends on the following modules:\r
64  * - \ref gmac_group Ethernet Media Access Controller (GMAC) module.\r
65  *\r
66  * @{\r
67  */\r
68 \r
69 /* Max PHY number */\r
70 #define ETH_PHY_MAX_ADDR   31\r
71 \r
72 /* Ethernet PHY operation max retry count */\r
73 #define ETH_PHY_RETRY_MAX 1000000\r
74 \r
75 /* Ethernet PHY operation timeout */\r
76 #define ETH_PHY_TIMEOUT 10\r
77 \r
78 /**\r
79  * \brief Find a valid PHY Address ( from addrStart to 31 ).\r
80  *\r
81  * \param p_gmac   Pointer to the GMAC instance.\r
82  * \param uc_phy_addr PHY address.\r
83  * \param uc_start_addr Start address of the PHY to be searched.\r
84  *\r
85  * \return 0xFF when no valid PHY address is found.\r
86  */\r
87 static uint8_t ethernet_phy_find_valid(Gmac *p_gmac, uint8_t uc_phy_addr,\r
88                 uint8_t uc_start_addr)\r
89 {\r
90         uint32_t ul_value = 0;\r
91         uint8_t uc_rc = 0;\r
92         uint8_t uc_cnt;\r
93         uint8_t uc_phy_address = uc_phy_addr;\r
94 \r
95         gmac_enable_management(p_gmac, true);\r
96 \r
97         /* Check the current PHY address */\r
98         gmac_phy_read(p_gmac, uc_phy_addr, GMII_PHYID1, &ul_value);\r
99 \r
100         /* Find another one */\r
101         if (ul_value != GMII_OUI_LSB) {\r
102                 uc_rc = 0xFF;\r
103                 for (uc_cnt = uc_start_addr; uc_cnt <= ETH_PHY_MAX_ADDR; uc_cnt++) {\r
104                         uc_phy_address = (uc_phy_address + 1) & 0x1F;\r
105                         gmac_phy_read(p_gmac, uc_phy_address, GMII_PHYID1, &ul_value);\r
106                         if (ul_value == GMII_OUI_MSB) {\r
107                                 uc_rc = uc_phy_address;\r
108                                 break;\r
109                         }\r
110                 }\r
111         }\r
112 \r
113         gmac_enable_management(p_gmac, false);\r
114 \r
115         if (uc_rc != 0xFF) {\r
116                 gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_value);\r
117         }\r
118         return uc_rc;\r
119 }\r
120 \r
121 \r
122 /**\r
123  * \brief Perform a HW initialization to the PHY and set up clocks.\r
124  *\r
125  * This should be called only once to initialize the PHY pre-settings.\r
126  * The PHY address is the reset status of CRS, RXD[3:0] (the emacPins' pullups).\r
127  * The COL pin is used to select MII mode on reset (pulled up for Reduced MII).\r
128  * The RXDV pin is used to select test mode on reset (pulled up for test mode).\r
129  * The above pins should be predefined for corresponding settings in resetPins.\r
130  * The GMAC peripheral pins are configured after the reset is done.\r
131  *\r
132  * \param p_gmac   Pointer to the GMAC instance.\r
133  * \param uc_phy_addr PHY address.\r
134  * \param ul_mck GMAC MCK.\r
135  *\r
136  * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.\r
137  */\r
138 uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t mck)\r
139 {\r
140         uint8_t uc_rc = GMAC_TIMEOUT;\r
141         uint8_t uc_phy;\r
142 \r
143         ethernet_phy_reset(GMAC,uc_phy_addr);\r
144 \r
145         /* Configure GMAC runtime clock */\r
146         uc_rc = gmac_set_mdc_clock(p_gmac, mck);\r
147         if (uc_rc != GMAC_OK) {\r
148                 return 0;\r
149         }\r
150 \r
151         /* Check PHY Address */\r
152         uc_phy = ethernet_phy_find_valid(p_gmac, uc_phy_addr, 0);\r
153         if (uc_phy == 0xFF) {\r
154                 return 0;\r
155         }\r
156         if (uc_phy != uc_phy_addr) {\r
157                 ethernet_phy_reset(p_gmac, uc_phy_addr);\r
158         }\r
159 \r
160         return uc_rc;\r
161 }\r
162 \r
163 \r
164 /**\r
165  * \brief Get the Link & speed settings, and automatically set up the GMAC with the\r
166  * settings.\r
167  *\r
168  * \param p_gmac   Pointer to the GMAC instance.\r
169  * \param uc_phy_addr PHY address.\r
170  * \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.\r
171  *\r
172  * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.\r
173  */\r
174 uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr,\r
175                 uint8_t uc_apply_setting_flag)\r
176 {\r
177         uint32_t ul_stat1;\r
178         uint32_t ul_stat2;\r
179         uint8_t uc_phy_address, uc_speed, uc_fd;\r
180         uint8_t uc_rc = GMAC_TIMEOUT;\r
181 \r
182         gmac_enable_management(p_gmac, true);\r
183 \r
184         uc_phy_address = uc_phy_addr;\r
185 \r
186         uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_stat1);\r
187         if (uc_rc != GMAC_OK) {\r
188                 /* Disable PHY management and start the GMAC transfer */\r
189                 gmac_enable_management(p_gmac, false);\r
190 \r
191                 return uc_rc;\r
192         }\r
193 \r
194         if ((ul_stat1 & GMII_LINK_STATUS) == 0) {\r
195                 /* Disable PHY management and start the GMAC transfer */\r
196                 gmac_enable_management(p_gmac, false);\r
197 \r
198                 return GMAC_INVALID;\r
199         }\r
200 \r
201         if (uc_apply_setting_flag == 0) {\r
202                 /* Disable PHY management and start the GMAC transfer */\r
203                 gmac_enable_management(p_gmac, false);\r
204 \r
205                 return uc_rc;\r
206         }\r
207 \r
208         /* Read advertisement */\r
209         uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_ANAR, &ul_stat2);\r
210         if (uc_rc != GMAC_OK) {\r
211                 /* Disable PHY management and start the GMAC transfer */\r
212                 gmac_enable_management(p_gmac, false);\r
213 \r
214                 return uc_rc;\r
215         }\r
216 \r
217         if ((ul_stat1 & GMII_100BASE_TX_FD) && (ul_stat2 & GMII_100TX_FDX)) {\r
218                 /* Set GMAC for 100BaseTX and Full Duplex */\r
219                 uc_speed = true;\r
220                 uc_fd = true;\r
221         }\r
222 \r
223         if ((ul_stat1 & GMII_10BASE_T_FD) && (ul_stat2 & GMII_10_FDX)) {\r
224                 /* Set MII for 10BaseT and Full Duplex */\r
225                 uc_speed = false;\r
226                 uc_fd = true;\r
227         }\r
228 \r
229         if ((ul_stat1 & GMII_100BASE_T4_HD) && (ul_stat2 & GMII_100TX_HDX)) {\r
230                 /* Set MII for 100BaseTX and Half Duplex */\r
231                 uc_speed = true;\r
232                 uc_fd = false;\r
233         }\r
234 \r
235         if ((ul_stat1 & GMII_10BASE_T_HD) && (ul_stat2 & GMII_10_HDX)) {\r
236                 /* Set MII for 10BaseT and Half Duplex */\r
237                 uc_speed = false;\r
238                 uc_fd = false;\r
239         }\r
240 \r
241         gmac_set_speed(p_gmac, uc_speed);\r
242         gmac_enable_full_duplex(p_gmac, uc_fd);\r
243 \r
244         /* Start the GMAC transfers */\r
245         gmac_enable_management(p_gmac, false);\r
246         return uc_rc;\r
247 }\r
248 \r
249 \r
250 /**\r
251  * \brief Issue an auto negotiation of the PHY.\r
252  *\r
253  * \param p_gmac   Pointer to the GMAC instance.\r
254  * \param uc_phy_addr PHY address.\r
255  *\r
256  * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.\r
257  */\r
258 uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr)\r
259 {\r
260         uint32_t ul_retry_max = ETH_PHY_RETRY_MAX;\r
261         uint32_t ul_value;\r
262         uint32_t ul_phy_anar;\r
263         uint32_t ul_phy_analpar;\r
264         uint32_t ul_retry_count = 0;\r
265         uint8_t uc_speed = 0;\r
266         uint8_t uc_fd=0;\r
267         uint8_t uc_rc = GMAC_TIMEOUT;\r
268 \r
269         gmac_enable_management(p_gmac, true);\r
270 \r
271         /* Set up control register */\r
272         uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);\r
273         if (uc_rc != GMAC_OK) {\r
274                 gmac_enable_management(p_gmac, false);\r
275                 return uc_rc;\r
276         }\r
277 \r
278         ul_value &= ~(uint32_t)GMII_AUTONEG; /* Remove auto-negotiation enable */\r
279         ul_value &= ~(uint32_t)(GMII_LOOPBACK | GMII_POWER_DOWN);\r
280         ul_value |= (uint32_t)GMII_ISOLATE; /* Electrically isolate PHY */\r
281         uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);\r
282         if (uc_rc != GMAC_OK) {\r
283                 gmac_enable_management(p_gmac, false);\r
284                 return uc_rc;\r
285         }\r
286 \r
287         /* \r
288          * Set the Auto_negotiation Advertisement Register.\r
289          * MII advertising for Next page.\r
290          * 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3.\r
291          */\r
292         ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX | \r
293                         GMII_AN_IEEE_802_3;\r
294         uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar);\r
295         if (uc_rc != GMAC_OK) {\r
296                 gmac_enable_management(p_gmac, false);\r
297                 return uc_rc;\r
298         }\r
299 \r
300         /* Read & modify control register */\r
301         uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);\r
302         if (uc_rc != GMAC_OK) {\r
303                 gmac_enable_management(p_gmac, false);\r
304                 return uc_rc;\r
305         }\r
306 \r
307         ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE;\r
308         uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);\r
309         if (uc_rc != GMAC_OK) {\r
310                 gmac_enable_management(p_gmac, false);\r
311                 return uc_rc;\r
312         }\r
313 \r
314         /* Restart auto negotiation */\r
315         ul_value |= (uint32_t)GMII_RESTART_AUTONEG;\r
316         ul_value &= ~(uint32_t)GMII_ISOLATE;\r
317         uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);\r
318         if (uc_rc != GMAC_OK) {\r
319                 gmac_enable_management(p_gmac, false);\r
320                 return uc_rc;\r
321         }\r
322 \r
323         /* Check if auto negotiation is completed */\r
324         while (1) {\r
325                 uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMSR, &ul_value);\r
326                 if (uc_rc != GMAC_OK) {\r
327                         gmac_enable_management(p_gmac, false);\r
328                         return uc_rc;\r
329                 }\r
330                 /* Done successfully */\r
331                 if (ul_value & GMII_AUTONEG_COMP) {\r
332                         break;\r
333                 }\r
334 \r
335                 /* Timeout check */\r
336                 if (ul_retry_max) {\r
337                         if (++ul_retry_count >= ul_retry_max) {\r
338                                 gmac_enable_management(p_gmac, false);\r
339                                 return GMAC_TIMEOUT;\r
340                         }\r
341                 }\r
342         }\r
343 \r
344         /* Get the auto negotiate link partner base page */\r
345         uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_PCR1, &ul_phy_analpar);\r
346         if (uc_rc != GMAC_OK) {\r
347                 gmac_enable_management(p_gmac, false);\r
348                 return uc_rc;\r
349         }\r
350 \r
351 \r
352         /* Set up the GMAC link speed */\r
353         if ((ul_phy_anar & ul_phy_analpar) & GMII_100TX_FDX) {\r
354                 /* Set MII for 100BaseTX and Full Duplex */\r
355                 uc_speed = true;\r
356                 uc_fd = true;\r
357         } else if ((ul_phy_anar & ul_phy_analpar) & GMII_10_FDX) {\r
358                 /* Set MII for 10BaseT and Full Duplex */\r
359                 uc_speed = false;\r
360                 uc_fd = true;\r
361         } else if ((ul_phy_anar & ul_phy_analpar) & GMII_100TX_HDX) {\r
362                 /* Set MII for 100BaseTX and half Duplex */\r
363                 uc_speed = true;\r
364                 uc_fd = false;\r
365         } else if ((ul_phy_anar & ul_phy_analpar) & GMII_10_HDX) {\r
366                 /* Set MII for 10BaseT and half Duplex */\r
367                 uc_speed = false;\r
368                 uc_fd = false;\r
369         }\r
370 \r
371         gmac_set_speed(p_gmac, uc_speed);\r
372         gmac_enable_full_duplex(p_gmac, uc_fd);\r
373 \r
374         /* Select Media Independent Interface type */\r
375         gmac_select_mii_mode(p_gmac, ETH_PHY_MODE);\r
376 \r
377         gmac_enable_transmit(GMAC, true);\r
378         gmac_enable_receive(GMAC, true);\r
379 \r
380         gmac_enable_management(p_gmac, false);\r
381         return uc_rc;\r
382 }\r
383 \r
384 /**\r
385  * \brief Issue a SW reset to reset all registers of the PHY.\r
386  *\r
387  * \param p_gmac   Pointer to the GMAC instance.\r
388  * \param uc_phy_addr PHY address.\r
389  *\r
390  * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.\r
391  */\r
392 uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr)\r
393 {\r
394         uint32_t ul_bmcr = GMII_RESET;\r
395         uint8_t uc_phy_address = uc_phy_addr;\r
396         uint32_t ul_timeout = ETH_PHY_TIMEOUT;\r
397         uint8_t uc_rc = GMAC_TIMEOUT;\r
398 \r
399         gmac_enable_management(p_gmac, true);\r
400 \r
401         ul_bmcr = GMII_RESET;\r
402         gmac_phy_write(p_gmac, uc_phy_address, GMII_BMCR, ul_bmcr);\r
403 \r
404         do {\r
405                 gmac_phy_read(p_gmac, uc_phy_address, GMII_BMCR, &ul_bmcr);\r
406                 ul_timeout--;\r
407         } while ((ul_bmcr & GMII_RESET) && ul_timeout);\r
408 \r
409         gmac_enable_management(p_gmac, false);\r
410 \r
411         if (!ul_timeout) {\r
412                 uc_rc = GMAC_OK;\r
413         }\r
414 \r
415         return (uc_rc);\r
416 }\r
417 \r
418 /// @cond 0\r
419 /**INDENT-OFF**/\r
420 #ifdef __cplusplus\r
421 }\r
422 #endif\r
423 /**INDENT-ON**/\r
424 /// @endcond\r
425 \r
426 /**\r
427  * \}\r
428  */\r