norflash.c

Go to the documentation of this file.
00001 /***************************************************************************/
00038 #include "em_common.h"
00039 #include "em_ebi.h"
00040 #include "norflash.h"
00041 
00044 static volatile uint16_t     *flashBase;
00045 static bool                  flashInitialized = false;
00046 static NORFLASH_Info_TypeDef flashInfo;
00047 
00048 static int  flashInterrogate(void);
00049 static int  flashPoll(uint32_t addr, uint16_t data);
00050 static void flashReset(void);
00051 static void flashUnlockCmd(void);
00052 static int  flashWriteBuffer(uint32_t sectorAddr, uint32_t addr,
00053                              uint16_t *data, uint32_t count);
00054 
00057 /***************************************************************************/
00067 bool NORFLASH_AddressValid(uint32_t addr)
00068 {
00069   if (!flashInitialized)
00070   {
00071     if (flashInterrogate() != NORFLASH_STATUS_OK)
00072       return false;
00073   }
00074 
00075   if ((addr >= flashInfo.baseAddress) &&
00076       (addr < (flashInfo.baseAddress + flashInfo.deviceSize)))
00077     return true;
00078 
00079   return false;
00080 }
00081 
00082 /***************************************************************************/
00092 NORFLASH_Info_TypeDef *NORFLASH_DeviceInfo(void)
00093 {
00094   if (!flashInitialized)
00095   {
00096     if (flashInterrogate() != NORFLASH_STATUS_OK)
00097       return NULL;
00098   }
00099 
00100   return &flashInfo;
00101 }
00102 
00103 /***************************************************************************/
00111 int NORFLASH_EraseDevice(void)
00112 {
00113   int status;
00114 
00115   if (!flashInitialized)
00116   {
00117     status = flashInterrogate();
00118 
00119     if (status != NORFLASH_STATUS_OK)
00120       return status;
00121   }
00122 
00123   flashUnlockCmd();
00124 
00125   flashBase[0x555] = 0x80;
00126   flashBase[0x555] = 0xAA;
00127   flashBase[0x2AA] = 0x55;
00128   flashBase[0x555] = 0x10;
00129 
00130   return flashPoll(flashInfo.baseAddress, 0xFFFF);
00131 }
00132 
00133 /***************************************************************************/
00144 int NORFLASH_EraseSector(uint32_t addr)
00145 {
00146   int status;
00147 
00148   if (!flashInitialized)
00149   {
00150     status = flashInterrogate();
00151 
00152     if (status != NORFLASH_STATUS_OK)
00153       return status;
00154   }
00155 
00156   if (!NORFLASH_AddressValid(addr))
00157   {
00158     EFM_ASSERT(false);
00159     return NORFLASH_INVALID_ADDRESS;
00160   }
00161 
00162   /* Mask off LSB's according to sectorsize to get sector start address */
00163   addr = addr & ~(flashInfo.sectorSize - 1);
00164 
00165   flashUnlockCmd();
00166 
00167   flashBase[0x555] = 0x80;
00168   flashBase[0x555] = 0xAA;
00169   flashBase[0x2AA] = 0x55;
00170 
00171   *(volatile uint16_t*) addr = 0x30;
00172 
00173   return flashPoll(addr, 0xFFFF);
00174 }
00175 
00176 /***************************************************************************/
00188 int NORFLASH_Init(void)
00189 {
00190   return flashInterrogate();
00191 }
00192 
00193 /***************************************************************************/
00213 int NORFLASH_Program(uint32_t addr, uint8_t *data, uint32_t count)
00214 {
00215   int      status;
00216   uint32_t sectorAddress, burst;
00217 
00218   if (!flashInitialized)
00219   {
00220     status = flashInterrogate();
00221 
00222     if (status != NORFLASH_STATUS_OK)
00223       return status;
00224   }
00225 
00226   if (!NORFLASH_AddressValid(addr) ||
00227       !NORFLASH_AddressValid(addr + count - 1))
00228   {
00229     EFM_ASSERT(false);
00230     return NORFLASH_INVALID_ADDRESS;
00231   }
00232 
00233   /* Check if odd byte aligned */
00234   if (addr & 1)
00235   {
00236     status = NORFLASH_ProgramByte(addr, *data);
00237 
00238     if (status != NORFLASH_STATUS_OK)
00239       return status;
00240 
00241     addr++;
00242     data++;
00243     count--;
00244   }
00245 
00246   while (count >= 2)
00247   {
00248 #if 0     /* Traditional write method, write one word at a time */
00249     status = NORFLASH_ProgramWord16(addr, (*(data + 1) << 8) | *data);
00250 
00251     if (status != NORFLASH_STATUS_OK)
00252       return status;
00253 
00254     addr  += 2;
00255     data  += 2;
00256     count -= 2;
00257 
00258 #else     /* "Write Buffer" write method */
00259     sectorAddress = addr & ~(flashInfo.sectorSize - 1);
00260 
00261     /* Max 32 "words" at a time, must not cross sector boundary */
00262     burst = EFM32_MIN(64U, sectorAddress + flashInfo.sectorSize - addr);
00263     burst = EFM32_MIN(burst, count & 0xFFFFFFFE);
00264 
00265     status = flashWriteBuffer(sectorAddress, addr, (uint16_t*) data, burst);
00266 
00267     if (status != NORFLASH_STATUS_OK)
00268       return status;
00269 
00270     addr  += burst;
00271     data  += burst;
00272     count -= burst;
00273 #endif
00274 
00275   }
00276 
00277   /* Check if a trailing odd byte aligned value must be programmed */
00278   if (count)
00279   {
00280     status = NORFLASH_ProgramByte(addr, *data);
00281   }
00282 
00283   return status;
00284 }
00285 
00286 /***************************************************************************/
00303 int NORFLASH_ProgramByte(uint32_t addr, uint8_t data)
00304 {
00305   uint16_t tmp;
00306 
00307   tmp = *(volatile uint16_t*)(addr & 0xFFFFFFFE);
00308   if (addr & 1)
00309   {
00310     tmp = (tmp & 0xFF) | (data << 8);
00311   }
00312   else
00313   {
00314     tmp = (tmp & 0xFF00) | data;
00315   }
00316 
00317   return NORFLASH_ProgramWord16(addr & 0xFFFFFFFE, tmp);
00318 }
00319 
00320 /***************************************************************************/
00337 int NORFLASH_ProgramWord16(uint32_t addr, uint16_t data)
00338 {
00339   int status;
00340 
00341   if (!flashInitialized)
00342   {
00343     status = flashInterrogate();
00344 
00345     if (status != NORFLASH_STATUS_OK)
00346       return status;
00347   }
00348 
00349   if (!NORFLASH_AddressValid(addr) ||
00350       !NORFLASH_AddressValid(addr + 1))
00351   {
00352     EFM_ASSERT(false);
00353     return NORFLASH_INVALID_ADDRESS;
00354   }
00355 
00356   if (addr & 1)
00357     return NORFLASH_MISALIGNED_ADDRESS;
00358 
00359   flashUnlockCmd();
00360   flashBase[0x555] = 0xA0;
00361 
00362   *(volatile uint16_t*) addr = data;
00363 
00364   return flashPoll(addr, data);
00365 }
00366 
00367 /***************************************************************************/
00384 int NORFLASH_ProgramWord32(uint32_t addr, uint32_t data)
00385 {
00386   int status;
00387 
00388   if (addr & 3)
00389     return NORFLASH_MISALIGNED_ADDRESS;
00390 
00391   status = NORFLASH_ProgramWord16(addr, data & 0xFFFF);
00392 
00393   if (status == NORFLASH_STATUS_OK)
00394   {
00395     addr  += 2;
00396     status = NORFLASH_ProgramWord16(addr, data >> 16);
00397   }
00398 
00399   return status;
00400 }
00401 
00404 /***************************************************************************/
00413 static int flashInterrogate(void)
00414 {
00415   flashInfo.baseAddress = EBI_BankAddress(EBI_BANK3);
00416   flashBase             = (volatile uint16_t*) flashInfo.baseAddress;
00417 
00418   flashReset();
00419 
00420   flashUnlockCmd();
00421   flashBase[0x555] = 0x90;      /* Autoselect command */
00422 
00423   /* Read device info */
00424   flashInfo.manufacturerId = flashBase[0x00];
00425   flashInfo.deviceId       = (flashBase[0x01] & 0xFF) << 16;
00426   flashInfo.deviceId      |= (flashBase[0x0E] & 0xFF) << 8;
00427   flashInfo.deviceId      |= flashBase[0x0F] & 0xFF;
00428 
00429   flashReset();
00430 
00431   flashBase[0x55] = 0x98;       /* CFI query command */
00432 
00433   /* Check for CFI compliant device */
00434   if ((flashBase[0x10] != 'Q') ||
00435       (flashBase[0x11] != 'R') ||
00436       (flashBase[0x12] != 'Y'))
00437   {
00438     flashReset();
00439     return NORFLASH_NOT_CFI_DEVICE;
00440   }
00441 
00442   /* Get device geometry info, flash sector region count */
00443   if (flashBase[0x2C] != 1)
00444   {
00445     flashReset();
00446     return NORFLASH_NONUNIFORM_GEOMETRY;
00447   }
00448 
00449   flashInfo.deviceSize   = flashBase[0x27];
00450   flashInfo.deviceSize   = 1 << flashInfo.deviceSize;
00451   flashInfo.sectorCount  = flashBase[0x2D];
00452   flashInfo.sectorCount |= (flashBase[0x2E] << 8) & 0xFF00;
00453   flashInfo.sectorSize   = flashBase[0x2F];
00454   flashInfo.sectorSize  |= (flashBase[0x30] << 8) & 0xFF00;
00455 
00456   flashInfo.sectorCount += 1;
00457   flashInfo.sectorSize  *= 256;
00458 
00459   flashReset();
00460 
00461   flashInitialized = true;
00462 
00463   return NORFLASH_STATUS_OK;
00464 }
00465 
00466 /***************************************************************************/
00487 static int flashPoll(uint32_t addr, uint16_t data)
00488 {
00489   #define TOGGLE_BIT     0x40
00490   #define TIMEOUT_BIT    0x20
00491 
00492   int      i = 0;
00493   uint16_t flashData1, flashData2, flashData3;
00494 
00495   if ((flashData1 = *(volatile uint16_t*) addr) == data)
00496     return NORFLASH_STATUS_OK;
00497 
00498   if ((flashData2 = *(volatile uint16_t*) addr) == data)
00499     return NORFLASH_STATUS_OK;
00500 
00501   while (1)
00502   {
00503     if ((flashData3 = *(volatile uint16_t*) addr) == data)
00504       return NORFLASH_STATUS_OK;
00505 
00506     if ((((flashData1 ^ flashData2) & TOGGLE_BIT) == TOGGLE_BIT) &&
00507         (((flashData2 ^ flashData3) & TOGGLE_BIT) == TOGGLE_BIT) &&
00508         ((flashData1 & TIMEOUT_BIT) == TIMEOUT_BIT))
00509     {
00510       /* DQ6 is still toggling and DQ5 (timeout) is set */
00511       flashReset();
00512       return NORFLASH_WRITE_TIMEOUT;
00513     }
00514 
00515     if ((((flashData1 ^ flashData2) & TOGGLE_BIT) != TOGGLE_BIT) ||
00516         (((flashData2 ^ flashData3) & TOGGLE_BIT) != TOGGLE_BIT))
00517     {
00518       /* DQ6 has stopped toggling */
00519       if (*(volatile uint16_t*) addr == data)
00520         return NORFLASH_STATUS_OK;
00521 
00522       /* Code will typically end here if attempting to program a 0 to a 1 */
00523       flashReset();
00524       return NORFLASH_WRITE_FAILURE;
00525     }
00526 
00527     flashData1 = flashData2;
00528     flashData2 = flashData3;
00529     i++;
00530   }
00531   #undef TOGGLE_BIT
00532   #undef TIMEOUT_BIT
00533 }
00534 
00535 /***************************************************************************/
00539 static void flashReset(void)
00540 {
00541   flashBase[0] = 0xF0;
00542 }
00543 
00544 /***************************************************************************/
00548 static void flashUnlockCmd(void)
00549 {
00550   flashBase[0x555] = 0xAA;
00551   flashBase[0x2AA] = 0x55;
00552 }
00553 
00554 /***************************************************************************/
00574 static int flashWriteBuffer(uint32_t sectorAddr,
00575                             uint32_t addr,
00576                             uint16_t *data,
00577                             uint32_t count)
00578 {
00579   uint32_t          i;
00580   volatile uint16_t *pDst;
00581 
00582   pDst  = (volatile uint16_t*) addr;
00583   count = (count / 2) - 1;
00584 
00585   flashUnlockCmd();
00586   *(volatile uint16_t*) sectorAddr = 0x25;         /* Write buffer command */
00587   *(volatile uint16_t*) sectorAddr = count;        /* Word16count - 1      */
00588   for (i = 0; i <= count; i++)
00589   {
00590     *pDst++ = *data++;
00591   }
00592   *(volatile uint16_t*) sectorAddr = 0x29;         /* Write confirm        */
00593 
00594   pDst--;
00595   data--;
00596   return flashPoll((uint32_t) pDst, *data);
00597 }
00598