index 22ac31e7c805b11f2f5fcce59788c3a657ec3bca..a6398a8784a452626c9b875db80d849a4d61472c 100644 (file)
#include "nandgpioloc.h"
/* Pointer to the device configuration */
+extern volatile cregister Uint32 TSCL;
nandDevInfo_t *hwDevInfo;
-
/**
* @brief
* Delay for a number of cycles (approximate)
void ndelay(Uint32 uiDelay)
{
- volatile Uint32 i;
+ Uint32 t;
+ TSCL = 1;
- for (i = 0; i < uiDelay>>3; i++);
+ t = TSCL;
+ while(TSCL < (t + uiDelay));
}
+Uint32 ptNandWaitRdy(Uint32 in_timeout)
+{
+ Uint32 count = 0;
+ ndelay(NAND_WAIT_PIN_POLL_ST_DLY);
+ ndelay(NAND_WAIT_PIN_POLL_ST_DLY);
-/**
- * @brief
- * a 100us delay
- */
-void ptNandWaitRdy(void)
-{
- ndelay(100 * 1000); // 100 usec
-}
+ while(!hwGpioReadInput(NAND_BSY_GPIO_PIN))
+ {
+ ndelay(NAND_WAIT_PIN_POLL_ST_DLY);
+ count ++;
+ if (count > in_timeout)
+ return 0;
+ }
+ return 1;
+}
/**
* @brief
// Data is written to the data register on the rising edge of WE# when
// \95 CE#, CLE, and ALE are LOW, and
// \95 the device is not busy.
+ hwGpioClearDataBus(GPIO_DATAMASK);
+
hwGpioClearOutput(NAND_NWE_GPIO_PIN);
ndelay(TARGET_NAND_STD_DELAY);
- hwGpioClearDataBus(GPIO_DATAMASK);
+
hwGpioWriteDataBus(data);
ndelay(TARGET_NAND_STD_DELAY);
+
hwGpioSetOutput(NAND_NWE_GPIO_PIN); // At posedge clock, make WE# = 1.
ndelay(TARGET_NAND_STD_DELAY);
}
{
// ALE HIGH indicates address cycle occurring
hwGpioSetOutput(NAND_ALE_GPIO_PIN);
- ptNandWriteDataByte(addr);
+ ptNandWriteDataByte((Uint8)addr);
hwGpioClearOutput(NAND_ALE_GPIO_PIN);
}
// \95 CLE is HIGH, and : CLE HIGH indicates command cycle occurring
// \95 the device is not busy
hwGpioSetOutput(NAND_CLE_GPIO_PIN);
- ptNandWriteDataByte(cmd);
+ ptNandWriteDataByte((Uint8)cmd);
hwGpioClearOutput(NAND_CLE_GPIO_PIN);
}
* Setup hwGpio to drive the NAND interface
*/
void ptNandConfig (void)
-{
+{
+ hwGpioSetOutput(NAND_NCE_GPIO_PIN); // Chip Enable = 1
+ hwGpioClearOutput(NAND_ALE_GPIO_PIN); // Address latch Enable = 0
+ hwGpioClearOutput(NAND_CLE_GPIO_PIN); // Command Latch enable = 0
+ hwGpioSetOutput(NAND_NWE_GPIO_PIN); // Write Enable = 1
+ hwGpioSetOutput(NAND_NRE_GPIO_PIN); // Read Enable = 1
+
// Set direction of control signals as OUT
- hwGpioSetDirection(NAND_CLE_GPIO_PIN, GPIO_OUT);
hwGpioSetDirection(NAND_NCE_GPIO_PIN, GPIO_OUT);
- hwGpioSetDirection(NAND_NWE_GPIO_PIN, GPIO_OUT);
hwGpioSetDirection(NAND_ALE_GPIO_PIN, GPIO_OUT);
+ hwGpioSetDirection(NAND_CLE_GPIO_PIN, GPIO_OUT);
+ hwGpioSetDirection(NAND_NWE_GPIO_PIN, GPIO_OUT);
hwGpioSetDirection(NAND_NRE_GPIO_PIN, GPIO_OUT);
+
+ hwGpioSetDirection(NAND_BSY_GPIO_PIN, GPIO_IN);
// Set Data Bus direction as OUT
hwGpioSetDataBusDirection(GPIO_OUT);
-
- hwGpioSetOutput(NAND_NCE_GPIO_PIN); // Chip Enable = 1
- hwGpioClearOutput(NAND_CLE_GPIO_PIN); // Command Latch enable = 0
- hwGpioClearOutput(NAND_ALE_GPIO_PIN); // Address latch Enable = 0
- hwGpioSetOutput(NAND_NWE_GPIO_PIN); // Write Enable = 1
- hwGpioSetOutput(NAND_NRE_GPIO_PIN); // Read Enable = 1
}
+/**
+* @brief
+* Read a single data byte
+*/
+void ptNandReadDataByte(Uint8* puchValue)
+{
+ Uint32 temp;
+ // Set Data Bus direction as IN
+ hwGpioSetDataBusDirection(GPIO_IN);
+ ndelay(TARGET_NAND_STD_DELAY);
+
+ hwGpioClearOutput(NAND_NRE_GPIO_PIN);
+ ndelay(TARGET_NAND_STD_DELAY);
+
+ temp = hwGpioReadDataBus();
+ temp = temp & 0xff;
+ *puchValue = (Uint8)temp;
+
+ ndelay(TARGET_NAND_STD_DELAY);
+ hwGpioSetOutput(NAND_NRE_GPIO_PIN);
+ ndelay(TARGET_NAND_STD_DELAY);
+
+ // Set Data Bus direction as OUT
+ hwGpioSetDataBusDirection(GPIO_OUT);
+ ndelay(TARGET_NAND_STD_DELAY);
+}
+
+
/**
* @brief Initialize the driver
*
Int32 nandHwGpioDriverInit (int32 cs, void *vdevInfo)
{
Uint32 cmd;
- nandDevInfo_t *devInfo = (nandDevInfo_t *)vdevInfo;
+ Uint32 ret;
+
+ nandDevInfo_t *devInfo = (nandDevInfo_t *)vdevInfo;
- hwDevInfo = devInfo;
+ hwDevInfo = devInfo;
- if (devInfo->addressBytes > 4)
- return (NAND_INVALID_ADDR_SIZE);
+ if (devInfo->addressBytes > 4)
+ return (NAND_INVALID_ADDR_SIZE);
// Initialize NAND interface
ptNandConfig();
cmd = hwDevInfo->resetCommand;
// Send reset command to NAND
hwGpioClearOutput(NAND_NCE_GPIO_PIN); // Chip EN = 0
+ ndelay(TARGET_NAND_STD_DELAY * 10);
ptNandCmdSet(cmd);
+ ndelay(TARGET_NAND_STD_DELAY * 10);
hwGpioSetOutput(NAND_NCE_GPIO_PIN);
- ptNandWaitRdy();
-
- return (0);
+ ret = ptNandWaitRdy(100000);
+ if (ret == 1)
+ return 0;
+ else
+ return -1;
}
-/**
- * @brief
- * Read a single data byte
- */
-void ptNandReadDataByte(Uint8* puchValue)
-{
- // Set Data Bus direction as IN
- hwGpioSetDataBusDirection(GPIO_IN);
-
- hwGpioClearOutput(NAND_NRE_GPIO_PIN);
- ndelay(TARGET_NAND_STD_DELAY);
-
- *puchValue = hwGpioReadDataBus();
- hwGpioSetOutput(NAND_NRE_GPIO_PIN);
- ndelay(TARGET_NAND_STD_DELAY);
-
- // Set Data Bus direction as OUT
- hwGpioSetDataBusDirection(GPIO_OUT);
- ndelay(TARGET_NAND_STD_DELAY);
-}
-
/**
* @brief
* Read multiple bytes
@@ -250,62 +276,73 @@ Int32 nandHwGpioDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32
{
Uint32 addr;
-
+ Uint32 cmd;
+ Uint32 ret;
+
if (data == NULL)
return (NAND_NULL_ARG);
- if ( (block >= hwDevInfo->totalBlocks) ||
- (page >= hwDevInfo->pagesPerBlock) )
- return (NAND_INVALID_ADDR);
+ if ( (block >= hwDevInfo->totalBlocks) ||
+ (page >= hwDevInfo->pagesPerBlock) )
+ return (NAND_INVALID_ADDR);
ndelay(TARGET_NAND_STD_DELAY*10);
hwGpioClearOutput(NAND_NCE_GPIO_PIN);
ndelay(TARGET_NAND_STD_DELAY*5);
-
- ptNandCmdSet(hwDevInfo->readCommandPre); // First cycle send 0
-
- // Send address of the block + page to be read
- // Address cycles = 4, Block shift = 22, Page Shift = 16, Bigblock = 0
- addr = (block << hwDevInfo->blockOffset) +
- (page << hwDevInfo->pageOffset) +
- (byte << hwDevInfo->columnOffset);
-
- if (hwDevInfo->lsbFirst == FALSE)
- addr = swapBytes (addr);
-
- ptNandAleSet(addr & 0xFF); // BIT0-7 1rst Cycle
- ndelay(TARGET_NAND_STD_DELAY);
-
- if (hwDevInfo->addressBytes >= 2) {
- ptNandAleSet((addr >> 8u) & 0x0F); // Bits8-11 2nd Cycle
- ndelay(TARGET_NAND_STD_DELAY);
- }
-
- if (hwDevInfo->addressBytes >= 3) {
- ptNandAleSet((addr >> 16u) & 0xFF); // Bits16-23
- ndelay(TARGET_NAND_STD_DELAY);
- }
-
- if (hwDevInfo->addressBytes >= 4) {
- ptNandAleSet((addr >> 24u) & 0xFF); // Bits24-31
- ndelay(TARGET_NAND_STD_DELAY);
- }
-
- if (hwDevInfo->postCommand == TRUE)
- ptNandCmdSet(hwDevInfo->readCommandPost);
+ if (byte < hwDevInfo->pageSizeBytes)
+ {
+ /* Read page data */
+ cmd = hwDevInfo->readCommandPre;
+ ptNandCmdSet(cmd); // First cycle send 0
+ addr = PACK_ADDR(0x0, page, block);
+ }
+ else
+ {
+ /* Read spare area data */
+ if (hwDevInfo->pageSizeBytes == 512) {
+ cmd = 0x50;
+ ptNandCmdSet(cmd);
+ addr = PACK_ADDR(0x0, page, block);
+ } else if (hwDevInfo->pageSizeBytes == 2048) {
+ cmd = 0x0;
+ ptNandCmdSet(cmd);
+ addr = PACK_ADDR(0x800, page, block);
+ }
+ }
+
+ if (hwDevInfo->pageSizeBytes == 512) {
+ ptNandAleSet((addr >> 0u) & 0xFF); /* A0-A7 1st Cycle; column addr */
+ ndelay(TARGET_NAND_STD_DELAY);
+ ptNandAleSet((addr >> 9u) & 0xFF); /* A9-A16 2nd Cycle; page addr & blk */
+ ndelay(TARGET_NAND_STD_DELAY);
+ ptNandAleSet((addr >> 17u) & 0xFF); /* A17-A24 3rd Cycle; Block addr */
+ ndelay(TARGET_NAND_STD_DELAY);
+ ptNandAleSet((addr >> 25u) & 0x1); /* A25 4th Cycle; Plane addr */
+ ndelay(TARGET_NAND_STD_DELAY);
+ } else {
+ ptNandAleSet((addr >> 0u) & 0xFF); /* A0-A7 1st Cycle; column addr */
+ ndelay(TARGET_NAND_STD_DELAY);
+ ptNandAleSet((addr >> 8u) & 0x0F); /* A8-A11 2nd Cycle; page addr & blk */
+ ndelay(TARGET_NAND_STD_DELAY);
+ ptNandAleSet((addr >> 16u) & 0xFF); /* A16-A23 3rd Cycle; Block addr */
+ ndelay(TARGET_NAND_STD_DELAY);
+ ptNandAleSet((addr >> 24u) & 0xFF); /* A24-A31 4th Cycle; Plane addr */
+ ndelay(TARGET_NAND_STD_DELAY);
+
+ ptNandCmdSet(0x30);
+ }
+
// Wait for Ready Busy Pin to go HIGH
- ptNandWaitRdy();
-
+ ret = ptNandWaitRdy(100000);
ptNandReadDataBytes(nbytes, data);
-
// Set Chip enable
hwGpioSetOutput(NAND_NCE_GPIO_PIN);
- ndelay(TARGET_NAND_STD_DELAY*5);
-
+ ndelay(TARGET_NAND_STD_DELAY*5);
+
return (0);
}
{
Int32 ret;
Int32 i;
- Int32 nblocks;
- Uint8 *blockp;
- Uint8 *eccp;
Uint8 eccCalc[3];
+ int32 iErrors = ECC_SUCCESS;
+ Uint8 *SpareAreaBuf = NULL;
+ Uint8 tempSpareAreaBuf[3];
+ SpareAreaBuf = data + hwDevInfo->pageSizeBytes;
+
/* Read the page, including the extra bytes */
ret = nandHwGpioDriverReadBytes (block, page, 0, hwDevInfo->pageSizeBytes + hwDevInfo->pageEccBytes, data);
if (ret < 0)
/* Perform ECC on 256 byte blocks. Three bytes of ecc per 256 byte block are used. The last
* 3 bytes are used for the last block, the previous three for the block before that, etc */
- nblocks = hwDevInfo->pageSizeBytes >> 8;
-
- for (i = 0; i < nblocks; i++) {
-
- blockp = &data[i * 256];
- eccp = &data[hwDevInfo->pageSizeBytes + hwDevInfo->pageEccBytes - ((nblocks - i) * 3)];
-
- eccComputeECC (blockp, eccCalc);
- if (eccCorrectData (blockp, eccp, eccCalc) != ECC_SUCCESS)
- return (NAND_ECC_FAILURE);
-
- }
+ for(i = 0; i < hwDevInfo->pageSizeBytes / ECC_BLOCK_SIZE; i++)
+ {
+
+ if (hwDevInfo->pageSizeBytes == 512) {
+ /* Correct ecc error for each 256 byte blocks */
+ eccComputeECC(data + i * ECC_BLOCK_SIZE, eccCalc);
+
+ if ( i == 0) {
+ iErrors = eccCorrectData(data + (i * ECC_BLOCK_SIZE),
+ (SpareAreaBuf + (i * 3)), eccCalc);
+ }
+
+ if (i == 1) {
+ tempSpareAreaBuf[0] = SpareAreaBuf[3];
+ tempSpareAreaBuf[1] = SpareAreaBuf[6];
+ tempSpareAreaBuf[2] = SpareAreaBuf[7];
+
+ iErrors = eccCorrectData(data + (i * ECC_BLOCK_SIZE),
+ tempSpareAreaBuf, eccCalc);
+ }
+ } else if (hwDevInfo->pageSizeBytes == 2048) {
+ /* Correct ecc error for each 256 byte blocks */
+ eccComputeECC(data + i * ECC_BLOCK_SIZE, eccCalc);
+ iErrors = eccCorrectData(data + (i * ECC_BLOCK_SIZE),
+ (SpareAreaBuf + 40 + (i * 3)), eccCalc);
+ }
+ }
return (0);