netcp_sgmii.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * SGMI module initialisation
  4. *
  5. * Copyright (C) 2014 Texas Instruments Incorporated
  6. * Authors: Sandeep Nair <[email protected]>
  7. * Sandeep Paulraj <[email protected]>
  8. * Wingman Kwok <[email protected]>
  9. *
  10. */
  11. #include "netcp.h"
  12. #define SGMII_SRESET_RESET BIT(0)
  13. #define SGMII_SRESET_RTRESET BIT(1)
  14. #define SGMII_REG_STATUS_LOCK BIT(4)
  15. #define SGMII_REG_STATUS_LINK BIT(0)
  16. #define SGMII_REG_STATUS_AUTONEG BIT(2)
  17. #define SGMII_REG_CONTROL_AUTONEG BIT(0)
  18. #define SGMII23_OFFSET(x) ((x - 2) * 0x100)
  19. #define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x)))
  20. /* SGMII registers */
  21. #define SGMII_SRESET_REG(x) (SGMII_OFFSET(x) + 0x004)
  22. #define SGMII_CTL_REG(x) (SGMII_OFFSET(x) + 0x010)
  23. #define SGMII_STATUS_REG(x) (SGMII_OFFSET(x) + 0x014)
  24. #define SGMII_MRADV_REG(x) (SGMII_OFFSET(x) + 0x018)
  25. static void sgmii_write_reg(void __iomem *base, int reg, u32 val)
  26. {
  27. writel(val, base + reg);
  28. }
  29. static u32 sgmii_read_reg(void __iomem *base, int reg)
  30. {
  31. return readl(base + reg);
  32. }
  33. static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val)
  34. {
  35. writel((readl(base + reg) | val), base + reg);
  36. }
  37. /* port is 0 based */
  38. int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port)
  39. {
  40. /* Soft reset */
  41. sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port),
  42. SGMII_SRESET_RESET);
  43. while ((sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) &
  44. SGMII_SRESET_RESET) != 0x0)
  45. ;
  46. return 0;
  47. }
  48. /* port is 0 based */
  49. bool netcp_sgmii_rtreset(void __iomem *sgmii_ofs, int port, bool set)
  50. {
  51. u32 reg;
  52. bool oldval;
  53. /* Initiate a soft reset */
  54. reg = sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port));
  55. oldval = (reg & SGMII_SRESET_RTRESET) != 0x0;
  56. if (set)
  57. reg |= SGMII_SRESET_RTRESET;
  58. else
  59. reg &= ~SGMII_SRESET_RTRESET;
  60. sgmii_write_reg(sgmii_ofs, SGMII_SRESET_REG(port), reg);
  61. wmb();
  62. return oldval;
  63. }
  64. int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port)
  65. {
  66. u32 status = 0, link = 0;
  67. status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
  68. if ((status & SGMII_REG_STATUS_LINK) != 0)
  69. link = 1;
  70. return link;
  71. }
  72. int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface)
  73. {
  74. unsigned int i, status, mask;
  75. u32 mr_adv_ability;
  76. u32 control;
  77. switch (interface) {
  78. case SGMII_LINK_MAC_MAC_AUTONEG:
  79. mr_adv_ability = 0x9801;
  80. control = 0x21;
  81. break;
  82. case SGMII_LINK_MAC_PHY:
  83. case SGMII_LINK_MAC_PHY_NO_MDIO:
  84. mr_adv_ability = 1;
  85. control = 1;
  86. break;
  87. case SGMII_LINK_MAC_MAC_FORCED:
  88. mr_adv_ability = 0x9801;
  89. control = 0x20;
  90. break;
  91. case SGMII_LINK_MAC_FIBER:
  92. mr_adv_ability = 0x20;
  93. control = 0x1;
  94. break;
  95. default:
  96. WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface);
  97. return -EINVAL;
  98. }
  99. sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0);
  100. /* Wait for the SerDes pll to lock */
  101. for (i = 0; i < 1000; i++) {
  102. usleep_range(1000, 2000);
  103. status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
  104. if ((status & SGMII_REG_STATUS_LOCK) != 0)
  105. break;
  106. }
  107. if ((status & SGMII_REG_STATUS_LOCK) == 0)
  108. pr_err("serdes PLL not locked\n");
  109. sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability);
  110. sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control);
  111. mask = SGMII_REG_STATUS_LINK;
  112. if (control & SGMII_REG_CONTROL_AUTONEG)
  113. mask |= SGMII_REG_STATUS_AUTONEG;
  114. for (i = 0; i < 1000; i++) {
  115. usleep_range(200, 500);
  116. status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
  117. if ((status & mask) == mask)
  118. break;
  119. }
  120. return 0;
  121. }