Lan9118DxeUtil.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  1. /** @file
  2. *
  3. * Copyright (c) 2012-2014, ARM Limited. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause-Patent
  6. *
  7. **/
  8. #include "Lan9118Dxe.h"
  9. STATIC EFI_MAC_ADDRESS mZeroMac = { { 0 } };
  10. /**
  11. This internal function reverses bits for 32bit data.
  12. @param Value The data to be reversed.
  13. @return Data reversed.
  14. **/
  15. UINT32
  16. ReverseBits (
  17. UINT32 Value
  18. )
  19. {
  20. UINTN Index;
  21. UINT32 NewValue;
  22. NewValue = 0;
  23. for (Index = 0; Index < 32; Index++) {
  24. if ((Value & (1 << Index)) != 0) {
  25. NewValue = NewValue | (1 << (31 - Index));
  26. }
  27. }
  28. return NewValue;
  29. }
  30. /*
  31. ** Create Ethernet CRC
  32. **
  33. ** INFO USED:
  34. ** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check
  35. **
  36. ** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html
  37. **
  38. ** 3: http://en.wikipedia.org/wiki/Computation_of_CRC
  39. */
  40. UINT32
  41. GenEtherCrc32 (
  42. IN EFI_MAC_ADDRESS *Mac,
  43. IN UINT32 AddrLen
  44. )
  45. {
  46. INT32 Iter;
  47. UINT32 Remainder;
  48. UINT8 *Ptr;
  49. Iter = 0;
  50. Remainder = 0xFFFFFFFF; // 0xFFFFFFFF is standard seed for Ethernet
  51. // Convert Mac Address to array of bytes
  52. Ptr = (UINT8*)Mac;
  53. // Generate the Crc bit-by-bit (LSB first)
  54. while (AddrLen--) {
  55. Remainder ^= *Ptr++;
  56. for (Iter = 0;Iter < 8;Iter++) {
  57. // Check if exponent is set
  58. if (Remainder & 1) {
  59. Remainder = (Remainder >> 1) ^ CRC_POLYNOMIAL;
  60. } else {
  61. Remainder = (Remainder >> 1) ^ 0;
  62. }
  63. }
  64. }
  65. // Reverse the bits before returning (to Big Endian)
  66. //TODO: Need to be reviewed. Do we want to do a bit reverse or a byte reverse (in this case use SwapBytes32())
  67. return ReverseBits (Remainder);
  68. }
  69. // Function to read from MAC indirect registers
  70. UINT32
  71. IndirectMACRead32 (
  72. UINT32 Index
  73. )
  74. {
  75. UINT32 MacCSR;
  76. // Check index is in the range
  77. ASSERT(Index <= 12);
  78. // Wait until CSR busy bit is cleared
  79. while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
  80. // Set CSR busy bit to ensure read will occur
  81. // Set the R/W bit to indicate we are reading
  82. // Set the index of CSR Address to access desired register
  83. MacCSR = MAC_CSR_BUSY | MAC_CSR_READ | MAC_CSR_ADDR(Index);
  84. // Write to the register
  85. Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR);
  86. // Wait until CSR busy bit is cleared
  87. while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
  88. // Now read from data register to get read value
  89. return Lan9118MmioRead32 (LAN9118_MAC_CSR_DATA);
  90. }
  91. /*
  92. * LAN9118 chips have special restrictions on some back-to-back Write/Read or
  93. * Read/Read pairs of accesses. After a read or write that changes the state of
  94. * the device, there is a period in which stale values may be returned in
  95. * response to a read. This period is dependent on the registers accessed.
  96. *
  97. * We must delay prior reads by this period. This can either be achieved by
  98. * timer-based delays, or by performing dummy reads of the BYTE_TEST register,
  99. * for which the recommended number of reads is described in the LAN9118 data
  100. * sheet. This is required in addition to any memory barriers.
  101. *
  102. * This function performs a number of dummy reads of the BYTE_TEST register, as
  103. * a building block for the above.
  104. */
  105. VOID
  106. WaitDummyReads (
  107. UINTN Count
  108. )
  109. {
  110. while (Count--)
  111. MmioRead32(LAN9118_BYTE_TEST);
  112. }
  113. UINT32
  114. Lan9118RawMmioRead32(
  115. UINTN Address,
  116. UINTN Delay
  117. )
  118. {
  119. UINT32 Value;
  120. Value = MmioRead32(Address);
  121. WaitDummyReads(Delay);
  122. return Value;
  123. }
  124. UINT32
  125. Lan9118RawMmioWrite32(
  126. UINTN Address,
  127. UINT32 Value,
  128. UINTN Delay
  129. )
  130. {
  131. MmioWrite32(Address, Value);
  132. WaitDummyReads(Delay);
  133. return Value;
  134. }
  135. // Function to write to MAC indirect registers
  136. UINT32
  137. IndirectMACWrite32 (
  138. UINT32 Index,
  139. UINT32 Value
  140. )
  141. {
  142. UINT32 ValueWritten;
  143. UINT32 MacCSR;
  144. // Check index is in the range
  145. ASSERT(Index <= 12);
  146. // Wait until CSR busy bit is cleared
  147. while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
  148. // Set CSR busy bit to ensure read will occur
  149. // Set the R/W bit to indicate we are writing
  150. // Set the index of CSR Address to access desired register
  151. MacCSR = MAC_CSR_BUSY | MAC_CSR_WRITE | MAC_CSR_ADDR(Index);
  152. // Now write the value to the register before issuing the write command
  153. ValueWritten = Lan9118MmioWrite32 (LAN9118_MAC_CSR_DATA, Value);
  154. // Write the config to the register
  155. Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR);
  156. // Wait until CSR busy bit is cleared
  157. while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) == MAC_CSR_BUSY);
  158. return ValueWritten;
  159. }
  160. // Function to read from MII register (PHY Access)
  161. UINT32
  162. IndirectPHYRead32 (
  163. UINT32 Index
  164. )
  165. {
  166. UINT32 ValueRead;
  167. UINT32 MiiAcc;
  168. // Check it is a valid index
  169. ASSERT(Index < 31);
  170. // Wait for busy bit to clear
  171. while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
  172. // Clear the R/W bit to indicate we are reading
  173. // Set the index of the MII register
  174. // Set the PHY Address
  175. // Set the MII busy bit to allow read
  176. MiiAcc = MII_ACC_MII_READ | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY;
  177. // Now write this config to register
  178. IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF);
  179. // Wait for busy bit to clear
  180. while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
  181. // Now read the value of the register
  182. ValueRead = (IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_DATA) & 0xFFFF); // only lower 16 bits are valid for any PHY register
  183. return ValueRead;
  184. }
  185. // Function to write to the MII register (PHY Access)
  186. UINT32
  187. IndirectPHYWrite32 (
  188. UINT32 Index,
  189. UINT32 Value
  190. )
  191. {
  192. UINT32 MiiAcc;
  193. UINT32 ValueWritten;
  194. // Check it is a valid index
  195. ASSERT(Index < 31);
  196. // Wait for busy bit to clear
  197. while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
  198. // Clear the R/W bit to indicate we are reading
  199. // Set the index of the MII register
  200. // Set the PHY Address
  201. // Set the MII busy bit to allow read
  202. MiiAcc = MII_ACC_MII_WRITE | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY_VALUE | MII_ACC_MII_BUSY;
  203. // Write the desired value to the register first
  204. ValueWritten = IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_DATA, (Value & 0xFFFF));
  205. // Now write the config to register
  206. IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF);
  207. // Wait for operation to terminate
  208. while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUSY) == MII_ACC_MII_BUSY);
  209. return ValueWritten;
  210. }
  211. /* ---------------- EEPROM Operations ------------------ */
  212. // Function to read from EEPROM memory
  213. UINT32
  214. IndirectEEPROMRead32 (
  215. UINT32 Index
  216. )
  217. {
  218. UINT32 EepromCmd;
  219. // Set the busy bit to ensure read will occur
  220. EepromCmd = E2P_EPC_BUSY | E2P_EPC_CMD_READ;
  221. // Set the index to access desired EEPROM memory location
  222. EepromCmd |= E2P_EPC_ADDRESS(Index);
  223. // Write to Eeprom command register
  224. Lan9118MmioWrite32 (LAN9118_E2P_CMD, EepromCmd);
  225. // Wait until operation has completed
  226. while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
  227. // Check that operation didn't time out
  228. if (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) {
  229. DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Read command on index %x\n",Index));
  230. return 0;
  231. }
  232. // Wait until operation has completed
  233. while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
  234. // Finally read the value
  235. return Lan9118MmioRead32 (LAN9118_E2P_DATA);
  236. }
  237. // Function to write to EEPROM memory
  238. UINT32
  239. IndirectEEPROMWrite32 (
  240. UINT32 Index,
  241. UINT32 Value
  242. )
  243. {
  244. UINT32 ValueWritten;
  245. UINT32 EepromCmd;
  246. ValueWritten = 0;
  247. // Read the EEPROM Command register
  248. EepromCmd = Lan9118MmioRead32 (LAN9118_E2P_CMD);
  249. // Set the busy bit to ensure read will occur
  250. EepromCmd |= ((UINT32)1 << 31);
  251. // Set the EEPROM command to write(0b011)
  252. EepromCmd &= ~(7 << 28); // Clear the command first
  253. EepromCmd |= (3 << 28); // Write 011
  254. // Set the index to access desired EEPROM memory location
  255. EepromCmd |= (Index & 0xF);
  256. // Write the value to the data register first
  257. ValueWritten = Lan9118MmioWrite32 (LAN9118_E2P_DATA, Value);
  258. // Write to Eeprom command register
  259. Lan9118MmioWrite32 (LAN9118_E2P_CMD, EepromCmd);
  260. // Wait until operation has completed
  261. while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
  262. // Check that operation didn't time out
  263. if (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) {
  264. DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Write command at memloc 0x%x, with value 0x%x\n",Index, Value));
  265. return 0;
  266. }
  267. // Wait until operation has completed
  268. while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
  269. return ValueWritten;
  270. }
  271. /* ---------------- General Operations ----------------- */
  272. VOID
  273. Lan9118SetMacAddress (
  274. EFI_MAC_ADDRESS *Mac,
  275. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  276. )
  277. {
  278. IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL,
  279. (Mac->Addr[0] & 0xFF) |
  280. ((Mac->Addr[1] & 0xFF) << 8) |
  281. ((Mac->Addr[2] & 0xFF) << 16) |
  282. ((Mac->Addr[3] & 0xFF) << 24)
  283. );
  284. IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH,
  285. (UINT32)(Mac->Addr[4] & 0xFF) |
  286. ((Mac->Addr[5] & 0xFF) << 8)
  287. );
  288. }
  289. VOID
  290. Lan9118ReadMacAddress (
  291. OUT EFI_MAC_ADDRESS *MacAddress
  292. )
  293. {
  294. UINT32 MacAddrHighValue;
  295. UINT32 MacAddrLowValue;
  296. // Read the Mac Addr high register
  297. MacAddrHighValue = (IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRH) & 0xFFFF);
  298. // Read the Mac Addr low register
  299. MacAddrLowValue = IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRL);
  300. SetMem (MacAddress, sizeof(*MacAddress), 0);
  301. MacAddress->Addr[0] = (MacAddrLowValue & 0xFF);
  302. MacAddress->Addr[1] = (MacAddrLowValue & 0xFF00) >> 8;
  303. MacAddress->Addr[2] = (MacAddrLowValue & 0xFF0000) >> 16;
  304. MacAddress->Addr[3] = (MacAddrLowValue & 0xFF000000) >> 24;
  305. MacAddress->Addr[4] = (MacAddrHighValue & 0xFF);
  306. MacAddress->Addr[5] = (MacAddrHighValue & 0xFF00) >> 8;
  307. }
  308. /*
  309. * Power up the 9118 and find its MAC address.
  310. *
  311. * This operation can be carried out when the LAN9118 is in any power state
  312. *
  313. */
  314. EFI_STATUS
  315. Lan9118Initialize (
  316. IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  317. )
  318. {
  319. UINTN Retries;
  320. UINT64 DefaultMacAddress;
  321. // Attempt to wake-up the device if it is in a lower power state
  322. if (((Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PM_MODE_MASK) >> 12) != 0) {
  323. DEBUG ((DEBUG_NET, "Waking from reduced power state.\n"));
  324. Lan9118MmioWrite32 (LAN9118_BYTE_TEST, 0xFFFFFFFF);
  325. }
  326. // Check that device is active
  327. Retries = 20;
  328. while ((Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_READY) == 0 && --Retries) {
  329. gBS->Stall (LAN9118_STALL);
  330. }
  331. if (!Retries) {
  332. return EFI_TIMEOUT;
  333. }
  334. // Check that EEPROM isn't active
  335. Retries = 20;
  336. while ((Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY) && --Retries){
  337. gBS->Stall (LAN9118_STALL);
  338. }
  339. if (!Retries) {
  340. return EFI_TIMEOUT;
  341. }
  342. // Check if a MAC address was loaded from EEPROM, and if it was, set it as the
  343. // current address.
  344. if ((Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_MAC_ADDRESS_LOADED) == 0) {
  345. DEBUG ((EFI_D_ERROR, "Warning: There was an error detecting EEPROM or loading the MAC Address.\n"));
  346. // If we had an address before (set by StationAddess), continue to use it
  347. if (CompareMem (&Snp->Mode->CurrentAddress, &mZeroMac, NET_ETHER_ADDR_LEN)) {
  348. Lan9118SetMacAddress (&Snp->Mode->CurrentAddress, Snp);
  349. } else {
  350. // If there are no cached addresses, then fall back to a default
  351. DEBUG ((EFI_D_WARN, "Warning: using driver-default MAC address\n"));
  352. DefaultMacAddress = FixedPcdGet64 (PcdLan9118DefaultMacAddress);
  353. Lan9118SetMacAddress((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp);
  354. CopyMem (&Snp->Mode->CurrentAddress, &DefaultMacAddress, NET_ETHER_ADDR_LEN);
  355. }
  356. } else {
  357. // Store the MAC address that was loaded from EEPROM
  358. Lan9118ReadMacAddress (&Snp->Mode->CurrentAddress);
  359. CopyMem (&Snp->Mode->PermanentAddress, &Snp->Mode->CurrentAddress, NET_ETHER_ADDR_LEN);
  360. }
  361. // Clear and acknowledge interrupts
  362. Lan9118MmioWrite32 (LAN9118_INT_EN, 0);
  363. Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0);
  364. Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
  365. // Do self tests here?
  366. return EFI_SUCCESS;
  367. }
  368. // Perform software reset on the LAN9118
  369. // Return 0 on success, -1 on error
  370. EFI_STATUS
  371. SoftReset (
  372. UINT32 Flags,
  373. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  374. )
  375. {
  376. UINT32 HwConf;
  377. UINT32 ResetTime;
  378. // Initialize variable
  379. ResetTime = 0;
  380. // Stop Rx and Tx
  381. StopTx (STOP_TX_MAC | STOP_TX_CFG | STOP_TX_CLEAR, Snp);
  382. StopRx (STOP_RX_CLEAR, Snp); // Clear receiver FIFO
  383. // Issue the reset
  384. HwConf = Lan9118MmioRead32 (LAN9118_HW_CFG);
  385. HwConf |= 1;
  386. // Set the Must Be One (MBO) bit
  387. if (((HwConf & HWCFG_MBO) >> 20) == 0) {
  388. HwConf |= HWCFG_MBO;
  389. }
  390. // Check that EEPROM isn't active
  391. while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
  392. // Write the configuration
  393. Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf);
  394. // Wait for reset to complete
  395. while (Lan9118MmioRead32 (LAN9118_HW_CFG) & HWCFG_SRST) {
  396. gBS->Stall (LAN9118_STALL);
  397. ResetTime += 1;
  398. // If time taken exceeds 100us, then there was an error condition
  399. if (ResetTime > 1000) {
  400. Snp->Mode->State = EfiSimpleNetworkStopped;
  401. return EFI_TIMEOUT;
  402. }
  403. }
  404. // Check that EEPROM isn't active
  405. while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY);
  406. // TODO we probably need to re-set the mac address here.
  407. // Clear and acknowledge all interrupts
  408. if (Flags & SOFT_RESET_CLEAR_INT) {
  409. Lan9118MmioWrite32 (LAN9118_INT_EN, 0);
  410. Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0);
  411. Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
  412. }
  413. // Do self tests here?
  414. if (Flags & SOFT_RESET_SELF_TEST) {
  415. }
  416. return EFI_SUCCESS;
  417. }
  418. // Perform PHY software reset
  419. EFI_STATUS
  420. PhySoftReset (
  421. UINT32 Flags,
  422. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  423. )
  424. {
  425. UINT32 PmtCtrl = 0;
  426. // PMT PHY reset takes precedence over BCR
  427. if (Flags & PHY_RESET_PMT) {
  428. PmtCtrl = Lan9118MmioRead32 (LAN9118_PMT_CTRL);
  429. PmtCtrl |= MPTCTRL_PHY_RST;
  430. Lan9118MmioWrite32 (LAN9118_PMT_CTRL,PmtCtrl);
  431. // Wait for completion
  432. while (Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PHY_RST) {
  433. gBS->Stall (LAN9118_STALL);
  434. }
  435. // PHY Basic Control Register reset
  436. } else if (Flags & PHY_RESET_BCR) {
  437. IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PHYCR_RESET);
  438. // Wait for completion
  439. while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) {
  440. gBS->Stall (LAN9118_STALL);
  441. }
  442. }
  443. // Clear and acknowledge all interrupts
  444. if (Flags & PHY_SOFT_RESET_CLEAR_INT) {
  445. Lan9118MmioWrite32 (LAN9118_INT_EN, 0);
  446. Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0);
  447. Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF);
  448. }
  449. return EFI_SUCCESS;
  450. }
  451. // Configure hardware for LAN9118
  452. EFI_STATUS
  453. ConfigureHardware (
  454. UINT32 Flags,
  455. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  456. )
  457. {
  458. UINT32 GpioConf;
  459. // Check if we want to use LEDs on GPIO
  460. if (Flags & HW_CONF_USE_LEDS) {
  461. GpioConf = Lan9118MmioRead32 (LAN9118_GPIO_CFG);
  462. // Enable GPIO as LEDs and Config as Push-Pull driver
  463. GpioConf |= GPIO_GPIO0_PUSH_PULL | GPIO_GPIO1_PUSH_PULL | GPIO_GPIO2_PUSH_PULL |
  464. GPIO_LED1_ENABLE | GPIO_LED2_ENABLE | GPIO_LED3_ENABLE;
  465. // Write the configuration
  466. Lan9118MmioWrite32 (LAN9118_GPIO_CFG, GpioConf);
  467. }
  468. return EFI_SUCCESS;
  469. }
  470. // Configure flow control
  471. EFI_STATUS
  472. ConfigureFlow (
  473. UINT32 Flags,
  474. UINT32 HighTrig,
  475. UINT32 LowTrig,
  476. UINT32 BPDuration,
  477. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  478. )
  479. {
  480. return EFI_SUCCESS;
  481. }
  482. // Do auto-negotiation
  483. EFI_STATUS
  484. AutoNegotiate (
  485. UINT32 Flags,
  486. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  487. )
  488. {
  489. UINT32 PhyControl;
  490. UINT32 PhyStatus;
  491. UINT32 Features;
  492. UINT32 Retries;
  493. // First check that auto-negotiation is supported
  494. PhyStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS);
  495. if ((PhyStatus & PHYSTS_AUTO_CAP) == 0) {
  496. DEBUG ((EFI_D_ERROR, "Auto-negotiation not supported.\n"));
  497. return EFI_DEVICE_ERROR;
  498. }
  499. // Check that link is up first
  500. if ((PhyStatus & PHYSTS_LINK_STS) == 0) {
  501. // Wait until it is up or until Time Out
  502. Retries = FixedPcdGet32 (PcdLan9118DefaultNegotiationTimeout) / LAN9118_STALL;
  503. while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_LINK_STS) == 0) {
  504. gBS->Stall (LAN9118_STALL);
  505. Retries--;
  506. if (!Retries) {
  507. DEBUG ((EFI_D_ERROR, "Link timeout in auto-negotiation.\n"));
  508. return EFI_TIMEOUT;
  509. }
  510. }
  511. }
  512. // Configure features to advertise
  513. Features = IndirectPHYRead32 (PHY_INDEX_AUTO_NEG_ADVERT);
  514. if ((Flags & AUTO_NEGOTIATE_ADVERTISE_ALL) > 0) {
  515. // Link speed capabilities
  516. Features |= (PHYANA_10BASET | PHYANA_10BASETFD | PHYANA_100BASETX | PHYANA_100BASETXFD);
  517. // Pause frame capabilities
  518. Features &= ~(PHYANA_PAUSE_OP_MASK);
  519. Features |= 3 << 10;
  520. }
  521. Features &= FixedPcdGet32 (PcdLan9118NegotiationFeatureMask);
  522. // Write the features
  523. IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT, Features);
  524. // Read control register
  525. PhyControl = IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL);
  526. // Enable Auto-Negotiation
  527. if ((PhyControl & PHYCR_AUTO_EN) == 0) {
  528. PhyControl |= PHYCR_AUTO_EN;
  529. }
  530. // Restart auto-negotiation
  531. PhyControl |= PHYCR_RST_AUTO;
  532. // Enable collision test if required to do so
  533. if (Flags & AUTO_NEGOTIATE_COLLISION_TEST) {
  534. PhyControl |= PHYCR_COLL_TEST;
  535. } else {
  536. PhyControl &= ~ PHYCR_COLL_TEST;
  537. }
  538. // Write this configuration
  539. IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PhyControl);
  540. // Wait until process has completed
  541. while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) == 0);
  542. return EFI_SUCCESS;
  543. }
  544. // Check the Link Status and take appropriate action
  545. EFI_STATUS
  546. CheckLinkStatus (
  547. UINT32 Flags,
  548. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  549. )
  550. {
  551. // Get the PHY Status
  552. UINT32 PhyBStatus = IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS);
  553. if (PhyBStatus & PHYSTS_LINK_STS) {
  554. return EFI_SUCCESS;
  555. } else {
  556. return EFI_DEVICE_ERROR;
  557. }
  558. }
  559. // Stop the transmitter
  560. EFI_STATUS
  561. StopTx (
  562. UINT32 Flags,
  563. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  564. )
  565. {
  566. UINT32 MacCsr;
  567. UINT32 TxCfg;
  568. MacCsr = 0;
  569. TxCfg = 0;
  570. // Check if we want to clear tx
  571. if (Flags & STOP_TX_CLEAR) {
  572. TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
  573. TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP;
  574. Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
  575. }
  576. // Check if already stopped
  577. if (Flags & STOP_TX_MAC) {
  578. MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
  579. if (MacCsr & MACCR_TX_EN) {
  580. MacCsr &= ~MACCR_TX_EN;
  581. IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
  582. }
  583. }
  584. if (Flags & STOP_TX_CFG) {
  585. TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
  586. if (TxCfg & TXCFG_TX_ON) {
  587. TxCfg |= TXCFG_STOP_TX;
  588. Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
  589. // Wait for Tx to finish transmitting
  590. while (Lan9118MmioRead32 (LAN9118_TX_CFG) & TXCFG_STOP_TX);
  591. }
  592. }
  593. return EFI_SUCCESS;
  594. }
  595. // Stop the receiver
  596. EFI_STATUS
  597. StopRx (
  598. UINT32 Flags,
  599. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  600. )
  601. {
  602. UINT32 MacCsr;
  603. UINT32 RxCfg;
  604. RxCfg = 0;
  605. // Check if already stopped
  606. MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
  607. if (MacCsr & MACCR_RX_EN) {
  608. MacCsr &= ~ MACCR_RX_EN;
  609. IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
  610. }
  611. // Check if we want to clear receiver FIFOs
  612. if (Flags & STOP_RX_CLEAR) {
  613. RxCfg = Lan9118MmioRead32 (LAN9118_RX_CFG);
  614. RxCfg |= RXCFG_RX_DUMP;
  615. Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfg);
  616. while (Lan9118MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP);
  617. }
  618. return EFI_SUCCESS;
  619. }
  620. // Start the transmitter
  621. EFI_STATUS
  622. StartTx (
  623. UINT32 Flags,
  624. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  625. )
  626. {
  627. UINT32 MacCsr;
  628. UINT32 TxCfg;
  629. MacCsr = 0;
  630. TxCfg = 0;
  631. // Check if we want to clear tx
  632. if (Flags & START_TX_CLEAR) {
  633. TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
  634. TxCfg |= TXCFG_TXS_DUMP | TXCFG_TXD_DUMP;
  635. Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
  636. }
  637. // Check if tx was started from MAC and enable if not
  638. if (Flags & START_TX_MAC) {
  639. MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
  640. if ((MacCsr & MACCR_TX_EN) == 0) {
  641. MacCsr |= MACCR_TX_EN;
  642. IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
  643. }
  644. }
  645. // Check if tx was started from TX_CFG and enable if not
  646. if (Flags & START_TX_CFG) {
  647. TxCfg = Lan9118MmioRead32 (LAN9118_TX_CFG);
  648. if ((TxCfg & TXCFG_TX_ON) == 0) {
  649. TxCfg |= TXCFG_TX_ON;
  650. Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg);
  651. }
  652. }
  653. // Set the tx data trigger level
  654. return EFI_SUCCESS;
  655. }
  656. // Start the receiver
  657. EFI_STATUS
  658. StartRx (
  659. UINT32 Flags,
  660. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  661. )
  662. {
  663. UINT32 MacCsr;
  664. UINT32 RxCfg;
  665. RxCfg = 0;
  666. // Check if already started
  667. MacCsr = IndirectMACRead32 (INDIRECT_MAC_INDEX_CR);
  668. if ((MacCsr & MACCR_RX_EN) == 0) {
  669. // Check if we want to clear receiver FIFOs before starting
  670. if (Flags & START_RX_CLEAR) {
  671. RxCfg = Lan9118MmioRead32 (LAN9118_RX_CFG);
  672. RxCfg |= RXCFG_RX_DUMP;
  673. Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfg);
  674. while (Lan9118MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP);
  675. }
  676. MacCsr |= MACCR_RX_EN;
  677. IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr);
  678. }
  679. return EFI_SUCCESS;
  680. }
  681. // Check Tx Data available space
  682. UINT32
  683. TxDataFreeSpace (
  684. UINT32 Flags,
  685. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  686. )
  687. {
  688. UINT32 TxInf;
  689. UINT32 FreeSpace;
  690. // Get the amount of free space from information register
  691. TxInf = Lan9118MmioRead32 (LAN9118_TX_FIFO_INF);
  692. FreeSpace = (TxInf & TXFIFOINF_TDFREE_MASK);
  693. return FreeSpace; // Value in bytes
  694. }
  695. // Check Tx Status used space
  696. UINT32
  697. TxStatusUsedSpace (
  698. UINT32 Flags,
  699. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  700. )
  701. {
  702. UINT32 TxInf;
  703. UINT32 UsedSpace;
  704. // Get the amount of used space from information register
  705. TxInf = Lan9118MmioRead32 (LAN9118_TX_FIFO_INF);
  706. UsedSpace = (TxInf & TXFIFOINF_TXSUSED_MASK) >> 16;
  707. return UsedSpace << 2; // Value in bytes
  708. }
  709. // Check Rx Data used space
  710. UINT32
  711. RxDataUsedSpace (
  712. UINT32 Flags,
  713. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  714. )
  715. {
  716. UINT32 RxInf;
  717. UINT32 UsedSpace;
  718. // Get the amount of used space from information register
  719. RxInf = Lan9118MmioRead32 (LAN9118_RX_FIFO_INF);
  720. UsedSpace = (RxInf & RXFIFOINF_RXDUSED_MASK);
  721. return UsedSpace; // Value in bytes (rounded up to nearest DWORD)
  722. }
  723. // Check Rx Status used space
  724. UINT32
  725. RxStatusUsedSpace (
  726. UINT32 Flags,
  727. EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  728. )
  729. {
  730. UINT32 RxInf;
  731. UINT32 UsedSpace;
  732. // Get the amount of used space from information register
  733. RxInf = Lan9118MmioRead32 (LAN9118_RX_FIFO_INF);
  734. UsedSpace = (RxInf & RXFIFOINF_RXSUSED_MASK) >> 16;
  735. return UsedSpace << 2; // Value in bytes
  736. }
  737. // Change the allocation of FIFOs
  738. EFI_STATUS
  739. ChangeFifoAllocation (
  740. IN UINT32 Flags,
  741. IN OUT UINTN *TxDataSize OPTIONAL,
  742. IN OUT UINTN *RxDataSize OPTIONAL,
  743. IN OUT UINT32 *TxStatusSize OPTIONAL,
  744. IN OUT UINT32 *RxStatusSize OPTIONAL,
  745. IN OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp
  746. )
  747. {
  748. UINT32 HwConf;
  749. UINT32 TxFifoOption;
  750. // Check that desired sizes don't exceed limits
  751. if (*TxDataSize > TX_FIFO_MAX_SIZE)
  752. return EFI_INVALID_PARAMETER;
  753. #if defined(RX_FIFO_MIN_SIZE) && defined(RX_FIFO_MAX_SIZE)
  754. if (*RxDataSize > RX_FIFO_MAX_SIZE) {
  755. return EFI_INVALID_PARAMETER;
  756. }
  757. #endif
  758. if (Flags & ALLOC_USE_DEFAULT) {
  759. return EFI_SUCCESS;
  760. }
  761. // If we use the FIFOs (always use this first)
  762. if (Flags & ALLOC_USE_FIFOS) {
  763. // Read the current value of allocation
  764. HwConf = Lan9118MmioRead32 (LAN9118_HW_CFG);
  765. TxFifoOption = (HwConf >> 16) & 0xF;
  766. // Choose the correct size (always use larger than requested if possible)
  767. if (*TxDataSize < TX_FIFO_MIN_SIZE) {
  768. *TxDataSize = TX_FIFO_MIN_SIZE;
  769. *RxDataSize = 13440;
  770. *RxStatusSize = 896;
  771. TxFifoOption = 2;
  772. } else if ((*TxDataSize > TX_FIFO_MIN_SIZE) && (*TxDataSize <= 2560)) {
  773. *TxDataSize = 2560;
  774. *RxDataSize = 12480;
  775. *RxStatusSize = 832;
  776. TxFifoOption = 3;
  777. } else if ((*TxDataSize > 2560) && (*TxDataSize <= 3584)) {
  778. *TxDataSize = 3584;
  779. *RxDataSize = 11520;
  780. *RxStatusSize = 768;
  781. TxFifoOption = 4;
  782. } else if ((*TxDataSize > 3584) && (*TxDataSize <= 4608)) { // default option
  783. *TxDataSize = 4608;
  784. *RxDataSize = 10560;
  785. *RxStatusSize = 704;
  786. TxFifoOption = 5;
  787. } else if ((*TxDataSize > 4608) && (*TxDataSize <= 5632)) {
  788. *TxDataSize = 5632;
  789. *RxDataSize = 9600;
  790. *RxStatusSize = 640;
  791. TxFifoOption = 6;
  792. } else if ((*TxDataSize > 5632) && (*TxDataSize <= 6656)) {
  793. *TxDataSize = 6656;
  794. *RxDataSize = 8640;
  795. *RxStatusSize = 576;
  796. TxFifoOption = 7;
  797. } else if ((*TxDataSize > 6656) && (*TxDataSize <= 7680)) {
  798. *TxDataSize = 7680;
  799. *RxDataSize = 7680;
  800. *RxStatusSize = 512;
  801. TxFifoOption = 8;
  802. } else if ((*TxDataSize > 7680) && (*TxDataSize <= 8704)) {
  803. *TxDataSize = 8704;
  804. *RxDataSize = 6720;
  805. *RxStatusSize = 448;
  806. TxFifoOption = 9;
  807. } else if ((*TxDataSize > 8704) && (*TxDataSize <= 9728)) {
  808. *TxDataSize = 9728;
  809. *RxDataSize = 5760;
  810. *RxStatusSize = 384;
  811. TxFifoOption = 10;
  812. } else if ((*TxDataSize > 9728) && (*TxDataSize <= 10752)) {
  813. *TxDataSize = 10752;
  814. *RxDataSize = 4800;
  815. *RxStatusSize = 320;
  816. TxFifoOption = 11;
  817. } else if ((*TxDataSize > 10752) && (*TxDataSize <= 11776)) {
  818. *TxDataSize = 11776;
  819. *RxDataSize = 3840;
  820. *RxStatusSize = 256;
  821. TxFifoOption = 12;
  822. } else if ((*TxDataSize > 11776) && (*TxDataSize <= 12800)) {
  823. *TxDataSize = 12800;
  824. *RxDataSize = 2880;
  825. *RxStatusSize = 192;
  826. TxFifoOption = 13;
  827. } else if ((*TxDataSize > 12800) && (*TxDataSize <= 13824)) {
  828. *TxDataSize = 13824;
  829. *RxDataSize = 1920;
  830. *RxStatusSize = 128;
  831. TxFifoOption = 14;
  832. }
  833. } else {
  834. ASSERT(0); // Untested code path
  835. HwConf = 0;
  836. TxFifoOption = 0;
  837. }
  838. // Do we need DMA?
  839. if (Flags & ALLOC_USE_DMA) {
  840. return EFI_UNSUPPORTED; // Unsupported as of now
  841. }
  842. // Clear and assign the new size option
  843. HwConf &= ~(0xF0000);
  844. HwConf |= ((TxFifoOption & 0xF) << 16);
  845. Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf);
  846. return EFI_SUCCESS;
  847. }