swphy.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Software PHY emulation
  4. *
  5. * Code taken from fixed_phy.c by Russell King <rmk+kernel@arm.linux.org.uk>
  6. *
  7. * Author: Vitaly Bordug <vbordug@ru.mvista.com>
  8. * Anton Vorontsov <avorontsov@ru.mvista.com>
  9. *
  10. * Copyright (c) 2006-2007 MontaVista Software, Inc.
  11. */
  12. #include <linux/export.h>
  13. #include <linux/mii.h>
  14. #include <linux/phy.h>
  15. #include <linux/phy_fixed.h>
  16. #include "swphy.h"
  17. #define MII_REGS_NUM 29
  18. struct swmii_regs {
  19. u16 bmsr;
  20. u16 lpa;
  21. u16 lpagb;
  22. u16 estat;
  23. };
  24. enum {
  25. SWMII_SPEED_10 = 0,
  26. SWMII_SPEED_100,
  27. SWMII_SPEED_1000,
  28. SWMII_DUPLEX_HALF = 0,
  29. SWMII_DUPLEX_FULL,
  30. };
  31. /*
  32. * These two tables get bitwise-anded together to produce the final result.
  33. * This means the speed table must contain both duplex settings, and the
  34. * duplex table must contain all speed settings.
  35. */
  36. static const struct swmii_regs speed[] = {
  37. [SWMII_SPEED_10] = {
  38. .lpa = LPA_10FULL | LPA_10HALF,
  39. },
  40. [SWMII_SPEED_100] = {
  41. .bmsr = BMSR_100FULL | BMSR_100HALF,
  42. .lpa = LPA_100FULL | LPA_100HALF,
  43. },
  44. [SWMII_SPEED_1000] = {
  45. .bmsr = BMSR_ESTATEN,
  46. .lpagb = LPA_1000FULL | LPA_1000HALF,
  47. .estat = ESTATUS_1000_TFULL | ESTATUS_1000_THALF,
  48. },
  49. };
  50. static const struct swmii_regs duplex[] = {
  51. [SWMII_DUPLEX_HALF] = {
  52. .bmsr = BMSR_ESTATEN | BMSR_100HALF,
  53. .lpa = LPA_10HALF | LPA_100HALF,
  54. .lpagb = LPA_1000HALF,
  55. .estat = ESTATUS_1000_THALF,
  56. },
  57. [SWMII_DUPLEX_FULL] = {
  58. .bmsr = BMSR_ESTATEN | BMSR_100FULL,
  59. .lpa = LPA_10FULL | LPA_100FULL,
  60. .lpagb = LPA_1000FULL,
  61. .estat = ESTATUS_1000_TFULL,
  62. },
  63. };
  64. static int swphy_decode_speed(int speed)
  65. {
  66. switch (speed) {
  67. case 1000:
  68. return SWMII_SPEED_1000;
  69. case 100:
  70. return SWMII_SPEED_100;
  71. case 10:
  72. return SWMII_SPEED_10;
  73. default:
  74. return -EINVAL;
  75. }
  76. }
  77. /**
  78. * swphy_validate_state - validate the software phy status
  79. * @state: software phy status
  80. *
  81. * This checks that we can represent the state stored in @state can be
  82. * represented in the emulated MII registers. Returns 0 if it can,
  83. * otherwise returns -EINVAL.
  84. */
  85. int swphy_validate_state(const struct fixed_phy_status *state)
  86. {
  87. int err;
  88. if (state->link) {
  89. err = swphy_decode_speed(state->speed);
  90. if (err < 0) {
  91. pr_warn("swphy: unknown speed\n");
  92. return -EINVAL;
  93. }
  94. }
  95. return 0;
  96. }
  97. EXPORT_SYMBOL_GPL(swphy_validate_state);
  98. /**
  99. * swphy_read_reg - return a MII register from the fixed phy state
  100. * @reg: MII register
  101. * @state: fixed phy status
  102. *
  103. * Return the MII @reg register generated from the fixed phy state @state.
  104. */
  105. int swphy_read_reg(int reg, const struct fixed_phy_status *state)
  106. {
  107. int speed_index, duplex_index;
  108. u16 bmsr = BMSR_ANEGCAPABLE;
  109. u16 estat = 0;
  110. u16 lpagb = 0;
  111. u16 lpa = 0;
  112. if (reg > MII_REGS_NUM)
  113. return -1;
  114. speed_index = swphy_decode_speed(state->speed);
  115. if (WARN_ON(speed_index < 0))
  116. return 0;
  117. duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
  118. bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
  119. estat |= speed[speed_index].estat & duplex[duplex_index].estat;
  120. if (state->link) {
  121. bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
  122. lpa |= speed[speed_index].lpa & duplex[duplex_index].lpa;
  123. lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb;
  124. if (state->pause)
  125. lpa |= LPA_PAUSE_CAP;
  126. if (state->asym_pause)
  127. lpa |= LPA_PAUSE_ASYM;
  128. }
  129. switch (reg) {
  130. case MII_BMCR:
  131. return BMCR_ANENABLE;
  132. case MII_BMSR:
  133. return bmsr;
  134. case MII_PHYSID1:
  135. case MII_PHYSID2:
  136. return 0;
  137. case MII_LPA:
  138. return lpa;
  139. case MII_STAT1000:
  140. return lpagb;
  141. case MII_ESTATUS:
  142. return estat;
  143. /*
  144. * We do not support emulating Clause 45 over Clause 22 register
  145. * reads. Return an error instead of bogus data.
  146. */
  147. case MII_MMD_CTRL:
  148. case MII_MMD_DATA:
  149. return -1;
  150. default:
  151. return 0xffff;
  152. }
  153. }
  154. EXPORT_SYMBOL_GPL(swphy_read_reg);