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 #include "ethernet_phy.h"
\r
46 #include "conf_eth.h"
\r
57 * \defgroup ksz8051mnl_ethernet_phy_group PHY component (KSZ8051MNL)
\r
59 * Driver for the ksz8051mnl component. This driver provides access to the main
\r
60 * features of the PHY.
\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
69 /* Max PHY number */
\r
70 #define ETH_PHY_MAX_ADDR 31
\r
72 /* Ethernet PHY operation max retry count */
\r
73 #define ETH_PHY_RETRY_MAX 1000000
\r
75 /* Ethernet PHY operation timeout */
\r
76 #define ETH_PHY_TIMEOUT 10
\r
79 * \brief Find a valid PHY Address ( from addrStart to 31 ).
\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
85 * \return 0xFF when no valid PHY address is found.
\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
90 uint32_t ul_value = 0;
\r
93 uint8_t uc_phy_address = uc_phy_addr;
\r
95 gmac_enable_management(p_gmac, true);
\r
97 /* Check the current PHY address */
\r
98 gmac_phy_read(p_gmac, uc_phy_addr, GMII_PHYID1, &ul_value);
\r
100 /* Find another one */
\r
101 if (ul_value != GMII_OUI_LSB) {
\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
113 gmac_enable_management(p_gmac, false);
\r
115 if (uc_rc != 0xFF) {
\r
116 gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_value);
\r
123 * \brief Perform a HW initialization to the PHY and set up clocks.
\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
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
136 * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\r
138 uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t mck)
\r
140 uint8_t uc_rc = GMAC_TIMEOUT;
\r
143 ethernet_phy_reset(GMAC,uc_phy_addr);
\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
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
156 if (uc_phy != uc_phy_addr) {
\r
157 ethernet_phy_reset(p_gmac, uc_phy_addr);
\r
165 * \brief Get the Link & speed settings, and automatically set up the GMAC with the
\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
172 * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\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
179 uint8_t uc_phy_address, uc_speed, uc_fd;
\r
180 uint8_t uc_rc = GMAC_TIMEOUT;
\r
182 gmac_enable_management(p_gmac, true);
\r
184 uc_phy_address = uc_phy_addr;
\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
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
198 return GMAC_INVALID;
\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
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
217 if ((ul_stat1 & GMII_100BASE_TX_FD) && (ul_stat2 & GMII_100TX_FDX)) {
\r
218 /* Set GMAC for 100BaseTX and Full Duplex */
\r
223 if ((ul_stat1 & GMII_10BASE_T_FD) && (ul_stat2 & GMII_10_FDX)) {
\r
224 /* Set MII for 10BaseT and Full Duplex */
\r
229 if ((ul_stat1 & GMII_100BASE_T4_HD) && (ul_stat2 & GMII_100TX_HDX)) {
\r
230 /* Set MII for 100BaseTX and Half Duplex */
\r
235 if ((ul_stat1 & GMII_10BASE_T_HD) && (ul_stat2 & GMII_10_HDX)) {
\r
236 /* Set MII for 10BaseT and Half Duplex */
\r
241 gmac_set_speed(p_gmac, uc_speed);
\r
242 gmac_enable_full_duplex(p_gmac, uc_fd);
\r
244 /* Start the GMAC transfers */
\r
245 gmac_enable_management(p_gmac, false);
\r
251 * \brief Issue an auto negotiation of the PHY.
\r
253 * \param p_gmac Pointer to the GMAC instance.
\r
254 * \param uc_phy_addr PHY address.
\r
256 * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\r
258 uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr)
\r
260 uint32_t ul_retry_max = ETH_PHY_RETRY_MAX;
\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
267 uint8_t uc_rc = GMAC_TIMEOUT;
\r
269 gmac_enable_management(p_gmac, true);
\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
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
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
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
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
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
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
323 /* Check if auto negotiation is completed */
\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
330 /* Done successfully */
\r
331 if (ul_value & GMII_AUTONEG_COMP) {
\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
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
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
357 } else if ((ul_phy_anar & ul_phy_analpar) & GMII_10_FDX) {
\r
358 /* Set MII for 10BaseT and Full Duplex */
\r
361 } else if ((ul_phy_anar & ul_phy_analpar) & GMII_100TX_HDX) {
\r
362 /* Set MII for 100BaseTX and half Duplex */
\r
365 } else if ((ul_phy_anar & ul_phy_analpar) & GMII_10_HDX) {
\r
366 /* Set MII for 10BaseT and half Duplex */
\r
371 gmac_set_speed(p_gmac, uc_speed);
\r
372 gmac_enable_full_duplex(p_gmac, uc_fd);
\r
374 /* Select Media Independent Interface type */
\r
375 gmac_select_mii_mode(p_gmac, ETH_PHY_MODE);
\r
377 gmac_enable_transmit(GMAC, true);
\r
378 gmac_enable_receive(GMAC, true);
\r
380 gmac_enable_management(p_gmac, false);
\r
385 * \brief Issue a SW reset to reset all registers of the PHY.
\r
387 * \param p_gmac Pointer to the GMAC instance.
\r
388 * \param uc_phy_addr PHY address.
\r
390 * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout.
\r
392 uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr)
\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
399 gmac_enable_management(p_gmac, true);
\r
401 ul_bmcr = GMII_RESET;
\r
402 gmac_phy_write(p_gmac, uc_phy_address, GMII_BMCR, ul_bmcr);
\r
405 gmac_phy_read(p_gmac, uc_phy_address, GMII_BMCR, &ul_bmcr);
\r
407 } while ((ul_bmcr & GMII_RESET) && ul_timeout);
\r
409 gmac_enable_management(p_gmac, false);
\r