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.00";
52 /* The input file name is hard coded */
53 char *input_file = "nand_writer_input.txt";
55 /* Parameters defined in the input_file */
56 #define FILE_NAME "file_name"
57 #define START_ADDR "start_addr"
59 /* Memory address to store the write data */
60 #define WRITE_DATA_ADDRESS 0x80000000
62 /* NAND device specific definitions */
63 #define BAD_BLOCK_MARKER_VALUE 0xA5
65 /******************************************************************************
66 * Structure: NAND_WRITER_INFO_T
67 *
68 * NAND writer control data. This structure should be filled in
69 * by the user before running
70 ******************************************************************************/
71 #define MAX_LINE_LENGTH 40
72 typedef struct NAND_WRITER_INFO_tag
73 {
74 char file_name[MAX_LINE_LENGTH]; /* CCS format data file name */
75 uint32_t blockSizeBytes; /* The size of each sector */
76 uint32_t deviceTotalBytes; /* Total number of bytes available in the device */
77 uint32_t startAddr; /* Start address to write */
78 uint32_t writeBytes; /* Number of bytes to be written into the device */
79 uint8_t *writeData; /* Address to store the write data */
80 uint8_t *readData; /* Address to store the read data */
82 } NAND_WRITER_INFO_T;
84 NAND_WRITER_INFO_T nandWriterInfo;
86 /******************************************************************************
87 * Function: print_platform_errno
88 ******************************************************************************/
89 void
90 print_platform_errno
91 (
92 void
93 )
94 {
95 printf ("Returned platform error number is %d\n", platform_errno);
96 }
98 /******************************************************************************
99 * Function: checkBadBlockMark
100 *
101 * Checks for the bad block mark. Returns TRUE if a block is marked bad.
102 ******************************************************************************/
103 Bool
104 checkBadBlockMark
105 (
106 PLATFORM_DEVICE_info *p_device,
107 uint32_t block
108 )
109 {
110 if (p_device->bblist[block] != 0xff)
111 {
112 return TRUE;
113 }
114 else
115 {
116 return FALSE;
117 }
118 }
120 /******************************************************************************
121 * Function: markBlockBad
122 *
123 * Mark a block as bad. Byte 5 of the spare area data is
124 * written as 0xA5.
125 ******************************************************************************/
126 void
127 markBlockBad
128 (
129 PLATFORM_DEVICE_info *p_device,
130 uint32_t block
131 )
132 {
133 uint8_t *spare_data;
135 spare_data = malloc(p_device->spare_size);
136 if (spare_data == NULL)
137 {
138 printf ("Can not allocate spare_data memory!\n");
139 return;
140 }
142 platform_device_read_spare_data(p_device->handle, block, 0, spare_data);
144 /* Set all data bytes to 0xff, only set the user defined bad block mark value */
145 spare_data[p_device->bboffset] = BAD_BLOCK_MARKER_VALUE;
147 /* Write the data to page */
148 platform_device_write_spare_data(p_device->handle, block, 0, spare_data);
150 /* Save the user defined bad block mark in bblist */
151 p_device->bblist[block] = BAD_BLOCK_MARKER_VALUE;
153 free (spare_data);
154 }
156 /******************************************************************************
157 * Function: form_block
158 *
159 * Form a block of data to write to the NOR. The block is
160 * created as a byte stream from the 4 byte stream in which
161 * the MSB is always sent first.
162 ******************************************************************************/
163 void
164 formBlock
165 (
166 uint32_t *data,
167 uint32_t blockSize,
168 uint8_t *scratch
169 )
170 {
171 uint32_t i, j;
173 /* Convert the data to a byte stream */
174 for (i = j = 0; j < blockSize; i++, j+=4)
175 {
176 scratch[j+0] = (data[i] >> 24) & 0xff;
177 scratch[j+1] = (data[i] >> 16) & 0xff;
178 scratch[j+2] = (data[i] >> 8) & 0xff;
179 scratch[j+3] = (data[i] >> 0) & 0xff;
180 }
181 }
183 /******************************************************************************
184 * Function: flashNand
185 *
186 * Write the image to flash.
187 * Returns TRUE if the image is written successfully
188 * FALSE if the image write fails
189 ******************************************************************************/
190 Bool
191 flash_nand
192 (
193 PLATFORM_DEVICE_info *p_device
194 )
195 {
196 uint32_t wPos, wLen;
197 uint32_t block, start_block;
198 uint8_t *scrach_block;
200 scrach_block = malloc(nandWriterInfo.blockSizeBytes);
201 if (scrach_block == NULL)
202 {
203 printf ("Can not allocate scratch block memory!\n");
204 return (FALSE);
205 }
207 start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
209 /* Program the NAND */
210 for (block = start_block, wPos = 0; wPos < nandWriterInfo.writeBytes; block++, wPos += nandWriterInfo.blockSizeBytes)
211 {
212 while(checkBadBlockMark(p_device, block))
213 {
214 printf ("Bad block # %d detected, skipping block ... \n", block);
215 if (++block == p_device->block_count)
216 {
217 printf ("Flash failed: End of device reached\n");
218 free (scrach_block);
219 return (FALSE);
220 }
221 }
223 printf ("Flashing block %d (%d bytes of %d)\n", block, wPos, nandWriterInfo.writeBytes);
225 wLen = nandWriterInfo.blockSizeBytes;
226 if (nandWriterInfo.writeBytes - wPos < nandWriterInfo.blockSizeBytes)
227 {
228 wLen = nandWriterInfo.writeBytes - wPos;
229 }
231 formBlock((uint32_t *)(&nandWriterInfo.writeData[wPos]), nandWriterInfo.blockSizeBytes, scrach_block);
232 if (platform_device_write(p_device->handle,
233 block*nandWriterInfo.blockSizeBytes,
234 scrach_block,
235 wLen) != Platform_EOK)
236 {
237 printf ("platform_device_write block # %d failed!\n", block);
238 print_platform_errno();
239 free (scrach_block);
240 return (FALSE);
241 }
243 }
245 free (scrach_block);
246 return (TRUE);
247 }
249 /******************************************************************************
250 * Function: flashVerify
251 *
252 * Read back the data file that was just flashed. On errors mark the block as bad.
253 * Returns TRUE if the image verified correctly.
254 * FALSE if the image verification failed
255 ******************************************************************************/
256 Bool
257 flash_verify
258 (
259 PLATFORM_DEVICE_info *p_device
260 )
261 {
262 uint32_t rPos, rLen;
263 uint32_t i, j;
264 uint32_t block, start_block;
265 uint8_t *scrach_block;
266 uint32_t *read_data_w;
268 scrach_block = malloc(nandWriterInfo.blockSizeBytes);
269 if (scrach_block == NULL)
270 {
271 printf ("Can not allocate scratch block memory!\n");
272 return (FALSE);
273 }
275 start_block = nandWriterInfo.startAddr / nandWriterInfo.blockSizeBytes;
277 for (block = start_block, rPos = 0; rPos < nandWriterInfo.writeBytes; block++, rPos += nandWriterInfo.blockSizeBytes)
278 {
279 while(checkBadBlockMark(p_device, block))
280 {
281 printf ("Bad block # %d detected, skipping block ... \n", block);
282 if (++block == p_device->block_count)
283 {
284 printf ("Flash failed: End of device reached\n");
285 free (scrach_block);
286 return (FALSE);
287 }
288 }
291 printf ("Reading and verifying block %d (%d bytes of %d)\n", block, rPos, nandWriterInfo.writeBytes);
293 /* Read a block of data */
294 if(platform_device_read(p_device->handle,
295 block*nandWriterInfo.blockSizeBytes,
296 scrach_block,
297 nandWriterInfo.blockSizeBytes) != Platform_EOK)
298 {
299 printf ("Failure in reading block %d\n", block);
300 print_platform_errno();
301 if (platform_errno == PLATFORM_ERRNO_ECC_FAIL)
302 {
303 printf ("marking block %d as bad, re-flash attempted\n", block);
304 markBlockBad (p_device, block);
305 }
306 free (scrach_block);
307 return (FALSE);
308 }
310 /* Convert the packed data */
311 read_data_w = (uint32_t *)(&nandWriterInfo.readData[rPos]);
312 for (i = 0, j = 0; i < nandWriterInfo.blockSizeBytes; i += 4)
313 read_data_w[j++] = (scrach_block[i+0] << 24) | (scrach_block[i+1] << 16) | (scrach_block[i+2] << 8) | scrach_block[i+3];
315 rLen = nandWriterInfo.blockSizeBytes;
316 if (nandWriterInfo.writeBytes - rPos < nandWriterInfo.blockSizeBytes)
317 {
318 rLen = nandWriterInfo.writeBytes - rPos;
319 }
321 /* Compare the data read with data programmed */
322 for (i = rPos; i < rLen; i++)
323 {
324 if (nandWriterInfo.readData[i] != nandWriterInfo.writeData[i])
325 {
326 printf ("Failure in block %d, at byte %d, (at byte %d in the data file) expected 0x%08x, read 0x%08x\n",
327 block, i, rPos, nandWriterInfo.writeData[i], nandWriterInfo.readData[i]);
328 free (scrach_block);
329 return (FALSE);
330 }
331 }
333 }
335 free (scrach_block);
336 return (TRUE);
337 }
339 /******************************************************************************
340 * Function: parse_input_file
341 ******************************************************************************/
342 Bool
343 parse_input_file
344 (
345 FILE* fp
346 )
347 {
348 char line[MAX_LINE_LENGTH];
349 char tokens[] = " :=;\n";
350 char *key, *data;
352 memset(line, 0, MAX_LINE_LENGTH);
354 fgets(line, MAX_LINE_LENGTH, fp);
355 key = (char *)strtok(line, tokens);
356 data = (char *)strtok(NULL, tokens);
358 if(strlen(data) == 0)
359 {
360 return FALSE;
361 }
363 if(strcmp(key, FILE_NAME) != 0)
364 {
365 return FALSE;
366 }
368 strcpy (nandWriterInfo.file_name, data);
370 fgets(line, MAX_LINE_LENGTH, fp);
371 key = (char *)strtok(line, tokens);
372 data = (char *)strtok(NULL, tokens);
374 if(strlen(data) == 0)
375 {
376 return FALSE;
377 }
379 if(strcmp(key, START_ADDR) != 0)
380 {
381 return FALSE;
382 }
384 nandWriterInfo.startAddr = (uint32_t)atoi(data);
386 return TRUE;
387 }
389 /******************************************************************************
390 * Function: parse_ccs_file
391 ******************************************************************************/
392 Bool
393 parse_ccs_file
394 (
395 FILE* fp
396 )
397 {
398 char line[MAX_LINE_LENGTH];
399 char *pEnd;
400 uint32_t data_len, write_addr;
402 memset(line, 0, MAX_LINE_LENGTH);
404 fgets(line, MAX_LINE_LENGTH, fp);
406 /* Read the write address from the CCS header */
407 strtoul (line,&pEnd,16);
408 strtoul (pEnd,&pEnd,16);
409 write_addr = strtoul (pEnd,&pEnd,16);
410 strtoul (pEnd,&pEnd,16);
412 /* Read the data length */
413 data_len = (strtoul (pEnd,NULL,16)) * 4;
414 if (data_len > (nandWriterInfo.deviceTotalBytes - nandWriterInfo.startAddr))
415 {
416 printf ("The data file is too big to fit into the device.\n");
417 return FALSE;
418 }
420 nandWriterInfo.writeBytes = data_len;
421 if (write_addr != WRITE_DATA_ADDRESS)
422 write_addr = WRITE_DATA_ADDRESS;
423 nandWriterInfo.writeData = (uint8_t *)write_addr;
424 nandWriterInfo.readData = (uint8_t *)(write_addr + nandWriterInfo.deviceTotalBytes);
426 return TRUE;
427 }
429 /******************************************************************************
430 * Function: main
431 ******************************************************************************/
432 void main ()
433 {
434 FILE *fp;
435 platform_init_flags init_flags;
436 platform_init_config init_config;
437 PLATFORM_DEVICE_info *p_device;
438 Bool ret;
439 uint32_t rCount;
441 fp = fopen(input_file, "r");
442 if (fp == NULL)
443 {
444 printf("Error in opening %s input file\n", input_file);
445 return;
446 }
448 ret = parse_input_file(fp);
449 fclose (fp);
451 if (ret == FALSE)
452 {
453 printf("Error in parsing %s input file\n", input_file);
454 return;
455 }
457 /* Initialize main Platform lib */
458 memset(&init_config, 0, sizeof(platform_init_config));
459 memset(&init_flags, 1, sizeof(platform_init_flags));
460 if (platform_init(&init_flags, &init_config) != Platform_EOK)
461 {
462 printf ("Platform init failed!\n");
463 print_platform_errno();
464 return;
465 }
467 p_device = platform_device_open(PLATFORM_DEVID_NAND512R3A2D, 0);
468 if (p_device == NULL)
469 {
470 printf ("NAND device open failed!\n");
471 print_platform_errno();
472 return;
473 }
474 nandWriterInfo.deviceTotalBytes = p_device->block_count * p_device->page_count * p_device->page_size;
475 nandWriterInfo.blockSizeBytes = p_device->page_count * p_device->page_size;
477 if ((nandWriterInfo.startAddr % nandWriterInfo.blockSizeBytes) != 0)
478 {
479 printf ("The start programming address 0x%8x set in %s is not at the beginning of a block, block size = 0x%4x\n",
480 nandWriterInfo.startAddr,
481 nandWriterInfo.file_name,
482 nandWriterInfo.blockSizeBytes);
483 return;
484 }
486 /* Open and find the length of the data file */
487 fp = fopen (nandWriterInfo.file_name, "rb");
488 if (fp == NULL)
489 {
490 printf ("Failed to open file %s\n", nandWriterInfo.file_name);
491 platform_device_close(p_device->handle);
492 return;
493 }
495 /* Parse the CCS format file */
496 ret = parse_ccs_file(fp);
497 fclose (fp);
498 if (ret == FALSE)
499 {
500 printf("Error in parsing CCS file %s\n", nandWriterInfo.file_name);
501 platform_device_close(p_device->handle);
502 return;
503 }
506 /* Write the flash, verify the results. On read back failure mark
507 * the block as bad and try rewriting again */
508 rCount = 0;
510 do
511 {
512 if (flash_nand (p_device) == FALSE)
513 {
514 printf ("NAND write giving up\n");
515 break;
516 }
518 rCount += 1;
520 } while ((flash_verify (p_device) == FALSE) && (rCount < 5));
523 if (rCount >= 5)
524 {
525 printf ("NAND write failed (maximum retries reached)\n");
526 }
527 else
528 {
529 printf ("NAND programming completed successfully\n");
530 }
532 platform_device_close(p_device->handle);
534 return;
535 }