A board support package for the LPC4088 Display Module.

Dependencies:   DM_HttpServer DM_USBHost

Dependents:   lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more

Fork of DMSupport by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPIFI.cpp Source File

SPIFI.cpp

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