Added platform osal malloc and free functions
[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 /* 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 /******************************************************************************
104  * Function:    print_platform_errno
105  ******************************************************************************/
106 void
107 print_platform_errno
109     void
112     printf ("Returned platform error number is %d\n", platform_errno);
115 /******************************************************************************
116  * Function:    checkBadBlockMark
117  *
118  *              Checks for the bad block mark. Returns TRUE if a block is marked bad.
119  ******************************************************************************/
120 Bool
121 checkBadBlockMark 
123     PLATFORM_DEVICE_info    *p_device,
124     uint32_t                  block
127     if (p_device->bblist[block] != 0xff)
128     {
129         return TRUE;
130     }
131     else
132     {
133         return FALSE;
134     }
137 /******************************************************************************
138  * Function:    markBlockBad
139  *
140  *              Mark a block as bad. Byte 5 of the spare area data is
141  *              written as 0xA5.
142  ******************************************************************************/
143 void 
144 markBlockBad 
146     PLATFORM_DEVICE_info        *p_device,
147     uint32_t                    block
150     uint8_t       *spare_data;
152     spare_data = malloc(p_device->spare_size);
153     if (spare_data == NULL)
154     {
155         printf ("Can not allocate spare_data memory!\n");
156         return;
157     }
159     platform_device_read_spare_data(p_device->handle, block, 0, spare_data);
161     /* Set all data bytes to 0xff, only set the user defined bad block mark value */
162     spare_data[p_device->bboffset] = BAD_BLOCK_MARKER_VALUE;
164     /* Write the data to page */
165     platform_device_write_spare_data(p_device->handle, block, 0, spare_data);
167     /* Save the user defined bad block mark in bblist */
168     p_device->bblist[block] = BAD_BLOCK_MARKER_VALUE;
170     free (spare_data);
173 /******************************************************************************
174  * Function:    form_block
175  *
176  *      Form a block of data to write to the NOR. The block is
177  *      created as a byte stream from the 4 byte stream in which
178  *      the MSB is always sent first.
179  ******************************************************************************/
180 void
181 formBlock
183     uint32_t      *data,
184     uint32_t      blockSize,
185     uint8_t       *scratch
188     uint32_t i, j;
190     /* Convert the data to a byte stream */
191     for (i = j = 0; j < blockSize; i++, j+=4)
192     {
193         scratch[j+0] = (data[i] >> 24) & 0xff;
194         scratch[j+1] = (data[i] >> 16) & 0xff;
195         scratch[j+2] = (data[i] >>  8) & 0xff;
196         scratch[j+3] = (data[i] >>  0) & 0xff;
197     }
200 /******************************************************************************
201  * Function:    flashNand
202  *
203  *              Write the image to flash.
204  *              Returns TRUE if the image is written successfully
205  *                      FALSE if the image write fails
206  ******************************************************************************/
207 Bool 
208 flash_nand
210     PLATFORM_DEVICE_info    *p_device
213     uint32_t      wPos, wLen;
214     uint32_t      block, start_block;
215     uint8_t       *scrach_block;
217     if (swap_byte)
218     {
219         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
220         if (scrach_block == NULL)
221         {
222             printf ("Can not allocate scratch block memory!\n");
223             return (FALSE);
224         }
225     }
227     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
229     /* Program the NAND */
230     for (block = start_block, wPos = 0; wPos < nandWriterInfo.writeBytes; block++, wPos += nandWriterInfo.blockSizeBytes)
231     {
232         while(checkBadBlockMark(p_device, block))
233         {
234             printf ("Bad block # %d detected, skipping block ... \n", block);
235             if (++block == p_device->block_count)
236             {
237                 printf ("Flash failed: End of device reached\n");
238                 if (swap_byte) free (scrach_block);
239                 return (FALSE);        
240             }
241         }
243         printf ("Flashing block %d (%d bytes of %d)\n", block, wPos, nandWriterInfo.writeBytes);
245         platform_device_erase_block(p_device->handle, block);
247         wLen = nandWriterInfo.blockSizeBytes;
248         if (nandWriterInfo.writeBytes - wPos < nandWriterInfo.blockSizeBytes)
249         {
250             wLen = nandWriterInfo.writeBytes - wPos;
251         }
253         if (swap_byte)
254         {
255             formBlock((uint32_t *)(&nandWriterInfo.writeData[wPos]), nandWriterInfo.blockSizeBytes, scrach_block);
256         }
257         else
258         {
259             scrach_block = &nandWriterInfo.writeData[wPos];
260         }
261         if (platform_device_write(p_device->handle, 
262                                   block*nandWriterInfo.blockSizeBytes, 
263                                   scrach_block, 
264                                   wLen) != Platform_EOK)
265         {
266             printf ("platform_device_write block # %d failed!\n", block);
267             print_platform_errno();
268             if (swap_byte) free (scrach_block);
269             return (FALSE);
270         }
272     }
274     if (swap_byte) free (scrach_block);
275     return (TRUE);
276 }    
278 /******************************************************************************
279  * Function:    flashVerify
280  *
281  *              Read back the data file that was just flashed. On errors mark the block as bad.
282  *              Returns TRUE if the image verified correctly.
283  *                      FALSE if the image verification failed
284  ******************************************************************************/
285 Bool 
286 flash_verify
288     PLATFORM_DEVICE_info    *p_device
291     uint32_t      rPos, rLen;
292     uint32_t      i, j;
293     uint32_t      block, start_block;
294     uint8_t       *scrach_block;
295     uint32_t      *read_data_w;
297     if (swap_byte) 
298     {
299         scrach_block = malloc(nandWriterInfo.blockSizeBytes);
300         if (scrach_block == NULL)
301         {
302             printf ("Can not allocate scratch block memory!\n");
303             return (FALSE);
304         }
305     }
307     start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
309     for (block = start_block, rPos = 0; rPos < nandWriterInfo.writeBytes; block++, rPos += nandWriterInfo.blockSizeBytes)
310     {
311         while(checkBadBlockMark(p_device, block))
312         {
313             printf ("Bad block # %d detected, skipping block ... \n", block);
314             if (++block == p_device->block_count)
315             {
316                 printf ("Flash failed: End of device reached\n");
317                 if (swap_byte) free (scrach_block);
318                 return (FALSE);        
319             }
320         }
323         printf ("Reading and verifying block %d (%d bytes of %d)\n", block, rPos, nandWriterInfo.writeBytes);
325         if (!swap_byte)
326         {
327             scrach_block = &nandWriterInfo.readData[rPos];
329         }
331         /* Read a block of data */
332         if(platform_device_read(p_device->handle, 
333                                 block*nandWriterInfo.blockSizeBytes, 
334                                 scrach_block,
335                                 nandWriterInfo.blockSizeBytes) != Platform_EOK)
336         {
337             printf ("Failure in reading block %d\n", block);
338             print_platform_errno();
339             if (platform_errno == PLATFORM_ERRNO_ECC_FAIL)
340             {
341                 printf ("marking block %d as bad, re-flash attempted\n", block);
342                 markBlockBad (p_device, block);
343             }
344             if (swap_byte) free (scrach_block);
345             return (FALSE);
346         }
348         /* Convert the packed data */
349         if (swap_byte)
350         {
351             read_data_w = (uint32_t *)(&nandWriterInfo.readData[rPos]);
352             for  (i = 0, j = 0; i < nandWriterInfo.blockSizeBytes; i += 4)
353                 read_data_w[j++] = (scrach_block[i+0] << 24) | (scrach_block[i+1] << 16) | (scrach_block[i+2] << 8) | scrach_block[i+3];
354         }
356         rLen = nandWriterInfo.blockSizeBytes;
357         if (nandWriterInfo.writeBytes - rPos < nandWriterInfo.blockSizeBytes)
358         {
359             rLen = nandWriterInfo.writeBytes - rPos;
360         }
362         /* Compare the data read with data programmed */
363         for (i = rPos; i < rLen; i++)
364         {
365             if (nandWriterInfo.readData[i] != nandWriterInfo.writeData[i])
366             {
367                 printf ("Failure in block %d, at byte %d, (at byte %d in the data file) expected 0x%08x, read 0x%08x\n", 
368                         block, i, rPos, nandWriterInfo.writeData[i], nandWriterInfo.readData[i]);
369                 if (swap_byte) free (scrach_block);
370                 return (FALSE);
371             }
372         }
374     }
376     if (swap_byte) free (scrach_block);
377     return (TRUE);
380 /******************************************************************************
381  * Function:    parse_input_file  
382  ******************************************************************************/
383 static Bool
384 parse_input_file
386     FILE*               fp
389     char line[MAX_LINE_LENGTH];
390     char tokens[] = " :=;\n";
391     char *key, *data;
393     memset(line, 0, MAX_LINE_LENGTH);
395     fgets(line, MAX_LINE_LENGTH, fp);
396     key  = (char *)strtok(line, tokens);
397     data = (char *)strtok(NULL, tokens);
399     if(strlen(data) == 0)
400     {
401        return FALSE;
402     }
404     if(strcmp(key, FILE_NAME) != 0)
405     {
406         return FALSE;
407     }
409     strcpy (nandWriterInfo.file_name, data);
411     fgets(line, MAX_LINE_LENGTH, fp);
412     key  = (char *)strtok(line, tokens);
413     data = (char *)strtok(NULL, tokens);
415     if(strlen(data) == 0)
416     {
417        return FALSE;
418     }
420     if(strcmp(key, START_ADDR) != 0)
421     {
422         return FALSE;
423     }
425     nandWriterInfo.startAddr = (uint32_t)atoi(data);
427     return TRUE;
430 /******************************************************************************
431  * Function:    find_file_length
432  ******************************************************************************/
433 static Bool
434 find_file_length
436     FILE*               fp
439     char        line[MAX_LINE_LENGTH];
440     char        *pEnd;
441     char        *ext;
442     uint32_t    data_len, write_addr;
444     memset(line, 0, MAX_LINE_LENGTH);
446     ext = strrchr(nandWriterInfo.file_name, '.');
447     if (ext && (strcmp(ext, ".dat") == 0))
448     {
449     fgets(line, MAX_LINE_LENGTH, fp);
451     /* Read the write address from the CCS header */
452     strtoul (line,&pEnd,16);
453     strtoul (pEnd,&pEnd,16);
454     write_addr = strtoul (pEnd,&pEnd,16);
455     strtoul (pEnd,&pEnd,16);
457     /* Read the data length */
458     data_len = (strtoul (pEnd,NULL,16)) * 4;
459     }
460     else
461     {
462         /* find the data length by seeking to the end and getting position */
463         fseek(fp, 0, SEEK_END);
464         data_len = ftell(fp);
465         fseek(fp, 0, SEEK_SET);
466     }
468     if (data_len > (nandWriterInfo.deviceTotalBytes - nandWriterInfo.startAddr))
469     {
470         printf ("The data file is too big to fit into the device.\n");
471         return FALSE;
472     }
474     nandWriterInfo.writeBytes = data_len;
475     if (write_addr != WRITE_DATA_ADDRESS)
476         write_addr = WRITE_DATA_ADDRESS;
477     nandWriterInfo.writeData  = (uint8_t *)write_addr;
478     nandWriterInfo.readData   = (uint8_t *)(write_addr + nandWriterInfo.deviceTotalBytes);
480     return TRUE;
483 /******************************************************************************
484  * Function:    main  
485  ******************************************************************************/
486 void main ()
488     FILE                    *fp;
489     platform_init_flags     init_flags;
490     platform_init_config    init_config;
491     PLATFORM_DEVICE_info    *p_device;
492     Bool                    ret;
493     uint32_t                rCount;
494     printf("NAND Writer Utility Version %s\n\n", version);
496     fp = fopen(input_file, "r");
497     if (fp == NULL)
498     {
499         printf("Error in opening %s input file\n", input_file);
500         return;
501     }
503     ret = parse_input_file(fp);
504     fclose (fp);
506     if (ret == FALSE)
507     {
508         printf("Error in parsing %s input file\n", input_file);
509         return;
510     }
512     /* Initialize main Platform lib */
513     memset(&init_config, 0, sizeof(platform_init_config));
514     memset(&init_flags, 1, sizeof(platform_init_flags));
515     if (platform_init(&init_flags, &init_config) != Platform_EOK)
516     {
517         printf ("Platform init failed!\n");
518         print_platform_errno();
519         return;
520     }
522     p_device = platform_device_open(PLATFORM_DEVID_NAND512R3A2D, 0);
523     if (p_device == NULL) 
524     {
525         printf ("NAND device open failed!\n");
526         print_platform_errno();
527         return;
528     }
529     nandWriterInfo.deviceTotalBytes = p_device->block_count * p_device->page_count * p_device->page_size;
530     nandWriterInfo.blockSizeBytes   = p_device->page_count * p_device->page_size;
532     if ((nandWriterInfo.startAddr % nandWriterInfo.blockSizeBytes) != 0)
533     {
534         printf ("The start programming address 0x%8x set in %s is not at the beginning of a block, block size = 0x%4x\n", 
535                 nandWriterInfo.startAddr, 
536                 nandWriterInfo.file_name,
537                 nandWriterInfo.blockSizeBytes);
538         return;
539     }
541     /* Open and find the length of the data file */
542     fp = fopen (nandWriterInfo.file_name, "rb");
543     if (fp == NULL)
544     {
545       printf ("Failed to open file %s\n", nandWriterInfo.file_name);
546       platform_device_close(p_device->handle);
547       return;
548     }
550     /* Parse the CCS format file */
551     ret = find_file_length(fp);
552     fclose (fp);
553     if (ret == FALSE)
554     {
555         printf("Error in parsing CCS file %s\n", nandWriterInfo.file_name);
556         platform_device_close(p_device->handle);
557         return;
558     }
559     
561     /* Write the flash, verify the results. On read back failure mark
562      * the block as bad and try rewriting again */
563     rCount = 0;
565     do  
566     {
567         if (flash_nand (p_device) == FALSE)
568         {
569             printf ("NAND write giving up\n");
570             return;
571         }
573         rCount += 1;
575     }  while ((flash_verify (p_device) == FALSE) && (rCount < 5));
577     
578     if (rCount >= 5) 
579     {
580         printf ("NAND write failed (maximum retries reached)\n");
581     }
582     else
583     {
584         printf ("NAND programming completed successfully\n");
585     }
587     platform_device_close(p_device->handle);
588     
589     return;