1 /*
2 *
3 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
38 /**************************************************************************************
39 * FILE PURPOSE: NAND writer for the IBL
40 **************************************************************************************
41 * FILE NAME: nandwriter.c
42 *
43 * DESCRIPTION: A simple nand writer used to program the flash with an image
44 * that the ibl can read.
45 *
46 * @file nandwriter.c
47 *
48 * @brief
49 * A simple nand writer
50 *
51 ***************************************************************************************/
52 #include "types.h"
53 #include "ibl.h"
54 #include "nandhwapi.h"
55 #include "ecc.h"
56 #include "pllapi.h"
57 #include "device_nb.h"
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <string.h>
63 /**
64 * @brief
65 * The input file name is hard coded
66 */
67 char *fileName = "c:\\flash.bin";
70 /**
71 * @brief
72 * NAND device configuration. This structure should be filled in
73 * by the user before running
74 */
75 typedef struct nandWriterInfo_s
76 {
77 uint32 busWidthBits; /**< 8 or 16 bit bus width */
78 uint32 pageSizeBytes; /**< The size of each page */
79 uint32 pageEccBytes; /**< Number of ecc bytes in each page */
80 uint32 pagesPerBlock; /**< The number of pages in each block */
81 uint32 totalBlocks; /**< The total number of blocks in a device */
83 uint32 addressBytes; /**< Number of bytes in the address */
84 bool lsbFirst; /**< Set to true if the LSB is output first, otherwise msb is first */
85 uint32 blockOffset; /**< Address bits which specify the block number */
86 uint32 pageOffset; /**< Address bits which specify the page number */
87 uint32 columnOffset; /**< Address bits which specify the column number */
89 uint8 resetCommand; /**< The command to reset the flash */
90 uint8 readCommandPre; /**< The read command sent before the address */
91 uint8 readCommandPost; /**< The read command sent after the address */
92 bool postCommand; /**< If TRUE the post command is sent */
94 } nandWriterInfo_t;
96 nandWriterInfo_t nandWriterInfo;
99 /**
100 * @brief
101 * Information used only for programming the flash
102 */
103 nandProgramInfo_t nandProgramInfo;
105 /**
106 * @brief
107 * System setup information
108 */
109 typedef struct sysSetup_s
110 {
111 Int32 pllPrediv;
112 Int32 pllMult;
113 Int32 pllPostdiv;
115 } sysSetup_t;
117 sysSetup_t sysSetup;
121 /**
122 * @brief
123 * Checks for the bad block mark. Returns TRUE if a block is marked bad
124 */
125 BOOL checkBadBlockMark (Int32 block)
126 {
127 uint8 data[4];
128 Int32 ret;
130 /* A block is marked bad if the first ECC byte on page 1 and page 0 of the block
131 * is not 0xff. These bytes will not be used for ECC checks */
132 ret = nandHwDriverReadBytes (block, 0, nandWriterInfo.pageSizeBytes, 1, &data[0]);
133 if (ret < 0) {
134 printf ("Fatal error in nandHwDriverReadBytes, exiting\n");
135 exit (-1);
136 }
138 ret = nandHwDriverReadBytes (block, 1, nandWriterInfo.pageSizeBytes, 1, &data[1]);
139 if (ret < 0) {
140 printf ("Fatal error in nandHwDriverReadBytes, exiting\n");
141 exit (-1);
142 }
144 /* Return TRUE if the block has been marked bad */
145 if ((data[0] != 0xff) || (data[1] != 0xff)) {
146 printf ("Block %d already marked bad, skipping\n", block);
147 return (TRUE);
148 }
151 /* Return FALSE if the block has not been marked bad */
152 return (FALSE);
154 }
156 /**
157 * @brief
158 * Mark a block as bad. Byte 0 for pages 0 and 1 of the ecc data (extra bytes) are
159 * written as non-zero. Both pages are programmed
160 */
161 void markBlockBad (Int32 block, Uint8 *pageData)
162 {
164 /* Set all data bytes to 0xff, only zero the bad block marks */
165 memset (pageData, 0xff, ((nandWriterInfo.pageSizeBytes + nandWriterInfo.pageEccBytes) * sizeof (Uint8)));
166 pageData[nandWriterInfo.pageSizeBytes] = 0;
168 /* Write the data to pages 0 and 1 */
169 nandHwDriverWritePage (block, 0, pageData, &nandProgramInfo);
170 nandHwDriverWritePage (block, 1, pageData, &nandProgramInfo);
171 }
174 int flashNand (FILE *fp, Uint32 flen, Uint8 *data)
175 {
176 Uint32 fpos;
177 Uint32 rlen;
178 Int32 block;
179 Int32 page;
180 Int32 ret;
181 Int32 i, j;
183 Int32 eccsPerPage; /* Number of 256 bytes ecc sections in a page */
185 Uint8 *eccBytes; /* Points to the generated ECC data */
187 /* Reset to the start of the data file */
188 fseek (fp, 0l, SEEK_SET);
190 eccsPerPage = nandWriterInfo.pageSizeBytes / eccBytesPerBlock ();
193 /* Program the NAND */
194 for (block = -1, page = nandWriterInfo.pagesPerBlock, fpos = 0; fpos < flen; fpos += nandWriterInfo.pageSizeBytes) {
196 /* Advance over a block boundary. Verify block limit and bad block mark */
197 if (++page >= nandWriterInfo.pagesPerBlock) {
199 do {
201 block += 1;
203 } while ((block < nandWriterInfo.totalBlocks) && (checkBadBlockMark (block) == TRUE));
205 nandHwDriverBlockErase (block, &nandProgramInfo);
207 page = 0;
208 }
210 if (block >= nandWriterInfo.totalBlocks) {
211 printf ("Flash failed: End of device reached\n");
212 free (data);
213 fclose (fp);
214 return (-1);
215 }
217 /* Initialize the entire page (with ecc bytes) to 0xff. This will preserve the good block
218 * mark at the beginning of pages 0 and 1 */
219 memset (data, 0xff, ((nandWriterInfo.pageSizeBytes + nandWriterInfo.pageEccBytes) * sizeof (Uint8)));
222 /* Read the data from the file */
223 rlen = nandWriterInfo.pageSizeBytes;
224 if (flen - fpos < nandWriterInfo.pageSizeBytes) {
225 rlen = flen - fpos;
226 }
228 if (fread (data, sizeof (Uint8), rlen, fp) == 0) {
229 printf ("fread unexpectedly returned 0 on read of %d bytes staring at byte location %d.\n", rlen, fpos);
230 printf (" Total file length = %d bytes\n", flen);
231 free (data);
232 fclose (fp);
233 return (-1);
234 }
236 /* The page is broken into 256 byte blocks, each has its own ecc data */
237 for (i = 0; i < eccsPerPage; i++) {
239 /* The eccs values are at the end of the page. The very last bytes correspond
240 * to the very last block */
241 j = (eccsPerPage - i) * eccNumBytes ();
243 eccBytes = &data[nandWriterInfo.pageSizeBytes + nandWriterInfo.pageEccBytes - j];
244 eccComputeECC (&data[i * eccBytesPerBlock()], eccBytes);
246 }
249 printf ("Flashing block %d, page %d (%d bytes of %d)\n", block, page, fpos, flen);
251 ret = nandHwDriverWritePage (block, page, data, &nandProgramInfo);
252 if (ret < 0) {
253 printf ("nandHwWritePage returned error code %d writing block %d, page %d\n", ret, block, page);
254 free (data);
255 fclose (fp);
256 return (-1);
257 }
259 }
262 return (0);
264 }
267 /**
268 * @brief
269 * Read back the data file that was just flashed. On errors mark the block as bad.
270 * Returns TRUE if the image verified correctly.
271 * FALSE if the image verification failed
272 */
274 BOOL flashVerify (FILE *fp, Uint32 flen, Uint8 *data)
275 {
276 Uint8 *nandData;
277 Int32 block;
278 Int32 page;
279 Int32 fpos;
280 Int32 ret;
281 Int32 rlen;
282 Int32 i;
285 nandData = malloc ((nandWriterInfo.pageSizeBytes + nandWriterInfo.pageEccBytes) * sizeof (Uint8));
286 if (nandData == NULL) {
287 printf ("Malloc failed on verification data block of %d bytes\n", nandWriterInfo.pageSizeBytes + nandWriterInfo.pageEccBytes);
288 return (TRUE); /* return true so the program gives up */
289 }
292 /* Reset to the start of the data file */
293 fseek (fp, 0l, SEEK_SET);
296 for (block = -1, page = nandWriterInfo.pagesPerBlock, fpos = 0; fpos < flen; fpos += nandWriterInfo.pageSizeBytes) {
298 /* Advance over a block boundary. Verify block limit and bad block mark */
299 if (++page >= nandWriterInfo.pagesPerBlock) {
301 do {
303 block += 1;
305 } while ((block < nandWriterInfo.totalBlocks) && (checkBadBlockMark (block) == TRUE));
307 page = 0;
308 }
310 if (block >= nandWriterInfo.totalBlocks) {
311 printf ("Verify failed: End of flash device reached\n");
312 free (nandData);
313 return (TRUE); /* Return TRUE to allow the program to exit */
314 }
317 /* Read a page of data */
318 ret = nandHwDriverReadPage (block, page, nandData);
319 if (ret < 0) {
320 printf ("nandHwDriverReadPage returned error code %d\n", ret);
321 free (nandData);
322 return (TRUE); /* return TRUE to allow the program to exit */
323 }
325 /* Read the data from the file */
326 rlen = nandWriterInfo.pageSizeBytes;
327 if (flen - fpos < nandWriterInfo.pageSizeBytes) {
328 rlen = flen - fpos;
329 }
331 if (fread (data, sizeof (Uint8), rlen, fp) == 0) {
332 printf ("fread unexpectedly returned 0 on read of %d bytes staring at byte location %d.\n", rlen, fpos);
333 printf (" Total file length = %d bytes\n", flen);
334 free (nandData);
335 return (TRUE);
336 }
338 printf ("Verifying block %d, page %d (%d bytes of %d)\n", block, page, fpos, flen);
340 for (i = 0; i < rlen; i++) {
341 if (data[i] != nandData[i]) {
342 printf ("Failure in block %d, page %d, at byte %d, (at byte %d in the data file) expected 0x%08x, read 0x%08x\n", block, page, i, fpos, data[i], nandData[i]);
343 printf ("marking block %d as bad, re-flash attempted\n");
344 markBlockBad (block, nandData);
345 free (nandData);
346 return (FALSE);
347 }
348 }
350 }
352 free (nandData);
353 return (TRUE);
355 }
358 /**
359 * @brief
360 * The nandDevInfo structure is a subset of the nandWriteInfo, and is seperated
361 * here to use the existing ibl functions for the writer
362 */
363 nandDevInfo_t devInfo;
366 int main (void)
367 {
368 Uint8 *data;
369 FILE *fp;
370 Uint32 flen;
371 Int32 ret;
372 Int32 rCount;
375 /* Configure the main pll */
376 hwPllSetPll (0, (uint16)sysSetup.pllPrediv, (uint16)sysSetup.pllMult, (uint16)sysSetup.pllPostdiv);
379 /* Initialize the nand driver */
380 devInfo.busWidthBits = nandWriterInfo.busWidthBits;
381 devInfo.pageSizeBytes = nandWriterInfo.pageSizeBytes;
382 devInfo.pageEccBytes = nandWriterInfo.pageEccBytes;
383 devInfo.pagesPerBlock = nandWriterInfo.pagesPerBlock;
384 devInfo.totalBlocks = nandWriterInfo.totalBlocks;
386 devInfo.addressBytes = nandWriterInfo.addressBytes;
387 devInfo.lsbFirst = nandWriterInfo.lsbFirst;
388 devInfo.blockOffset = nandWriterInfo.blockOffset;
389 devInfo.pageOffset = nandWriterInfo.pageOffset;
390 devInfo.columnOffset = nandWriterInfo.columnOffset;
392 devInfo.resetCommand = nandWriterInfo.resetCommand;
393 devInfo.readCommandPre = nandWriterInfo.readCommandPre;
394 devInfo.readCommandPost = nandWriterInfo.readCommandPost;
395 devInfo.postCommand = nandWriterInfo.postCommand;
399 /* Open and find the length of the data file */
400 fp = fopen (fileName, "rb");
401 if (fp == NULL) {
402 printf ("Failed to open file %s\n", fileName);
403 return (-1);
404 }
406 fseek (fp, 0l, SEEK_END);
407 flen = ftell (fp);
408 fseek (fp, 0l, SEEK_SET);
410 data = malloc ((nandWriterInfo.pageSizeBytes + nandWriterInfo.pageEccBytes) * sizeof (Uint8));
411 if (data == NULL) {
412 printf ("Malloc failed on size of %d bytes\n", nandWriterInfo.pageSizeBytes + nandWriterInfo.pageEccBytes);
413 fclose (fp);
414 return (-1);
415 }
418 /* Device specific nand setup */
419 deviceConfigureForNand();
421 /* Initialize the programming interface */
422 ret = nandHwEmifDriverInit (&devInfo);
423 if (ret != 0) {
424 printf ("nandHwDriverInit failed with error code %d\n", ret);
425 free (data);
426 fclose (fp);
427 return (-1);
428 }
430 /* Write the flash, verify the results. On read back failure mark
431 * the block as bad and try rewriting again */
432 rCount = 0;
434 do {
436 if (flashNand (fp, flen, data) != 0) {
437 printf ("nand write giving up\n");
438 break;
439 }
441 rCount += 1;
443 } while ((flashVerify (fp, flen, data) == FALSE) && (rCount < 5));
446 if (rCount >= 5)
447 printf ("nand write failed (maximum retries reached)\n");
448 else
449 printf ("flash programming completed\n");
451 free (data);
452 fclose (fp);
453 return (0);
455 }