pcs-altera-tse.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2022 Bootlin
  4. *
  5. * Maxime Chevallier <maxime.chevallier@bootlin.com>
  6. */
  7. #include <linux/netdevice.h>
  8. #include <linux/phy.h>
  9. #include <linux/phylink.h>
  10. #include <linux/pcs-altera-tse.h>
  11. /* SGMII PCS register addresses
  12. */
  13. #define SGMII_PCS_SCRATCH 0x10
  14. #define SGMII_PCS_REV 0x11
  15. #define SGMII_PCS_LINK_TIMER_0 0x12
  16. #define SGMII_PCS_LINK_TIMER_REG(x) (0x12 + (x))
  17. #define SGMII_PCS_LINK_TIMER_1 0x13
  18. #define SGMII_PCS_IF_MODE 0x14
  19. #define PCS_IF_MODE_SGMII_ENA BIT(0)
  20. #define PCS_IF_MODE_USE_SGMII_AN BIT(1)
  21. #define PCS_IF_MODE_SGMI_SPEED_MASK GENMASK(3, 2)
  22. #define PCS_IF_MODE_SGMI_SPEED_10 (0 << 2)
  23. #define PCS_IF_MODE_SGMI_SPEED_100 (1 << 2)
  24. #define PCS_IF_MODE_SGMI_SPEED_1000 (2 << 2)
  25. #define PCS_IF_MODE_SGMI_HALF_DUPLEX BIT(4)
  26. #define PCS_IF_MODE_SGMI_PHY_AN BIT(5)
  27. #define SGMII_PCS_DIS_READ_TO 0x15
  28. #define SGMII_PCS_READ_TO 0x16
  29. #define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */
  30. struct altera_tse_pcs {
  31. struct phylink_pcs pcs;
  32. void __iomem *base;
  33. int reg_width;
  34. };
  35. static struct altera_tse_pcs *phylink_pcs_to_tse_pcs(struct phylink_pcs *pcs)
  36. {
  37. return container_of(pcs, struct altera_tse_pcs, pcs);
  38. }
  39. static u16 tse_pcs_read(struct altera_tse_pcs *tse_pcs, int regnum)
  40. {
  41. if (tse_pcs->reg_width == 4)
  42. return readl(tse_pcs->base + regnum * 4);
  43. else
  44. return readw(tse_pcs->base + regnum * 2);
  45. }
  46. static void tse_pcs_write(struct altera_tse_pcs *tse_pcs, int regnum,
  47. u16 value)
  48. {
  49. if (tse_pcs->reg_width == 4)
  50. writel(value, tse_pcs->base + regnum * 4);
  51. else
  52. writew(value, tse_pcs->base + regnum * 2);
  53. }
  54. static int tse_pcs_reset(struct altera_tse_pcs *tse_pcs)
  55. {
  56. int i = 0;
  57. u16 bmcr;
  58. /* Reset PCS block */
  59. bmcr = tse_pcs_read(tse_pcs, MII_BMCR);
  60. bmcr |= BMCR_RESET;
  61. tse_pcs_write(tse_pcs, MII_BMCR, bmcr);
  62. for (i = 0; i < SGMII_PCS_SW_RESET_TIMEOUT; i++) {
  63. if (!(tse_pcs_read(tse_pcs, MII_BMCR) & BMCR_RESET))
  64. return 0;
  65. udelay(1);
  66. }
  67. return -ETIMEDOUT;
  68. }
  69. static int alt_tse_pcs_validate(struct phylink_pcs *pcs,
  70. unsigned long *supported,
  71. const struct phylink_link_state *state)
  72. {
  73. if (state->interface == PHY_INTERFACE_MODE_SGMII ||
  74. state->interface == PHY_INTERFACE_MODE_1000BASEX)
  75. return 1;
  76. return -EINVAL;
  77. }
  78. static int alt_tse_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
  79. phy_interface_t interface,
  80. const unsigned long *advertising,
  81. bool permit_pause_to_mac)
  82. {
  83. struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
  84. u32 ctrl, if_mode;
  85. ctrl = tse_pcs_read(tse_pcs, MII_BMCR);
  86. if_mode = tse_pcs_read(tse_pcs, SGMII_PCS_IF_MODE);
  87. /* Set link timer to 1.6ms, as per the MegaCore Function User Guide */
  88. tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_0, 0x0D40);
  89. tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_1, 0x03);
  90. if (interface == PHY_INTERFACE_MODE_SGMII) {
  91. if_mode |= PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA;
  92. } else if (interface == PHY_INTERFACE_MODE_1000BASEX) {
  93. if_mode &= ~(PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA);
  94. if_mode |= PCS_IF_MODE_SGMI_SPEED_1000;
  95. }
  96. ctrl |= (BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE);
  97. tse_pcs_write(tse_pcs, MII_BMCR, ctrl);
  98. tse_pcs_write(tse_pcs, SGMII_PCS_IF_MODE, if_mode);
  99. return tse_pcs_reset(tse_pcs);
  100. }
  101. static void alt_tse_pcs_get_state(struct phylink_pcs *pcs,
  102. struct phylink_link_state *state)
  103. {
  104. struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
  105. u16 bmsr, lpa;
  106. bmsr = tse_pcs_read(tse_pcs, MII_BMSR);
  107. lpa = tse_pcs_read(tse_pcs, MII_LPA);
  108. phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
  109. }
  110. static void alt_tse_pcs_an_restart(struct phylink_pcs *pcs)
  111. {
  112. struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
  113. u16 bmcr;
  114. bmcr = tse_pcs_read(tse_pcs, MII_BMCR);
  115. bmcr |= BMCR_ANRESTART;
  116. tse_pcs_write(tse_pcs, MII_BMCR, bmcr);
  117. /* This PCS seems to require a soft reset to re-sync the AN logic */
  118. tse_pcs_reset(tse_pcs);
  119. }
  120. static const struct phylink_pcs_ops alt_tse_pcs_ops = {
  121. .pcs_validate = alt_tse_pcs_validate,
  122. .pcs_get_state = alt_tse_pcs_get_state,
  123. .pcs_config = alt_tse_pcs_config,
  124. .pcs_an_restart = alt_tse_pcs_an_restart,
  125. };
  126. struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev,
  127. void __iomem *pcs_base, int reg_width)
  128. {
  129. struct altera_tse_pcs *tse_pcs;
  130. if (reg_width != 4 && reg_width != 2)
  131. return ERR_PTR(-EINVAL);
  132. tse_pcs = devm_kzalloc(&ndev->dev, sizeof(*tse_pcs), GFP_KERNEL);
  133. if (!tse_pcs)
  134. return ERR_PTR(-ENOMEM);
  135. tse_pcs->pcs.ops = &alt_tse_pcs_ops;
  136. tse_pcs->base = pcs_base;
  137. tse_pcs->reg_width = reg_width;
  138. return &tse_pcs->pcs;
  139. }
  140. EXPORT_SYMBOL_GPL(alt_tse_pcs_create);
  141. MODULE_LICENSE("GPL");
  142. MODULE_DESCRIPTION("Altera TSE PCS driver");
  143. MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");