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)
72 * After WR command cpu write bufferd page into flash memory.
74 * \note This function has to be placed in RAM because
75 * executing code from Flash while a writing process
76 * is in progress is forbidden.
78 RAM_FUNC NOINLINE static void flash_at91_sendWRcmd(uint32_t page)
82 LOG_INFO("Writing page %ld...\n", page);
84 IRQ_SAVE_DISABLE(flags);
86 // Send the 'write page' command
87 MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
89 // Wait for end of command
90 while(!(MC_FSR & BV(MC_FRDY)))
100 * Return 0 if no error are occurred after flash memory
101 * read or write operation, otherwise return error code.
103 static int flash_at91_getStatus(UNUSED_ARG(struct KFile *, _fd))
106 * This bit is set to one if we programming of at least one locked lock
109 if(MC_FSR & BV(MC_LOCKE))
113 * This bit is set to one if an invalid command and/or a bad keywords was/were
114 * written in the Flash Command Register.
116 if(MC_FSR & BV(MC_PROGE))
124 * Write modified page on internal latch, and then send write command to
125 * flush page to internal flash.
127 static int flash_at91_flush(KFile *_fd)
129 Flash *fd = FLASH_CAST(_fd);
132 //Compute page address of current page.
133 page_addr_t *addr = (page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE);
135 //Copy modified page into internal latch.
136 for (page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
138 // This is needed in order to have a single 32bit write instruction in addr.
139 // (8 and 16 writes cause unpredictable results).
141 memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
145 // Send write command to transfer page from latch to internal flash memory.
146 flash_at91_sendWRcmd(fd->curr_page);
147 fd->page_dirty = false;
154 * Check current page and if \a page is different, load it in
157 static void flash_at91_loadPage(Flash *fd, page_t page)
159 if (page != fd->curr_page)
161 flash_at91_flush(&fd->fd);
163 memcpy(fd->page_buf, (char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
164 fd->curr_page = page;
165 LOG_INFO("Loaded page %lu\n", fd->curr_page);
171 * Write program memory.
172 * Write \a size bytes from buffer \a _buf to file \a fd
173 * \note Write operations are buffered.
175 static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
177 Flash *fd = FLASH_CAST(_fd);
178 const uint8_t *buf =(const uint8_t *)_buf;
181 page_addr_t page_addr;
182 size_t total_write = 0;
184 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
186 LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos);
189 page = (fd->fd.seek_pos + FLASH_START_ADDR) / FLASH_PAGE_SIZE_BYTES;
190 page_addr = (fd->fd.seek_pos + FLASH_START_ADDR) % FLASH_PAGE_SIZE_BYTES;
192 flash_at91_loadPage(fd, page);
194 size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr));
196 memcpy(fd->page_buf + page_addr, buf, wr_len);
197 fd->page_dirty = true;
200 fd->fd.seek_pos += wr_len;
202 total_write += wr_len;
204 LOG_INFO("written %u bytes\n", total_write);
209 * Open flash file \a fd
210 * \a name and \a mode are unused, cause flash memory is
211 * threated like one file.
213 static void flash_at91_open(struct Flash *fd)
215 fd->curr_page = FLASH_START_PAGE;
216 fd->fd.size = FLASH_MEM_SIZE - fd->curr_page * FLASH_PAGE_SIZE_BYTES;
219 memcpy(fd->page_buf, (char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
221 fd->page_dirty = false;
222 LOG_INFO("Flash file opened, pos %ld, size %ld\n", fd->fd.seek_pos, fd->fd.size);
226 * Read from file \a fd \a size bytes and put it in buffer \a buf
227 * \return the number of bytes read.
229 static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
231 Flash *fd = FLASH_CAST(_fd);
232 uint8_t *buf =(uint8_t *)_buf;
234 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
236 LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
238 // Flush current buffered page (if modified).
239 flash_at91_flush(&fd->fd);
241 kfile_off_t *addr = (kfile_off_t *)(fd->fd.seek_pos + FLASH_START_ADDR);
242 memcpy(buf, addr, size);
244 fd->fd.seek_pos += size;
246 LOG_INFO("Read %u bytes\n", size);
252 * Init module to perform write and read operation on internal
255 void flash_hw_init(struct Flash *fd)
257 memset(fd, 0, sizeof(*fd));
260 DB(fd->fd._type = KFT_FLASH);
262 // Set up flash programming functions.
263 fd->fd.write = flash_at91_write;
264 fd->fd.read = flash_at91_read;
265 fd->fd.error = flash_at91_getStatus;
266 fd->fd.flush = flash_at91_flush;