Move flash related flags to the flash driver; refactor accordingly.
[bertos.git] / bertos / cpu / cortex-m3 / drv / flash_lm3s.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
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.
10  *
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.
15  *
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
19  *
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.
28  *
29  * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief LM3S1968 internal flash memory driver.
34  *
35  * \author Andrea Righi <arighi@develer.com>
36  */
37
38 #include "flash_lm3s.h"
39 #include "cfg/cfg_emb_flash.h"
40
41 // Define log settings for cfg/log.h
42 #define LOG_LEVEL    CONFIG_FLASH_EMB_LOG_LEVEL
43 #define LOG_FORMAT   CONFIG_FLASH_EMB_LOG_FORMAT
44 #include <cfg/log.h>
45 #include <cfg/macros.h>
46
47 #include <io/kblock.h>
48
49 #include <drv/timer.h>
50 #include <drv/flash.h>
51
52 #include <cpu/power.h> /* cpu_relax() */
53 #include <cpu/types.h>
54
55 #include <string.h> /* memcpy() */
56
57 struct FlashHardware
58 {
59         int status;
60 };
61
62 static bool flash_wait(struct KBlock *blk, uint32_t event)
63 {
64         Flash *fls = FLASH_CAST(blk);
65         ticks_t start = timer_clock();
66         while (true)
67         {
68                 if (!(FLASH_FMC_R & event))
69                         break;
70
71                 if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
72                 {
73                         fls->hw->status |= FLASH_WR_PROTECT;
74                         LOG_ERR("wr protect..\n");
75                         return false;
76                 }
77
78                 if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT))
79                 {
80                         fls->hw->status |= FLASH_WR_TIMEOUT;
81                         LOG_ERR("Timeout..\n");
82                         return false;
83                 }
84
85                 cpu_relax();
86         }
87
88         return true;
89 }
90
91 static int lm3s_erasePage(struct KBlock *blk, uint32_t addr)
92 {
93         FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
94
95         FLASH_FMA_R = (volatile uint32_t)addr;
96         FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
97
98         return flash_wait(blk, FLASH_FMC_ERASE);
99 }
100
101 static int lm3s_writeWord(struct KBlock *blk, uint32_t addr, uint32_t data)
102 {
103         FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
104
105         FLASH_FMA_R = (volatile uint32_t)addr;
106         FLASH_FMD_R = (volatile uint32_t)data;
107         FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
108
109         return flash_wait(blk, FLASH_FMC_WRITE);
110 }
111
112 static size_t lm3s_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
113 {
114         memcpy(buf, (void *)(idx * blk->blk_size + offset), size);
115         return size;
116 }
117
118 static size_t lm3s_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
119 {
120         (void)offset;
121         ASSERT(offset == 0);
122         ASSERT(size == blk->blk_size);
123
124         if (!lm3s_erasePage(blk, (idx * blk->blk_size)))
125                 return 0;
126
127         uint32_t addr = idx * blk->blk_size;
128         const uint8_t *buf = (const uint8_t *)_buf;
129
130         while (size)
131         {
132                 uint32_t data = (*(buf + 3) << 24) |
133                                                 (*(buf + 2) << 16) |
134                                                 (*(buf + 1) << 8)  |
135                                                 *buf;
136
137                 if (!lm3s_writeWord(blk, addr, data))
138                         return 0;
139
140                 size -= 4;
141                 buf += 4;
142                 addr += 4;
143         }
144
145         return blk->blk_size;
146 }
147
148 static int lm3s_flash_error(struct KBlock *blk)
149 {
150         Flash *fls = FLASH_CAST(blk);
151         return fls->hw->status;
152 }
153
154 static void lm3s_flash_clearerror(struct KBlock *blk)
155 {
156         Flash *fls = FLASH_CAST(blk);
157         fls->hw->status = 0;
158 }
159
160 static const KBlockVTable flash_lm3s_buffered_vt =
161 {
162         .readDirect = lm3s_flash_readDirect,
163         .writeDirect = lm3s_flash_writeDirect,
164
165         .readBuf = kblock_swReadBuf,
166         .writeBuf = kblock_swWriteBuf,
167         .load = kblock_swLoad,
168         .store = kblock_swStore,
169
170         .close = kblock_swClose,
171
172         .error = lm3s_flash_error,
173         .clearerr = lm3s_flash_clearerror,
174 };
175
176 static const KBlockVTable flash_lm3s_unbuffered_vt =
177 {
178         .readDirect = lm3s_flash_readDirect,
179         .writeDirect = lm3s_flash_writeDirect,
180
181         .close = kblock_swClose,
182
183         .error = lm3s_flash_error,
184         .clearerr = lm3s_flash_clearerror,
185 };
186
187 static struct FlashHardware flash_lm3s_hw;
188 static uint8_t flash_buf[FLASH_PAGE_SIZE];
189
190 static void common_init(Flash *fls)
191 {
192         memset(fls, 0, sizeof(*fls));
193         DB(fls->blk.priv.type = KBT_FLASH);
194
195         FLASH_USECRL_R = CPU_FREQ / 1000000 - 1;
196
197         fls->hw = &flash_lm3s_hw;
198
199         fls->blk.blk_size = FLASH_PAGE_SIZE;
200         fls->blk.blk_cnt =  FLASH_SIZE / FLASH_PAGE_SIZE;
201 }
202
203
204 void flash_hw_init(Flash *fls, UNUSED_ARG(int, flags))
205 {
206         common_init(fls);
207         fls->blk.priv.vt = &flash_lm3s_buffered_vt;
208         fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
209         fls->blk.priv.buf = flash_buf;
210
211         /* Load the first block in the cache */
212         void *flash_start = 0x0;
213         memcpy(fls->blk.priv.buf, flash_start, fls->blk.blk_size);
214 }
215
216 void flash_hw_initUnbuffered(Flash *fls, UNUSED_ARG(int, flags))
217 {
218         common_init(fls);
219         fls->blk.priv.vt = &flash_lm3s_unbuffered_vt;
220 }
221
222
223