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