Fix typo.
[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         ASSERT(offset == 0);
115         ASSERT(size == blk->blk_size);
116
117         memcpy(buf, (void *)(idx * blk->blk_size), size);
118         return size;
119 }
120
121 static size_t lm3s_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
122 {
123         ASSERT(offset == 0);
124         ASSERT(size == blk->blk_size);
125
126         if (!lm3s_erasePage(blk, (idx * blk->blk_size)))
127                 return 0;
128
129         uint32_t addr = idx * blk->blk_size;
130         const uint8_t *buf = (const uint8_t *)_buf;
131
132         while (size)
133         {
134                 uint32_t data = (*(buf + 3) << 24) |
135                                                 (*(buf + 2) << 16) |
136                                                 (*(buf + 1) << 8)  |
137                                                 *buf;
138
139                 if (!lm3s_writeWord(blk, addr, data))
140                         return 0;
141
142                 size -= 4;
143                 buf += 4;
144                 addr += 4;
145         }
146
147         return blk->blk_size;
148 }
149
150 static int lm3s_flash_error(struct KBlock *blk)
151 {
152         Flash *fls = FLASH_CAST(blk);
153         return fls->hw->status;
154 }
155
156 static void lm3s_flash_clearerror(struct KBlock *blk)
157 {
158         Flash *fls = FLASH_CAST(blk);
159         fls->hw->status = 0;
160 }
161
162 static const KBlockVTable flash_lm3s_buffered_vt =
163 {
164         .readDirect = lm3s_flash_readDirect,
165         .writeDirect = lm3s_flash_writeDirect,
166
167         .readBuf = kblock_swReadBuf,
168         .writeBuf = kblock_swWriteBuf,
169         .load = kblock_swLoad,
170         .store = kblock_swStore,
171
172         .close = kblock_swClose,
173
174         .error = lm3s_flash_error,
175         .clearerr = lm3s_flash_clearerror,
176 };
177
178 static const KBlockVTable flash_lm3s_unbuffered_vt =
179 {
180         .readDirect = lm3s_flash_readDirect,
181         .writeDirect = lm3s_flash_writeDirect,
182
183         .close = kblock_swClose,
184
185         .error = lm3s_flash_error,
186         .clearerr = lm3s_flash_clearerror,
187 };
188
189 static struct FlashHardware flash_lm3s_hw;
190 static uint8_t flash_buf[FLASH_PAGE_SIZE];
191
192 static void common_init(Flash *fls)
193 {
194         memset(fls, 0, sizeof(*fls));
195         DB(fls->blk.priv.type = KBT_FLASH);
196
197         FLASH_USECRL_R = CPU_FREQ / 1000000 - 1;
198
199         fls->hw = &flash_lm3s_hw;
200
201         fls->blk.blk_size = FLASH_PAGE_SIZE;
202         fls->blk.blk_cnt =  FLASH_SIZE / FLASH_PAGE_SIZE;
203 }
204
205
206 void flash_hw_init(Flash *fls, int flags)
207 {
208         common_init(fls);
209         fls->blk.priv.vt = &flash_lm3s_buffered_vt;
210         fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE | flags;
211         fls->blk.priv.buf = flash_buf;
212
213         /* Load the first block in the cache */
214         void *flash_start = 0x0;
215         memcpy(fls->blk.priv.buf, flash_start, fls->blk.blk_size);
216 }
217
218 void flash_hw_initUnbuffered(Flash *fls, int flags)
219 {
220         common_init(fls);
221         fls->blk.priv.vt = &flash_lm3s_unbuffered_vt;
222         fls->blk.priv.flags |= flags;
223 }
224
225
226