4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2009 Develer S.r.l. (http://www.develer.com/)
33 * \author Daniele Basile <asterix@develer.com>
35 * \brief At91sam7 Internal flash read/write driver.
40 #include "flash_at91.h"
42 #include "cfg/cfg_flash_at91.h"
43 #include <cfg/macros.h>
45 #include "hw/hw_boot.h"
47 // Define log settings for cfg/log.h
48 #define LOG_LEVEL CONFIG_FLASH_AT91_LOG_LEVEL
49 #define LOG_FORMAT CONFIG_FLASH_AT91_LOG_FORMAT
55 #include <cpu/power.h>
57 #include <kern/kfile.h>
61 #include <drv/timer.h>
66 * Check if flash memory is ready to accept other commands.
68 RAM_FUNC static bool flash_at91_isReady(void)
70 return (MC_FSR & BV(MC_FRDY));
76 * After WR command cpu write bufferd page into flash memory.
78 RAM_FUNC static void flash_at91_sendWRcmd(uint32_t page)
82 // Wait for end of command
83 while(!flash_at91_isReady())
88 IRQ_SAVE_DISABLE(flags);
90 // Send the 'write page' command
91 MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
93 // Wait for end of command
94 while(!flash_at91_isReady())
103 * Return 0 if no error are occurred after flash memory
104 * read or write operation, otherwise return error code.
106 RAM_FUNC static int flash_at91_getStatus(struct KFile *_fd)
112 * This bit is set to one if we programming of at least one locked lock
115 if(MC_FSR & BV(MC_LOCKE))
119 * This bit is set to one if an invalid command and/or a bad keywords was/were
120 * written in the Flash Command Register.
122 if(MC_FSR & BV(MC_PROGE))
130 * Write modified page on internal latch, and then send write command to
131 * flush page to internal flash.
133 RAM_FUNC static void flash_at91_flush(FlashAt91 *fd)
137 //Compute page address of current page.
138 arm_page_addr_t *addr = (arm_page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE);
140 //Copy modified page into internal latch.
141 for (arm_page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
144 memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
149 // Send write command to transfer page from latch to internal flash memory.
150 flash_at91_sendWRcmd(fd->curr_page);
155 * Flush At91 flash function.
157 * Write current buffered page in flash memory (if modified).
158 * This function erase flash memory page before writing.
160 static int flash_at91_kfileFlush(struct KFile *_fd)
162 FlashAt91 *fd = FLASHAT91_CAST(_fd);
163 flash_at91_flush(fd);
169 * Check current page and if \a page is different, load it in
172 static void flash_at91_loadPage(FlashAt91 *fd, arm_page_t page)
174 if (page != fd->curr_page)
176 flash_at91_flush(fd);
178 memcpy(fd->page_buf, (const char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
179 fd->curr_page = page;
180 LOG_INFO("Loaded page %lu\n", fd->curr_page);
186 * Write program memory.
187 * Write \a size bytes from buffer \a _buf to file \a fd
188 * \note Write operations are buffered.
190 static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
192 FlashAt91 *fd = FLASHAT91_CAST(_fd);
193 const uint8_t *buf =(const uint8_t *)_buf;
196 arm_page_addr_t page_addr;
197 size_t total_write = 0;
199 size = MIN((kfile_off_t)size, (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
201 LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos);
204 page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
205 page_addr = (fd->fd.seek_pos - FLASH_BASE) % FLASH_PAGE_SIZE_BYTES;
207 flash_at91_loadPage(fd, page);
209 size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr));
211 memcpy(fd->page_buf + page_addr, buf, wr_len);
212 fd->page_dirty = true;
215 fd->fd.seek_pos += wr_len;
217 total_write += wr_len;
219 LOG_INFO("written %u bytes\n", total_write);
226 static int flash_at91_close(struct KFile *_fd)
228 FlashAt91 *fd = FLASHAT91_CAST(_fd);
229 flash_at91_flush(fd);
230 LOG_INFO("Flash file closed\n");
236 * Open flash file \a fd
237 * \a name and \a mode are unused, cause flash memory is
238 * threated like one file.
240 static void flash_at91_open(struct FlashAt91 *fd)
242 fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
243 fd->fd.seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
244 fd->curr_page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
246 memcpy(fd->page_buf, (const char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
248 fd->page_dirty = false;
249 LOG_INFO("Flash file opened\n");
254 * Move \a fd file seek position of \a offset bytes from \a whence.
257 static kfile_off_t flash_at91_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
259 FlashAt91 *fd = FLASHAT91_CAST(_fd);
260 kfile_off_t seek_pos;
266 seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
269 seek_pos = fd->fd.size;
272 seek_pos = fd->fd.seek_pos;
280 #if LOG_LEVEL >= LOG_LVL_INFO
282 if (seek_pos + offset > fd->fd.size)
283 LOG_INFO("seek outside EOF\n");
286 fd->fd.seek_pos = seek_pos + offset;
288 return fd->fd.seek_pos - (FLASH_BASE + FLASH_BOOT_SIZE);
294 static struct KFile *flash_at91_reopen(struct KFile *_fd)
296 FlashAt91 *fd = FLASHAT91_CAST(_fd);
297 flash_at91_close(_fd);
304 * Read from file \a fd \a size bytes and put it in buffer \a buf
305 * \return the number of bytes read.
307 static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
309 FlashAt91 *fd = FLASHAT91_CAST(_fd);
310 uint8_t *buf =(uint8_t *)_buf;
312 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
314 LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
316 // Flush current buffered page (if modified).
317 flash_at91_flush(fd);
319 uint32_t *addr = (uint32_t *)fd->fd.seek_pos;
320 memcpy(buf, (uint8_t *)addr, size);
322 fd->fd.seek_pos += size;
324 LOG_INFO("Read %u bytes\n", size);
330 * Init module to perform write and read operation on internal
333 void flash_at91_init(FlashAt91 *fd)
335 memset(fd, 0, sizeof(*fd));
336 DB(fd->fd._type = KFT_FLASHAT91);
338 // Set up flash programming functions.
339 fd->fd.reopen = flash_at91_reopen;
340 fd->fd.close = flash_at91_close;
341 fd->fd.write = flash_at91_write;
342 fd->fd.read = flash_at91_read;
343 fd->fd.seek = flash_at91_seek;
344 fd->fd.error = flash_at91_getStatus;
345 fd->fd.flush = flash_at91_kfileFlush;
354 * Compute values to insert into mode register.
357 /* main clocks in 1.5uS */
358 fmcn = (CPU_FREQ/1000000ul) + (CPU_FREQ/2000000ul) + 1;
360 /* hard overclocking */
364 /* Only allow fmcn=0 if clock period is > 30 us = 33kHz. */
365 if (CPU_FREQ <= 33333ul)
368 /* Only allow fws=0 if clock frequency is < 30 MHz. */
369 if (CPU_FREQ > 30000000ul)
374 // Set wait states and number of MCK cycles in 1.5 usecs
375 MC_FMR = fmcn << 16 | fws << 8;