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>
62 #include <drv/flash.h>
66 #define FLASH_START_PAGE DIV_ROUNDUP(FLASH_BOOT_SIZE, FLASH_PAGE_SIZE_BYTES)
67 #define FLASH_START_ADDR (FLASH_START_PAGE * FLASH_PAGE_SIZE_BYTES)
70 * Really send the flash write command.
72 * \note This function has to be placed in RAM because
73 * executing code from flash while a writing process
74 * is in progress is forbidden.
76 RAM_FUNC NOINLINE static void write_page(uint32_t page)
78 // Send the 'write page' command
79 MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
81 // Wait for the end of command
82 while(!(MC_FSR & BV(MC_FRDY)))
92 * After WR command cpu write bufferd page into flash memory.
95 INLINE void flash_at91_sendWRcmd(uint32_t page)
99 LOG_INFO("Writing page %ld...\n", page);
101 IRQ_SAVE_DISABLE(flags);
109 * Return 0 if no error are occurred after flash memory
110 * read or write operation, otherwise return error code.
112 static int flash_at91_getStatus(UNUSED_ARG(struct KFile *, _fd))
115 * This bit is set to one if we programming of at least one locked lock
118 if(MC_FSR & BV(MC_LOCKE))
122 * This bit is set to one if an invalid command and/or a bad keywords was/were
123 * written in the Flash Command Register.
125 if(MC_FSR & BV(MC_PROGE))
133 * Write modified page on internal latch, and then send write command to
134 * flush page to internal flash.
136 static int flash_at91_flush(KFile *_fd)
138 Flash *fd = FLASH_CAST(_fd);
141 //Compute page address of current page.
142 page_addr_t *addr = (page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE);
144 //Copy modified page into internal latch.
145 for (page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
147 // This is needed in order to have a single 32bit write instruction in addr.
148 // (8 and 16 writes cause unpredictable results).
150 memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
154 // Send write command to transfer page from latch to internal flash memory.
155 flash_at91_sendWRcmd(fd->curr_page);
156 fd->page_dirty = false;
163 * Check current page and if \a page is different, load it in
166 static void flash_at91_loadPage(Flash *fd, page_t page)
168 if (page != fd->curr_page)
170 flash_at91_flush(&fd->fd);
172 memcpy(fd->page_buf, (char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
173 fd->curr_page = page;
174 LOG_INFO("Loaded page %lu\n", fd->curr_page);
180 * Write program memory.
181 * Write \a size bytes from buffer \a _buf to file \a fd
182 * \note Write operations are buffered.
184 static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
186 Flash *fd = FLASH_CAST(_fd);
187 const uint8_t *buf =(const uint8_t *)_buf;
190 page_addr_t page_addr;
191 size_t total_write = 0;
193 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
195 LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos);
198 page = (fd->fd.seek_pos + FLASH_START_ADDR) / FLASH_PAGE_SIZE_BYTES;
199 page_addr = (fd->fd.seek_pos + FLASH_START_ADDR) % FLASH_PAGE_SIZE_BYTES;
201 flash_at91_loadPage(fd, page);
203 size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr));
205 memcpy(fd->page_buf + page_addr, buf, wr_len);
206 fd->page_dirty = true;
209 fd->fd.seek_pos += wr_len;
211 total_write += wr_len;
213 LOG_INFO("written %u bytes\n", total_write);
218 * Open flash file \a fd
219 * \a name and \a mode are unused, cause flash memory is
220 * threated like one file.
222 static void flash_at91_open(struct Flash *fd)
224 fd->curr_page = FLASH_START_PAGE;
225 fd->fd.size = FLASH_MEM_SIZE - fd->curr_page * FLASH_PAGE_SIZE_BYTES;
228 memcpy(fd->page_buf, (char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
230 fd->page_dirty = false;
231 LOG_INFO("Flash file opened, pos %ld, size %ld\n", fd->fd.seek_pos, fd->fd.size);
235 * Read from file \a fd \a size bytes and put it in buffer \a buf
236 * \return the number of bytes read.
238 static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
240 Flash *fd = FLASH_CAST(_fd);
241 uint8_t *buf =(uint8_t *)_buf;
243 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
245 LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
247 // Flush current buffered page (if modified).
248 flash_at91_flush(&fd->fd);
250 kfile_off_t *addr = (kfile_off_t *)(fd->fd.seek_pos + FLASH_START_ADDR);
251 memcpy(buf, addr, size);
253 fd->fd.seek_pos += size;
255 LOG_INFO("Read %u bytes\n", size);
261 * Init module to perform write and read operation on internal
264 void flash_hw_init(struct Flash *fd)
266 memset(fd, 0, sizeof(*fd));
269 DB(fd->fd._type = KFT_FLASH);
271 // Set up flash programming functions.
272 fd->fd.write = flash_at91_write;
273 fd->fd.read = flash_at91_read;
274 fd->fd.error = flash_at91_getStatus;
275 fd->fd.flush = flash_at91_flush;