1From 6d274379f584a638c1f2b4b8a19014d4baef1d9f Mon Sep 17 00:00:00 2001
2From: sahil <sahil@arm.com>
3Date: Thu, 11 Aug 2022 11:26:29 +0530
4Subject: [PATCH] Platform/ARM/N1Sdp: manually poll QSPI status bit after
5 erase/write
6
7This patch adds a function to poll Nor flash memory's status register
8bit (WIP bit) to wait for an erase/write operation to complete.
9The polling timeout is set to 1 second.
10
11Upstream-Status: Pending
12Signed-off-by: Xueliang Zhong <xueliang.zhong@arm.com>
13Signed-off-by: sahil <sahil@arm.com>
14Change-Id: Ie678b7586671964ae0f8506a0542d73cbddddfe4
15---
16 .../Drivers/CadenceQspiDxe/CadenceQspiDxe.inf |  1 +
17 .../Drivers/CadenceQspiDxe/CadenceQspiReg.h   |  6 +-
18 .../N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c   | 80 ++++++++++++++++++-
19 .../N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h   |  5 ++
20 4 files changed, 88 insertions(+), 4 deletions(-)
21
22diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
23index 4f20c3ba..7a39eb2d 100644
24--- a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
25+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
26@@ -39,6 +39,7 @@
27   MemoryAllocationLib
28   NorFlashInfoLib
29   NorFlashPlatformLib
30+  TimerLib
31   UefiBootServicesTableLib
32   UefiDriverEntryPoint
33   UefiLib
34diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
35index fe3b327c..1971631d 100644
36--- a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
37+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
38@@ -16,13 +16,15 @@
39 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS         19
40 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS    16
41 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT           0x02
42-#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_4B         0x03
43-#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_3B         0x02
44 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS       24
45 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE          0x01
46 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_BYTE_3B         0x02
47 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS       23
48 #define CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS     20
49+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C             0x8
50+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS        7
51+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES(x) ((x - 1) << CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS)
52+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES(x) ((x - 1) << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS)
53
54 #define CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET          0xA0
55
56diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
57index 188c75e2..6832351a 100644
58--- a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
59+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
60@@ -10,6 +10,7 @@
61 #include <Library/MemoryAllocationLib.h>
62 #include <Library/NorFlashInfoLib.h>
63 #include <Library/PcdLib.h>
64+#include <Library/TimerLib.h>
65 #include <Library/UefiBootServicesTableLib.h>
66 #include <Library/UefiLib.h>
67
68@@ -184,6 +185,74 @@ FreeInstance:
69   return Status;
70 }
71
72+/**
73+  Converts milliseconds into number of ticks of the performance counter.
74+
75+  @param[in] Milliseconds  Milliseconds to convert into ticks.
76+
77+  @retval Milliseconds expressed as number of ticks.
78+
79+**/
80+STATIC
81+UINT64
82+MilliSecondsToTicks (
83+  IN UINTN Milliseconds
84+  )
85+{
86+  CONST UINT64  NanoSecondsPerTick = GetTimeInNanoSecond (1);
87+
88+  return (Milliseconds * 1000000) / NanoSecondsPerTick;
89+}
90+
91+/**
92+  Poll Status register for NOR flash erase/write completion.
93+
94+  @param[in]      Instance           NOR flash Instance.
95+
96+  @retval         EFI_SUCCESS        Request is executed successfully.
97+  @retval         EFI_TIMEOUT        Operation timed out.
98+  @retval         EFI_DEVICE_ERROR   Controller operartion failed.
99+
100+**/
101+STATIC
102+EFI_STATUS
103+NorFlashPollStatusRegister (
104+  IN NOR_FLASH_INSTANCE     *Instance
105+  )
106+{
107+  BOOLEAN     SRegDone;
108+  UINT32      val;
109+
110+  val = SPINOR_OP_RDSR << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
111+      CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS |
112+      CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES(1) |
113+      CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C << CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS;
114+
115+  CONST UINT64  TickOut =
116+    GetPerformanceCounter () + MilliSecondsToTicks (SPINOR_SR_WIP_POLL_TIMEOUT_MS);
117+
118+  do {
119+    if (GetPerformanceCounter () > TickOut) {
120+      DEBUG ((
121+        DEBUG_ERROR,
122+        "NorFlashPollStatusRegister: Timeout waiting for erase/write.\n"
123+        ));
124+      return EFI_TIMEOUT;
125+    }
126+
127+    if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
128+      return EFI_DEVICE_ERROR;
129+    }
130+
131+    SRegDone =
132+      (MmioRead8 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET)
133+      & SPINOR_SR_WIP) == 0;
134+
135+  } while (!SRegDone);
136+
137+  return EFI_SUCCESS;
138+}
139+
140 /**
141   Check whether NOR flash opertions are Locked.
142
143@@ -305,12 +374,16 @@ NorFlashEraseSingleBlock (
144
145   DevConfigVal = SPINOR_OP_BE_4K << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
146                  CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS |
147-                 CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_3B << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS;
148+                 CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES(3);
149
150   if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, DevConfigVal))) {
151     return EFI_DEVICE_ERROR;
152   }
153
154+  if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {
155+      return EFI_DEVICE_ERROR;
156+  }
157+
158   return EFI_SUCCESS;
159 }
160
161@@ -383,6 +456,9 @@ NorFlashWriteSingleWord (
162     return EFI_DEVICE_ERROR;
163   }
164   MmioWrite32 (WordAddress, WriteData);
165+  if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {
166+    return EFI_DEVICE_ERROR;
167+  }
168   return EFI_SUCCESS;
169 }
170
171@@ -907,7 +983,7 @@ NorFlashReadID (
172
173   val = SPINOR_OP_RDID << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
174         CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS |
175-        CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_3B << CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS;
176+        CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES(3);
177
178   if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
179     return EFI_DEVICE_ERROR;
180diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
181index e720937e..eb0afc60 100644
182--- a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
183+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
184@@ -477,8 +477,13 @@ NorFlashReadID (
185   OUT UINT8               JedecId[3]
186   );
187
188+#define SPINOR_SR_WIP                 BIT0  // Write in progress
189+
190 #define SPINOR_OP_WREN                0x06  // Write enable
191 #define SPINOR_OP_BE_4K               0x20  // Erase 4KiB block
192 #define SPINOR_OP_RDID                0x9f  // Read JEDEC ID
193+#define SPINOR_OP_RDSR                0x05  // Read status register
194+
195+#define SPINOR_SR_WIP_POLL_TIMEOUT_MS  1000u // Status Register read timeout
196
197 #endif /* NOR_FLASH_DXE_H_ */
198