]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.c
ArmPlatformPkg: Apply uncrustify changes
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashStandaloneMm.c
CommitLineData
4e511554
MK
1/** @file NorFlashStandaloneMm.c\r
2\r
8015f3f6 3 Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>\r
4e511554
MK
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#include <Library/MemoryAllocationLib.h>\r
12#include <Library/MmServicesTableLib.h>\r
13\r
14#include "NorFlash.h"\r
15\r
16//\r
17// Global variable declarations\r
18//\r
40b0b23e
MK
19NOR_FLASH_INSTANCE **mNorFlashInstances;\r
20UINT32 mNorFlashDeviceCount;\r
21UINTN mFlashNvStorageVariableBase;\r
4e511554
MK
22\r
23NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {\r
24 NOR_FLASH_SIGNATURE, // Signature\r
40b0b23e 25 NULL, // Handle ... NEED TO BE FILLED\r
4e511554
MK
26\r
27 0, // DeviceBaseAddress ... NEED TO BE FILLED\r
28 0, // RegionBaseAddress ... NEED TO BE FILLED\r
29 0, // Size ... NEED TO BE FILLED\r
30 0, // StartLba\r
31\r
32 {\r
33 EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision\r
40b0b23e
MK
34 NULL, // Media ... NEED TO BE FILLED\r
35 NULL, // Reset;\r
36 NULL, // ReadBlocks\r
37 NULL, // WriteBlocks\r
38 NULL // FlushBlocks\r
4e511554
MK
39 }, // BlockIoProtocol\r
40\r
41 {\r
40b0b23e 42 0, // MediaId ... NEED TO BE FILLED\r
4e511554 43 FALSE, // RemovableMedia\r
40b0b23e 44 TRUE, // MediaPresent\r
4e511554
MK
45 FALSE, // LogicalPartition\r
46 FALSE, // ReadOnly\r
47 FALSE, // WriteCaching;\r
40b0b23e
MK
48 0, // BlockSize ... NEED TO BE FILLED\r
49 4, // IoAlign\r
50 0, // LastBlock ... NEED TO BE FILLED\r
51 0, // LowestAlignedLba\r
52 1, // LogicalBlocksPerPhysicalBlock\r
53 }, // Media;\r
4e511554
MK
54\r
55 {\r
56 EFI_DISK_IO_PROTOCOL_REVISION, // Revision\r
40b0b23e
MK
57 NULL, // ReadDisk\r
58 NULL // WriteDisk\r
4e511554
MK
59 },\r
60\r
61 {\r
40b0b23e
MK
62 FvbGetAttributes, // GetAttributes\r
63 FvbSetAttributes, // SetAttributes\r
64 FvbGetPhysicalAddress, // GetPhysicalAddress\r
65 FvbGetBlockSize, // GetBlockSize\r
66 FvbRead, // Read\r
67 FvbWrite, // Write\r
68 FvbEraseBlocks, // EraseBlocks\r
69 NULL, // ParentHandle\r
70 }, // FvbProtoccol;\r
4e511554
MK
71 NULL, // ShadowBuffer\r
72 {\r
73 {\r
74 {\r
75 HARDWARE_DEVICE_PATH,\r
76 HW_VENDOR_DP,\r
77 {\r
78 (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),\r
79 (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)\r
80 }\r
81 },\r
40b0b23e
MK
82 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\r
83 }, // GUID ... NEED TO BE FILLED\r
4e511554
MK
84 },\r
85 0, // Index\r
86 {\r
87 END_DEVICE_PATH_TYPE,\r
88 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
89 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
90 }\r
40b0b23e 91 } // DevicePath\r
4e511554
MK
92};\r
93\r
94EFI_STATUS\r
95NorFlashCreateInstance (\r
40b0b23e
MK
96 IN UINTN NorFlashDeviceBase,\r
97 IN UINTN NorFlashRegionBase,\r
98 IN UINTN NorFlashSize,\r
99 IN UINT32 Index,\r
100 IN UINT32 BlockSize,\r
101 IN BOOLEAN SupportFvb,\r
102 OUT NOR_FLASH_INSTANCE **NorFlashInstance\r
4e511554
MK
103 )\r
104{\r
40b0b23e
MK
105 EFI_STATUS Status;\r
106 NOR_FLASH_INSTANCE *Instance;\r
4e511554 107\r
40b0b23e 108 ASSERT (NorFlashInstance != NULL);\r
4e511554 109\r
40b0b23e 110 Instance = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INSTANCE), &mNorFlashInstanceTemplate);\r
4e511554
MK
111 if (Instance == NULL) {\r
112 return EFI_OUT_OF_RESOURCES;\r
113 }\r
114\r
115 Instance->DeviceBaseAddress = NorFlashDeviceBase;\r
116 Instance->RegionBaseAddress = NorFlashRegionBase;\r
40b0b23e 117 Instance->Size = NorFlashSize;\r
4e511554
MK
118\r
119 Instance->BlockIoProtocol.Media = &Instance->Media;\r
40b0b23e
MK
120 Instance->Media.MediaId = Index;\r
121 Instance->Media.BlockSize = BlockSize;\r
122 Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;\r
4e511554
MK
123\r
124 CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);\r
125 Instance->DevicePath.Index = (UINT8)Index;\r
126\r
40b0b23e 127 Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);\r
4e511554
MK
128 if (Instance->ShadowBuffer == NULL) {\r
129 return EFI_OUT_OF_RESOURCES;\r
130 }\r
131\r
132 if (SupportFvb) {\r
133 NorFlashFvbInitialize (Instance);\r
134\r
135 Status = gMmst->MmInstallProtocolInterface (\r
136 &Instance->Handle,\r
137 &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
138 EFI_NATIVE_INTERFACE,\r
139 &Instance->FvbProtocol\r
140 );\r
40b0b23e 141 if (EFI_ERROR (Status)) {\r
4e511554
MK
142 FreePool (Instance);\r
143 return Status;\r
144 }\r
145 } else {\r
40b0b23e 146 DEBUG ((DEBUG_ERROR, "standalone MM NOR Flash driver only support FVB.\n"));\r
4e511554
MK
147 FreePool (Instance);\r
148 return EFI_UNSUPPORTED;\r
149 }\r
150\r
151 *NorFlashInstance = Instance;\r
152 return Status;\r
153}\r
154\r
155/**\r
156 * This function unlock and erase an entire NOR Flash block.\r
157 **/\r
158EFI_STATUS\r
159NorFlashUnlockAndEraseSingleBlock (\r
40b0b23e
MK
160 IN NOR_FLASH_INSTANCE *Instance,\r
161 IN UINTN BlockAddress\r
4e511554
MK
162 )\r
163{\r
40b0b23e
MK
164 EFI_STATUS Status;\r
165 UINTN Index;\r
4e511554
MK
166\r
167 Index = 0;\r
168 // The block erase might fail a first time (SW bug ?). Retry it ...\r
169 do {\r
170 // Unlock the block if we have to\r
171 Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);\r
172 if (EFI_ERROR (Status)) {\r
173 break;\r
174 }\r
40b0b23e 175\r
4e511554
MK
176 Status = NorFlashEraseSingleBlock (Instance, BlockAddress);\r
177 Index++;\r
178 } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));\r
179\r
180 if (Index == NOR_FLASH_ERASE_RETRY) {\r
40b0b23e 181 DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress, Index));\r
4e511554
MK
182 }\r
183\r
184 return Status;\r
185}\r
186\r
187EFI_STATUS\r
188NorFlashWriteFullBlock (\r
40b0b23e
MK
189 IN NOR_FLASH_INSTANCE *Instance,\r
190 IN EFI_LBA Lba,\r
191 IN UINT32 *DataBuffer,\r
192 IN UINT32 BlockSizeInWords\r
4e511554
MK
193 )\r
194{\r
40b0b23e
MK
195 EFI_STATUS Status;\r
196 UINTN WordAddress;\r
197 UINT32 WordIndex;\r
198 UINTN BufferIndex;\r
199 UINTN BlockAddress;\r
200 UINTN BuffersInBlock;\r
201 UINTN RemainingWords;\r
202 UINTN Cnt;\r
4e511554
MK
203\r
204 Status = EFI_SUCCESS;\r
205\r
206 // Get the physical address of the block\r
207 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4);\r
208\r
209 // Start writing from the first address at the start of the block\r
210 WordAddress = BlockAddress;\r
211\r
212 Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);\r
40b0b23e
MK
213 if (EFI_ERROR (Status)) {\r
214 DEBUG ((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));\r
4e511554
MK
215 goto EXIT;\r
216 }\r
217\r
218 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.\r
219\r
220 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero\r
221 if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {\r
4e511554
MK
222 // First, break the entire block into buffer-sized chunks.\r
223 BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;\r
224\r
225 // Then feed each buffer chunk to the NOR Flash\r
226 // If a buffer does not contain any data, don't write it.\r
40b0b23e 227 for (BufferIndex = 0;\r
4e511554
MK
228 BufferIndex < BuffersInBlock;\r
229 BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS\r
40b0b23e
MK
230 )\r
231 {\r
4e511554
MK
232 // Check the buffer to see if it contains any data (not set all 1s).\r
233 for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {\r
234 if (~DataBuffer[Cnt] != 0 ) {\r
235 // Some data found, write the buffer.\r
40b0b23e
MK
236 Status = NorFlashWriteBuffer (\r
237 Instance,\r
238 WordAddress,\r
239 P30_MAX_BUFFER_SIZE_IN_BYTES,\r
240 DataBuffer\r
241 );\r
242 if (EFI_ERROR (Status)) {\r
4e511554
MK
243 goto EXIT;\r
244 }\r
40b0b23e 245\r
4e511554
MK
246 break;\r
247 }\r
248 }\r
249 }\r
250\r
251 // Finally, finish off any remaining words that are less than the maximum size of the buffer\r
252 RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;\r
253\r
40b0b23e 254 if (RemainingWords != 0) {\r
4e511554 255 Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);\r
40b0b23e 256 if (EFI_ERROR (Status)) {\r
4e511554
MK
257 goto EXIT;\r
258 }\r
259 }\r
4e511554
MK
260 } else {\r
261 // For now, use the single word programming algorithm\r
262 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,\r
263 // i.e. which ends in the range 0x......01 - 0x......7F.\r
40b0b23e 264 for (WordIndex = 0; WordIndex < BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {\r
4e511554 265 Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);\r
40b0b23e 266 if (EFI_ERROR (Status)) {\r
4e511554
MK
267 goto EXIT;\r
268 }\r
269 }\r
270 }\r
271\r
272EXIT:\r
40b0b23e
MK
273 if (EFI_ERROR (Status)) {\r
274 DEBUG ((DEBUG_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));\r
4e511554 275 }\r
40b0b23e 276\r
4e511554
MK
277 return Status;\r
278}\r
279\r
280EFI_STATUS\r
281EFIAPI\r
282NorFlashInitialise (\r
40b0b23e
MK
283 IN EFI_HANDLE ImageHandle,\r
284 IN EFI_MM_SYSTEM_TABLE *MmSystemTable\r
4e511554
MK
285 )\r
286{\r
40b0b23e
MK
287 EFI_STATUS Status;\r
288 UINT32 Index;\r
289 NOR_FLASH_DESCRIPTION *NorFlashDevices;\r
290 BOOLEAN ContainVariableStorage;\r
4e511554
MK
291\r
292 Status = NorFlashPlatformInitialization ();\r
40b0b23e
MK
293 if (EFI_ERROR (Status)) {\r
294 DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to initialize Nor Flash devices\n"));\r
4e511554
MK
295 return Status;\r
296 }\r
297\r
298 Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);\r
40b0b23e
MK
299 if (EFI_ERROR (Status)) {\r
300 DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to get Nor Flash devices\n"));\r
4e511554
MK
301 return Status;\r
302 }\r
303\r
40b0b23e 304 mNorFlashInstances = AllocatePool (sizeof (NOR_FLASH_INSTANCE *) * mNorFlashDeviceCount);\r
4e511554
MK
305\r
306 for (Index = 0; Index < mNorFlashDeviceCount; Index++) {\r
307 // Check if this NOR Flash device contain the variable storage region\r
8015f3f6 308\r
40b0b23e
MK
309 if (FixedPcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {\r
310 ContainVariableStorage =\r
311 (NorFlashDevices[Index].RegionBaseAddress <= FixedPcdGet64 (PcdFlashNvStorageVariableBase64)) &&\r
312 (FixedPcdGet64 (PcdFlashNvStorageVariableBase64) + FixedPcdGet32 (PcdFlashNvStorageVariableSize) <=\r
313 NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);\r
314 } else {\r
315 ContainVariableStorage =\r
316 (NorFlashDevices[Index].RegionBaseAddress <= FixedPcdGet32 (PcdFlashNvStorageVariableBase)) &&\r
317 (FixedPcdGet32 (PcdFlashNvStorageVariableBase) + FixedPcdGet32 (PcdFlashNvStorageVariableSize) <=\r
318 NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);\r
319 }\r
4e511554
MK
320\r
321 Status = NorFlashCreateInstance (\r
40b0b23e
MK
322 NorFlashDevices[Index].DeviceBaseAddress,\r
323 NorFlashDevices[Index].RegionBaseAddress,\r
324 NorFlashDevices[Index].Size,\r
325 Index,\r
326 NorFlashDevices[Index].BlockSize,\r
327 ContainVariableStorage,\r
328 &mNorFlashInstances[Index]\r
329 );\r
330 if (EFI_ERROR (Status)) {\r
331 DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n", Index));\r
4e511554
MK
332 }\r
333 }\r
334\r
335 return Status;\r
336}\r
337\r
338EFI_STATUS\r
339EFIAPI\r
340NorFlashFvbInitialize (\r
40b0b23e 341 IN NOR_FLASH_INSTANCE *Instance\r
4e511554
MK
342 )\r
343{\r
344 EFI_STATUS Status;\r
345 UINT32 FvbNumLba;\r
346\r
40b0b23e 347 ASSERT ((Instance != NULL));\r
4e511554 348\r
8015f3f6 349 mFlashNvStorageVariableBase = (FixedPcdGet64 (PcdFlashNvStorageVariableBase64) != 0) ?\r
40b0b23e 350 FixedPcdGet64 (PcdFlashNvStorageVariableBase64) : FixedPcdGet32 (PcdFlashNvStorageVariableBase);\r
4e511554 351 // Set the index of the first LBA for the FVB\r
8015f3f6 352 Instance->StartLba = (mFlashNvStorageVariableBase - Instance->RegionBaseAddress) / Instance->Media.BlockSize;\r
4e511554
MK
353\r
354 // Determine if there is a valid header at the beginning of the NorFlash\r
355 Status = ValidateFvHeader (Instance);\r
356\r
357 // Install the Default FVB header if required\r
40b0b23e 358 if (EFI_ERROR (Status)) {\r
4e511554
MK
359 // There is no valid header, so time to install one.\r
360 DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__));\r
40b0b23e
MK
361 DEBUG ((\r
362 DEBUG_INFO,\r
363 "%a: Installing a correct one for this volume.\n",\r
364 __FUNCTION__\r
365 ));\r
4e511554
MK
366\r
367 // Erase all the NorFlash that is reserved for variable storage\r
40b0b23e 368 FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize;\r
4e511554
MK
369\r
370 Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR);\r
40b0b23e 371 if (EFI_ERROR (Status)) {\r
4e511554
MK
372 return Status;\r
373 }\r
374\r
375 // Install all appropriate headers\r
376 Status = InitializeFvAndVariableStoreHeaders (Instance);\r
40b0b23e 377 if (EFI_ERROR (Status)) {\r
4e511554
MK
378 return Status;\r
379 }\r
380 }\r
381\r
382 return Status;\r
383}\r