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