3 * Copyright (c) 2012-2014, ARM Limited. All rights reserved.
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "Lan9118Dxe.h"
17 STATIC EFI_MAC_ADDRESS mZeroMac
= { { 0 } };
20 This internal function reverses bits for 32bit data.
22 @param Value The data to be reversed.
24 @return Data reversed.
36 for (Index
= 0; Index
< 32; Index
++) {
37 if ((Value
& (1 << Index
)) != 0) {
38 NewValue
= NewValue
| (1 << (31 - Index
));
46 ** Create Ethernet CRC
49 ** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check
51 ** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html
53 ** 3: http://en.wikipedia.org/wiki/Computation_of_CRC
57 IN EFI_MAC_ADDRESS
*Mac
,
66 Remainder
= 0xFFFFFFFF; // 0xFFFFFFFF is standard seed for Ethernet
68 // Convert Mac Address to array of bytes
71 // Generate the Crc bit-by-bit (LSB first)
74 for (Iter
= 0;Iter
< 8;Iter
++) {
75 // Check if exponent is set
77 Remainder
= (Remainder
>> 1) ^ CRC_POLYNOMIAL
;
79 Remainder
= (Remainder
>> 1) ^ 0;
84 // Reverse the bits before returning (to Big Endian)
85 //TODO: Need to be reviewed. Do we want to do a bit reverse or a byte reverse (in this case use SwapBytes32())
86 return ReverseBits (Remainder
);
89 // Function to read from MAC indirect registers
97 // Check index is in the range
100 // Wait until CSR busy bit is cleared
101 while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD
) & MAC_CSR_BUSY
) == MAC_CSR_BUSY
);
103 // Set CSR busy bit to ensure read will occur
104 // Set the R/W bit to indicate we are reading
105 // Set the index of CSR Address to access desired register
106 MacCSR
= MAC_CSR_BUSY
| MAC_CSR_READ
| MAC_CSR_ADDR(Index
);
108 // Write to the register
109 Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD
, MacCSR
);
111 // Wait until CSR busy bit is cleared
112 while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD
) & MAC_CSR_BUSY
) == MAC_CSR_BUSY
);
114 // Now read from data register to get read value
115 return Lan9118MmioRead32 (LAN9118_MAC_CSR_DATA
);
119 * LAN9118 chips have special restrictions on some back-to-back Write/Read or
120 * Read/Read pairs of accesses. After a read or write that changes the state of
121 * the device, there is a period in which stale values may be returned in
122 * response to a read. This period is dependent on the registers accessed.
124 * We must delay prior reads by this period. This can either be achieved by
125 * timer-based delays, or by performing dummy reads of the BYTE_TEST register,
126 * for which the recommended number of reads is described in the LAN9118 data
127 * sheet. This is required in addition to any memory barriers.
129 * This function performs a number of dummy reads of the BYTE_TEST register, as
130 * a building block for the above.
138 MmioRead32(LAN9118_BYTE_TEST
);
142 Lan9118RawMmioRead32(
149 Value
= MmioRead32(Address
);
150 WaitDummyReads(Delay
);
155 Lan9118RawMmioWrite32(
161 MmioWrite32(Address
, Value
);
162 WaitDummyReads(Delay
);
166 // Function to write to MAC indirect registers
176 // Check index is in the range
179 // Wait until CSR busy bit is cleared
180 while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD
) & MAC_CSR_BUSY
) == MAC_CSR_BUSY
);
182 // Set CSR busy bit to ensure read will occur
183 // Set the R/W bit to indicate we are writing
184 // Set the index of CSR Address to access desired register
185 MacCSR
= MAC_CSR_BUSY
| MAC_CSR_WRITE
| MAC_CSR_ADDR(Index
);
187 // Now write the value to the register before issuing the write command
188 ValueWritten
= Lan9118MmioWrite32 (LAN9118_MAC_CSR_DATA
, Value
);
190 // Write the config to the register
191 Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD
, MacCSR
);
193 // Wait until CSR busy bit is cleared
194 while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD
) & MAC_CSR_BUSY
) == MAC_CSR_BUSY
);
199 // Function to read from MII register (PHY Access)
208 // Check it is a valid index
211 // Wait for busy bit to clear
212 while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC
) & MII_ACC_MII_BUSY
) == MII_ACC_MII_BUSY
);
214 // Clear the R/W bit to indicate we are reading
215 // Set the index of the MII register
216 // Set the PHY Address
217 // Set the MII busy bit to allow read
218 MiiAcc
= MII_ACC_MII_READ
| MII_ACC_MII_REG_INDEX(Index
) | MII_ACC_PHY_VALUE
| MII_ACC_MII_BUSY
;
220 // Now write this config to register
221 IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC
, MiiAcc
& 0xFFFF);
223 // Wait for busy bit to clear
224 while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC
) & MII_ACC_MII_BUSY
) == MII_ACC_MII_BUSY
);
226 // Now read the value of the register
227 ValueRead
= (IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_DATA
) & 0xFFFF); // only lower 16 bits are valid for any PHY register
233 // Function to write to the MII register (PHY Access)
243 // Check it is a valid index
246 // Wait for busy bit to clear
247 while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC
) & MII_ACC_MII_BUSY
) == MII_ACC_MII_BUSY
);
249 // Clear the R/W bit to indicate we are reading
250 // Set the index of the MII register
251 // Set the PHY Address
252 // Set the MII busy bit to allow read
253 MiiAcc
= MII_ACC_MII_WRITE
| MII_ACC_MII_REG_INDEX(Index
) | MII_ACC_PHY_VALUE
| MII_ACC_MII_BUSY
;
255 // Write the desired value to the register first
256 ValueWritten
= IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_DATA
, (Value
& 0xFFFF));
258 // Now write the config to register
259 IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC
, MiiAcc
& 0xFFFF);
261 // Wait for operation to terminate
262 while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC
) & MII_ACC_MII_BUSY
) == MII_ACC_MII_BUSY
);
268 /* ---------------- EEPROM Operations ------------------ */
271 // Function to read from EEPROM memory
273 IndirectEEPROMRead32 (
279 // Set the busy bit to ensure read will occur
280 EepromCmd
= E2P_EPC_BUSY
| E2P_EPC_CMD_READ
;
282 // Set the index to access desired EEPROM memory location
283 EepromCmd
|= E2P_EPC_ADDRESS(Index
);
285 // Write to Eeprom command register
286 Lan9118MmioWrite32 (LAN9118_E2P_CMD
, EepromCmd
);
288 // Wait until operation has completed
289 while (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_BUSY
);
291 // Check that operation didn't time out
292 if (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_TIMEOUT
) {
293 DEBUG ((EFI_D_ERROR
, "EEPROM Operation Timed out: Read command on index %x\n",Index
));
297 // Wait until operation has completed
298 while (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_BUSY
);
300 // Finally read the value
301 return Lan9118MmioRead32 (LAN9118_E2P_DATA
);
304 // Function to write to EEPROM memory
306 IndirectEEPROMWrite32 (
316 // Read the EEPROM Command register
317 EepromCmd
= Lan9118MmioRead32 (LAN9118_E2P_CMD
);
319 // Set the busy bit to ensure read will occur
320 EepromCmd
|= ((UINT32
)1 << 31);
322 // Set the EEPROM command to write(0b011)
323 EepromCmd
&= ~(7 << 28); // Clear the command first
324 EepromCmd
|= (3 << 28); // Write 011
326 // Set the index to access desired EEPROM memory location
327 EepromCmd
|= (Index
& 0xF);
329 // Write the value to the data register first
330 ValueWritten
= Lan9118MmioWrite32 (LAN9118_E2P_DATA
, Value
);
332 // Write to Eeprom command register
333 Lan9118MmioWrite32 (LAN9118_E2P_CMD
, EepromCmd
);
335 // Wait until operation has completed
336 while (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_BUSY
);
338 // Check that operation didn't time out
339 if (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_TIMEOUT
) {
340 DEBUG ((EFI_D_ERROR
, "EEPROM Operation Timed out: Write command at memloc 0x%x, with value 0x%x\n",Index
, Value
));
344 // Wait until operation has completed
345 while (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_BUSY
);
350 /* ---------------- General Operations ----------------- */
353 Lan9118SetMacAddress (
354 EFI_MAC_ADDRESS
*Mac
,
355 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
358 IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL
,
359 (Mac
->Addr
[0] & 0xFF) |
360 ((Mac
->Addr
[1] & 0xFF) << 8) |
361 ((Mac
->Addr
[2] & 0xFF) << 16) |
362 ((Mac
->Addr
[3] & 0xFF) << 24)
365 IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH
,
366 (UINT32
)(Mac
->Addr
[4] & 0xFF) |
367 ((Mac
->Addr
[5] & 0xFF) << 8)
372 Lan9118ReadMacAddress (
373 OUT EFI_MAC_ADDRESS
*MacAddress
376 UINT32 MacAddrHighValue
;
377 UINT32 MacAddrLowValue
;
379 // Read the Mac Addr high register
380 MacAddrHighValue
= (IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRH
) & 0xFFFF);
381 // Read the Mac Addr low register
382 MacAddrLowValue
= IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRL
);
384 SetMem (MacAddress
, sizeof(*MacAddress
), 0);
385 MacAddress
->Addr
[0] = (MacAddrLowValue
& 0xFF);
386 MacAddress
->Addr
[1] = (MacAddrLowValue
& 0xFF00) >> 8;
387 MacAddress
->Addr
[2] = (MacAddrLowValue
& 0xFF0000) >> 16;
388 MacAddress
->Addr
[3] = (MacAddrLowValue
& 0xFF000000) >> 24;
389 MacAddress
->Addr
[4] = (MacAddrHighValue
& 0xFF);
390 MacAddress
->Addr
[5] = (MacAddrHighValue
& 0xFF00) >> 8;
394 * Power up the 9118 and find its MAC address.
396 * This operation can be carried out when the LAN9118 is in any power state
401 IN EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
405 UINT64 DefaultMacAddress
;
407 // Attempt to wake-up the device if it is in a lower power state
408 if (((Lan9118MmioRead32 (LAN9118_PMT_CTRL
) & MPTCTRL_PM_MODE_MASK
) >> 12) != 0) {
409 DEBUG ((DEBUG_NET
, "Waking from reduced power state.\n"));
410 Lan9118MmioWrite32 (LAN9118_BYTE_TEST
, 0xFFFFFFFF);
413 // Check that device is active
415 while ((Lan9118MmioRead32 (LAN9118_PMT_CTRL
) & MPTCTRL_READY
) == 0 && --Retries
) {
416 gBS
->Stall (LAN9118_STALL
);
422 // Check that EEPROM isn't active
424 while ((Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_BUSY
) && --Retries
){
425 gBS
->Stall (LAN9118_STALL
);
431 // Check if a MAC address was loaded from EEPROM, and if it was, set it as the
433 if ((Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_MAC_ADDRESS_LOADED
) == 0) {
434 DEBUG ((EFI_D_ERROR
, "Warning: There was an error detecting EEPROM or loading the MAC Address.\n"));
436 // If we had an address before (set by StationAddess), continue to use it
437 if (CompareMem (&Snp
->Mode
->CurrentAddress
, &mZeroMac
, NET_ETHER_ADDR_LEN
)) {
438 Lan9118SetMacAddress (&Snp
->Mode
->CurrentAddress
, Snp
);
440 // If there are no cached addresses, then fall back to a default
441 DEBUG ((EFI_D_WARN
, "Warning: using driver-default MAC address\n"));
442 DefaultMacAddress
= FixedPcdGet64 (PcdLan9118DefaultMacAddress
);
443 Lan9118SetMacAddress((EFI_MAC_ADDRESS
*) &DefaultMacAddress
, Snp
);
444 CopyMem (&Snp
->Mode
->CurrentAddress
, &DefaultMacAddress
, NET_ETHER_ADDR_LEN
);
447 // Store the MAC address that was loaded from EEPROM
448 Lan9118ReadMacAddress (&Snp
->Mode
->CurrentAddress
);
449 CopyMem (&Snp
->Mode
->PermanentAddress
, &Snp
->Mode
->CurrentAddress
, NET_ETHER_ADDR_LEN
);
452 // Clear and acknowledge interrupts
453 Lan9118MmioWrite32 (LAN9118_INT_EN
, 0);
454 Lan9118MmioWrite32 (LAN9118_IRQ_CFG
, 0);
455 Lan9118MmioWrite32 (LAN9118_INT_STS
, 0xFFFFFFFF);
457 // Do self tests here?
463 // Perform software reset on the LAN9118
464 // Return 0 on success, -1 on error
468 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
474 // Initialize variable
478 StopTx (STOP_TX_MAC
| STOP_TX_CFG
| STOP_TX_CLEAR
, Snp
);
479 StopRx (STOP_RX_CLEAR
, Snp
); // Clear receiver FIFO
482 HwConf
= Lan9118MmioRead32 (LAN9118_HW_CFG
);
485 // Set the Must Be One (MBO) bit
486 if (((HwConf
& HWCFG_MBO
) >> 20) == 0) {
490 // Check that EEPROM isn't active
491 while (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_BUSY
);
493 // Write the configuration
494 Lan9118MmioWrite32 (LAN9118_HW_CFG
, HwConf
);
496 // Wait for reset to complete
497 while (Lan9118MmioRead32 (LAN9118_HW_CFG
) & HWCFG_SRST
) {
499 gBS
->Stall (LAN9118_STALL
);
502 // If time taken exceeds 100us, then there was an error condition
503 if (ResetTime
> 1000) {
504 Snp
->Mode
->State
= EfiSimpleNetworkStopped
;
509 // Check that EEPROM isn't active
510 while (Lan9118MmioRead32 (LAN9118_E2P_CMD
) & E2P_EPC_BUSY
);
512 // TODO we probably need to re-set the mac address here.
514 // Clear and acknowledge all interrupts
515 if (Flags
& SOFT_RESET_CLEAR_INT
) {
516 Lan9118MmioWrite32 (LAN9118_INT_EN
, 0);
517 Lan9118MmioWrite32 (LAN9118_IRQ_CFG
, 0);
518 Lan9118MmioWrite32 (LAN9118_INT_STS
, 0xFFFFFFFF);
521 // Do self tests here?
522 if (Flags
& SOFT_RESET_SELF_TEST
) {
530 // Perform PHY software reset
534 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
539 // PMT PHY reset takes precedence over BCR
540 if (Flags
& PHY_RESET_PMT
) {
541 PmtCtrl
= Lan9118MmioRead32 (LAN9118_PMT_CTRL
);
542 PmtCtrl
|= MPTCTRL_PHY_RST
;
543 Lan9118MmioWrite32 (LAN9118_PMT_CTRL
,PmtCtrl
);
545 // Wait for completion
546 while (Lan9118MmioRead32 (LAN9118_PMT_CTRL
) & MPTCTRL_PHY_RST
) {
547 gBS
->Stall (LAN9118_STALL
);
549 // PHY Basic Control Register reset
550 } else if (Flags
& PHY_RESET_BCR
) {
551 IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL
, PHYCR_RESET
);
553 // Wait for completion
554 while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL
) & PHYCR_RESET
) {
555 gBS
->Stall (LAN9118_STALL
);
559 // Clear and acknowledge all interrupts
560 if (Flags
& PHY_SOFT_RESET_CLEAR_INT
) {
561 Lan9118MmioWrite32 (LAN9118_INT_EN
, 0);
562 Lan9118MmioWrite32 (LAN9118_IRQ_CFG
, 0);
563 Lan9118MmioWrite32 (LAN9118_INT_STS
, 0xFFFFFFFF);
570 // Configure hardware for LAN9118
574 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
579 // Check if we want to use LEDs on GPIO
580 if (Flags
& HW_CONF_USE_LEDS
) {
581 GpioConf
= Lan9118MmioRead32 (LAN9118_GPIO_CFG
);
583 // Enable GPIO as LEDs and Config as Push-Pull driver
584 GpioConf
|= GPIO_GPIO0_PUSH_PULL
| GPIO_GPIO1_PUSH_PULL
| GPIO_GPIO2_PUSH_PULL
|
585 GPIO_LED1_ENABLE
| GPIO_LED2_ENABLE
| GPIO_LED3_ENABLE
;
587 // Write the configuration
588 Lan9118MmioWrite32 (LAN9118_GPIO_CFG
, GpioConf
);
594 // Configure flow control
601 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
607 // Do auto-negotiation
611 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
619 // First check that auto-negotiation is supported
620 PhyStatus
= IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS
);
621 if ((PhyStatus
& PHYSTS_AUTO_CAP
) == 0) {
622 DEBUG ((EFI_D_ERROR
, "Auto-negotiation not supported.\n"));
623 return EFI_DEVICE_ERROR
;
626 // Check that link is up first
627 if ((PhyStatus
& PHYSTS_LINK_STS
) == 0) {
628 // Wait until it is up or until Time Out
629 Retries
= FixedPcdGet32 (PcdLan9118DefaultNegotiationTimeout
) / LAN9118_STALL
;
630 while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS
) & PHYSTS_LINK_STS
) == 0) {
631 gBS
->Stall (LAN9118_STALL
);
634 DEBUG ((EFI_D_ERROR
, "Link timeout in auto-negotiation.\n"));
640 // Configure features to advertise
641 Features
= IndirectPHYRead32 (PHY_INDEX_AUTO_NEG_ADVERT
);
643 if ((Flags
& AUTO_NEGOTIATE_ADVERTISE_ALL
) > 0) {
644 // Link speed capabilities
645 Features
|= (PHYANA_10BASET
| PHYANA_10BASETFD
| PHYANA_100BASETX
| PHYANA_100BASETXFD
);
647 // Pause frame capabilities
648 Features
&= ~(PHYANA_PAUSE_OP_MASK
);
651 Features
&= FixedPcdGet32 (PcdLan9118NegotiationFeatureMask
);
653 // Write the features
654 IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT
, Features
);
656 // Read control register
657 PhyControl
= IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL
);
659 // Enable Auto-Negotiation
660 if ((PhyControl
& PHYCR_AUTO_EN
) == 0) {
661 PhyControl
|= PHYCR_AUTO_EN
;
664 // Restart auto-negotiation
665 PhyControl
|= PHYCR_RST_AUTO
;
667 // Enable collision test if required to do so
668 if (Flags
& AUTO_NEGOTIATE_COLLISION_TEST
) {
669 PhyControl
|= PHYCR_COLL_TEST
;
671 PhyControl
&= ~ PHYCR_COLL_TEST
;
674 // Write this configuration
675 IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL
, PhyControl
);
677 // Wait until process has completed
678 while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS
) & PHYSTS_AUTO_COMP
) == 0);
683 // Check the Link Status and take appropriate action
687 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
690 // Get the PHY Status
691 UINT32 PhyBStatus
= IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS
);
693 if (PhyBStatus
& PHYSTS_LINK_STS
) {
696 return EFI_DEVICE_ERROR
;
700 // Stop the transmitter
704 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
713 // Check if we want to clear tx
714 if (Flags
& STOP_TX_CLEAR
) {
715 TxCfg
= Lan9118MmioRead32 (LAN9118_TX_CFG
);
716 TxCfg
|= TXCFG_TXS_DUMP
| TXCFG_TXD_DUMP
;
717 Lan9118MmioWrite32 (LAN9118_TX_CFG
, TxCfg
);
720 // Check if already stopped
721 if (Flags
& STOP_TX_MAC
) {
722 MacCsr
= IndirectMACRead32 (INDIRECT_MAC_INDEX_CR
);
724 if (MacCsr
& MACCR_TX_EN
) {
725 MacCsr
&= ~MACCR_TX_EN
;
726 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR
, MacCsr
);
730 if (Flags
& STOP_TX_CFG
) {
731 TxCfg
= Lan9118MmioRead32 (LAN9118_TX_CFG
);
733 if (TxCfg
& TXCFG_TX_ON
) {
734 TxCfg
|= TXCFG_STOP_TX
;
735 Lan9118MmioWrite32 (LAN9118_TX_CFG
, TxCfg
);
737 // Wait for Tx to finish transmitting
738 while (Lan9118MmioRead32 (LAN9118_TX_CFG
) & TXCFG_STOP_TX
);
749 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
757 // Check if already stopped
758 MacCsr
= IndirectMACRead32 (INDIRECT_MAC_INDEX_CR
);
760 if (MacCsr
& MACCR_RX_EN
) {
761 MacCsr
&= ~ MACCR_RX_EN
;
762 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR
, MacCsr
);
765 // Check if we want to clear receiver FIFOs
766 if (Flags
& STOP_RX_CLEAR
) {
767 RxCfg
= Lan9118MmioRead32 (LAN9118_RX_CFG
);
768 RxCfg
|= RXCFG_RX_DUMP
;
769 Lan9118MmioWrite32 (LAN9118_RX_CFG
, RxCfg
);
771 while (Lan9118MmioRead32 (LAN9118_RX_CFG
) & RXCFG_RX_DUMP
);
777 // Start the transmitter
781 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
790 // Check if we want to clear tx
791 if (Flags
& START_TX_CLEAR
) {
792 TxCfg
= Lan9118MmioRead32 (LAN9118_TX_CFG
);
793 TxCfg
|= TXCFG_TXS_DUMP
| TXCFG_TXD_DUMP
;
794 Lan9118MmioWrite32 (LAN9118_TX_CFG
, TxCfg
);
797 // Check if tx was started from MAC and enable if not
798 if (Flags
& START_TX_MAC
) {
799 MacCsr
= IndirectMACRead32 (INDIRECT_MAC_INDEX_CR
);
800 if ((MacCsr
& MACCR_TX_EN
) == 0) {
801 MacCsr
|= MACCR_TX_EN
;
802 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR
, MacCsr
);
806 // Check if tx was started from TX_CFG and enable if not
807 if (Flags
& START_TX_CFG
) {
808 TxCfg
= Lan9118MmioRead32 (LAN9118_TX_CFG
);
809 if ((TxCfg
& TXCFG_TX_ON
) == 0) {
810 TxCfg
|= TXCFG_TX_ON
;
811 Lan9118MmioWrite32 (LAN9118_TX_CFG
, TxCfg
);
815 // Set the tx data trigger level
820 // Start the receiver
824 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
832 // Check if already started
833 MacCsr
= IndirectMACRead32 (INDIRECT_MAC_INDEX_CR
);
835 if ((MacCsr
& MACCR_RX_EN
) == 0) {
836 // Check if we want to clear receiver FIFOs before starting
837 if (Flags
& START_RX_CLEAR
) {
838 RxCfg
= Lan9118MmioRead32 (LAN9118_RX_CFG
);
839 RxCfg
|= RXCFG_RX_DUMP
;
840 Lan9118MmioWrite32 (LAN9118_RX_CFG
, RxCfg
);
842 while (Lan9118MmioRead32 (LAN9118_RX_CFG
) & RXCFG_RX_DUMP
);
845 MacCsr
|= MACCR_RX_EN
;
846 IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR
, MacCsr
);
852 // Check Tx Data available space
856 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
862 // Get the amount of free space from information register
863 TxInf
= Lan9118MmioRead32 (LAN9118_TX_FIFO_INF
);
864 FreeSpace
= (TxInf
& TXFIFOINF_TDFREE_MASK
);
866 return FreeSpace
; // Value in bytes
869 // Check Tx Status used space
873 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
879 // Get the amount of used space from information register
880 TxInf
= Lan9118MmioRead32 (LAN9118_TX_FIFO_INF
);
881 UsedSpace
= (TxInf
& TXFIFOINF_TXSUSED_MASK
) >> 16;
883 return UsedSpace
<< 2; // Value in bytes
886 // Check Rx Data used space
890 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
896 // Get the amount of used space from information register
897 RxInf
= Lan9118MmioRead32 (LAN9118_RX_FIFO_INF
);
898 UsedSpace
= (RxInf
& RXFIFOINF_RXDUSED_MASK
);
900 return UsedSpace
; // Value in bytes (rounded up to nearest DWORD)
903 // Check Rx Status used space
907 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
913 // Get the amount of used space from information register
914 RxInf
= Lan9118MmioRead32 (LAN9118_RX_FIFO_INF
);
915 UsedSpace
= (RxInf
& RXFIFOINF_RXSUSED_MASK
) >> 16;
917 return UsedSpace
<< 2; // Value in bytes
921 // Change the allocation of FIFOs
923 ChangeFifoAllocation (
925 IN OUT UINTN
*TxDataSize OPTIONAL
,
926 IN OUT UINTN
*RxDataSize OPTIONAL
,
927 IN OUT UINT32
*TxStatusSize OPTIONAL
,
928 IN OUT UINT32
*RxStatusSize OPTIONAL
,
929 IN OUT EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
935 // Check that desired sizes don't exceed limits
936 if (*TxDataSize
> TX_FIFO_MAX_SIZE
)
937 return EFI_INVALID_PARAMETER
;
939 #if defined(RX_FIFO_MIN_SIZE) && defined(RX_FIFO_MAX_SIZE)
940 if (*RxDataSize
> RX_FIFO_MAX_SIZE
) {
941 return EFI_INVALID_PARAMETER
;
945 if (Flags
& ALLOC_USE_DEFAULT
) {
949 // If we use the FIFOs (always use this first)
950 if (Flags
& ALLOC_USE_FIFOS
) {
951 // Read the current value of allocation
952 HwConf
= Lan9118MmioRead32 (LAN9118_HW_CFG
);
953 TxFifoOption
= (HwConf
>> 16) & 0xF;
955 // Choose the correct size (always use larger than requested if possible)
956 if (*TxDataSize
< TX_FIFO_MIN_SIZE
) {
957 *TxDataSize
= TX_FIFO_MIN_SIZE
;
961 } else if ((*TxDataSize
> TX_FIFO_MIN_SIZE
) && (*TxDataSize
<= 2560)) {
966 } else if ((*TxDataSize
> 2560) && (*TxDataSize
<= 3584)) {
971 } else if ((*TxDataSize
> 3584) && (*TxDataSize
<= 4608)) { // default option
976 } else if ((*TxDataSize
> 4608) && (*TxDataSize
<= 5632)) {
981 } else if ((*TxDataSize
> 5632) && (*TxDataSize
<= 6656)) {
986 } else if ((*TxDataSize
> 6656) && (*TxDataSize
<= 7680)) {
991 } else if ((*TxDataSize
> 7680) && (*TxDataSize
<= 8704)) {
996 } else if ((*TxDataSize
> 8704) && (*TxDataSize
<= 9728)) {
1001 } else if ((*TxDataSize
> 9728) && (*TxDataSize
<= 10752)) {
1002 *TxDataSize
= 10752;
1004 *RxStatusSize
= 320;
1006 } else if ((*TxDataSize
> 10752) && (*TxDataSize
<= 11776)) {
1007 *TxDataSize
= 11776;
1009 *RxStatusSize
= 256;
1011 } else if ((*TxDataSize
> 11776) && (*TxDataSize
<= 12800)) {
1012 *TxDataSize
= 12800;
1014 *RxStatusSize
= 192;
1016 } else if ((*TxDataSize
> 12800) && (*TxDataSize
<= 13824)) {
1017 *TxDataSize
= 13824;
1019 *RxStatusSize
= 128;
1023 ASSERT(0); // Untested code path
1029 if (Flags
& ALLOC_USE_DMA
) {
1030 return EFI_UNSUPPORTED
; // Unsupported as of now
1032 // Clear and assign the new size option
1033 HwConf
&= ~(0xF0000);
1034 HwConf
|= ((TxFifoOption
& 0xF) << 16);
1035 Lan9118MmioWrite32 (LAN9118_HW_CFG
, HwConf
);