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 2010 Develer S.r.l. (http://www.develer.com/)
33 * \brief LM3S1968 internal flash memory driver.
35 * \author Andrea Righi <arighi@develer.com>
38 #include "flash_lm3s.h"
41 #include <cfg/macros.h>
45 #include <drv/timer.h>
46 #include <drv/flash.h>
47 #include <cpu/power.h> /* cpu_relax() */
49 #include <string.h> /* memcpy() */
52 static int flash_lm3s_erase_page(page_t addr)
54 FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
56 FLASH_FMA_R = (volatile uint32_t)addr;
57 FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
59 while (FLASH_FMC_R & FLASH_FMC_ERASE)
61 if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
66 static int flash_lm3s_write_word(page_t addr, const uint8_t *data, size_t len)
68 FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
71 memcpy(&_data, data, len);
72 FLASH_FMA_R = (volatile uint32_t)addr;
73 FLASH_FMD_R = (volatile uint32_t)_data;
74 FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
76 while (FLASH_FMC_R & FLASH_FMC_WRITE)
78 if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
83 static void _flash_lm3s_flush(Flash *fd)
88 LOG_INFO("Erase page %p\n", fd->curr_page);
89 flash_lm3s_erase_page(fd->curr_page);
91 LOG_INFO("Flush page %p\n", fd->curr_page);
92 for (int i = 0; i < FLASH_PAGE_SIZE_BYTES; i+=4)
93 flash_lm3s_write_word(fd->curr_page + i, &fd->page_buf[i], sizeof(uint32_t));
94 fd->page_dirty = false;
97 static void flash_lm3s_load_page(Flash *fd, page_t page)
99 ASSERT(!((size_t)page % FLASH_PAGE_SIZE_BYTES));
101 if (page == fd->curr_page)
105 _flash_lm3s_flush(fd);
107 /* Load a new page */
108 memcpy(fd->page_buf, FLASH_BASE + (uint8_t *)page, FLASH_PAGE_SIZE_BYTES);
109 fd->curr_page = page;
110 LOG_INFO("Loaded page %p\n", fd->curr_page);
114 * Write program memory.
115 * Write \a size bytes from buffer \a _buf to file \a fd
116 * \note Write operations are not buffered.
118 static size_t flash_lm3s_write(struct KFile *_fd, const void *_buf, size_t size)
120 Flash *fd = FLASH_CAST(_fd);
121 const uint8_t *buf =(const uint8_t *)_buf;
122 size_t total_write = 0;
125 size = MIN((kfile_off_t)size,
126 (kfile_off_t)(fd->fd.size - (fd->fd.seek_pos - FLASH_BASE)));
128 LOG_INFO("Writing at pos[%lx]\n", fd->fd.seek_pos);
131 page_t page = (fd->fd.seek_pos & ~(FLASH_PAGE_SIZE_BYTES - 1));
132 size_t offset = fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES;
134 flash_lm3s_load_page(fd, page);
136 len = MIN(size, FLASH_PAGE_SIZE_BYTES - offset);
138 memcpy((uint8_t *)fd->page_buf + offset, buf, len);
139 fd->page_dirty = true;
142 fd->fd.seek_pos += len;
146 LOG_INFO("written %u bytes\n", total_write);
153 static int flash_lm3s_close(struct KFile *_fd)
155 Flash *fd = FLASH_CAST(_fd);
156 _flash_lm3s_flush(fd);
157 LOG_INFO("Flash file closed\n");
162 * Open flash file \a fd
164 static void flash_lm3s_open(Flash *fd)
166 fd->fd.size = FLASH_BASE + FLASH_MEM_SIZE;
167 fd->fd.seek_pos = FLASH_BASE;
169 * Set an invalid page to force the load of the next actually used page
172 fd->curr_page = FLASH_BASE + FLASH_MEM_SIZE;
174 fd->page_dirty = false;
175 LOG_INFO("Flash file opened\n");
179 * Move \a fd file seek position of \a offset bytes from \a whence.
181 static kfile_off_t flash_lm3s_seek(struct KFile *_fd, kfile_off_t offset, KSeekMode whence)
183 Flash *fd = FLASH_CAST(_fd);
184 kfile_off_t seek_pos;
189 seek_pos = FLASH_BASE;
192 seek_pos = FLASH_BASE + fd->fd.size;
195 seek_pos = fd->fd.seek_pos;
202 if (seek_pos + offset > fd->fd.size)
203 LOG_ERR("seek outside EOF\n");
204 fd->fd.seek_pos = seek_pos + offset;
206 return fd->fd.seek_pos - FLASH_BASE;
212 static struct KFile *flash_lm3s_reopen(struct KFile *_fd)
214 Flash *fd = FLASH_CAST(_fd);
215 flash_lm3s_close(_fd);
222 * Read from file \a fd \a size bytes and put it in buffer \a buf
223 * \return the number of bytes read.
225 static size_t flash_lm3s_read(struct KFile *_fd, void *_buf, size_t size)
227 Flash *fd = FLASH_CAST(_fd);
228 uint8_t *buf =(uint8_t *)_buf, *addr;
230 size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
232 LOG_INFO("Reading at pos[%lx]\n", fd->fd.seek_pos);
233 /* Check if we can get current cached page */
234 if ((size_t)fd->fd.seek_pos / FLASH_PAGE_SIZE_BYTES ==
235 (size_t)fd->curr_page)
236 addr = (uint8_t *)fd->curr_page +
237 fd->fd.seek_pos % FLASH_PAGE_SIZE_BYTES;
239 addr = (uint8_t *)fd->fd.seek_pos;
240 memcpy(buf, (uint8_t *)addr, size);
241 fd->fd.seek_pos += size;
243 LOG_INFO("Read %u bytes\n", size);
247 static int flash_lm3s_flush(struct KFile *_fd)
249 Flash *fd = FLASH_CAST(_fd);
251 _flash_lm3s_flush(fd);
256 * Init module to perform write and read operation on internal
259 void flash_hw_init(Flash *fd)
261 memset(fd, 0, sizeof(*fd));
262 DB(fd->fd._type = KFT_FLASH);
264 fd->fd.reopen = flash_lm3s_reopen;
265 fd->fd.close = flash_lm3s_close;
266 fd->fd.write = flash_lm3s_write;
267 fd->fd.read = flash_lm3s_read;
268 fd->fd.seek = flash_lm3s_seek;
269 fd->fd.flush = flash_lm3s_flush;
271 FLASH_USECRL_R = CPU_FREQ / 1000000 - 1;