1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13/** 14 * \file phy.c 15 * 16 * \brief APIs for configuring ethernet PHYs 17 * 18 * This file contains the device abstraction APIs for ethernet PHYs. 19 */ 20 21/* 22* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 23*/ 24/* 25* Redistribution and use in source and binary forms, with or without 26* modification, are permitted provided that the following conditions 27* are met: 28* 29* Redistributions of source code must retain the above copyright 30* notice, this list of conditions and the following disclaimer. 31* 32* Redistributions in binary form must reproduce the above copyright 33* notice, this list of conditions and the following disclaimer in the 34* documentation and/or other materials provided with the 35* distribution. 36* 37* Neither the name of Texas Instruments Incorporated nor the names of 38* its contributors may be used to endorse or promote products derived 39* from this software without specific prior written permission. 40* 41* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 42* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 43* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 44* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 45* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 51* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52* 53*/ 54 55#include <ethdrivers/plat/hw/hw_types.h> 56#include <ethdrivers/plat/mdio.h> 57#include <ethdrivers/plat/phy.h> 58 59#define PHY_ADV_VAL_MASK (0xff10) 60 61/******************************************************************************* 62* API FUNCTION DEFINITIONS 63*******************************************************************************/ 64/** 65 * \brief Reads the PHY ID. 66 * 67 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 68 * \param phyAddr PHY Adress. 69 * 70 * \return 32 bit PHY ID (ID1:ID2) 71 * 72 **/ 73unsigned int PhyIDGet(unsigned int mdioBaseAddr, unsigned int phyAddr) 74{ 75 unsigned int id = 0; 76 unsigned short data; 77 78 /* read the ID1 register */ 79 MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ID1, &data); 80 81 /* update the ID1 value */ 82 id = data << PHY_ID_SHIFT; 83 84 /* read the ID2 register */ 85 MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ID2, &data); 86 87 /* update the ID2 value */ 88 id |= data; 89 90 /* return the ID in ID1:ID2 format */ 91 return id; 92} 93 94/** 95 * \brief Reads a register from the the PHY 96 * 97 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 98 * \param phyAddr PHY Adress. 99 * \param regIdx Index of the register to be read 100 * \param regValAdr address where value of the register will be written 101 * 102 * \return status of the read 103 * 104 **/ 105unsigned int PhyRegRead(unsigned int mdioBaseAddr, unsigned int phyAddr, 106 unsigned int regIdx, unsigned short *regValAdr) 107{ 108 return (MDIOPhyRegRead(mdioBaseAddr, phyAddr, regIdx, regValAdr)); 109} 110 111/** 112 * \brief Writes a register with the input 113 * 114 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 115 * \param phyAddr PHY Adress. 116 * \param regIdx Index of the register to be read 117 * \param regValAdr value to be written 118 * 119 * \return None 120 * 121 **/ 122void PhyRegWrite(unsigned int mdioBaseAddr, unsigned int phyAddr, 123 unsigned int regIdx, unsigned short regVal) 124{ 125 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, regIdx, regVal); 126} 127 128/** 129 * \brief Enables Loop Back mode 130 * 131 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 132 * \param phyAddr PHY Adress. 133 * 134 * \return status after enabling. \n 135 * TRUE if loop back is enabled \n 136 * FALSE if not able to enable 137 * 138 **/ 139unsigned int PhyLoopBackEnable(unsigned int mdioBaseAddr, unsigned int phyAddr) 140{ 141 unsigned short data; 142 143 if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE ) { 144 return FALSE; 145 } 146 147 data |= PHY_LPBK_ENABLE; 148 149 /* Enable loop back */ 150 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data); 151 152 return TRUE; 153} 154 155/** 156 * \brief Disables Loop Back mode 157 * 158 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 159 * \param phyAddr PHY Adress. 160 * 161 * \return status after enabling. \n 162 * TRUE if loop back is disabled \n 163 * FALSE if not able to disable 164 * 165 **/ 166unsigned int PhyLoopBackDisable(unsigned int mdioBaseAddr, unsigned int phyAddr) 167{ 168 unsigned short data; 169 170 if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE ) { 171 return FALSE; 172 } 173 174 data &= ~(PHY_LPBK_ENABLE); 175 176 /* Disable loop back */ 177 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data); 178 179 return TRUE; 180} 181 182/** 183 * \brief This function ask the phy device to start auto negotiation. 184 * 185 * 186 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 187 * \param phyAddr PHY Adress. 188 * \param advVal Autonegotiation advertisement value 189 * \param gigAdvVal Gigabit capability advertisement value 190 * advVal can take the following any OR combination of the values \n 191 * PHY_100BTX - 100BaseTX \n 192 * PHY_100BTX_FD - Full duplex capabilty for 100BaseTX \n 193 * PHY_10BT - 10BaseT \n 194 * PHY_10BT_FD - Full duplex capability for 10BaseT \n 195 * gigAdvVal can take one of the following values \n 196 * PHY_NO_1000BT - No 1000Base-T capability\n 197 * PHY_1000BT_FD - Full duplex capabilty for 1000 Base-T \n 198 * PHY_1000BT_HD - Half duplex capabilty for 1000 Base-T \n 199 * FALSE - It is passed as an argument if phy dosen't support 200 * Giga bit capability 201 * 202 * \return status after autonegotiation \n 203 * TRUE if autonegotiation started 204 * FALSE if autonegotiation not started 205 * 206 **/ 207unsigned int PhyAutoNegotiate(unsigned int mdioBaseAddr, unsigned int phyAddr, 208 unsigned short *advPtr, unsigned short *gigAdvPtr) 209{ 210 volatile unsigned short data; 211 volatile unsigned short anar; 212 213 if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE ) { 214 return FALSE; 215 } 216 217 data |= PHY_AUTONEG_ENABLE; 218 219 if (*gigAdvPtr != 0) { 220 /* Set phy for gigabit speed */ 221 data &= PHY_SPEED_MASK; 222 data |= PHY_SPEED_1000MBPS; 223 } 224 225 /* Enable Auto Negotiation */ 226 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data); 227 228 if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE ) { 229 return FALSE; 230 } 231 232 /* Write Auto Negotiation capabilities */ 233 MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_AUTONEG_ADV, &anar); 234 anar &= ~PHY_ADV_VAL_MASK; 235 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_AUTONEG_ADV, (anar | (*advPtr))); 236 237 if (*gigAdvPtr != 0) { 238 /* Write the gigabit capabilities */ 239 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_1000BT_CONTROL, (*gigAdvPtr)); 240 } 241 242 data |= PHY_AUTONEG_RESTART; 243 244 /* Start Auto Negotiation */ 245 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data); 246 247 return TRUE; 248} 249 250/** 251 * \brief Returns the status of Auto Negotiation completion. 252 * 253 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 254 * \param phyAddr PHY Adress. 255 * 256 * \return Auto negotiation completion status \n 257 * TRUE if auto negotiation is completed 258 * FALSE if auto negotiation is not completed 259 **/ 260unsigned int PhyAutoNegStatusGet(unsigned int mdioBaseAddr, unsigned int phyAddr) 261{ 262 volatile unsigned short data; 263 264 MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BSR, &data); 265 266 /* Auto negotiation completion status */ 267 if (PHY_AUTONEG_COMPLETE == (data & (PHY_AUTONEG_STATUS))) { 268 return TRUE; 269 } 270 271 return FALSE; 272} 273 274/** 275 * \brief Reads the Link Partner Ability register of the PHY. 276 * 277 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 278 * \param phyAddr PHY Adress. 279 * \param ptnerAblty Pointer to which partner ability will be written. 280 * \param gbpsPtnerAblty Pointer to which Giga bit capability will be written. 281 * 282 * gbpsPtnerAblty can take following Macros.\n 283 * 284 * TRUE - It is passed as argument if phy supports Giga bit capability.\n 285 * FALSE - It is passed as argument if phy dosen't supports Giga bit 286 * capability.\n 287 * 288 * \return status after reading \n 289 * TRUE if reading successful 290 * FALSE if reading failed 291 **/ 292unsigned int PhyPartnerAbilityGet(unsigned int mdioBaseAddr, 293 unsigned int phyAddr, 294 unsigned short *ptnerAblty, 295 unsigned short *gbpsPtnerAblty) 296{ 297 unsigned int status; 298 299 status = MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_LINK_PARTNER_ABLTY, 300 ptnerAblty); 301 302 if (*gbpsPtnerAblty != 0) { 303 status = status | MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_1000BT_STATUS, 304 gbpsPtnerAblty); 305 } 306 307 return status; 308} 309 310/** 311 * \brief Reads the link status of the PHY. 312 * 313 * \param mdioBaseAddr Base Address of the MDIO Module Registers. 314 * \param phyAddr PHY Adress. 315 * \param retries The number of retries before indicating down status 316 * 317 * \return link status after reading \n 318 * TRUE if link is up 319 * FALSE if link is down \n 320 * 321 * \note This reads both the basic status register of the PHY and the 322 * link register of MDIO for double check 323 **/ 324unsigned int PhyLinkStatusGet(unsigned int mdioBaseAddr, 325 unsigned int phyAddr, 326 volatile unsigned int retries) 327{ 328 volatile unsigned short linkStatus; 329 330 retries++; 331 while (retries) { 332 /* First read the BSR of the PHY */ 333 MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BSR, &linkStatus); 334 335 if (linkStatus & PHY_LINK_STATUS) { 336 return TRUE; 337 } 338 339 retries--; 340 } 341 342 return FALSE; 343} 344 345 346/* The next two functions were copied from 'bb-sel4' project at: 347 * https://github.com/juli1/bb-sel4 348 * In particular, they were taken from: 349 * https://github.com/juli1/bb-sel4/blob/701e87f4d4a403d3b0c02326d42e8580a7ff4b7f/bb-eth/components/ConsumerThreadImpl/src/phy.c 350 */ 351unsigned int PhyReset(unsigned int mdioBaseAddr, unsigned int phyAddr) 352{ 353 unsigned short data; 354 355 data = PHY_SOFTRESET; 356 357 /* Reset the phy */ 358 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, data); 359 360 /* wait till the reset bit is auto cleared */ 361 while(data & PHY_SOFTRESET) 362 { 363 /* Read the reset */ 364 if(MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BCR, &data) != TRUE) 365 { 366 return FALSE; 367 } 368 } 369 370 return TRUE; 371} 372 373unsigned int PhyConfigure(unsigned int mdioBaseAddr, unsigned int phyAddr, 374 unsigned short speed, unsigned short duplexMode) 375{ 376 /* Set the configurations */ 377 MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BCR, (speed | duplexMode)); 378 379 return TRUE; 380} 381 382/**************************** End Of File ***********************************/ 383