mdio_mt7620.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /* This program is free software; you can redistribute it and/or modify
  2. * it under the terms of the GNU General Public License as published by
  3. * the Free Software Foundation; version 2 of the License
  4. *
  5. * This program is distributed in the hope that it will be useful,
  6. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. * GNU General Public License for more details.
  9. *
  10. * Copyright (C) 2009-2015 John Crispin <[email protected]>
  11. * Copyright (C) 2009-2015 Felix Fietkau <[email protected]>
  12. * Copyright (C) 2013-2015 Michael Lee <[email protected]>
  13. */
  14. #include <linux/module.h>
  15. #include <linux/kernel.h>
  16. #include <linux/types.h>
  17. #include "mtk_eth_soc.h"
  18. #include "gsw_mt7620.h"
  19. #include "mdio.h"
  20. static int mt7620_mii_busy_wait(struct mt7620_gsw *gsw)
  21. {
  22. unsigned long t_start = jiffies;
  23. while (1) {
  24. if (!(mtk_switch_r32(gsw, MT7620A_GSW_REG_PIAC) & GSW_MDIO_ACCESS))
  25. return 0;
  26. if (time_after(jiffies, t_start + GSW_REG_PHY_TIMEOUT))
  27. break;
  28. }
  29. dev_err(gsw->dev, "mdio: MDIO timeout\n");
  30. return -1;
  31. }
  32. u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr,
  33. u32 phy_register, u32 write_data)
  34. {
  35. if (mt7620_mii_busy_wait(gsw))
  36. return -1;
  37. write_data &= 0xffff;
  38. mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_WRITE |
  39. (phy_register << GSW_MDIO_REG_SHIFT) |
  40. (phy_addr << GSW_MDIO_ADDR_SHIFT) | write_data,
  41. MT7620A_GSW_REG_PIAC);
  42. if (mt7620_mii_busy_wait(gsw))
  43. return -1;
  44. return 0;
  45. }
  46. u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg)
  47. {
  48. u32 d;
  49. if (mt7620_mii_busy_wait(gsw))
  50. return 0xffff;
  51. mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_READ |
  52. (phy_reg << GSW_MDIO_REG_SHIFT) |
  53. (phy_addr << GSW_MDIO_ADDR_SHIFT),
  54. MT7620A_GSW_REG_PIAC);
  55. if (mt7620_mii_busy_wait(gsw))
  56. return 0xffff;
  57. d = mtk_switch_r32(gsw, MT7620A_GSW_REG_PIAC) & 0xffff;
  58. return d;
  59. }
  60. int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val)
  61. {
  62. struct fe_priv *priv = bus->priv;
  63. struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
  64. return _mt7620_mii_write(gsw, phy_addr, phy_reg, val);
  65. }
  66. int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
  67. {
  68. struct fe_priv *priv = bus->priv;
  69. struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
  70. return _mt7620_mii_read(gsw, phy_addr, phy_reg);
  71. }
  72. void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val)
  73. {
  74. _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
  75. _mt7620_mii_write(gsw, 0x1f, (reg >> 2) & 0xf, val & 0xffff);
  76. _mt7620_mii_write(gsw, 0x1f, 0x10, val >> 16);
  77. }
  78. u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg)
  79. {
  80. u16 high, low;
  81. _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff);
  82. low = _mt7620_mii_read(gsw, 0x1f, (reg >> 2) & 0xf);
  83. high = _mt7620_mii_read(gsw, 0x1f, 0x10);
  84. return (high << 16) | (low & 0xffff);
  85. }
  86. static unsigned char *fe_speed_str(int speed)
  87. {
  88. switch (speed) {
  89. case 2:
  90. case SPEED_1000:
  91. return "1000";
  92. case 1:
  93. case SPEED_100:
  94. return "100";
  95. case 0:
  96. case SPEED_10:
  97. return "10";
  98. }
  99. return "? ";
  100. }
  101. int mt7620_has_carrier(struct fe_priv *priv)
  102. {
  103. struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv;
  104. int i;
  105. for (i = 0; i < GSW_PORT6; i++)
  106. if (mtk_switch_r32(gsw, GSW_REG_PORT_STATUS(i)) & 0x1)
  107. return 1;
  108. return 0;
  109. }
  110. void mt7620_handle_carrier(struct fe_priv *priv)
  111. {
  112. if (!priv->phy)
  113. return;
  114. if (mt7620_has_carrier(priv))
  115. netif_carrier_on(priv->netdev);
  116. else
  117. netif_carrier_off(priv->netdev);
  118. }
  119. void mt7620_print_link_state(struct fe_priv *priv, int port, int link,
  120. int speed, int duplex)
  121. {
  122. if (link)
  123. netdev_info(priv->netdev, "port %d link up (%sMbps/%s duplex)\n",
  124. port, fe_speed_str(speed),
  125. (duplex) ? "Full" : "Half");
  126. else
  127. netdev_info(priv->netdev, "port %d link down\n", port);
  128. }
  129. void mt7620_mdio_link_adjust(struct fe_priv *priv, int port)
  130. {
  131. mt7620_print_link_state(priv, port, priv->link[port],
  132. priv->phy->speed[port],
  133. (priv->phy->duplex[port] == DUPLEX_FULL));
  134. mt7620_handle_carrier(priv);
  135. }