dv-eth_phy.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* Ethernet Physical Receiver model.
  2. Copyright (C) 2010-2022 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. /* This must come before any other includes. */
  16. #include "defs.h"
  17. #include "sim-main.h"
  18. #include "devices.h"
  19. #if defined (HAVE_LINUX_MII_H) && defined (HAVE_LINUX_TYPES_H)
  20. /* Workaround old/broken linux headers. */
  21. #include <linux/types.h>
  22. #include <linux/mii.h>
  23. #define REG_PHY_SIZE 0x20
  24. struct eth_phy
  25. {
  26. bu32 base;
  27. bu16 regs[REG_PHY_SIZE];
  28. };
  29. #define reg_base() offsetof(struct eth_phy, regs[0])
  30. #define reg_offset(reg) (offsetof(struct eth_phy, reg) - reg_base())
  31. #define reg_idx(reg) (reg_offset (reg) / 4)
  32. static const char * const reg_names[] =
  33. {
  34. [MII_BMCR ] = "MII_BMCR",
  35. [MII_BMSR ] = "MII_BMSR",
  36. [MII_PHYSID1 ] = "MII_PHYSID1",
  37. [MII_PHYSID2 ] = "MII_PHYSID2",
  38. [MII_ADVERTISE ] = "MII_ADVERTISE",
  39. [MII_LPA ] = "MII_LPA",
  40. [MII_EXPANSION ] = "MII_EXPANSION",
  41. #ifdef MII_CTRL1000
  42. [MII_CTRL1000 ] = "MII_CTRL1000",
  43. #endif
  44. #ifdef MII_STAT1000
  45. [MII_STAT1000 ] = "MII_STAT1000",
  46. #endif
  47. #ifdef MII_ESTATUS
  48. [MII_ESTATUS ] = "MII_ESTATUS",
  49. #endif
  50. [MII_DCOUNTER ] = "MII_DCOUNTER",
  51. [MII_FCSCOUNTER ] = "MII_FCSCOUNTER",
  52. [MII_NWAYTEST ] = "MII_NWAYTEST",
  53. [MII_RERRCOUNTER] = "MII_RERRCOUNTER",
  54. [MII_SREVISION ] = "MII_SREVISION",
  55. [MII_RESV1 ] = "MII_RESV1",
  56. [MII_LBRERROR ] = "MII_LBRERROR",
  57. [MII_PHYADDR ] = "MII_PHYADDR",
  58. [MII_RESV2 ] = "MII_RESV2",
  59. [MII_TPISTATUS ] = "MII_TPISTATUS",
  60. [MII_NCONFIG ] = "MII_NCONFIG",
  61. };
  62. #define mmr_name(off) (reg_names[off] ? : "<INV>")
  63. #define mmr_off reg_off
  64. static unsigned
  65. eth_phy_io_write_buffer (struct hw *me, const void *source,
  66. int space, address_word addr, unsigned nr_bytes)
  67. {
  68. struct eth_phy *phy = hw_data (me);
  69. bu16 reg_off;
  70. bu16 value;
  71. bu16 *valuep;
  72. value = dv_load_2 (source);
  73. reg_off = addr - phy->base;
  74. valuep = (void *)((uintptr_t)phy + reg_base() + reg_off);
  75. HW_TRACE_WRITE ();
  76. switch (reg_off)
  77. {
  78. case MII_BMCR:
  79. *valuep = value;
  80. break;
  81. case MII_PHYSID1:
  82. case MII_PHYSID2:
  83. /* Discard writes to these. */
  84. break;
  85. default:
  86. /* XXX: Discard writes to unknown regs ? */
  87. *valuep = value;
  88. break;
  89. }
  90. return nr_bytes;
  91. }
  92. static unsigned
  93. eth_phy_io_read_buffer (struct hw *me, void *dest,
  94. int space, address_word addr, unsigned nr_bytes)
  95. {
  96. struct eth_phy *phy = hw_data (me);
  97. bu16 reg_off;
  98. bu16 *valuep;
  99. reg_off = addr - phy->base;
  100. valuep = (void *)((uintptr_t)phy + reg_base() + reg_off);
  101. HW_TRACE_READ ();
  102. switch (reg_off)
  103. {
  104. case MII_BMCR:
  105. dv_store_2 (dest, *valuep);
  106. break;
  107. case MII_BMSR:
  108. /* XXX: Let people control this ? */
  109. *valuep = BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF |
  110. BMSR_ANEGCOMPLETE | BMSR_ANEGCAPABLE | BMSR_LSTATUS;
  111. dv_store_2 (dest, *valuep);
  112. break;
  113. case MII_LPA:
  114. /* XXX: Let people control this ? */
  115. *valuep = LPA_100FULL | LPA_100HALF | LPA_10FULL | LPA_10HALF;
  116. dv_store_2 (dest, *valuep);
  117. break;
  118. default:
  119. dv_store_2 (dest, *valuep);
  120. break;
  121. }
  122. return nr_bytes;
  123. }
  124. static void
  125. attach_eth_phy_regs (struct hw *me, struct eth_phy *phy)
  126. {
  127. address_word attach_address;
  128. int attach_space;
  129. unsigned attach_size;
  130. reg_property_spec reg;
  131. if (hw_find_property (me, "reg") == NULL)
  132. hw_abort (me, "Missing \"reg\" property");
  133. if (!hw_find_reg_array_property (me, "reg", 0, &reg))
  134. hw_abort (me, "\"reg\" property must contain three addr/size entries");
  135. hw_unit_address_to_attach_address (hw_parent (me),
  136. &reg.address,
  137. &attach_space, &attach_address, me);
  138. hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
  139. if (attach_size != REG_PHY_SIZE)
  140. hw_abort (me, "\"reg\" size must be %#x", REG_PHY_SIZE);
  141. hw_attach_address (hw_parent (me),
  142. 0, attach_space, attach_address, attach_size, me);
  143. phy->base = attach_address;
  144. }
  145. static void
  146. eth_phy_finish (struct hw *me)
  147. {
  148. struct eth_phy *phy;
  149. phy = HW_ZALLOC (me, struct eth_phy);
  150. set_hw_data (me, phy);
  151. set_hw_io_read_buffer (me, eth_phy_io_read_buffer);
  152. set_hw_io_write_buffer (me, eth_phy_io_write_buffer);
  153. attach_eth_phy_regs (me, phy);
  154. /* Initialize the PHY. */
  155. phy->regs[MII_PHYSID1] = 0; /* Unassigned Vendor */
  156. phy->regs[MII_PHYSID2] = 0xAD; /* Product */
  157. }
  158. #else
  159. static void
  160. eth_phy_finish (struct hw *me)
  161. {
  162. HW_TRACE ((me, "No linux/mii.h support found"));
  163. }
  164. #endif
  165. const struct hw_descriptor dv_eth_phy_descriptor[] =
  166. {
  167. {"eth_phy", eth_phy_finish,},
  168. {NULL, NULL},
  169. };