]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/ibl.git/blob - src/hw/nands/gpio/nandgpio.c
GPIO-NAND: Add check for 2K page size NAND
[keystone-rtos/ibl.git] / src / hw / nands / gpio / nandgpio.c
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 extern volatile cregister Uint32 TSCL;
62 nandDevInfo_t *hwDevInfo;
64 /**
65  * @brief
66  *   Delay for a number of cycles (approximate)
67  */
69 void ndelay(Uint32 uiDelay)
70 {
71         Uint32 t;
72         TSCL = 1;
74         t = TSCL;
75         while(TSCL < (t + uiDelay));
76 }
78 Uint32 ptNandWaitRdy(Uint32 in_timeout) 
79 {
80     Uint32 t;
82     ndelay(NAND_WAIT_PIN_POLL_ST_DLY);
84     TSCL = 1; 
85     t = TSCL;
86      
87     while(!hwGpioReadInput(NAND_BSY_GPIO_PIN))
88     {
89         if( TSCL > (t + in_timeout) )
90         {
91             return 0; /* fail */
92         }
93     }
94     return 1; /* success */
95 }
97 /**
98  * @brief
99  *   Write to the flash (command for the boot loader) 
100  */
101 void ptNandWriteDataByte(Uint8 data)
103         // Data is written to the data register on the rising edge of WE# when
104         //      \95 CE#, CLE, and ALE are LOW, and
105         //      \95 the device is not busy.
106         hwGpioClearOutput(NAND_NWE_GPIO_PIN);
107         ndelay(TARGET_NAND_STD_DELAY);
108         hwGpioClearDataBus(GPIO_DATAMASK);
109         hwGpioWriteDataBus(data);
110         ndelay(TARGET_NAND_STD_DELAY);
111         hwGpioSetOutput(NAND_NWE_GPIO_PIN);   // At posedge clock, make WE# = 1.
112         ndelay(TARGET_NAND_STD_DELAY);
116 /**
117  *  @brief
118  *      Set the address latch
119  */
120 void ptNandAleSet(Uint32 addr)
122         // ALE HIGH indicates address cycle occurring
123         hwGpioSetOutput(NAND_ALE_GPIO_PIN);
124         ptNandWriteDataByte(addr);
125         hwGpioClearOutput(NAND_ALE_GPIO_PIN);
128 /**
129  *  @brief
130  *  Write a command to the nand flash
131  */
132 void ptNandCmdSet(Uint32 cmd)
134         // Commands are written to the command register on the rising edge of WE# when
135         //      \95 CE# and ALE are LOW, and
136         //      \95 CLE is HIGH, and : CLE HIGH indicates command cycle occurring
137         //      \95 the device is not busy
138         hwGpioSetOutput(NAND_CLE_GPIO_PIN);
139         ptNandWriteDataByte(cmd);
140         hwGpioClearOutput(NAND_CLE_GPIO_PIN);
144 /**
145  *  @brief
146  *  Setup hwGpio to drive the NAND interface
147  */
148 void ptNandConfig (void) 
149 {       
150         // Set direction of control signals as OUT
151         hwGpioSetDirection(NAND_CLE_GPIO_PIN, GPIO_OUT);
152         hwGpioSetDirection(NAND_NCE_GPIO_PIN, GPIO_OUT);
153         hwGpioSetDirection(NAND_NWE_GPIO_PIN, GPIO_OUT);
154         hwGpioSetDirection(NAND_ALE_GPIO_PIN, GPIO_OUT);
155         hwGpioSetDirection(NAND_NRE_GPIO_PIN, GPIO_OUT);
156         
157         // Set Data Bus direction as OUT
158         hwGpioSetDataBusDirection(GPIO_OUT);
159         
160         hwGpioSetOutput(NAND_NCE_GPIO_PIN);     // Chip Enable = 1
161     hwGpioClearOutput(NAND_CLE_GPIO_PIN);       // Command Latch enable = 0
162     hwGpioClearOutput(NAND_ALE_GPIO_PIN);               // Address latch Enable = 0
163         hwGpioSetOutput(NAND_NWE_GPIO_PIN);             // Write Enable = 1
164         hwGpioSetOutput(NAND_NRE_GPIO_PIN);             // Read Enable = 1
167 /**
168  *  @brief Initialize the driver
169  *
170  */
171 Int32 nandHwGpioDriverInit (int32 cs, void *vdevInfo)
173         Uint32 cmd;
174         Uint32 ret;
175     nandDevInfo_t *devInfo = (nandDevInfo_t *)vdevInfo;
177     hwDevInfo = devInfo;
179     if (devInfo->addressBytes > 4)
180         return (NAND_INVALID_ADDR_SIZE);
182         // Initialize NAND interface
183         ptNandConfig();
184         ndelay(TARGET_NAND_STD_DELAY*10);       
185         
186         cmd = hwDevInfo->resetCommand;
187         // Send reset command to NAND
188         hwGpioClearOutput(NAND_NCE_GPIO_PIN);           // Chip EN = 0
189         ptNandCmdSet(cmd);
190         hwGpioSetOutput(NAND_NCE_GPIO_PIN);
191                 
192         ret = ptNandWaitRdy(100000);
193         if (ret != 1)
194                 return -1;
196     return (0);
197 }        
199 /**
200  *  @brief
201  *      Read a single data byte
202  */
203 void ptNandReadDataByte(Uint8* puchValue)
205         // Set Data Bus direction as IN
206         hwGpioSetDataBusDirection(GPIO_IN);
207         
208         hwGpioClearOutput(NAND_NRE_GPIO_PIN);
209         ndelay(TARGET_NAND_STD_DELAY);
210         
211         *puchValue = hwGpioReadDataBus();
212         hwGpioSetOutput(NAND_NRE_GPIO_PIN);
213         ndelay(TARGET_NAND_STD_DELAY);
214         
215         // Set Data Bus direction as OUT
216         hwGpioSetDataBusDirection(GPIO_OUT);
217         ndelay(TARGET_NAND_STD_DELAY);
220 /**
221  *  @brief
222  *      Read multiple bytes
223  */
224 Uint32 ptNandReadDataBytes(Uint32 numBytes, Uint8 *destAddr)
226         Uint32 i;
227         
228         // 8-bit NAND
229     for (i = 0; i < numBytes; i++)
230     {
231                 // NANDRead done directly without checking for nand width
232                 ptNandReadDataByte((Uint8 *)destAddr);
233         destAddr++;
234     }
235         return SUCCESS;
238 /**
239  *  @brief
240  *      Swap the bytes in a 4 byte field
241  */
242 Uint32 swapBytes (Uint32 v)
244     Uint32 w;
246     w = (((v >> 24) & 0xff) <<  0)  |
247         (((v >> 16) & 0xff) <<  8)  |
248         (((v >>  8) & 0xff) << 16)  |
249         (((v >>  0) & 0xff) << 24)  ;
251     return (w);
256 /**
257  *  @brief
258  *     Read a complete page including the extra page bytes.
259  */  
261 Int32 nandHwGpioDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data)
264         Uint32 addr;
265         Uint32 cmd;
266         Uint32 ret;
267         if (data == NULL)
268                 return (NAND_NULL_ARG);
270     if ( (block >= hwDevInfo->totalBlocks)    ||
271          (page  >= hwDevInfo->pagesPerBlock)  )
272         return (NAND_INVALID_ADDR);
274         ndelay(TARGET_NAND_STD_DELAY*10);
275                 
276         hwGpioClearOutput(NAND_NCE_GPIO_PIN);
277         ndelay(TARGET_NAND_STD_DELAY*5);
279         if (byte < hwDevInfo->pageSizeBytes) 
280         {
281                 /* Read page data */
282                 cmd = hwDevInfo->readCommandPre;
283         }
284         else
285         {
286                 /* Read spare area data */
287                 cmd = 0x50;
288         }
290         ptNandCmdSet(cmd); // First cycle send 0
292         /* 
293          * Send address of the block + page to be read
294          * Address cycles = 4, Block shift = 14,
295          * Page Shift = 9, Bigblock = 0
296          */
297         addr = PACK_ADDR(0x0, page, block);
298         
299         if (hwDevInfo->pageSizeBytes == 512) {
300                 ptNandAleSet((addr >>  0u) & 0xFF);   /* A0-A7  1st Cycle;  column addr */
301                 ndelay(TARGET_NAND_STD_DELAY);
302                 ptNandAleSet((addr >>  9u) & 0xFF);   /* A9-A16 2nd Cycle;  page addr & blk */
303                 ndelay(TARGET_NAND_STD_DELAY);
304                 ptNandAleSet((addr >> 17u) & 0xFF);   /* A17-A24 3rd Cycle; Block addr */
305                 ndelay(TARGET_NAND_STD_DELAY);
306                 ptNandAleSet((addr >> 25u) & 0x1);    /* A25    4th Cycle;  Plane addr */
307                 ndelay(TARGET_NAND_STD_DELAY);
308         } else {
309                 ptNandAleSet((addr >>  0u) & 0xFF);   /* A0-A7  1st Cycle;  column addr */
310                 ndelay(TARGET_NAND_STD_DELAY);
311                 ptNandAleSet((addr >>  8u) & 0x0F);   /* A8-A11 2nd Cycle;  page addr & blk */
312                 ndelay(TARGET_NAND_STD_DELAY);
313                 ptNandAleSet((addr >> 16u) & 0xFF);   /* A16-A23 3rd Cycle; Block addr */
314                 ndelay(TARGET_NAND_STD_DELAY);
315                 ptNandAleSet((addr >> 24u) & 0xFF);    /* A24-A31 4th Cycle;  Plane addr */
316                 ndelay(TARGET_NAND_STD_DELAY);
318                 ptNandCmdSet(0x30);
319         }
320     
321         // Wait for Ready Busy Pin to go HIGH  
322         ret = ptNandWaitRdy(100000);
323     
324         ptNandReadDataBytes(nbytes, data);
325         
326         // Set Chip enable
327         hwGpioSetOutput(NAND_NCE_GPIO_PIN);     
328         ndelay(TARGET_NAND_STD_DELAY*5);
330         return (0);
336 /**
337  *  @brief
338  *     Read a complete page including the extra page bytes
339  */  
340 Int32 nandHwGpioDriverReadPage(Uint32 block, Uint32 page, Uint8 *data)
342     Int32  ret;
343     Int32  i;
344     Int32  nblocks;
345     Uint8 *blockp;
346     Uint8 *eccp;
347     Uint8  eccCalc[3];
348     int32 iErrors = ECC_SUCCESS;
349     Uint8 *SpareAreaBuf = NULL;
350     Uint8  tempSpareAreaBuf[3];
352     SpareAreaBuf = data + hwDevInfo->pageSizeBytes;
353     
354     /* Read the page, including the extra bytes */
355     ret = nandHwGpioDriverReadBytes (block, page, 0, hwDevInfo->pageSizeBytes + hwDevInfo->pageEccBytes, data);
356     if (ret < 0)
357         return (ret);
359     /* Perform ECC on 256 byte blocks. Three bytes of ecc per 256 byte block are used. The last
360      * 3 bytes are used for the last block, the previous three for the block before that, etc */
362         for(i = 0; i < hwDevInfo->pageSizeBytes / ECC_BLOCK_SIZE; i++)
363         {
364                 
365                 if (hwDevInfo->pageSizeBytes == 512) {
366                         /* Correct ecc error for each 256 byte blocks */
367                         eccComputeECC(data + i * ECC_BLOCK_SIZE, eccCalc);
368                         
369                         if ( i == 0) {
370                                 iErrors = eccCorrectData(data + (i * ECC_BLOCK_SIZE), 
371                                 (SpareAreaBuf +  (i * 3)), eccCalc);
372                         }
374                         if (i == 1) {
375                                 tempSpareAreaBuf[0] = SpareAreaBuf[3];
376                                 tempSpareAreaBuf[1] = SpareAreaBuf[6];
377                                 tempSpareAreaBuf[2] = SpareAreaBuf[7];
378                 
379                                 iErrors = eccCorrectData(data + (i * ECC_BLOCK_SIZE), 
380                                         tempSpareAreaBuf, eccCalc);
381                         }
382                 } else if (hwDevInfo->pageSizeBytes == 2048) {
383                         /* Correct ecc error for each 256 byte blocks */
384                         eccComputeECC(data + i * ECC_BLOCK_SIZE, eccCalc);
385                         iErrors = eccCorrectData(data + (i * ECC_BLOCK_SIZE),
386                                 (SpareAreaBuf + 40 + (i * 3)), eccCalc);
387                 }
388         }
390     return (0);
396 /**
397  *  @brief
398  *      Close the driver
399  */
400 int32 nandHwGpioDriverClose (void)
402     return (0);