Updated changes for GA RC1
[keystone-rtos/mcsdk-tools.git] / writer / nand / src / nandwriter.c
1 /******************************************************************************
2  * Copyright (c) 2011 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.03";
52 /* The input file name is hard coded */
53 char *input_file = "nand_writer_input.txt";
55 uint32_t swap_byte = 0;
57 /* Parameters defined in the input_file */
58 #define FILE_NAME      "file_name"
59 #define START_ADDR     "start_addr"
61 /* Memory address to store the write data */
62 #define WRITE_DATA_ADDRESS     0x80000000
64 /* NAND device specific definitions */
65 #define BAD_BLOCK_MARKER_VALUE  0xA5
67 /******************************************************************************
68  * Structure:   NAND_WRITER_INFO_T
69  *
70  *              NAND writer control data. This structure should be filled in
71  *              by the user before running
72  ******************************************************************************/
73 #define MAX_LINE_LENGTH 40
74 typedef struct NAND_WRITER_INFO_tag
75 {
76     char        file_name[MAX_LINE_LENGTH]; /* CCS format data file name */
77     uint32_t    blockSizeBytes;             /* The size of each sector */
78     uint32_t    deviceTotalBytes;           /* Total number of bytes available in the device */
79     uint32_t    startAddr;                  /* Start address to write */
80     uint32_t    writeBytes;                 /* Number of bytes to be written into the device */
81     uint8_t     *writeData;                 /* Address to store the write data */
82     uint8_t     *readData;                  /* Address to store the read data */
84 } NAND_WRITER_INFO_T;
86 NAND_WRITER_INFO_T nandWriterInfo;
88 /******************************************************************************
89  * Function:    print_platform_errno
90  ******************************************************************************/
91 void
92 print_platform_errno
93 (
94     void
95 )
96 {
97     printf ("Returned platform error number is %d\n", platform_errno);
98 }
100 /******************************************************************************
101  * Function:    checkBadBlockMark
102  *
103  *              Checks for the bad block mark. Returns TRUE if a block is marked bad.
104  ******************************************************************************/
105 Bool
106 checkBadBlockMark 
108     PLATFORM_DEVICE_info    *p_device,
109     uint32_t                  block
112     if (p_device->bblist[block] != 0xff)
113     {
114         return TRUE;
115     }
116     else
117     {
118         return FALSE;
119     }
122 /******************************************************************************
123  * Function:    markBlockBad
124  *
125  *              Mark a block as bad. Byte 5 of the spare area data is
126  *              written as 0xA5.
127  ******************************************************************************/
128 void 
129 markBlockBad 
131     PLATFORM_DEVICE_info        *p_device,
132     uint32_t                    block
135     uint8_t       *spare_data;
137     spare_data = malloc(p_device->spare_size);
138     if (spare_data == NULL)
139     {
140         printf ("Can not allocate spare_data memory!\n");
141         return;
142     }
144     platform_device_read_spare_data(p_device->handle, block, 0, spare_data);
146     /* Set all data bytes to 0xff, only set the user defined bad block mark value */
147     spare_data[p_device->bboffset] = BAD_BLOCK_MARKER_VALUE;
149     /* Write the data to page */
150     platform_device_write_spare_data(p_device->handle, block, 0, spare_data);
152     /* Save the user defined bad block mark in bblist */
153     p_device->bblist[block] = BAD_BLOCK_MARKER_VALUE;
155     free (spare_data);
158 /******************************************************************************
159  * Function:    form_block
160  *
161  *      Form a block of data to write to the NOR. The block is
162  *      created as a byte stream from the 4 byte stream in which
163  *      the MSB is always sent first.
164  ******************************************************************************/
165 void
166 formBlock
168     uint32_t      *data,
169     uint32_t      blockSize,
170     uint8_t       *scratch
173     uint32_t i, j;
175     /* Convert the data to a byte stream */
176     for (i = j = 0; j < blockSize; i++, j+=4)
177     {
178         scratch[j+0] = (data[i] >> 24) & 0xff;
179         scratch[j+1] = (data[i] >> 16) & 0xff;
180         scratch[j+2] = (data[i] >>  8) & 0xff;
181         scratch[j+3] = (data[i] >>  0) & 0xff;
182     }
185 /******************************************************************************
186  * Function:    flashNand
187  *
188  *              Write the image to flash.
189  *              Returns TRUE if the image is written successfully
190  *                      FALSE if the image write fails
191  ******************************************************************************/
192 Bool 
193 flash_nand
195     PLATFORM_DEVICE_info    *p_device
198     uint32_t      wPos, wLen;
199     uint32_t      block, start_block;
200     uint8_t       *scrach_block;
202     if (swap_byte)
203     {
204         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
205         if (scrach_block == NULL)
206         {
207             printf ("Can not allocate scratch block memory!\n");
208             return (FALSE);
209         }
210     }
212     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
214     /* Program the NAND */
215     for (block = start_block, wPos = 0; wPos < nandWriterInfo.writeBytes; block++, wPos += nandWriterInfo.blockSizeBytes)
216     {
217         while(checkBadBlockMark(p_device, block))
218         {
219             printf ("Bad block # %d detected, skipping block ... \n", block);
220             if (++block == p_device->block_count)
221             {
222                 printf ("Flash failed: End of device reached\n");
223                 if (swap_byte) free (scrach_block);
224                 return (FALSE);        
225             }
226         }
228         printf ("Flashing block %d (%d bytes of %d)\n", block, wPos, nandWriterInfo.writeBytes);
230         platform_device_erase_block(p_device->handle, block);
232         wLen = nandWriterInfo.blockSizeBytes;
233         if (nandWriterInfo.writeBytes - wPos < nandWriterInfo.blockSizeBytes)
234         {
235             wLen = nandWriterInfo.writeBytes - wPos;
236         }
238         if (swap_byte)
239         {
240             formBlock((uint32_t *)(&nandWriterInfo.writeData[wPos]), nandWriterInfo.blockSizeBytes, scrach_block);
241         }
242         else
243         {
244             scrach_block = &nandWriterInfo.writeData[wPos];
245         }
246         if (platform_device_write(p_device->handle, 
247                                   block*nandWriterInfo.blockSizeBytes, 
248                                   scrach_block, 
249                                   wLen) != Platform_EOK)
250         {
251             printf ("platform_device_write block # %d failed!\n", block);
252             print_platform_errno();
253             if (swap_byte) free (scrach_block);
254             return (FALSE);
255         }
257     }
259     if (swap_byte) free (scrach_block);
260     return (TRUE);
261 }    
263 /******************************************************************************
264  * Function:    flashVerify
265  *
266  *              Read back the data file that was just flashed. On errors mark the block as bad.
267  *              Returns TRUE if the image verified correctly.
268  *                      FALSE if the image verification failed
269  ******************************************************************************/
270 Bool 
271 flash_verify
273     PLATFORM_DEVICE_info    *p_device
276     uint32_t      rPos, rLen;
277     uint32_t      i, j;
278     uint32_t      block, start_block;
279     uint8_t       *scrach_block;
280     uint32_t      *read_data_w;
282     if (swap_byte) 
283     {
284         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
285         if (scrach_block == NULL)
286         {
287             printf ("Can not allocate scratch block memory!\n");
288             return (FALSE);
289         }
290     }
292     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
294     for (block = start_block, rPos = 0; rPos < nandWriterInfo.writeBytes; block++, rPos += nandWriterInfo.blockSizeBytes)
295     {
296         while(checkBadBlockMark(p_device, block))
297         {
298             printf ("Bad block # %d detected, skipping block ... \n", block);
299             if (++block == p_device->block_count)
300             {
301                 printf ("Flash failed: End of device reached\n");
302                 if (swap_byte) free (scrach_block);
303                 return (FALSE);        
304             }
305         }
308         printf ("Reading and verifying block %d (%d bytes of %d)\n", block, rPos, nandWriterInfo.writeBytes);
310         if (!swap_byte)
311         {
312             scrach_block = &nandWriterInfo.readData[rPos];
314         }
316         /* Read a block of data */
317         if(platform_device_read(p_device->handle, 
318                                 block*nandWriterInfo.blockSizeBytes, 
319                                 scrach_block,
320                                 nandWriterInfo.blockSizeBytes) != Platform_EOK)
321         {
322             printf ("Failure in reading block %d\n", block);
323             print_platform_errno();
324             if (platform_errno == PLATFORM_ERRNO_ECC_FAIL)
325             {
326                 printf ("marking block %d as bad, re-flash attempted\n", block);
327                 markBlockBad (p_device, block);
328             }
329             if (swap_byte) free (scrach_block);
330             return (FALSE);
331         }
333         /* Convert the packed data */
334         if (swap_byte)
335         {
336             read_data_w = (uint32_t *)(&nandWriterInfo.readData[rPos]);
337             for  (i = 0, j = 0; i < nandWriterInfo.blockSizeBytes; i += 4)
338                 read_data_w[j++] = (scrach_block[i+0] << 24) | (scrach_block[i+1] << 16) | (scrach_block[i+2] << 8) | scrach_block[i+3];
339         }
341         rLen = nandWriterInfo.blockSizeBytes;
342         if (nandWriterInfo.writeBytes - rPos < nandWriterInfo.blockSizeBytes)
343         {
344             rLen = nandWriterInfo.writeBytes - rPos;
345         }
347         /* Compare the data read with data programmed */
348         for (i = rPos; i < rLen; i++)
349         {
350             if (nandWriterInfo.readData[i] != nandWriterInfo.writeData[i])
351             {
352                 printf ("Failure in block %d, at byte %d, (at byte %d in the data file) expected 0x%08x, read 0x%08x\n", 
353                         block, i, rPos, nandWriterInfo.writeData[i], nandWriterInfo.readData[i]);
354                 if (swap_byte) free (scrach_block);
355                 return (FALSE);
356             }
357         }
359     }
361     if (swap_byte) free (scrach_block);
362     return (TRUE);
365 /******************************************************************************
366  * Function:    parse_input_file  
367  ******************************************************************************/
368 static Bool
369 parse_input_file
371     FILE*               fp
374     char line[MAX_LINE_LENGTH];
375     char tokens[] = " :=;\n";
376     char *key, *data;
378     memset(line, 0, MAX_LINE_LENGTH);
380     fgets(line, MAX_LINE_LENGTH, fp);
381     key  = (char *)strtok(line, tokens);
382     data = (char *)strtok(NULL, tokens);
384     if(strlen(data) == 0)
385     {
386        return FALSE;
387     }
389     if(strcmp(key, FILE_NAME) != 0)
390     {
391         return FALSE;
392     }
394     strcpy (nandWriterInfo.file_name, data);
396     fgets(line, MAX_LINE_LENGTH, fp);
397     key  = (char *)strtok(line, tokens);
398     data = (char *)strtok(NULL, tokens);
400     if(strlen(data) == 0)
401     {
402        return FALSE;
403     }
405     if(strcmp(key, START_ADDR) != 0)
406     {
407         return FALSE;
408     }
410     nandWriterInfo.startAddr = (uint32_t)atoi(data);
412     return TRUE;
415 /******************************************************************************
416  * Function:    find_file_length
417  ******************************************************************************/
418 static Bool
419 find_file_length
421     FILE*               fp
424     char        line[MAX_LINE_LENGTH];
425     char        *pEnd;
426     char        *ext;
427     uint32_t    data_len, write_addr;
429     memset(line, 0, MAX_LINE_LENGTH);
431     ext = strrchr(nandWriterInfo.file_name, '.');
432     if (ext && (strcmp(ext, ".dat") == 0))
433     {
434     fgets(line, MAX_LINE_LENGTH, fp);
436     /* Read the write address from the CCS header */
437     strtoul (line,&pEnd,16);
438     strtoul (pEnd,&pEnd,16);
439     write_addr = strtoul (pEnd,&pEnd,16);
440     strtoul (pEnd,&pEnd,16);
442     /* Read the data length */
443     data_len = (strtoul (pEnd,NULL,16)) * 4;
444     }
445     else
446     {
447         /* find the data length by seeking to the end and getting position */
448         fseek(fp, 0, SEEK_END);
449         data_len = ftell(fp);
450         fseek(fp, 0, SEEK_SET);
451     }
453     if (data_len > (nandWriterInfo.deviceTotalBytes - nandWriterInfo.startAddr))
454     {
455         printf ("The data file is too big to fit into the device.\n");
456         return FALSE;
457     }
459     nandWriterInfo.writeBytes = data_len;
460     if (write_addr != WRITE_DATA_ADDRESS)
461         write_addr = WRITE_DATA_ADDRESS;
462     nandWriterInfo.writeData  = (uint8_t *)write_addr;
463     nandWriterInfo.readData   = (uint8_t *)(write_addr + nandWriterInfo.deviceTotalBytes);
465     return TRUE;
468 /******************************************************************************
469  * Function:    main  
470  ******************************************************************************/
471 void main ()
473     FILE                    *fp;
474     platform_init_flags     init_flags;
475     platform_init_config    init_config;
476     PLATFORM_DEVICE_info    *p_device;
477     Bool                    ret;
478     uint32_t                rCount;
479     printf("NAND Writer Utility Version %s\n\n", version);
481     fp = fopen(input_file, "r");
482     if (fp == NULL)
483     {
484         printf("Error in opening %s input file\n", input_file);
485         return;
486     }
488     ret = parse_input_file(fp);
489     fclose (fp);
491     if (ret == FALSE)
492     {
493         printf("Error in parsing %s input file\n", input_file);
494         return;
495     }
497     /* Initialize main Platform lib */
498     memset(&init_config, 0, sizeof(platform_init_config));
499     memset(&init_flags, 1, sizeof(platform_init_flags));
500     if (platform_init(&init_flags, &init_config) != Platform_EOK)
501     {
502         printf ("Platform init failed!\n");
503         print_platform_errno();
504         return;
505     }
507     p_device = platform_device_open(PLATFORM_DEVID_NAND512R3A2D, 0);
508     if (p_device == NULL) 
509     {
510         printf ("NAND device open failed!\n");
511         print_platform_errno();
512         return;
513     }
514     nandWriterInfo.deviceTotalBytes = p_device->block_count * p_device->page_count * p_device->page_size;
515     nandWriterInfo.blockSizeBytes   = p_device->page_count * p_device->page_size;
517     if ((nandWriterInfo.startAddr % nandWriterInfo.blockSizeBytes) != 0)
518     {
519         printf ("The start programming address 0x%8x set in %s is not at the beginning of a block, block size = 0x%4x\n", 
520                 nandWriterInfo.startAddr, 
521                 nandWriterInfo.file_name,
522                 nandWriterInfo.blockSizeBytes);
523         return;
524     }
526     /* Open and find the length of the data file */
527     fp = fopen (nandWriterInfo.file_name, "rb");
528     if (fp == NULL)
529     {
530       printf ("Failed to open file %s\n", nandWriterInfo.file_name);
531       platform_device_close(p_device->handle);
532       return;
533     }
535     /* Parse the CCS format file */
536     ret = find_file_length(fp);
537     fclose (fp);
538     if (ret == FALSE)
539     {
540         printf("Error in parsing CCS file %s\n", nandWriterInfo.file_name);
541         platform_device_close(p_device->handle);
542         return;
543     }
544     
546     /* Write the flash, verify the results. On read back failure mark
547      * the block as bad and try rewriting again */
548     rCount = 0;
550     do  
551     {
552         if (flash_nand (p_device) == FALSE)
553         {
554             printf ("NAND write giving up\n");
555             return;
556         }
558         rCount += 1;
560     }  while ((flash_verify (p_device) == FALSE) && (rCount < 5));
562     
563     if (rCount >= 5) 
564     {
565         printf ("NAND write failed (maximum retries reached)\n");
566     }
567     else
568     {
569         printf ("NAND programming completed successfully\n");
570     }
572     platform_device_close(p_device->handle);
573     
574     return;