00001
00041 #include "flash_lpc2.h"
00042 #include "cfg/cfg_emb_flash.h"
00043
00044
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
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
00200 uint32_t addr = idx * blk->blk_size;
00201 uint32_t sector = addr_to_sector(addr);
00202
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
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 }