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