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>
67 * Check if flash memory is ready to accept other commands.
69 RAM_FUNC static bool flash_at91_isReady(void)
71 return (MC_FSR & BV(MC_FRDY));
77 * After WR command cpu write bufferd page into flash memory.
79 RAM_FUNC static void flash_at91_sendWRcmd(uint32_t page)
83 // Wait for end of command
84 while(!flash_at91_isReady())
89 IRQ_SAVE_DISABLE(flags);
91 // Send the 'write page' command
92 MC_FCR = MC_KEY | MC_FCMD_WP | (MC_PAGEN_MASK & (page << 8));
94 // Wait for end of command
95 while(!flash_at91_isReady())
104 * Return 0 if no error are occurred after flash memory
105 * read or write operation, otherwise return error code.
107 RAM_FUNC static int flash_at91_getStatus(struct KFile *_fd)
113 * This bit is set to one if we programming of at least one locked lock
116 if(MC_FSR & BV(MC_LOCKE))
120 * This bit is set to one if an invalid command and/or a bad keywords was/were
121 * written in the Flash Command Register.
123 if(MC_FSR & BV(MC_PROGE))
131 * Write modified page on internal latch, and then send write command to
132 * flush page to internal flash.
134 RAM_FUNC static void flash_at91_flush(Flash *fd)
138 //Compute page address of current page.
139 page_addr_t *addr = (page_addr_t *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE);
141 //Copy modified page into internal latch.
142 for (page_addr_t page_addr = 0; page_addr < FLASH_PAGE_SIZE_BYTES; page_addr += 4)
145 memcpy(&data, &fd->page_buf[page_addr], sizeof(data));
150 // Send write command to transfer page from latch to internal flash memory.
151 flash_at91_sendWRcmd(fd->curr_page);
156 * Flush At91 flash function.
158 * Write current buffered page in flash memory (if modified).
159 * This function erase flash memory page before writing.
161 static int flash_at91_kfileFlush(struct KFile *_fd)
163 Flash *fd = FLASH_CAST(_fd);
164 flash_at91_flush(fd);
170 * Check current page and if \a page is different, load it in
173 static void flash_at91_loadPage(Flash *fd, page_t page)
175 if (page != fd->curr_page)
177 flash_at91_flush(fd);
179 memcpy(fd->page_buf, (const char *)((page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
180 fd->curr_page = page;
181 LOG_INFO("Loaded page %lu\n", fd->curr_page);
187 * Write program memory.
188 * Write \a size bytes from buffer \a _buf to file \a fd
189 * \note Write operations are buffered.
191 static size_t flash_at91_write(struct KFile *_fd, const void *_buf, size_t size)
193 Flash *fd = FLASH_CAST(_fd);
194 const uint8_t *buf =(const uint8_t *)_buf;
197 page_addr_t page_addr;
198 size_t total_write = 0;
200 size = MIN((kfile_off_t)size, (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
202 LOG_INFO("Writing at pos[%lu]\n", fd->fd.seek_pos);
205 page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
206 page_addr = (fd->fd.seek_pos - FLASH_BASE) % FLASH_PAGE_SIZE_BYTES;
208 flash_at91_loadPage(fd, page);
210 size_t wr_len = MIN(size, (size_t)(FLASH_PAGE_SIZE_BYTES - page_addr));
212 memcpy(fd->page_buf + page_addr, buf, wr_len);
213 fd->page_dirty = true;
216 fd->fd.seek_pos += wr_len;
218 total_write += wr_len;
220 LOG_INFO("written %u bytes\n", total_write);
227 static int flash_at91_close(struct KFile *_fd)
229 Flash *fd = FLASH_CAST(_fd);
230 flash_at91_flush(fd);
231 LOG_INFO("Flash file closed\n");
237 * Open flash file \a fd
238 * \a name and \a mode are unused, cause flash memory is
239 * threated like one file.
241 static void flash_at91_open(struct Flash *fd)
243 fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
244 fd->fd.seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
245 fd->curr_page = (fd->fd.seek_pos - FLASH_BASE) / FLASH_PAGE_SIZE_BYTES;
247 memcpy(fd->page_buf, (const char *)((fd->curr_page * FLASH_PAGE_SIZE_BYTES) + FLASH_BASE), FLASH_PAGE_SIZE_BYTES);
249 fd->page_dirty = false;
250 LOG_INFO("Flash file opened\n");
255 * Move \a fd file seek position of \a offset bytes from \a whence.
258 static kfile_off_t flash_at91_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
260 Flash *fd = FLASH_CAST(_fd);
261 kfile_off_t seek_pos;
267 seek_pos = FLASH_BASE + FLASH_BOOT_SIZE;
270 seek_pos = fd->fd.size;
273 seek_pos = fd->fd.seek_pos;
281 #if LOG_LEVEL >= LOG_LVL_INFO
283 if (seek_pos + offset > fd->fd.size)
284 LOG_INFO("seek outside EOF\n");
287 fd->fd.seek_pos = seek_pos + offset;
289 return fd->fd.seek_pos - (FLASH_BASE + FLASH_BOOT_SIZE);
295 static struct KFile *flash_at91_reopen(struct KFile *_fd)
297 Flash *fd = FLASH_CAST(_fd);
298 flash_at91_close(_fd);
305 * Read from file \a fd \a size bytes and put it in buffer \a buf
306 * \return the number of bytes read.
308 static size_t flash_at91_read(struct KFile *_fd, void *_buf, size_t size)
310 Flash *fd = FLASH_CAST(_fd);
311 uint8_t *buf =(uint8_t *)_buf;
313 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
315 LOG_INFO("Reading at pos[%lu]\n", fd->fd.seek_pos);
317 // Flush current buffered page (if modified).
318 flash_at91_flush(fd);
320 uint32_t *addr = (uint32_t *)fd->fd.seek_pos;
321 memcpy(buf, (uint8_t *)addr, size);
323 fd->fd.seek_pos += size;
325 LOG_INFO("Read %u bytes\n", size);
331 * Init module to perform write and read operation on internal
334 void flash_hw_init(struct Flash *fd)
336 memset(fd, 0, sizeof(*fd));
337 DB(fd->fd._type = KFT_FLASH);
339 // Set up flash programming functions.
340 fd->fd.reopen = flash_at91_reopen;
341 fd->fd.close = flash_at91_close;
342 fd->fd.write = flash_at91_write;
343 fd->fd.read = flash_at91_read;
344 fd->fd.seek = flash_at91_seek;
345 fd->fd.error = flash_at91_getStatus;
346 fd->fd.flush = flash_at91_kfileFlush;
355 * Compute values to insert into mode register.
358 /* main clocks in 1.5uS */
359 fmcn = (CPU_FREQ/1000000ul) + (CPU_FREQ/2000000ul) + 1;
361 /* hard overclocking */
365 /* Only allow fmcn=0 if clock period is > 30 us = 33kHz. */
366 if (CPU_FREQ <= 33333ul)
369 /* Only allow fws=0 if clock frequency is < 30 MHz. */
370 if (CPU_FREQ > 30000000ul)
375 // Set wait states and number of MCK cycles in 1.5 usecs
376 MC_FMR = fmcn << 16 | fws << 8;