BeRTOS
|
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 }