dbabc08ae7185b2979794de9b800fb22dff1eb06
[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/log.h"
40
41 #include <cfg/macros.h>
42
43 #include <io/kblock.h>
44
45 #include <drv/timer.h>
46 #include <drv/flash.h>
47
48 #include <cpu/power.h> /* cpu_relax() */
49 #include <cpu/types.h>
50
51 #include <string.h> /* memcpy() */
52
53 struct FlashHardware
54 {
55         int status;
56 };
57
58 static bool flash_wait(struct KBlock *blk)
59 {
60         Flash *fls = FLASH_CAST(blk);
61         ticks_t start = timer_clock();
62         while (true)
63         {
64                 if (!(FLASH_FMC_R & FLASH_FMC_ERASE))
65                         break;
66
67                 if (FLASH_FCRIS_R & FLASH_FCRIS_ARIS)
68                 {
69                         fls->hw->status |= FLASH_WR_PROTECT;
70                         LOG_ERR("wr protect..\n");
71                         return false;
72                 }
73
74                 if (timer_clock() - start > ms_to_ticks(CONFIG_FLASH_WR_TIMEOUT))
75                 {
76                         fls->hw->status |= FLASH_WR_TIMEOUT;
77                         LOG_ERR("Timeout..\n");
78                         return false;
79                 }
80
81                 cpu_relax();
82         }
83
84         return true;
85 }
86
87 static int lm3s_erasePage(struct KBlock *blk, uint32_t addr)
88 {
89         FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
90
91         FLASH_FMA_R = (volatile uint32_t)addr;
92         FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
93
94         return flash_wait(blk);
95 }
96
97 static int lm3s_writeWord(struct KBlock *blk, uint32_t addr, uint32_t data)
98 {
99         FLASH_FCMISC_R = FLASH_FCMISC_AMISC;
100
101         FLASH_FMA_R = (volatile uint32_t)addr;
102         FLASH_FMD_R = (volatile uint32_t)data;
103         FLASH_FMC_R = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
104
105         return flash_wait(blk);
106 }
107
108 static size_t lm3s_flash_readDirect(struct KBlock *blk, block_idx_t idx, void *buf, size_t offset, size_t size)
109 {
110         memcpy(buf, (void *)(idx * blk->blk_size + offset), size);
111         return size;
112 }
113
114 static size_t lm3s_flash_writeDirect(struct KBlock *blk, block_idx_t idx, const void *_buf, size_t offset, size_t size)
115 {
116         ASSERT(offset == 0);
117         ASSERT(size == blk->blk_size);
118
119         if (!lm3s_erasePage(blk, (idx * blk->blk_size)))
120                 return 0;
121
122         uint32_t addr = idx * blk->blk_size;
123         const uint8_t *buf = (const uint8_t *)_buf;
124
125         while (size)
126         {
127                 uint32_t data = (*(buf + 3) << 24) |
128                                                 (*(buf + 2) << 16) |
129                                                 (*(buf + 1) << 8)  |
130                                                 *buf;
131
132                 if (!lm3s_writeWord(blk, addr, data))
133                         return 0;
134
135                 size -= 4;
136                 buf += 4;
137                 addr += 4;
138         }
139
140         return blk->blk_size;
141 }
142
143 static int lm3s_flash_error(struct KBlock *blk)
144 {
145         Flash *fls = FLASH_CAST(blk);
146         return fls->hw->status;
147 }
148
149 static void lm3s_flash_clearerror(struct KBlock *blk)
150 {
151         Flash *fls = FLASH_CAST(blk);
152         fls->hw->status = 0;
153 }
154
155 static const KBlockVTable flash_lm3s_buffered_vt =
156 {
157         .readDirect = lm3s_flash_readDirect,
158         .writeDirect = lm3s_flash_writeDirect,
159
160         .readBuf = kblock_swReadBuf,
161         .writeBuf = kblock_swWriteBuf,
162         .load = kblock_swLoad,
163         .store = kblock_swStore,
164
165         .error = lm3s_flash_error,
166         .clearerr = lm3s_flash_clearerror,
167 };
168
169 static const KBlockVTable flash_lm3s_unbuffered_vt =
170 {
171         .readDirect = lm3s_flash_readDirect,
172         .writeDirect = lm3s_flash_writeDirect,
173
174         .error = lm3s_flash_error,
175         .clearerr = lm3s_flash_clearerror,
176 };
177
178 /* Flash memory mapping */
179 #if CPU_CM3_LM3S1968
180         #define EMB_FLASH_SIZE               0x40000 //< 256KiB
181         #define EMB_FLASH_PAGE_SIZE          0x400   //< 1KiB
182 #else
183         #error Unknown CPU
184 #endif
185
186 static struct FlashHardware flash_lm3s_hw;
187 static uint8_t flash_buf[EMB_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 = EMB_FLASH_PAGE_SIZE;
199         fls->blk.blk_cnt =  EMB_FLASH_SIZE / EMB_FLASH_PAGE_SIZE;
200 }
201
202
203 void flash_hw_init(Flash *fls)
204 {
205         common_init(fls);
206         fls->blk.priv.vt = &flash_lm3s_buffered_vt;
207         fls->blk.priv.flags |= KB_BUFFERED | KB_PARTIAL_WRITE;
208         fls->blk.priv.buf = flash_buf;
209 }
210
211 void flash_hw_initUnbuffered(Flash *fls)
212 {
213         common_init(fls);
214         fls->blk.priv.vt = &flash_lm3s_unbuffered_vt;
215 }
216
217
218