From 73683a2464e2f81b7b9dfb9b84b537290235bbe1 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 6 May 2016 18:19:07 +0100 Subject: [PATCH] EmbeddedPkg/Lan9118Dxe: add LAN9118 MMIO wrappers As described in the LAN9118 datasheet, delays are necessary after some reads and writes in order to ensure subsequent reads do not see stale data. This patch adds helpers to provide these delays automatically, by performing dummy reads of the BYTE_TEST register (as recommended in the LAN9118 datasheet). This approach allows the device register file itself to provide the required delay, avoiding issues with early write acknowledgement, or re-ordering of MMIO accesses aganist other instructions (e.g. the delay loop). Cc: Leif Lindholm Cc: Ryan Harkin Signed-off-by: Mark Rutland Contributed-under: TianoCore Contribution Agreement 1.0 Reviewed-by: Ard Biesheuvel --- EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h | 71 +++++++++++++++++++ .../Drivers/Lan9118Dxe/Lan9118DxeUtil.c | 48 +++++++++++++ .../Drivers/Lan9118Dxe/Lan9118DxeUtil.h | 17 +++++ 3 files changed, 136 insertions(+) diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h index 9e89d27459..11895849a4 100644 --- a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h @@ -57,6 +57,77 @@ #define LAN9118_E2P_CMD (0x000000B0 + LAN9118_BA) // EEPROM Command #define LAN9118_E2P_DATA (0x000000B4 + LAN9118_BA) // EEPROM Data +/* + * Required delays following write cycles (number of BYTE_TEST reads) + * Taken from Table 6.1 in Revision 1.5 (07-11-08) of the LAN9118 datasheet. + * Where no delay listed, 0 has been assumed. + */ +#define LAN9118_RX_DATA_WR_DELAY 0 +#define LAN9118_RX_STATUS_WR_DELAY 0 +#define LAN9118_RX_STATUS_PEEK_WR_DELAY 0 +#define LAN9118_TX_DATA_WR_DELAY 0 +#define LAN9118_TX_STATUS_WR_DELAY 0 +#define LAN9118_TX_STATUS_PEEK_WR_DELAY 0 +#define LAN9118_ID_REV_WR_DELAY 0 +#define LAN9118_IRQ_CFG_WR_DELAY 3 +#define LAN9118_INT_STS_WR_DELAY 2 +#define LAN9118_INT_EN_WR_DELAY 1 +#define LAN9118_BYTE_TEST_WR_DELAY 0 +#define LAN9118_FIFO_INT_WR_DELAY 1 +#define LAN9118_RX_CFG_WR_DELAY 1 +#define LAN9118_TX_CFG_WR_DELAY 1 +#define LAN9118_HW_CFG_WR_DELAY 1 +#define LAN9118_RX_DP_CTL_WR_DELAY 1 +#define LAN9118_RX_FIFO_INF_WR_DELAY 0 +#define LAN9118_TX_FIFO_INF_WR_DELAY 3 +#define LAN9118_PMT_CTRL_WR_DELAY 7 +#define LAN9118_GPIO_CFG_WR_DELAY 1 +#define LAN9118_GPT_CFG_WR_DELAY 1 +#define LAN9118_GPT_CNT_WR_DELAY 3 +#define LAN9118_WORD_SWAP_WR_DELAY 1 +#define LAN9118_FREE_RUN_WR_DELAY 4 +#define LAN9118_RX_DROP_WR_DELAY 0 +#define LAN9118_MAC_CSR_CMD_WR_DELAY 1 +#define LAN9118_MAC_CSR_DATA_WR_DELAY 1 +#define LAN9118_AFC_CFG_WR_DELAY 1 +#define LAN9118_E2P_CMD_WR_DELAY 1 +#define LAN9118_E2P_DATA_WR_DELAY 1 + +/* + * Required delays following read cycles (number of BYTE_TEST reads) + * Taken from Table 6.2 in Revision 1.5 (07-11-08) of the LAN9118 datasheet. + * Where no delay listed, 0 has been assumed. + */ +#define LAN9118_RX_DATA_RD_DELAY 3 +#define LAN9118_RX_STATUS_RD_DELAY 3 +#define LAN9118_RX_STATUS_PEEK_RD_DELAY 0 +#define LAN9118_TX_DATA_RD_DELAY 0 +#define LAN9118_TX_STATUS_RD_DELAY 3 +#define LAN9118_TX_STATUS_PEEK_RD_DELAY 0 +#define LAN9118_ID_REV_RD_DELAY 0 +#define LAN9118_IRQ_CFG_RD_DELAY 0 +#define LAN9118_INT_STS_RD_DELAY 0 +#define LAN9118_INT_EN_RD_DELAY 0 +#define LAN9118_BYTE_TEST_RD_DELAY 0 +#define LAN9118_FIFO_INT_RD_DELAY 0 +#define LAN9118_RX_CFG_RD_DELAY 0 +#define LAN9118_TX_CFG_RD_DELAY 0 +#define LAN9118_HW_CFG_RD_DELAY 0 +#define LAN9118_RX_DP_CTL_RD_DELAY 0 +#define LAN9118_RX_FIFO_INF_RD_DELAY 0 +#define LAN9118_TX_FIFO_INF_RD_DELAY 0 +#define LAN9118_PMT_CTRL_RD_DELAY 0 +#define LAN9118_GPIO_CFG_RD_DELAY 0 +#define LAN9118_GPT_CFG_RD_DELAY 0 +#define LAN9118_GPT_CNT_RD_DELAY 0 +#define LAN9118_WORD_SWAP_RD_DELAY 0 +#define LAN9118_FREE_RUN_RD_DELAY 0 +#define LAN9118_RX_DROP_RD_DELAY 4 +#define LAN9118_MAC_CSR_CMD_RD_DELAY 0 +#define LAN9118_MAC_CSR_DATA_RD_DELAY 0 +#define LAN9118_AFC_CFG_RD_DELAY 0 +#define LAN9118_E2P_CMD_RD_DELAY 0 +#define LAN9118_E2P_DATA_RD_DELAY 0 // Receiver Status bits #define RXSTATUS_CRC_ERROR BIT1 // Cyclic Redundancy Check Error diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c index bd20eebd04..002ea203ae 100644 --- a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c @@ -115,6 +115,54 @@ IndirectMACRead32 ( return MmioRead32 (LAN9118_MAC_CSR_DATA); } +/* + * LAN9118 chips have special restrictions on some back-to-back Write/Read or + * Read/Read pairs of accesses. After a read or write that changes the state of + * the device, there is a period in which stale values may be returned in + * response to a read. This period is dependent on the registers accessed. + * + * We must delay prior reads by this period. This can either be achieved by + * timer-based delays, or by performing dummy reads of the BYTE_TEST register, + * for which the recommended number of reads is described in the LAN9118 data + * sheet. This is required in addition to any memory barriers. + * + * This function performs a number of dummy reads of the BYTE_TEST register, as + * a building block for the above. + */ +VOID +WaitDummyReads ( + UINTN Count + ) +{ + while (Count--) + MmioRead32(LAN9118_BYTE_TEST); +} + +UINT32 +Lan9118RawMmioRead32( + UINTN Address, + UINTN Delay + ) +{ + UINT32 Value; + + Value = MmioRead32(Address); + WaitDummyReads(Delay); + return Value; +} + +UINT32 +Lan9118RawMmioWrite32( + UINTN Address, + UINT32 Value, + UINTN Delay + ) +{ + MmioWrite32(Address, Value); + WaitDummyReads(Delay); + return Value; +} + // Function to write to MAC indirect registers UINT32 IndirectMACWrite32 ( diff --git a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h index 424bdc5a85..1a9a940082 100644 --- a/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h +++ b/EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h @@ -38,6 +38,23 @@ GenEtherCrc32 ( IN UINT32 AddrLen ); +UINT32 +Lan9118RawMmioRead32( + UINTN Address, + UINTN Delay + ); +#define Lan9118MmioRead32(a) \ + Lan9118RawMmioRead32(a, a ## _RD_DELAY) + +UINT32 +Lan9118RawMmioWrite32( + UINTN Address, + UINT32 Value, + UINTN Delay + ); +#define Lan9118MmioWrite32(a, v) \ + Lan9118RawMmioWrite32(a, v, a ## _WR_DELAY) + /* ------------------ MAC CSR Access ------------------- */ // Read from MAC indirect registers