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: Hardware nand driver for 8 bit hwGpio driven nand
40 ********************************************************************************
41 * FILE NAME: nandhwGpio.c
42 *
43 * DESCRIPTION: The low level nand driver which accesses the nand through hwGpio
44 *
45 * @file nandhwGpio.c
46 *
47 * @brief
48 * The low level nand driver which accesses the nand through hwGpio
49 *
50 ********************************************************************************/
51 #include "types.h"
52 #include "ibl.h"
53 #include "iblcfg.h"
54 #include "nandhwapi.h"
55 #include "gpio.h"
56 #include "ecc.h"
57 #include "target.h"
58 #include "nandgpioloc.h"
60 /* Pointer to the device configuration */
61 nandDevInfo_t *hwDevInfo;
64 /**
65 * @brief
66 * Delay for a number of cycles (approximate)
67 */
69 void ndelay(Uint32 uiDelay)
70 {
71 volatile Uint32 i;
73 for (i = 0; i < uiDelay>>3; i++);
74 }
78 /**
79 * @brief
80 * a 100us delay
81 */
82 void ptNandWaitRdy(void)
83 {
84 ndelay(100 * 1000); // 100 usec
85 }
88 /**
89 * @brief
90 * Write to the flash (command for the boot loader)
91 */
92 void ptNandWriteDataByte(Uint8 data)
93 {
94 // Data is written to the data register on the rising edge of WE# when
95 // \95 CE#, CLE, and ALE are LOW, and
96 // \95 the device is not busy.
97 hwGpioClearOutput(NAND_NWE_GPIO_PIN);
98 ndelay(TARGET_NAND_STD_DELAY);
99 hwGpioClearDataBus(GPIO_DATAMASK);
100 hwGpioWriteDataBus(data);
101 ndelay(TARGET_NAND_STD_DELAY);
102 hwGpioSetOutput(NAND_NWE_GPIO_PIN); // At posedge clock, make WE# = 1.
103 ndelay(TARGET_NAND_STD_DELAY);
104 }
107 /**
108 * @brief
109 * Set the address latch
110 */
111 void ptNandAleSet(Uint32 addr)
112 {
113 // ALE HIGH indicates address cycle occurring
114 hwGpioSetOutput(NAND_ALE_GPIO_PIN);
115 ptNandWriteDataByte(addr);
116 hwGpioClearOutput(NAND_ALE_GPIO_PIN);
117 }
119 /**
120 * @brief
121 * Write a command to the nand flash
122 */
123 void ptNandCmdSet(Uint32 cmd)
124 {
125 // Commands are written to the command register on the rising edge of WE# when
126 // \95 CE# and ALE are LOW, and
127 // \95 CLE is HIGH, and : CLE HIGH indicates command cycle occurring
128 // \95 the device is not busy
129 hwGpioSetOutput(NAND_CLE_GPIO_PIN);
130 ptNandWriteDataByte(cmd);
131 hwGpioClearOutput(NAND_CLE_GPIO_PIN);
132 }
135 /**
136 * @brief
137 * Setup hwGpio to drive the NAND interface
138 */
139 void ptNandConfig (void)
140 {
141 // Set direction of control signals as OUT
142 hwGpioSetDirection(NAND_CLE_GPIO_PIN, GPIO_OUT);
143 hwGpioSetDirection(NAND_NCE_GPIO_PIN, GPIO_OUT);
144 hwGpioSetDirection(NAND_NWE_GPIO_PIN, GPIO_OUT);
145 hwGpioSetDirection(NAND_ALE_GPIO_PIN, GPIO_OUT);
146 hwGpioSetDirection(NAND_NRE_GPIO_PIN, GPIO_OUT);
148 // Set Data Bus direction as OUT
149 hwGpioSetDataBusDirection(GPIO_OUT);
151 hwGpioSetOutput(NAND_NCE_GPIO_PIN); // Chip Enable = 1
152 hwGpioClearOutput(NAND_CLE_GPIO_PIN); // Command Latch enable = 0
153 hwGpioClearOutput(NAND_ALE_GPIO_PIN); // Address latch Enable = 0
154 hwGpioSetOutput(NAND_NWE_GPIO_PIN); // Write Enable = 1
155 hwGpioSetOutput(NAND_NRE_GPIO_PIN); // Read Enable = 1
156 }
158 /**
159 * @brief Initialize the driver
160 *
161 */
162 Int32 nandHwDriverInit (int32 cs, nandDevInfo_t *devInfo)
163 {
164 Uint32 cmd;
166 hwDevInfo = devInfo;
168 if (devInfo->addressBytes > 4)
169 return (NAND_INVALID_ADDR_SIZE);
171 // Initialize NAND interface
172 ptNandConfig();
173 ndelay(TARGET_NAND_STD_DELAY*10);
175 cmd = hwDevInfo->resetCommand;
176 // Send reset command to NAND
177 hwGpioClearOutput(NAND_NCE_GPIO_PIN); // Chip EN = 0
178 ptNandCmdSet(cmd);
179 hwGpioSetOutput(NAND_NCE_GPIO_PIN);
181 ptNandWaitRdy();
183 return (0);
184 }
186 /**
187 * @brief
188 * Read a single data byte
189 */
190 void ptNandReadDataByte(Uint8* puchValue)
191 {
192 // Set Data Bus direction as IN
193 hwGpioSetDataBusDirection(GPIO_IN);
195 hwGpioClearOutput(NAND_NRE_GPIO_PIN);
196 ndelay(TARGET_NAND_STD_DELAY);
198 *puchValue = hwGpioReadDataBus();
199 hwGpioSetOutput(NAND_NRE_GPIO_PIN);
200 ndelay(TARGET_NAND_STD_DELAY);
202 // Set Data Bus direction as OUT
203 hwGpioSetDataBusDirection(GPIO_OUT);
204 ndelay(TARGET_NAND_STD_DELAY);
205 }
207 /**
208 * @brief
209 * Read multiple bytes
210 */
211 Uint32 ptNandReadDataBytes(Uint32 numBytes, Uint8 *destAddr)
212 {
213 Uint32 i;
215 // 8-bit NAND
216 for (i = 0; i < numBytes; i++)
217 {
218 // NANDRead done directly without checking for nand width
219 ptNandReadDataByte((Uint8 *)destAddr);
220 destAddr++;
221 }
222 return SUCCESS;
223 }
225 /**
226 * @brief
227 * Swap the bytes in a 4 byte field
228 */
229 Uint32 swapBytes (Uint32 v)
230 {
231 Uint32 w;
233 w = (((v >> 24) & 0xff) << 0) |
234 (((v >> 16) & 0xff) << 8) |
235 (((v >> 8) & 0xff) << 16) |
236 (((v >> 0) & 0xff) << 24) ;
238 return (w);
240 }
243 /**
244 * @brief
245 * Read a complete page including the extra page bytes.
246 */
248 Int32 nandHwDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data)
249 {
251 Uint32 addr;
253 if (data == NULL)
254 return (NAND_NULL_ARG);
256 if ( (block >= hwDevInfo->totalBlocks) ||
257 (page >= hwDevInfo->pagesPerBlock) )
258 return (NAND_INVALID_ADDR);
260 ndelay(TARGET_NAND_STD_DELAY*10);
262 hwGpioClearOutput(NAND_NCE_GPIO_PIN);
263 ndelay(TARGET_NAND_STD_DELAY*5);
265 ptNandCmdSet(hwDevInfo->readCommandPre); // First cycle send 0
267 // Send address of the block + page to be read
268 // Address cycles = 4, Block shift = 22, Page Shift = 16, Bigblock = 0
269 addr = (block << hwDevInfo->blockOffset) +
270 (page << hwDevInfo->pageOffset) +
271 (byte << hwDevInfo->columnOffset);
273 if (hwDevInfo->lsbFirst == FALSE)
274 addr = swapBytes (addr);
276 ptNandAleSet(addr & 0xFF); // BIT0-7 1rst Cycle
277 ndelay(TARGET_NAND_STD_DELAY);
279 if (hwDevInfo->addressBytes >= 2) {
280 ptNandAleSet((addr >> 8u) & 0x0F); // Bits8-11 2nd Cycle
281 ndelay(TARGET_NAND_STD_DELAY);
282 }
284 if (hwDevInfo->addressBytes >= 3) {
285 ptNandAleSet((addr >> 16u) & 0xFF); // Bits16-23
286 ndelay(TARGET_NAND_STD_DELAY);
287 }
289 if (hwDevInfo->addressBytes >= 4) {
290 ptNandAleSet((addr >> 24u) & 0xFF); // Bits24-31
291 ndelay(TARGET_NAND_STD_DELAY);
292 }
294 if (hwDevInfo->postCommand == TRUE)
295 ptNandCmdSet(hwDevInfo->readCommandPost);
297 // Wait for Ready Busy Pin to go HIGH
298 ptNandWaitRdy();
301 ptNandReadDataBytes(nbytes, data);
304 // Set Chip enable
305 hwGpioSetOutput(NAND_NCE_GPIO_PIN);
306 ndelay(TARGET_NAND_STD_DELAY*5);
308 return (0);
309 }
314 /**
315 * @brief
316 * Read a complete page including the extra page bytes
317 */
318 Int32 nandHwDriverReadPage(Uint32 block, Uint32 page, Uint8 *data)
319 {
320 Int32 ret;
321 Int32 i;
322 Int32 nblocks;
323 Uint8 *blockp;
324 Uint8 *eccp;
325 Uint8 eccCalc[3];
327 /* Read the page, including the extra bytes */
328 ret = nandHwDriverReadBytes (block, page, 0, hwDevInfo->pageSizeBytes + hwDevInfo->pageEccBytes, data);
329 if (ret < 0)
330 return (ret);
332 /* Perform ECC on 256 byte blocks. Three bytes of ecc per 256 byte block are used. The last
333 * 3 bytes are used for the last block, the previous three for the block before that, etc */
334 nblocks = hwDevInfo->pageSizeBytes >> 8;
336 for (i = 0; i < nblocks; i++) {
338 blockp = &data[i * 256];
339 eccp = &data[hwDevInfo->pageSizeBytes + hwDevInfo->pageEccBytes - ((nblocks - i) * 3)];
341 eccComputeECC (blockp, eccCalc);
343 if (eccCorrectData (blockp, eccp, eccCalc) != ECC_SUCCESS)
344 return (NAND_ECC_FAILURE);
346 }
348 return (0);
350 }
354 /**
355 * @brief
356 * Close the driver
357 */
358 int32 nandHwDriverClose (void)
359 {
360 return (0);
362 }