4 * \brief API driver for KSZ8051MNL PHY component.
\r
6 * Copyright (c) 2013 Atmel Corporation. All rights reserved.
\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
15 * 1. Redistributions of source code must retain the above copyright notice,
\r
16 * this list of conditions and the following disclaimer.
\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
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
25 * 4. This software may only be redistributed and used in connection with an
\r
26 * Atmel microcontroller product.
\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
44 /* Standard includes. */
\r
49 /* FreeRTOS includes. */
\r
50 #include "FreeRTOS.h"
\r
51 #include "FreeRTOSIPConfig.h"
\r
53 #include "ethernet_phy.h"
\r
54 #include "instance/gmac.h"
\r
65 * \defgroup ksz8051mnl_ethernet_phy_group PHY component (KSZ8051MNL)
\r
67 * Driver for the ksz8051mnl component. This driver provides access to the main
\r
68 * features of the PHY.
\r
70 * \section dependencies Dependencies
\r
71 * This driver depends on the following modules:
\r
72 * - \ref gmac_group Ethernet Media Access Controller (GMAC) module.
\r
79 /* Max PHY number */
\r
80 #define ETH_PHY_MAX_ADDR 31
\r
82 /* Ethernet PHY operation max retry count */
\r
83 #define ETH_PHY_RETRY_MAX 1000000
\r
85 /* Ethernet PHY operation timeout */
\r
86 #define ETH_PHY_TIMEOUT 10
\r
89 * \brief Find a valid PHY Address ( from addrStart to 31 ).
\r
91 * \param p_gmac Pointer to the GMAC instance.
\r
92 * \param uc_phy_addr PHY address.
\r
93 * \param uc_start_addr Start address of the PHY to be searched.
\r
95 * \return 0xFF when no valid PHY address is found.
\r
97 int ethernet_phy_addr = 0;
\r
98 static uint8_t ethernet_phy_find_valid(Gmac *p_gmac, uint8_t uc_phy_addr,
\r
99 uint8_t uc_start_addr)
\r
101 uint32_t ul_value = 0;
\r
103 uint8_t uc_phy_address = uc_phy_addr;
\r
105 gmac_enable_management(p_gmac, true);
\r
107 #define GMII_OUI_MSB 0x0022
\r
108 #define GMII_OUI_LSB 0x05
\r
112 0001_0101_0101_0000 = 0x1550 <= mask should be 0xFFF0
\r
114 /* Check the current PHY address */
\r
115 gmac_phy_read(p_gmac, uc_phy_addr, GMII_PHYID1, &ul_value);
\r
117 /* Find another one */
\r
118 if (ul_value != GMII_OUI_MSB) {
\r
119 ethernet_phy_addr = 0xFF;
\r
120 for (uc_cnt = uc_start_addr; uc_cnt <= ETH_PHY_MAX_ADDR; uc_cnt++) {
\r
121 uc_phy_address = (uc_phy_address + 1) & 0x1F;
\r
123 gmac_phy_read(p_gmac, uc_phy_address, GMII_PHYID1, &ul_value);
\r
124 if (ul_value == GMII_OUI_MSB) {
\r
125 ethernet_phy_addr = uc_phy_address;
\r
131 gmac_enable_management(p_gmac, false);
\r
133 if (ethernet_phy_addr != 0xFF) {
\r
134 gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_value);
\r
136 return ethernet_phy_addr;
\r
141 * \brief Perform a HW initialization to the PHY and set up clocks.
\r
143 * This should be called only once to initialize the PHY pre-settings.
\r
144 * The PHY address is the reset status of CRS, RXD[3:0] (the emacPins' pullups).
\r
145 * The COL pin is used to select MII mode on reset (pulled up for Reduced MII).
\r
146 * The RXDV pin is used to select test mode on reset (pulled up for test mode).
\r
147 * The above pins should be predefined for corresponding settings in resetPins.
\r
148 * The GMAC peripheral pins are configured after the reset is done.
\r
150 * \param p_gmac Pointer to the GMAC instance.
\r
151 * \param uc_phy_addr PHY address.
\r
152 * \param ul_mck GMAC MCK.
\r
154 * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\r
156 uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t mck)
\r
158 uint8_t uc_rc = GMAC_TIMEOUT;
\r
161 ethernet_phy_reset(GMAC,uc_phy_addr);
\r
163 /* Configure GMAC runtime clock */
\r
164 uc_rc = gmac_set_mdc_clock(p_gmac, mck);
\r
165 if (uc_rc != GMAC_OK) {
\r
169 /* Check PHY Address */
\r
170 uc_phy = ethernet_phy_find_valid(p_gmac, uc_phy_addr, 0);
\r
171 if (uc_phy == 0xFF) {
\r
174 if (uc_phy != uc_phy_addr) {
\r
175 ethernet_phy_reset(p_gmac, uc_phy_addr);
\r
177 phy_props.phy_chn = uc_phy;
\r
183 * \brief Get the Link & speed settings, and automatically set up the GMAC with the
\r
186 * \param p_gmac Pointer to the GMAC instance.
\r
187 * \param uc_phy_addr PHY address.
\r
188 * \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply.
\r
190 * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\r
192 uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr,
\r
193 uint8_t uc_apply_setting_flag)
\r
197 uint8_t uc_phy_address, uc_speed = true, uc_fd = true;
\r
198 uint8_t uc_rc = GMAC_TIMEOUT;
\r
200 gmac_enable_management(p_gmac, true);
\r
202 uc_phy_address = uc_phy_addr;
\r
204 uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_stat1);
\r
205 if (uc_rc != GMAC_OK) {
\r
206 /* Disable PHY management and start the GMAC transfer */
\r
207 gmac_enable_management(p_gmac, false);
\r
211 if ((ul_stat1 & GMII_LINK_STATUS) == 0) {
\r
212 /* Disable PHY management and start the GMAC transfer */
\r
213 gmac_enable_management(p_gmac, false);
\r
215 return GMAC_INVALID;
\r
218 if (uc_apply_setting_flag == 0) {
\r
219 /* Disable PHY management and start the GMAC transfer */
\r
220 gmac_enable_management(p_gmac, false);
\r
225 /* Read advertisement */
\r
226 uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_ANAR, &ul_stat2);
\r
227 phy_props.phy_stat1 = ul_stat1;
\r
228 phy_props.phy_stat2 = ul_stat2;
\r
229 if (uc_rc != GMAC_OK) {
\r
230 /* Disable PHY management and start the GMAC transfer */
\r
231 gmac_enable_management(p_gmac, false);
\r
236 if ((ul_stat1 & GMII_100BASE_TX_FD) && (ul_stat2 & GMII_100TX_FDX)) {
\r
237 /* Set GMAC for 100BaseTX and Full Duplex */
\r
241 if ((ul_stat1 & GMII_100BASE_T4_HD) && (ul_stat2 & GMII_100TX_HDX)) {
\r
242 /* Set MII for 100BaseTX and Half Duplex */
\r
246 if ((ul_stat1 & GMII_10BASE_T_FD) && (ul_stat2 & GMII_10_FDX)) {
\r
247 /* Set MII for 10BaseT and Full Duplex */
\r
251 if ((ul_stat1 & GMII_10BASE_T_HD) && (ul_stat2 & GMII_10_HDX)) {
\r
252 /* Set MII for 10BaseT and Half Duplex */
\r
257 gmac_set_speed(p_gmac, uc_speed);
\r
258 gmac_enable_full_duplex(p_gmac, uc_fd);
\r
260 /* Start the GMAC transfers */
\r
261 gmac_enable_management(p_gmac, false);
\r
265 PhyProps_t phy_props;
\r
268 * \brief Issue an auto negotiation of the PHY.
\r
270 * \param p_gmac Pointer to the GMAC instance.
\r
271 * \param uc_phy_addr PHY address.
\r
273 * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\r
275 uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr)
\r
277 uint32_t ul_retry_max = ETH_PHY_RETRY_MAX;
\r
279 uint32_t ul_phy_anar;
\r
280 uint32_t ul_retry_count = 0;
\r
281 uint8_t uc_speed = 0;
\r
283 uint8_t uc_rc = GMAC_TIMEOUT;
\r
285 gmac_enable_management(p_gmac, true);
\r
287 /* Set up control register */
\r
288 uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);
\r
289 if (uc_rc != GMAC_OK) {
\r
290 gmac_enable_management(p_gmac, false);
\r
291 phy_props.phy_result = -1;
\r
295 ul_value &= ~(uint32_t)GMII_AUTONEG; /* Remove auto-negotiation enable */
\r
296 ul_value &= ~(uint32_t)(GMII_LOOPBACK | GMII_POWER_DOWN);
\r
297 ul_value |= (uint32_t)GMII_ISOLATE; /* Electrically isolate PHY */
\r
298 uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
\r
299 if (uc_rc != GMAC_OK) {
\r
300 gmac_enable_management(p_gmac, false);
\r
301 phy_props.phy_result = -2;
\r
306 * Set the Auto_negotiation Advertisement Register.
\r
307 * MII advertising for Next page.
\r
308 * 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3.
\r
310 ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX |
\r
311 GMII_AN_IEEE_802_3;
\r
312 uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar);
\r
313 if (uc_rc != GMAC_OK) {
\r
314 gmac_enable_management(p_gmac, false);
\r
315 phy_props.phy_result = -3;
\r
319 /* Read & modify control register */
\r
320 uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value);
\r
321 if (uc_rc != GMAC_OK) {
\r
322 gmac_enable_management(p_gmac, false);
\r
323 phy_props.phy_result = -4;
\r
327 ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE;
\r
328 uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
\r
329 if (uc_rc != GMAC_OK) {
\r
330 gmac_enable_management(p_gmac, false);
\r
331 phy_props.phy_result = -5;
\r
335 /* Restart auto negotiation */
\r
336 ul_value |= (uint32_t)GMII_RESTART_AUTONEG;
\r
337 ul_value &= ~(uint32_t)GMII_ISOLATE;
\r
338 uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value);
\r
339 if (uc_rc != GMAC_OK) {
\r
340 gmac_enable_management(p_gmac, false);
\r
341 phy_props.phy_result = -6;
\r
345 /* Check if auto negotiation is completed */
\r
347 uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMSR, &ul_value);
\r
348 if (uc_rc != GMAC_OK) {
\r
349 gmac_enable_management(p_gmac, false);
\r
350 phy_props.phy_result = -7;
\r
353 /* Done successfully */
\r
354 if (ul_value & GMII_AUTONEG_COMP) {
\r
358 /* Timeout check */
\r
359 if (ul_retry_max) {
\r
360 if (++ul_retry_count >= ul_retry_max) {
\r
361 gmac_enable_management(p_gmac, false);
\r
362 phy_props.phy_result = -8;
\r
363 return GMAC_TIMEOUT;
\r
368 /* Get the auto negotiate link partner base page */
\r
369 uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_PCR1, &phy_props.phy_params);
\r
370 if (uc_rc != GMAC_OK) {
\r
371 gmac_enable_management(p_gmac, false);
\r
372 phy_props.phy_result = -9;
\r
377 /* Set up the GMAC link speed */
\r
378 if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_FDX) {
\r
379 /* Set MII for 100BaseTX and Full Duplex */
\r
382 } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_FDX) {
\r
383 /* Set MII for 10BaseT and Full Duplex */
\r
386 } else if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_HDX) {
\r
387 /* Set MII for 100BaseTX and half Duplex */
\r
390 } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_HDX) {
\r
391 /* Set MII for 10BaseT and half Duplex */
\r
396 gmac_set_speed(p_gmac, uc_speed);
\r
397 gmac_enable_full_duplex(p_gmac, uc_fd);
\r
399 /* Select Media Independent Interface type */
\r
400 gmac_select_mii_mode(p_gmac, ETH_PHY_MODE);
\r
402 gmac_enable_transmit(GMAC, true);
\r
403 gmac_enable_receive(GMAC, true);
\r
405 gmac_enable_management(p_gmac, false);
\r
406 phy_props.phy_result = 1;
\r
411 * \brief Issue a SW reset to reset all registers of the PHY.
\r
413 * \param p_gmac Pointer to the GMAC instance.
\r
414 * \param uc_phy_addr PHY address.
\r
416 * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\r
418 uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr)
\r
420 uint32_t ul_bmcr = GMII_RESET;
\r
421 uint8_t uc_phy_address = uc_phy_addr;
\r
422 uint32_t ul_timeout = ETH_PHY_TIMEOUT;
\r
423 uint8_t uc_rc = GMAC_TIMEOUT;
\r
425 gmac_enable_management(p_gmac, true);
\r
427 ul_bmcr = GMII_RESET;
\r
428 gmac_phy_write(p_gmac, uc_phy_address, GMII_BMCR, ul_bmcr);
\r
431 gmac_phy_read(p_gmac, uc_phy_address, GMII_BMCR, &ul_bmcr);
\r
433 } while ((ul_bmcr & GMII_RESET) && ul_timeout);
\r
435 gmac_enable_management(p_gmac, false);
\r