BeRTOS
flash_lpc2.c
Go to the documentation of this file.
00001 
00041 #include "flash_lpc2.h"
00042 #include "cfg/cfg_emb_flash.h"
00043 
00044 // Define log settings for cfg/log.h
00045 #define LOG_LEVEL    CONFIG_FLASH_EMB_LOG_LEVEL
00046 #define LOG_FORMAT   CONFIG_FLASH_EMB_LOG_FORMAT
00047 #include <cfg/log.h>
00048 #include <cfg/macros.h>
00049 
00050 #include <cpu/irq.h>
00051 #include <cpu/attr.h>
00052 #include <cpu/power.h>
00053 #include <cpu/types.h>
00054 
00055 #include <io/kblock.h>
00056 #include <io/arm.h>
00057 
00058 #include <drv/timer.h>
00059 #include <drv/flash.h>
00060 
00061 #include <struct/bitarray.h>
00062 
00063 #include <string.h>
00064 
00065 /* Embedded flash programming defines. */
00066 #define IAP_ADDRESS 0x7ffffff1
00067 
00068 typedef enum IapCommands
00069 {
00070     PREPARE_SECTOR_FOR_WRITE = 50,
00071     COPY_RAM_TO_FLASH = 51,
00072     ERASE_SECTOR = 52,
00073     BLANK_CHECK_SECTOR = 53,
00074     READ_PART_ID = 54,
00075     READ_BOOT_VER = 55,
00076     COMPARE = 56,
00077     REINVOKE_ISP = 57,
00078 } IapCommands;
00079 
00080 #if CPU_ARM_LPC2378
00081     #define FLASH_MEM_SIZE         (504 * 1024L)
00082     #define FLASH_PAGE_SIZE_BYTES          4096
00083     #define FLASH_REAL_PAGE_CNT              28
00084 #else
00085     #error Unknown CPU
00086 #endif
00087 
00088 #define CMD_SUCCESS 0
00089 
00090 struct FlashHardware
00091 {
00092     uint8_t status;
00093     int flags;
00094 };
00095 
00096 #define FLASH_PAGE_CNT  FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES
00097 
00098 BITARRAY_ALLOC(page_dirty, FLASH_PAGE_CNT);
00099 static BitArray lpc2_bitx;
00100 
00101 uint8_t erase_group[] = {
00102 
00103     4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES,
00104     4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES,
00105 
00106     4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES,
00107     4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES,
00108 
00109     32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES,
00110     32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES,
00111 
00112     32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES,
00113     32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES,
00114 
00115     32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES,
00116     32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES,
00117 
00118     32768 / FLASH_PAGE_SIZE_BYTES, 32768 / FLASH_PAGE_SIZE_BYTES,
00119     4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES,
00120 
00121     4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES,
00122     4096 / FLASH_PAGE_SIZE_BYTES, 4096 / FLASH_PAGE_SIZE_BYTES,
00123 };
00124 
00125 typedef struct IapCmd
00126 {
00127     uint32_t cmd;
00128     uint32_t param[4];
00129 } IapCmd;
00130 
00131 typedef struct IapRes
00132 {
00133     uint32_t status;
00134     uint32_t res[2];
00135 } IapRes;
00136 
00137 typedef void (*iap_callback_t)(IapCmd *, IapRes *);
00138 
00139 iap_callback_t iap = (iap_callback_t)IAP_ADDRESS;
00140 
00141 static size_t sector_size(uint32_t page)
00142 {
00143     if (page < 8)
00144         return 4096;
00145     else if (page < 22)
00146         return 32768;
00147     else if (page < 28)
00148         return 4096;
00149 
00150     ASSERT(0);
00151     return 0;
00152 }
00153 
00154 static size_t sector_addr(uint32_t page)
00155 {
00156     if (page < 8)
00157         return page * 4096;
00158     else if (page < 22)
00159         return (page - 8) * 32768 + 4096 * 8;
00160     else if (page < 28)
00161         return (page - 22) * 4096 + 32768 * 14 + 4096 * 8;
00162 
00163     ASSERT(0);
00164     return 0;
00165 }
00166 
00167 
00168 static uint32_t addr_to_sector(size_t addr)
00169 {
00170     if (addr < 4096 * 8)
00171         return addr / 4096;
00172     else if (addr < 4096 * 8 + 32768L * 14)
00173         return ((addr - 4096 * 8) / 32768) + 8;
00174     else if (addr < 4096 * 8 + 32768L * 14 + 4096 * 6)
00175         return ((addr - 4096 * 8 - 32768L * 14) / 4096) + 22;
00176 
00177     ASSERT(0);
00178     return 0;
00179 }
00180 
00181 static size_t lpc2_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
00182 {
00183     memcpy(buf, (void *)(idx * blk->blk_size + offset), size);
00184     return size;
00185 }
00186 
00187 static size_t lpc2_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
00188 {
00189     ASSERT(offset == 0);
00190     ASSERT(FLASH_PAGE_SIZE_BYTES == size);
00191 
00192     Flash *fls = FLASH_CAST(blk);
00193     if (!(fls->hw->flags & FLASH_WRITE_ONCE))
00194         ASSERT(sector_size(idx) <= FLASH_PAGE_SIZE_BYTES);
00195 
00196     const uint8_t *buf = (const uint8_t *)_buf;
00197     cpu_flags_t flags;
00198 
00199     //Compute page address of current page.
00200     uint32_t addr = idx * blk->blk_size;
00201     uint32_t sector = addr_to_sector(addr);
00202     // Compute the first page index in the sector to manage the status
00203     int idx_sector = sector_addr(sector) /  blk->blk_size;
00204 
00205     LOG_INFO("Writing page[%ld]sector[%ld]idx[%d]\n", idx, sector, idx_sector);
00206     IRQ_SAVE_DISABLE(flags);
00207 
00208     IapCmd cmd;
00209     IapRes res;
00210     cmd.cmd = PREPARE_SECTOR_FOR_WRITE;
00211     cmd.param[0] = cmd.param[1] = sector;
00212     iap(&cmd, &res);
00213 
00214     if (res.status != CMD_SUCCESS)
00215         goto flash_error;
00216 
00217     if ((fls->hw->flags & FLASH_WRITE_ONCE) &&
00218             bitarray_isRangeFull(&lpc2_bitx, idx_sector, erase_group[sector]))
00219     {
00220         kputs("blocchi pieni\n");
00221         ASSERT(0);
00222         goto flash_error;
00223     }
00224 
00225     bool erase = false;
00226     if ((fls->hw->flags & FLASH_WRITE_ONCE) &&
00227             bitarray_isRangeEmpty(&lpc2_bitx, idx_sector, erase_group[sector]))
00228         erase = true;
00229 
00230     if (!(fls->hw->flags & FLASH_WRITE_ONCE))
00231         erase = true;
00232 
00233     if (erase)
00234     {
00235         cmd.cmd = ERASE_SECTOR;
00236         cmd.param[0] = cmd.param[1] = sector;
00237         cmd.param[2] = CPU_FREQ / 1000;
00238         iap(&cmd, &res);
00239 
00240         if (res.status != CMD_SUCCESS)
00241             goto flash_error;
00242     }
00243 
00244     LOG_INFO("Writing page [%ld], addr [%ld] in sector[%ld]\n", idx, addr, sector);
00245     cmd.cmd = PREPARE_SECTOR_FOR_WRITE;
00246     cmd.param[0] = cmd.param[1] = sector;
00247     iap(&cmd, &res);
00248 
00249     if (res.status != CMD_SUCCESS)
00250         goto flash_error;
00251 
00252     if (fls->hw->flags & FLASH_WRITE_ONCE)
00253     {
00254         if (bitarray_test(&lpc2_bitx, idx))
00255         {
00256             ASSERT(0);
00257             goto flash_error;
00258         }
00259         else
00260             bitarray_set(&lpc2_bitx, idx);
00261     }
00262 
00263     cmd.cmd = COPY_RAM_TO_FLASH;
00264     cmd.param[0] = addr;
00265     cmd.param[1] = (uint32_t)buf;
00266     cmd.param[2] = FLASH_PAGE_SIZE_BYTES;
00267     cmd.param[3] = CPU_FREQ / 1000;
00268     iap(&cmd, &res);
00269 
00270     if (res.status != CMD_SUCCESS)
00271         goto flash_error;
00272 
00273     IRQ_RESTORE(flags);
00274     LOG_INFO("Done\n");
00275 
00276     return blk->blk_size;
00277 
00278 flash_error:
00279     IRQ_RESTORE(flags);
00280     LOG_ERR("%ld\n", res.status);
00281     fls->hw->status |= FLASH_WR_ERR;
00282     return 0;
00283 }
00284 
00285 static int lpc2_flash_close(UNUSED_ARG(struct KBlock, *blk))
00286 {
00287     memset(page_dirty, 0, sizeof(page_dirty));
00288     return 0;
00289 }
00290 
00291 
00292 static int lpc2_flash_error(struct KBlock *blk)
00293 {
00294     Flash *fls = FLASH_CAST(blk);
00295     return fls->hw->status;
00296 }
00297 
00298 static void lpc2_flash_clearerror(struct KBlock *blk)
00299 {
00300     Flash *fls = FLASH_CAST(blk);
00301     fls->hw->status = 0;
00302 }
00303 
00304 static const KBlockVTable flash_lpc2_buffered_vt =
00305 {
00306     .readDirect = lpc2_flash_readDirect,
00307     .writeDirect = lpc2_flash_writeDirect,
00308 
00309     .readBuf = kblock_swReadBuf,
00310     .writeBuf = kblock_swWriteBuf,
00311     .load = kblock_swLoad,
00312     .store = kblock_swStore,
00313 
00314     .close = lpc2_flash_close,
00315 
00316     .error = lpc2_flash_error,
00317     .clearerr = lpc2_flash_clearerror,
00318 };
00319 
00320 static const KBlockVTable flash_lpc2_unbuffered_vt =
00321 {
00322     .readDirect = lpc2_flash_readDirect,
00323     .writeDirect = lpc2_flash_writeDirect,
00324 
00325     .close = lpc2_flash_close,
00326 
00327     .error = lpc2_flash_error,
00328     .clearerr = lpc2_flash_clearerror,
00329 };
00330 
00331 static struct FlashHardware flash_lpc2_hw;
00332 static uint8_t flash_buf[FLASH_PAGE_SIZE_BYTES];
00333 
00334 static void common_init(Flash *fls, int flags)
00335 {
00336     memset(fls, 0, sizeof(*fls));
00337     DB(fls->blk.priv.type = KBT_FLASH);
00338 
00339     fls->hw = &flash_lpc2_hw;
00340     fls->hw->flags = flags;
00341 
00342     fls->blk.blk_size = FLASH_PAGE_SIZE_BYTES;
00343     fls->blk.blk_cnt = FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES;
00344 
00345     bitarray_init(&lpc2_bitx, FLASH_PAGE_CNT, page_dirty, sizeof(page_dirty));
00346 }
00347 
00348 void flash_hw_init(Flash *fls, int flags)
00349 {
00350     common_init(fls, flags);
00351     fls->blk.priv.vt = &flash_lpc2_buffered_vt;
00352     fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
00353     fls->blk.priv.buf = flash_buf;
00354 
00355 
00356     /* Load the first block in the cache */
00357     void *flash_start = 0x0;
00358     memcpy(fls->blk.priv.buf, flash_start, fls->blk.blk_size);
00359 }
00360 
00361 void flash_hw_initUnbuffered(Flash *fls, int flags)
00362 {
00363     common_init(fls, flags);
00364     fls->blk.priv.vt = &flash_lpc2_unbuffered_vt;
00365 }