1 /******************************************************************************
2 * Copyright (c) 2011-2012 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.00";
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 }
101 }
103 void Osal_platformSpiCsEnter(void)
104 {
105 return;
106 }
108 void Osal_platformSpiCsExit (void)
109 {
110 return;
111 }
113 /******************************************************************************
114 * Function: print_platform_errno
115 ******************************************************************************/
116 void
117 print_platform_errno
118 (
119 void
120 )
121 {
122 printf ("Returned platform error number is %d\n", platform_errno);
123 }
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
132 (
133 PLATFORM_DEVICE_info *p_device,
134 uint32_t block
135 )
136 {
137 if (p_device->bblist[block] != 0xff)
138 {
139 return TRUE;
140 }
141 else
142 {
143 return FALSE;
144 }
145 }
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
155 (
156 PLATFORM_DEVICE_info *p_device,
157 uint32_t block
158 )
159 {
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);
181 }
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
192 (
193 uint32_t *data,
194 uint32_t blockSize,
195 uint8_t *scratch
196 )
197 {
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 }
208 }
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
219 (
220 PLATFORM_DEVICE_info *p_device
221 )
222 {
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
297 (
298 PLATFORM_DEVICE_info *p_device
299 )
300 {
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);
388 }
390 /******************************************************************************
391 * Function: parse_input_file
392 ******************************************************************************/
393 static Bool
394 parse_input_file
395 (
396 FILE* fp
397 )
398 {
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;
438 }
440 /******************************************************************************
441 * Function: find_file_length
442 ******************************************************************************/
443 static Bool
444 find_file_length
445 (
446 FILE* fp
447 )
448 {
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;
491 }
493 /******************************************************************************
494 * Function: main
495 ******************************************************************************/
496 void main ()
497 {
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 init_flags.pll = 0;
526 init_flags.ddr = 0;
527 if (platform_init(&init_flags, &init_config) != Platform_EOK)
528 {
529 printf ("Platform init failed!\n");
530 print_platform_errno();
531 return;
532 }
533 #if !(defined(_EVMC6657L_))
534 p_device = platform_device_open(PLATFORM_DEVID_NAND512R3A2D, 0);
535 #else
536 p_device = platform_device_open(PLATFORM_DEVID_MT29F1G08ABCHC, 0);
537 #endif
538 if (p_device == NULL)
539 {
540 printf ("NAND device open failed!\n");
541 print_platform_errno();
542 return;
543 }
544 nandWriterInfo.deviceTotalBytes = p_device->block_count * p_device->page_count * p_device->page_size;
545 nandWriterInfo.blockSizeBytes = p_device->page_count * p_device->page_size;
547 if ((nandWriterInfo.startAddr % nandWriterInfo.blockSizeBytes) != 0)
548 {
549 printf ("The start programming address 0x%8x set in %s is not at the beginning of a block, block size = 0x%4x\n",
550 nandWriterInfo.startAddr,
551 nandWriterInfo.file_name,
552 nandWriterInfo.blockSizeBytes);
553 return;
554 }
556 /* Open and find the length of the data file */
557 fp = fopen (nandWriterInfo.file_name, "rb");
558 if (fp == NULL)
559 {
560 printf ("Failed to open file %s\n", nandWriterInfo.file_name);
561 platform_device_close(p_device->handle);
562 return;
563 }
565 /* Parse the CCS format file */
566 ret = find_file_length(fp);
567 fclose (fp);
568 if (ret == FALSE)
569 {
570 printf("Error in parsing CCS file %s\n", nandWriterInfo.file_name);
571 platform_device_close(p_device->handle);
572 return;
573 }
576 /* Write the flash, verify the results. On read back failure mark
577 * the block as bad and try rewriting again */
578 rCount = 0;
580 do
581 {
582 if (flash_nand (p_device) == FALSE)
583 {
584 printf ("NAND write giving up\n");
585 return;
586 }
588 rCount += 1;
590 } while ((flash_verify (p_device) == FALSE) && (rCount < 5));
593 if (rCount >= 5)
594 {
595 printf ("NAND write failed (maximum retries reached)\n");
596 }
597 else
598 {
599 printf ("NAND programming completed successfully\n");
600 }
602 platform_device_close(p_device->handle);
604 return;
605 }