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)
100 {
101 /* Free up the memory */
102 if (dataPtr)
103 {
104 free(dataPtr);
105 }
106 }
108 void Osal_platformSpiCsEnter(void)
109 {
110 return;
111 }
113 void Osal_platformSpiCsExit (void)
114 {
115 return;
116 }
118 /******************************************************************************
119 * Function: print_platform_errno
120 ******************************************************************************/
121 void
122 print_platform_errno
123 (
124 void
125 )
126 {
127 printf ("Returned platform error number is %d\n", platform_errno);
128 }
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
137 (
138 PLATFORM_DEVICE_info *p_device,
139 uint32_t block
140 )
141 {
142 if (p_device->bblist[block] != 0xff)
143 {
144 return TRUE;
145 }
146 else
147 {
148 return FALSE;
149 }
150 }
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
160 (
161 PLATFORM_DEVICE_info *p_device,
162 uint32_t block
163 )
164 {
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);
186 }
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
197 (
198 uint32_t *data,
199 uint32_t blockSize,
200 uint8_t *scratch
201 )
202 {
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 }
213 }
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
224 (
225 PLATFORM_DEVICE_info *p_device
226 )
227 {
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
328 (
329 PLATFORM_DEVICE_info *p_device
330 )
331 {
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);
419 }
421 /******************************************************************************
422 * Function: parse_input_file
423 ******************************************************************************/
424 static Bool
425 parse_input_file
426 (
427 FILE* fp
428 )
429 {
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);
468 fgets(line, MAX_LINE_LENGTH, fp);
469 key = (char *)strtok(line, tokens);
470 data = (char *)strtok(NULL, tokens);
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;
496 }
498 /******************************************************************************
499 * Function: find_file_length
500 ******************************************************************************/
501 static Bool
502 find_file_length
503 (
504 FILE* fp
505 )
506 {
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;
549 }
551 static Bool
552 nand_erase_all_blks(PLATFORM_DEVICE_info *p_device)
553 {
554 uint32_t block;
555 uint32_t max_blks;
557 max_blks = p_device->block_count;
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);
568 }
570 /******************************************************************************
571 * Function: main
572 ******************************************************************************/
573 void main ()
574 {
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 }
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));
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);
703 return;
704 }