mv88e1xxx.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */
  3. #include "common.h"
  4. #include "mv88e1xxx.h"
  5. #include "cphy.h"
  6. #include "elmer0.h"
  7. /* MV88E1XXX MDI crossover register values */
  8. #define CROSSOVER_MDI 0
  9. #define CROSSOVER_MDIX 1
  10. #define CROSSOVER_AUTO 3
  11. #define INTR_ENABLE_MASK 0x6CA0
  12. /*
  13. * Set the bits given by 'bitval' in PHY register 'reg'.
  14. */
  15. static void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval)
  16. {
  17. u32 val;
  18. (void) simple_mdio_read(cphy, reg, &val);
  19. (void) simple_mdio_write(cphy, reg, val | bitval);
  20. }
  21. /*
  22. * Clear the bits given by 'bitval' in PHY register 'reg'.
  23. */
  24. static void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval)
  25. {
  26. u32 val;
  27. (void) simple_mdio_read(cphy, reg, &val);
  28. (void) simple_mdio_write(cphy, reg, val & ~bitval);
  29. }
  30. /*
  31. * NAME: phy_reset
  32. *
  33. * DESC: Reset the given PHY's port. NOTE: This is not a global
  34. * chip reset.
  35. *
  36. * PARAMS: cphy - Pointer to PHY instance data.
  37. *
  38. * RETURN: 0 - Successful reset.
  39. * -1 - Timeout.
  40. */
  41. static int mv88e1xxx_reset(struct cphy *cphy, int wait)
  42. {
  43. u32 ctl;
  44. int time_out = 1000;
  45. mdio_set_bit(cphy, MII_BMCR, BMCR_RESET);
  46. do {
  47. (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
  48. ctl &= BMCR_RESET;
  49. if (ctl)
  50. udelay(1);
  51. } while (ctl && --time_out);
  52. return ctl ? -1 : 0;
  53. }
  54. static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
  55. {
  56. /* Enable PHY interrupts. */
  57. (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER,
  58. INTR_ENABLE_MASK);
  59. /* Enable Marvell interrupts through Elmer0. */
  60. if (t1_is_asic(cphy->adapter)) {
  61. u32 elmer;
  62. t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
  63. elmer |= ELMER0_GP_BIT1;
  64. if (is_T2(cphy->adapter))
  65. elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
  66. t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
  67. }
  68. return 0;
  69. }
  70. static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
  71. {
  72. /* Disable all phy interrupts. */
  73. (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0);
  74. /* Disable Marvell interrupts through Elmer0. */
  75. if (t1_is_asic(cphy->adapter)) {
  76. u32 elmer;
  77. t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
  78. elmer &= ~ELMER0_GP_BIT1;
  79. if (is_T2(cphy->adapter))
  80. elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
  81. t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
  82. }
  83. return 0;
  84. }
  85. static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
  86. {
  87. u32 elmer;
  88. /* Clear PHY interrupts by reading the register. */
  89. (void) simple_mdio_read(cphy,
  90. MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer);
  91. /* Clear Marvell interrupts through Elmer0. */
  92. if (t1_is_asic(cphy->adapter)) {
  93. t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
  94. elmer |= ELMER0_GP_BIT1;
  95. if (is_T2(cphy->adapter))
  96. elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
  97. t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
  98. }
  99. return 0;
  100. }
  101. /*
  102. * Set the PHY speed and duplex. This also disables auto-negotiation, except
  103. * for 1Gb/s, where auto-negotiation is mandatory.
  104. */
  105. static int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex)
  106. {
  107. u32 ctl;
  108. (void) simple_mdio_read(phy, MII_BMCR, &ctl);
  109. if (speed >= 0) {
  110. ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
  111. if (speed == SPEED_100)
  112. ctl |= BMCR_SPEED100;
  113. else if (speed == SPEED_1000)
  114. ctl |= BMCR_SPEED1000;
  115. }
  116. if (duplex >= 0) {
  117. ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
  118. if (duplex == DUPLEX_FULL)
  119. ctl |= BMCR_FULLDPLX;
  120. }
  121. if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */
  122. ctl |= BMCR_ANENABLE;
  123. (void) simple_mdio_write(phy, MII_BMCR, ctl);
  124. return 0;
  125. }
  126. static int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover)
  127. {
  128. u32 data32;
  129. (void) simple_mdio_read(cphy,
  130. MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32);
  131. data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE);
  132. data32 |= V_PSCR_MDI_XOVER_MODE(crossover);
  133. (void) simple_mdio_write(cphy,
  134. MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32);
  135. return 0;
  136. }
  137. static int mv88e1xxx_autoneg_enable(struct cphy *cphy)
  138. {
  139. u32 ctl;
  140. (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO);
  141. (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
  142. /* restart autoneg for change to take effect */
  143. ctl |= BMCR_ANENABLE | BMCR_ANRESTART;
  144. (void) simple_mdio_write(cphy, MII_BMCR, ctl);
  145. return 0;
  146. }
  147. static int mv88e1xxx_autoneg_disable(struct cphy *cphy)
  148. {
  149. u32 ctl;
  150. /*
  151. * Crossover *must* be set to manual in order to disable auto-neg.
  152. * The Alaska FAQs document highlights this point.
  153. */
  154. (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI);
  155. /*
  156. * Must include autoneg reset when disabling auto-neg. This
  157. * is described in the Alaska FAQ document.
  158. */
  159. (void) simple_mdio_read(cphy, MII_BMCR, &ctl);
  160. ctl &= ~BMCR_ANENABLE;
  161. (void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART);
  162. return 0;
  163. }
  164. static int mv88e1xxx_autoneg_restart(struct cphy *cphy)
  165. {
  166. mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART);
  167. return 0;
  168. }
  169. static int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map)
  170. {
  171. u32 val = 0;
  172. if (advertise_map &
  173. (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
  174. (void) simple_mdio_read(phy, MII_GBCR, &val);
  175. val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL);
  176. if (advertise_map & ADVERTISED_1000baseT_Half)
  177. val |= GBCR_ADV_1000HALF;
  178. if (advertise_map & ADVERTISED_1000baseT_Full)
  179. val |= GBCR_ADV_1000FULL;
  180. }
  181. (void) simple_mdio_write(phy, MII_GBCR, val);
  182. val = 1;
  183. if (advertise_map & ADVERTISED_10baseT_Half)
  184. val |= ADVERTISE_10HALF;
  185. if (advertise_map & ADVERTISED_10baseT_Full)
  186. val |= ADVERTISE_10FULL;
  187. if (advertise_map & ADVERTISED_100baseT_Half)
  188. val |= ADVERTISE_100HALF;
  189. if (advertise_map & ADVERTISED_100baseT_Full)
  190. val |= ADVERTISE_100FULL;
  191. if (advertise_map & ADVERTISED_PAUSE)
  192. val |= ADVERTISE_PAUSE;
  193. if (advertise_map & ADVERTISED_ASYM_PAUSE)
  194. val |= ADVERTISE_PAUSE_ASYM;
  195. (void) simple_mdio_write(phy, MII_ADVERTISE, val);
  196. return 0;
  197. }
  198. static int mv88e1xxx_set_loopback(struct cphy *cphy, int on)
  199. {
  200. if (on)
  201. mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
  202. else
  203. mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK);
  204. return 0;
  205. }
  206. static int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok,
  207. int *speed, int *duplex, int *fc)
  208. {
  209. u32 status;
  210. int sp = -1, dplx = -1, pause = 0;
  211. (void) simple_mdio_read(cphy,
  212. MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
  213. if ((status & V_PSSR_STATUS_RESOLVED) != 0) {
  214. if (status & V_PSSR_RX_PAUSE)
  215. pause |= PAUSE_RX;
  216. if (status & V_PSSR_TX_PAUSE)
  217. pause |= PAUSE_TX;
  218. dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
  219. sp = G_PSSR_SPEED(status);
  220. if (sp == 0)
  221. sp = SPEED_10;
  222. else if (sp == 1)
  223. sp = SPEED_100;
  224. else
  225. sp = SPEED_1000;
  226. }
  227. if (link_ok)
  228. *link_ok = (status & V_PSSR_LINK) != 0;
  229. if (speed)
  230. *speed = sp;
  231. if (duplex)
  232. *duplex = dplx;
  233. if (fc)
  234. *fc = pause;
  235. return 0;
  236. }
  237. static int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable)
  238. {
  239. u32 val;
  240. (void) simple_mdio_read(cphy,
  241. MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val);
  242. /*
  243. * Set the downshift counter to 2 so we try to establish Gb link
  244. * twice before downshifting.
  245. */
  246. val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT));
  247. if (downshift_enable)
  248. val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2);
  249. (void) simple_mdio_write(cphy,
  250. MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val);
  251. return 0;
  252. }
  253. static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
  254. {
  255. int cphy_cause = 0;
  256. u32 status;
  257. /*
  258. * Loop until cause reads zero. Need to handle bouncing interrupts.
  259. */
  260. while (1) {
  261. u32 cause;
  262. (void) simple_mdio_read(cphy,
  263. MV88E1XXX_INTERRUPT_STATUS_REGISTER,
  264. &cause);
  265. cause &= INTR_ENABLE_MASK;
  266. if (!cause)
  267. break;
  268. if (cause & MV88E1XXX_INTR_LINK_CHNG) {
  269. (void) simple_mdio_read(cphy,
  270. MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
  271. if (status & MV88E1XXX_INTR_LINK_CHNG)
  272. cphy->state |= PHY_LINK_UP;
  273. else {
  274. cphy->state &= ~PHY_LINK_UP;
  275. if (cphy->state & PHY_AUTONEG_EN)
  276. cphy->state &= ~PHY_AUTONEG_RDY;
  277. cphy_cause |= cphy_cause_link_change;
  278. }
  279. }
  280. if (cause & MV88E1XXX_INTR_AUTONEG_DONE)
  281. cphy->state |= PHY_AUTONEG_RDY;
  282. if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) ==
  283. (PHY_LINK_UP | PHY_AUTONEG_RDY))
  284. cphy_cause |= cphy_cause_link_change;
  285. }
  286. return cphy_cause;
  287. }
  288. static void mv88e1xxx_destroy(struct cphy *cphy)
  289. {
  290. kfree(cphy);
  291. }
  292. static const struct cphy_ops mv88e1xxx_ops = {
  293. .destroy = mv88e1xxx_destroy,
  294. .reset = mv88e1xxx_reset,
  295. .interrupt_enable = mv88e1xxx_interrupt_enable,
  296. .interrupt_disable = mv88e1xxx_interrupt_disable,
  297. .interrupt_clear = mv88e1xxx_interrupt_clear,
  298. .interrupt_handler = mv88e1xxx_interrupt_handler,
  299. .autoneg_enable = mv88e1xxx_autoneg_enable,
  300. .autoneg_disable = mv88e1xxx_autoneg_disable,
  301. .autoneg_restart = mv88e1xxx_autoneg_restart,
  302. .advertise = mv88e1xxx_advertise,
  303. .set_loopback = mv88e1xxx_set_loopback,
  304. .set_speed_duplex = mv88e1xxx_set_speed_duplex,
  305. .get_link_status = mv88e1xxx_get_link_status,
  306. };
  307. static struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr,
  308. const struct mdio_ops *mdio_ops)
  309. {
  310. struct adapter *adapter = netdev_priv(dev);
  311. struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
  312. if (!cphy)
  313. return NULL;
  314. cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops);
  315. /* Configure particular PHY's to run in a different mode. */
  316. if ((board_info(adapter)->caps & SUPPORTED_TP) &&
  317. board_info(adapter)->chip_phy == CHBT_PHY_88E1111) {
  318. /*
  319. * Configure the PHY transmitter as class A to reduce EMI.
  320. */
  321. (void) simple_mdio_write(cphy,
  322. MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB);
  323. (void) simple_mdio_write(cphy,
  324. MV88E1XXX_EXTENDED_REGISTER, 0x8004);
  325. }
  326. (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */
  327. /* LED */
  328. if (is_T2(adapter)) {
  329. (void) simple_mdio_write(cphy,
  330. MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
  331. }
  332. return cphy;
  333. }
  334. static int mv88e1xxx_phy_reset(adapter_t* adapter)
  335. {
  336. return 0;
  337. }
  338. const struct gphy t1_mv88e1xxx_ops = {
  339. .create = mv88e1xxx_phy_create,
  340. .reset = mv88e1xxx_phy_reset
  341. };