IxEthMii.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /**
  2. * @file IxEthMii.c
  3. *
  4. * @author Intel Corporation
  5. * @date
  6. *
  7. * @brief MII control functions
  8. *
  9. * Design Notes:
  10. *
  11. *
  12. * @par
  13. * IXP400 SW Release version 2.0
  14. *
  15. * -- Copyright Notice --
  16. *
  17. * @par
  18. * Copyright 2001-2005, Intel Corporation.
  19. * All rights reserved.
  20. *
  21. * @par
  22. * SPDX-License-Identifier: BSD-3-Clause
  23. * @par
  24. * -- End of Copyright Notice --
  25. */
  26. #include "IxOsal.h"
  27. #include "IxEthAcc.h"
  28. #include "IxEthMii_p.h"
  29. #ifdef __wince
  30. #include "IxOsPrintf.h"
  31. #endif
  32. /* Array to store the phy IDs of the discovered phys */
  33. PRIVATE UINT32 ixEthMiiPhyId[IXP425_ETH_ACC_MII_MAX_ADDR];
  34. /*********************************************************
  35. *
  36. * Scan for PHYs on the MII bus. This function returns
  37. * an array of booleans, one for each PHY address.
  38. * If a PHY is found at a particular address, the
  39. * corresponding entry in the array is set to true.
  40. *
  41. */
  42. PUBLIC IX_STATUS
  43. ixEthMiiPhyScan(BOOL phyPresent[], UINT32 maxPhyCount)
  44. {
  45. UINT32 i;
  46. UINT16 regval, regvalId1, regvalId2;
  47. /*Search for PHYs on the MII*/
  48. /*Search for existant phys on the MDIO bus*/
  49. if ((phyPresent == NULL) ||
  50. (maxPhyCount > IXP425_ETH_ACC_MII_MAX_ADDR))
  51. {
  52. return IX_FAIL;
  53. }
  54. /* fill the array */
  55. for(i=0;
  56. i<IXP425_ETH_ACC_MII_MAX_ADDR;
  57. i++)
  58. {
  59. phyPresent[i] = false;
  60. }
  61. /* iterate through the PHY addresses */
  62. for(i=0;
  63. maxPhyCount > 0 && i<IXP425_ETH_ACC_MII_MAX_ADDR;
  64. i++)
  65. {
  66. ixEthMiiPhyId[i] = IX_ETH_MII_INVALID_PHY_ID;
  67. if(ixEthAccMiiReadRtn(i,
  68. IX_ETH_MII_CTRL_REG,
  69. &regval) == IX_ETH_ACC_SUCCESS)
  70. {
  71. if((regval & 0xffff) != 0xffff)
  72. {
  73. maxPhyCount--;
  74. /*Need to read the register twice here to flush PHY*/
  75. ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
  76. ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
  77. ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID2_REG, &regvalId2);
  78. ixEthMiiPhyId[i] = (regvalId1 << IX_ETH_MII_REG_SHL) | regvalId2;
  79. if ((ixEthMiiPhyId[i] == IX_ETH_MII_KS8995_PHY_ID)
  80. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT971_PHY_ID)
  81. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT972_PHY_ID)
  82. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT973_PHY_ID)
  83. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT973A3_PHY_ID)
  84. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT9785_PHY_ID)
  85. )
  86. {
  87. /* supported phy */
  88. phyPresent[i] = true;
  89. } /* end of if(ixEthMiiPhyId) */
  90. else
  91. {
  92. if (ixEthMiiPhyId[i] != IX_ETH_MII_INVALID_PHY_ID)
  93. {
  94. /* unsupported phy */
  95. ixOsalLog (IX_OSAL_LOG_LVL_ERROR,
  96. IX_OSAL_LOG_DEV_STDOUT,
  97. "ixEthMiiPhyScan : unexpected Mii PHY ID %8.8x\n",
  98. ixEthMiiPhyId[i], 2, 3, 4, 5, 6);
  99. ixEthMiiPhyId[i] = IX_ETH_MII_UNKNOWN_PHY_ID;
  100. phyPresent[i] = true;
  101. }
  102. }
  103. }
  104. }
  105. }
  106. return IX_SUCCESS;
  107. }
  108. /************************************************************
  109. *
  110. * Configure the PHY at the specified address
  111. *
  112. */
  113. PUBLIC IX_STATUS
  114. ixEthMiiPhyConfig(UINT32 phyAddr,
  115. BOOL speed100,
  116. BOOL fullDuplex,
  117. BOOL autonegotiate)
  118. {
  119. UINT16 regval=0;
  120. /* parameter check */
  121. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  122. (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
  123. {
  124. /*
  125. * set the control register
  126. */
  127. if(autonegotiate)
  128. {
  129. regval |= IX_ETH_MII_CR_AUTO_EN | IX_ETH_MII_CR_RESTART;
  130. }
  131. else
  132. {
  133. if(speed100)
  134. {
  135. regval |= IX_ETH_MII_CR_100;
  136. }
  137. if(fullDuplex)
  138. {
  139. regval |= IX_ETH_MII_CR_FDX;
  140. }
  141. } /* end of if-else() */
  142. if (ixEthAccMiiWriteRtn(phyAddr,
  143. IX_ETH_MII_CTRL_REG,
  144. regval) == IX_ETH_ACC_SUCCESS)
  145. {
  146. return IX_SUCCESS;
  147. }
  148. } /* end of if(phyAddr) */
  149. return IX_FAIL;
  150. }
  151. /******************************************************************
  152. *
  153. * Enable the PHY Loopback at the specified address
  154. */
  155. PUBLIC IX_STATUS
  156. ixEthMiiPhyLoopbackEnable (UINT32 phyAddr)
  157. {
  158. UINT16 regval ;
  159. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  160. (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
  161. {
  162. /* read/write the control register */
  163. if(ixEthAccMiiReadRtn (phyAddr,
  164. IX_ETH_MII_CTRL_REG,
  165. &regval)
  166. == IX_ETH_ACC_SUCCESS)
  167. {
  168. if(ixEthAccMiiWriteRtn (phyAddr,
  169. IX_ETH_MII_CTRL_REG,
  170. regval | IX_ETH_MII_CR_LOOPBACK)
  171. == IX_ETH_ACC_SUCCESS)
  172. {
  173. return IX_SUCCESS;
  174. }
  175. }
  176. }
  177. return IX_FAIL;
  178. }
  179. /******************************************************************
  180. *
  181. * Disable the PHY Loopback at the specified address
  182. */
  183. PUBLIC IX_STATUS
  184. ixEthMiiPhyLoopbackDisable (UINT32 phyAddr)
  185. {
  186. UINT16 regval ;
  187. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  188. (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
  189. {
  190. /* read/write the control register */
  191. if(ixEthAccMiiReadRtn (phyAddr,
  192. IX_ETH_MII_CTRL_REG,
  193. &regval)
  194. == IX_ETH_ACC_SUCCESS)
  195. {
  196. if(ixEthAccMiiWriteRtn (phyAddr,
  197. IX_ETH_MII_CTRL_REG,
  198. regval & (~IX_ETH_MII_CR_LOOPBACK))
  199. == IX_ETH_ACC_SUCCESS)
  200. {
  201. return IX_SUCCESS;
  202. }
  203. }
  204. }
  205. return IX_FAIL;
  206. }
  207. /******************************************************************
  208. *
  209. * Reset the PHY at the specified address
  210. */
  211. PUBLIC IX_STATUS
  212. ixEthMiiPhyReset(UINT32 phyAddr)
  213. {
  214. UINT32 timeout;
  215. UINT16 regval;
  216. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  217. (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
  218. {
  219. if ((ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT971_PHY_ID) ||
  220. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT972_PHY_ID) ||
  221. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT973_PHY_ID) ||
  222. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT973A3_PHY_ID) ||
  223. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT9785_PHY_ID)
  224. )
  225. {
  226. /* use the control register to reset the phy */
  227. ixEthAccMiiWriteRtn(phyAddr,
  228. IX_ETH_MII_CTRL_REG,
  229. IX_ETH_MII_CR_RESET);
  230. /* poll until the reset bit is cleared */
  231. timeout = 0;
  232. do
  233. {
  234. ixOsalSleep (IX_ETH_MII_RESET_POLL_MS);
  235. /* read the control register and check for timeout */
  236. ixEthAccMiiReadRtn(phyAddr,
  237. IX_ETH_MII_CTRL_REG,
  238. &regval);
  239. if ((regval & IX_ETH_MII_CR_RESET) == 0)
  240. {
  241. /* timeout bit is self-cleared */
  242. break;
  243. }
  244. timeout += IX_ETH_MII_RESET_POLL_MS;
  245. }
  246. while (timeout < IX_ETH_MII_RESET_DELAY_MS);
  247. /* check for timeout */
  248. if (timeout >= IX_ETH_MII_RESET_DELAY_MS)
  249. {
  250. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  251. IX_ETH_MII_CR_NORM_EN);
  252. return IX_FAIL;
  253. }
  254. return IX_SUCCESS;
  255. } /* end of if(ixEthMiiPhyId) */
  256. else if (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_KS8995_PHY_ID)
  257. {
  258. /* reset bit is reserved, just reset the control register */
  259. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  260. IX_ETH_MII_CR_NORM_EN);
  261. return IX_SUCCESS;
  262. }
  263. else
  264. {
  265. /* unknown PHY, set the control register reset bit,
  266. * wait 2 s. and clear the control register.
  267. */
  268. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  269. IX_ETH_MII_CR_RESET);
  270. ixOsalSleep (IX_ETH_MII_RESET_DELAY_MS);
  271. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  272. IX_ETH_MII_CR_NORM_EN);
  273. return IX_SUCCESS;
  274. } /* end of if-else(ixEthMiiPhyId) */
  275. } /* end of if(phyAddr) */
  276. return IX_FAIL;
  277. }
  278. /*****************************************************************
  279. *
  280. * Link state query functions
  281. */
  282. PUBLIC IX_STATUS
  283. ixEthMiiLinkStatus(UINT32 phyAddr,
  284. BOOL *linkUp,
  285. BOOL *speed100,
  286. BOOL *fullDuplex,
  287. BOOL *autoneg)
  288. {
  289. UINT16 ctrlRegval, statRegval, regval, regval4, regval5;
  290. /* check the parameters */
  291. if ((linkUp == NULL) ||
  292. (speed100 == NULL) ||
  293. (fullDuplex == NULL) ||
  294. (autoneg == NULL))
  295. {
  296. return IX_FAIL;
  297. }
  298. *linkUp = false;
  299. *speed100 = false;
  300. *fullDuplex = false;
  301. *autoneg = false;
  302. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  303. (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
  304. {
  305. if ((ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT971_PHY_ID) ||
  306. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT972_PHY_ID) ||
  307. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT9785_PHY_ID)
  308. )
  309. {
  310. /* --------------------------------------------------*/
  311. /* Retrieve information from PHY specific register */
  312. /* --------------------------------------------------*/
  313. if (ixEthAccMiiReadRtn(phyAddr,
  314. IX_ETH_MII_STAT2_REG,
  315. &regval) != IX_ETH_ACC_SUCCESS)
  316. {
  317. return IX_FAIL;
  318. }
  319. *linkUp = ((regval & IX_ETH_MII_SR2_LINK) != 0);
  320. *speed100 = ((regval & IX_ETH_MII_SR2_100) != 0);
  321. *fullDuplex = ((regval & IX_ETH_MII_SR2_FD) != 0);
  322. *autoneg = ((regval & IX_ETH_MII_SR2_AUTO) != 0);
  323. return IX_SUCCESS;
  324. } /* end of if(ixEthMiiPhyId) */
  325. else
  326. {
  327. /* ----------------------------------------------------*/
  328. /* Retrieve information from status and ctrl registers */
  329. /* ----------------------------------------------------*/
  330. if (ixEthAccMiiReadRtn(phyAddr,
  331. IX_ETH_MII_CTRL_REG,
  332. &ctrlRegval) != IX_ETH_ACC_SUCCESS)
  333. {
  334. return IX_FAIL;
  335. }
  336. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &statRegval);
  337. *linkUp = ((statRegval & IX_ETH_MII_SR_LINK_STATUS) != 0);
  338. if (*linkUp)
  339. {
  340. *autoneg = ((ctrlRegval & IX_ETH_MII_CR_AUTO_EN) != 0) &&
  341. ((statRegval & IX_ETH_MII_SR_AUTO_SEL) != 0) &&
  342. ((statRegval & IX_ETH_MII_SR_AUTO_NEG) != 0);
  343. if (*autoneg)
  344. {
  345. /* mask the current stat values with the capabilities */
  346. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_ADS_REG, &regval4);
  347. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_PRTN_REG, &regval5);
  348. /* merge the flags from the 3 registers */
  349. regval = (statRegval & ((regval4 & regval5) << 6));
  350. /* initialise from status register values */
  351. if ((regval & IX_ETH_MII_SR_TX_FULL_DPX) != 0)
  352. {
  353. /* 100 Base X full dplx */
  354. *speed100 = true;
  355. *fullDuplex = true;
  356. return IX_SUCCESS;
  357. }
  358. if ((regval & IX_ETH_MII_SR_TX_HALF_DPX) != 0)
  359. {
  360. /* 100 Base X half dplx */
  361. *speed100 = true;
  362. return IX_SUCCESS;
  363. }
  364. if ((regval & IX_ETH_MII_SR_10T_FULL_DPX) != 0)
  365. {
  366. /* 10 mb full dplx */
  367. *fullDuplex = true;
  368. return IX_SUCCESS;
  369. }
  370. if ((regval & IX_ETH_MII_SR_10T_HALF_DPX) != 0)
  371. {
  372. /* 10 mb half dplx */
  373. return IX_SUCCESS;
  374. }
  375. } /* end of if(autoneg) */
  376. else
  377. {
  378. /* autonegotiate not complete, return setup parameters */
  379. *speed100 = ((ctrlRegval & IX_ETH_MII_CR_100) != 0);
  380. *fullDuplex = ((ctrlRegval & IX_ETH_MII_CR_FDX) != 0);
  381. }
  382. } /* end of if(linkUp) */
  383. } /* end of if-else(ixEthMiiPhyId) */
  384. } /* end of if(phyAddr) */
  385. else
  386. {
  387. return IX_FAIL;
  388. } /* end of if-else(phyAddr) */
  389. return IX_SUCCESS;
  390. }
  391. /*****************************************************************
  392. *
  393. * Link state display functions
  394. */
  395. PUBLIC IX_STATUS
  396. ixEthMiiPhyShow (UINT32 phyAddr)
  397. {
  398. BOOL linkUp, speed100, fullDuplex, autoneg;
  399. UINT16 cregval;
  400. UINT16 sregval;
  401. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &sregval);
  402. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_CTRL_REG, &cregval);
  403. /* get link information */
  404. if (ixEthMiiLinkStatus(phyAddr,
  405. &linkUp,
  406. &speed100,
  407. &fullDuplex,
  408. &autoneg) != IX_ETH_ACC_SUCCESS)
  409. {
  410. printf("PHY Status unknown\n");
  411. return IX_FAIL;
  412. }
  413. printf("PHY ID [phyAddr]: %8.8x\n",ixEthMiiPhyId[phyAddr]);
  414. printf( " Status reg: %4.4x\n",sregval);
  415. printf( " control reg: %4.4x\n",cregval);
  416. /* display link information */
  417. printf("PHY Status:\n");
  418. printf(" Link is %s\n",
  419. (linkUp ? "Up" : "Down"));
  420. if((sregval & IX_ETH_MII_SR_REMOTE_FAULT) != 0)
  421. {
  422. printf(" Remote fault detected\n");
  423. }
  424. printf(" Auto Negotiation %s\n",
  425. (autoneg ? "Completed" : "Not Completed"));
  426. printf("PHY Configuration:\n");
  427. printf(" Speed %sMb/s\n",
  428. (speed100 ? "100" : "10"));
  429. printf(" %s Duplex\n",
  430. (fullDuplex ? "Full" : "Half"));
  431. printf(" Auto Negotiation %s\n",
  432. (autoneg ? "Enabled" : "Disabled"));
  433. return IX_SUCCESS;
  434. }