vsc8211.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * This file is part of the Chelsio T3 Ethernet driver.
  3. *
  4. * Copyright (C) 2005-2006 Chelsio Communications. All rights reserved.
  5. *
  6. * This program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8. * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
  9. * release for licensing terms and conditions.
  10. */
  11. #include "common.h"
  12. /* VSC8211 PHY specific registers. */
  13. enum {
  14. VSC8211_INTR_ENABLE = 25,
  15. VSC8211_INTR_STATUS = 26,
  16. VSC8211_AUX_CTRL_STAT = 28,
  17. };
  18. enum {
  19. VSC_INTR_RX_ERR = 1 << 0,
  20. VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
  21. VSC_INTR_CABLE = 1 << 2, /* cable impairment */
  22. VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
  23. VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
  24. VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
  25. VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
  26. VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
  27. VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
  28. VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
  29. VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
  30. VSC_INTR_LINK_CHG = 1 << 13, /* link change */
  31. VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
  32. };
  33. #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
  34. VSC_INTR_NEG_DONE)
  35. #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
  36. VSC_INTR_ENABLE)
  37. /* PHY specific auxiliary control & status register fields */
  38. #define S_ACSR_ACTIPHY_TMR 0
  39. #define M_ACSR_ACTIPHY_TMR 0x3
  40. #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
  41. #define S_ACSR_SPEED 3
  42. #define M_ACSR_SPEED 0x3
  43. #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
  44. #define S_ACSR_DUPLEX 5
  45. #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
  46. #define S_ACSR_ACTIPHY 6
  47. #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
  48. /*
  49. * Reset the PHY. This PHY completes reset immediately so we never wait.
  50. */
  51. static int vsc8211_reset(struct cphy *cphy, int wait)
  52. {
  53. return t3_phy_reset(cphy, 0, 0);
  54. }
  55. static int vsc8211_intr_enable(struct cphy *cphy)
  56. {
  57. return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
  58. }
  59. static int vsc8211_intr_disable(struct cphy *cphy)
  60. {
  61. return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
  62. }
  63. static int vsc8211_intr_clear(struct cphy *cphy)
  64. {
  65. u32 val;
  66. /* Clear PHY interrupts by reading the register. */
  67. return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
  68. }
  69. static int vsc8211_autoneg_enable(struct cphy *cphy)
  70. {
  71. return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
  72. BMCR_ANENABLE | BMCR_ANRESTART);
  73. }
  74. static int vsc8211_autoneg_restart(struct cphy *cphy)
  75. {
  76. return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
  77. BMCR_ANRESTART);
  78. }
  79. static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
  80. int *speed, int *duplex, int *fc)
  81. {
  82. unsigned int bmcr, status, lpa, adv;
  83. int err, sp = -1, dplx = -1, pause = 0;
  84. err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
  85. if (!err)
  86. err = mdio_read(cphy, 0, MII_BMSR, &status);
  87. if (err)
  88. return err;
  89. if (link_ok) {
  90. /*
  91. * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
  92. * once more to get the current link state.
  93. */
  94. if (!(status & BMSR_LSTATUS))
  95. err = mdio_read(cphy, 0, MII_BMSR, &status);
  96. if (err)
  97. return err;
  98. *link_ok = (status & BMSR_LSTATUS) != 0;
  99. }
  100. if (!(bmcr & BMCR_ANENABLE)) {
  101. dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
  102. if (bmcr & BMCR_SPEED1000)
  103. sp = SPEED_1000;
  104. else if (bmcr & BMCR_SPEED100)
  105. sp = SPEED_100;
  106. else
  107. sp = SPEED_10;
  108. } else if (status & BMSR_ANEGCOMPLETE) {
  109. err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
  110. if (err)
  111. return err;
  112. dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
  113. sp = G_ACSR_SPEED(status);
  114. if (sp == 0)
  115. sp = SPEED_10;
  116. else if (sp == 1)
  117. sp = SPEED_100;
  118. else
  119. sp = SPEED_1000;
  120. if (fc && dplx == DUPLEX_FULL) {
  121. err = mdio_read(cphy, 0, MII_LPA, &lpa);
  122. if (!err)
  123. err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
  124. if (err)
  125. return err;
  126. if (lpa & adv & ADVERTISE_PAUSE_CAP)
  127. pause = PAUSE_RX | PAUSE_TX;
  128. else if ((lpa & ADVERTISE_PAUSE_CAP) &&
  129. (lpa & ADVERTISE_PAUSE_ASYM) &&
  130. (adv & ADVERTISE_PAUSE_ASYM))
  131. pause = PAUSE_TX;
  132. else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
  133. (adv & ADVERTISE_PAUSE_CAP))
  134. pause = PAUSE_RX;
  135. }
  136. }
  137. if (speed)
  138. *speed = sp;
  139. if (duplex)
  140. *duplex = dplx;
  141. if (fc)
  142. *fc = pause;
  143. return 0;
  144. }
  145. static int vsc8211_power_down(struct cphy *cphy, int enable)
  146. {
  147. return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
  148. enable ? BMCR_PDOWN : 0);
  149. }
  150. static int vsc8211_intr_handler(struct cphy *cphy)
  151. {
  152. unsigned int cause;
  153. int err, cphy_cause = 0;
  154. err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
  155. if (err)
  156. return err;
  157. cause &= INTR_MASK;
  158. if (cause & CFG_CHG_INTR_MASK)
  159. cphy_cause |= cphy_cause_link_change;
  160. if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
  161. cphy_cause |= cphy_cause_fifo_error;
  162. return cphy_cause;
  163. }
  164. static struct cphy_ops vsc8211_ops = {
  165. .reset = vsc8211_reset,
  166. .intr_enable = vsc8211_intr_enable,
  167. .intr_disable = vsc8211_intr_disable,
  168. .intr_clear = vsc8211_intr_clear,
  169. .intr_handler = vsc8211_intr_handler,
  170. .autoneg_enable = vsc8211_autoneg_enable,
  171. .autoneg_restart = vsc8211_autoneg_restart,
  172. .advertise = t3_phy_advertise,
  173. .set_speed_duplex = t3_set_phy_speed_duplex,
  174. .get_link_status = vsc8211_get_link_status,
  175. .power_down = vsc8211_power_down,
  176. };
  177. void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
  178. int phy_addr, const struct mdio_ops *mdio_ops)
  179. {
  180. cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
  181. }