norflash.c

Go to the documentation of this file.
00001 /***************************************************************************/
00020 #include "em_common.h"
00021 #include "em_ebi.h"
00022 #include "norflash.h"
00023 
00026 static volatile uint16_t     *flashBase;
00027 static bool                  flashInitialized = false;
00028 static NORFLASH_Info_TypeDef flashInfo;
00029 
00030 static int  flashInterrogate(void);
00031 static int  flashPoll(uint32_t addr, uint16_t data);
00032 static void flashReset(void);
00033 static void flashUnlockCmd(void);
00034 static int  flashWriteBuffer(uint32_t sectorAddr, uint32_t addr,
00035                              uint16_t *data, uint32_t count);
00036 
00039 /***************************************************************************/
00049 bool NORFLASH_AddressValid(uint32_t addr)
00050 {
00051   if (!flashInitialized)
00052   {
00053     if (flashInterrogate() != NORFLASH_STATUS_OK)
00054       return false;
00055   }
00056 
00057   if ((addr >= flashInfo.baseAddress) &&
00058       (addr < (flashInfo.baseAddress + flashInfo.deviceSize)))
00059     return true;
00060 
00061   return false;
00062 }
00063 
00064 /***************************************************************************/
00074 NORFLASH_Info_TypeDef *NORFLASH_DeviceInfo(void)
00075 {
00076   if (!flashInitialized)
00077   {
00078     if (flashInterrogate() != NORFLASH_STATUS_OK)
00079       return NULL;
00080   }
00081 
00082   return &flashInfo;
00083 }
00084 
00085 /***************************************************************************/
00093 int NORFLASH_EraseDevice(void)
00094 {
00095   int status;
00096 
00097   if (!flashInitialized)
00098   {
00099     status = flashInterrogate();
00100 
00101     if (status != NORFLASH_STATUS_OK)
00102       return status;
00103   }
00104 
00105   flashUnlockCmd();
00106 
00107   flashBase[0x555] = 0x80;
00108   flashBase[0x555] = 0xAA;
00109   flashBase[0x2AA] = 0x55;
00110   flashBase[0x555] = 0x10;
00111 
00112   return flashPoll(flashInfo.baseAddress, 0xFFFF);
00113 }
00114 
00115 /***************************************************************************/
00126 int NORFLASH_EraseSector(uint32_t addr)
00127 {
00128   int status;
00129 
00130   if (!flashInitialized)
00131   {
00132     status = flashInterrogate();
00133 
00134     if (status != NORFLASH_STATUS_OK)
00135       return status;
00136   }
00137 
00138   if (!NORFLASH_AddressValid(addr))
00139   {
00140     EFM_ASSERT(false);
00141     return NORFLASH_INVALID_ADDRESS;
00142   }
00143 
00144   /* Mask off LSB's according to sectorsize to get sector start address */
00145   addr = addr & ~(flashInfo.sectorSize - 1);
00146 
00147   flashUnlockCmd();
00148 
00149   flashBase[0x555] = 0x80;
00150   flashBase[0x555] = 0xAA;
00151   flashBase[0x2AA] = 0x55;
00152 
00153   *(volatile uint16_t*) addr = 0x30;
00154 
00155   return flashPoll(addr, 0xFFFF);
00156 }
00157 
00158 /***************************************************************************/
00170 int NORFLASH_Init(void)
00171 {
00172   return flashInterrogate();
00173 }
00174 
00175 /***************************************************************************/
00195 int NORFLASH_Program(uint32_t addr, uint8_t *data, uint32_t count)
00196 {
00197   int      status;
00198   uint32_t sectorAddress, burst;
00199 
00200   if (!flashInitialized)
00201   {
00202     status = flashInterrogate();
00203 
00204     if (status != NORFLASH_STATUS_OK)
00205       return status;
00206   }
00207 
00208   if (!NORFLASH_AddressValid(addr) ||
00209       !NORFLASH_AddressValid(addr + count - 1))
00210   {
00211     EFM_ASSERT(false);
00212     return NORFLASH_INVALID_ADDRESS;
00213   }
00214 
00215   /* Check if odd byte aligned */
00216   if (addr & 1)
00217   {
00218     status = NORFLASH_ProgramByte(addr, *data);
00219 
00220     if (status != NORFLASH_STATUS_OK)
00221       return status;
00222 
00223     addr++;
00224     data++;
00225     count--;
00226   }
00227 
00228   while (count >= 2)
00229   {
00230 #if 0     /* Traditional write method, write one word at a time */
00231     status = NORFLASH_ProgramWord16(addr, (*(data + 1) << 8) | *data);
00232 
00233     if (status != NORFLASH_STATUS_OK)
00234       return status;
00235 
00236     addr  += 2;
00237     data  += 2;
00238     count -= 2;
00239 
00240 #else     /* "Write Buffer" write method */
00241     sectorAddress = addr & ~(flashInfo.sectorSize - 1);
00242 
00243     /* Max 32 "words" at a time, must not cross sector boundary */
00244     burst = EFM32_MIN(64U, sectorAddress + flashInfo.sectorSize - addr);
00245     burst = EFM32_MIN(burst, count & 0xFFFFFFFE);
00246 
00247     status = flashWriteBuffer(sectorAddress, addr, (uint16_t*) data, burst);
00248 
00249     if (status != NORFLASH_STATUS_OK)
00250       return status;
00251 
00252     addr  += burst;
00253     data  += burst;
00254     count -= burst;
00255 #endif
00256 
00257   }
00258 
00259   /* Check if a trailing odd byte aligned value must be programmed */
00260   if (count)
00261   {
00262     status = NORFLASH_ProgramByte(addr, *data);
00263   }
00264 
00265   return status;
00266 }
00267 
00268 /***************************************************************************/
00285 int NORFLASH_ProgramByte(uint32_t addr, uint8_t data)
00286 {
00287   uint16_t tmp;
00288 
00289   tmp = *(volatile uint16_t*)(addr & 0xFFFFFFFE);
00290   if (addr & 1)
00291   {
00292     tmp = (tmp & 0xFF) | (data << 8);
00293   }
00294   else
00295   {
00296     tmp = (tmp & 0xFF00) | data;
00297   }
00298 
00299   return NORFLASH_ProgramWord16(addr & 0xFFFFFFFE, tmp);
00300 }
00301 
00302 /***************************************************************************/
00319 int NORFLASH_ProgramWord16(uint32_t addr, uint16_t data)
00320 {
00321   int status;
00322 
00323   if (!flashInitialized)
00324   {
00325     status = flashInterrogate();
00326 
00327     if (status != NORFLASH_STATUS_OK)
00328       return status;
00329   }
00330 
00331   if (!NORFLASH_AddressValid(addr) ||
00332       !NORFLASH_AddressValid(addr + 1))
00333   {
00334     EFM_ASSERT(false);
00335     return NORFLASH_INVALID_ADDRESS;
00336   }
00337 
00338   if (addr & 1)
00339     return NORFLASH_MISALIGNED_ADDRESS;
00340 
00341   flashUnlockCmd();
00342   flashBase[0x555] = 0xA0;
00343 
00344   *(volatile uint16_t*) addr = data;
00345 
00346   return flashPoll(addr, data);
00347 }
00348 
00349 /***************************************************************************/
00366 int NORFLASH_ProgramWord32(uint32_t addr, uint32_t data)
00367 {
00368   int status;
00369 
00370   if (addr & 3)
00371     return NORFLASH_MISALIGNED_ADDRESS;
00372 
00373   status = NORFLASH_ProgramWord16(addr, data & 0xFFFF);
00374 
00375   if (status == NORFLASH_STATUS_OK)
00376   {
00377     addr  += 2;
00378     status = NORFLASH_ProgramWord16(addr, data >> 16);
00379   }
00380 
00381   return status;
00382 }
00383 
00386 /***************************************************************************/
00395 static int flashInterrogate(void)
00396 {
00397   flashInfo.baseAddress = EBI_BankAddress(EBI_BANK3);
00398   flashBase             = (volatile uint16_t*) flashInfo.baseAddress;
00399 
00400   flashReset();
00401 
00402   flashUnlockCmd();
00403   flashBase[0x555] = 0x90;      /* Autoselect command */
00404 
00405   /* Read device info */
00406   flashInfo.manufacturerId = flashBase[0x00];
00407   flashInfo.deviceId       = (flashBase[0x01] & 0xFF) << 16;
00408   flashInfo.deviceId      |= (flashBase[0x0E] & 0xFF) << 8;
00409   flashInfo.deviceId      |= flashBase[0x0F] & 0xFF;
00410 
00411   flashReset();
00412 
00413   flashBase[0x55] = 0x98;       /* CFI query command */
00414 
00415   /* Check for CFI compliant device */
00416   if ((flashBase[0x10] != 'Q') ||
00417       (flashBase[0x11] != 'R') ||
00418       (flashBase[0x12] != 'Y'))
00419   {
00420     flashReset();
00421     return NORFLASH_NOT_CFI_DEVICE;
00422   }
00423 
00424   /* Get device geometry info, flash sector region count */
00425   if (flashBase[0x2C] != 1)
00426   {
00427     flashReset();
00428     return NORFLASH_NONUNIFORM_GEOMETRY;
00429   }
00430 
00431   flashInfo.deviceSize   = flashBase[0x27];
00432   flashInfo.deviceSize   = 1 << flashInfo.deviceSize;
00433   flashInfo.sectorCount  = flashBase[0x2D];
00434   flashInfo.sectorCount |= (flashBase[0x2E] << 8) & 0xFF00;
00435   flashInfo.sectorSize   = flashBase[0x2F];
00436   flashInfo.sectorSize  |= (flashBase[0x30] << 8) & 0xFF00;
00437 
00438   flashInfo.sectorCount += 1;
00439   flashInfo.sectorSize  *= 256;
00440 
00441   flashReset();
00442 
00443   flashInitialized = true;
00444 
00445   return NORFLASH_STATUS_OK;
00446 }
00447 
00448 /***************************************************************************/
00469 static int flashPoll(uint32_t addr, uint16_t data)
00470 {
00471   #define TOGGLE_BIT     0x40
00472   #define TIMEOUT_BIT    0x20
00473 
00474   int      i = 0;
00475   uint16_t flashData1, flashData2, flashData3;
00476 
00477   if ((flashData1 = *(volatile uint16_t*) addr) == data)
00478     return NORFLASH_STATUS_OK;
00479 
00480   if ((flashData2 = *(volatile uint16_t*) addr) == data)
00481     return NORFLASH_STATUS_OK;
00482 
00483   while (1)
00484   {
00485     if ((flashData3 = *(volatile uint16_t*) addr) == data)
00486       return NORFLASH_STATUS_OK;
00487 
00488     if ((((flashData1 ^ flashData2) & TOGGLE_BIT) == TOGGLE_BIT) &&
00489         (((flashData2 ^ flashData3) & TOGGLE_BIT) == TOGGLE_BIT) &&
00490         ((flashData1 & TIMEOUT_BIT) == TIMEOUT_BIT))
00491     {
00492       /* DQ6 is still toggling and DQ5 (timeout) is set */
00493       flashReset();
00494       return NORFLASH_WRITE_TIMEOUT;
00495     }
00496 
00497     if ((((flashData1 ^ flashData2) & TOGGLE_BIT) != TOGGLE_BIT) ||
00498         (((flashData2 ^ flashData3) & TOGGLE_BIT) != TOGGLE_BIT))
00499     {
00500       /* DQ6 has stopped toggling */
00501       if (*(volatile uint16_t*) addr == data)
00502         return NORFLASH_STATUS_OK;
00503 
00504       /* Code will typically end here if attempting to program a 0 to a 1 */
00505       flashReset();
00506       return NORFLASH_WRITE_FAILURE;
00507     }
00508 
00509     flashData1 = flashData2;
00510     flashData2 = flashData3;
00511     i++;
00512   }
00513   #undef TOGGLE_BIT
00514   #undef TIMEOUT_BIT
00515 }
00516 
00517 /***************************************************************************/
00521 static void flashReset(void)
00522 {
00523   flashBase[0] = 0xF0;
00524 }
00525 
00526 /***************************************************************************/
00530 static void flashUnlockCmd(void)
00531 {
00532   flashBase[0x555] = 0xAA;
00533   flashBase[0x2AA] = 0x55;
00534 }
00535 
00536 /***************************************************************************/
00556 static int flashWriteBuffer(uint32_t sectorAddr,
00557                             uint32_t addr,
00558                             uint16_t *data,
00559                             uint32_t count)
00560 {
00561   uint32_t          i;
00562   volatile uint16_t *pDst;
00563 
00564   pDst  = (volatile uint16_t*) addr;
00565   count = (count / 2) - 1;
00566 
00567   flashUnlockCmd();
00568   *(volatile uint16_t*) sectorAddr = 0x25;         /* Write buffer command */
00569   *(volatile uint16_t*) sectorAddr = count;        /* Word16count - 1      */
00570   for (i = 0; i <= count; i++)
00571   {
00572     *pDst++ = *data++;
00573   }
00574   *(volatile uint16_t*) sectorAddr = 0x29;         /* Write confirm        */
00575 
00576   pDst--;
00577   data--;
00578   return flashPoll((uint32_t) pDst, *data);
00579 }
00580