dv-eth_phy.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* Ethernet Physical Receiver model.
  2. Copyright (C) 2010-2015 Free Software Foundation, Inc.
  3. Contributed by Analog Devices, Inc.
  4. This file is part of simulators.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. #include "config.h"
  16. #include "sim-main.h"
  17. #include "devices.h"
  18. #if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H)
  19. /* Workaround old/broken linux headers. */
  20. #include <linux/types.h>
  21. #include <linux/mii.h>
  22. #define REG_PHY_SIZE 0x20
  23. struct eth_phy
  24. {
  25. bu32 base;
  26. bu16 regs[REG_PHY_SIZE];
  27. };
  28. #define reg_base() offsetof(struct eth_phy, regs[0])
  29. #define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base())
  30. #define reg_idx(reg) (reg_offset (reg) / 4)
  31. static const char * const reg_names[] =
  32. {
  33. [MII_BMCR ] = "MII_BMCR",
  34. [MII_BMSR ] = "MII_BMSR",
  35. [MII_PHYSID1 ] = "MII_PHYSID1",
  36. [MII_PHYSID2 ] = "MII_PHYSID2",
  37. [MII_ADVERTISE ] = "MII_ADVERTISE",
  38. [MII_LPA ] = "MII_LPA",
  39. [MII_EXPANSION ] = "MII_EXPANSION",
  40. #ifdef MII_CTRL1000
  41. [MII_CTRL1000 ] = "MII_CTRL1000",
  42. #endif
  43. #ifdef MII_STAT1000
  44. [MII_STAT1000 ] = "MII_STAT1000",
  45. #endif
  46. #ifdef MII_ESTATUS
  47. [MII_ESTATUS ] = "MII_ESTATUS",
  48. #endif
  49. [MII_DCOUNTER ] = "MII_DCOUNTER",
  50. [MII_FCSCOUNTER ] = "MII_FCSCOUNTER",
  51. [MII_NWAYTEST ] = "MII_NWAYTEST",
  52. [MII_RERRCOUNTER] = "MII_RERRCOUNTER",
  53. [MII_SREVISION ] = "MII_SREVISION",
  54. [MII_RESV1 ] = "MII_RESV1",
  55. [MII_LBRERROR ] = "MII_LBRERROR",
  56. [MII_PHYADDR ] = "MII_PHYADDR",
  57. [MII_RESV2 ] = "MII_RESV2",
  58. [MII_TPISTATUS ] = "MII_TPISTATUS",
  59. [MII_NCONFIG ] = "MII_NCONFIG",
  60. };
  61. #define mmr_name(off) (reg_names[off] ? : "<INV>")
  62. #define mmr_off reg_off
  63. static unsigned
  64. eth_phy_io_write_buffer (struct hw *me, const void *source,
  65. int space, address_word addr, unsigned nr_bytes)
  66. {
  67. struct eth_phy *phy = hw_data (me);
  68. bu16 reg_off;
  69. bu16 value;
  70. bu16 *valuep;
  71. value = dv_load_2 (source);
  72. reg_off = addr - phy->base;
  73. valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
  74. HW_TRACE_WRITE ();
  75. switch (reg_off)
  76. {
  77. case MII_BMCR:
  78. *valuep = value;
  79. break;
  80. case MII_PHYSID1:
  81. case MII_PHYSID2:
  82. /* Discard writes to these. */
  83. break;
  84. default:
  85. /* XXX: Discard writes to unknown regs ? */
  86. *valuep = value;
  87. break;
  88. }
  89. return nr_bytes;
  90. }
  91. static unsigned
  92. eth_phy_io_read_buffer (struct hw *me, void *dest,
  93. int space, address_word addr, unsigned nr_bytes)
  94. {
  95. struct eth_phy *phy = hw_data (me);
  96. bu16 reg_off;
  97. bu16 *valuep;
  98. reg_off = addr - phy->base;
  99. valuep = (void *)((unsigned long)phy + reg_base() + reg_off);
  100. HW_TRACE_READ ();
  101. switch (reg_off)
  102. {
  103. case MII_BMCR:
  104. dv_store_2 (dest, *valuep);
  105. break;
  106. case MII_BMSR:
  107. /* XXX: Let people control this ? */
  108. *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF |
  109. BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS;
  110. dv_store_2 (dest, *valuep);
  111. break;
  112. case MII_LPA:
  113. /* XXX: Let people control this ? */
  114. *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF;
  115. dv_store_2 (dest, *valuep);
  116. break;
  117. default:
  118. dv_store_2 (dest, *valuep);
  119. break;
  120. }
  121. return nr_bytes;
  122. }
  123. static void
  124. attach_eth_phy_regs (struct hw *me, struct eth_phy *phy)
  125. {
  126. address_word attach_address;
  127. int attach_space;
  128. unsigned attach_size;
  129. reg_property_spec reg;
  130. if (hw_find_property (me, "reg") == NULL)
  131. hw_abort (me, "Missing \"reg\" property");
  132. if (!hw_find_reg_array_property (me, "reg", 0, &reg))
  133. hw_abort (me, "\"reg\" property must contain three addr/size entries");
  134. hw_unit_address_to_attach_address (hw_parent (me),
  135. &reg.address,
  136. &attach_space, &attach_address, me);
  137. hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
  138. if (attach_size != REG_PHY_SIZE)
  139. hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE);
  140. hw_attach_address (hw_parent (me),
  141. 0, attach_space, attach_address, attach_size, me);
  142. phy->base = attach_address;
  143. }
  144. static void
  145. eth_phy_finish (struct hw *me)
  146. {
  147. struct eth_phy *phy;
  148. phy = HW_ZALLOC (me, struct eth_phy);
  149. set_hw_data (me, phy);
  150. set_hw_io_read_buffer (me, eth_phy_io_read_buffer);
  151. set_hw_io_write_buffer (me, eth_phy_io_write_buffer);
  152. attach_eth_phy_regs (me, phy);
  153. /* Initialize the PHY. */
  154. phy->regs[MII_PHYSID1] = 0; /* Unassigned Vendor */
  155. phy->regs[MII_PHYSID2] = 0xAD; /* Product */
  156. }
  157. #else
  158. static void
  159. eth_phy_finish (struct hw *me)
  160. {
  161. HW_TRACE ((me, "No linux/mii.h support found"));
  162. }
  163. #endif
  164. const struct hw_descriptor dv_eth_phy_descriptor[] =
  165. {
  166. {"eth_phy", eth_phy_finish,},
  167. {NULL, NULL},
  168. };