lan9118_phy.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * SMSC LAN9118 PHY emulation
  3. *
  4. * Copyright (c) 2009 CodeSourcery, LLC.
  5. * Written by Paul Brook
  6. *
  7. * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net>
  8. *
  9. * This code is licensed under the GNU GPL v2
  10. *
  11. * Contributions after 2012-01-13 are licensed under the terms of the
  12. * GNU GPL, version 2 or (at your option) any later version.
  13. */
  14. #include "qemu/osdep.h"
  15. #include "hw/net/lan9118_phy.h"
  16. #include "hw/net/mii.h"
  17. #include "hw/irq.h"
  18. #include "hw/resettable.h"
  19. #include "migration/vmstate.h"
  20. #include "qemu/log.h"
  21. #include "trace.h"
  22. #define PHY_INT_ENERGYON (1 << 7)
  23. #define PHY_INT_AUTONEG_COMPLETE (1 << 6)
  24. #define PHY_INT_FAULT (1 << 5)
  25. #define PHY_INT_DOWN (1 << 4)
  26. #define PHY_INT_AUTONEG_LP (1 << 3)
  27. #define PHY_INT_PARFAULT (1 << 2)
  28. #define PHY_INT_AUTONEG_PAGE (1 << 1)
  29. static void lan9118_phy_update_irq(Lan9118PhyState *s)
  30. {
  31. qemu_set_irq(s->irq, !!(s->ints & s->int_mask));
  32. }
  33. uint16_t lan9118_phy_read(Lan9118PhyState *s, int reg)
  34. {
  35. uint16_t val;
  36. switch (reg) {
  37. case MII_BMCR:
  38. val = s->control;
  39. break;
  40. case MII_BMSR:
  41. val = s->status;
  42. break;
  43. case MII_PHYID1:
  44. val = SMSCLAN9118_PHYID1;
  45. break;
  46. case MII_PHYID2:
  47. val = SMSCLAN9118_PHYID2;
  48. break;
  49. case MII_ANAR:
  50. val = s->advertise;
  51. break;
  52. case MII_ANLPAR:
  53. val = MII_ANLPAR_PAUSEASY | MII_ANLPAR_PAUSE | MII_ANLPAR_T4 |
  54. MII_ANLPAR_TXFD | MII_ANLPAR_TX | MII_ANLPAR_10FD |
  55. MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
  56. break;
  57. case MII_ANER:
  58. val = MII_ANER_NWAY;
  59. break;
  60. case 29: /* Interrupt source. */
  61. val = s->ints;
  62. s->ints = 0;
  63. lan9118_phy_update_irq(s);
  64. break;
  65. case 30: /* Interrupt mask */
  66. val = s->int_mask;
  67. break;
  68. case 17:
  69. case 18:
  70. case 27:
  71. case 31:
  72. qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
  73. __func__, reg);
  74. val = 0;
  75. break;
  76. default:
  77. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
  78. __func__, reg);
  79. val = 0;
  80. break;
  81. }
  82. trace_lan9118_phy_read(val, reg);
  83. return val;
  84. }
  85. void lan9118_phy_write(Lan9118PhyState *s, int reg, uint16_t val)
  86. {
  87. trace_lan9118_phy_write(val, reg);
  88. switch (reg) {
  89. case MII_BMCR:
  90. if (val & MII_BMCR_RESET) {
  91. lan9118_phy_reset(s);
  92. } else {
  93. s->control = val & (MII_BMCR_LOOPBACK | MII_BMCR_SPEED100 |
  94. MII_BMCR_AUTOEN | MII_BMCR_PDOWN | MII_BMCR_FD |
  95. MII_BMCR_CTST);
  96. /* Complete autonegotiation immediately. */
  97. if (val & MII_BMCR_AUTOEN) {
  98. s->status |= MII_BMSR_AN_COMP;
  99. }
  100. }
  101. break;
  102. case MII_ANAR:
  103. s->advertise = (val & (MII_ANAR_RFAULT | MII_ANAR_PAUSE_ASYM |
  104. MII_ANAR_PAUSE | MII_ANAR_TXFD | MII_ANAR_10FD |
  105. MII_ANAR_10 | MII_ANAR_SELECT))
  106. | MII_ANAR_TX;
  107. break;
  108. case 30: /* Interrupt mask */
  109. s->int_mask = val & 0xff;
  110. lan9118_phy_update_irq(s);
  111. break;
  112. case 17:
  113. case 18:
  114. case 27:
  115. case 31:
  116. qemu_log_mask(LOG_UNIMP, "%s: reg %d not implemented\n",
  117. __func__, reg);
  118. break;
  119. default:
  120. qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad address at offset %d\n",
  121. __func__, reg);
  122. break;
  123. }
  124. }
  125. void lan9118_phy_update_link(Lan9118PhyState *s, bool link_down)
  126. {
  127. s->link_down = link_down;
  128. /* Autonegotiation status mirrors link status. */
  129. if (link_down) {
  130. trace_lan9118_phy_update_link("down");
  131. s->status &= ~(MII_BMSR_AN_COMP | MII_BMSR_LINK_ST);
  132. s->ints |= PHY_INT_DOWN;
  133. } else {
  134. trace_lan9118_phy_update_link("up");
  135. s->status |= MII_BMSR_AN_COMP | MII_BMSR_LINK_ST;
  136. s->ints |= PHY_INT_ENERGYON;
  137. s->ints |= PHY_INT_AUTONEG_COMPLETE;
  138. }
  139. lan9118_phy_update_irq(s);
  140. }
  141. void lan9118_phy_reset(Lan9118PhyState *s)
  142. {
  143. trace_lan9118_phy_reset();
  144. s->control = MII_BMCR_AUTOEN | MII_BMCR_SPEED100;
  145. s->status = MII_BMSR_100TX_FD
  146. | MII_BMSR_100TX_HD
  147. | MII_BMSR_10T_FD
  148. | MII_BMSR_10T_HD
  149. | MII_BMSR_AUTONEG
  150. | MII_BMSR_EXTCAP;
  151. s->advertise = MII_ANAR_TXFD
  152. | MII_ANAR_TX
  153. | MII_ANAR_10FD
  154. | MII_ANAR_10
  155. | MII_ANAR_CSMACD;
  156. s->int_mask = 0;
  157. s->ints = 0;
  158. lan9118_phy_update_link(s, s->link_down);
  159. }
  160. static void lan9118_phy_reset_hold(Object *obj, ResetType type)
  161. {
  162. Lan9118PhyState *s = LAN9118_PHY(obj);
  163. lan9118_phy_reset(s);
  164. }
  165. static void lan9118_phy_init(Object *obj)
  166. {
  167. Lan9118PhyState *s = LAN9118_PHY(obj);
  168. qdev_init_gpio_out(DEVICE(s), &s->irq, 1);
  169. }
  170. static const VMStateDescription vmstate_lan9118_phy = {
  171. .name = "lan9118-phy",
  172. .version_id = 1,
  173. .minimum_version_id = 1,
  174. .fields = (const VMStateField[]) {
  175. VMSTATE_UINT16(status, Lan9118PhyState),
  176. VMSTATE_UINT16(control, Lan9118PhyState),
  177. VMSTATE_UINT16(advertise, Lan9118PhyState),
  178. VMSTATE_UINT16(ints, Lan9118PhyState),
  179. VMSTATE_UINT16(int_mask, Lan9118PhyState),
  180. VMSTATE_BOOL(link_down, Lan9118PhyState),
  181. VMSTATE_END_OF_LIST()
  182. }
  183. };
  184. static void lan9118_phy_class_init(ObjectClass *klass, void *data)
  185. {
  186. ResettableClass *rc = RESETTABLE_CLASS(klass);
  187. DeviceClass *dc = DEVICE_CLASS(klass);
  188. rc->phases.hold = lan9118_phy_reset_hold;
  189. dc->vmsd = &vmstate_lan9118_phy;
  190. }
  191. static const TypeInfo types[] = {
  192. {
  193. .name = TYPE_LAN9118_PHY,
  194. .parent = TYPE_SYS_BUS_DEVICE,
  195. .instance_size = sizeof(Lan9118PhyState),
  196. .instance_init = lan9118_phy_init,
  197. .class_init = lan9118_phy_class_init,
  198. }
  199. };
  200. DEFINE_TYPES(types)