EnetPhy.Mod 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. MODULE EnetPhy;
  2. (**
  3. AUTHOR: Alexey Morozov, HighDim GmbH, 2015
  4. PURPOSE: Ethernet networking stack, PHY management
  5. *)
  6. IMPORT
  7. S := SYSTEM, EnetTiming, EnetBase;
  8. TYPE
  9. Int8 = EnetBase.Int8;
  10. Int16 = EnetBase.Int16;
  11. Int = EnetBase.Int;
  12. UInt = EnetBase.UInt;
  13. CONST
  14. InvalidPhyAddr* = 0xFF; (** Invalid PHY address *)
  15. (**
  16. Generic MII registers.
  17. *)
  18. MII_BMCR* = 0x00; (** Basic mode control register *)
  19. MII_BMSR* = 0x01; (** Basic mode status register *)
  20. MII_PHYSID1* = 0x02; (** PHYS ID 1 *)
  21. MII_PHYSID2* = 0x03; (** PHYS ID 2 *)
  22. MII_ADVERTISE* = 0x04; (** Advertisement control reg *)
  23. MII_LPA* = 0x05; (** Link partner ability reg *)
  24. MII_EXPANSION* = 0x06; (** Expansion register *)
  25. MII_CTRL1000* = 0x09; (** 1000BASE-T control *)
  26. MII_STAT1000* = 0x0a; (** 1000BASE-T status *)
  27. MII_ESTATUS* = 0x0f; (** Extended Status *)
  28. MII_DCOUNTER* = 0x12; (** Disconnect counter *)
  29. MII_FCSCOUNTER* = 0x13; (** False carrier counter *)
  30. MII_NWAYTEST* = 0x14; (** N-way auto-neg test reg *)
  31. MII_RERRCOUNTER* = 0x15; (** Receive error counter *)
  32. MII_SREVISION* = 0x16; (** Silicon revision *)
  33. MII_RESV1* = 0x17; (** Reserved *)
  34. MII_LBRERROR* = 0x18; (** Lpback, rx, bypass error *)
  35. MII_PHYADDR* = 0x19; (** PHY address *)
  36. MII_RESV2* = 0x1a; (** Reserved *)
  37. MII_TPISTATUS* = 0x1b; (** TPI status for 10mbps *)
  38. MII_NCONFIG* = 0x1c; (** Network interface config *)
  39. (** Basic mode control register. *)
  40. BMCR_RESV* = 0x003f; (** Reserved *)
  41. BMCR_SPEED1000* = 0x0040; (** MSB of Speed (1000) *)
  42. BMCR_CTST* = 0x0080; (** Collision test *)
  43. BMCR_FULLDPLX* = 0x0100; (** Full duplex *)
  44. BMCR_ANRESTART* = 0x0200; (** Auto negotiation restart *)
  45. BMCR_ISOLATE* = 0x0400; (** Disconnect DP83840 from MII *)
  46. BMCR_PDOWN* = 0x0800; (** Powerdown the DP83840 *)
  47. BMCR_ANENABLE* = 0x1000; (** Enable auto negotiation *)
  48. BMCR_SPEED100* = 0x2000; (** Select 100Mbps *)
  49. BMCR_LOOPBACK* = 0x4000; (** TXD loopback bits *)
  50. BMCR_RESET* = 0x8000; (** Reset the DP83840 *)
  51. (** Basic mode status register. *)
  52. BMSR_ERCAP* = 0x0001; (** Ext-reg capability *)
  53. BMSR_JCD* = 0x0002; (** Jabber detected *)
  54. BMSR_LSTATUS* = 0x0004; (** Link status *)
  55. BMSR_ANEGCAPABLE* = 0x0008; (** Able to do auto-negotiation *)
  56. BMSR_RFAULT* = 0x0010; (** Remote fault detected *)
  57. BMSR_ANEGCOMPLETE* = 0x0020; (** Auto-negotiation complete *)
  58. BMSR_RESV* = 0x00c0; (** Reserved *)
  59. BMSR_ESTATEN* = 0x0100; (** Extended Status in R15 *)
  60. BMSR_100FULL2* = 0x0200; (** Can do 100BASE-T2 HDX *)
  61. BMSR_100HALF2* = 0x0400; (** Can do 100BASE-T2 FDX *)
  62. BMSR_10HALF* = 0x0800; (** Can do 10mbps, half-duplex *)
  63. BMSR_10FULL* = 0x1000; (** Can do 10mbps, full-duplex *)
  64. BMSR_100HALF* = 0x2000; (** Can do 100mbps, half-duplex *)
  65. BMSR_100FULL* = 0x4000; (** Can do 100mbps, full-duplex *)
  66. BMSR_100BASE4* = 0x8000; (** Can do 100mbps, 4k packets *)
  67. (** Advertisement control register. *)
  68. ADVERTISE_SLCT* = 0x001f; (** Selector bits *)
  69. ADVERTISE_CSMA* = 0x0001; (** Only selector supported *)
  70. ADVERTISE_10HALF* = 0x0020; (** Try for 10mbps half-duplex *)
  71. ADVERTISE_1000XFULL* = 0x0020; (** Try for 1000BASE-X full-duplex *)
  72. ADVERTISE_10FULL* = 0x0040; (** Try for 10mbps full-duplex *)
  73. ADVERTISE_1000XHALF* = 0x0040; (** Try for 1000BASE-X half-duplex *)
  74. ADVERTISE_100HALF* = 0x0080; (** Try for 100mbps half-duplex *)
  75. ADVERTISE_1000XPAUSE* = 0x0080; (** Try for 1000BASE-X pause *)
  76. ADVERTISE_100FULL* = 0x0100; (** Try for 100mbps full-duplex *)
  77. ADVERTISE_1000XPSE_ASYM* = 0x0100; (** Try for 1000BASE-X asym pause *)
  78. ADVERTISE_100BASE4* = 0x0200; (** Try for 100mbps 4k packets *)
  79. ADVERTISE_PAUSE_CAP* = 0x0400; (** Try for pause *)
  80. ADVERTISE_PAUSE_ASYM* = 0x0800; (** Try for asymetric pause *)
  81. ADVERTISE_RESV* = 0x1000; (** Reserved *)
  82. ADVERTISE_RFAULT* = 0x2000; (** Say we can detect faults *)
  83. ADVERTISE_LPACK* = 0x4000; (** Ack link partners response *)
  84. ADVERTISE_NPAGE* = 0x8000; (** Next page bit *)
  85. ADVERTISE_FULL* = ADVERTISE_100FULL + ADVERTISE_10FULL + ADVERTISE_CSMA;
  86. ADVERTISE_ALL* = ADVERTISE_10HALF + ADVERTISE_10FULL + ADVERTISE_100HALF + ADVERTISE_100FULL;
  87. (** Link partner ability register. *)
  88. LPA_SLCT* = 0x001f; (** Same as advertise selector *)
  89. LPA_10HALF* = 0x0020; (** Can do 10mbps half-duplex *)
  90. LPA_1000XFULL* = 0x0020; (** Can do 1000BASE-X full-duplex *)
  91. LPA_10FULL* = 0x0040; (** Can do 10mbps full-duplex *)
  92. LPA_1000XHALF* = 0x0040; (** Can do 1000BASE-X half-duplex *)
  93. LPA_100HALF* = 0x0080; (** Can do 100mbps half-duplex *)
  94. LPA_1000XPAUSE* = 0x0080; (** Can do 1000BASE-X pause *)
  95. LPA_100FULL* = 0x0100; (** Can do 100mbps full-duplex *)
  96. LPA_1000XPAUSE_ASYM* = 0x0100; (** Can do 1000BASE-X pause asym *)
  97. LPA_100BASE4* = 0x0200; (** Can do 100mbps 4k packets *)
  98. LPA_PAUSE_CAP* = 0x0400; (** Can pause *)
  99. LPA_PAUSE_ASYM* = 0x0800; (** Can pause asymetrically *)
  100. LPA_RESV* = 0x1000; (** Reserved *)
  101. LPA_RFAULT* = 0x2000; (** Link partner faulted *)
  102. LPA_LPACK* = 0x4000; (** Link partner acked us *)
  103. LPA_NPAGE* = 0x8000; (** Next page bit *)
  104. LPA_DUPLEX* = LPA_10FULL + LPA_100FULL;
  105. LPA_100* = LPA_100FULL + LPA_100HALF + LPA_100BASE4;
  106. (** Expansion register for auto-negotiation. *)
  107. EXPANSION_NWAY* = 0x0001; (** Can do N-way auto-nego *)
  108. EXPANSION_LCWP* = 0x0002; (** Got new RX page code word *)
  109. EXPANSION_ENABLENPAGE* = 0x0004; (** This enables npage words *)
  110. EXPANSION_NPCAPABLE* = 0x0008; (** Link partner supports npage *)
  111. EXPANSION_MFAULTS* = 0x0010; (** Multiple faults detected *)
  112. EXPANSION_RESV* = 0xffe0; (** Reserved *)
  113. ESTATUS_1000_TFULL* = 0x2000; (** Can do 1000BT Full *)
  114. ESTATUS_1000_THALF* = 0x1000; (** Can do 1000BT Half *)
  115. (** N-way test register. *)
  116. NWAYTEST_RESV1* = 0x00ff; (** Reserved *)
  117. NWAYTEST_LOOPBACK* = 0x0100; (** Enable loopback for N-way *)
  118. NWAYTEST_RESV2* = 0xfe00; (** Reserved *)
  119. (** 1000BASE-T Control register *)
  120. ADVERTISE_1000FULL* = 0x0200; (** Advertise 1000BASE-T full duplex *)
  121. ADVERTISE_1000HALF* = 0x0100; (** Advertise 1000BASE-T half duplex *)
  122. (** 1000BASE-T Status register *)
  123. LPA_1000LOCALRXOK* = 0x2000; (** Link partner local receiver status *)
  124. LPA_1000REMRXOK* = 0x1000; (** Link partner remote receiver status *)
  125. LPA_1000FULL* = 0x0800; (** Link partner 1000BASE-T full duplex *)
  126. LPA_1000HALF* = 0x0400; (** Link partner 1000BASE-T half duplex *)
  127. (**
  128. Detect PHY device
  129. phyAddr: retuned PHY address (EnetBase.InvalidPhyAddr in case if no PHY found)
  130. allowZeroPhyAddr: TRUE to allow the use of PHY address 0
  131. res: error code
  132. *)
  133. PROCEDURE DetectPhy*(dev: EnetBase.LinkDevice; VAR phyAddr: UInt; allowZeroPhyAddr: BOOLEAN; VAR res: Int): BOOLEAN;
  134. VAR
  135. minAddr: UInt;
  136. d1, d2: UInt;
  137. BEGIN
  138. (*
  139. PHY address 0 cannot be used when multiple PHY's a sitting on the same MDIO serial bus.
  140. This address is reserved for broadcasting and can work only for writing (e.g. a command to
  141. reset multiple PHY's at the same time). Reading from this address will lead to contention on the bus.
  142. *)
  143. IF allowZeroPhyAddr THEN minAddr := 0; ELSE minAddr := 1; END;
  144. phyAddr := 32;
  145. REPEAT
  146. DEC(phyAddr);
  147. IF ~dev.phyRead(dev,phyAddr,MII_PHYSID1,d1,res) OR ~dev.phyRead(dev,phyAddr,MII_PHYSID2,d2,res) THEN
  148. phyAddr := InvalidPhyAddr;
  149. RETURN FALSE;
  150. END;
  151. IF (d1 # 0xFFFF) & (d2 # 0xFFFF) THEN
  152. res := 0;
  153. RETURN TRUE;
  154. END;
  155. UNTIL phyAddr = minAddr;
  156. phyAddr := InvalidPhyAddr;
  157. res := EnetBase.ErrPhyNotDetected;
  158. RETURN FALSE;
  159. END DetectPhy;
  160. (**
  161. Reset a PHY device
  162. *)
  163. PROCEDURE ResetPhy*(dev: EnetBase.LinkDevice; phyAddr: UInt; timeoutInMs: EnetTiming.Time; VAR res: Int): BOOLEAN;
  164. VAR
  165. d: UInt;
  166. t: EnetTiming.Timer;
  167. BEGIN
  168. IF ~dev.phyRead(dev,phyAddr,MII_BMCR,d,res) THEN RETURN FALSE; END;
  169. d := S.MSK(d,-BMCR_RESET-1) + BMCR_RESET;
  170. IF ~dev.phyWrite(dev,phyAddr,MII_BMCR,d,res) THEN RETURN FALSE; END;
  171. EnetTiming.SetTimerMilli(t,timeoutInMs);
  172. EnetTiming.StartTimer(t);
  173. REPEAT
  174. IF ~dev.phyRead(dev,phyAddr,MII_BMCR,d,res) THEN RETURN FALSE; END;
  175. UNTIL (S.MSK(d,BMCR_RESET) = 0) OR EnetTiming.IsTimerExpired(t);
  176. IF S.MSK(d,BMCR_RESET) = 0 THEN
  177. res := 0;
  178. RETURN TRUE;
  179. ELSE
  180. res := EnetBase.ErrTimeoutExpired;
  181. RETURN FALSE;
  182. END;
  183. END ResetPhy;
  184. END EnetPhy.