SPI NAND flash added
authorMike Line <m-line1@ti.com>
Tue, 21 Dec 2010 23:23:12 +0000 (18:23 -0500)
committerMike Line <m-line1@ti.com>
Tue, 21 Dec 2010 23:23:12 +0000 (18:23 -0500)
19 files changed:
src/device/c64x/make/makefile
src/device/c661x/c661x.c
src/device/c661x/target.h
src/device/device.h
src/driver/c64x/make/makefile
src/driver/nand/nand.c
src/hw/c64x/make/makefile
src/hw/nands/emif25/nandemif25.c
src/hw/nands/nandhwapi.h
src/hw/nands/spi/nandspi.c [new file with mode: 0644]
src/hw/spi/spi.c [new file with mode: 0644]
src/hw/spi/spi_api.h [new file with mode: 0644]
src/hw/spi/spi_loc.h [new file with mode: 0644]
src/ibl.h
src/main/iblinit.c
src/make/Makefile
src/make/ibl_c661x/ibl_objs_template.inc
src/util/i2cConfig/makestg2
src/util/i2cWrite/makestg2

index da83c7be558617851488b84451bc4a24bbbd568e..d1cb5b1c01f085a8175426a4d3e99d80b8087000 100644 (file)
@@ -97,7 +97,9 @@ C6X_C_DIR+= ;$(IBL_ROOT)/hw/qm
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/cpdma
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/pa
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/serdes
+C6X_C_DIR+= ;$(IBL_ROOT)/hw/nands
 C6X_C_DIR+= ;$(IBL_ROOT)/driver/eth
+C6X_C_DIR+= ;$(IBL_ROOT)/hw/spi
 export C6X_C_DIR
 
 vpath % $(IBL_ROOT)/device/$(TARGET)
index 96e5edcfdfd6a6c12ba95fd23334ba67d60b2619..e908fe70e51f3d6b59a6aac2b19e5bc3e9acd620 100644 (file)
@@ -61,6 +61,8 @@
 #include "pa_api.h"
 #include "serdes_api.h"
 #include "net.h"
+#include "nandhwapi.h"
+#include "spi_api.h"
 #include <string.h>
 
 extern cregister unsigned int DNUM;
@@ -163,14 +165,54 @@ int32 devicePowerPeriph (int32 modNum)
 
 
 /**
- *  @brief  Enable the pass through version of the nand controller
+ *  @brief  Enable EMIF25 or SPI interface to the NAND
  *
- *  @details  On the evm the nand controller is enabled by setting 
- *            gpio 14 high
  */
 #ifndef EXCLUDE_NAND
 int32 deviceConfigureForNand(void)
 {
+
+#ifndef EXCLUDE_NAND_SPI
+
+    if (ibl.nandConfig.interface == ibl_NAND_IF_SPI)  {
+
+        spiConfig_t spiCfg;
+        uint32      v;
+        SINT16      ret;
+
+        /* SPI is module number 3 only on the c6618. On the c6616 the SPI is in the
+         * always on domain */
+        v = *((Uint32 *)DEVICE_JTAG_ID_REG);
+        if (v == DEVICE_C6618_JTAG_ID_VAL)
+            devicePowerPeriph (3);
+
+        /* Translate to the low level driver */
+        spiCfg.port      = 0;
+        spiCfg.mode      = ibl.spiConfig.mode;
+        spiCfg.addrWidth = ibl.spiConfig.addrWidth;
+        spiCfg.npin      = ibl.spiConfig.nPins;
+        spiCfg.csel      = ibl.spiConfig.csel;
+        spiCfg.c2tdelay  = ibl.spiConfig.c2tdelay;
+
+        /* On c661x devices the PLL module has a built in divide by 6, and the SPI
+         * has a maximum clock divider value of 0xff */
+        v = ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz / (DEVICE_SPI_MOD_DIVIDER * ibl.spiConfig.busFreqMHz);
+        if (v > 0xff)
+            v = 0xff;
+
+        spiCfg.clkdiv =  (UINT16) v;
+
+        ret = hwSpiConfig (&spiCfg);
+
+        if (ret != 0)  {
+            iblStatus.iblFail = ibl_FAIL_CODE_SPI_PARAMS;
+            return (-1);
+        }
+
+    }
+
+#endif
+
     return (0);
 
 }
@@ -525,6 +567,53 @@ void targetFreeQs (void)
 }    
 
 
+/**
+ *  @brief Return the NAND interface (EMIF25 or SPI) used based on the value
+ *         of interface
+ */
+#ifndef EXCLUDE_NAND_EMIF
+nandCtbl_t nandEmifCtbl =  {
+
+    nandHwDriverInit,
+    nandHwDriverReadBytes,
+    nandHwDriverReadPage,
+    nandHwDriverClose
+
+};
+#endif
+
+#ifndef EXCLUDE_NAND_SPI
+nandCtbl_t nandSpiCtbl =  {
+
+
+    nandHwSpiDriverInit,
+    nandHwSpiDriverReadBytes,
+    nandHwSpiDriverReadPage,
+    nandHwSpiDriverClose
+
+};
+#endif
+
+nandCtbl_t *deviceGetNandCtbl (int32 interface)
+{
+
+#ifndef EXCLUDE_NAND_SPI
+
+    if (interface == ibl_NAND_IF_SPI)
+        return (&nandSpiCtbl);
+
+#endif
+
+#ifndef EXCLUDE_NAND_EMIF
+    if ((interface >= ibl_NAND_IF_CHIPSEL_2) && (interface <= ibl_NAND_IF_CHIPSEL_5))
+        return (&nandEmifCtbl);
+
+#endif
+
+    return (NULL);
+
+}
+
     
 
 
index a282ecdedc54386d3687bd7c3854770a28621528..ea10352cab42a7fdc97c24a538b0a51e2120a805 100644 (file)
  */
 #define DEVICE_PSC_BASE     0x02350000u
 
+/**
+ *  @brief
+ *    The SPI module base and module divider
+ */
+#define DEVICE_SPI_BASE(x)          0x20bf0000u
+#define DEVICE_SPI_MOD_DIVIDER      6
 
 /**
  * @brief
index 952f328980342b06b8a6b96513d722b6b8422ed6..12a075bc37b8fa9cde6577746734c9055adeb954 100644 (file)
@@ -148,8 +148,6 @@ void deviceSetEthResetState (int32 portNum, BOOL applyReset);
   */
 bool deviceIsLittleEndian(void);
 
-#endif
-
 
 /**
  *  @brief
@@ -160,3 +158,27 @@ bool deviceIsLittleEndian(void);
  */
 void chipDelay32 (uint32 nCycles);
 
+
+/**
+ *  @brief
+ *      Return the NAND interface function table
+ *
+ *  @details
+ *      Some devices support multiple NAND interface at once (EMIF25 and SPI).
+ *      This function returns to the lower level driver the pointer to the
+ *      table to use. The table is selected in the ibl configuration.
+ */
+typedef struct nandCtbl_s  {
+
+    Int32 (*nct_driverInit)      (int32 cs, void *nandDevInfo);
+    Int32 (*nct_driverReadBytes) (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
+    Int32 (*nct_driverReadPage)  (Uint32 block, Uint32 page, Uint8 *data);
+    Int32 (*nct_driverClose)     (void);
+
+} nandCtbl_t;
+
+nandCtbl_t *deviceGetNandCtbl (int32 interface);
+
+
+
+#endif
index 9a1e1a05308a102b0801467b04d7c0d3a2bd061c..bb7d45e6ceb7141aa73d2c50cb032d205e3a8bdd 100644 (file)
@@ -82,6 +82,8 @@ C6X_C_DIR+= ;$(IBL_ROOT)/driver/nand
 C6X_C_DIR+= ;$(IBL_ROOT)/cfg/$(TARGET)
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/timer
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/nands
+C6X_C_DIR+= ;$(IBL_ROOT)/device
+C6X_C_DIR+= ;$(IBL_ROOT)/device/$(TARGET)
 export C6X_C_DIR
 
 vpath % $(subst ;,$(PATHSEP), $(ECODIR)/$(ETHDIR); $(ECODIR)/$(STRMDIR); $(ECODIR)/$(TIMDIR); $(ECODIR)/$(NANDDIR) )
index 496b7bdee12c9c9759a2f2a63abe6b345c9a42f3..40528c588300a7748a6d6a75a3a3e34d39490c7a 100644 (file)
@@ -51,6 +51,7 @@
 #include "types.h"
 #include "ibl.h"
 #include "iblloc.h"
+#include "device.h"
 #include "nand.h" 
 #include "nandhwapi.h"
 #include <string.h>
@@ -76,11 +77,15 @@ typedef struct nandmcb_s
     Uint8  *blocks;                     /**< There is one byte per block. A non-zero value indicates
                                              that the block is bad */
 
+    nandCtbl_t *nand_if;                /**< Current low level interface (GPIO, EMIF or SPI) */
+    
+
 } nandmcb_t;
 
 nandmcb_t nandmcb;
 
 
+
 /**
  *  @b Description
  *  @n
@@ -121,8 +126,10 @@ Int32 nand_seek (Int32 loc, Int32 from)
         return (0);
 
     /* Otherwise load the desired page */
-    if (nandHwDriverReadPage((Uint32)(nandmcb.logicalToPhysMap[desiredBlock]), desiredPage, nandmcb.page) < 0)
-        return (-2);
+    if (nandmcb.nand_if->nct_driverReadPage != NULL)  {
+        if ((*nandmcb.nand_if->nct_driverReadPage)((Uint32)(nandmcb.logicalToPhysMap[desiredBlock]), desiredPage, nandmcb.page) < 0)
+            return (-2);
+    }
 
     /* Update the currently loaded block/page info */
     nandmcb.currentLogicalBlock = desiredBlock;
@@ -165,7 +172,7 @@ Int32 nand_free_return (Int32 retcode)
  *  This function initializes the nand control structure and reads the bad block info
  *  from the nand.
  */
-Int32 nand_open (void *ptr_driver, void (*asyncComplete)(void *), int32 chipSelect)
+Int32 nand_open (void *ptr_driver, void (*asyncComplete)(void *))
 {
     iblNand_t *ibln = (iblNand_t *)ptr_driver;
     
@@ -182,9 +189,19 @@ Int32 nand_open (void *ptr_driver, void (*asyncComplete)(void *), int32 chipSele
     nandmcb.physToLogicalMap = NULL;
     nandmcb.blocks           = NULL;
 
-    ret = nandHwDriverInit (ibln->cs, &nandmcb.devInfo);
-    if (ret < 0)
-        nand_free_return (ret);
+    nandmcb.nand_if = deviceGetNandCtbl (ibln->interface);
+
+    if (nandmcb.nand_if != NULL)  {
+
+        ret = (*nandmcb.nand_if->nct_driverInit)(ibln->interface, (void *)&nandmcb.devInfo);
+        if (ret < 0)
+            nand_free_return (ret);
+
+    }  else  {
+
+        return (-1);
+
+    }
 
     /* allocate memory for the page data and the logical to physical block map */
     size = nandmcb.devInfo.pageSizeBytes + nandmcb.devInfo.pageEccBytes;
@@ -213,22 +230,25 @@ Int32 nand_open (void *ptr_driver, void (*asyncComplete)(void *), int32 chipSele
 
     /* Bad blocks are identified by reading page 0 and page 1. If the first 
      * byte in these pages is not 0xff then the block is bad */
+    if (nandmcb.nand_if == NULL)
+        return (-1);
+
     nandmcb.numBadBlocks = 0;
     for (i = 0; i < nandmcb.devInfo.totalBlocks; i++)  {
 
-       ret = nandHwDriverReadBytes (i, 0, nandmcb.devInfo.pageSizeBytes, 1, &nandmcb.page[0]);
-       if (ret < 0)
-          nand_free_return (ret);
+        ret = (*nandmcb.nand_if->nct_driverReadBytes)(i, 0, nandmcb.devInfo.pageSizeBytes, 1, &nandmcb.page[0]);
+        if (ret < 0)
+            nand_free_return (ret);
 
-       ret = nandHwDriverReadBytes (i, 1, nandmcb.devInfo.pageSizeBytes, 1, &nandmcb.page[1]);
-       if (ret < 0)
-          nand_free_return (ret);
+        ret = (*nandmcb.nand_if->nct_driverReadBytes)(i, 1, nandmcb.devInfo.pageSizeBytes, 1, &nandmcb.page[1]);
+        if (ret < 0)
+            nand_free_return (ret);
         
-       if ((nandmcb.page[0] != 0xff) || (nandmcb.page[1] != 0xff))  {
-          nandmcb.blocks[i] = 0xff;
-          nandmcb.numBadBlocks += 1;
-       } else
-          nandmcb.blocks[i] = 0;
+        if ((nandmcb.page[0] != 0xff) || (nandmcb.page[1] != 0xff))  {
+            nandmcb.blocks[i] = 0xff;
+            nandmcb.numBadBlocks += 1;
+        } else
+            nandmcb.blocks[i] = 0;
 
     }
     
@@ -271,6 +291,10 @@ Int32 nand_read (Uint8 *ptr_buf, Uint32 num_bytes)
     Int32  i;
     Int32  pIdx;
 
+
+    if (nandmcb.nand_if == NULL)
+        return (-1);
+
     /* Convert the global file position to an offset in the currently cached page */
     pIdx = nandmcb.fpos % nandmcb.devInfo.pageSizeBytes;
 
@@ -291,7 +315,7 @@ Int32 nand_read (Uint8 *ptr_buf, Uint32 num_bytes)
 
             
             /* Load the new page */
-            if (nandHwDriverReadPage((Uint32)(nandmcb.logicalToPhysMap[nandmcb.currentLogicalBlock]), nandmcb.currentPage, nandmcb.page) < 0)
+            if ((*nandmcb.nand_if->nct_driverReadPage)((Uint32)(nandmcb.logicalToPhysMap[nandmcb.currentLogicalBlock]), nandmcb.currentPage, nandmcb.page) < 0)
                 return (-2);
 
         }
@@ -313,6 +337,10 @@ Int32 nand_peek (Uint8 *ptr_buf, Uint32 num_bytes)
     Uint32 origLogicalBlock;
     Uint32 origPage;
 
+
+    if (nandmcb.nand_if == NULL)
+        return (-1);
+
     origPos          = nandmcb.fpos;
     origLogicalBlock = nandmcb.currentLogicalBlock;
     origPage         = nandmcb.currentPage;
@@ -322,7 +350,7 @@ Int32 nand_peek (Uint8 *ptr_buf, Uint32 num_bytes)
     if ( (origLogicalBlock != nandmcb.currentLogicalBlock)  ||
          (origPage         != nandmcb.currentPage)  )   {
 
-            if (nandHwDriverReadPage((Uint32)(nandmcb.logicalToPhysMap[origLogicalBlock]), origPage, nandmcb.page) < 0)
+            if ((*nandmcb.nand_if->nct_driverReadPage)((Uint32)(nandmcb.logicalToPhysMap[origLogicalBlock]), origPage, nandmcb.page) < 0)
                 return (-2);
     }
     
@@ -353,7 +381,9 @@ Int32 nand_query (void)
  */
 Int32 nand_close (void)
 {
-    nandHwDriverClose ();
+    if (nandmcb.nand_if != NULL)
+        nandHwDriverClose ();
+
     return (nand_free_return (0));
 
 }
index e6ed3f6111818d00c72f0468b719278eb7c80e51..6e7540b880b856b8c0d2b805efa626a8fb0b65cd 100644 (file)
@@ -64,10 +64,10 @@ else
        else
         ifeq ($(TARGET),c661x)
          CSRC= t64.c pll.c cfgpll.c cfgpll2.c mdio.c i2c.c psc.c cpsw.c qm.c cpdma.c pa.c sgmii.c serdes.c gmacsl.c emif4.c
-         CSRC+= nandemif25.c
+         CSRC+= nandemif25.c spi.c nandspi.c
      else
       CSRC= t64.c cpmacdrv.c pll.c psc.c emif31.c mdio.c gpio.c nandgpio.c i2c.c nandwrgpio.c sgmii.c cfgpll.c cfgpll2.c
-         CSRC+= qm.c cpdma.c pa.c serdes.c gmacsl.c emif4.c nandemif25.c
+         CSRC+= qm.c cpdma.c pa.c serdes.c gmacsl.c emif4.c nandemif25.c spi.c nandspi.c
      endif
     endif
    endif
@@ -101,11 +101,13 @@ C6X_C_DIR+= ;$(IBL_ROOT)/hw/gpio
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/nands
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/nands/gpio
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/nands/emif25
+C6X_C_DIR+= ;$(IBL_ROOT)/hw/nands/spi
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/i2c
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/sgmii
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/cpsw
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/cpdma
 C6X_C_DIR+= ;$(IBL_ROOT)/hw/pa
+C6X_C_DIR+= ;$(IBL_ROOT)/hw/spi
 C6X_C_DIR+= ;$(IBL_ROOT)/ecc
 export C6X_C_DIR
 
@@ -183,6 +185,8 @@ ifeq ($(TARGET),c661x)
  vpath % $(ECODIR)/macs/cpmacsl
  vpath % $(ECODIR)/ddrs/emif4
  vpath % $(ECODIR)/nands/emif25
+ vpath % $(ECODIR)/nands/spi
+ vpath % $(ECODIR)/spi
 endif
 
 
index 3801a154ff0c4c0aeeb33faf179b75277e0bb5fc..878da613f4b2918a4667e50532404538edbc96c3 100644 (file)
@@ -158,7 +158,7 @@ Int32 nandHwDriverReadPage (Uint32 block, Uint32 page, Uint8 *data)
         v = v | (1 << (gCs + 8 - 2));
         DEVICE_REG32_W (DEVICE_EMIF25_BASE + NAND_FLASH_CTL_REG, v);
 
-        nandHwDriverReadBytes (block, page, i << 8, 256, data);
+        nandHwDriverReadBytes (block, page, i << 8, 256, blockp);
 
         /* Read the ECC value computed by the hardware */
         v = DEVICE_REG32_R (DEVICE_EMIF25_BASE + NAND_FLASH_ECC_REG(gCs));
index 8042dc92b087ef50b2afed279045af0454163ee1..44ac03a9d9e406c19fddad40c269fab5fcf7738c 100644 (file)
@@ -57,6 +57,7 @@
 #define NAND_INVALID_ADDR           -812
 #define NAND_ECC_FAILURE            -813
 #define NAND_INVALID_CS             -814
+#define NAND_READ_FAILURE           -815
 
 
 /* Information used only for programming flash */
@@ -76,7 +77,7 @@ typedef struct nandProgramInfo_s
 
 
 
-/* Driver functions */
+/* Driver functions, EMIF and GPIO interface */
 Int32 nandHwDriverInit (int32 cs, nandDevInfo_t *devInfo);
 Int32 nandHwDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
 Int32 nandHwDriverReadPage(Uint32 block, Uint32 page, Uint8 *data);
@@ -85,6 +86,12 @@ Int32 nandHwDriverClose (void);
 Int32 nandHwDriverWritePage  (Uint32 block, Uint32 page, Uint8 *data, nandProgramInfo_t *winfo);
 Int32 nandHwDriverBlockErase (Uint32 uiBlockNumber, nandProgramInfo_t *winfo);
 
+/* Driver functions, SPI interface */
+Int32 nandHwSpiDriverInit (int32 cs, nandDevInfo_t *devInfo);
+Int32 nandHwSpiDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, Uint8 *data);
+Int32 nandHwSpiDriverReadPage(Uint32 block, Uint32 page, Uint8 *data);
+Int32 nandHwSpiDriverClose (void);
+
 
 
 
diff --git a/src/hw/nands/spi/nandspi.c b/src/hw/nands/spi/nandspi.c
new file mode 100644 (file)
index 0000000..ac5560c
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 
+ * 
+ * 
+ *  Redistribution and use in source and binary forms, with or without 
+ *  modification, are permitted provided that the following conditions 
+ *  are met:
+ *
+ *    Redistributions of source code must retain the above copyright 
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ *    Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the 
+ *    documentation and/or other materials provided with the   
+ *    distribution.
+ *
+ *    Neither the name of Texas Instruments Incorporated nor the names of
+ *    its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+#include "types.h"
+#include "ibl.h"
+#include "iblcfg.h"
+#include "nandhwapi.h"
+#include "ecc.h"
+#include "target.h"
+#include "spi_api.h"
+
+nandDevInfo_t *hwSpiDevInfo;  /* Pointer to the NAND configuration */
+
+/**
+ *  @brief
+ *      Initialize the NAND SPI configuration. The SPI interface
+ *      must be initialized seperately at a higher level 
+ */
+Int32 nandHwSpiDriverInit (int32 cs, nandDevInfo_t *devInfo)
+{
+
+    hwSpiDevInfo = devInfo;
+
+    return (0);
+
+}
+
+
+/**
+ *  @brief
+ *      Read bytes without ECC correction
+ */
+Int32 nandHwSpiDriverReadBytes (Uint32 block, Uint32 page, Uint32 byte, Uint32 nbytes, uint8 *data)
+{
+    Uint32 uAddr;
+
+    uAddr = (block << hwSpiDevInfo->blockOffset) + (page << hwSpiDevInfo->pageOffset) + 
+            (byte  << hwSpiDevInfo->columnOffset);
+
+    
+    if (hwSpiRead (uAddr, nbytes, data) != 0)
+        return (-1);
+
+    return (0);
+
+}
+
+
+/**
+ *  @brief
+ *      Read a complete page of data
+ */
+Int32 nandHwSpiDriverReadPage (Uint32 block, Uint32 page, Uint8 *data)
+{
+    Int32   i;
+    Int32   nSegs;
+    Uint8  *blockp;
+    Uint8  *eccp;
+    Uint8   eccCalc[3];
+
+
+    /* Read the entire page, including the extra bytes. The array data
+     * has been sized to handle the full page */
+    if (nandHwSpiDriverReadBytes (block, page, 0, hwSpiDevInfo->pageSizeBytes + hwSpiDevInfo->pageEccBytes, data))
+        return (NAND_READ_FAILURE);
+
+
+
+    /* Break the page into segments of 256 bytes for ECC correction */
+    nSegs = hwSpiDevInfo->pageSizeBytes >> 8;
+
+    for (i = 0; i < nSegs; i++)  {
+
+        blockp = &data[i << 8];
+        eccp   = &data[hwSpiDevInfo->pageSizeBytes + hwSpiDevInfo->pageEccBytes - ((nSegs - i) * 3)];
+        eccComputeECC (blockp, eccCalc);
+
+        if (eccCorrectData (blockp, eccp, eccCalc) != ECC_SUCCESS)
+            return (NAND_ECC_FAILURE);
+
+    }
+
+    return (0);
+
+}
+
+/**
+ *  @brief
+ *      Close the driver
+ */
+int32 nandHwSpiDriverClose (void)
+{
+    return (0);
+
+}
+
+
+
+
+
diff --git a/src/hw/spi/spi.c b/src/hw/spi/spi.c
new file mode 100644 (file)
index 0000000..fb0ba45
--- /dev/null
@@ -0,0 +1,260 @@
+/**********************************************************************************************
+ * FILE PURPOSE: The SPI boot driver
+ **********************************************************************************************
+ * FILE NAME: spi.c
+ *
+ * DESCRIPTION: Implements an SPI eeprom read.
+ *
+ **********************************************************************************************/
+#include "types.h"
+#include "device.h"
+#include "spi_api.h"
+#include "spi_loc.h"
+
+typedef struct spimcb_s
+{
+    spiConfig_t spiCfg;
+
+} spimcb_t;
+
+spimcb_t spimcb;
+
+
+/**********************************************************************************************
+ * FUNCTION PURPOSE: Initialize the SPI interface
+ **********************************************************************************************
+ * DESCRIPTION: The SPI interface is setup. Only format register 0 is configured
+ **********************************************************************************************/
+SINT16 hwSpiConfig (spiConfig_t *cfg)
+{
+    UINT32 v;
+
+    if ((cfg->addrWidth != 24) && (cfg->addrWidth != 16))
+        return (SPI_INVALID_ADDR_WIDTH);
+
+    if ((cfg->npin != 4) && (cfg->npin != 5))
+        return (SPI_INVALID_NPIN);
+
+    /* Store the configuration for subsequent reads */
+    spimcb.spiCfg = *cfg;
+    
+
+    /* Reset */
+    DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIGCR0, SPI_REG_VAL_SPIGCR0_RESET);
+
+    /* Release Reset */
+    DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIGCR0, SPI_REG_VAL_SPIGCR0_ENABLE);
+
+    /* Master mode */
+    if (cfg->npin == 4)  
+        DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIPC0, SPI_REG_VAL_SPIPC0_4PIN);
+    else
+        DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIPC0, SPI_REG_VAL_SPIPC0_5PIN);
+
+    /* Format 0 register */
+    v = 0;
+    if (cfg->clkdiv > 0)
+        SPI_REG_SPIFMT_SET_PRESCALE(v, cfg->clkdiv - 1);
+    else
+        SPI_REG_SPIFMT_SET_PRESCALE(v, 0);
+
+    SPI_REG_SPIFMT_SET_CHARLEN(v, 8);
+    SPI_REG_SPIFMT_SET_MODE(v, cfg->mode);
+    SPI_REG_SPIFMT_SET_SHIFTDIR(v, SPI_REG_VAL_SPIFMT_SHIFT_MSB_FIRST);
+    DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIFMT(0), v);
+
+    /* Chip select to transmit delay */
+    v = 0;
+    SPI_REG_SPIDELAY_SET_C2T(v, cfg->c2tdelay);
+    DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIDELAY, v);
+
+
+    return (0);
+
+} /* hwSpiConfig */
+
+
+/*************************************************************************************************
+ * FUNCTION PURPOSE: Perform an SPI transfer
+ *************************************************************************************************
+ * DESCRIPTION: A bi-directional transfer is done
+ *************************************************************************************************/
+SINT16 hw_spi_xfer (UINT16 nbytes, UINT8 *dataOut, UINT8 *dataIn, spiConfig_t *cfg, BOOL terminate)
+{
+    UINT32 v;
+    UINT32 i;
+    UINT32 tcount;
+    UINT32 timeout;
+    UINT32 spidat1;
+
+
+    /* The SPIDAT1 upper 16 bits */
+    spidat1 = 0;
+    SPI_REG_SPIDAT1_SET_CSHOLD(spidat1, 1);
+    SPI_REG_SPIDAT1_SET_WDELAY(spidat1, 1);
+    SPI_REG_SPIDAT1_SET_CSNR(spidat1, cfg->csel);
+
+
+    /* The timeout is used to prevent traps. 
+     *
+     * Each bit on the SPI bus will clock in at MOD_DIVIDER * cfg->clkdiv
+     * cpu cycles. So the timeout is based on the MOD_DIVIDER * cfg->clkdiv
+     * product. The actual number of cycles the loop takes isnt known
+     * with too much accuracy since the code is in C, so assume the
+     * compiler is spectacular and condenses each loop into just one
+     * cpu cycle. In that case it would take MOD_DIVIDER * cfg->clkdiv * 8
+     * passes through the loop to get the data byte. Since the compiler
+     * is slower then that the timeout value is good. But an extra
+     * x20 is thrown in just to be safe. */
+
+    timeout = (cfg->clkdiv + 1) * 8 * 20 * DEVICE_SPI_MOD_DIVIDER;
+
+
+    /* Clear out any pending read data */
+    do  {
+        v = DEVICE_REG32_R (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIBUF);
+        v = DEVICE_REG32_R (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIFLG);
+    }  while (SPI_REG_SPIFLG_RX_DATA(v));
+
+
+    /* Perform the transfer */
+    for (i = 0; i < nbytes; i++)  {
+
+
+        /* For the last byte release the hold */
+        if ((terminate == TRUE) && (i == (nbytes - 1)))  {
+            SPI_REG_SPIDAT1_SET_CSHOLD(spidat1, 0);
+        }
+
+        tcount = 0;
+
+        do  {
+
+            v = DEVICE_REG32_R (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIFLG);
+            tcount += 1;
+
+        } while ( (SPI_REG_SPIFLG_TX_EMPTY(v) == 0) && (tcount < timeout) );
+
+        if (tcount >= timeout)  {
+
+            /* Disable transfer */
+            DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIGCR1, SPI_REG_VAL_SPIGCR1_XFER_DISABLE);
+
+            return (SPI_TIMEOUT);
+        }
+        
+        if (dataOut != NULL)
+            v = dataOut[i];
+        else
+            v = 0;
+
+
+        /* Send the data */
+        SPI_REG_SPIDAT1_SET_DATA(spidat1, v);
+        DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIDAT1, spidat1);
+
+        /* Receive the data */
+        tcount = 0;
+
+        do  {
+
+            v = DEVICE_REG32_R (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIFLG);
+            tcount += 1;
+
+        } while ( (SPI_REG_SPIFLG_RX_DATA(v) == 0) && (tcount < timeout) );
+
+        if (tcount >= timeout)  {
+
+            /* Disable transfer */
+            DEVICE_REG32_W (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIGCR1, SPI_REG_VAL_SPIGCR1_XFER_DISABLE);
+
+            return (SPI_TIMEOUT);
+        }
+
+
+        v = DEVICE_REG32_R (DEVICE_SPI_BASE(cfg->port) + SPI_REG_SPIBUF);
+
+        if (dataIn != NULL)
+            dataIn[i] = v & 0xff;
+
+
+    }
+
+    return (0);
+
+}
+
+
+
+
+/*************************************************************************************************
+ * FUNCTION PURPOSE: Read a block of data
+ *************************************************************************************************
+ * DESCRIPTION: A single data block of a fixed size is read
+ *************************************************************************************************/
+SINT16 hwSpiRead (UINT32 addr, UINT16 sizeBytes, UINT8 *data)
+{
+    UINT32 n;
+    UINT8  command[4];
+    UINT16 ret;
+
+    /* Do nothing for a read of 0 bytes */
+    if (sizeBytes == 0)
+        return (0);
+
+    /* Format the read command and address */
+    command[0] = SPI_COMMAND_READ;
+    if (spimcb.spiCfg.addrWidth == 24)  {
+        n = 4;
+        command[1] = (addr >> 16) & 0xff;
+        command[2] = (addr >>  8) & 0xff;
+        command[3] = addr & 0xff;
+
+    }  else if (spimcb.spiCfg.addrWidth == 16)  {
+        n = 3;
+        command[1] = (addr >> 8) & 0xff;
+        command[2] = addr & 0xff;
+
+    }  else  {
+        return (SPI_INVALID_ADDR_WIDTH);
+    }
+
+
+    /* Enable the device for transfer */
+    DEVICE_REG32_W (DEVICE_SPI_BASE(spimcb.spiCfg.port) + SPI_REG_SPIGCR1, SPI_REG_VAL_SPIGCR1_XFER);
+
+    /* Send the command and address */
+    ret = hw_spi_xfer (n, command, NULL, &spimcb.spiCfg, FALSE);
+    if (ret != 0)
+        return (ret);
+
+
+    /* Read the data */
+    ret = hw_spi_xfer (sizeBytes, NULL, data, &spimcb.spiCfg, TRUE);
+    if (ret != 0)
+        return (ret);
+
+
+    DEVICE_REG32_W (DEVICE_SPI_BASE(spimcb.spifg.port) + SPI_REG_SPIGCR1, SPI_REG_VAL_SPIGCR1_XFER_DISABLE);
+    return (0);
+
+}
+
+
+    
+
+
+
+        
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/hw/spi/spi_api.h b/src/hw/spi/spi_api.h
new file mode 100644 (file)
index 0000000..6a80a79
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _SPI_API_H
+#define _SPI_API_H
+/*****************************************************************************************************
+ * FILE PURPOSE: Define the boot SPI driver
+ *****************************************************************************************************
+ * DESCRIPTION: The SPI API is defined
+ *
+ *****************************************************************************************************/
+typedef struct spiConfig_s  {
+
+  UINT16 port;
+  UINT16 mode;
+  UINT16 addrWidth;
+  UINT16 npin;
+  UINT16 csel;
+  UINT16 clkdiv;
+  UINT16 c2tdelay;
+  
+} spiConfig_t;
+
+SINT16 hwSpiConfig (spiConfig_t *spiCfg);
+SINT16 hwSpiRead (UINT32 addr, UINT16 sizeBytes, UINT8 *data);
+
+/* Return values */
+#define SPI_INVALID_ADDR_WIDTH  -1
+#define SPI_INVALID_NPIN        -2
+#define SPI_TIMEOUT             -3
+#define SPI_NOT_ENOUGH_BYTES    -4
+
+
+
+
+
+#endif /* _SPI_API_H */
+
+
+
+
diff --git a/src/hw/spi/spi_loc.h b/src/hw/spi/spi_loc.h
new file mode 100644 (file)
index 0000000..296a72f
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _SPI_LOC_H
+#define _SPI_LOC_H
+/************************************************************************************************
+ * FILE PURPOSE: LOCAL SPI definitions
+ ************************************************************************************************
+ * FILE NAME: spi_loc.h
+ *
+ * DESCRIPTION: Defines the SPI hardware operation
+ *
+ ************************************************************************************************/
+
+/* Register offsets */
+#define SPI_REG_SPIGCR0         0x00
+#define SPI_REG_SPIGCR1         0x04
+#define SPI_REG_SPIFLG          0x10
+#define SPI_REG_SPIPC0          0x14
+#define SPI_REG_SPIDAT1         0x3c
+#define SPI_REG_SPIBUF          0x40
+#define SPI_REG_SPIDELAY        0x48
+#define SPI_REG_SPIFMT(x)       (0x50 + ((x)*4))
+    
+/* Register values */    
+#define SPI_REG_VAL_SPIGCR0_RESET           0x0
+#define SPI_REG_VAL_SPIGCR0_ENABLE          0x1
+
+#define SPI_REG_VAL_SPIGCR1_XFER            0x01000003
+#define SPI_REG_VAL_SPIGCR1_XFER_DISABLE    0
+
+#define SPI_REG_SPIFLG_TX_EMPTY(v)  ((v) & 0x0200)
+#define SPI_REG_SPIFLG_RX_DATA(v)   ((v) & 0x0100)
+
+#define SPI_REG_VAL_SPIPC0_4PIN     0x01010e01  /* 1 pin input, 1 pin output, clock, cs0 */
+#define SPI_REG_VAL_SPIPC0_5PIN     0x01010e03  /* Same as 3 pin with cs1 as well */
+
+#define SPI_REG_SPIFMT_SET_PRESCALE(v, dev)   (v) = BOOT_SET_BITFIELD((v),dev,  15,  8)
+#define SPI_REG_SPIFMT_SET_CHARLEN(v, wid)    (v) = BOOT_SET_BITFIELD((v),wid,   4,  0)
+#define SPI_REG_SPIFMT_SET_MODE(v, mode)      (v) = BOOT_SET_BITFIELD((v),mode, 17, 16)
+#define SPI_REG_SPIFMT_SET_SHIFTDIR(v, dir)   (v) = BOOT_SET_BITFIELD((v),dir,  20, 20)
+
+#define SPI_REG_VAL_SPIFMT_SHIFT_MSB_FIRST    0
+
+
+#define SPI_REG_SPIDELAY_SET_C2T(v, delay)    (v) = BOOT_SET_BITFIELD((v), delay, 31, 24)
+
+
+#define SPI_REG_SPIDAT1_SET_CSHOLD(v, hold)   (v) = BOOT_SET_BITFIELD((v), hold, 28, 28)
+#define SPI_REG_SPIDAT1_SET_WDELAY(v, delay)  (v) = BOOT_SET_BITFIELD((v), delay, 26, 26)
+#define SPI_REG_SPIDAT1_SET_CSNR(v, csel)     (v) = BOOT_SET_BITFIELD((v), csel, 23, 16)
+#define SPI_REG_SPIDAT1_SET_DATA(v, data)     (v) = BOOT_SET_BITFIELD((v), data, 15,  0)
+
+
+/* Commands */
+#define SPI_COMMAND_READ    3
+
+#endif /* _SPI_LOC_H */
index 0ab5f75c59ed16d6f911c97eeceb2336f07febf1..d09fbfabf0f3e89e3a9b22b510281eedeb907d71 100644 (file)
--- a/src/ibl.h
+++ b/src/ibl.h
@@ -466,13 +466,58 @@ typedef struct iblNand_s
 
     uint32   nandPriority;      /**< The nand boot priority. @ref iblPeriphPriority */
     int32    bootFormat;        /**< The format of the boot data file. @ref iblBootFormats */                            
-    int32    cs;                /**< The nand chip select space */
+    int32    interface;         /**< The nand interface @ref iblNandIf */
     iblBinBlob_t blob;          /**< Used only if the format is ibl_BOOT_FORMAT_BBLOB */
     
     
     nandDevInfo_t nandInfo;     /** Low level device info */
 
 } iblNand_t;
+
+/**
+ * @defgroup iblNandIf defines the interface used for NAND memory. Not all values
+ *           are valid for all devices.
+ *
+ * @ingroup iblNandIf
+ * @{
+ */
+/** @def ibl_NAND_IF_GPIO - GPIO interface */
+#define  ibl_NAND_IF_GPIO           0
+
+/** @def ibl_NAND_IF_CHIPSEL_2 - EMIF interface using chip select 2 */
+#define  ibl_NAND_IF_CHIPSEL_2      2
+
+/** @def ibl_NAND_IF_CHIPSEL_3 - EMIF interface using chip select 3 */
+#define ibl_NAND_IF_CHIPSEL_3       3
+
+/** @def ibl_NAND_IF_CHIPSEL_4 - EMIF interface using chip select 4 */
+#define ibl_NAND_IF_CHIPSEL_4       4
+
+/** @def ibl_NAND_IF_CHIPSEL_5 - EMIF interface using chip select 5 */
+#define ibl_NAND_IF_CHIPSEL_5       5
+
+/** @def ibl_NAND_IF_SPI - NAND interface through SPI */
+#define  ibl_NAND_IF_SPI            100
+
+
+/* @} */
+
+
+/**
+ *  @brief
+ *      SPI configuration used for either NOR or NAND
+ */
+typedef struct iblSpi_s
+{
+    int16  addrWidth;       /**<  16 or 24 are the only valid values */
+    int16  nPins;           /**<  4 or 5 are the only valid values */
+    int16  mode;            /**<  Clock / data polarities (valid values 0-3) */
+    int16  csel;            /**<  Chip select value (5 pin). Only 0b10 and 0b01 are valid */
+    uint16 c2tdelay;        /**<  Setup time between chip select and the transaction */
+    uint16 busFreqMHz;      /**<  Bus speed */
+    
+} iblSpi_t;
+    
     
     
 /**
@@ -561,11 +606,10 @@ typedef struct ibl_s
     
     iblNand_t nandConfig;                    /**< NAND configuration @ref iblNand_t */
     
-    uint16    chkSum;                        /**< Ones complement checksum over the whole config structure */
+    iblSpi_t  spiConfig;                     /**< SPI configuration @ref iblSpi_s */
     
+    uint16    chkSum;                        /**< Ones complement checksum over the whole config structure */
     
-/*    iblI2c_t  i2cConfig;  */
-/*    iblSpi_t  spiConfig;  */
     
      
 } ibl_t;
@@ -621,6 +665,11 @@ extern ibl_t ibl;
  */
 #define ibl_FAIL_CODE_PA                    702     /**< Packet Accelerator setup failed */
    
+   
+/**
+ *  @def ibl_FAIL_CODE_SPI_PARAMS
+ */
+#define ibl_FAIL_CODE_SPI_PARAMS            703     /**< Invalid SPI configuration found */
 
  
  /* @} */
index 0e81aebf0666d5b2d1bcfee8e5342b040beac6f3..c39999962a4b3a140fb67e7ed42c06734569b5a9 100644 (file)
@@ -239,6 +239,7 @@ void iblSwap (void)
 
     ibl.nandConfig.nandPriority       = swap32val (ibl.nandConfig.nandPriority);
     ibl.nandConfig.bootFormat         = swap32val (ibl.nandConfig.bootFormat);
+    ibl.nandConfig.interface          = swap32val (ibl.nandConfig.interface);
     ibl.nandConfig.blob.startAddress  = swap32val (ibl.nandConfig.blob.startAddress);
     ibl.nandConfig.blob.sizeBytes     = swap32val (ibl.nandConfig.blob.sizeBytes);
     ibl.nandConfig.blob.branchAddress = swap32val (ibl.nandConfig.blob.branchAddress);
@@ -255,6 +256,12 @@ void iblSwap (void)
     ibl.nandConfig.nandInfo.columnOffset  = swap32val (ibl.nandConfig.nandInfo.columnOffset);
     ibl.nandConfig.nandInfo.postCommand   = swap16val (ibl.nandConfig.nandInfo.postCommand);
 
+    ibl.spiConfig.addrWidth  = swap16val (ibl.spiConfig.addrWidth);
+    ibl.spiConfig.nPins      = swap16val (ibl.spiConfig.nPins);
+    ibl.spiConfig.csel       = swap16val (ibl.spiConfig.csel);
+    ibl.spiConfig.c2tdelay   = swap16val (ibl.spiConfig.c2tdelay);
+    ibl.spiConfig.busFreqMHz = swap16val (ibl.spiConfig.busFreqMHz);
+
     ibl.chkSum = swap16val (ibl.chkSum);
 }
 
index a6108f1a1437d4e89209e9f22ef8d308976cf333..67c6a38a93528ae2d7beda0296a58d6964c3b7a4 100644 (file)
@@ -146,6 +146,10 @@ evm_c6457:
        make -f makestg1 ARCH=c64x TARGET=c6457 I2C_BUS_ADDR=0x51 COMPACT_I2C=yes ENDIAN_MODE=big EXCLUDES='ELF NAND BIS' I2C_SIZE_BYTES=0x8000 c6457
        cp ibl_c6457/i2crom.dat ibl_c6457/i2crom_0x51.dat
 
+# The 6618 EVM
+evm_c6618:
+       make -f makestg1 ARCH=c64x TARGET=c661x I2C_BUS_ADDR=0x50 ENDIAN_MODE=little EXCLUDES= DEBUG=YES c661x
+
 # Test - builds all the targets, with single component exclusion
 test_build:
        make -f makestg1 ARCH=c64x TARGET=c6455 I2C_BUS_ADDR=0x50 COMPACT_I2C=no ENDIAN_MODE=both EXCLUDES=     c6455
index ae2b82e3e5df95787eb95558911a80507027d466..c619ddc0b3b0b36dc908791be8046b3efe91dc7f 100644 (file)
 
 #ifndef EXCLUDE_NAND
 ../nandboot/c64x/make/nandboot.ENDIAN_TAG.oc
-../hw/c64x/make/nandemif25.ENDIAN_TAG.oc
 ../driver/c64x/make/nand.ENDIAN_TAG.oc
 ../ecc/c64x/make/3byte_ecc.ENDIAN_TAG.oc
+
+ #ifndef EXCLUDE_NAND_EMIF
+ ../hw/c64x/make/nandemif25.ENDIAN_TAG.oc
+ #endif
+
+ #ifndef EXCLUDE_NAND_SPI
+  ../hw/c64x/make/nandspi.ENDIAN_TAG.oc
+ #endif
+
+#endif
+
+#ifndef EXCLUDE_SPI
+../hw/c64x/make/spi.ENDIAN_TAG.oc
 #endif
index 0443787a7e97410e25f4be274cc2ff8c45259220..63b69434d92493beeb4e20a5e88cbed28a92b9db 100644 (file)
@@ -23,7 +23,8 @@ endif
 # The PLL object files are device specific
 PLL_PATH= ../../hw/c64x/make
 ifeq ($(TARGET),c661x)
- PLL_OBJS= $(PLL_PATH)/pll.$(IEXT).oc $(PLL_PATH)/cfgpll.$(IEXT).oc $(PLL_PATH)/cfgpll2.$(IEXT).oc
+ PLL_OBJS=  $(PLL_PATH)/pll.$(IEXT).oc $(PLL_PATH)/cfgpll.$(IEXT).oc $(PLL_PATH)/cfgpll2.$(IEXT).oc
+ PLL_OBJS+= ../../device/c64x/make/c64x.$(IEXT).oa
 else
  PLL_OBJS= $(PLL_PATH)/pll.$(IEXT).oc
 endif
index 77e3288a29d3fcd364062fb2881ea8290d99278c..ab47afb4607fde77f7a0e0034fd113e8bd69a12d 100644 (file)
@@ -24,7 +24,8 @@ endif
 # The PLL object files are device specific
 PLL_PATH= ../../hw/c64x/make
 ifeq ($(TARGET),c661x)
- PLL_OBJS= $(PLL_PATH)/pll.$(IEXT).oc $(PLL_PATH)/cfgpll.$(IEXT).oc $(PLL_PATH)/cfgpll2.$(IEXT).oc
+ PLL_OBJS=  $(PLL_PATH)/pll.$(IEXT).oc $(PLL_PATH)/cfgpll.$(IEXT).oc $(PLL_PATH)/cfgpll2.$(IEXT).oc
+ PLL_OBJS+= ../../device/c64x/make/c64x.$(IEXT).oa
 else
  PLL_OBJS= $(PLL_PATH)/pll.$(IEXT).oc
 endif