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