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