fsl_phy.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2017 NXP
  4. *
  5. * Redistribution and use in source and binary forms, with or without modification,
  6. * are permitted provided that the following conditions are met:
  7. *
  8. * o Redistributions of source code must retain the above copyright notice, this list
  9. * of conditions and the following disclaimer.
  10. *
  11. * o Redistributions in binary form must reproduce the above copyright notice, this
  12. * list of conditions and the following disclaimer in the documentation and/or
  13. * other materials provided with the distribution.
  14. *
  15. * o Neither the name of the copyright holder nor the names of its
  16. * contributors may be used to endorse or promote products derived from this
  17. * software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  23. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  26. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #include "fsl_phy.h"
  31. #include <rtthread.h>
  32. /*******************************************************************************
  33. * Definitions
  34. ******************************************************************************/
  35. /*! @brief Defines the timeout macro. */
  36. #define PHY_TIMEOUT_COUNT 0xFFFFU
  37. /*******************************************************************************
  38. * Prototypes
  39. ******************************************************************************/
  40. /*!
  41. * @brief Get the ENET instance from peripheral base address.
  42. *
  43. * @param base ENET peripheral base address.
  44. * @return ENET instance.
  45. */
  46. extern uint32_t ENET_GetInstance(ENET_Type *base);
  47. /*******************************************************************************
  48. * Variables
  49. ******************************************************************************/
  50. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  51. /*! @brief Pointers to enet clocks for each instance. */
  52. extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
  53. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  54. /*******************************************************************************
  55. * Code
  56. ******************************************************************************/
  57. status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
  58. {
  59. uint32_t bssReg;
  60. uint32_t counter = PHY_TIMEOUT_COUNT;
  61. uint32_t idReg = 0;
  62. status_t result = kStatus_Success;
  63. uint32_t instance = ENET_GetInstance(base);
  64. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  65. /* Set SMI first. */
  66. CLOCK_EnableClock(s_enetClock[instance]);
  67. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  68. ENET_SetSMI(base, srcClock_Hz, false);
  69. /* Initialization after PHY stars to work. */
  70. while ((idReg != PHY_CONTROL_ID1) && (counter != 0))
  71. {
  72. PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
  73. counter --;
  74. }
  75. if (!counter)
  76. {
  77. return kStatus_Fail;
  78. }
  79. /* Reset PHY. */
  80. counter = 6;
  81. result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
  82. if (result == kStatus_Success)
  83. {
  84. #if defined(BOARD_RT1050_FIRE)
  85. for (uint32_t i = 0x10000; i > 0; i--)
  86. {
  87. result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &bssReg);
  88. if (!(bssReg & PHY_BCTL_POWER_DOWN_MASK))
  89. {
  90. break;
  91. }
  92. }
  93. #endif
  94. #if defined(BOARD_RT1050_ATK)
  95. rt_thread_delay(RT_TICK_PER_SECOND);
  96. #endif
  97. #if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE)
  98. uint32_t data = 0;
  99. result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
  100. if ( result != kStatus_Success)
  101. {
  102. return result;
  103. }
  104. result = PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REFCLK_SELECT_MASK));
  105. if (result != kStatus_Success)
  106. {
  107. return result;
  108. }
  109. #endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */
  110. /* Set the negotiation. */
  111. result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
  112. (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
  113. PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U));
  114. if (result == kStatus_Success)
  115. {
  116. result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG,
  117. (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
  118. if (result == kStatus_Success)
  119. {
  120. /* Check auto negotiation complete. */
  121. while (counter --)
  122. {
  123. result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg);
  124. if ( result == kStatus_Success)
  125. {
  126. #if defined(BOARD_RT1050_FIRE) || defined(BOARD_RT1050_ATK)
  127. if (((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0))
  128. #else
  129. uint32_t ctlReg = 0;
  130. PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
  131. if (((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) && (ctlReg & PHY_LINK_READY_MASK))
  132. #endif
  133. {
  134. rt_kprintf("auto negotiation complete success\n");
  135. break;
  136. }
  137. else
  138. {
  139. /* Wait a moment for Phy status stable. */
  140. __ASM("nop");
  141. }
  142. }
  143. rt_kprintf("[PHY] wait autonegotiation complete...\n");
  144. rt_thread_delay(RT_TICK_PER_SECOND);
  145. if (!counter)
  146. {
  147. return kStatus_PHY_AutoNegotiateFail;
  148. }
  149. }
  150. }
  151. }
  152. }
  153. return result;
  154. }
  155. status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
  156. {
  157. uint32_t counter;
  158. /* Clear the SMI interrupt event. */
  159. ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
  160. /* Starts a SMI write command. */
  161. ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data);
  162. /* Wait for SMI complete. */
  163. for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
  164. {
  165. if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
  166. {
  167. break;
  168. }
  169. }
  170. /* Check for timeout. */
  171. if (!counter)
  172. {
  173. return kStatus_PHY_SMIVisitTimeout;
  174. }
  175. /* Clear MII interrupt event. */
  176. ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
  177. return kStatus_Success;
  178. }
  179. status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr)
  180. {
  181. assert(dataPtr);
  182. uint32_t counter;
  183. /* Clear the MII interrupt event. */
  184. ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
  185. /* Starts a SMI read command operation. */
  186. ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame);
  187. /* Wait for MII complete. */
  188. for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--)
  189. {
  190. if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)
  191. {
  192. break;
  193. }
  194. }
  195. /* Check for timeout. */
  196. if (!counter)
  197. {
  198. return kStatus_PHY_SMIVisitTimeout;
  199. }
  200. /* Get data from MII register. */
  201. *dataPtr = ENET_ReadSMIData(base);
  202. /* Clear MII interrupt event. */
  203. ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
  204. return kStatus_Success;
  205. }
  206. status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, phy_speed_t speed, bool enable)
  207. {
  208. status_t result;
  209. uint32_t data = 0;
  210. /* Set the loop mode. */
  211. if (enable)
  212. {
  213. if (mode == kPHY_LocalLoop)
  214. {
  215. if (speed == kPHY_Speed100M)
  216. {
  217. data = PHY_BCTL_SPEED_100M_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
  218. }
  219. else
  220. {
  221. data = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
  222. }
  223. return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, data);
  224. }
  225. else
  226. {
  227. /* First read the current status in control register. */
  228. result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
  229. if (result == kStatus_Success)
  230. {
  231. return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REMOTELOOP_MASK));
  232. }
  233. }
  234. }
  235. else
  236. {
  237. /* Disable the loop mode. */
  238. if (mode == kPHY_LocalLoop)
  239. {
  240. /* First read the current status in control register. */
  241. result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data);
  242. if (result == kStatus_Success)
  243. {
  244. data &= ~PHY_BCTL_LOOP_MASK;
  245. return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data | PHY_BCTL_RESTART_AUTONEG_MASK));
  246. }
  247. }
  248. else
  249. {
  250. /* First read the current status in control one register. */
  251. result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data);
  252. if (result == kStatus_Success)
  253. {
  254. return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data & ~PHY_CTL2_REMOTELOOP_MASK));
  255. }
  256. }
  257. }
  258. return result;
  259. }
  260. status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status)
  261. {
  262. assert(status);
  263. status_t result = kStatus_Success;
  264. uint32_t data;
  265. /* Read the basic status register. */
  266. result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &data);
  267. if (result == kStatus_Success)
  268. {
  269. if (!(PHY_BSTATUS_LINKSTATUS_MASK & data))
  270. {
  271. /* link down. */
  272. *status = false;
  273. }
  274. else
  275. {
  276. /* link up. */
  277. *status = true;
  278. }
  279. }
  280. return result;
  281. }
  282. status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex)
  283. {
  284. assert(duplex);
  285. status_t result = kStatus_Success;
  286. uint32_t data, ctlReg;
  287. /* Read the control two register. */
  288. #if defined(BOARD_RT1050_FIRE) || defined(BOARD_RT1050_ATK)
  289. result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &ctlReg);
  290. #endif
  291. #if defined(BOARD_RT1050_EVK)
  292. result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg);
  293. #endif
  294. if (result == kStatus_Success)
  295. {
  296. data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
  297. if ((PHY_CTL1_10FULLDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
  298. {
  299. /* Full duplex. */
  300. *duplex = kPHY_FullDuplex;
  301. }
  302. else
  303. {
  304. /* Half duplex. */
  305. *duplex = kPHY_HalfDuplex;
  306. }
  307. data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK;
  308. if ((PHY_CTL1_100HALFDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data))
  309. {
  310. /* 100M speed. */
  311. *speed = kPHY_Speed100M;
  312. }
  313. else
  314. { /* 10M speed. */
  315. *speed = kPHY_Speed10M;
  316. }
  317. }
  318. return result;
  319. }