]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/ibl.git/blobdiff - src/hw/nands/gpio/nandgpio.c
GPIO NAND: Fix for Big Endian Boot
[keystone-rtos/ibl.git] / src / hw / nands / gpio / nandgpio.c
index 22ac31e7c805b11f2f5fcce59788c3a657ec3bca..a6398a8784a452626c9b875db80d849a4d61472c 100644 (file)
@@ -58,9 +58,9 @@
 #include "nandgpioloc.h"
 
 /* Pointer to the device configuration */
+extern volatile cregister Uint32 TSCL;
 nandDevInfo_t *hwDevInfo;
 
-
 /**
  * @brief
  *   Delay for a number of cycles (approximate)
@@ -68,22 +68,30 @@ nandDevInfo_t *hwDevInfo;
 
 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
@@ -94,11 +102,14 @@ void ptNandWriteDataByte(Uint8 data)
        // 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);
 }
@@ -112,7 +123,7 @@ void ptNandAleSet(Uint32 addr)
 {
        // ALE HIGH indicates address cycle occurring
        hwGpioSetOutput(NAND_ALE_GPIO_PIN);
-       ptNandWriteDataByte(addr);
+       ptNandWriteDataByte((Uint8)addr);
        hwGpioClearOutput(NAND_ALE_GPIO_PIN);
 }
 
@@ -127,7 +138,7 @@ void ptNandCmdSet(Uint32 cmd)
        //      \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);
 }
 
@@ -137,24 +148,54 @@ void ptNandCmdSet(Uint32 cmd)
  *  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
  *
@@ -162,12 +203,14 @@ void ptNandConfig (void)
 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();
@@ -176,35 +219,18 @@ Int32 nandHwGpioDriverInit (int32 cs, void *vdevInfo)
        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);
 }
 
@@ -320,11 +357,13 @@ Int32 nandHwGpioDriverReadPage(Uint32 block, Uint32 page, Uint8 *data)
 {
     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)
@@ -332,19 +371,34 @@ Int32 nandHwGpioDriverReadPage(Uint32 block, Uint32 page, Uint8 *data)
 
     /* 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);