ks8721.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * (C) Copyright 2006
  3. * Author : Eric Benard (Eukrea Electromatique)
  4. * based on dm9161.c which is :
  5. * (C) Copyright 2003
  6. * Author : Hamid Ikdoumi (Atmel)
  7. *
  8. * See file CREDITS for list of people who contributed to this
  9. * project.
  10. *
  11. * This program is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU General Public License as
  13. * published by the Free Software Foundation; either version 2 of
  14. * the License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24. * MA 02111-1307 USA
  25. */
  26. #include <at91rm9200_net.h>
  27. #include <net.h>
  28. #include <ks8721.h>
  29. #ifdef CONFIG_DRIVER_ETHER
  30. #if defined(CONFIG_CMD_NET)
  31. /*
  32. * Name:
  33. * ks8721_isphyconnected
  34. * Description:
  35. * Reads the 2 PHY ID registers
  36. * Arguments:
  37. * p_mac - pointer to AT91S_EMAC struct
  38. * Return value:
  39. * 1 - if id read successfully
  40. * 0 - if error
  41. */
  42. unsigned int ks8721_isphyconnected(AT91PS_EMAC p_mac)
  43. {
  44. unsigned short id1, id2;
  45. at91rm9200_EmacEnableMDIO(p_mac);
  46. at91rm9200_EmacReadPhy(p_mac,
  47. CONFIG_PHY_ADDRESS | KS8721_PHYID1, &id1);
  48. at91rm9200_EmacReadPhy(p_mac,
  49. CONFIG_PHY_ADDRESS | KS8721_PHYID2, &id2);
  50. at91rm9200_EmacDisableMDIO(p_mac);
  51. if ((id1 == (KS8721_PHYID_OUI >> 6)) &&
  52. ((id2 >> 10) == (KS8721_PHYID_OUI & KS8721_LSB_MASK))) {
  53. if ((id2 & KS8721_MODELMASK) == KS8721BL_MODEL)
  54. printf("Micrel KS8721bL PHY detected : ");
  55. else
  56. printf("Unknown Micrel PHY detected : ");
  57. return 1;
  58. }
  59. return 0;
  60. }
  61. /*
  62. * Name:
  63. * ks8721_getlinkspeed
  64. * Description:
  65. * Link parallel detection status of MAC is checked and set in the
  66. * MAC configuration registers
  67. * Arguments:
  68. * p_mac - pointer to MAC
  69. * Return value:
  70. * 1 - if link status set succesfully
  71. * 0 - if link status not set
  72. */
  73. unsigned char ks8721_getlinkspeed(AT91PS_EMAC p_mac)
  74. {
  75. unsigned short stat1;
  76. if (!at91rm9200_EmacReadPhy(p_mac, KS8721_BMSR, &stat1))
  77. return 0;
  78. if (!(stat1 & KS8721_LINK_STATUS)) {
  79. /* link status up? */
  80. printf("Link Down !\n");
  81. return 0;
  82. }
  83. if (stat1 & KS8721_100BASE_TX_FD) {
  84. /* set Emac for 100BaseTX and Full Duplex */
  85. printf("100BT FD\n");
  86. p_mac->EMAC_CFG |= AT91C_EMAC_SPD | AT91C_EMAC_FD;
  87. return 1;
  88. }
  89. if (stat1 & KS8721_10BASE_T_FD) {
  90. /* set MII for 10BaseT and Full Duplex */
  91. printf("10BT FD\n");
  92. p_mac->EMAC_CFG = (p_mac->EMAC_CFG &
  93. ~(AT91C_EMAC_SPD | AT91C_EMAC_FD))
  94. | AT91C_EMAC_FD;
  95. return 1;
  96. }
  97. if (stat1 & KS8721_100BASE_T4_HD) {
  98. /* set MII for 100BaseTX and Half Duplex */
  99. printf("100BT HD\n");
  100. p_mac->EMAC_CFG = (p_mac->EMAC_CFG &
  101. ~(AT91C_EMAC_SPD | AT91C_EMAC_FD))
  102. | AT91C_EMAC_SPD;
  103. return 1;
  104. }
  105. if (stat1 & KS8721_10BASE_T_HD) {
  106. /* set MII for 10BaseT and Half Duplex */
  107. printf("10BT HD\n");
  108. p_mac->EMAC_CFG &= ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
  109. return 1;
  110. }
  111. return 0;
  112. }
  113. /*
  114. * Name:
  115. * ks8721_initphy
  116. * Description:
  117. * MAC starts checking its link by using parallel detection and
  118. * Autonegotiation and the same is set in the MAC configuration registers
  119. * Arguments:
  120. * p_mac - pointer to struct AT91S_EMAC
  121. * Return value:
  122. * 1 - if link status set succesfully
  123. * 0 - if link status not set
  124. */
  125. unsigned char ks8721_initphy(AT91PS_EMAC p_mac)
  126. {
  127. unsigned char ret = 1;
  128. unsigned short intvalue;
  129. at91rm9200_EmacEnableMDIO(p_mac);
  130. /* Try another time */
  131. if (!ks8721_getlinkspeed(p_mac))
  132. ret = ks8721_getlinkspeed(p_mac);
  133. /* Disable PHY Interrupts */
  134. intvalue = 0;
  135. at91rm9200_EmacWritePhy(p_mac,
  136. CONFIG_PHY_ADDRESS | KS8721_MDINTR, &intvalue);
  137. at91rm9200_EmacDisableMDIO(p_mac);
  138. return ret;
  139. }
  140. /*
  141. * Name:
  142. * ks8721_autonegotiate
  143. * Description:
  144. * MAC Autonegotiates with the partner status of same is set in the
  145. * MAC configuration registers
  146. * Arguments:
  147. * dev - pointer to struct net_device
  148. * Return value:
  149. * 1 - if link status set successfully
  150. * 0 - if link status not set
  151. */
  152. unsigned char ks8721_autonegotiate(AT91PS_EMAC p_mac, int *status)
  153. {
  154. unsigned short value;
  155. unsigned short phyanar;
  156. unsigned short phyanalpar;
  157. /* Set ks8721 control register */
  158. if (!at91rm9200_EmacReadPhy(p_mac,
  159. CONFIG_PHY_ADDRESS | KS8721_BMCR, &value))
  160. return 0;
  161. /* remove autonegotiation enable */
  162. value &= ~KS8721_AUTONEG;
  163. /* Electrically isolate PHY */
  164. value |= KS8721_ISOLATE;
  165. if (!at91rm9200_EmacWritePhy(p_mac,
  166. CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
  167. return 0;
  168. }
  169. /*
  170. * Set the Auto_negotiation Advertisement Register
  171. * MII advertising for Next page, 100BaseTxFD and HD,
  172. * 10BaseTFD and HD, IEEE 802.3
  173. */
  174. phyanar = KS8721_NP | KS8721_TX_FDX | KS8721_TX_HDX |
  175. KS8721_10_FDX | KS8721_10_HDX | KS8721_AN_IEEE_802_3;
  176. if (!at91rm9200_EmacWritePhy(p_mac,
  177. CONFIG_PHY_ADDRESS | KS8721_ANAR, &phyanar)) {
  178. return 0;
  179. }
  180. /* Read the Control Register */
  181. if (!at91rm9200_EmacReadPhy(p_mac,
  182. CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
  183. return 0;
  184. }
  185. value |= KS8721_SPEED_SELECT | KS8721_AUTONEG | KS8721_DUPLEX_MODE;
  186. if (!at91rm9200_EmacWritePhy(p_mac,
  187. CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
  188. return 0;
  189. }
  190. /* Restart Auto_negotiation */
  191. value |= KS8721_RESTART_AUTONEG;
  192. value &= ~KS8721_ISOLATE;
  193. if (!at91rm9200_EmacWritePhy(p_mac,
  194. CONFIG_PHY_ADDRESS | KS8721_BMCR, &value)) {
  195. return 0;
  196. }
  197. /* Check AutoNegotiate complete */
  198. udelay(10000);
  199. at91rm9200_EmacReadPhy(p_mac,
  200. CONFIG_PHY_ADDRESS | KS8721_BMSR, &value);
  201. if (!(value & KS8721_AUTONEG_COMP))
  202. return 0;
  203. /* Get the AutoNeg Link partner base page */
  204. if (!at91rm9200_EmacReadPhy(p_mac,
  205. CONFIG_PHY_ADDRESS | KS8721_ANLPAR, &phyanalpar)) {
  206. return 0;
  207. }
  208. if ((phyanar & KS8721_TX_FDX) && (phyanalpar & KS8721_TX_FDX)) {
  209. /* Set MII for 100BaseTX and Full Duplex */
  210. p_mac->EMAC_CFG |= AT91C_EMAC_SPD | AT91C_EMAC_FD;
  211. return 1;
  212. }
  213. if ((phyanar & KS8721_10_FDX) && (phyanalpar & KS8721_10_FDX)) {
  214. /* Set MII for 10BaseT and Full Duplex */
  215. p_mac->EMAC_CFG = (p_mac->EMAC_CFG &
  216. ~(AT91C_EMAC_SPD | AT91C_EMAC_FD))
  217. | AT91C_EMAC_FD;
  218. return 1;
  219. }
  220. return 0;
  221. }
  222. #endif /* CONFIG_CMD_NET */
  223. #endif /* CONFIG_DRIVER_ETHER */