IxEthMii.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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. * Redistribution and use in source and binary forms, with or without
  23. * modification, are permitted provided that the following conditions
  24. * are met:
  25. * 1. Redistributions of source code must retain the above copyright
  26. * notice, this list of conditions and the following disclaimer.
  27. * 2. Redistributions in binary form must reproduce the above copyright
  28. * notice, this list of conditions and the following disclaimer in the
  29. * documentation and/or other materials provided with the distribution.
  30. * 3. Neither the name of the Intel Corporation nor the names of its contributors
  31. * may be used to endorse or promote products derived from this software
  32. * without specific prior written permission.
  33. *
  34. * @par
  35. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
  36. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  38. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  39. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  40. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  41. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  42. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  43. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  44. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  45. * SUCH DAMAGE.
  46. *
  47. * @par
  48. * -- End of Copyright Notice --
  49. */
  50. #include "IxOsal.h"
  51. #include "IxEthAcc.h"
  52. #include "IxEthMii_p.h"
  53. #ifdef __wince
  54. #include "IxOsPrintf.h"
  55. #endif
  56. /* Array to store the phy IDs of the discovered phys */
  57. PRIVATE UINT32 ixEthMiiPhyId[IXP425_ETH_ACC_MII_MAX_ADDR];
  58. /*********************************************************
  59. *
  60. * Scan for PHYs on the MII bus. This function returns
  61. * an array of booleans, one for each PHY address.
  62. * If a PHY is found at a particular address, the
  63. * corresponding entry in the array is set to true.
  64. *
  65. */
  66. PUBLIC IX_STATUS
  67. ixEthMiiPhyScan(BOOL phyPresent[], UINT32 maxPhyCount)
  68. {
  69. UINT32 i;
  70. UINT16 regval, regvalId1, regvalId2;
  71. /*Search for PHYs on the MII*/
  72. /*Search for existant phys on the MDIO bus*/
  73. if ((phyPresent == NULL) ||
  74. (maxPhyCount > IXP425_ETH_ACC_MII_MAX_ADDR))
  75. {
  76. return IX_FAIL;
  77. }
  78. /* fill the array */
  79. for(i=0;
  80. i<IXP425_ETH_ACC_MII_MAX_ADDR;
  81. i++)
  82. {
  83. phyPresent[i] = false;
  84. }
  85. /* iterate through the PHY addresses */
  86. for(i=0;
  87. maxPhyCount > 0 && i<IXP425_ETH_ACC_MII_MAX_ADDR;
  88. i++)
  89. {
  90. ixEthMiiPhyId[i] = IX_ETH_MII_INVALID_PHY_ID;
  91. if(ixEthAccMiiReadRtn(i,
  92. IX_ETH_MII_CTRL_REG,
  93. &regval) == IX_ETH_ACC_SUCCESS)
  94. {
  95. if((regval & 0xffff) != 0xffff)
  96. {
  97. maxPhyCount--;
  98. /*Need to read the register twice here to flush PHY*/
  99. ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
  100. ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
  101. ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID2_REG, &regvalId2);
  102. ixEthMiiPhyId[i] = (regvalId1 << IX_ETH_MII_REG_SHL) | regvalId2;
  103. if ((ixEthMiiPhyId[i] == IX_ETH_MII_KS8995_PHY_ID)
  104. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT971_PHY_ID)
  105. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT972_PHY_ID)
  106. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT973_PHY_ID)
  107. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT973A3_PHY_ID)
  108. || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT9785_PHY_ID)
  109. )
  110. {
  111. /* supported phy */
  112. phyPresent[i] = true;
  113. } /* end of if(ixEthMiiPhyId) */
  114. else
  115. {
  116. if (ixEthMiiPhyId[i] != IX_ETH_MII_INVALID_PHY_ID)
  117. {
  118. /* unsupported phy */
  119. ixOsalLog (IX_OSAL_LOG_LVL_ERROR,
  120. IX_OSAL_LOG_DEV_STDOUT,
  121. "ixEthMiiPhyScan : unexpected Mii PHY ID %8.8x\n",
  122. ixEthMiiPhyId[i], 2, 3, 4, 5, 6);
  123. ixEthMiiPhyId[i] = IX_ETH_MII_UNKNOWN_PHY_ID;
  124. phyPresent[i] = true;
  125. }
  126. }
  127. }
  128. }
  129. }
  130. return IX_SUCCESS;
  131. }
  132. /************************************************************
  133. *
  134. * Configure the PHY at the specified address
  135. *
  136. */
  137. PUBLIC IX_STATUS
  138. ixEthMiiPhyConfig(UINT32 phyAddr,
  139. BOOL speed100,
  140. BOOL fullDuplex,
  141. BOOL autonegotiate)
  142. {
  143. UINT16 regval=0;
  144. /* parameter check */
  145. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  146. (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
  147. {
  148. /*
  149. * set the control register
  150. */
  151. if(autonegotiate)
  152. {
  153. regval |= IX_ETH_MII_CR_AUTO_EN | IX_ETH_MII_CR_RESTART;
  154. }
  155. else
  156. {
  157. if(speed100)
  158. {
  159. regval |= IX_ETH_MII_CR_100;
  160. }
  161. if(fullDuplex)
  162. {
  163. regval |= IX_ETH_MII_CR_FDX;
  164. }
  165. } /* end of if-else() */
  166. if (ixEthAccMiiWriteRtn(phyAddr,
  167. IX_ETH_MII_CTRL_REG,
  168. regval) == IX_ETH_ACC_SUCCESS)
  169. {
  170. return IX_SUCCESS;
  171. }
  172. } /* end of if(phyAddr) */
  173. return IX_FAIL;
  174. }
  175. /******************************************************************
  176. *
  177. * Enable the PHY Loopback at the specified address
  178. */
  179. PUBLIC IX_STATUS
  180. ixEthMiiPhyLoopbackEnable (UINT32 phyAddr)
  181. {
  182. UINT16 regval ;
  183. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  184. (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
  185. {
  186. /* read/write the control register */
  187. if(ixEthAccMiiReadRtn (phyAddr,
  188. IX_ETH_MII_CTRL_REG,
  189. &regval)
  190. == IX_ETH_ACC_SUCCESS)
  191. {
  192. if(ixEthAccMiiWriteRtn (phyAddr,
  193. IX_ETH_MII_CTRL_REG,
  194. regval | IX_ETH_MII_CR_LOOPBACK)
  195. == IX_ETH_ACC_SUCCESS)
  196. {
  197. return IX_SUCCESS;
  198. }
  199. }
  200. }
  201. return IX_FAIL;
  202. }
  203. /******************************************************************
  204. *
  205. * Disable the PHY Loopback at the specified address
  206. */
  207. PUBLIC IX_STATUS
  208. ixEthMiiPhyLoopbackDisable (UINT32 phyAddr)
  209. {
  210. UINT16 regval ;
  211. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  212. (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
  213. {
  214. /* read/write the control register */
  215. if(ixEthAccMiiReadRtn (phyAddr,
  216. IX_ETH_MII_CTRL_REG,
  217. &regval)
  218. == IX_ETH_ACC_SUCCESS)
  219. {
  220. if(ixEthAccMiiWriteRtn (phyAddr,
  221. IX_ETH_MII_CTRL_REG,
  222. regval & (~IX_ETH_MII_CR_LOOPBACK))
  223. == IX_ETH_ACC_SUCCESS)
  224. {
  225. return IX_SUCCESS;
  226. }
  227. }
  228. }
  229. return IX_FAIL;
  230. }
  231. /******************************************************************
  232. *
  233. * Reset the PHY at the specified address
  234. */
  235. PUBLIC IX_STATUS
  236. ixEthMiiPhyReset(UINT32 phyAddr)
  237. {
  238. UINT32 timeout;
  239. UINT16 regval;
  240. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  241. (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
  242. {
  243. if ((ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT971_PHY_ID) ||
  244. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT972_PHY_ID) ||
  245. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT973_PHY_ID) ||
  246. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT973A3_PHY_ID) ||
  247. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT9785_PHY_ID)
  248. )
  249. {
  250. /* use the control register to reset the phy */
  251. ixEthAccMiiWriteRtn(phyAddr,
  252. IX_ETH_MII_CTRL_REG,
  253. IX_ETH_MII_CR_RESET);
  254. /* poll until the reset bit is cleared */
  255. timeout = 0;
  256. do
  257. {
  258. ixOsalSleep (IX_ETH_MII_RESET_POLL_MS);
  259. /* read the control register and check for timeout */
  260. ixEthAccMiiReadRtn(phyAddr,
  261. IX_ETH_MII_CTRL_REG,
  262. &regval);
  263. if ((regval & IX_ETH_MII_CR_RESET) == 0)
  264. {
  265. /* timeout bit is self-cleared */
  266. break;
  267. }
  268. timeout += IX_ETH_MII_RESET_POLL_MS;
  269. }
  270. while (timeout < IX_ETH_MII_RESET_DELAY_MS);
  271. /* check for timeout */
  272. if (timeout >= IX_ETH_MII_RESET_DELAY_MS)
  273. {
  274. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  275. IX_ETH_MII_CR_NORM_EN);
  276. return IX_FAIL;
  277. }
  278. return IX_SUCCESS;
  279. } /* end of if(ixEthMiiPhyId) */
  280. else if (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_KS8995_PHY_ID)
  281. {
  282. /* reset bit is reserved, just reset the control register */
  283. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  284. IX_ETH_MII_CR_NORM_EN);
  285. return IX_SUCCESS;
  286. }
  287. else
  288. {
  289. /* unknown PHY, set the control register reset bit,
  290. * wait 2 s. and clear the control register.
  291. */
  292. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  293. IX_ETH_MII_CR_RESET);
  294. ixOsalSleep (IX_ETH_MII_RESET_DELAY_MS);
  295. ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
  296. IX_ETH_MII_CR_NORM_EN);
  297. return IX_SUCCESS;
  298. } /* end of if-else(ixEthMiiPhyId) */
  299. } /* end of if(phyAddr) */
  300. return IX_FAIL;
  301. }
  302. /*****************************************************************
  303. *
  304. * Link state query functions
  305. */
  306. PUBLIC IX_STATUS
  307. ixEthMiiLinkStatus(UINT32 phyAddr,
  308. BOOL *linkUp,
  309. BOOL *speed100,
  310. BOOL *fullDuplex,
  311. BOOL *autoneg)
  312. {
  313. UINT16 ctrlRegval, statRegval, regval, regval4, regval5;
  314. /* check the parameters */
  315. if ((linkUp == NULL) ||
  316. (speed100 == NULL) ||
  317. (fullDuplex == NULL) ||
  318. (autoneg == NULL))
  319. {
  320. return IX_FAIL;
  321. }
  322. *linkUp = false;
  323. *speed100 = false;
  324. *fullDuplex = false;
  325. *autoneg = false;
  326. if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
  327. (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
  328. {
  329. if ((ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT971_PHY_ID) ||
  330. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT972_PHY_ID) ||
  331. (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT9785_PHY_ID)
  332. )
  333. {
  334. /* --------------------------------------------------*/
  335. /* Retrieve information from PHY specific register */
  336. /* --------------------------------------------------*/
  337. if (ixEthAccMiiReadRtn(phyAddr,
  338. IX_ETH_MII_STAT2_REG,
  339. &regval) != IX_ETH_ACC_SUCCESS)
  340. {
  341. return IX_FAIL;
  342. }
  343. *linkUp = ((regval & IX_ETH_MII_SR2_LINK) != 0);
  344. *speed100 = ((regval & IX_ETH_MII_SR2_100) != 0);
  345. *fullDuplex = ((regval & IX_ETH_MII_SR2_FD) != 0);
  346. *autoneg = ((regval & IX_ETH_MII_SR2_AUTO) != 0);
  347. return IX_SUCCESS;
  348. } /* end of if(ixEthMiiPhyId) */
  349. else
  350. {
  351. /* ----------------------------------------------------*/
  352. /* Retrieve information from status and ctrl registers */
  353. /* ----------------------------------------------------*/
  354. if (ixEthAccMiiReadRtn(phyAddr,
  355. IX_ETH_MII_CTRL_REG,
  356. &ctrlRegval) != IX_ETH_ACC_SUCCESS)
  357. {
  358. return IX_FAIL;
  359. }
  360. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &statRegval);
  361. *linkUp = ((statRegval & IX_ETH_MII_SR_LINK_STATUS) != 0);
  362. if (*linkUp)
  363. {
  364. *autoneg = ((ctrlRegval & IX_ETH_MII_CR_AUTO_EN) != 0) &&
  365. ((statRegval & IX_ETH_MII_SR_AUTO_SEL) != 0) &&
  366. ((statRegval & IX_ETH_MII_SR_AUTO_NEG) != 0);
  367. if (*autoneg)
  368. {
  369. /* mask the current stat values with the capabilities */
  370. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_ADS_REG, &regval4);
  371. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_PRTN_REG, &regval5);
  372. /* merge the flags from the 3 registers */
  373. regval = (statRegval & ((regval4 & regval5) << 6));
  374. /* initialise from status register values */
  375. if ((regval & IX_ETH_MII_SR_TX_FULL_DPX) != 0)
  376. {
  377. /* 100 Base X full dplx */
  378. *speed100 = true;
  379. *fullDuplex = true;
  380. return IX_SUCCESS;
  381. }
  382. if ((regval & IX_ETH_MII_SR_TX_HALF_DPX) != 0)
  383. {
  384. /* 100 Base X half dplx */
  385. *speed100 = true;
  386. return IX_SUCCESS;
  387. }
  388. if ((regval & IX_ETH_MII_SR_10T_FULL_DPX) != 0)
  389. {
  390. /* 10 mb full dplx */
  391. *fullDuplex = true;
  392. return IX_SUCCESS;
  393. }
  394. if ((regval & IX_ETH_MII_SR_10T_HALF_DPX) != 0)
  395. {
  396. /* 10 mb half dplx */
  397. return IX_SUCCESS;
  398. }
  399. } /* end of if(autoneg) */
  400. else
  401. {
  402. /* autonegotiate not complete, return setup parameters */
  403. *speed100 = ((ctrlRegval & IX_ETH_MII_CR_100) != 0);
  404. *fullDuplex = ((ctrlRegval & IX_ETH_MII_CR_FDX) != 0);
  405. }
  406. } /* end of if(linkUp) */
  407. } /* end of if-else(ixEthMiiPhyId) */
  408. } /* end of if(phyAddr) */
  409. else
  410. {
  411. return IX_FAIL;
  412. } /* end of if-else(phyAddr) */
  413. return IX_SUCCESS;
  414. }
  415. /*****************************************************************
  416. *
  417. * Link state display functions
  418. */
  419. PUBLIC IX_STATUS
  420. ixEthMiiPhyShow (UINT32 phyAddr)
  421. {
  422. BOOL linkUp, speed100, fullDuplex, autoneg;
  423. UINT16 cregval;
  424. UINT16 sregval;
  425. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &sregval);
  426. ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_CTRL_REG, &cregval);
  427. /* get link information */
  428. if (ixEthMiiLinkStatus(phyAddr,
  429. &linkUp,
  430. &speed100,
  431. &fullDuplex,
  432. &autoneg) != IX_ETH_ACC_SUCCESS)
  433. {
  434. printf("PHY Status unknown\n");
  435. return IX_FAIL;
  436. }
  437. printf("PHY ID [phyAddr]: %8.8x\n",ixEthMiiPhyId[phyAddr]);
  438. printf( " Status reg: %4.4x\n",sregval);
  439. printf( " control reg: %4.4x\n",cregval);
  440. /* display link information */
  441. printf("PHY Status:\n");
  442. printf(" Link is %s\n",
  443. (linkUp ? "Up" : "Down"));
  444. if((sregval & IX_ETH_MII_SR_REMOTE_FAULT) != 0)
  445. {
  446. printf(" Remote fault detected\n");
  447. }
  448. printf(" Auto Negotiation %s\n",
  449. (autoneg ? "Completed" : "Not Completed"));
  450. printf("PHY Configuration:\n");
  451. printf(" Speed %sMb/s\n",
  452. (speed100 ? "100" : "10"));
  453. printf(" %s Duplex\n",
  454. (fullDuplex ? "Full" : "Half"));
  455. printf(" Auto Negotiation %s\n",
  456. (autoneg ? "Enabled" : "Disabled"));
  457. return IX_SUCCESS;
  458. }