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