]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlash.c
ArmPlatformPkg: Apply uncrustify changes
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlash.c
CommitLineData
c2d1cf1b
MK
1/** @file NorFlash.c\r
2\r
3 Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>\r
4 Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include <Library/BaseMemoryLib.h>\r
11\r
12#include "NorFlash.h"\r
13\r
14//\r
15// Global variable declarations\r
16//\r
40b0b23e
MK
17extern NOR_FLASH_INSTANCE **mNorFlashInstances;\r
18extern UINT32 mNorFlashDeviceCount;\r
c2d1cf1b
MK
19\r
20UINT32\r
21NorFlashReadStatusRegister (\r
40b0b23e
MK
22 IN NOR_FLASH_INSTANCE *Instance,\r
23 IN UINTN SR_Address\r
c2d1cf1b
MK
24 )\r
25{\r
26 // Prepare to read the status register\r
27 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);\r
28 return MmioRead32 (Instance->DeviceBaseAddress);\r
29}\r
30\r
31STATIC\r
32BOOLEAN\r
33NorFlashBlockIsLocked (\r
40b0b23e
MK
34 IN NOR_FLASH_INSTANCE *Instance,\r
35 IN UINTN BlockAddress\r
c2d1cf1b
MK
36 )\r
37{\r
40b0b23e 38 UINT32 LockStatus;\r
c2d1cf1b
MK
39\r
40 // Send command for reading device id\r
41 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);\r
42\r
43 // Read block lock status\r
40b0b23e 44 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));\r
c2d1cf1b
MK
45\r
46 // Decode block lock status\r
40b0b23e 47 LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);\r
c2d1cf1b
MK
48\r
49 if ((LockStatus & 0x2) != 0) {\r
40b0b23e 50 DEBUG ((DEBUG_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));\r
c2d1cf1b
MK
51 }\r
52\r
53 return ((LockStatus & 0x1) != 0);\r
54}\r
55\r
56STATIC\r
57EFI_STATUS\r
58NorFlashUnlockSingleBlock (\r
40b0b23e
MK
59 IN NOR_FLASH_INSTANCE *Instance,\r
60 IN UINTN BlockAddress\r
c2d1cf1b
MK
61 )\r
62{\r
40b0b23e 63 UINT32 LockStatus;\r
c2d1cf1b
MK
64\r
65 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations\r
66 // and to protect shared data structures.\r
67\r
68 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) == TRUE) {\r
69 do {\r
70 // Request a lock setup\r
71 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);\r
72\r
73 // Request an unlock\r
74 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);\r
75\r
76 // Send command for reading device id\r
77 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);\r
78\r
79 // Read block lock status\r
40b0b23e 80 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));\r
c2d1cf1b
MK
81\r
82 // Decode block lock status\r
40b0b23e 83 LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);\r
c2d1cf1b
MK
84 } while ((LockStatus & 0x1) == 1);\r
85 } else {\r
86 // Request a lock setup\r
87 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);\r
88\r
89 // Request an unlock\r
90 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);\r
91\r
92 // Wait until the status register gives us the all clear\r
93 do {\r
94 LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);\r
95 } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);\r
96 }\r
97\r
98 // Put device back into Read Array mode\r
99 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);\r
100\r
40b0b23e 101 DEBUG ((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress));\r
c2d1cf1b
MK
102\r
103 return EFI_SUCCESS;\r
104}\r
105\r
106EFI_STATUS\r
107NorFlashUnlockSingleBlockIfNecessary (\r
40b0b23e
MK
108 IN NOR_FLASH_INSTANCE *Instance,\r
109 IN UINTN BlockAddress\r
c2d1cf1b
MK
110 )\r
111{\r
40b0b23e 112 EFI_STATUS Status;\r
c2d1cf1b
MK
113\r
114 Status = EFI_SUCCESS;\r
115\r
116 if (NorFlashBlockIsLocked (Instance, BlockAddress)) {\r
117 Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);\r
118 }\r
119\r
120 return Status;\r
121}\r
122\r
c2d1cf1b
MK
123/**\r
124 * The following function presumes that the block has already been unlocked.\r
125 **/\r
126EFI_STATUS\r
127NorFlashEraseSingleBlock (\r
40b0b23e
MK
128 IN NOR_FLASH_INSTANCE *Instance,\r
129 IN UINTN BlockAddress\r
c2d1cf1b
MK
130 )\r
131{\r
40b0b23e
MK
132 EFI_STATUS Status;\r
133 UINT32 StatusRegister;\r
c2d1cf1b
MK
134\r
135 Status = EFI_SUCCESS;\r
136\r
137 // Request a block erase and then confirm it\r
40b0b23e
MK
138 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);\r
139 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);\r
c2d1cf1b
MK
140\r
141 // Wait until the status register gives us the all clear\r
142 do {\r
143 StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);\r
144 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);\r
145\r
146 if (StatusRegister & P30_SR_BIT_VPP) {\r
40b0b23e 147 DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));\r
c2d1cf1b
MK
148 Status = EFI_DEVICE_ERROR;\r
149 }\r
150\r
151 if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {\r
40b0b23e 152 DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));\r
c2d1cf1b
MK
153 Status = EFI_DEVICE_ERROR;\r
154 }\r
155\r
156 if (StatusRegister & P30_SR_BIT_ERASE) {\r
40b0b23e 157 DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));\r
c2d1cf1b
MK
158 Status = EFI_DEVICE_ERROR;\r
159 }\r
160\r
161 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {\r
162 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...\r
40b0b23e 163 DEBUG ((DEBUG_INFO, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));\r
c2d1cf1b
MK
164 Status = EFI_WRITE_PROTECTED;\r
165 }\r
166\r
40b0b23e 167 if (EFI_ERROR (Status)) {\r
c2d1cf1b
MK
168 // Clear the Status Register\r
169 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);\r
170 }\r
171\r
172 // Put device back into Read Array mode\r
173 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);\r
174\r
175 return Status;\r
176}\r
177\r
178EFI_STATUS\r
179NorFlashWriteSingleWord (\r
40b0b23e
MK
180 IN NOR_FLASH_INSTANCE *Instance,\r
181 IN UINTN WordAddress,\r
182 IN UINT32 WriteData\r
c2d1cf1b
MK
183 )\r
184{\r
40b0b23e
MK
185 EFI_STATUS Status;\r
186 UINT32 StatusRegister;\r
c2d1cf1b
MK
187\r
188 Status = EFI_SUCCESS;\r
189\r
190 // Request a write single word command\r
40b0b23e 191 SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);\r
c2d1cf1b
MK
192\r
193 // Store the word into NOR Flash;\r
194 MmioWrite32 (WordAddress, WriteData);\r
195\r
196 // Wait for the write to complete and then check for any errors; i.e. check the Status Register\r
197 do {\r
198 // Prepare to read the status register\r
199 StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);\r
200 // The chip is busy while the WRITE bit is not asserted\r
201 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);\r
202\r
c2d1cf1b
MK
203 // Perform a full status check:\r
204 // Mask the relevant bits of Status Register.\r
205 // Everything should be zero, if not, we have a problem\r
206\r
207 if (StatusRegister & P30_SR_BIT_VPP) {\r
40b0b23e 208 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress));\r
c2d1cf1b
MK
209 Status = EFI_DEVICE_ERROR;\r
210 }\r
211\r
212 if (StatusRegister & P30_SR_BIT_PROGRAM) {\r
40b0b23e 213 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress));\r
c2d1cf1b
MK
214 Status = EFI_DEVICE_ERROR;\r
215 }\r
216\r
217 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {\r
40b0b23e 218 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress));\r
c2d1cf1b
MK
219 Status = EFI_DEVICE_ERROR;\r
220 }\r
221\r
40b0b23e 222 if (!EFI_ERROR (Status)) {\r
c2d1cf1b
MK
223 // Clear the Status Register\r
224 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);\r
225 }\r
226\r
227 // Put device back into Read Array mode\r
228 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);\r
229\r
230 return Status;\r
231}\r
232\r
233/*\r
234 * Writes data to the NOR Flash using the Buffered Programming method.\r
235 *\r
236 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.\r
237 * Therefore this function will only handle buffers up to 32 words or 128 bytes.\r
238 * To deal with larger buffers, call this function again.\r
239 *\r
240 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize\r
241 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.\r
242 *\r
243 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,\r
244 * then programming time is doubled and power consumption is increased.\r
245 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.\r
246 * i.e. the last 4 bits of the target start address must be zero: 0x......00\r
247 */\r
248EFI_STATUS\r
249NorFlashWriteBuffer (\r
40b0b23e
MK
250 IN NOR_FLASH_INSTANCE *Instance,\r
251 IN UINTN TargetAddress,\r
252 IN UINTN BufferSizeInBytes,\r
253 IN UINT32 *Buffer\r
c2d1cf1b
MK
254 )\r
255{\r
40b0b23e
MK
256 EFI_STATUS Status;\r
257 UINTN BufferSizeInWords;\r
258 UINTN Count;\r
259 volatile UINT32 *Data;\r
260 UINTN WaitForBuffer;\r
261 BOOLEAN BufferAvailable;\r
262 UINT32 StatusRegister;\r
c2d1cf1b
MK
263\r
264 WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;\r
265 BufferAvailable = FALSE;\r
266\r
267 // Check that the target address does not cross a 32-word boundary.\r
268 if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {\r
269 return EFI_INVALID_PARAMETER;\r
270 }\r
271\r
272 // Check there are some data to program\r
273 if (BufferSizeInBytes == 0) {\r
274 return EFI_BUFFER_TOO_SMALL;\r
275 }\r
276\r
277 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.\r
278 if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {\r
279 return EFI_BAD_BUFFER_SIZE;\r
280 }\r
281\r
282 // Check that the buffer size is a multiple of 32-bit words\r
283 if ((BufferSizeInBytes % 4) != 0) {\r
284 return EFI_BAD_BUFFER_SIZE;\r
285 }\r
286\r
287 // Pre-programming conditions checked, now start the algorithm.\r
288\r
289 // Prepare the data destination address\r
290 Data = (UINT32 *)TargetAddress;\r
291\r
292 // Check the availability of the buffer\r
293 do {\r
294 // Issue the Buffered Program Setup command\r
40b0b23e 295 SEND_NOR_COMMAND (TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);\r
c2d1cf1b
MK
296\r
297 // Read back the status register bit#7 from the same address\r
298 if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {\r
299 BufferAvailable = TRUE;\r
300 }\r
301\r
302 // Update the loop counter\r
303 WaitForBuffer--;\r
c2d1cf1b
MK
304 } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));\r
305\r
306 // The buffer was not available for writing\r
307 if (WaitForBuffer == 0) {\r
308 Status = EFI_DEVICE_ERROR;\r
309 goto EXIT;\r
310 }\r
311\r
312 // From now on we work in 32-bit words\r
313 BufferSizeInWords = BufferSizeInBytes / (UINTN)4;\r
314\r
315 // Write the word count, which is (buffer_size_in_words - 1),\r
316 // because word count 0 means one word.\r
40b0b23e 317 SEND_NOR_COMMAND (TargetAddress, 0, (BufferSizeInWords - 1));\r
c2d1cf1b
MK
318\r
319 // Write the data to the NOR Flash, advancing each address by 4 bytes\r
40b0b23e 320 for (Count = 0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {\r
c2d1cf1b
MK
321 MmioWrite32 ((UINTN)Data, *Buffer);\r
322 }\r
323\r
324 // Issue the Buffered Program Confirm command, to start the programming operation\r
325 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);\r
326\r
327 // Wait for the write to complete and then check for any errors; i.e. check the Status Register\r
328 do {\r
329 StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);\r
330 // The chip is busy while the WRITE bit is not asserted\r
331 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);\r
332\r
c2d1cf1b
MK
333 // Perform a full status check:\r
334 // Mask the relevant bits of Status Register.\r
335 // Everything should be zero, if not, we have a problem\r
336\r
40b0b23e 337 Status = EFI_SUCCESS;\r
c2d1cf1b
MK
338\r
339 if (StatusRegister & P30_SR_BIT_VPP) {\r
40b0b23e 340 DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));\r
c2d1cf1b
MK
341 Status = EFI_DEVICE_ERROR;\r
342 }\r
343\r
344 if (StatusRegister & P30_SR_BIT_PROGRAM) {\r
40b0b23e 345 DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));\r
c2d1cf1b
MK
346 Status = EFI_DEVICE_ERROR;\r
347 }\r
348\r
349 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {\r
40b0b23e 350 DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n", TargetAddress));\r
c2d1cf1b
MK
351 Status = EFI_DEVICE_ERROR;\r
352 }\r
353\r
40b0b23e 354 if (!EFI_ERROR (Status)) {\r
c2d1cf1b
MK
355 // Clear the Status Register\r
356 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);\r
357 }\r
358\r
359EXIT:\r
360 // Put device back into Read Array mode\r
361 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);\r
362\r
363 return Status;\r
364}\r
365\r
366EFI_STATUS\r
367NorFlashWriteBlocks (\r
40b0b23e
MK
368 IN NOR_FLASH_INSTANCE *Instance,\r
369 IN EFI_LBA Lba,\r
370 IN UINTN BufferSizeInBytes,\r
371 IN VOID *Buffer\r
c2d1cf1b
MK
372 )\r
373{\r
40b0b23e
MK
374 UINT32 *pWriteBuffer;\r
375 EFI_STATUS Status;\r
376 EFI_LBA CurrentBlock;\r
377 UINT32 BlockSizeInWords;\r
378 UINT32 NumBlocks;\r
379 UINT32 BlockCount;\r
c2d1cf1b
MK
380\r
381 Status = EFI_SUCCESS;\r
382\r
383 // The buffer must be valid\r
384 if (Buffer == NULL) {\r
385 return EFI_INVALID_PARAMETER;\r
386 }\r
387\r
40b0b23e 388 if (Instance->Media.ReadOnly == TRUE) {\r
c2d1cf1b
MK
389 return EFI_WRITE_PROTECTED;\r
390 }\r
391\r
392 // We must have some bytes to read\r
40b0b23e
MK
393 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));\r
394 if (BufferSizeInBytes == 0) {\r
c2d1cf1b
MK
395 return EFI_BAD_BUFFER_SIZE;\r
396 }\r
397\r
398 // The size of the buffer must be a multiple of the block size\r
40b0b23e 399 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->Media.BlockSize));\r
c2d1cf1b
MK
400 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {\r
401 return EFI_BAD_BUFFER_SIZE;\r
402 }\r
403\r
404 // All blocks must be within the device\r
40b0b23e 405 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize;\r
c2d1cf1b 406\r
40b0b23e 407 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba));\r
c2d1cf1b
MK
408\r
409 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {\r
40b0b23e 410 DEBUG ((DEBUG_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));\r
c2d1cf1b
MK
411 return EFI_INVALID_PARAMETER;\r
412 }\r
413\r
414 BlockSizeInWords = Instance->Media.BlockSize / 4;\r
415\r
416 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer\r
417 // to a proper data type, so use *ReadBuffer\r
418 pWriteBuffer = (UINT32 *)Buffer;\r
419\r
420 CurrentBlock = Lba;\r
40b0b23e
MK
421 for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {\r
422 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));\r
c2d1cf1b
MK
423\r
424 Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);\r
425\r
40b0b23e 426 if (EFI_ERROR (Status)) {\r
c2d1cf1b
MK
427 break;\r
428 }\r
429 }\r
430\r
40b0b23e 431 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));\r
c2d1cf1b
MK
432 return Status;\r
433}\r
434\r
40b0b23e 435#define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)\r
c2d1cf1b
MK
436\r
437/**\r
438 Copy Length bytes from Source to Destination, using aligned accesses only.\r
439 Note that this implementation uses memcpy() semantics rather then memmove()\r
440 semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.\r
441\r
442 @param DestinationBuffer The target of the copy request.\r
443 @param SourceBuffer The place to copy from.\r
444 @param Length The number of bytes to copy.\r
445\r
446 @return Destination\r
447\r
448**/\r
449STATIC\r
450VOID *\r
451AlignedCopyMem (\r
40b0b23e
MK
452 OUT VOID *DestinationBuffer,\r
453 IN CONST VOID *SourceBuffer,\r
454 IN UINTN Length\r
c2d1cf1b
MK
455 )\r
456{\r
40b0b23e
MK
457 UINT8 *Destination8;\r
458 CONST UINT8 *Source8;\r
459 UINT32 *Destination32;\r
460 CONST UINT32 *Source32;\r
461 UINT64 *Destination64;\r
462 CONST UINT64 *Source64;\r
463\r
464 if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 8) && (Length >= 8)) {\r
c2d1cf1b 465 Destination64 = DestinationBuffer;\r
40b0b23e 466 Source64 = SourceBuffer;\r
c2d1cf1b
MK
467 while (Length >= 8) {\r
468 *Destination64++ = *Source64++;\r
40b0b23e 469 Length -= 8;\r
c2d1cf1b
MK
470 }\r
471\r
472 Destination8 = (UINT8 *)Destination64;\r
40b0b23e
MK
473 Source8 = (CONST UINT8 *)Source64;\r
474 } else if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 4) && (Length >= 4)) {\r
c2d1cf1b 475 Destination32 = DestinationBuffer;\r
40b0b23e 476 Source32 = SourceBuffer;\r
c2d1cf1b
MK
477 while (Length >= 4) {\r
478 *Destination32++ = *Source32++;\r
40b0b23e 479 Length -= 4;\r
c2d1cf1b
MK
480 }\r
481\r
482 Destination8 = (UINT8 *)Destination32;\r
40b0b23e 483 Source8 = (CONST UINT8 *)Source32;\r
c2d1cf1b
MK
484 } else {\r
485 Destination8 = DestinationBuffer;\r
40b0b23e 486 Source8 = SourceBuffer;\r
c2d1cf1b 487 }\r
40b0b23e 488\r
c2d1cf1b
MK
489 while (Length-- != 0) {\r
490 *Destination8++ = *Source8++;\r
491 }\r
40b0b23e 492\r
c2d1cf1b
MK
493 return DestinationBuffer;\r
494}\r
495\r
496EFI_STATUS\r
497NorFlashReadBlocks (\r
40b0b23e
MK
498 IN NOR_FLASH_INSTANCE *Instance,\r
499 IN EFI_LBA Lba,\r
500 IN UINTN BufferSizeInBytes,\r
501 OUT VOID *Buffer\r
c2d1cf1b
MK
502 )\r
503{\r
40b0b23e
MK
504 UINT32 NumBlocks;\r
505 UINTN StartAddress;\r
506\r
507 DEBUG ((\r
508 DEBUG_BLKIO,\r
509 "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",\r
510 BufferSizeInBytes,\r
511 Instance->Media.BlockSize,\r
512 Instance->Media.LastBlock,\r
513 Lba\r
514 ));\r
c2d1cf1b
MK
515\r
516 // The buffer must be valid\r
517 if (Buffer == NULL) {\r
518 return EFI_INVALID_PARAMETER;\r
519 }\r
520\r
521 // Return if we have not any byte to read\r
522 if (BufferSizeInBytes == 0) {\r
523 return EFI_SUCCESS;\r
524 }\r
525\r
526 // The size of the buffer must be a multiple of the block size\r
527 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {\r
528 return EFI_BAD_BUFFER_SIZE;\r
529 }\r
530\r
531 // All blocks must be within the device\r
40b0b23e 532 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize;\r
c2d1cf1b
MK
533\r
534 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {\r
40b0b23e 535 DEBUG ((DEBUG_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));\r
c2d1cf1b
MK
536 return EFI_INVALID_PARAMETER;\r
537 }\r
538\r
539 // Get the address to start reading from\r
40b0b23e
MK
540 StartAddress = GET_NOR_BLOCK_ADDRESS (\r
541 Instance->RegionBaseAddress,\r
542 Lba,\r
543 Instance->Media.BlockSize\r
544 );\r
c2d1cf1b
MK
545\r
546 // Put the device into Read Array mode\r
547 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);\r
548\r
549 // Readout the data\r
550 AlignedCopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);\r
551\r
552 return EFI_SUCCESS;\r
553}\r
554\r
555EFI_STATUS\r
556NorFlashRead (\r
40b0b23e
MK
557 IN NOR_FLASH_INSTANCE *Instance,\r
558 IN EFI_LBA Lba,\r
559 IN UINTN Offset,\r
560 IN UINTN BufferSizeInBytes,\r
561 OUT VOID *Buffer\r
c2d1cf1b
MK
562 )\r
563{\r
564 UINTN StartAddress;\r
565\r
566 // The buffer must be valid\r
567 if (Buffer == NULL) {\r
568 return EFI_INVALID_PARAMETER;\r
569 }\r
570\r
571 // Return if we have not any byte to read\r
572 if (BufferSizeInBytes == 0) {\r
573 return EFI_SUCCESS;\r
574 }\r
575\r
576 if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) {\r
577 DEBUG ((DEBUG_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));\r
578 return EFI_INVALID_PARAMETER;\r
579 }\r
580\r
581 // Get the address to start reading from\r
40b0b23e
MK
582 StartAddress = GET_NOR_BLOCK_ADDRESS (\r
583 Instance->RegionBaseAddress,\r
584 Lba,\r
585 Instance->Media.BlockSize\r
586 );\r
c2d1cf1b
MK
587\r
588 // Put the device into Read Array mode\r
589 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);\r
590\r
591 // Readout the data\r
592 AlignedCopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);\r
593\r
594 return EFI_SUCCESS;\r
595}\r
596\r
597/*\r
598 Write a full or portion of a block. It must not span block boundaries; that is,\r
599 Offset + *NumBytes <= Instance->Media.BlockSize.\r
600*/\r
601EFI_STATUS\r
602NorFlashWriteSingleBlock (\r
40b0b23e
MK
603 IN NOR_FLASH_INSTANCE *Instance,\r
604 IN EFI_LBA Lba,\r
605 IN UINTN Offset,\r
606 IN OUT UINTN *NumBytes,\r
607 IN UINT8 *Buffer\r
c2d1cf1b
MK
608 )\r
609{\r
610 EFI_STATUS TempStatus;\r
611 UINT32 Tmp;\r
612 UINT32 TmpBuf;\r
613 UINT32 WordToWrite;\r
614 UINT32 Mask;\r
615 BOOLEAN DoErase;\r
616 UINTN BytesToWrite;\r
617 UINTN CurOffset;\r
618 UINTN WordAddr;\r
619 UINTN BlockSize;\r
620 UINTN BlockAddress;\r
621 UINTN PrevBlockAddress;\r
622\r
623 PrevBlockAddress = 0;\r
624\r
625 DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));\r
626\r
627 // Detect WriteDisabled state\r
628 if (Instance->Media.ReadOnly == TRUE) {\r
629 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));\r
630 // It is in WriteDisabled state, return an error right away\r
631 return EFI_ACCESS_DENIED;\r
632 }\r
633\r
634 // Cache the block size to avoid de-referencing pointers all the time\r
635 BlockSize = Instance->Media.BlockSize;\r
636\r
637 // The write must not span block boundaries.\r
638 // We need to check each variable individually because adding two large values together overflows.\r
40b0b23e
MK
639 if ((Offset >= BlockSize) ||\r
640 (*NumBytes > BlockSize) ||\r
641 ((Offset + *NumBytes) > BlockSize))\r
642 {\r
643 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));\r
c2d1cf1b
MK
644 return EFI_BAD_BUFFER_SIZE;\r
645 }\r
646\r
647 // We must have some bytes to write\r
648 if (*NumBytes == 0) {\r
40b0b23e 649 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));\r
c2d1cf1b
MK
650 return EFI_BAD_BUFFER_SIZE;\r
651 }\r
652\r
653 // Pick 128bytes as a good start for word operations as opposed to erasing the\r
654 // block and writing the data regardless if an erase is really needed.\r
655 // It looks like most individual NV variable writes are smaller than 128bytes.\r
656 if (*NumBytes <= 128) {\r
657 // Check to see if we need to erase before programming the data into NOR.\r
658 // If the destination bits are only changing from 1s to 0s we can just write.\r
659 // After a block is erased all bits in the block is set to 1.\r
660 // If any byte requires us to erase we just give up and rewrite all of it.\r
661 DoErase = FALSE;\r
662 BytesToWrite = *NumBytes;\r
663 CurOffset = Offset;\r
664\r
665 while (BytesToWrite > 0) {\r
666 // Read full word from NOR, splice as required. A word is the smallest\r
667 // unit we can write.\r
40b0b23e 668 TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof (Tmp), &Tmp);\r
c2d1cf1b
MK
669 if (EFI_ERROR (TempStatus)) {\r
670 return EFI_DEVICE_ERROR;\r
671 }\r
672\r
673 // Physical address of word in NOR to write.\r
40b0b23e
MK
674 WordAddr = (CurOffset & ~(0x3)) + GET_NOR_BLOCK_ADDRESS (\r
675 Instance->RegionBaseAddress,\r
676 Lba,\r
677 BlockSize\r
678 );\r
c2d1cf1b 679 // The word of data that is to be written.\r
40b0b23e 680 TmpBuf = *((UINT32 *)(Buffer + (*NumBytes - BytesToWrite)));\r
c2d1cf1b
MK
681\r
682 // First do word aligned chunks.\r
683 if ((CurOffset & 0x3) == 0) {\r
684 if (BytesToWrite >= 4) {\r
685 // Is the destination still in 'erased' state?\r
686 if (~Tmp != 0) {\r
687 // Check to see if we are only changing bits to zero.\r
688 if ((Tmp ^ TmpBuf) & TmpBuf) {\r
689 DoErase = TRUE;\r
690 break;\r
691 }\r
692 }\r
40b0b23e 693\r
c2d1cf1b 694 // Write this word to NOR\r
40b0b23e
MK
695 WordToWrite = TmpBuf;\r
696 CurOffset += sizeof (TmpBuf);\r
697 BytesToWrite -= sizeof (TmpBuf);\r
c2d1cf1b
MK
698 } else {\r
699 // BytesToWrite < 4. Do small writes and left-overs\r
700 Mask = ~((~0) << (BytesToWrite * 8));\r
701 // Mask out the bytes we want.\r
702 TmpBuf &= Mask;\r
703 // Is the destination still in 'erased' state?\r
704 if ((Tmp & Mask) != Mask) {\r
705 // Check to see if we are only changing bits to zero.\r
706 if ((Tmp ^ TmpBuf) & TmpBuf) {\r
707 DoErase = TRUE;\r
708 break;\r
709 }\r
710 }\r
40b0b23e 711\r
c2d1cf1b 712 // Merge old and new data. Write merged word to NOR\r
40b0b23e
MK
713 WordToWrite = (Tmp & ~Mask) | TmpBuf;\r
714 CurOffset += BytesToWrite;\r
c2d1cf1b
MK
715 BytesToWrite = 0;\r
716 }\r
717 } else {\r
718 // Do multiple words, but starting unaligned.\r
719 if (BytesToWrite > (4 - (CurOffset & 0x3))) {\r
720 Mask = ((~0) << ((CurOffset & 0x3) * 8));\r
721 // Mask out the bytes we want.\r
722 TmpBuf &= Mask;\r
723 // Is the destination still in 'erased' state?\r
724 if ((Tmp & Mask) != Mask) {\r
725 // Check to see if we are only changing bits to zero.\r
726 if ((Tmp ^ TmpBuf) & TmpBuf) {\r
727 DoErase = TRUE;\r
728 break;\r
729 }\r
730 }\r
40b0b23e 731\r
c2d1cf1b 732 // Merge old and new data. Write merged word to NOR\r
40b0b23e 733 WordToWrite = (Tmp & ~Mask) | TmpBuf;\r
c2d1cf1b 734 BytesToWrite -= (4 - (CurOffset & 0x3));\r
40b0b23e 735 CurOffset += (4 - (CurOffset & 0x3));\r
c2d1cf1b
MK
736 } else {\r
737 // Unaligned and fits in one word.\r
738 Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);\r
739 // Mask out the bytes we want.\r
740 TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;\r
741 // Is the destination still in 'erased' state?\r
742 if ((Tmp & Mask) != Mask) {\r
743 // Check to see if we are only changing bits to zero.\r
744 if ((Tmp ^ TmpBuf) & TmpBuf) {\r
745 DoErase = TRUE;\r
746 break;\r
747 }\r
748 }\r
40b0b23e 749\r
c2d1cf1b 750 // Merge old and new data. Write merged word to NOR\r
40b0b23e
MK
751 WordToWrite = (Tmp & ~Mask) | TmpBuf;\r
752 CurOffset += BytesToWrite;\r
c2d1cf1b
MK
753 BytesToWrite = 0;\r
754 }\r
755 }\r
756\r
757 //\r
758 // Write the word to NOR.\r
759 //\r
760\r
761 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);\r
762 if (BlockAddress != PrevBlockAddress) {\r
763 TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);\r
764 if (EFI_ERROR (TempStatus)) {\r
765 return EFI_DEVICE_ERROR;\r
766 }\r
40b0b23e 767\r
c2d1cf1b
MK
768 PrevBlockAddress = BlockAddress;\r
769 }\r
40b0b23e 770\r
c2d1cf1b
MK
771 TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);\r
772 if (EFI_ERROR (TempStatus)) {\r
773 return EFI_DEVICE_ERROR;\r
774 }\r
775 }\r
40b0b23e 776\r
c2d1cf1b
MK
777 // Exit if we got here and could write all the data. Otherwise do the\r
778 // Erase-Write cycle.\r
779 if (!DoErase) {\r
780 return EFI_SUCCESS;\r
781 }\r
782 }\r
783\r
784 // Check we did get some memory. Buffer is BlockSize.\r
785 if (Instance->ShadowBuffer == NULL) {\r
786 DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));\r
787 return EFI_DEVICE_ERROR;\r
788 }\r
789\r
790 // Read NOR Flash data into shadow buffer\r
791 TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);\r
792 if (EFI_ERROR (TempStatus)) {\r
793 // Return one of the pre-approved error statuses\r
794 return EFI_DEVICE_ERROR;\r
795 }\r
796\r
797 // Put the data at the appropriate location inside the buffer area\r
40b0b23e 798 CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);\r
c2d1cf1b
MK
799\r
800 // Write the modified buffer back to the NorFlash\r
801 TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);\r
802 if (EFI_ERROR (TempStatus)) {\r
803 // Return one of the pre-approved error statuses\r
804 return EFI_DEVICE_ERROR;\r
805 }\r
806\r
807 return EFI_SUCCESS;\r
808}\r
809\r
810/*\r
811 Although DiskIoDxe will automatically install the DiskIO protocol whenever\r
812 we install the BlockIO protocol, its implementation is sub-optimal as it reads\r
813 and writes entire blocks using the BlockIO protocol. In fact we can access\r
814 NOR flash with a finer granularity than that, so we can improve performance\r
815 by directly producing the DiskIO protocol.\r
816*/\r
817\r
818/**\r
819 Read BufferSize bytes from Offset into Buffer.\r
820\r
821 @param This Protocol instance pointer.\r
822 @param MediaId Id of the media, changes every time the media is replaced.\r
823 @param Offset The starting byte offset to read from\r
824 @param BufferSize Size of Buffer\r
825 @param Buffer Buffer containing read data\r
826\r
827 @retval EFI_SUCCESS The data was read correctly from the device.\r
828 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
829 @retval EFI_NO_MEDIA There is no media in the device.\r
830 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
831 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not\r
832 valid for the device.\r
833\r
834**/\r
835EFI_STATUS\r
836EFIAPI\r
837NorFlashDiskIoReadDisk (\r
40b0b23e
MK
838 IN EFI_DISK_IO_PROTOCOL *This,\r
839 IN UINT32 MediaId,\r
840 IN UINT64 DiskOffset,\r
841 IN UINTN BufferSize,\r
842 OUT VOID *Buffer\r
c2d1cf1b
MK
843 )\r
844{\r
40b0b23e 845 NOR_FLASH_INSTANCE *Instance;\r
c2d1cf1b
MK
846 UINT32 BlockSize;\r
847 UINT32 BlockOffset;\r
848 EFI_LBA Lba;\r
849\r
40b0b23e 850 Instance = INSTANCE_FROM_DISKIO_THIS (This);\r
c2d1cf1b
MK
851\r
852 if (MediaId != Instance->Media.MediaId) {\r
853 return EFI_MEDIA_CHANGED;\r
854 }\r
855\r
856 BlockSize = Instance->Media.BlockSize;\r
40b0b23e 857 Lba = (EFI_LBA)DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);\r
c2d1cf1b
MK
858\r
859 return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer);\r
860}\r
861\r
862/**\r
863 Writes a specified number of bytes to a device.\r
864\r
865 @param This Indicates a pointer to the calling context.\r
866 @param MediaId ID of the medium to be written.\r
867 @param Offset The starting byte offset on the logical block I/O device to write.\r
868 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.\r
869 @param Buffer A pointer to the buffer containing the data to be written.\r
870\r
871 @retval EFI_SUCCESS The data was written correctly to the device.\r
872 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
873 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
874 @retval EFI_NO_MEDIA There is no media in the device.\r
875 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
876 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not\r
877 valid for the device.\r
878\r
879**/\r
880EFI_STATUS\r
881EFIAPI\r
882NorFlashDiskIoWriteDisk (\r
40b0b23e
MK
883 IN EFI_DISK_IO_PROTOCOL *This,\r
884 IN UINT32 MediaId,\r
885 IN UINT64 DiskOffset,\r
886 IN UINTN BufferSize,\r
887 IN VOID *Buffer\r
c2d1cf1b
MK
888 )\r
889{\r
40b0b23e 890 NOR_FLASH_INSTANCE *Instance;\r
c2d1cf1b
MK
891 UINT32 BlockSize;\r
892 UINT32 BlockOffset;\r
893 EFI_LBA Lba;\r
894 UINTN RemainingBytes;\r
895 UINTN WriteSize;\r
896 EFI_STATUS Status;\r
897\r
40b0b23e 898 Instance = INSTANCE_FROM_DISKIO_THIS (This);\r
c2d1cf1b
MK
899\r
900 if (MediaId != Instance->Media.MediaId) {\r
901 return EFI_MEDIA_CHANGED;\r
902 }\r
903\r
904 BlockSize = Instance->Media.BlockSize;\r
40b0b23e 905 Lba = (EFI_LBA)DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);\r
c2d1cf1b
MK
906\r
907 RemainingBytes = BufferSize;\r
908\r
909 // Write either all the remaining bytes, or the number of bytes that bring\r
910 // us up to a block boundary, whichever is less.\r
911 // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next\r
912 // block boundary (even if it is already on one).\r
913 WriteSize = MIN (RemainingBytes, ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset);\r
914\r
915 do {\r
916 if (WriteSize == BlockSize) {\r
917 // Write a full block\r
918 Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, BlockSize / sizeof (UINT32));\r
919 } else {\r
920 // Write a partial block\r
921 Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, Buffer);\r
922 }\r
40b0b23e 923\r
c2d1cf1b
MK
924 if (EFI_ERROR (Status)) {\r
925 return Status;\r
926 }\r
40b0b23e 927\r
c2d1cf1b
MK
928 // Now continue writing either all the remaining bytes or single blocks.\r
929 RemainingBytes -= WriteSize;\r
40b0b23e 930 Buffer = (UINT8 *)Buffer + WriteSize;\r
c2d1cf1b
MK
931 Lba++;\r
932 BlockOffset = 0;\r
40b0b23e 933 WriteSize = MIN (RemainingBytes, BlockSize);\r
c2d1cf1b
MK
934 } while (RemainingBytes);\r
935\r
936 return Status;\r
937}\r
938\r
939EFI_STATUS\r
940NorFlashReset (\r
40b0b23e 941 IN NOR_FLASH_INSTANCE *Instance\r
c2d1cf1b
MK
942 )\r
943{\r
944 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode\r
945 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);\r
946 return EFI_SUCCESS;\r
947}\r
948\r
949/**\r
950 Fixup internal data so that EFI can be call in virtual mode.\r
951 Call the passed in Child Notify event and convert any pointers in\r
952 lib to virtual mode.\r
953\r
954 @param[in] Event The Event that is being processed\r
955 @param[in] Context Event Context\r
956**/\r
957VOID\r
958EFIAPI\r
959NorFlashVirtualNotifyEvent (\r
40b0b23e
MK
960 IN EFI_EVENT Event,\r
961 IN VOID *Context\r
c2d1cf1b
MK
962 )\r
963{\r
40b0b23e 964 UINTN Index;\r
c2d1cf1b
MK
965\r
966 for (Index = 0; Index < mNorFlashDeviceCount; Index++) {\r
40b0b23e
MK
967 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress);\r
968 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress);\r
c2d1cf1b
MK
969\r
970 // Convert BlockIo protocol\r
40b0b23e
MK
971 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks);\r
972 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks);\r
973 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.Reset);\r
974 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks);\r
c2d1cf1b
MK
975\r
976 // Convert Fvb\r
40b0b23e
MK
977 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);\r
978 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);\r
979 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);\r
980 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);\r
981 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read);\r
982 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);\r
983 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write);\r
c2d1cf1b
MK
984\r
985 if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {\r
40b0b23e 986 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);\r
c2d1cf1b
MK
987 }\r
988 }\r
989\r
990 return;\r
991}\r