]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/mcsdk-tools.git/blob - writer/nand/src/nandwriter.c
742be938994c1956a087abc4f96a488a909e4533
[keystone-rtos/mcsdk-tools.git] / writer / nand / src / nandwriter.c
1 /******************************************************************************
2  * Copyright (c) 2013-2014 Texas Instruments Incorporated - http://www.ti.com
3  * 
4  *  Redistribution and use in source and binary forms, with or without 
5  *  modification, are permitted provided that the following conditions 
6  *  are met:
7  *
8  *    Redistributions of source code must retain the above copyright 
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  *    Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the 
13  *    documentation and/or other materials provided with the   
14  *    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 
21  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
24  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
25  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
26  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
29  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  * 
32  *****************************************************************************/
34 /**************************************************************************************
35  * FILE PURPOSE: NAND writer utility
36  **************************************************************************************
37  * FILE NAME: nandwriter.c
38  *
39  * DESCRIPTION: A simple nand writer using platform lib APIs to program the NAND flash
40  *              with an image that the ibl can read.
41  *
42  ***************************************************************************************/
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include "platform.h"
47 #include "types.h"
49 /* NAND writer utility version */
50 char version[] = "01.00.00.05";
52 /* The input file name is hard coded */
53 char *input_file = "nand_writer_input.txt";
55 uint32_t swap_byte = 0;
56 volatile uint32_t nand_erase_flag = 0;
58 /* Parameters defined in the input_file */
59 #define FILE_NAME      "file_name"
60 #define START_ADDR     "start_addr"
61 #define RBL_ECC        "rbl_ecc"
62 #define SKIP_BAD       "skip_bad"
64 /* Memory address to store the write data */
65 #define WRITE_DATA_ADDRESS     0x80000000
67 /* NAND device specific definitions */
68 #define BAD_BLOCK_MARKER_VALUE  0xA5
70 /******************************************************************************
71  * Structure:   NAND_WRITER_INFO_T
72  *
73  *              NAND writer control data. This structure should be filled in
74  *              by the user before running
75  ******************************************************************************/
76 #define MAX_LINE_LENGTH 40
77 typedef struct NAND_WRITER_INFO_tag
78 {
79     char        file_name[MAX_LINE_LENGTH]; /* CCS format data file name */
80     uint32_t    blockSizeBytes;             /* The size of each sector */
81     uint32_t    deviceTotalBytes;           /* Total number of bytes available in the device */
82     uint32_t    startAddr;                  /* Start address to write */
83     uint32_t    writeBytes;                 /* Number of bytes to be written into the device */
84     uint8_t     flags;                      /* Flag used for EVMK2H for multiple ECC formats */
85     uint8_t     skip_bad_blks;              /* Flag used to skip bad blocks */
86     uint8_t     *writeData;                 /* Address to store the write data */
87     uint8_t     *readData;                  /* Address to store the read data */
89 } NAND_WRITER_INFO_T;
91 NAND_WRITER_INFO_T nandWriterInfo;
93 /* OSAL functions for Platform Library */
94 uint8_t *Osal_platformMalloc (uint32_t num_bytes, uint32_t alignment)
95 {
96         return malloc(num_bytes);
97 }
99 void Osal_platformFree (uint8_t *dataPtr, uint32_t num_bytes)
101     /* Free up the memory */
102     if (dataPtr)
103     {
104         free(dataPtr);
105     }
108 void Osal_platformSpiCsEnter(void)
110     return;
113 void Osal_platformSpiCsExit (void)
115     return;
118 /******************************************************************************
119  * Function:    print_platform_errno
120  ******************************************************************************/
121 void
122 print_platform_errno
124     void
127     printf ("Returned platform error number is %d\n", platform_errno);
130 /******************************************************************************
131  * Function:    checkBadBlockMark
132  *
133  *              Checks for the bad block mark. Returns TRUE if a block is marked bad.
134  ******************************************************************************/
135 Bool
136 checkBadBlockMark 
138     PLATFORM_DEVICE_info    *p_device,
139     uint32_t                  block
142     if (p_device->bblist[block] != 0xff)
143     {
144         return TRUE;
145     }
146     else
147     {
148         return FALSE;
149     }
152 /******************************************************************************
153  * Function:    markBlockBad
154  *
155  *              Mark a block as bad. Byte 5 of the spare area data is
156  *              written as 0xA5.
157  ******************************************************************************/
158 void 
159 markBlockBad 
161     PLATFORM_DEVICE_info        *p_device,
162     uint32_t                    block
165     uint8_t       *spare_data;
167     spare_data = malloc(p_device->spare_size);
168     if (spare_data == NULL)
169     {
170         printf ("Can not allocate spare_data memory!\n");
171         return;
172     }
174     platform_device_read_spare_data(p_device->handle, block, 0, spare_data);
176     /* Set all data bytes to 0xff, only set the user defined bad block mark value */
177     spare_data[p_device->bboffset] = BAD_BLOCK_MARKER_VALUE;
179     /* Write the data to page */
180     platform_device_write_spare_data(p_device->handle, block, 0, spare_data);
182     /* Save the user defined bad block mark in bblist */
183     p_device->bblist[block] = BAD_BLOCK_MARKER_VALUE;
185     free (spare_data);
188 /******************************************************************************
189  * Function:    formBlock
190  *
191  *      Form a block of data to write to the NAND. The block is
192  *      created as a byte stream from the 4 byte stream in which
193  *      the MSB is always sent first.
194  ******************************************************************************/
195 void
196 formBlock
198     uint32_t      *data,
199     uint32_t      blockSize,
200     uint8_t       *scratch
203     uint32_t i, j;
205     /* Convert the data to a byte stream */
206     for (i = j = 0; j < blockSize; i++, j+=4)
207     {
208         scratch[j+0] = (data[i] >> 24) & 0xff;
209         scratch[j+1] = (data[i] >> 16) & 0xff;
210         scratch[j+2] = (data[i] >>  8) & 0xff;
211         scratch[j+3] = (data[i] >>  0) & 0xff;
212     }
215 /******************************************************************************
216  * Function:    flash_nand
217  *
218  *              Write the image to flash.
219  *              Returns TRUE if the image is written successfully
220  *                      FALSE if the image write fails
221  ******************************************************************************/
222 Bool 
223 flash_nand
225     PLATFORM_DEVICE_info    *p_device
228     uint32_t      wPos, wLen;
229     uint32_t      block, start_block;
230     uint8_t       *scrach_block;
231     uint32_t      num_blks;
232     uint32_t      bad_block_found;
234     if (swap_byte)
235     {
236         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
237         if (scrach_block == NULL)
238         {
239             printf ("Can not allocate scratch block memory!\n");
240             return (FALSE);
241         }
242     }
244     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
246     /* skip the bad blocks if the flag is set */
247     if (nandWriterInfo.skip_bad_blks)
248     {
249         num_blks = nandWriterInfo.writeBytes / nandWriterInfo.blockSizeBytes;
250         if ((nandWriterInfo.writeBytes - nandWriterInfo.blockSizeBytes * num_blks) > 0)
251                 num_blks++;
253         while (TRUE)
254         {
255                 bad_block_found = FALSE;
256                 for (block = start_block; block < start_block + num_blks; block++)
257                 {
258                         if (checkBadBlockMark(p_device, block))
259                         {
260                                 start_block = block + 1;
261                                 bad_block_found = TRUE;
262                                 break;
263                         }
264                 }
265                 if (bad_block_found == FALSE)
266                         break;
267         }
268     }
270     /* Program the NAND */
271     for (block = start_block, wPos = 0; wPos < nandWriterInfo.writeBytes; block++, wPos += nandWriterInfo.blockSizeBytes)
272     {
273         while(checkBadBlockMark(p_device, block))
274         {
275             printf ("Bad block # %d detected, skipping block ... \n", block);
276             if (++block == p_device->block_count)
277             {
278                 printf ("Flash failed: End of device reached\n");
279                 if (swap_byte) free (scrach_block);
280                 return (FALSE);        
281             }
282         }
284         printf ("Flashing block %d (%d bytes of %d)\n", block, wPos, nandWriterInfo.writeBytes);
286         platform_device_erase_block(p_device->handle, block);
288         wLen = nandWriterInfo.blockSizeBytes;
289         if (nandWriterInfo.writeBytes - wPos < nandWriterInfo.blockSizeBytes)
290         {
291             wLen = nandWriterInfo.writeBytes - wPos;
292         }
294         if (swap_byte)
295         {
296             formBlock((uint32_t *)(&nandWriterInfo.writeData[wPos]), nandWriterInfo.blockSizeBytes, scrach_block);
297         }
298         else
299         {
300             scrach_block = &nandWriterInfo.writeData[wPos];
301         }
302         if (platform_device_write(p_device->handle, 
303                                   block*nandWriterInfo.blockSizeBytes, 
304                                   scrach_block, 
305                                   wLen) != Platform_EOK)
306         {
307             printf ("platform_device_write block # %d failed!\n", block);
308             print_platform_errno();
309             if (swap_byte) free (scrach_block);
310             return (FALSE);
311         }
313     }
315     if (swap_byte) free (scrach_block);
316     return (TRUE);
317 }    
319 /******************************************************************************
320  * Function:    flash_verify
321  *
322  *              Read back the data file that was just flashed. On errors mark the block as bad.
323  *              Returns TRUE if the image verified correctly.
324  *                      FALSE if the image verification failed
325  ******************************************************************************/
326 Bool 
327 flash_verify
329     PLATFORM_DEVICE_info    *p_device
332     uint32_t      rPos, rLen;
333     uint32_t      i, j;
334     uint32_t      block, start_block;
335     uint8_t       *scrach_block;
336     uint32_t      *read_data_w;
338     if (swap_byte) 
339     {
340         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
341         if (scrach_block == NULL)
342         {
343             printf ("Can not allocate scratch block memory!\n");
344             return (FALSE);
345         }
346     }
348     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
350     for (block = start_block, rPos = 0; rPos < nandWriterInfo.writeBytes; block++, rPos += nandWriterInfo.blockSizeBytes)
351     {
352         while(checkBadBlockMark(p_device, block))
353         {
354             printf ("Bad block # %d detected, skipping block ... \n", block);
355             if (++block == p_device->block_count)
356             {
357                 printf ("Flash failed: End of device reached\n");
358                 if (swap_byte) free (scrach_block);
359                 return (FALSE);        
360             }
361         }
364         printf ("Reading and verifying block %d (%d bytes of %d)\n", block, rPos, nandWriterInfo.writeBytes);
366         if (!swap_byte)
367         {
368             scrach_block = &nandWriterInfo.readData[rPos];
370         }
372         /* Read a block of data */
373         if(platform_device_read(p_device->handle, 
374                                 block*nandWriterInfo.blockSizeBytes, 
375                                 scrach_block,
376                                 nandWriterInfo.blockSizeBytes) != Platform_EOK)
377         {
378             printf ("Failure in reading block %d\n", block);
379             print_platform_errno();
380             if (platform_errno == PLATFORM_ERRNO_ECC_FAIL)
381             {
382                 printf ("marking block %d as bad, re-flash attempted\n", block);
383                 markBlockBad (p_device, block);
384             }
385             if (swap_byte) free (scrach_block);
386             return (FALSE);
387         }
389         /* Convert the packed data */
390         if (swap_byte)
391         {
392             read_data_w = (uint32_t *)(&nandWriterInfo.readData[rPos]);
393             for  (i = 0, j = 0; i < nandWriterInfo.blockSizeBytes; i += 4)
394                 read_data_w[j++] = (scrach_block[i+0] << 24) | (scrach_block[i+1] << 16) | (scrach_block[i+2] << 8) | scrach_block[i+3];
395         }
397         rLen = nandWriterInfo.blockSizeBytes;
398         if (nandWriterInfo.writeBytes - rPos < nandWriterInfo.blockSizeBytes)
399         {
400             rLen = nandWriterInfo.writeBytes - rPos;
401         }
403         /* Compare the data read with data programmed */
404         for (i = rPos; i < rLen; i++)
405         {
406             if (nandWriterInfo.readData[i] != nandWriterInfo.writeData[i])
407             {
408                 printf ("Failure in block %d, at byte %d, (at byte %d in the data file) expected 0x%08x, read 0x%08x\n", 
409                         block, i, rPos, nandWriterInfo.writeData[i], nandWriterInfo.readData[i]);
410                 if (swap_byte) free (scrach_block);
411                 return (FALSE);
412             }
413         }
415     }
417     if (swap_byte) free (scrach_block);
418     return (TRUE);
421 /******************************************************************************
422  * Function:    parse_input_file  
423  ******************************************************************************/
424 static Bool
425 parse_input_file
427     FILE*               fp
430     char line[MAX_LINE_LENGTH];
431     char tokens[] = " :=;\n\r";
432     char *key, *data;
434     memset(line, 0, MAX_LINE_LENGTH);
436     fgets(line, MAX_LINE_LENGTH, fp);
437     key  = (char *)strtok(line, tokens);
438     data = (char *)strtok(NULL, tokens);
440     if(strlen(data) == 0)
441     {
442        return FALSE;
443     }
445     if(strcmp(key, FILE_NAME) != 0)
446     {
447         return FALSE;
448     }
450     strcpy (nandWriterInfo.file_name, data);
452     fgets(line, MAX_LINE_LENGTH, fp);
453     key  = (char *)strtok(line, tokens);
454     data = (char *)strtok(NULL, tokens);
456     if(strlen(data) == 0)
457     {
458        return FALSE;
459     }
461     if(strcmp(key, START_ADDR) != 0)
462     {
463         return FALSE;
464     }
466     nandWriterInfo.startAddr = (uint32_t)atoi(data);
467     
468     fgets(line, MAX_LINE_LENGTH, fp);
469     key = (char *)strtok(line, tokens);
470     data = (char *)strtok(NULL, tokens);
471     
472     if(strlen(data) != 0 && (strcmp(key, RBL_ECC) == 0))
473     {
474         nandWriterInfo.flags = (uint8_t)atoi(data);
475     }
476     else
477     {
478         nandWriterInfo.flags = 0;
479     }
481     /* Scan skip bad block input parameter */
482     fgets(line, MAX_LINE_LENGTH, fp);
483     key = (char *)strtok(line, tokens);
484     data = (char *)strtok(NULL, tokens);
486     if(strlen(data) != 0 && (strcmp(key, SKIP_BAD) == 0))
487     {
488         nandWriterInfo.skip_bad_blks = (uint8_t)atoi(data);
489     }
490     else
491     {
492         nandWriterInfo.skip_bad_blks = 0;
493     }
495     return TRUE;
498 /******************************************************************************
499  * Function:    find_file_length
500  ******************************************************************************/
501 static Bool
502 find_file_length
504     FILE*               fp
507     char        line[MAX_LINE_LENGTH];
508     char        *pEnd;
509     char        *ext;
510     uint32_t    data_len, write_addr;
512     memset(line, 0, MAX_LINE_LENGTH);
514     ext = strrchr(nandWriterInfo.file_name, '.');
515     if (ext && (strcmp(ext, ".dat") == 0))
516     {
517     fgets(line, MAX_LINE_LENGTH, fp);
519     /* Read the write address from the CCS header */
520     strtoul (line,&pEnd,16);
521     strtoul (pEnd,&pEnd,16);
522     write_addr = strtoul (pEnd,&pEnd,16);
523     strtoul (pEnd,&pEnd,16);
525     /* Read the data length */
526     data_len = (strtoul (pEnd,NULL,16)) * 4;
527     }
528     else
529     {
530         /* find the data length by seeking to the end and getting position */
531         fseek(fp, 0, SEEK_END);
532         data_len = ftell(fp);
533         fseek(fp, 0, SEEK_SET);
534     }
536     if (data_len > (nandWriterInfo.deviceTotalBytes - nandWriterInfo.startAddr))
537     {
538         printf ("The data file is too big to fit into the device.\n");
539         return FALSE;
540     }
542     nandWriterInfo.writeBytes = data_len;
543     if (write_addr != WRITE_DATA_ADDRESS)
544         write_addr = WRITE_DATA_ADDRESS;
545     nandWriterInfo.writeData  = (uint8_t *)write_addr;
546     nandWriterInfo.readData   = (uint8_t *)(write_addr + nandWriterInfo.deviceTotalBytes);
548     return TRUE;
551 static Bool 
552 nand_erase_all_blks(PLATFORM_DEVICE_info *p_device)
554   uint32_t block;
555   uint32_t max_blks;
557   max_blks = p_device->block_count;
558   
559   for (block=0; block<max_blks;block++)
560   {
561       printf (".");
562       if (platform_device_erase_block(p_device->handle, block) != Platform_EOK)
563         return FALSE;
564   }
566   printf ("\nFormatted %d nand blocks \n", block);
567   return (TRUE);
570 /******************************************************************************
571  * Function:    main  
572  ******************************************************************************/
573 void main ()
575     FILE                    *fp;
576     platform_init_flags     init_flags;
577     platform_init_config    init_config;
578     PLATFORM_DEVICE_info    *p_device;
579     Bool                    ret;
580     uint32_t                rCount;
581     printf("NAND Writer Utility Version %s\n\n", version);
583     fp = fopen(input_file, "r");
584     if (fp == NULL)
585     {
586         printf("Error in opening %s input file\n", input_file);
587         return;
588     }
590     ret = parse_input_file(fp);
591     fclose (fp);
593     if (ret == FALSE)
594     {
595         printf("Error in parsing %s input file\n", input_file);
596         return;
597     }
599     /* Initialize main Platform lib */
600     memset(&init_config, 0, sizeof(platform_init_config));
601     memset(&init_flags, 1, sizeof(platform_init_flags));
602     init_flags.pll = 0;
603     init_flags.ddr = 0;
604     init_flags.phy =0;
605     if (platform_init(&init_flags, &init_config) != Platform_EOK)
606     {
607         printf ("Platform init failed!\n");
608         print_platform_errno();
609         return;
610     }
611 #if (defined(_EVMC6657L_) || defined(DEVICE_K2H))
612      p_device = platform_device_open(PLATFORM_DEVID_MT29F1G08ABCHC, nandWriterInfo.flags);
613 #elif defined(DEVICE_K2E)
614      p_device = platform_device_open(PLATFORM_DEVID_MT29F4G08ABADA, nandWriterInfo.flags);
615 #elif defined(DEVICE_K2L)
616      p_device = platform_device_open(PLATFORM_DEVID_MT29F16G08ADBCAH4C, nandWriterInfo.flags);
617 #elif defined(DEVICE_K2G)
618      p_device = platform_device_open(PLATFORM_DEVID_MT29F2G16ABAFA, nandWriterInfo.flags);
619 #else
620     p_device = platform_device_open(PLATFORM_DEVID_NAND512R3A2D, 0);
621 #endif
622     if (p_device == NULL) 
623     {
624         printf ("NAND device open failed!\n");
625         print_platform_errno();
626         return;
627     }
628     nandWriterInfo.deviceTotalBytes = p_device->block_count * p_device->page_count * p_device->page_size;
629     nandWriterInfo.blockSizeBytes   = p_device->page_count * p_device->page_size;
631     if ((nandWriterInfo.startAddr % nandWriterInfo.blockSizeBytes) != 0)
632     {
633         printf ("The start programming address 0x%8x set in %s is not at the beginning of a block, block size = 0x%4x\n", 
634                 nandWriterInfo.startAddr, 
635                 nandWriterInfo.file_name,
636                 nandWriterInfo.blockSizeBytes);
637         return;
638     }
640     /* Check if we need to erase the nand completely */
641      if (nand_erase_flag == 0x12345678)
642      {
643         if (nand_erase_all_blks(p_device) == FALSE)
644         {
645            printf ("Formatting all nand blocks - failed \n");
646         }
647         else
648         {
649            printf ("Formatting all nand blocks - Successful\n");
650         }
651         platform_device_close(p_device->handle);
652         /* Operation Complete */
653         return;
654      }
656     /* Open and find the length of the data file */
657     fp = fopen (nandWriterInfo.file_name, "rb");
658     if (fp == NULL)
659     {
660       printf ("Failed to open file %s\n", nandWriterInfo.file_name);
661       platform_device_close(p_device->handle);
662       return;
663     }
665     /* Parse the CCS format file */
666     ret = find_file_length(fp);
667     fclose (fp);
668     if (ret == FALSE)
669     {
670         printf("Error in parsing CCS file %s\n", nandWriterInfo.file_name);
671         platform_device_close(p_device->handle);
672         return;
673     }
674     
675     /* Write the flash, verify the results. On read back failure mark
676      * the block as bad and try rewriting again */
677     rCount = 0;
679     do  
680     {
681         if (flash_nand (p_device) == FALSE)
682         {
683             printf ("NAND write giving up\n");
684             return;
685         }
687         rCount += 1;
689     }  while ((flash_verify (p_device) == FALSE) && (rCount < 5));
691     
692     if (rCount >= 5) 
693     {
694         printf ("NAND write failed (maximum retries reached)\n");
695     }
696     else
697     {
698         printf ("NAND programming completed successfully\n");
699     }
701     platform_device_close(p_device->handle);
702     
703     return;