Cleanup SerailIO drivers to have a device path and use PCD settings for various stuff...
[mirror_edk2.git] / Omap35xxPkg / Flash / Flash.c
1 /** @file
2
3   Copyright (c) 2008-2009, Apple Inc. All rights reserved.
4   
5   All rights reserved. This program and the accompanying materials
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
17 NAND_PART_INFO_TABLE gNandPartInfoTable[1] = {
18   { 0x2C, 0xBA, 17, 11 }
19 };
20
21 NAND_FLASH_INFO *gNandFlashInfo = NULL;
22 UINT8           *gEccCode;
23 UINTN           gNum512BytesChunks = 0;
24
25 //
26
27 // Device path for SemiHosting. It contains our autogened Caller ID GUID.
28
29 //
30
31 typedef struct {
32
33   VENDOR_DEVICE_PATH        Guid;
34
35   EFI_DEVICE_PATH_PROTOCOL  End;
36
37 } FLASH_DEVICE_PATH;
38
39
40
41 FLASH_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
55
56
57 //Actual page address = Column address + Page address + Block address.
58 UINTN
59 GetActualPageAddressInBytes (
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
69 VOID
70 NandSendCommand (
71   UINT8 Command
72 )
73 {
74   MmioWrite16(GPMC_NAND_COMMAND_0, Command);
75 }
76
77 VOID
78 NandSendAddress (
79   UINT8 Address
80 )
81 {
82   MmioWrite16(GPMC_NAND_ADDRESS_0, Address);
83 }
84
85 UINT16
86 NandReadStatus (
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
97 VOID
98 NandSendAddressCycles (
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
122 VOID
123 GpmcInit (
124   VOID
125   )
126 {
127   //Enable Smart-idle mode.
128   MmioWrite32 (GPMC_SYSCONFIG, SMARTIDLEMODE);
129
130   //Set IRQSTATUS and IRQENABLE to the reset value
131   MmioWrite32 (GPMC_IRQSTATUS, 0x0);
132   MmioWrite32 (GPMC_IRQENABLE, 0x0);
133
134   //Disable GPMC timeout control.
135   MmioWrite32 (GPMC_TIMEOUT_CONTROL, TIMEOUTDISABLE);
136
137   //Set WRITEPROTECT bit to enable write access.
138   MmioWrite32 (GPMC_CONFIG, WRITEPROTECT_HIGH);
139
140   //NOTE: Following GPMC_CONFIGi_0 register settings are taken from u-boot memory dump.
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);
148 }
149
150 EFI_STATUS
151 NandDetectPart (
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
227 VOID
228 NandConfigureEcc (
229   VOID
230   )
231 {
232   //Define ECC size 0 and size 1 to 512 bytes
233   MmioWrite32 (GPMC_ECC_SIZE_CONFIG, (ECCSIZE0_512BYTES | ECCSIZE1_512BYTES));
234 }
235
236 VOID 
237 NandEnableEcc (
238   VOID
239   )
240 {
241   //Clear all the ECC result registers and select ECC result register 1
242   MmioWrite32 (GPMC_ECC_CONTROL, (ECCCLEAR | ECCPOINTER_REG1));
243
244   //Enable ECC engine on CS0
245   MmioWrite32 (GPMC_ECC_CONFIG, (ECCENABLE | ECCCS_0 | ECC16B));
246 }
247
248 VOID
249 NandDisableEcc (
250   VOID
251   )
252 {
253   //Turn off ECC engine.
254   MmioWrite32 (GPMC_ECC_CONFIG, ECCDISABLE);
255 }
256
257 VOID
258 NandCalculateEcc (
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
274     EccResult = MmioRead32(EccResultRegister);
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
288 EFI_STATUS
289 NandReadPage (
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
357 EFI_STATUS
358 NandWritePage (
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.
414   while (Timeout) {
415     NandStatus = NandReadStatus();
416     if ((NandStatus & NAND_READY) == NAND_READY) {
417       break;
418     }
419     Timeout--;
420   }
421
422   if (Timeout == 0) {
423     DEBUG ((EFI_D_ERROR, "Program page timed out.\n"));
424     return EFI_TIMEOUT;
425   }
426
427   //Bit0 indicates Pass/Fail status
428   if (NandStatus & NAND_FAILURE) {
429     return EFI_DEVICE_ERROR;
430   }
431
432   return EFI_SUCCESS;
433 }
434
435 EFI_STATUS
436 NandEraseBlock (
437   IN UINTN BlockIndex
438 )
439 {
440   UINTN      Address;
441   UINTN      NandStatus;
442   UINTN      Timeout = MAX_RETRY_COUNT;
443
444   //Generate device address in bytes to access specific block and page index
445   Address = GetActualPageAddressInBytes(BlockIndex, 0);
446
447   //Send ERASE SETUP command
448   NandSendCommand(BLOCK_ERASE_CMD);
449
450   //Send 3 address cycles to device to access Page address and Block address
451   Address >>= 11; //Ignore column addresses
452
453   NandSendAddress(Address & 0xff);
454   Address >>= 8;
455
456   NandSendAddress(Address & 0xff);
457   Address >>= 8;
458
459   NandSendAddress(Address & 0xff);
460
461   //Send ERASE CONFIRM command
462   NandSendCommand(BLOCK_ERASE_CONFIRM_CMD);
463
464   //Poll till device is busy.
465   while (Timeout) {
466     NandStatus = NandReadStatus();
467     if ((NandStatus & NAND_READY) == NAND_READY) {
468       break;
469     }
470     Timeout--;
471     gBS->Stall(1);
472   }
473
474   if (Timeout == 0) {
475     DEBUG ((EFI_D_ERROR, "Erase block timed out for Block: %d.\n", BlockIndex));
476     return EFI_TIMEOUT;
477   }
478
479   //Bit0 indicates Pass/Fail status
480   if (NandStatus & NAND_FAILURE) {
481     return EFI_DEVICE_ERROR;
482   }
483
484   return EFI_SUCCESS;
485 }
486
487 EFI_STATUS
488 NandReadBlock (
489   IN UINTN                          StartBlockIndex,
490   IN UINTN                          EndBlockIndex,
491   OUT VOID                          *Buffer,
492   OUT VOID                          *SpareBuffer
493 )
494 {
495   UINTN      BlockIndex;
496   UINTN      PageIndex;
497   EFI_STATUS Status = EFI_SUCCESS;
498
499   for (BlockIndex = StartBlockIndex; BlockIndex <= EndBlockIndex; BlockIndex++) {
500     //For each block read number of pages
501     for (PageIndex = 0; PageIndex < gNandFlashInfo->NumPagesPerBlock; PageIndex++) {
502       Status = NandReadPage(BlockIndex, PageIndex, Buffer, SpareBuffer);
503       if (EFI_ERROR(Status)) {
504         return Status;
505       }
506       Buffer = ((UINT8 *)Buffer + gNandFlashInfo->PageSize);
507     }
508   }
509
510   return Status;
511 }
512
513 EFI_STATUS
514 NandWriteBlock (
515   IN UINTN                          StartBlockIndex,
516   IN UINTN                          EndBlockIndex,
517   OUT VOID                          *Buffer,
518   OUT VOID                          *SpareBuffer
519   )
520 {
521   UINTN      BlockIndex;
522   UINTN      PageIndex;
523   EFI_STATUS Status = EFI_SUCCESS;
524
525   for (BlockIndex = StartBlockIndex; BlockIndex <= EndBlockIndex; BlockIndex++) {
526     //Page programming.
527     for (PageIndex = 0; PageIndex < gNandFlashInfo->NumPagesPerBlock; PageIndex++) {
528       Status = NandWritePage(BlockIndex, PageIndex, Buffer, SpareBuffer);
529       if (EFI_ERROR(Status)) {
530         return Status;
531       }
532       Buffer = ((UINT8 *)Buffer + gNandFlashInfo->PageSize);
533     }
534   }
535
536   return Status;
537 }
538
539 EFI_STATUS
540 EFIAPI
541 NandFlashReset (
542   IN EFI_BLOCK_IO_PROTOCOL          *This,
543   IN BOOLEAN                        ExtendedVerification
544   )
545 {
546   UINTN BusyStall = 50;                            // microSeconds
547   UINTN ResetBusyTimeout = (1000000 / BusyStall);  // 1 Second
548
549   //Send RESET command to device.
550   NandSendCommand(RESET_CMD);
551   
552   //Wait for 1ms before we check status register.
553   gBS->Stall(1000);
554
555   //Check BIT#5 & BIT#6 in Status register to make sure RESET is done.
556   while ((NandReadStatus() & NAND_RESET_STATUS) != NAND_RESET_STATUS) {
557
558     //In case of extended verification, wait for extended amount of time
559     //to make sure device is reset.
560     if (ExtendedVerification) {
561       if (ResetBusyTimeout == 0) {
562         return EFI_DEVICE_ERROR;
563       }
564
565       gBS->Stall(BusyStall);
566       ResetBusyTimeout--;
567     }
568   }
569   
570   return EFI_SUCCESS;
571 }
572
573 EFI_STATUS
574 EFIAPI
575 NandFlashReadBlocks (
576   IN EFI_BLOCK_IO_PROTOCOL          *This,
577   IN UINT32                         MediaId,
578   IN EFI_LBA                        Lba,
579   IN UINTN                          BufferSize,
580   OUT VOID                          *Buffer
581   )
582 {
583   UINTN      NumBlocks;
584   UINTN      EndBlockIndex;
585   EFI_STATUS Status;
586   UINT8      *SpareBuffer = NULL;
587
588   if (Buffer == NULL) {
589     Status = EFI_INVALID_PARAMETER;
590     goto exit;
591   }
592   
593   if (Lba > LAST_BLOCK) {
594     Status = EFI_INVALID_PARAMETER;
595     goto exit;
596   }
597   
598   if ((BufferSize % gNandFlashInfo->BlockSize) != 0) {
599     Status = EFI_BAD_BUFFER_SIZE;
600     goto exit;
601   }
602
603   NumBlocks = DivU64x32(BufferSize, gNandFlashInfo->BlockSize);
604   EndBlockIndex = ((UINTN)Lba + NumBlocks) - 1;
605
606   SpareBuffer = (UINT8 *)AllocatePool(gNandFlashInfo->SparePageSize);
607   if (SpareBuffer == NULL) {
608     Status = EFI_OUT_OF_RESOURCES;
609     goto exit;
610   }
611
612   //Read block
613   Status = NandReadBlock((UINTN)Lba, EndBlockIndex, Buffer, SpareBuffer);
614   if (EFI_ERROR(Status)) {
615     DEBUG((EFI_D_ERROR, "Read block fails: %x\n", Status));
616     goto exit;
617   }
618
619 exit:
620   if (SpareBuffer != NULL) {
621     FreePool (SpareBuffer);
622   }
623
624   return Status;
625 }
626
627 EFI_STATUS
628 EFIAPI
629 NandFlashWriteBlocks (
630   IN EFI_BLOCK_IO_PROTOCOL          *This,
631   IN UINT32                         MediaId,
632   IN EFI_LBA                        Lba,
633   IN UINTN                          BufferSize,
634   IN VOID                           *Buffer
635   )
636 {
637   UINTN      BlockIndex;
638   UINTN      NumBlocks;
639   UINTN      EndBlockIndex;
640   EFI_STATUS Status;
641   UINT8      *SpareBuffer = NULL;
642
643   if (Buffer == NULL) {
644     Status = EFI_INVALID_PARAMETER;
645     goto exit;
646   }
647   
648   if (Lba > LAST_BLOCK) {
649     Status = EFI_INVALID_PARAMETER;
650     goto exit;
651   }
652   
653   if ((BufferSize % gNandFlashInfo->BlockSize) != 0) {
654     Status = EFI_BAD_BUFFER_SIZE;
655     goto exit;
656   }
657
658   NumBlocks = DivU64x32(BufferSize, gNandFlashInfo->BlockSize);
659   EndBlockIndex = ((UINTN)Lba + NumBlocks) - 1;
660
661   SpareBuffer = (UINT8 *)AllocatePool(gNandFlashInfo->SparePageSize);
662   if (SpareBuffer == NULL) {
663     Status = EFI_OUT_OF_RESOURCES;
664     goto exit;
665   }
666
667   // Erase block
668   for (BlockIndex = (UINTN)Lba; BlockIndex <= EndBlockIndex; BlockIndex++) {
669     Status = NandEraseBlock(BlockIndex);
670     if (EFI_ERROR(Status)) {
671       DEBUG((EFI_D_ERROR, "Erase block failed. Status: %x\n", Status));
672       goto exit;
673     }
674   }
675   
676   // Program data
677   Status = NandWriteBlock((UINTN)Lba, EndBlockIndex, Buffer, SpareBuffer);
678   if (EFI_ERROR(Status)) {
679     DEBUG((EFI_D_ERROR, "Block write fails: %x\n", Status));
680     goto exit;
681   }
682
683 exit:
684   if (SpareBuffer != NULL) {
685     FreePool (SpareBuffer);
686   }
687
688   return Status;
689 }
690
691 EFI_STATUS
692 EFIAPI
693 NandFlashFlushBlocks (
694   IN EFI_BLOCK_IO_PROTOCOL  *This
695   )
696 {
697   return EFI_SUCCESS;
698 }
699
700
701
702 EFI_BLOCK_IO_MEDIA gNandFlashMedia = {
703   SIGNATURE_32('n','a','n','d'),            // MediaId
704   FALSE,                                    // RemovableMedia
705   TRUE,                                     // MediaPresent
706   FALSE,                                    // LogicalPartition
707   FALSE,                                    // ReadOnly
708   FALSE,                                    // WriteCaching
709   0,                                        // BlockSize
710   2,                                        // IoAlign
711   0,                                        // Pad
712   0                                         // LastBlock
713 };
714
715 EFI_BLOCK_IO_PROTOCOL BlockIo = 
716 {
717   EFI_BLOCK_IO_INTERFACE_REVISION,  // Revision
718   &gNandFlashMedia,                  // *Media
719   NandFlashReset,                   // Reset
720   NandFlashReadBlocks,              // ReadBlocks
721   NandFlashWriteBlocks,             // WriteBlocks
722   NandFlashFlushBlocks              // FlushBlocks
723 };
724
725 EFI_STATUS
726 NandFlashInitialize (
727   IN EFI_HANDLE         ImageHandle,
728   IN EFI_SYSTEM_TABLE   *SystemTable
729   )
730 {
731   EFI_STATUS  Status;
732   
733   gNandFlashInfo = (NAND_FLASH_INFO *)AllocateZeroPool (sizeof(NAND_FLASH_INFO));
734
735   //Initialize GPMC module.
736   GpmcInit();
737
738   //Reset NAND part
739   NandFlashReset(&BlockIo, FALSE);
740
741   //Detect NAND part and populate gNandFlashInfo structure
742   Status = NandDetectPart ();
743   if (EFI_ERROR(Status)) {
744     DEBUG((EFI_D_ERROR, "Nand part id detection failure: Status: %x\n", Status));
745     return Status;
746   }
747
748   //Count total number of 512Bytes chunk based on the page size.
749   if (gNandFlashInfo->PageSize == PAGE_SIZE_512B) {
750     gNum512BytesChunks = 1;
751   } else if (gNandFlashInfo->PageSize == PAGE_SIZE_2K) {
752     gNum512BytesChunks = 4;
753   } else if (gNandFlashInfo->PageSize == PAGE_SIZE_4K) {
754     gNum512BytesChunks = 8;
755   }
756
757   gEccCode = (UINT8 *)AllocatePool(gNum512BytesChunks * 3);
758   if (gEccCode == NULL) {
759     return EFI_OUT_OF_RESOURCES;
760   }
761
762   //Configure ECC
763   NandConfigureEcc ();
764
765   //Patch EFI_BLOCK_IO_MEDIA structure.
766   gNandFlashMedia.BlockSize = gNandFlashInfo->BlockSize;
767   gNandFlashMedia.LastBlock = LAST_BLOCK;
768
769   //Publish BlockIO.
770   Status = gBS->InstallMultipleProtocolInterfaces (
771                   &ImageHandle, 
772                   &gEfiBlockIoProtocolGuid, &BlockIo,
773                   &gEfiDevicePathProtocolGuid, &gDevicePath, 
774                   NULL
775                   );
776   return Status;
777 }
778