]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - psdk_cust/pdk_k2g_1_0_1_0_eng/packages/ti/board/src/flash/platform_flash/evm66x_nand.c
PASDK-258:Update PDK eng to 1.0.1.1. Using build number to differentiate PDK eng...
[processor-sdk/performance-audio-sr.git] / psdk_cust / pdk_k2g_1_0_1_0_eng / packages / ti / board / src / flash / platform_flash / evm66x_nand.c
1 /*
2  * Copyright (c) 2010-2015, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  */
34 /**
35  *
36  * \file  evm66x_nand.c
37  *
38  * \brief This contains TCI66xK2x specific nand functions.
39  *
40  *
41  ******************************************************************************/
42 #include "platform_internal.h"
44 #if (PLATFORM_NAND_IN)
46 /************************
47  * Include Files
48  ************************/
50 /************************
51  * Globals
52  ************************/
54 /************************
55  * Defines and Macros
56  ************************/
58 #pragma DATA_SECTION(nandPageBuf,"platform_lib");
59 static uint8_t nandPageBuf[BYTES_PER_PAGE + SPARE_BYTES_PER_PAGE];
61 #if (PLATFORM_NAND_ECC_IN)
63 // Both RBL and Linux offsets are set for 8-bit BCH ECC
64 /*
65  * RBL ECC placement structure for each 512 byte block:
66  *
67  * 0    1       2        3    4    5    6    7    8    9   10   11   12    13    14    15
68  * Unused ECC0 ECC1 ECC2 ECC3 ECC4 ECC5 ECC6 ECC7 ECC8 ECC9 ECC10 ECC11 ECC12 Unused
69  */
70 static const uint8_t rbl_eccLoc[4*NAND_MAX_NUM_ECC_BYTES] = {
71     2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
72     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
73     34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
74     50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
75 };
77 /*
78  * U-Boot ECC placement structure:
79  *
80  *  The first 2 bytes are used for Bad block marker - 0xFFFF => Good block
81  *  The next 'N' bytes is used for BCH bytes
82  *
83  *  N = B * <Number of 512-byte sectors in a page>
84  *
85  *  B = 8 bytes per 512 byte sector in BCH4
86  *  B = 14 bytes per 512 byte sector in BCH8
87  *  B = 26 bytes per 512 byte sector in BCH16
88  *
89  */
90 static const uint8_t linux_eccLoc[4*NAND_MAX_NUM_ECC_BYTES] = {
91     2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
92     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
93     30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
94     44, 45, 46, 47, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
95 };
97 #endif // #if (PLATFORM_NAND_ECC_IN)
99 NandInfo_t gNandInfo;
100 NandCtrlInfo_t gNandCtrlInfo;
101 NandEccInfo_t gNandEccInfo;
102 NandTimingInfo_t gNandTimingInfo;
104 /******************************************************************************
105  *
106  * Function:    NandCmdSet
107  *
108  * Description: This function is used to indicate command cycle occurring
109  *              and to send command to NAND device
110  *
111  * Parameters:  uint32_t cmd - Command to NAND
112  *
113  * Return Value: None
114  *
115  *****************************************************************************/
116 static void NandCmdSet(uint32_t cmd)
118     uint16_t *cle_addr  = (uint16_t *) NAND_CMD_ADDR;
120     *cle_addr = (uint16_t) cmd;
123 /******************************************************************************
124  *
125  * Function:    NandAleSet
126  *
127  * Description: This function is used to indicate Address cycle occurring
128  *              and to send address value to NAND device
129  *
130  * Parameters:  uint32_t addr - Address to NAND
131  *
132  * Return Value: None
133  *
134  *****************************************************************************/
135 static void NandAleSet(uint32_t addr)
137       uint16_t *ale_addr  = (uint16_t *) NAND_ALE_ADDR;
139       *ale_addr = (uint16_t) addr;
141       return;
144 /******************************************************************************
145  *
146  * Function:    NandProgAddr
147  *
148  * Description: This function is used to send the column, page and block
149  *              address to the NAND device using NandAleSet
150  *
151  * Parameters:  NAND_ADDR addr - Address to NAND
152  *
153  * Return Value: None
154  *
155  *****************************************************************************/
156 static void NandProgAddr(NAND_ADDR addr)
158     /*
159      * Send address of the block + page to be read
160      * Address cycles = 5
161      */
162     NandAleSet((addr.uiColumnAddr >>  0u) & 0xFF);   // CA0 -CA7  1st Cycle; Column addr
163     NandAleSet((addr.uiColumnAddr >>  8u) & 0x07);   // CA8 -CA10 2nd Cycle; Column addr
164     NandAleSet(((addr.uiBlockAddr <<  6u) & 0xC0) |  // BA6 -BA7  3rd Cycle; Block  addr
165                ((addr.uiPageAddr  >>  0u) & 0x3F));  // PA0 -PA5  3rd Cycle; Page   addr
166     NandAleSet((addr.uiBlockAddr  >>  2u) & 0xFF);   // BA8 -BA15 4th Cycle; Block  addr
167     NandAleSet((addr.uiBlockAddr  >> 10u) & 0x01);   // BA16      5th Cycle; Block  addr
170 /******************************************************************************
171   *
172   * Function:    NandWaitRdy
173   *
174   * Description: This function waits for the NAND status to be ready
175   *
176   * Parameters:  uint32_t in_timeout - time out value in micro seconds
177   *
178   * Return Value: Failure if Ready Pin is not high for prescribed time
179   *
180   *****************************************************************************/
181  static uint32_t NandWaitRdy(uint32_t in_timeout)
182  {
183      uint32_t count = 0;
185      do
186      {
187         platform_delay(1);
189         if (((nandWaitPinStatusGet(&gNandInfo)) & 1) == 1)
190         {
191             break;
192         }
194         count++;
196      } while (count < in_timeout);
198      if (count >= in_timeout)
199      {
200         return FAIL;
201          }
202      else
203      {
204         return SUCCESS;
205          }
206  }
208 #if (PLATFORM_NAND_READ_IN | PLATFORM_NAND_WRITE_IN)
210  /******************************************************************************
211   *
212   * Function:    NandReadDataByte
213   *
214   * Description: This function is used to read Nand data byte
215   *
216   * Parameters:  uint8_t* puchValue - Pointer to data buffer
217   *
218   * Return Value: None
219   *
220   *****************************************************************************/
221 static void NandReadDataByte(uint8_t* puchValue)
222  {
223     /*8-bit NAND*/
224     uint8_t *data_addr  = (uint8_t *) NAND_DATA_ADDR;
226     *puchValue = *data_addr;
227  }
229  /******************************************************************************
230   *
231   * Function:    NandReadDataBytes
232   *
233   * Description: This function is used to read data bytes from the NAND device
234   *
235   * Parameters:  uiNumBytes - Number of bytes to be read
236   *              pBuffer - Data buffer
237   *
238   * Return Value: Error/Success codes
239   *
240   *****************************************************************************/
241  static uint32_t NandReadDataBytes(uint32_t uiNumBytes, uint8_t *pBuffer)
242  {
243      uint32_t i;
245      /* 8-bit NAND */
246      for (i = 0; i < uiNumBytes; i++)
247      {
248          /* NANDRead done directly without checking for nand width */
249          NandReadDataByte((uint8_t *)pBuffer);
250          pBuffer++;
251      }
252      return SUCCESS;
253  }
255   /******************************************************************************
256    *
257    * Function:    NandReadDataWord
258    *
259    * Description: This function is used to read Nand data word
260    *
261    * Parameters:  uint16_t* pushValue - Pointer to data buffer
262    *
263    * Return Value: None
264    *
265    *****************************************************************************/
266  static void NandReadDataWord(uint16_t* pushValue)
267   {
268      uint16_t *data_addr  = (uint16_t *) NAND_DATA_ADDR;
270      *pushValue = *data_addr;
271   }
273   /******************************************************************************
274    *
275    * Function:    NandReadDataWords
276    *
277    * Description: This function is used to read data words from the NAND device
278    *
279    * Parameters:  uiNumBytes - Number of bytes to be read
280    *              pBuffer    - Data buffer
281    *
282    * Return Value: Error/Success codes
283    *
284    *****************************************************************************/
285 static uint32_t NandReadDataWords(uint32_t uiNumBytes, uint16_t *pBuffer)
287       uint32_t i;
289       for (i = 0; i < uiNumBytes/2; i++)
290       {
291           NandReadDataWord(pBuffer);
292           pBuffer++;
293       }
295       return SUCCESS;
298 static uint32_t NandReadData(PLATFORM_DEVICE_info *p_device, uint32_t uiNumBytes, uint8_t *pBuffer)
300     uint16_t *ptrData;
301     uint32_t retVal;
303     if(p_device->width == 8)
304     {
305                 /* 8-bit NAND */
306         retVal = NandReadDataBytes(uiNumBytes, pBuffer);
307     }
308     else
309     {
310                 /* 16-bit NAND */
311         ptrData = (uint16_t *)pBuffer;
312         retVal = NandReadDataWords(uiNumBytes, ptrData);
313     }
315     return (retVal);
318 /******************************************************************************
319   *
320   * Function:    NandReadSpareArea
321   *
322   * Description: Function to read Nand spare area
323   *
324   * Parameters:  uiBlkAddr - Block Address
325   *              uiPage - Page Number
326   *              pBuffer - Data Buffer
327   *
328   * Return Value: Error/Success codes
329   *
330   *****************************************************************************/
331 uint32_t NandReadSpareArea(PLATFORM_DEVICE_info *p_device, uint32_t uiBlkAddr, uint32_t uiPage, uint8_t *pBuffer)
333     uint32_t ret_val = SUCCESS;
334     uint8_t status;
335     NAND_ADDR address;
338      /* Read the data to the destination buffer and detect error */
339     address.uiColumnAddr = p_device->column;
340     address.uiPageAddr = uiPage;
341     address.uiBlockAddr = uiBlkAddr;
343      /* Send 0x50h command to read the spare area */
344     NandCmdSet(NAND_PAGE_READ); // First cycle send 0
345     platform_delay(10);
347     /* Send address */
348     NandProgAddr(address);
350     NandCmdSet(0x30); // Last  cycle send 30h command
351     platform_delay(NAND_WAIT_PIN_POLL_ST_DLY);
353     // Wait for Ready Busy Pin to go HIGH
354     ret_val = NandWaitRdy(NAND_PROG_TIMEOUT);
356     if (ret_val != SUCCESS) {
357         platform_errno = PLATFORM_ERRNO_DEV_BUSY;
358                 IFPRINT(platform_write("NandReadSpareArea: Device timeout.\n"));
359         return FAIL;
360     }
362     /* Read the data to the destination buffer and detect error */
363     NandReadData(p_device, p_device->spare_size, pBuffer);
364     printf("[1] pBuffer: 0x%08x, *pBuffer: %x\n",(uint32_t) pBuffer, *pBuffer);
365     printf("[2] pBuffer: 0x%08x, *pBuffer: %x\n",(uint32_t) pBuffer, *pBuffer+4);
366     printf("[3] pBuffer: 0x%08x, *pBuffer: %x\n",(uint32_t) pBuffer, *pBuffer+8);
367     printf("[4] pBuffer: 0x%08x, *pBuffer: %x\n",(uint32_t) pBuffer, *pBuffer+12);
369     NandCmdSet(NAND_STATUS);
370     platform_delay(10);
371     NandReadDataByte(&status);
373     if ((status & 0x01) == 1) {
374         /* if SR0 bit is set to 1, there is Error - operation failed */
375         platform_errno = PLATFORM_ERRNO_DEV_FAIL;
376                 IFPRINT(platform_write("NandReadSpareArea: Status (0x%x) has error bit set.\n", status));
377         return FAIL;
378     }
380     return SUCCESS;
382 #endif
385  /******************************************************************************
386   *
387   * Function:    readNandPage
388   *
389   * Description: This function reads a page from NAND flash and detects and
390   *              corrects the bit errors if ECC is enabled
391   *
392   * Parameters:  NAND_ADDR address - Block Address/Page address of NAND flash
393   *              uint8_t* puchBuffer - Pointer to buffer
394   *
395   * Return Value: status
396   *
397   * Assumptions: puchBuffer points to a 2KB buffer
398   *
399   ******************************************************************************/
400 #if (PLATFORM_NAND_READ_IN)
401 uint32_t readNandPage(PLATFORM_DEVICE_info *p_device, NAND_ADDR address, uint8_t* puchBuffer)
403     int32_t i = 0;
404     int32_t index;
405     uint32_t byte_count;
406     uint8_t *puchSpareAreaBuf;
407     uint8_t *pBuffer_loc;
408     uint32_t ret_val = SUCCESS;
409     uint8_t  status;
411 #if (PLATFORM_NAND_ECC_IN)
412     /* ECC locations for the micron nand device */
413     const uint8_t   *eccLoc = (p_device->flags == NAND_FLAG_RBL) ? rbl_eccLoc : linux_eccLoc;
414     uint8_t   eccCode[4*NAND_MAX_NUM_ECC_BYTES];
415 #endif
417     if(puchBuffer == NULL)
418         return NULL_POINTER_ERROR;
420     pBuffer_loc = nandPageBuf;
421     puchSpareAreaBuf = nandPageBuf + BYTES_PER_PAGE;
422     ret_val = NandReadSpareArea(p_device, address.uiBlockAddr, address.uiPageAddr, puchSpareAreaBuf);
424     if(ret_val != SUCCESS)
425         return FAIL;
427     platform_delay(10);
429     NandCmdSet(NAND_PAGE_READ);
430     platform_delay(10);
432     /* Send address */
433     NandProgAddr(address);
435     NandCmdSet(0x30); // Last cycle send 30h command
436     platform_delay(NAND_WAIT_PIN_POLL_ST_DLY);
438     /* Wait for Ready Busy Pin to go HIGH */
439     ret_val = NandWaitRdy(NAND_PROG_TIMEOUT);
441     if(ret_val != SUCCESS) {
442         platform_errno = PLATFORM_ERRNO_DEV_TIMEOUT;
443         return FAIL;
444     }
446 #if (PLATFORM_NAND_ECC_IN)
447         nandECCReadSet(&gNandInfo);
448         nandECCDisable(&gNandInfo);
449 #endif
451     for(byte_count = 0, index = 0; byte_count < p_device->page_size; pBuffer_loc += ECC_BLOCK_SIZE, index++, byte_count += ECC_BLOCK_SIZE)
452     {
453 #if (PLATFORM_NAND_ECC_IN)
454         /* Start 4-bit ECC HW calculation for read */
455         nandECCEnable(&gNandInfo);
456 #endif
458         /* Read the data to the destination buffer and detect error */
459         NandReadData(p_device, ECC_BLOCK_SIZE, pBuffer_loc);
460         platform_delay(10);
462 #if (PLATFORM_NAND_ECC_IN)
464         /* Read Parity - read parity stored in spare NAND flash */
465         for(i = 0; i < NAND_MAX_NUM_ECC_BYTES; i++)
466         {
467             eccCode[i + (index * NAND_MAX_NUM_ECC_BYTES)] = puchSpareAreaBuf[eccLoc[i + (index * NAND_MAX_NUM_ECC_BYTES)]];
468         }
470                 if(nandECCCheckAndCorrect(&gNandInfo, &eccCode[index * NAND_MAX_NUM_ECC_BYTES], pBuffer_loc) != NAND_STATUS_PASSED)
471         {
472             return FAIL;
473         }
475         nandECCDisable(&gNandInfo);
476 #endif
477     }
479     NandCmdSet(NAND_STATUS);
480     platform_delay(10);
482     NandReadDataByte(&status);
484     if ((status & 0x01) == 1) {
485         /* if SR0 bit is set to 1, there is Error - operation failed */
486         platform_errno = PLATFORM_ERRNO_DEV_FAIL;
487         return FAIL;
488     }
490     memcpy(puchBuffer, nandPageBuf, gDeviceNand.page_size);
492     return SUCCESS;
494 #endif
496  /******************************************************************************
497   *
498   * Function:    NandWriteDataBytes
499   *
500   * Description: This function is used to write data bytes to the NAND device
501   *
502   * Parameters:  uiNumBytes - Number of bytes to be written
503   *              pBuffer - Data buffer
504   *
505   * Return Value: Error/Success codes
506   *
507   *****************************************************************************/
509 #if (PLATFORM_NAND_WRITE_IN)
510  static void NandWriteDataByte(uint8_t uchData)
511  {
512      volatile uint8_t* dest;
514      /* Data is written to the data register on the rising edge of WE# when
515            CE#, CLE, and ALE are LOW, and
516                    the device is not busy. */
517      dest = (volatile uint8_t *)(NAND_DATA_ADDR);
518      *dest = uchData;
519  }
521 uint32_t NandWriteDataBytes(uint32_t uiNumBytes, uint8_t *pBuffer)
522  {
523      uint32_t i;
525          for (i = 0; i < uiNumBytes; i++)
526          {
527                  /* NAND Write done directly without checking for nand width */
528                  NandWriteDataByte( (uint8_t) *pBuffer );
529                  pBuffer++;
530          }
532      return SUCCESS;
533  }
535   static void NandWriteDataWord(uint16_t ushData)
536   {
537       volatile uint16_t* dest;
539       /* Data is written to the data register on the rising edge of WE# when
540             CE#, CLE, and ALE are LOW, and
541                    the device is not busy. */
542       dest = (volatile uint16_t *)(NAND_DATA_ADDR);
543       *dest = ushData;
544   }
546  uint32_t NandWriteDataWords(uint32_t uiNumBytes, uint16_t *pBuffer)
547   {
548       uint32_t i;
550           for (i = 0; i < uiNumBytes/2; i++)
551           {
552                   /* NAND Write done directly without checking for nand width */
553                   NandWriteDataWord(*pBuffer);
554                   pBuffer++;
555           }
557       return SUCCESS;
558  }
560 uint32_t NandWriteData(PLATFORM_DEVICE_info *p_device, uint32_t uiNumBytes, uint8_t *pBuffer)
562         uint16_t* pshData;
563         uint32_t  retVal;
565         if (p_device->width == 8)
566         {
567                 /* 8-bit NAND */
568                 retVal = NandWriteDataBytes(uiNumBytes, pBuffer);
569         }
570         else
571         {
572                 /* 16-bit NAND */
573                 pshData = (uint16_t* )pBuffer;
574                 retVal = NandWriteDataWords(uiNumBytes, pshData);
575         }
577         return (retVal);
580 #endif
582  /******************************************************************************
583   *
584   * Function:    writeNandPage
585   *
586   * Description: This function a page to NAND flash. It computes ECC and
587   *              and writes it to spare area if ECC is enabled
588   *
589   * Parameters:  NAND_ADDR address - Block Address/Page address of NAND flash
590   *              uint8_t* puchBuffer - Pointer to buffer
591   *
592   * Return Value: status
593   *
594   * Assumptions: puchBuffer points to a 2KB buffer
595   *
596   ******************************************************************************/
597 #if (PLATFORM_NAND_WRITE_IN)
598  uint32_t  writeNandPage(PLATFORM_DEVICE_info *p_device, NAND_ADDR address, uint8_t* puchBuffer)
599  {
600      int32_t iErrors = SUCCESS;
601      int32_t i = 0;
602      uint32_t byte_count, index;
603      uint8_t puchSpareAreaBuf[SPARE_BYTES_PER_PAGE];
604      uint8_t *pBuffer_loc;
605      uint32_t ret_val = SUCCESS;
606      uint8_t  status;
608 #if (PLATFORM_NAND_ECC_IN)
609      /* ECC locations for the Numonyx nand device */
610      const uint8_t  *eccLoc = (p_device->flags == NAND_FLAG_RBL) ? rbl_eccLoc : linux_eccLoc;
611      uint8_t   eccCalc[4*NAND_MAX_NUM_ECC_BYTES];
612 #endif
614      /* Init the buffer by reading the existing values in the spare area */
615     iErrors = NandReadSpareArea(p_device, address.uiBlockAddr, address.uiPageAddr, puchSpareAreaBuf);
616     if(iErrors != SUCCESS)
617     {
618         return iErrors;
619     }
621 #if (PLATFORM_NAND_ECC_IN)
622         nandECCWriteSet(&gNandInfo);
623         nandECCDisable(&gNandInfo);
624 #endif
626     pBuffer_loc = puchBuffer;
627     for(byte_count = 0, index = 0; byte_count < p_device->page_size; pBuffer_loc += ECC_BLOCK_SIZE, index++, byte_count += ECC_BLOCK_SIZE)
628     {
629         NandCmdSet(NAND_PROG_PAGE);
630         platform_delay(10);
632         address.uiColumnAddr = byte_count/2;
633         NandProgAddr(address);
634         platform_delay(NAND_WAIT_PIN_POLL_ST_DLY);
636 #if (PLATFORM_NAND_ECC_IN)
637         /* Start ECC HW calculation for write */
638         nandECCEnable(&gNandInfo);
639         platform_delay (10);
640 #endif
642         /* Write the data */
643         NandWriteData(p_device, ECC_BLOCK_SIZE, pBuffer_loc);
645         platform_delay (10);
647 #if (PLATFORM_NAND_ECC_IN)
649         /* Calculate the ECC bytes for write */
650         nandECCDisable(&gNandInfo);
651         nandECCCalculate(&gNandInfo, &eccCalc[index * NAND_MAX_NUM_ECC_BYTES]);
653         /* Update the calculated ECC bytes to spare area data */
654         for (i = 0; i < NAND_MAX_NUM_ECC_BYTES; i++)
655         {
656             puchSpareAreaBuf[eccLoc[i + (index * NAND_MAX_NUM_ECC_BYTES)]] = eccCalc[i + (index * NAND_MAX_NUM_ECC_BYTES)];
657         }
659 #endif
661         /* Wait for Ready Busy Pin to go HIGH  */
662         NandCmdSet(NAND_CMD_10H);
664         platform_delay(NAND_WAIT_PIN_POLL_ST_DLY);
666         ret_val = NandWaitRdy(NAND_PROG_TIMEOUT*50);
668         if (ret_val != SUCCESS) {
669             platform_errno = PLATFORM_ERRNO_DEV_TIMEOUT;
670             return FAIL;
671         }
673         NandCmdSet(NAND_STATUS);
674         platform_delay(10);
676         NandReadDataByte(&status);
678         if ((status & 0x01) == 1) {
679             /* if SR0 bit is set to 1, there is Error - operation failed */
680             platform_errno = PLATFORM_ERRNO_DEV_FAIL;
681             return FAIL;
682         }
683     }
685     /* Write the spare data */
686     ret_val = NandWriteSpareArea(p_device, address.uiBlockAddr, address.uiPageAddr, puchSpareAreaBuf);
688     if (ret_val != SUCCESS)
689         return FAIL;
691     return SUCCESS;
692  }
693 #endif
695  /******************************************************************************
696   *
697  * Function:    NandWriteSpareArea
698  *
699  * Description: Function to write a spare area of the NAND
700  *
701  * Parameters:  uiBlkAddr - Block Address
702  *              uiPage - Page Number
703  *              pBuffer - Data Buffer
704  *
705  * Return Value: Error/Success codes
706  *
707  *****************************************************************************/
708 #if (PLATFORM_NAND_WRITE_IN)
709 uint32_t NandWriteSpareArea (PLATFORM_DEVICE_info *p_device, uint32_t uiBlkAddr, uint32_t uiPage, uint8_t *pBuffer)
711     uint32_t ret_val = SUCCESS;
712     uint8_t  status;
713     uint8_t *pBuffer_loc;
714     NAND_ADDR address;
716     /* Read the data to the destination buffer and detect error */
717     address.uiColumnAddr = p_device->column;
718     address.uiPageAddr   = uiPage;
719     address.uiBlockAddr  = uiBlkAddr;
721     /* Spare Area*/
722     /*NandCmdSet(NAND_PAGE_READ);
723     platform_delay(20);*/
724     NandCmdSet(NAND_PROG_PAGE);
725     platform_delay(10);
727     /* Send address */
728     NandProgAddr(address);
729     platform_delay (NAND_WAIT_PIN_POLL_ST_DLY);
731     /* Write the data */
732     pBuffer_loc = pBuffer;
733     NandWriteData(p_device, p_device->spare_size, (uint8_t *)pBuffer_loc);
735     /* Wait for Ready Busy Pin to go HIGH  */
736     NandCmdSet(NAND_CMD_10H);
738     platform_delay(NAND_WAIT_PIN_POLL_ST_DLY);
740     ret_val = NandWaitRdy(NAND_PROG_TIMEOUT*50);
742     if (ret_val != SUCCESS) {
743         platform_errno = PLATFORM_ERRNO_DEV_TIMEOUT;
744         return FAIL;
745     }
747     NandCmdSet(NAND_STATUS);
748     platform_delay(10);
750     NandReadDataByte(&status);
752     if ((status & 0x01) == 1) {
753         /* if SR0 bit is set to 1, there is Error - operation failed */
754         platform_errno = PLATFORM_ERRNO_DEV_FAIL;
755         return FAIL;
756     }
758     return SUCCESS;
760 #endif
762  /******************************************************************************
763   *
764   * Function:    nandFlashBlockErase
765   *
766   * Description: This function erases the specified block of NAND flash
767   *
768   * Parameters:  NAND_ADDR address - Block Address of NAND flash
769   *
770   * Return Value: status
771   *
772   *****************************************************************************/
773 #if (PLATFORM_NAND_WRITE_IN)
774  uint32_t nandFlashBlockErase(PLATFORM_DEVICE_info *p_device, uint32_t uiBlockNumber)
775  {
776      uint32_t ret_val = SUCCESS;
777      uint8_t  status;
779      NandCmdSet(NAND_BLOCK_ERASE); // Block erase command
780      platform_delay(25);
782      /*
783       * Send address of the block + page to be read
784       * Address cycles = 3
785       */
787      /* Properly adjust the shifts to match to the data sheet */
789      NandAleSet((uiBlockNumber <<  6u) & 0xC0);  // B0 -B1  1st Cycle; Block addr
790      platform_delay(25);
791      NandAleSet((uiBlockNumber >>  2u) & 0xFF);  // B2 -B9  2nd Cycle; Block addr
792      platform_delay(25);
793      NandAleSet((uiBlockNumber >> 10u) & 0x01);  // B10-B11 3rd Cycle; Block addr
794      platform_delay(1000);
796      NandCmdSet(NAND_ERASE_CONFIRM); // Erase confirm
797      platform_delay(NAND_WAIT_PIN_POLL_ST_DLY);
799      /* Wait for erase operation to finish: 2msec  */
800      ret_val = NandWaitRdy(NAND_BLOCK_ERASE_TIMEOUT);
802      if (ret_val != SUCCESS) {
803         platform_errno = PLATFORM_ERRNO_DEV_TIMEOUT;
804          return FAIL;
805      }
807      NandCmdSet(NAND_STATUS);
808      platform_delay(10);
810      NandReadDataByte(&status);
812      if ((status & 0x01) == 1) {
813          /* if SR0 bit is set to 1, there is Error - operation failed */
814          platform_errno = PLATFORM_ERRNO_DEV_FAIL;
815          return FAIL;
816      }
818      return SUCCESS;
820  }
821 #endif
823 /******************************************************************************
824 *                                                                             *
825 * \brief  Function to initalize the NAND timing info.                         *
826 *                                                                             *
827 * \param  nandTimimgInfo : Pointer to structure containing                    *
828 *                          NAND timing info.                                  *
829 *                                                                             *
830 * \return none.                                                               *
831 *                                                                             *
832 ******************************************************************************/
833 static void NandTimingInfoInit(NandTimingInfo_t *nandTimingInfo)
835     nandTimingInfo->CSWrOffTime               = NAND_CSWROFFTIME;
836     nandTimingInfo->CSRdOffTime               = NAND_CSRDOFFTIME;
837     nandTimingInfo->CSExtDelayFlag            = GPMC_CS_EXTRA_NODELAY;
838     nandTimingInfo->CSOnTime                  = NAND_CSONTIME;
840     nandTimingInfo->ADVAADMuxWrOffTime        = NAND_ADVAADMUXWROFFTIME;
841     nandTimingInfo->ADVAADMuxRdOffTime        = NAND_ADVAADMUXRDOFFTIME;
842     nandTimingInfo->ADVWrOffTime              = NAND_ADVWROFFTIME;
843     nandTimingInfo->ADVRdOffTime              = NAND_ADVRDOFFTIME;
844     nandTimingInfo->ADVExtDelayFlag           = GPMC_ADV_EXTRA_NODELAY;
845     nandTimingInfo->ADVAADMuxOnTime           = NAND_ADVAADMUXONTIME;
846     nandTimingInfo->ADVOnTime                 = NAND_ADVONTIME;
848     nandTimingInfo->WEOffTime                 = NAND_WEOFFTIME;
849     nandTimingInfo->WEExtDelayFlag            = GPMC_WE_EXTRA_NODELAY;
850     nandTimingInfo->WEOnTime                  = NAND_WEONTIME;
851     nandTimingInfo->OEAADMuxOffTime           = NAND_OEAADMUXOFFTIME;
852     nandTimingInfo->OEOffTime                 = NAND_OEOFFTIME;
853     nandTimingInfo->OEExtDelayFlag            = GPMC_OE_EXTRA_NODELAY;
854     nandTimingInfo->OEAADMuxOnTime            = NAND_OEAADMUXONTIME;
855     nandTimingInfo->OEOnTime                  = NAND_OEONTIME;
857     nandTimingInfo->rdCycleTime               = NAND_RDCYCLETIME;
858     nandTimingInfo->wrCycleTime               = NAND_WRCYCLETIME;
859     nandTimingInfo->rdAccessTime              = NAND_RDACCESSTIME;
860     nandTimingInfo->pageBurstAccessTime       = NAND_PAGEBURSTACCESSTIME;
862     nandTimingInfo->cycle2CycleDelay          = NAND_CYCLE2CYCLEDELAY;
863     nandTimingInfo->cycle2CycleDelaySameCSCfg = NAND_CYCLE2CYCLESAMECSEN;
864     nandTimingInfo->cycle2CycleDelayDiffCSCfg = NAND_CYCLE2CYCLEDIFFCSEN;
865     nandTimingInfo->busTAtime                 = NAND_BUSTURNAROUND;
867         nandTimingInfo->wrAccessTime              = NAND_WRACCESSTIME;
868         nandTimingInfo->wrDataOnADMux             = NAND_WRDATAONADMUXBUS;
871 /******************************************************************************
872 *                                                                             *
873 * \brief  Function to initalize the NAND configuration info.                  *
874 *                                                                             *
875 * \param  nandTimimgInfo : Pointer to structure containing                    *
876 *                          NAND timing info.                                  *
877 *                                                                             *
878 * \return none.                                                               *
879 *                                                                             *
880 ******************************************************************************/
881 static void NandInfoInit(NandInfo_t *nandInfo)
883     NandCtrlInfo_t *hNandCtrlInfo = nandInfo->hNandCtrlInfo;
884     NandEccInfo_t  *hNandEccInfo  = nandInfo->hNandEccInfo;
886     /* Init the NAND Device Info */
887     nandInfo->eccType                       = NAND_ECC_ALGO_BCH_8BIT;
888     nandInfo->chipSelectCnt                 = 1;
889     nandInfo->dieCnt                        = 1;
890     nandInfo->chipSelects[0]                = NAND_CS;
891     nandInfo->busWidth                      = NAND_BUSWIDTH_16BIT;
892     nandInfo->pageSize                      = NAND_PAGESIZE_2048BYTES;
893     nandInfo->blkSize                       = NAND_BLOCKSIZE_128KB;
894         nandInfo->pagesPerBlk                   = PAGES_PER_BLOCK;
896     /* Init the NAND Controller Info struct */
897     hNandCtrlInfo->hNandTimingInfo          = &gNandTimingInfo;
898     hNandCtrlInfo->hGpmc                    = (gpmcHandle)CSL_GPMC_0_CFG_REGS;
899     hNandCtrlInfo->waitPin                  = GPMC_WAIT_PIN0;
900     hNandCtrlInfo->waitPinPol               = GPMC_WAIT_PIN_POLARITY_LOW;
901     hNandCtrlInfo->wpPinPol                 = GPMC_WP_PIN_LEVEL_HIGH;
902     hNandCtrlInfo->chipSelectBaseAddr[0]    = NAND_CS0_BASEADDR;
903     hNandCtrlInfo->chipSelectRegionSize[0]  = NAND_CS0_REGIONSIZE;
904     hNandCtrlInfo->currChipSelect           = NAND_CS;
906         hNandEccInfo->hElm                      = (elmHandle)CSL_ELM_0_CFG_REGS;
909  /******************************************************************************
910   *
911   * Function:    NandConfig
912   *
913   * Description: This function is used to congigure the NAND Device
914   *
915   * Parameters:  None
916   *
917   * Return Value: Err Status
918   *
919   *****************************************************************************/
920 static uint32_t NandConfig ()
922         NandStatus_t status;
924         /* Initialize NAND info */
925         NandInfoInit(&gNandInfo);
927         /* Initialize NAND timing information */
928         NandTimingInfoInit(gNandCtrlInfo.hNandTimingInfo);
930         /* Initialize the controller */
931         status = nandCtrlInit(&gNandInfo);
932         if (status != NAND_STATUS_PASSED)
933         {
934                 platform_errno =  PLATFORM_ERRNO_DEV_FAIL;
935                 IFPRINT(platform_write("NandConfig ... Nand Controller Init Failed \n"));
936                 return FAIL;
937         }
939     return SUCCESS;
942  /******************************************************************************
943   *
944   * Function:    NandOpenDevice
945   *
946   * Description: This function is used to open the NAND device and configure it
947   *
948   * Parameters:  None
949   *
950   * Return Value: Error/Success codes
951   *
952   *****************************************************************************/
953  static uint32_t NandOpenDevice(void)
954  {
955      uint8_t  status;
957      /* Initialize NAND interface */
958      if (NandConfig() != SUCCESS) {
959         IFPRINT(platform_write("NandOpenDevice ... could not initialize the Nand Interface. \n"));
960         return FAIL;
961      }
963 #if (PLATFORM_NAND_ECC_IN)
964      /* Initialize ECC module */
965      if (nandECCInit(&gNandInfo) != NAND_STATUS_PASSED) {
966         IFPRINT(platform_write("nandECCInit ... could not initialize the Nand ECC Interface. \n"));
967         return FAIL;
968      }
969 #endif
971      /* Send reset command to NAND */
972      NandCmdSet(NAND_RST);
973      platform_delay (NAND_WAIT_PIN_POLL_ST_DLY);
975      if (NandWaitRdy(NAND_RESET_TIMEOUT) != SUCCESS) {
976         platform_errno = PLATFORM_ERRNO_DEV_TIMEOUT;
977         IFPRINT(platform_write("NandOpenDevice ... Nand wait ready failed. \n"));
978         return FAIL;
979      }
981      NandCmdSet(NAND_STATUS);
982      platform_delay(10);
984      NandReadDataByte(&status);
986      if ((status & 0x01) == 1) {
987         /* if SR0 bit is set to 1, there is Error - operation failed */
988         platform_errno =  PLATFORM_ERRNO_DEV_FAIL;
989         IFPRINT(platform_write("NandOpenDevice ... Nand status error bit was set. \n"));
990          return FAIL;
991      }
993      return SUCCESS;
994  }
996  /******************************************************************************
997   *
998   * Function:    NandGetDetails
999   *
1000   * Description: Get details of the NAND flash used from the id and the
1001   *              table of NAND
1002   *
1003   * Parameters:  pNandInfo - Pointer to Nand Info structure
1004   *
1005   * Return Value: Error/Success codes
1006   *
1007   *****************************************************************************/
1008  uint32_t NandGetDetails(PLATFORM_DEVICE_info *pNandInfo)
1009  {
1010          uint32_t       i;
1011          uint32_t       uiStatus;
1012      NAND_ADDR  address;
1014      /* Clear the Information */
1015      pNandInfo->device_id = pNandInfo->manufacturer_id = 0x0;
1017      /* Read manufacturer ID and device ID */
1018      NandCmdSet(NAND_RDID);
1019      platform_delay(10);
1020      NandAleSet(NAND_ADD_00H);
1021      platform_delay(10);
1023      NandReadDataWord((uint16_t *)&pNandInfo->manufacturer_id);
1024      NandReadDataWord((uint16_t *)&pNandInfo->device_id);
1026      /* Get the bad block table */
1027      address.uiPageAddr         = 0;
1028      address.uiColumnAddr       = 0;
1030      for (i=0; i < BLOCKS_PER_DEVICE; i++) {
1031          address.uiBlockAddr     = i;
1033          /* Clear the Spare Area */
1034          memset(nandPageBuf, 0, SPARE_BYTES_PER_PAGE);
1036          // Read the spare area in to buffer
1037          uiStatus = NandReadSpareArea(pNandInfo, address.uiBlockAddr,
1038                                          address.uiPageAddr, nandPageBuf);
1039          if(uiStatus != SUCCESS) {
1040             return PLATFORM_ERRNO_NANDBBT;
1041          }
1042          else { // Success in reading the NAND spare area
1043              if (nandPageBuf[pNandInfo->bboffset] == 0xFF) {
1044                  pNandInfo->bblist[i]  = 0xFF;
1045              } else {
1046                  pNandInfo->bblist[i]  = 0x00;
1047              }
1048          }
1049      }
1050      return SUCCESS;
1051  }
1053  /******************************************************************************
1054   *
1055   * Function:    nandInit
1056   *
1057   * Description: This function initialize the EMIF16 NAND flash controller.
1058   *
1059   * Parameters:  None
1060   *
1061   * Return Value: status
1062   *
1063   ******************************************************************************/
1064 uint32_t nandInit(void)
1066         uint32_t retVal;
1068         gNandInfo.hNandCtrlInfo = &gNandCtrlInfo;
1069         gNandInfo.hNandEccInfo  = &gNandEccInfo;
1071         /* Open the NAND Device */
1072         retVal = NandOpenDevice();
1074         return (retVal);
1077 #endif /*(PLATFORM_NAND_IN)*/