25e8a0c12b7edd8825654989ab3b8b0495bbc36b
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: The top level NAND driver
40 ************************************************************************************************
41 * FILE NAME: nand.c
42 *
43 * DESCRIPTION: Provides the required driver functions which populate the BOOT_MODULE_FXN_TABLE
44 *
45 * @file nand.c
46 *
47 * @brief
48 * The top level nand driver
49 *
50 *************************************************************************************************/
51 #include "types.h"
52 #include "ibl.h"
53 #include "iblloc.h"
54 #include "nand.h"
55 #include "nandhwapi.h"
56 #include <string.h>
57 #include <stdlib.h>
60 /**
61 * @brief The nand master control block which tracks the current nand boot information
62 */
63 typedef struct nandmcb_s
64 {
65 nandDevInfo_t devInfo; /**< Device information */
67 Int32 fpos; /**< The current logical file position */
68 Uint32 currentLogicalBlock; /**< The logical block number of the page currently stored */
69 Uint32 currentPage; /**< The page number currently stored */
71 Uint8 *page; /**< The current page */
72 Uint16 *logicalToPhysMap; /**< Maps local block to physical block */
73 Uint16 *physToLogicalMap; /**< Maps a physical block number to a logical block number */
75 Uint32 numBadBlocks; /**< Total number of bad blocks */
76 Uint8 *blocks; /**< There is one byte per block. A non-zero value indicates
77 that the block is bad */
79 } nandmcb_t;
81 nandmcb_t nandmcb;
84 /**
85 * @b Description
86 * @n
87 *
88 * This function sets the current file position, and loads the page corresponding
89 * to that position into the pre-allocated page memory
90 */
91 Int32 nand_seek (Int32 loc, Int32 from)
92 {
93 Int32 desiredPos;
94 Uint32 desiredBlock;
95 Uint32 desiredPage;
97 /* Can't seek from the end of the file, since the end is not known */
98 if (from == 0)
99 desiredPos = loc;
100 else if (from == 1)
101 desiredPos = nandmcb.fpos + loc;
102 else
103 return (-1);
105 if (desiredPos < 0)
106 return (-1);
109 /* Convert the file position (relative to the file start) into a page number */
110 desiredPage = desiredPos / nandmcb.devInfo.pageSizeBytes;
112 /* Convert the logical page to logical block/page */
113 desiredBlock = desiredPage / nandmcb.devInfo.pagesPerBlock;
114 desiredPage = desiredPage % nandmcb.devInfo.pagesPerBlock;
116 /* Update the current position */
117 nandmcb.fpos = desiredPos;
119 /* Nothing to do if the current block/page is already loaded */
120 if ((desiredBlock == nandmcb.currentLogicalBlock) && (desiredPage == nandmcb.currentPage))
121 return (0);
123 /* Otherwise load the desired page */
124 if (nandHwDriverReadPage((Uint32)(nandmcb.logicalToPhysMap[desiredBlock]), desiredPage, nandmcb.page) < 0)
125 return (-2);
127 /* Update the currently loaded block/page info */
128 nandmcb.currentLogicalBlock = desiredBlock;
129 nandmcb.currentPage = desiredPage;
131 return (0);
133 }
136 /**
137 * @b Description
138 * @n
139 * Free any memory allocated by the driver
140 */
141 Int32 nand_free_return (Int32 retcode)
142 {
143 if (nandmcb.page != NULL)
144 iblFree (nandmcb.page);
146 if (nandmcb.logicalToPhysMap != NULL)
147 iblFree (nandmcb.logicalToPhysMap);
149 if (nandmcb.physToLogicalMap != NULL)
150 iblFree (nandmcb.physToLogicalMap);
152 if (nandmcb.blocks != NULL)
153 iblFree (nandmcb.blocks);
155 return (retcode);
157 }
161 /**
162 * @b Description
163 * @n
164 *
165 * This function initializes the nand control structure and reads the bad block info
166 * from the nand.
167 */
168 Int32 nand_open (void *ptr_driver, void (*asyncComplete)(void *))
169 {
170 iblNand_t *ibln = (iblNand_t *)ptr_driver;
172 Int32 size;
173 Int32 ret;
174 Int32 i, j;
176 /* Initialize the control info */
177 iblMemset (&nandmcb, 0, sizeof(nandmcb));
178 iblMemcpy (&nandmcb.devInfo, &ibln->nandInfo, sizeof(iblNand_t));
180 nandmcb.page = NULL;
181 nandmcb.logicalToPhysMap = NULL;
182 nandmcb.physToLogicalMap = NULL;
183 nandmcb.blocks = NULL;
185 ret = nandHwDriverInit (&nandmcb.devInfo);
186 if (ret < 0)
187 nand_free_return (ret);
189 /* allocate memory for the page data and the logical to physical block map */
190 size = nandmcb.devInfo.pageSizeBytes + nandmcb.devInfo.pageEccBytes;
191 nandmcb.page = iblMalloc (size * sizeof(Uint8));
192 if (nandmcb.page == NULL)
193 nand_free_return (NAND_MALLOC_PAGE_FAIL);
196 /* Logical to physical map data */
197 nandmcb.logicalToPhysMap = iblMalloc (nandmcb.devInfo.totalBlocks * sizeof(Uint16));
198 if (nandmcb.logicalToPhysMap == NULL)
199 nand_free_return (NAND_MALLOC_MAP_LTOP_FAIL);
202 /* Physical to logical map data */
203 nandmcb.physToLogicalMap = iblMalloc (nandmcb.devInfo.totalBlocks * sizeof(Uint16));
204 if (nandmcb.physToLogicalMap == NULL)
205 nand_free_return (NAND_MALLOC_MAP_PTOL_FAIL);
207 /* Block info */
208 size = nandmcb.devInfo.totalBlocks * sizeof(Uint8);
209 nandmcb.blocks = iblMalloc (size);
210 if (nandmcb.blocks == NULL)
211 nand_free_return (NAND_MALLOC_BLOCK_INFO_FAIL);
214 /* Bad blocks are identified by reading page 0 and page 1. If the first
215 * byte in these pages is not 0xff then the block is bad */
216 nandmcb.numBadBlocks = 0;
217 for (i = 0; i < nandmcb.devInfo.totalBlocks; i++) {
219 ret = nandHwDriverReadBytes (i, 0, nandmcb.devInfo.pageSizeBytes, 1, &nandmcb.page[0]);
220 if (ret < 0)
221 nand_free_return (ret);
223 ret = nandHwDriverReadBytes (i, 1, nandmcb.devInfo.pageSizeBytes, 1, &nandmcb.page[1]);
224 if (ret < 0)
225 nand_free_return (ret);
227 if ((nandmcb.page[0] != 0xff) || (nandmcb.page[1] != 0xff)) {
228 nandmcb.blocks[i] = 0xff;
229 nandmcb.numBadBlocks += 1;
230 } else
231 nandmcb.blocks[i] = 0;
233 }
236 /* Construct the logical to physical block array */
237 for (i = j = 0; i < nandmcb.devInfo.totalBlocks; i++) {
238 if (nandmcb.blocks[i] != 0xff)
239 nandmcb.logicalToPhysMap[j++] = i;
240 }
242 /* Construct the physical to logical block array */
243 for (i = j = 0; i < nandmcb.devInfo.totalBlocks; i++) {
244 if (nandmcb.blocks[i] == 0xff)
245 nandmcb.physToLogicalMap[i] = 0xff;
246 else
247 nandmcb.physToLogicalMap[i] = j++;
248 }
251 /* Seek to the first byte of the file */
252 nandmcb.fpos = -1; /* Force a read on the first seek */
253 nandmcb.currentLogicalBlock = 0xffffffff;
254 nandmcb.currentPage = 0xffffffff;
255 nand_seek (0, 0);
258 return (0);
260 }
263 /**
264 * @b Description
265 * @n
266 * This function performs a reads from the current read point
267 *
268 */
269 Int32 nand_read (Uint8 *ptr_buf, Uint32 num_bytes)
270 {
271 Int32 i;
272 Int32 pIdx;
274 /* Convert the global file position to an offset in the currently cached page */
275 pIdx = nandmcb.fpos % nandmcb.devInfo.pageSizeBytes;
277 for (i = 0; i < num_bytes; i++) {
279 ptr_buf[i] = nandmcb.page[pIdx++];
280 nandmcb.fpos += 1;
282 if (pIdx >= nandmcb.devInfo.pageSizeBytes) {
284 pIdx = 0;
285 nandmcb.currentPage += 1;
287 if (nandmcb.currentPage >= nandmcb.devInfo.pagesPerBlock) {
288 nandmcb.currentPage = 0;
289 nandmcb.currentLogicalBlock += 1;
290 }
293 /* Load the new page */
294 if (nandHwDriverReadPage((Uint32)(nandmcb.logicalToPhysMap[nandmcb.currentLogicalBlock]), nandmcb.currentPage, nandmcb.page) < 0)
295 return (-2);
297 }
298 }
300 return (0);
302 }
304 /**
305 * @b Description
306 * @n
307 * This function performs a peek from the current read point.
308 */
309 Int32 nand_peek (Uint8 *ptr_buf, Uint32 num_bytes)
310 {
311 Int32 ret;
312 Int32 origPos;
313 Uint32 origLogicalBlock;
314 Uint32 origPage;
316 origPos = nandmcb.fpos;
317 origLogicalBlock = nandmcb.currentLogicalBlock;
318 origPage = nandmcb.currentPage;
320 ret = nand_read (ptr_buf, num_bytes);
322 if ( (origLogicalBlock != nandmcb.currentLogicalBlock) ||
323 (origPage != nandmcb.currentPage) ) {
325 if (nandHwDriverReadPage((Uint32)(nandmcb.logicalToPhysMap[origLogicalBlock]), origPage, nandmcb.page) < 0)
326 return (-2);
327 }
329 nandmcb.fpos = origPos;
330 nandmcb.currentLogicalBlock = origLogicalBlock;
331 nandmcb.currentPage = origPage;
333 return (ret);
335 }
337 /**
338 * @b Description
339 * @n
340 * This function returns how much data is available for immediate read.
341 * On nand this always returns the page size.
342 */
343 Int32 nand_query (void)
344 {
345 return (nandmcb.devInfo.pageSizeBytes);
346 }
349 /**
350 * @b Description
351 * @n
352 * This function closes the nand driver
353 */
354 Int32 nand_close (void)
355 {
356 nandHwDriverClose ();
357 return (nand_free_return (0));
359 }
363 /**
364 * @brief The global nand module function table
365 */
366 BOOT_MODULE_FXN_TABLE nand_boot_module =
367 {
368 nand_open, /* Open API */
369 nand_close, /* Close API */
370 nand_read, /* Read API */
371 NULL, /* Write API */
372 nand_peek, /* Peek API */
373 nand_seek, /* Seek API */
374 nand_query /* Query API */
376 };