Copy program evm for mcsdk-210 branch
[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.04";
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 /* OSAL functions for Platform Library */
89 uint8_t *Osal_platformMalloc (uint32_t num_bytes, uint32_t alignment)
90 {
91         return malloc(num_bytes);
92 }
94 void Osal_platformFree (uint8_t *dataPtr, uint32_t num_bytes)
95 {
96     /* Free up the memory */
97     if (dataPtr)
98     {
99         free(dataPtr);
100     }
103 void Osal_platformSpiCsEnter(void)
105     return;
108 void Osal_platformSpiCsExit (void)
110     return;
113 /******************************************************************************
114  * Function:    print_platform_errno
115  ******************************************************************************/
116 void
117 print_platform_errno
119     void
122     printf ("Returned platform error number is %d\n", platform_errno);
125 /******************************************************************************
126  * Function:    checkBadBlockMark
127  *
128  *              Checks for the bad block mark. Returns TRUE if a block is marked bad.
129  ******************************************************************************/
130 Bool
131 checkBadBlockMark 
133     PLATFORM_DEVICE_info    *p_device,
134     uint32_t                  block
137     if (p_device->bblist[block] != 0xff)
138     {
139         return TRUE;
140     }
141     else
142     {
143         return FALSE;
144     }
147 /******************************************************************************
148  * Function:    markBlockBad
149  *
150  *              Mark a block as bad. Byte 5 of the spare area data is
151  *              written as 0xA5.
152  ******************************************************************************/
153 void 
154 markBlockBad 
156     PLATFORM_DEVICE_info        *p_device,
157     uint32_t                    block
160     uint8_t       *spare_data;
162     spare_data = malloc(p_device->spare_size);
163     if (spare_data == NULL)
164     {
165         printf ("Can not allocate spare_data memory!\n");
166         return;
167     }
169     platform_device_read_spare_data(p_device->handle, block, 0, spare_data);
171     /* Set all data bytes to 0xff, only set the user defined bad block mark value */
172     spare_data[p_device->bboffset] = BAD_BLOCK_MARKER_VALUE;
174     /* Write the data to page */
175     platform_device_write_spare_data(p_device->handle, block, 0, spare_data);
177     /* Save the user defined bad block mark in bblist */
178     p_device->bblist[block] = BAD_BLOCK_MARKER_VALUE;
180     free (spare_data);
183 /******************************************************************************
184  * Function:    form_block
185  *
186  *      Form a block of data to write to the NOR. The block is
187  *      created as a byte stream from the 4 byte stream in which
188  *      the MSB is always sent first.
189  ******************************************************************************/
190 void
191 formBlock
193     uint32_t      *data,
194     uint32_t      blockSize,
195     uint8_t       *scratch
198     uint32_t i, j;
200     /* Convert the data to a byte stream */
201     for (i = j = 0; j < blockSize; i++, j+=4)
202     {
203         scratch[j+0] = (data[i] >> 24) & 0xff;
204         scratch[j+1] = (data[i] >> 16) & 0xff;
205         scratch[j+2] = (data[i] >>  8) & 0xff;
206         scratch[j+3] = (data[i] >>  0) & 0xff;
207     }
210 /******************************************************************************
211  * Function:    flashNand
212  *
213  *              Write the image to flash.
214  *              Returns TRUE if the image is written successfully
215  *                      FALSE if the image write fails
216  ******************************************************************************/
217 Bool 
218 flash_nand
220     PLATFORM_DEVICE_info    *p_device
223     uint32_t      wPos, wLen;
224     uint32_t      block, start_block;
225     uint8_t       *scrach_block;
227     if (swap_byte)
228     {
229         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
230         if (scrach_block == NULL)
231         {
232             printf ("Can not allocate scratch block memory!\n");
233             return (FALSE);
234         }
235     }
237     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
239     /* Program the NAND */
240     for (block = start_block, wPos = 0; wPos < nandWriterInfo.writeBytes; block++, wPos += nandWriterInfo.blockSizeBytes)
241     {
242         while(checkBadBlockMark(p_device, block))
243         {
244             printf ("Bad block # %d detected, skipping block ... \n", block);
245             if (++block == p_device->block_count)
246             {
247                 printf ("Flash failed: End of device reached\n");
248                 if (swap_byte) free (scrach_block);
249                 return (FALSE);        
250             }
251         }
253         printf ("Flashing block %d (%d bytes of %d)\n", block, wPos, nandWriterInfo.writeBytes);
255         platform_device_erase_block(p_device->handle, block);
257         wLen = nandWriterInfo.blockSizeBytes;
258         if (nandWriterInfo.writeBytes - wPos < nandWriterInfo.blockSizeBytes)
259         {
260             wLen = nandWriterInfo.writeBytes - wPos;
261         }
263         if (swap_byte)
264         {
265             formBlock((uint32_t *)(&nandWriterInfo.writeData[wPos]), nandWriterInfo.blockSizeBytes, scrach_block);
266         }
267         else
268         {
269             scrach_block = &nandWriterInfo.writeData[wPos];
270         }
271         if (platform_device_write(p_device->handle, 
272                                   block*nandWriterInfo.blockSizeBytes, 
273                                   scrach_block, 
274                                   wLen) != Platform_EOK)
275         {
276             printf ("platform_device_write block # %d failed!\n", block);
277             print_platform_errno();
278             if (swap_byte) free (scrach_block);
279             return (FALSE);
280         }
282     }
284     if (swap_byte) free (scrach_block);
285     return (TRUE);
286 }    
288 /******************************************************************************
289  * Function:    flashVerify
290  *
291  *              Read back the data file that was just flashed. On errors mark the block as bad.
292  *              Returns TRUE if the image verified correctly.
293  *                      FALSE if the image verification failed
294  ******************************************************************************/
295 Bool 
296 flash_verify
298     PLATFORM_DEVICE_info    *p_device
301     uint32_t      rPos, rLen;
302     uint32_t      i, j;
303     uint32_t      block, start_block;
304     uint8_t       *scrach_block;
305     uint32_t      *read_data_w;
307     if (swap_byte) 
308     {
309         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
310         if (scrach_block == NULL)
311         {
312             printf ("Can not allocate scratch block memory!\n");
313             return (FALSE);
314         }
315     }
317     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
319     for (block = start_block, rPos = 0; rPos < nandWriterInfo.writeBytes; block++, rPos += nandWriterInfo.blockSizeBytes)
320     {
321         while(checkBadBlockMark(p_device, block))
322         {
323             printf ("Bad block # %d detected, skipping block ... \n", block);
324             if (++block == p_device->block_count)
325             {
326                 printf ("Flash failed: End of device reached\n");
327                 if (swap_byte) free (scrach_block);
328                 return (FALSE);        
329             }
330         }
333         printf ("Reading and verifying block %d (%d bytes of %d)\n", block, rPos, nandWriterInfo.writeBytes);
335         if (!swap_byte)
336         {
337             scrach_block = &nandWriterInfo.readData[rPos];
339         }
341         /* Read a block of data */
342         if(platform_device_read(p_device->handle, 
343                                 block*nandWriterInfo.blockSizeBytes, 
344                                 scrach_block,
345                                 nandWriterInfo.blockSizeBytes) != Platform_EOK)
346         {
347             printf ("Failure in reading block %d\n", block);
348             print_platform_errno();
349             if (platform_errno == PLATFORM_ERRNO_ECC_FAIL)
350             {
351                 printf ("marking block %d as bad, re-flash attempted\n", block);
352                 markBlockBad (p_device, block);
353             }
354             if (swap_byte) free (scrach_block);
355             return (FALSE);
356         }
358         /* Convert the packed data */
359         if (swap_byte)
360         {
361             read_data_w = (uint32_t *)(&nandWriterInfo.readData[rPos]);
362             for  (i = 0, j = 0; i < nandWriterInfo.blockSizeBytes; i += 4)
363                 read_data_w[j++] = (scrach_block[i+0] << 24) | (scrach_block[i+1] << 16) | (scrach_block[i+2] << 8) | scrach_block[i+3];
364         }
366         rLen = nandWriterInfo.blockSizeBytes;
367         if (nandWriterInfo.writeBytes - rPos < nandWriterInfo.blockSizeBytes)
368         {
369             rLen = nandWriterInfo.writeBytes - rPos;
370         }
372         /* Compare the data read with data programmed */
373         for (i = rPos; i < rLen; i++)
374         {
375             if (nandWriterInfo.readData[i] != nandWriterInfo.writeData[i])
376             {
377                 printf ("Failure in block %d, at byte %d, (at byte %d in the data file) expected 0x%08x, read 0x%08x\n", 
378                         block, i, rPos, nandWriterInfo.writeData[i], nandWriterInfo.readData[i]);
379                 if (swap_byte) free (scrach_block);
380                 return (FALSE);
381             }
382         }
384     }
386     if (swap_byte) free (scrach_block);
387     return (TRUE);
390 /******************************************************************************
391  * Function:    parse_input_file  
392  ******************************************************************************/
393 static Bool
394 parse_input_file
396     FILE*               fp
399     char line[MAX_LINE_LENGTH];
400     char tokens[] = " :=;\n\r";
401     char *key, *data;
403     memset(line, 0, MAX_LINE_LENGTH);
405     fgets(line, MAX_LINE_LENGTH, fp);
406     key  = (char *)strtok(line, tokens);
407     data = (char *)strtok(NULL, tokens);
409     if(strlen(data) == 0)
410     {
411        return FALSE;
412     }
414     if(strcmp(key, FILE_NAME) != 0)
415     {
416         return FALSE;
417     }
419     strcpy (nandWriterInfo.file_name, data);
421     fgets(line, MAX_LINE_LENGTH, fp);
422     key  = (char *)strtok(line, tokens);
423     data = (char *)strtok(NULL, tokens);
425     if(strlen(data) == 0)
426     {
427        return FALSE;
428     }
430     if(strcmp(key, START_ADDR) != 0)
431     {
432         return FALSE;
433     }
435     nandWriterInfo.startAddr = (uint32_t)atoi(data);
437     return TRUE;
440 /******************************************************************************
441  * Function:    find_file_length
442  ******************************************************************************/
443 static Bool
444 find_file_length
446     FILE*               fp
449     char        line[MAX_LINE_LENGTH];
450     char        *pEnd;
451     char        *ext;
452     uint32_t    data_len, write_addr;
454     memset(line, 0, MAX_LINE_LENGTH);
456     ext = strrchr(nandWriterInfo.file_name, '.');
457     if (ext && (strcmp(ext, ".dat") == 0))
458     {
459     fgets(line, MAX_LINE_LENGTH, fp);
461     /* Read the write address from the CCS header */
462     strtoul (line,&pEnd,16);
463     strtoul (pEnd,&pEnd,16);
464     write_addr = strtoul (pEnd,&pEnd,16);
465     strtoul (pEnd,&pEnd,16);
467     /* Read the data length */
468     data_len = (strtoul (pEnd,NULL,16)) * 4;
469     }
470     else
471     {
472         /* find the data length by seeking to the end and getting position */
473         fseek(fp, 0, SEEK_END);
474         data_len = ftell(fp);
475         fseek(fp, 0, SEEK_SET);
476     }
478     if (data_len > (nandWriterInfo.deviceTotalBytes - nandWriterInfo.startAddr))
479     {
480         printf ("The data file is too big to fit into the device.\n");
481         return FALSE;
482     }
484     nandWriterInfo.writeBytes = data_len;
485     if (write_addr != WRITE_DATA_ADDRESS)
486         write_addr = WRITE_DATA_ADDRESS;
487     nandWriterInfo.writeData  = (uint8_t *)write_addr;
488     nandWriterInfo.readData   = (uint8_t *)(write_addr + nandWriterInfo.deviceTotalBytes);
490     return TRUE;
493 /******************************************************************************
494  * Function:    main  
495  ******************************************************************************/
496 void main ()
498     FILE                    *fp;
499     platform_init_flags     init_flags;
500     platform_init_config    init_config;
501     PLATFORM_DEVICE_info    *p_device;
502     Bool                    ret;
503     uint32_t                rCount;
504     printf("NAND Writer Utility Version %s\n\n", version);
506     fp = fopen(input_file, "r");
507     if (fp == NULL)
508     {
509         printf("Error in opening %s input file\n", input_file);
510         return;
511     }
513     ret = parse_input_file(fp);
514     fclose (fp);
516     if (ret == FALSE)
517     {
518         printf("Error in parsing %s input file\n", input_file);
519         return;
520     }
522     /* Initialize main Platform lib */
523     memset(&init_config, 0, sizeof(platform_init_config));
524     memset(&init_flags, 1, sizeof(platform_init_flags));
525     if (platform_init(&init_flags, &init_config) != Platform_EOK)
526     {
527         printf ("Platform init failed!\n");
528         print_platform_errno();
529         return;
530     }
532     p_device = platform_device_open(PLATFORM_DEVID_NAND512R3A2D, 0);
533     if (p_device == NULL) 
534     {
535         printf ("NAND device open failed!\n");
536         print_platform_errno();
537         return;
538     }
539     nandWriterInfo.deviceTotalBytes = p_device->block_count * p_device->page_count * p_device->page_size;
540     nandWriterInfo.blockSizeBytes   = p_device->page_count * p_device->page_size;
542     if ((nandWriterInfo.startAddr % nandWriterInfo.blockSizeBytes) != 0)
543     {
544         printf ("The start programming address 0x%8x set in %s is not at the beginning of a block, block size = 0x%4x\n", 
545                 nandWriterInfo.startAddr, 
546                 nandWriterInfo.file_name,
547                 nandWriterInfo.blockSizeBytes);
548         return;
549     }
551     /* Open and find the length of the data file */
552     fp = fopen (nandWriterInfo.file_name, "rb");
553     if (fp == NULL)
554     {
555       printf ("Failed to open file %s\n", nandWriterInfo.file_name);
556       platform_device_close(p_device->handle);
557       return;
558     }
560     /* Parse the CCS format file */
561     ret = find_file_length(fp);
562     fclose (fp);
563     if (ret == FALSE)
564     {
565         printf("Error in parsing CCS file %s\n", nandWriterInfo.file_name);
566         platform_device_close(p_device->handle);
567         return;
568     }
569     
571     /* Write the flash, verify the results. On read back failure mark
572      * the block as bad and try rewriting again */
573     rCount = 0;
575     do  
576     {
577         if (flash_nand (p_device) == FALSE)
578         {
579             printf ("NAND write giving up\n");
580             return;
581         }
583         rCount += 1;
585     }  while ((flash_verify (p_device) == FALSE) && (rCount < 5));
587     
588     if (rCount >= 5) 
589     {
590         printf ("NAND write failed (maximum retries reached)\n");
591     }
592     else
593     {
594         printf ("NAND programming completed successfully\n");
595     }
597     platform_device_close(p_device->handle);
598     
599     return;