flash_at91.c
Go to the documentation of this file.
00001
00040 #include "flash_at91.h"
00041
00042 #include "cfg/cfg_emb_flash.h"
00043 #include <cfg/macros.h>
00044
00045 // Define log settings for cfg/log.h
00046 #define LOG_LEVEL    CONFIG_FLASH_EMB_LOG_LEVEL
00047 #define LOG_FORMAT   CONFIG_FLASH_EMB_LOG_FORMAT
00048 #include <cfg/log.h>
00049
00050 #include <cpu/irq.h>
00051 #include <cpu/attr.h>
00052 #include <cpu/power.h>
00053
00054 #include <io/kfile.h>
00055 #include <io/kblock.h>
00056 #include <io/arm.h>
00057
00058 #include <drv/timer.h>
00059 #include <drv/flash.h>
00060
00061 #include <string.h>
00062
00063 struct FlashHardware
00064 {
00065     uint8_t status;
00066 };
00067
00068
00076 RAM_FUNC NOINLINE static void write_page(uint32_t page)
00077 {
00078     reg32_t *fcr, *fsr;
00079
00080     #if CPU_ARM_AT91SAM7S512 || CPU_ARM_AT91SAM7X512
00081     if (page >= (FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES / 2))
00082     {
00083         fcr = &MC_FCR1;
00084         fsr = &MC_FSR1;
00085         page &= 0x3FF;
00086     }
00087     else
00088     #endif
00089     {
00090         fcr = &MC_FCR;
00091         fsr = &MC_FSR;
00092     }
00093
00094     // Send the 'write page' command
00095     *fcr = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
00096
00097     // Wait for the end of command
00098     while(!(*fsr & BV(MC_FRDY)))
00099     {
00100         //NOP;
00101     }
00102 }
00103
00104
00111 INLINE void flash_sendWRcmd(uint32_t page)
00112 {
00113     cpu_flags_t flags;
00114
00115     LOG_INFO("Writing page %ld...\n", page);
00116
00117     IRQ_SAVE_DISABLE(flags);
00118     write_page(page);
00119
00120     IRQ_RESTORE(flags);
00121     LOG_INFO("Done\n");
00122 }
00123
00128 static bool flash_getStatus(struct KBlock *blk)
00129 {
00130     Flash *fls = FLASH_CAST(blk);
00131     /*
00132      * This bit is set to one if an invalid command and/or a bad keywords was/were
00133      * written in the Flash Command Register.
00134      */
00135     if(MC_FSR & BV(MC_PROGE))
00136     {
00137         fls->hw->status |= FLASH_WR_ERR;
00138         LOG_ERR("flash not erased..\n");
00139         return false;
00140     }
00141
00142     /*
00143      * This bit is set to one if we programming of at least one locked lock
00144      * region.
00145      */
00146     if(MC_FSR & BV(MC_LOCKE))
00147     {
00148         fls->hw->status |= FLASH_WR_PROTECT;
00149         LOG_ERR("wr protect..\n");
00150         return false;
00151     }
00152     #if CPU_ARM_AT91SAM7X512 || CPU_ARM_AT91SAM7S512
00153         /* Check also EFC1 for larger devices */
00154         if(MC_FSR1 & BV(MC_PROGE))
00155         {
00156             fls->hw->status |= FLASH_WR_ERR;
00157             LOG_ERR("flash not erased..\n");
00158             return false;
00159         }
00160
00161         if(MC_FSR1 & BV(MC_LOCKE))
00162         {
00163             fls->hw->status |= FLASH_WR_PROTECT;
00164             LOG_ERR("wr protect..\n");
00165             return false;
00166         }
00167
00168     #endif
00169 
00170     return true;
00171 }
00172
00173 static size_t at91_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
00174 {
00175     memcpy(buf, (void *)(idx * blk->blk_size +  FLASH_BASE + offset), size);
00176     return size;
00177 }
00178
00179 static size_t at91_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
00180 {
00181     ASSERT(offset == 0);
00182     ASSERT(size == blk->blk_size);
00183
00184     uint32_t *addr = (uint32_t *)(idx * blk->blk_size +  FLASH_BASE);
00185     const uint8_t *buf = (const uint8_t *)_buf;
00186
00187     while (size)
00188     {
00189         uint32_t data = (*(buf + 3) << 24) |
00190                         (*(buf + 2) << 16) |
00191                         (*(buf + 1) << 8)  |
00192                         *buf;
00193         *addr = data;
00194
00195         size -= 4;
00196         buf += 4;
00197         addr++;
00198     }
00199
00200     flash_sendWRcmd(idx);
00201
00202     if (!flash_getStatus(blk))
00203         return 0;
00204
00205     return blk->blk_size;
00206 }
00207
00208
00209 static int at91_flash_error(struct KBlock *blk)
00210 {
00211     Flash *fls = FLASH_CAST(blk);
00212     return fls->hw->status;
00213 }
00214
00215 static void at91_flash_clearerror(struct KBlock *blk)
00216 {
00217     Flash *fls = FLASH_CAST(blk);
00218     fls->hw->status = 0;
00219 }
00220
00221 static const KBlockVTable flash_at91_buffered_vt =
00222 {
00223     .readDirect = at91_flash_readDirect,
00224     .writeDirect = at91_flash_writeDirect,
00225
00226     .readBuf = kblock_swReadBuf,
00227     .writeBuf = kblock_swWriteBuf,
00228     .load = kblock_swLoad,
00229     .store = kblock_swStore,
00230
00231     .error = at91_flash_error,
00232     .clearerr = at91_flash_clearerror,
00233 };
00234
00235 static const KBlockVTable flash_at91_unbuffered_vt =
00236 {
00237     .readDirect = at91_flash_readDirect,
00238     .writeDirect = at91_flash_writeDirect,
00239
00240     .error = at91_flash_error,
00241     .clearerr = at91_flash_clearerror,
00242 };
00243
00244 static struct FlashHardware flash_at91_hw;
00245 static uint8_t flash_buf[FLASH_PAGE_SIZE_BYTES];
00246
00247 static void common_init(Flash *fls)
00248 {
00249     memset(fls, 0, sizeof(*fls));
00250     DB(fls->blk.priv.type = KBT_FLASH);
00251
00252     fls->hw = &flash_at91_hw;
00253
00254     fls->blk.blk_size = FLASH_PAGE_SIZE_BYTES;
00255     fls->blk.blk_cnt = FLASH_MEM_SIZE / FLASH_PAGE_SIZE_BYTES;
00256 }
00257
00258 void flash_hw_init(Flash *fls, UNUSED_ARG(int, flags))
00259 {
00260     common_init(fls);
00261     fls->blk.priv.vt = &flash_at91_buffered_vt;
00262     fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
00263     fls->blk.priv.buf = flash_buf;
00264
00265     /* Load the first block in the cache */
00266     memcpy(fls->blk.priv.buf, (void *)(FLASH_BASE), fls->blk.blk_size);
00267 }
00268
00269 void flash_hw_initUnbuffered(Flash *fls, UNUSED_ARG(int, flags))
00270 {
00271     common_init(fls);
00272     fls->blk.priv.vt = &flash_at91_unbuffered_vt;
00273 }
00274