2 Implement the interface to the AX88772 Ethernet controller.
4 This module implements the interface to the ASIX AX88772
5 USB to Ethernet MAC with integrated 10/100 PHY. Note that this implementation
6 only supports the integrated PHY since no other test cases were available.
8 Copyright (c) 2011, Intel Corporation. All rights reserved.
9 SPDX-License-Identifier: BSD-2-Clause-Patent
19 @param [in] pMacAddress Address of a six byte buffer to containing the MAC address.
21 @returns The CRC-32 value associated with this MAC address
26 IN UINT8
* pMacAddress
36 // Walk the MAC address
39 pEnd
= &pMacAddress
[ PXE_HWADDR_LEN_ETHER
];
40 while ( pEnd
> pMacAddress
) {
41 Data
= *pMacAddress
++;
43 // CRC32: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
45 // 1 0000 0100 1100 0001 0001 1101 1011 0111
47 for ( BitNumber
= 0; 8 > BitNumber
; BitNumber
++ ) {
48 Carry
= (( Crc
>> 31 ) & 1 ) ^ ( Data
& 1 );
57 // Return the CRC value
66 This routine calls ::Ax88772UsbCommand to request the MAC
67 address from the network adapter.
69 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
70 @param [out] pMacAddress Address of a six byte buffer to receive the MAC address.
72 @retval EFI_SUCCESS The MAC address is available.
73 @retval other The MAC address is not valid.
77 Ax88772MacAddressGet (
78 IN NIC_DEVICE
* pNicDevice
,
79 OUT UINT8
* pMacAddress
82 USB_DEVICE_REQUEST SetupMsg
;
86 // Set the register address.
88 SetupMsg
.RequestType
= USB_ENDPOINT_DIR_IN
91 SetupMsg
.Request
= CMD_MAC_ADDRESS_READ
;
94 SetupMsg
.Length
= PXE_HWADDR_LEN_ETHER
;
97 // Read the PHY register
99 Status
= Ax88772UsbCommand ( pNicDevice
,
109 This routine calls ::Ax88772UsbCommand to set the MAC address
110 in the network adapter.
112 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
113 @param [in] pMacAddress Address of a six byte buffer to containing the new MAC address.
115 @retval EFI_SUCCESS The MAC address was set.
116 @retval other The MAC address was not set.
120 Ax88772MacAddressSet (
121 IN NIC_DEVICE
* pNicDevice
,
122 IN UINT8
* pMacAddress
125 USB_DEVICE_REQUEST SetupMsg
;
129 // Set the register address.
131 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
133 SetupMsg
.Request
= CMD_MAC_ADDRESS_WRITE
;
136 SetupMsg
.Length
= PXE_HWADDR_LEN_ETHER
;
139 // Read the PHY register
141 Status
= Ax88772UsbCommand ( pNicDevice
,
148 Clear the multicast hash table
150 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
154 Ax88772MulticastClear (
155 IN NIC_DEVICE
* pNicDevice
160 // Clear the multicast hash table
162 for ( i
= 0 ; i
< 8 ; i
++ )
163 pNicDevice
->MulticastHash
[0] = 0;
167 Enable a multicast address in the multicast hash table
169 This routine calls ::Ax88772Crc to compute the hash bit for
172 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
173 @param [in] pMacAddress Address of a six byte buffer to containing the MAC address.
177 Ax88772MulticastSet (
178 IN NIC_DEVICE
* pNicDevice
,
179 IN UINT8
* pMacAddress
185 // Compute the CRC on the destination address
187 Crc
= Ax88772Crc ( pMacAddress
) >> 26;
190 // Set the bit corresponding to the destination address
192 pNicDevice
->MulticastHash
[ Crc
>> 3 ] |= ( 1<< (Crc
& 7));
196 Start the link negotiation
198 This routine calls ::Ax88772PhyWrite to start the PHY's link
201 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
203 @retval EFI_SUCCESS The link negotiation was started.
204 @retval other Failed to start the link negotiation.
208 Ax88772NegotiateLinkStart (
209 IN NIC_DEVICE
* pNicDevice
216 // Set the supported capabilities.
218 Status
= Ax88772PhyWrite ( pNicDevice
,
221 | AN_TX_FDX
| AN_TX_HDX
222 | AN_10_FDX
| AN_10_HDX
);
223 if ( !EFI_ERROR ( Status
)) {
225 // Set the link speed and duplex
227 Control
= BMCR_AUTONEGOTIATION_ENABLE
228 | BMCR_RESTART_AUTONEGOTIATION
;
229 if ( pNicDevice
->b100Mbps
) {
230 Control
|= BMCR_100MBPS
;
232 if ( pNicDevice
->bFullDuplex
) {
233 Control
|= BMCR_FULL_DUPLEX
;
235 Status
= Ax88772PhyWrite ( pNicDevice
, PHY_BMCR
, Control
);
238 if (!EFI_ERROR(Status
)) {
242 if (pNicDevice
->bComplete
&& pNicDevice
->bLinkUp
) {
243 pNicDevice
->SimpleNetwork
.Mode
->MediaPresent
244 = pNicDevice
->bLinkUp
& pNicDevice
->bComplete
;
248 gBS
->Stall(AUTONEG_DELAY
);
249 Status
= Ax88772NegotiateLinkComplete ( pNicDevice
,
250 &pNicDevice
->PollCount
,
251 &pNicDevice
->bComplete
,
252 &pNicDevice
->bLinkUp
,
253 &pNicDevice
->b100Mbps
,
254 &pNicDevice
->bFullDuplex
);
257 }while(!pNicDevice
->bLinkUp
&& i
< AUTONEG_POLLCNT
);
264 Complete the negotiation of the PHY link
266 This routine calls ::Ax88772PhyRead to determine if the
267 link negotiation is complete.
269 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
270 @param [in, out] pPollCount Address of number of times this routine was polled
271 @param [out] pbComplete Address of boolean to receive complate status.
272 @param [out] pbLinkUp Address of boolean to receive link status, TRUE=up.
273 @param [out] pbHiSpeed Address of boolean to receive link speed, TRUE=100Mbps.
274 @param [out] pbFullDuplex Address of boolean to receive link duplex, TRUE=full.
276 @retval EFI_SUCCESS The MAC address is available.
277 @retval other The MAC address is not valid.
281 Ax88772NegotiateLinkComplete (
282 IN NIC_DEVICE
* pNicDevice
,
283 IN OUT UINTN
* pPollCount
,
284 OUT BOOLEAN
* pbComplete
,
285 OUT BOOLEAN
* pbLinkUp
,
286 OUT BOOLEAN
* pbHiSpeed
,
287 OUT BOOLEAN
* pbFullDuplex
295 // Determine if the link is up.
300 // Get the link status
302 Status
= Ax88772PhyRead ( pNicDevice
,
306 if ( !EFI_ERROR ( Status
)) {
307 *pbLinkUp
= (BOOLEAN
)( 0 != ( PhyData
& BMSR_LINKST
));
308 if ( 0 == *pbLinkUp
) {
309 DEBUG (( EFI_D_INFO
, "Link Down\n" ));
312 *pbComplete
= (BOOLEAN
)( 0 != ( PhyData
& 0x20 ));
313 if ( 0 == *pbComplete
) {
314 DEBUG (( EFI_D_INFO
, "Autoneg is not yet Complete\n" ));
317 Status
= Ax88772PhyRead ( pNicDevice
,
320 if ( !EFI_ERROR ( Status
)) {
322 // Autonegotiation is complete
323 // Determine the link speed.
325 *pbHiSpeed
= (BOOLEAN
)( 0 != ( PhyData
& ( AN_TX_FDX
| AN_TX_HDX
)));
328 // Determine the link duplex.
330 Mask
= ( *pbHiSpeed
) ? AN_TX_FDX
: AN_10_FDX
;
331 *pbFullDuplex
= (BOOLEAN
)( 0 != ( PhyData
& Mask
));
337 DEBUG (( EFI_D_ERROR
, "Failed to read BMCR\n" ));
344 Read a register from the PHY
346 This routine calls ::Ax88772UsbCommand to read a PHY register.
348 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
349 @param [in] RegisterAddress Number of the register to read.
350 @param [in, out] pPhyData Address of a buffer to receive the PHY register value
352 @retval EFI_SUCCESS The PHY data is available.
353 @retval other The PHY data is not valid.
358 IN NIC_DEVICE
* pNicDevice
,
359 IN UINT8 RegisterAddress
,
360 IN OUT UINT16
* pPhyData
363 USB_DEVICE_REQUEST SetupMsg
;
367 // Request access to the PHY
369 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
371 SetupMsg
.Request
= CMD_PHY_ACCESS_SOFTWARE
;
375 Status
= Ax88772UsbCommand ( pNicDevice
,
378 if ( !EFI_ERROR ( Status
)) {
380 // Read the PHY register address.
382 SetupMsg
.RequestType
= USB_ENDPOINT_DIR_IN
383 | USB_REQ_TYPE_VENDOR
385 SetupMsg
.Request
= CMD_PHY_REG_READ
;
386 SetupMsg
.Value
= pNicDevice
->PhyId
;
387 SetupMsg
.Index
= RegisterAddress
;
388 SetupMsg
.Length
= sizeof ( *pPhyData
);
389 Status
= Ax88772UsbCommand ( pNicDevice
,
392 if ( !EFI_ERROR ( Status
)) {
395 // Release the PHY to the hardware
397 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
399 SetupMsg
.Request
= CMD_PHY_ACCESS_HARDWARE
;
403 Status
= Ax88772UsbCommand ( pNicDevice
,
413 Write to a PHY register
415 This routine calls ::Ax88772UsbCommand to write a PHY register.
417 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
418 @param [in] RegisterAddress Number of the register to read.
419 @param [in] PhyData Address of a buffer to receive the PHY register value
421 @retval EFI_SUCCESS The PHY data was written.
422 @retval other Failed to wwrite the PHY register.
427 IN NIC_DEVICE
* pNicDevice
,
428 IN UINT8 RegisterAddress
,
432 USB_DEVICE_REQUEST SetupMsg
;
436 // Request access to the PHY
438 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
440 SetupMsg
.Request
= CMD_PHY_ACCESS_SOFTWARE
;
444 Status
= Ax88772UsbCommand ( pNicDevice
,
447 if ( !EFI_ERROR ( Status
)) {
449 // Write the PHY register
451 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
453 SetupMsg
.Request
= CMD_PHY_REG_WRITE
;
454 SetupMsg
.Value
= pNicDevice
->PhyId
;
455 SetupMsg
.Index
= RegisterAddress
;
456 SetupMsg
.Length
= sizeof ( PhyData
);
457 Status
= Ax88772UsbCommand ( pNicDevice
,
460 if ( !EFI_ERROR ( Status
)) {
463 // Release the PHY to the hardware
465 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
467 SetupMsg
.Request
= CMD_PHY_ACCESS_HARDWARE
;
471 Status
= Ax88772UsbCommand ( pNicDevice
,
484 This routine uses ::Ax88772UsbCommand to reset the network
485 adapter. This routine also uses ::Ax88772PhyWrite to reset
488 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
490 @retval EFI_SUCCESS The MAC address is available.
491 @retval other The MAC address is not valid.
496 IN NIC_DEVICE
* pNicDevice
499 USB_DEVICE_REQUEST SetupMsg
;
502 EFI_USB_IO_PROTOCOL
*pUsbIo
;
503 EFI_USB_DEVICE_DESCRIPTOR Device
;
505 pUsbIo
= pNicDevice
->pUsbIo
;
506 Status
= pUsbIo
->UsbGetDeviceDescriptor ( pUsbIo
, &Device
);
508 if (EFI_ERROR(Status
)) goto err
;
510 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
512 SetupMsg
.Request
= CMD_PHY_ACCESS_HARDWARE
;
516 Status
= Ax88772UsbCommand ( pNicDevice
,
520 if (EFI_ERROR(Status
)) goto err
;
522 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
524 SetupMsg
.Request
= CMD_PHY_SELECT
;
525 SetupMsg
.Value
= SPHY_PSEL
;
528 Status
= Ax88772UsbCommand ( pNicDevice
,
532 if (EFI_ERROR(Status
)) goto err
;
534 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
536 SetupMsg
.Request
= CMD_RESET
;
537 SetupMsg
.Value
= SRR_IPRL
;
540 Status
= Ax88772UsbCommand ( pNicDevice
,
544 if (EFI_ERROR(Status
)) goto err
;
546 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
548 SetupMsg
.Request
= CMD_RESET
;
549 SetupMsg
.Value
= SRR_IPPD
| SRR_IPRL
;
552 Status
= Ax88772UsbCommand ( pNicDevice
,
556 gBS
->Stall ( 200000 );
558 if (EFI_ERROR(Status
)) goto err
;
560 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
562 SetupMsg
.Request
= CMD_RESET
;
563 SetupMsg
.Value
= SRR_IPRL
;
566 Status
= Ax88772UsbCommand ( pNicDevice
,
570 gBS
->Stall ( 200000 );
572 if (EFI_ERROR(Status
)) goto err
;
574 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
576 SetupMsg
.Request
= CMD_RESET
;
580 Status
= Ax88772UsbCommand ( pNicDevice
,
584 if (EFI_ERROR(Status
)) goto err
;
586 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
588 SetupMsg
.Request
= CMD_PHY_SELECT
;
589 SetupMsg
.Value
= SPHY_PSEL
;
592 Status
= Ax88772UsbCommand ( pNicDevice
,
596 if (EFI_ERROR(Status
)) goto err
;
598 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
600 SetupMsg
.Request
= CMD_RESET
;
601 SetupMsg
.Value
= SRR_IPRL
| SRR_BZ
| SRR_BZTYPE
;
604 Status
= Ax88772UsbCommand ( pNicDevice
,
608 if (EFI_ERROR(Status
)) goto err
;
610 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
612 SetupMsg
.Request
= CMD_RX_CONTROL_WRITE
;
616 Status
= Ax88772UsbCommand ( pNicDevice
,
620 if (EFI_ERROR(Status
)) goto err
;
622 if (pNicDevice
->Flags
!= FLAG_TYPE_AX88772
) {
623 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
625 SetupMsg
.Request
= CMD_RXQTC
;
626 SetupMsg
.Value
= 0x8000;
627 SetupMsg
.Index
= 0x8001;
629 Status
= Ax88772UsbCommand ( pNicDevice
,
639 Enable or disable the receiver
641 This routine calls ::Ax88772UsbCommand to update the
642 receiver state. This routine also calls ::Ax88772MacAddressSet
643 to establish the MAC address for the network adapter.
645 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
646 @param [in] RxFilter Simple network RX filter mask value
648 @retval EFI_SUCCESS The MAC address was set.
649 @retval other The MAC address was not set.
654 IN NIC_DEVICE
* pNicDevice
,
660 USB_DEVICE_REQUEST SetupMsg
;
662 EFI_USB_IO_PROTOCOL
*pUsbIo
;
663 EFI_USB_DEVICE_DESCRIPTOR Device
;
665 pUsbIo
= pNicDevice
->pUsbIo
;
666 Status
= pUsbIo
->UsbGetDeviceDescriptor ( pUsbIo
, &Device
);
668 if (EFI_ERROR(Status
)) {
669 DEBUG (( EFI_D_ERROR
, "Failed to get device descriptor\n" ));
674 // Enable the receiver if something is to be received
677 if ( 0 != RxFilter
) {
679 // Enable the receiver
681 SetupMsg
.RequestType
= USB_ENDPOINT_DIR_IN
682 | USB_REQ_TYPE_VENDOR
684 SetupMsg
.Request
= CMD_MEDIUM_STATUS_READ
;
687 SetupMsg
.Length
= sizeof ( MediumStatus
);
688 Status
= Ax88772UsbCommand ( pNicDevice
,
691 if ( !EFI_ERROR ( Status
)) {
692 if ( 0 == ( MediumStatus
& MS_RE
)) {
693 MediumStatus
|= MS_RE
| MS_ONE
;
695 if ( pNicDevice
->bFullDuplex
)
696 MediumStatus
|= MS_TFC
| MS_RFC
| MS_FD
;
698 MediumStatus
&= ~(MS_TFC
| MS_RFC
| MS_FD
);
700 if ( pNicDevice
->b100Mbps
)
701 MediumStatus
|= MS_PS
;
703 MediumStatus
&= ~MS_PS
;
705 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
707 SetupMsg
.Request
= CMD_MEDIUM_STATUS_WRITE
;
708 SetupMsg
.Value
= MediumStatus
;
711 Status
= Ax88772UsbCommand ( pNicDevice
,
714 if ( EFI_ERROR ( Status
)) {
715 DEBUG (( EFI_D_ERROR
, "Failed to enable receiver, Status: %r\r\n",
721 DEBUG (( EFI_D_ERROR
, "Failed to read receiver status, Status: %r\r\n",
726 RxControl
= RXC_SO
| RXC_RH1M
;
728 // Enable multicast if requested
730 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST
)) {
733 // Update the multicast hash table
735 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
737 SetupMsg
.Request
= CMD_MULTICAST_HASH_WRITE
;
740 SetupMsg
.Length
= sizeof ( pNicDevice
->MulticastHash
);
741 Status
= Ax88772UsbCommand ( pNicDevice
,
743 &pNicDevice
->MulticastHash
);
746 // Enable all multicast if requested
748 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST
)) {
749 RxControl
|= RXC_AMALL
;
753 // Enable broadcast if requested
755 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST
)) {
760 // Enable promiscuous mode if requested
762 if ( 0 != ( RxFilter
& EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS
)) {
763 RxControl
|= RXC_PRO
;
767 // Update the receiver control
769 if (pNicDevice
->CurRxControl
!= RxControl
) {
770 SetupMsg
.RequestType
= USB_REQ_TYPE_VENDOR
772 SetupMsg
.Request
= CMD_RX_CONTROL_WRITE
;
773 SetupMsg
.Value
= RxControl
;
776 Status
= Ax88772UsbCommand ( pNicDevice
,
779 if ( !EFI_ERROR ( Status
)) {
780 pNicDevice
->CurRxControl
= RxControl
;
784 DEBUG (( EFI_D_ERROR
, "ERROR - Failed to set receiver control, Status: %r\r\n",
793 Read an SROM location
795 This routine calls ::Ax88772UsbCommand to read data from the
798 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
799 @param [in] Address SROM address
800 @param [out] pData Buffer to receive the data
802 @retval EFI_SUCCESS The read was successful
803 @retval other The read failed
808 IN NIC_DEVICE
* pNicDevice
,
813 return EFI_UNSUPPORTED
;
817 Send a command to the USB device.
819 @param [in] pNicDevice Pointer to the NIC_DEVICE structure
820 @param [in] pRequest Pointer to the request structure
821 @param [in, out] pBuffer Data buffer address
823 @retval EFI_SUCCESS The USB transfer was successful
824 @retval other The USB transfer failed
829 IN NIC_DEVICE
* pNicDevice
,
830 IN USB_DEVICE_REQUEST
* pRequest
,
831 IN OUT VOID
* pBuffer
835 EFI_USB_DATA_DIRECTION Direction
;
836 EFI_USB_IO_PROTOCOL
* pUsbIo
;
840 // Determine the transfer direction
842 Direction
= EfiUsbNoData
;
843 if ( 0 != pRequest
->Length
) {
844 Direction
= ( 0 != ( pRequest
->RequestType
& USB_ENDPOINT_DIR_IN
))
845 ? EfiUsbDataIn
: EfiUsbDataOut
;
851 pUsbIo
= pNicDevice
->pUsbIo
;
852 Status
= pUsbIo
->UsbControlTransfer ( pUsbIo
,
860 // Determine the operation status
862 if ( !EFI_ERROR ( Status
)) {
867 // Only use status values associated with the Simple Network protocol
869 if ( EFI_TIMEOUT
== Status
) {
870 Status
= EFI_DEVICE_ERROR
;