swphy.c 3.9 KB

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