]> git.proxmox.com Git - mirror_edk2.git/blame - Omap35xxPkg/Flash/Flash.c
Omap35xxPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / Omap35xxPkg / Flash / Flash.c
CommitLineData
1e57a462 1/** @file\r
2\r
3 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
3402aac7 4\r
538311f7 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1e57a462 6\r
7**/\r
8\r
9#include "Flash.h"\r
10\r
11NAND_PART_INFO_TABLE gNandPartInfoTable[1] = {\r
12 { 0x2C, 0xBA, 17, 11 }\r
13};\r
14\r
15NAND_FLASH_INFO *gNandFlashInfo = NULL;\r
16UINT8 *gEccCode;\r
17UINTN gNum512BytesChunks = 0;\r
18\r
19//\r
20\r
21// Device path for SemiHosting. It contains our autogened Caller ID GUID.\r
22\r
23//\r
24\r
25typedef struct {\r
26\r
27 VENDOR_DEVICE_PATH Guid;\r
28\r
29 EFI_DEVICE_PATH_PROTOCOL End;\r
30\r
31} FLASH_DEVICE_PATH;\r
32\r
33\r
34\r
35FLASH_DEVICE_PATH gDevicePath = {\r
1e57a462 36 {\r
b0fdce95 37 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },\r
1e57a462 38 EFI_CALLER_ID_GUID\r
1e57a462 39 },\r
b0fdce95 40 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0} }\r
1e57a462 41};\r
42\r
43\r
44\r
45//Actual page address = Column address + Page address + Block address.\r
46UINTN\r
47GetActualPageAddressInBytes (\r
48 UINTN BlockIndex,\r
49 UINTN PageIndex\r
50)\r
51{\r
52 //BlockAddressStart = Start of the Block address in actual NAND\r
53 //PageAddressStart = Start of the Page address in actual NAND\r
54 return ((BlockIndex << gNandFlashInfo->BlockAddressStart) + (PageIndex << gNandFlashInfo->PageAddressStart));\r
55}\r
56\r
57VOID\r
58NandSendCommand (\r
59 UINT8 Command\r
60)\r
61{\r
62 MmioWrite16(GPMC_NAND_COMMAND_0, Command);\r
63}\r
64\r
65VOID\r
66NandSendAddress (\r
67 UINT8 Address\r
68)\r
69{\r
70 MmioWrite16(GPMC_NAND_ADDRESS_0, Address);\r
71}\r
72\r
73UINT16\r
74NandReadStatus (\r
75 VOID\r
76 )\r
77{\r
78 //Send READ STATUS command\r
79 NandSendCommand(READ_STATUS_CMD);\r
80\r
81 //Read status.\r
82 return MmioRead16(GPMC_NAND_DATA_0);\r
83}\r
84\r
85VOID\r
86NandSendAddressCycles (\r
87 UINTN Address\r
88)\r
89{\r
90 //Column address\r
91 NandSendAddress(Address & 0xff);\r
92 Address >>= 8;\r
93\r
94 //Column address\r
95 NandSendAddress(Address & 0x07);\r
96 Address >>= 3;\r
97\r
98 //Page and Block address\r
99 NandSendAddress(Address & 0xff);\r
100 Address >>= 8;\r
101\r
102 //Block address\r
103 NandSendAddress(Address & 0xff);\r
104 Address >>= 8;\r
105\r
106 //Block address\r
107 NandSendAddress(Address & 0x01);\r
108}\r
109\r
110VOID\r
111GpmcInit (\r
112 VOID\r
113 )\r
114{\r
115 //Enable Smart-idle mode.\r
116 MmioWrite32 (GPMC_SYSCONFIG, SMARTIDLEMODE);\r
117\r
118 //Set IRQSTATUS and IRQENABLE to the reset value\r
119 MmioWrite32 (GPMC_IRQSTATUS, 0x0);\r
120 MmioWrite32 (GPMC_IRQENABLE, 0x0);\r
121\r
122 //Disable GPMC timeout control.\r
123 MmioWrite32 (GPMC_TIMEOUT_CONTROL, TIMEOUTDISABLE);\r
124\r
125 //Set WRITEPROTECT bit to enable write access.\r
126 MmioWrite32 (GPMC_CONFIG, WRITEPROTECT_HIGH);\r
127\r
128 //NOTE: Following GPMC_CONFIGi_0 register settings are taken from u-boot memory dump.\r
129 MmioWrite32 (GPMC_CONFIG1_0, DEVICETYPE_NAND | DEVICESIZE_X16);\r
130 MmioWrite32 (GPMC_CONFIG2_0, CSRDOFFTIME | CSWROFFTIME);\r
131 MmioWrite32 (GPMC_CONFIG3_0, ADVRDOFFTIME | ADVWROFFTIME);\r
132 MmioWrite32 (GPMC_CONFIG4_0, OEONTIME | OEOFFTIME | WEONTIME | WEOFFTIME);\r
133 MmioWrite32 (GPMC_CONFIG5_0, RDCYCLETIME | WRCYCLETIME | RDACCESSTIME | PAGEBURSTACCESSTIME);\r
134 MmioWrite32 (GPMC_CONFIG6_0, WRACCESSTIME | WRDATAONADMUXBUS | CYCLE2CYCLEDELAY | CYCLE2CYCLESAMECSEN);\r
135 MmioWrite32 (GPMC_CONFIG7_0, MASKADDRESS_128MB | CSVALID | BASEADDRESS);\r
136}\r
137\r
138EFI_STATUS\r
139NandDetectPart (\r
140 VOID\r
141)\r
142{\r
143 UINT8 NandInfo = 0;\r
144 UINT8 PartInfo[5];\r
145 UINTN Index;\r
146 BOOLEAN Found = FALSE;\r
147\r
148 //Send READ ID command\r
149 NandSendCommand(READ_ID_CMD);\r
150\r
151 //Send one address cycle.\r
152 NandSendAddress(0);\r
153\r
154 //Read 5-bytes to idenfity code programmed into the NAND flash devices.\r
155 //BYTE 0 = Manufacture ID\r
156 //Byte 1 = Device ID\r
157 //Byte 2, 3, 4 = Nand part specific information (Page size, Block size etc)\r
158 for (Index = 0; Index < sizeof(PartInfo); Index++) {\r
159 PartInfo[Index] = MmioRead16(GPMC_NAND_DATA_0);\r
160 }\r
161\r
162 //Check if the ManufactureId and DeviceId are part of the currently supported nand parts.\r
163 for (Index = 0; Index < sizeof(gNandPartInfoTable)/sizeof(NAND_PART_INFO_TABLE); Index++) {\r
164 if (gNandPartInfoTable[Index].ManufactureId == PartInfo[0] && gNandPartInfoTable[Index].DeviceId == PartInfo[1]) {\r
165 gNandFlashInfo->BlockAddressStart = gNandPartInfoTable[Index].BlockAddressStart;\r
166 gNandFlashInfo->PageAddressStart = gNandPartInfoTable[Index].PageAddressStart;\r
167 Found = TRUE;\r
168 break;\r
169 }\r
170 }\r
171\r
172 if (Found == FALSE) {\r
173 DEBUG ((EFI_D_ERROR, "Nand part is not currently supported. Manufacture id: %x, Device id: %x\n", PartInfo[0], PartInfo[1]));\r
174 return EFI_NOT_FOUND;\r
175 }\r
176\r
177 //Populate NAND_FLASH_INFO based on the result of READ ID command.\r
178 gNandFlashInfo->ManufactureId = PartInfo[0];\r
179 gNandFlashInfo->DeviceId = PartInfo[1];\r
180 NandInfo = PartInfo[3];\r
181\r
182 if (PAGE_SIZE(NandInfo) == PAGE_SIZE_2K_VAL) {\r
183 gNandFlashInfo->PageSize = PAGE_SIZE_2K;\r
184 } else {\r
185 DEBUG ((EFI_D_ERROR, "Unknown Page size.\n"));\r
186 return EFI_DEVICE_ERROR;\r
187 }\r
188\r
189 if (SPARE_AREA_SIZE(NandInfo) == SPARE_AREA_SIZE_64B_VAL) {\r
190 gNandFlashInfo->SparePageSize = SPARE_AREA_SIZE_64B;\r
191 } else {\r
192 DEBUG ((EFI_D_ERROR, "Unknown Spare area size.\n"));\r
193 return EFI_DEVICE_ERROR;\r
194 }\r
195\r
196 if (BLOCK_SIZE(NandInfo) == BLOCK_SIZE_128K_VAL) {\r
197 gNandFlashInfo->BlockSize = BLOCK_SIZE_128K;\r
198 } else {\r
199 DEBUG ((EFI_D_ERROR, "Unknown Block size.\n"));\r
200 return EFI_DEVICE_ERROR;\r
201 }\r
202\r
203 if (ORGANIZATION(NandInfo) == ORGANIZATION_X8) {\r
204 gNandFlashInfo->Organization = 0;\r
205 } else if (ORGANIZATION(NandInfo) == ORGANIZATION_X16) {\r
206 gNandFlashInfo->Organization = 1;\r
207 }\r
208\r
209 //Calculate total number of blocks.\r
210 gNandFlashInfo->NumPagesPerBlock = DivU64x32(gNandFlashInfo->BlockSize, gNandFlashInfo->PageSize);\r
211\r
212 return EFI_SUCCESS;\r
213}\r
214\r
215VOID\r
216NandConfigureEcc (\r
217 VOID\r
218 )\r
219{\r
220 //Define ECC size 0 and size 1 to 512 bytes\r
221 MmioWrite32 (GPMC_ECC_SIZE_CONFIG, (ECCSIZE0_512BYTES | ECCSIZE1_512BYTES));\r
222}\r
223\r
3402aac7 224VOID\r
1e57a462 225NandEnableEcc (\r
226 VOID\r
227 )\r
228{\r
229 //Clear all the ECC result registers and select ECC result register 1\r
230 MmioWrite32 (GPMC_ECC_CONTROL, (ECCCLEAR | ECCPOINTER_REG1));\r
231\r
232 //Enable ECC engine on CS0\r
233 MmioWrite32 (GPMC_ECC_CONFIG, (ECCENABLE | ECCCS_0 | ECC16B));\r
234}\r
235\r
236VOID\r
237NandDisableEcc (\r
238 VOID\r
239 )\r
240{\r
241 //Turn off ECC engine.\r
242 MmioWrite32 (GPMC_ECC_CONFIG, ECCDISABLE);\r
243}\r
244\r
245VOID\r
246NandCalculateEcc (\r
247 VOID\r
248 )\r
249{\r
250 UINTN Index;\r
251 UINTN EccResultRegister;\r
252 UINTN EccResult;\r
253\r
254 //Capture 32-bit ECC result for each 512-bytes chunk.\r
255 //In our case PageSize is 2K so read ECC1-ECC4 result registers and\r
256 //generate total of 12-bytes of ECC code for the particular page.\r
257\r
258 EccResultRegister = GPMC_ECC1_RESULT;\r
259\r
260 for (Index = 0; Index < gNum512BytesChunks; Index++) {\r
261\r
262 EccResult = MmioRead32 (EccResultRegister);\r
263\r
264 //Calculate ECC code from 32-bit ECC result value.\r
3402aac7 265 //NOTE: Following calculation is not part of TRM. We got this information\r
1e57a462 266 //from Beagleboard mailing list.\r
267 gEccCode[Index * 3] = EccResult & 0xFF;\r
268 gEccCode[(Index * 3) + 1] = (EccResult >> 16) & 0xFF;\r
269 gEccCode[(Index * 3) + 2] = (((EccResult >> 20) & 0xF0) | ((EccResult >> 8) & 0x0F));\r
270\r
271 //Point to next ECC result register.\r
272 EccResultRegister += 4;\r
273 }\r
274}\r
275\r
276EFI_STATUS\r
277NandReadPage (\r
278 IN UINTN BlockIndex,\r
279 IN UINTN PageIndex,\r
280 OUT VOID *Buffer,\r
281 OUT UINT8 *SpareBuffer\r
282)\r
283{\r
284 UINTN Address;\r
285 UINTN Index;\r
286 UINTN NumMainAreaWords = (gNandFlashInfo->PageSize/2);\r
287 UINTN NumSpareAreaWords = (gNandFlashInfo->SparePageSize/2);\r
288 UINT16 *MainAreaWordBuffer = Buffer;\r
289 UINT16 *SpareAreaWordBuffer = (UINT16 *)SpareBuffer;\r
290 UINTN Timeout = MAX_RETRY_COUNT;\r
291\r
292 //Generate device address in bytes to access specific block and page index\r
293 Address = GetActualPageAddressInBytes(BlockIndex, PageIndex);\r
294\r
295 //Send READ command\r
296 NandSendCommand(PAGE_READ_CMD);\r
297\r
298 //Send 5 Address cycles to access specific device address\r
299 NandSendAddressCycles(Address);\r
300\r
301 //Send READ CONFIRM command\r
302 NandSendCommand(PAGE_READ_CONFIRM_CMD);\r
303\r
304 //Poll till device is busy.\r
305 while (Timeout) {\r
306 if ((NandReadStatus() & NAND_READY) == NAND_READY) {\r
307 break;\r
308 }\r
309 Timeout--;\r
310 }\r
311\r
312 if (Timeout == 0) {\r
313 DEBUG ((EFI_D_ERROR, "Read page timed out.\n"));\r
314 return EFI_TIMEOUT;\r
315 }\r
316\r
317 //Reissue READ command\r
318 NandSendCommand(PAGE_READ_CMD);\r
319\r
320 //Enable ECC engine.\r
321 NandEnableEcc();\r
322\r
323 //Read data into the buffer.\r
324 for (Index = 0; Index < NumMainAreaWords; Index++) {\r
325 *MainAreaWordBuffer++ = MmioRead16(GPMC_NAND_DATA_0);\r
326 }\r
327\r
328 //Read spare area into the buffer.\r
329 for (Index = 0; Index < NumSpareAreaWords; Index++) {\r
330 *SpareAreaWordBuffer++ = MmioRead16(GPMC_NAND_DATA_0);\r
331 }\r
332\r
333 //Calculate ECC.\r
334 NandCalculateEcc();\r
335\r
336 //Turn off ECC engine.\r
337 NandDisableEcc();\r
338\r
339 //Perform ECC correction.\r
340 //Need to implement..\r
341\r
342 return EFI_SUCCESS;\r
343}\r
344\r
345EFI_STATUS\r
346NandWritePage (\r
347 IN UINTN BlockIndex,\r
348 IN UINTN PageIndex,\r
349 OUT VOID *Buffer,\r
350 IN UINT8 *SpareBuffer\r
351)\r
352{\r
353 UINTN Address;\r
354 UINT16 *MainAreaWordBuffer = Buffer;\r
355 UINT16 *SpareAreaWordBuffer = (UINT16 *)SpareBuffer;\r
356 UINTN Index;\r
357 UINTN NandStatus;\r
358 UINTN Timeout = MAX_RETRY_COUNT;\r
359\r
360 //Generate device address in bytes to access specific block and page index\r
361 Address = GetActualPageAddressInBytes(BlockIndex, PageIndex);\r
362\r
363 //Send SERIAL DATA INPUT command\r
364 NandSendCommand(PROGRAM_PAGE_CMD);\r
365\r
366 //Send 5 Address cycles to access specific device address\r
367 NandSendAddressCycles(Address);\r
368\r
369 //Enable ECC engine.\r
370 NandEnableEcc();\r
371\r
372 //Data input from Buffer\r
373 for (Index = 0; Index < (gNandFlashInfo->PageSize/2); Index++) {\r
374 MmioWrite16(GPMC_NAND_DATA_0, *MainAreaWordBuffer++);\r
375\r
376 //After each write access, device has to wait to accept data.\r
3402aac7 377 //Currently we may not be programming proper timing parameters to\r
1e57a462 378 //the GPMC_CONFIGi_0 registers and we would need to figure that out.\r
379 //Without following delay, page programming fails.\r
380 gBS->Stall(1);\r
381 }\r
382\r
383 //Calculate ECC.\r
384 NandCalculateEcc();\r
385\r
386 //Turn off ECC engine.\r
387 NandDisableEcc();\r
388\r
389 //Prepare Spare area buffer with ECC codes.\r
390 SetMem(SpareBuffer, gNandFlashInfo->SparePageSize, 0xFF);\r
391 CopyMem(&SpareBuffer[ECC_POSITION], gEccCode, gNum512BytesChunks * 3);\r
392\r
393 //Program spare area with calculated ECC.\r
394 for (Index = 0; Index < (gNandFlashInfo->SparePageSize/2); Index++) {\r
395 MmioWrite16(GPMC_NAND_DATA_0, *SpareAreaWordBuffer++);\r
396 }\r
397\r
398 //Send PROGRAM command\r
399 NandSendCommand(PROGRAM_PAGE_CONFIRM_CMD);\r
400\r
401 //Poll till device is busy.\r
402 NandStatus = 0;\r
403 while (Timeout) {\r
404 NandStatus = NandReadStatus();\r
405 if ((NandStatus & NAND_READY) == NAND_READY) {\r
406 break;\r
407 }\r
408 Timeout--;\r
409 }\r
410\r
411 if (Timeout == 0) {\r
412 DEBUG ((EFI_D_ERROR, "Program page timed out.\n"));\r
413 return EFI_TIMEOUT;\r
414 }\r
415\r
416 //Bit0 indicates Pass/Fail status\r
417 if (NandStatus & NAND_FAILURE) {\r
418 return EFI_DEVICE_ERROR;\r
419 }\r
420\r
421 return EFI_SUCCESS;\r
422}\r
423\r
424EFI_STATUS\r
425NandEraseBlock (\r
426 IN UINTN BlockIndex\r
427)\r
428{\r
429 UINTN Address;\r
430 UINTN NandStatus;\r
431 UINTN Timeout = MAX_RETRY_COUNT;\r
432\r
433 //Generate device address in bytes to access specific block and page index\r
434 Address = GetActualPageAddressInBytes(BlockIndex, 0);\r
435\r
436 //Send ERASE SETUP command\r
437 NandSendCommand(BLOCK_ERASE_CMD);\r
438\r
439 //Send 3 address cycles to device to access Page address and Block address\r
440 Address >>= 11; //Ignore column addresses\r
441\r
442 NandSendAddress(Address & 0xff);\r
443 Address >>= 8;\r
444\r
445 NandSendAddress(Address & 0xff);\r
446 Address >>= 8;\r
447\r
448 NandSendAddress(Address & 0xff);\r
449\r
450 //Send ERASE CONFIRM command\r
451 NandSendCommand(BLOCK_ERASE_CONFIRM_CMD);\r
452\r
453 //Poll till device is busy.\r
454 NandStatus = 0;\r
455 while (Timeout) {\r
456 NandStatus = NandReadStatus();\r
457 if ((NandStatus & NAND_READY) == NAND_READY) {\r
458 break;\r
459 }\r
460 Timeout--;\r
461 gBS->Stall(1);\r
462 }\r
463\r
464 if (Timeout == 0) {\r
465 DEBUG ((EFI_D_ERROR, "Erase block timed out for Block: %d.\n", BlockIndex));\r
466 return EFI_TIMEOUT;\r
467 }\r
468\r
469 //Bit0 indicates Pass/Fail status\r
470 if (NandStatus & NAND_FAILURE) {\r
471 return EFI_DEVICE_ERROR;\r
472 }\r
473\r
474 return EFI_SUCCESS;\r
475}\r
476\r
477EFI_STATUS\r
478NandReadBlock (\r
479 IN UINTN StartBlockIndex,\r
480 IN UINTN EndBlockIndex,\r
481 OUT VOID *Buffer,\r
482 OUT VOID *SpareBuffer\r
483)\r
484{\r
485 UINTN BlockIndex;\r
486 UINTN PageIndex;\r
487 EFI_STATUS Status = EFI_SUCCESS;\r
488\r
489 for (BlockIndex = StartBlockIndex; BlockIndex <= EndBlockIndex; BlockIndex++) {\r
490 //For each block read number of pages\r
491 for (PageIndex = 0; PageIndex < gNandFlashInfo->NumPagesPerBlock; PageIndex++) {\r
492 Status = NandReadPage(BlockIndex, PageIndex, Buffer, SpareBuffer);\r
493 if (EFI_ERROR(Status)) {\r
494 return Status;\r
495 }\r
496 Buffer = ((UINT8 *)Buffer + gNandFlashInfo->PageSize);\r
497 }\r
498 }\r
499\r
500 return Status;\r
501}\r
502\r
503EFI_STATUS\r
504NandWriteBlock (\r
505 IN UINTN StartBlockIndex,\r
506 IN UINTN EndBlockIndex,\r
507 OUT VOID *Buffer,\r
508 OUT VOID *SpareBuffer\r
509 )\r
510{\r
511 UINTN BlockIndex;\r
512 UINTN PageIndex;\r
513 EFI_STATUS Status = EFI_SUCCESS;\r
514\r
515 for (BlockIndex = StartBlockIndex; BlockIndex <= EndBlockIndex; BlockIndex++) {\r
516 //Page programming.\r
517 for (PageIndex = 0; PageIndex < gNandFlashInfo->NumPagesPerBlock; PageIndex++) {\r
518 Status = NandWritePage(BlockIndex, PageIndex, Buffer, SpareBuffer);\r
519 if (EFI_ERROR(Status)) {\r
520 return Status;\r
521 }\r
522 Buffer = ((UINT8 *)Buffer + gNandFlashInfo->PageSize);\r
523 }\r
524 }\r
525\r
526 return Status;\r
527}\r
528\r
529EFI_STATUS\r
530EFIAPI\r
531NandFlashReset (\r
532 IN EFI_BLOCK_IO_PROTOCOL *This,\r
533 IN BOOLEAN ExtendedVerification\r
534 )\r
535{\r
536 UINTN BusyStall = 50; // microSeconds\r
537 UINTN ResetBusyTimeout = (1000000 / BusyStall); // 1 Second\r
538\r
539 //Send RESET command to device.\r
540 NandSendCommand(RESET_CMD);\r
3402aac7 541\r
1e57a462 542 //Wait for 1ms before we check status register.\r
543 gBS->Stall(1000);\r
544\r
545 //Check BIT#5 & BIT#6 in Status register to make sure RESET is done.\r
546 while ((NandReadStatus() & NAND_RESET_STATUS) != NAND_RESET_STATUS) {\r
547\r
548 //In case of extended verification, wait for extended amount of time\r
549 //to make sure device is reset.\r
550 if (ExtendedVerification) {\r
551 if (ResetBusyTimeout == 0) {\r
552 return EFI_DEVICE_ERROR;\r
553 }\r
554\r
555 gBS->Stall(BusyStall);\r
556 ResetBusyTimeout--;\r
557 }\r
558 }\r
3402aac7 559\r
1e57a462 560 return EFI_SUCCESS;\r
561}\r
562\r
563EFI_STATUS\r
564EFIAPI\r
565NandFlashReadBlocks (\r
566 IN EFI_BLOCK_IO_PROTOCOL *This,\r
567 IN UINT32 MediaId,\r
568 IN EFI_LBA Lba,\r
569 IN UINTN BufferSize,\r
570 OUT VOID *Buffer\r
571 )\r
572{\r
573 UINTN NumBlocks;\r
574 UINTN EndBlockIndex;\r
575 EFI_STATUS Status;\r
576 UINT8 *SpareBuffer = NULL;\r
577\r
578 if (Buffer == NULL) {\r
579 Status = EFI_INVALID_PARAMETER;\r
580 goto exit;\r
581 }\r
3402aac7 582\r
1e57a462 583 if (Lba > LAST_BLOCK) {\r
584 Status = EFI_INVALID_PARAMETER;\r
585 goto exit;\r
586 }\r
3402aac7 587\r
1e57a462 588 if ((BufferSize % gNandFlashInfo->BlockSize) != 0) {\r
589 Status = EFI_BAD_BUFFER_SIZE;\r
590 goto exit;\r
591 }\r
592\r
593 NumBlocks = DivU64x32(BufferSize, gNandFlashInfo->BlockSize);\r
594 EndBlockIndex = ((UINTN)Lba + NumBlocks) - 1;\r
595\r
596 SpareBuffer = (UINT8 *)AllocatePool(gNandFlashInfo->SparePageSize);\r
597 if (SpareBuffer == NULL) {\r
598 Status = EFI_OUT_OF_RESOURCES;\r
599 goto exit;\r
600 }\r
601\r
602 //Read block\r
603 Status = NandReadBlock((UINTN)Lba, EndBlockIndex, Buffer, SpareBuffer);\r
604 if (EFI_ERROR(Status)) {\r
605 DEBUG((EFI_D_ERROR, "Read block fails: %x\n", Status));\r
606 goto exit;\r
607 }\r
608\r
609exit:\r
610 if (SpareBuffer != NULL) {\r
611 FreePool (SpareBuffer);\r
612 }\r
613\r
614 return Status;\r
615}\r
616\r
617EFI_STATUS\r
618EFIAPI\r
619NandFlashWriteBlocks (\r
620 IN EFI_BLOCK_IO_PROTOCOL *This,\r
621 IN UINT32 MediaId,\r
622 IN EFI_LBA Lba,\r
623 IN UINTN BufferSize,\r
624 IN VOID *Buffer\r
625 )\r
626{\r
627 UINTN BlockIndex;\r
628 UINTN NumBlocks;\r
629 UINTN EndBlockIndex;\r
630 EFI_STATUS Status;\r
631 UINT8 *SpareBuffer = NULL;\r
632\r
633 if (Buffer == NULL) {\r
634 Status = EFI_INVALID_PARAMETER;\r
635 goto exit;\r
636 }\r
3402aac7 637\r
1e57a462 638 if (Lba > LAST_BLOCK) {\r
639 Status = EFI_INVALID_PARAMETER;\r
640 goto exit;\r
641 }\r
3402aac7 642\r
1e57a462 643 if ((BufferSize % gNandFlashInfo->BlockSize) != 0) {\r
644 Status = EFI_BAD_BUFFER_SIZE;\r
645 goto exit;\r
646 }\r
647\r
648 NumBlocks = DivU64x32(BufferSize, gNandFlashInfo->BlockSize);\r
649 EndBlockIndex = ((UINTN)Lba + NumBlocks) - 1;\r
650\r
651 SpareBuffer = (UINT8 *)AllocatePool(gNandFlashInfo->SparePageSize);\r
652 if (SpareBuffer == NULL) {\r
653 Status = EFI_OUT_OF_RESOURCES;\r
654 goto exit;\r
655 }\r
656\r
657 // Erase block\r
658 for (BlockIndex = (UINTN)Lba; BlockIndex <= EndBlockIndex; BlockIndex++) {\r
659 Status = NandEraseBlock(BlockIndex);\r
660 if (EFI_ERROR(Status)) {\r
661 DEBUG((EFI_D_ERROR, "Erase block failed. Status: %x\n", Status));\r
662 goto exit;\r
663 }\r
664 }\r
3402aac7 665\r
1e57a462 666 // Program data\r
667 Status = NandWriteBlock((UINTN)Lba, EndBlockIndex, Buffer, SpareBuffer);\r
668 if (EFI_ERROR(Status)) {\r
669 DEBUG((EFI_D_ERROR, "Block write fails: %x\n", Status));\r
670 goto exit;\r
671 }\r
672\r
673exit:\r
674 if (SpareBuffer != NULL) {\r
675 FreePool (SpareBuffer);\r
676 }\r
677\r
678 return Status;\r
679}\r
680\r
681EFI_STATUS\r
682EFIAPI\r
683NandFlashFlushBlocks (\r
684 IN EFI_BLOCK_IO_PROTOCOL *This\r
685 )\r
686{\r
687 return EFI_SUCCESS;\r
688}\r
689\r
690\r
691\r
692EFI_BLOCK_IO_MEDIA gNandFlashMedia = {\r
693 SIGNATURE_32('n','a','n','d'), // MediaId\r
694 FALSE, // RemovableMedia\r
695 TRUE, // MediaPresent\r
696 FALSE, // LogicalPartition\r
697 FALSE, // ReadOnly\r
698 FALSE, // WriteCaching\r
699 0, // BlockSize\r
700 2, // IoAlign\r
701 0, // Pad\r
702 0 // LastBlock\r
703};\r
704\r
3402aac7 705EFI_BLOCK_IO_PROTOCOL BlockIo =\r
1e57a462 706{\r
707 EFI_BLOCK_IO_INTERFACE_REVISION, // Revision\r
708 &gNandFlashMedia, // *Media\r
709 NandFlashReset, // Reset\r
710 NandFlashReadBlocks, // ReadBlocks\r
711 NandFlashWriteBlocks, // WriteBlocks\r
712 NandFlashFlushBlocks // FlushBlocks\r
713};\r
714\r
715EFI_STATUS\r
716NandFlashInitialize (\r
717 IN EFI_HANDLE ImageHandle,\r
718 IN EFI_SYSTEM_TABLE *SystemTable\r
719 )\r
720{\r
721 EFI_STATUS Status;\r
3402aac7 722\r
1e57a462 723 gNandFlashInfo = (NAND_FLASH_INFO *)AllocateZeroPool (sizeof(NAND_FLASH_INFO));\r
724\r
725 //Initialize GPMC module.\r
726 GpmcInit();\r
727\r
728 //Reset NAND part\r
729 NandFlashReset(&BlockIo, FALSE);\r
730\r
731 //Detect NAND part and populate gNandFlashInfo structure\r
732 Status = NandDetectPart ();\r
733 if (EFI_ERROR(Status)) {\r
734 DEBUG((EFI_D_ERROR, "Nand part id detection failure: Status: %x\n", Status));\r
735 return Status;\r
736 }\r
737\r
738 //Count total number of 512Bytes chunk based on the page size.\r
739 if (gNandFlashInfo->PageSize == PAGE_SIZE_512B) {\r
740 gNum512BytesChunks = 1;\r
741 } else if (gNandFlashInfo->PageSize == PAGE_SIZE_2K) {\r
742 gNum512BytesChunks = 4;\r
743 } else if (gNandFlashInfo->PageSize == PAGE_SIZE_4K) {\r
744 gNum512BytesChunks = 8;\r
745 }\r
746\r
747 gEccCode = (UINT8 *)AllocatePool(gNum512BytesChunks * 3);\r
748 if (gEccCode == NULL) {\r
749 return EFI_OUT_OF_RESOURCES;\r
750 }\r
751\r
752 //Configure ECC\r
753 NandConfigureEcc ();\r
754\r
755 //Patch EFI_BLOCK_IO_MEDIA structure.\r
756 gNandFlashMedia.BlockSize = gNandFlashInfo->BlockSize;\r
757 gNandFlashMedia.LastBlock = LAST_BLOCK;\r
758\r
759 //Publish BlockIO.\r
760 Status = gBS->InstallMultipleProtocolInterfaces (\r
3402aac7 761 &ImageHandle,\r
1e57a462 762 &gEfiBlockIoProtocolGuid, &BlockIo,\r
3402aac7 763 &gEfiDevicePathProtocolGuid, &gDevicePath,\r
1e57a462 764 NULL\r
765 );\r
766 return Status;\r
767}\r
768\r