A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPIFI.cpp Source File

SPIFI.cpp

00001 /*
00002  *  Copyright 2013 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 #include "SPIFI.h"
00018 #include "mbed_debug.h"
00019 
00020 
00021 /******************************************************************************
00022  * Defines and typedefs
00023  *****************************************************************************/
00024 
00025 #define SPIFI_DBG             0
00026 
00027 /* 
00028  * The SPIFI_ROM_PTR (0x1FFF1FF8) points to an area where the pointers to
00029  * different drivers in ROM are stored.
00030  */
00031 typedef struct {
00032    /*const*/ unsigned p_usbd;     // USBROMD 
00033    /*const*/ unsigned p_clib;
00034    /*const*/ unsigned p_cand;
00035    /*const*/ unsigned p_pwrd;     // PWRROMD
00036    /*const*/ unsigned p_promd;    // DIVROMD
00037    /*const*/ SPIFI_RTNS *pSPIFID; // SPIFIROMD
00038    /*const*/ unsigned p_dev3;
00039    /*const*/ unsigned p_dev4; 
00040 } ROM;
00041 
00042 #define ROM_DRIVERS_PTR ((ROM *)(*((unsigned int *)SPIFI_ROM_PTR)))
00043 #define IS_ADDR_IN_SPIFI(__addr)  ( (((uint32_t)(__addr)) & 0xff000000) == SPIFI_MEM_BASE )
00044 
00045 #define SPIFI_MIN(__a, __b) (((__a) < (__b)) ? (__a) : (__b))
00046 
00047 /******************************************************************************
00048  * Local variables
00049  *****************************************************************************/
00050 
00051 /******************************************************************************
00052  * Private Functions
00053  *****************************************************************************/
00054 
00055 SPIFI::SpifiError SPIFI::translateError(int err, bool verify)
00056 {  
00057   SpifiError res;
00058   
00059   _verError = 0;
00060   
00061   if (err == 0)
00062   {
00063     res = Ok;
00064   }
00065   else if ((err >= Uninitialized) && (err <= UnknownError))
00066   {
00067     // This is a known error code
00068     res = (SpifiError)err;
00069   }
00070   else if ((err >= InternalError) && (err <= EraseConflict))
00071   {
00072     // This is a known error code
00073     res = (SpifiError)err;
00074   }
00075   else if (verify)
00076   {
00077     // As verification was selected and err is not in the list of known
00078     // codes this falls into this category in the User's Manual:
00079     //
00080     // "Other non-zero values can occur if options selects verification.
00081     //  They will be the address in the SPIFI memory area at which the
00082     //  first discrepancy was found."
00083     _verError = err;
00084     res = Verification;
00085   }
00086   else
00087   {
00088     // Should never happen :-) as all listed error codes are covered but
00089     // to be on the safe side and not interpret this as a success, a generic
00090     // error is set.
00091     res = UnknownError;
00092   }
00093   return res;
00094 }
00095 
00096 /******************************************************************************
00097  * Public Functions
00098  *****************************************************************************/
00099 
00100 SPIFI::SPIFI()
00101 {
00102   _verError       = 0;
00103   _initialized    = false;
00104   _device         = UnknownDevice;
00105   _memorySize     = 0;
00106   _eraseBlockSize = 0;
00107   
00108   _romData = (SPIFIobj*)malloc(sizeof(SPIFIobj));
00109   if (_romData == NULL) {
00110     debug("SPIFI: Failed to allocate memory for ROM data\n");
00111   }
00112 }
00113 
00114 SPIFI::~SPIFI()
00115 {
00116   if (_romData != NULL) {
00117     free(_romData);
00118   }
00119 }
00120 
00121 SPIFI::SpifiError SPIFI::init()
00122 {
00123   if (!_initialized) {
00124     
00125     // Turn on SPIFI block as it is disabled on reset
00126     LPC_SC->PCONP |= 0x00010000;
00127 
00128     // pinsel for SPIFI
00129     LPC_IOCON->P2_7 = 5; /* SPIFI_CSN @ P2.7 */
00130     LPC_IOCON->P0_22 = 5; /* SPIFI_CLK @ P0.22 */
00131     LPC_IOCON->P0_15 = 5; /* SPIFI_IO2 @ P0.15 */
00132     LPC_IOCON->P0_16 = 5; /* SPIFI_IO3 @ P0.16 */
00133     LPC_IOCON->P0_17 = 5; /* SPIFI_IO1 @ P0.17 */
00134     LPC_IOCON->P0_18 = 5; /* SPIFI_IO0 @ P0.18 */
00135     
00136     uint32_t spifi_clk_div = (*((volatile uint32_t*)0x400FC1B4)) & 0x1f;
00137     uint32_t spifi_clk_mhz = (SystemCoreClock / spifi_clk_div) / 1000000;
00138 
00139     _spifi = ROM_DRIVERS_PTR->pSPIFID;
00140 
00141     /* Typical time tCS is 20 ns min, we give 200 ns to be on safer side */
00142     int rc = _spifi->spifi_init (_romData, spifi_clk_mhz/5, S_FULLCLK+S_RCVCLK, spifi_clk_mhz);
00143     if (rc) {
00144       _spifi = NULL;
00145       return translateError(rc);
00146     }
00147 
00148     /* Make sure it is a tested flash module */
00149     if ((_romData->mfger == 1) && (_romData->devType == 0x2) && (_romData->devID == 0x15) && (_romData->memSize > 0x100000)) 
00150     {
00151       _device = Spansion_S25FL032;
00152       _memorySize = _romData->memSize;
00153       _eraseBlockSize = 64*1024;
00154     } 
00155     else if ((_romData->mfger == 0xef) && (_romData->devType == 0x40) && (_romData->devID == 0x17) && (_romData->memSize > 0x100000))
00156     {
00157       _device = Winbond_W25Q64FV;
00158       _memorySize = _romData->memSize;
00159       _eraseBlockSize = 4*1024;
00160     } 
00161     else if ((_romData->mfger == 0xc2) && (_romData->devType == 0x20) && (_romData->devID == 0x17) && (_romData->memSize > 0x100000))
00162     {
00163       _device = Macronix_MX25L6435EM2I;
00164       _memorySize = _romData->memSize;
00165       _eraseBlockSize = 4*1024;
00166     } 
00167     else 
00168     {
00169       debug("SPIFI::init(): Memory is unknown and may not work as expected\n");
00170       
00171       // Asuming it has 64Kb erase blocks (i.e. same setup as the Spansion S25FL032
00172       _device = UnknownDevice;
00173       _memorySize = _romData->memSize;
00174       _eraseBlockSize = 64*1024;
00175 
00176       /*
00177        * If this happens, check the manufacturer and device information
00178        * and compare with the data sheet for your chip. Also make sure
00179        * that the sector sizes are the same (i.e. 64KB) for your chip.
00180        * If everything is the same then add an exception for your chip.
00181        */
00182     }
00183     
00184     _initialized = true;
00185   }
00186   return Ok;
00187 }
00188 
00189 SPIFI::SpifiError SPIFI::program(uint32_t dest, unsigned len, char* src, Options options, bool verify, char* scratch)
00190 {
00191   unsigned written = 0;
00192   SPIFIopers opers;
00193   opers.dest = (char *)dest;
00194   opers.length = SPIFI_MIN(len, PROG_SIZE);
00195   opers.scratch = scratch;
00196   opers.protect = 0;
00197   opers.options = options;
00198   if (verify) {
00199     opers.options |= S_VERIFY_PROG;
00200   }
00201   
00202   if (IS_ADDR_IN_SPIFI(src))
00203   {
00204     // The SPIFI ROM driver cannot write data from SPIFI into
00205     // SPIFI (i.e. cannot read and write at the same time).
00206     // The workaround is to copy the source data into a buffer
00207     // in local memory and use that as source for the write
00208     // instead.
00209     while (written < len) {
00210       memcpy(_addrConflictBuff, src + written, opers.length);
00211       int rc = _spifi->spifi_program(_romData, _addrConflictBuff, &opers);
00212       if (rc) 
00213       {
00214         // got an error
00215         return translateError(rc, verify);
00216       }
00217       written += opers.length;
00218       opers.dest += opers.length;
00219       opers.length = SPIFI_MIN(len - written, PROG_SIZE);
00220     }
00221   }
00222   else 
00223   {
00224     while (written < len) {
00225       int rc = _spifi->spifi_program(_romData, src + written, &opers);
00226       if (rc) 
00227       {
00228         // got an error
00229         return translateError(rc, verify);
00230       }
00231       written += opers.length;
00232       opers.dest += opers.length;
00233       opers.length = SPIFI_MIN(len - written, PROG_SIZE);
00234     }
00235   }
00236   
00237   return Ok;
00238 }
00239 
00240 SPIFI::SpifiError SPIFI::erase(uint32_t dest, unsigned len, char* src, bool verify, char* scratch)
00241 {
00242   SPIFIopers opers;
00243   opers.dest = (char *)dest;
00244   opers.length = len;
00245   opers.scratch = scratch;
00246   opers.protect = 0;
00247   if (verify) {
00248     opers.options = S_VERIFY_ERASE;
00249   } else {
00250     opers.options = S_NO_VERIFY;
00251   }
00252   int rc = _spifi->spifi_erase(_romData, &opers);
00253   return translateError(rc);
00254 }
00255 
00256