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