bb40f6f708b95515d165da8e131031639474593b
[fw/altos] / src / ao_flash.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19 #include "at45db161d.h"
20
21 /* Total bytes of available storage */
22 __pdata uint32_t        ao_storage_total;
23
24 /* Block size - device is erased in these units. At least 256 bytes */
25 __pdata uint32_t        ao_storage_block;
26
27 /* Byte offset of config block. Will be ao_storage_block bytes long */
28 __pdata uint32_t        ao_storage_config;
29
30 /* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
31 __pdata uint16_t        ao_storage_unit;
32
33 #define FLASH_CS                P1_1
34 #define FLASH_CS_INDEX          1
35
36 #define FLASH_BLOCK_SIZE_MAX    512
37
38 __xdata uint8_t ao_flash_mutex;
39
40 #define ao_flash_delay() do { \
41         _asm nop _endasm; \
42         _asm nop _endasm; \
43         _asm nop _endasm; \
44 } while(0)
45
46 #define ao_flash_cs_low()       ao_spi_get_bit(FLASH_CS)
47
48 #define ao_flash_cs_high()      ao_spi_put_bit(FLASH_CS)
49
50 struct ao_flash_instruction {
51         uint8_t instruction;
52         uint8_t address[3];
53 } __xdata ao_flash_instruction;
54
55 static void
56 ao_flash_set_pagesize_512(void)
57 {
58         ao_flash_cs_low();
59         ao_flash_instruction.instruction = FLASH_SET_CONFIG;
60         ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0;
61         ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1;
62         ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2;
63         ao_spi_send(&ao_flash_instruction, 4);
64         ao_flash_cs_high();
65 }
66
67
68 static uint8_t
69 ao_flash_read_status(void)
70 {
71         ao_flash_cs_low();
72         ao_flash_instruction.instruction = FLASH_READ_STATUS;
73         ao_spi_send(&ao_flash_instruction, 1);
74         ao_spi_recv(&ao_flash_instruction, 1);
75         ao_flash_cs_high();
76         return ao_flash_instruction.instruction;
77 }
78
79 #define FLASH_BLOCK_NONE        0xffff
80
81 static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX];
82 static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE;
83 static __pdata uint8_t  ao_flash_block_dirty;
84 static __pdata uint8_t  ao_flash_write_pending;
85 static __pdata uint8_t  ao_flash_setup_done;
86 static __pdata uint8_t  ao_flash_block_shift;
87 static __pdata uint16_t ao_flash_block_size;
88 static __pdata uint16_t ao_flash_block_mask;
89
90 void
91 ao_storage_setup(void) __reentrant
92 {
93         uint8_t status;
94
95         if (ao_flash_setup_done)
96                 return;
97
98         ao_mutex_get(&ao_flash_mutex);
99         if (ao_flash_setup_done) {
100                 ao_mutex_put(&ao_flash_mutex);
101                 return;
102         }
103
104         /* On first use, check to see if the flash chip has
105          * been programmed to use 512 byte pages. If not, do so.
106          * And then, because the flash part must be power cycled
107          * for that change to take effect, panic.
108          */
109         status = ao_flash_read_status();
110
111         if (!(status & FLASH_STATUS_PAGESIZE_512)) {
112                 ao_flash_set_pagesize_512();
113                 ao_panic(AO_PANIC_FLASH);
114         }
115
116         switch (status & 0x3c) {
117
118         /* AT45DB321D */
119         case 0x34:
120                 ao_flash_block_shift = 9;
121                 ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024);
122                 break;
123
124         /* AT45DB161D */
125         case 0x2c:
126                 ao_flash_block_shift = 9;
127                 ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024);
128                 break;
129
130         /* AT45DB081D */
131         case 0x24:
132                 ao_flash_block_shift = 8;
133                 ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024);
134                 break;
135
136         /* AT45DB041D */
137         case 0x1c:
138                 ao_flash_block_shift = 8;
139                 ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024);
140                 break;
141
142         /* AT45DB021D */
143         case 0x14:
144                 ao_flash_block_shift = 8;
145                 ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024);
146                 break;
147
148         /* AT45DB011D */
149         case 0x0c:
150                 ao_flash_block_shift = 8;
151                 ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024);
152                 break;
153
154         default:
155                 ao_panic(AO_PANIC_FLASH);
156         }
157         ao_flash_block_size = 1 << ao_flash_block_shift;
158         ao_flash_block_mask = ao_flash_block_size - 1;
159
160         ao_storage_block = ao_flash_block_size;
161         ao_storage_config = ao_storage_total - ao_storage_block;
162         ao_storage_unit = ao_flash_block_size;
163
164         ao_flash_setup_done = 1;
165         ao_mutex_put(&ao_flash_mutex);
166 }
167
168 static void
169 ao_flash_wait_write(void)
170 {
171         if (ao_flash_write_pending) {
172                 for (;;) {
173                         uint8_t status = ao_flash_read_status();
174                         if ((status & FLASH_STATUS_RDY))
175                                 break;
176                 }
177                 ao_flash_write_pending = 0;
178         }
179 }
180
181 /* Write the current block to the FLASHPROM */
182 static void
183 ao_flash_write_block(void)
184 {
185         ao_flash_wait_write();
186         ao_flash_cs_low();
187         ao_flash_instruction.instruction = FLASH_WRITE;
188
189         /* 13/14 block bits + 9/8 byte bits (always 0) */
190         ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
191         ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
192         ao_flash_instruction.address[2] = 0;
193         ao_spi_send(&ao_flash_instruction, 4);
194         ao_spi_send(ao_flash_data, ao_storage_block);
195         ao_flash_cs_high();
196         ao_flash_write_pending = 1;
197 }
198
199 /* Read the current block from the FLASHPROM */
200 static void
201 ao_flash_read_block(void)
202 {
203         ao_flash_wait_write();
204         ao_flash_cs_low();
205         ao_flash_instruction.instruction = FLASH_READ;
206
207         /* 13/14 block bits + 9/8 byte bits (always 0) */
208         ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
209         ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
210         ao_flash_instruction.address[2] = 0;
211         ao_spi_send(&ao_flash_instruction, 4);
212         ao_spi_recv(ao_flash_data, ao_flash_block_size);
213         ao_flash_cs_high();
214 }
215
216 static void
217 ao_flash_flush_internal(void)
218 {
219         if (ao_flash_block_dirty) {
220                 ao_flash_write_block();
221                 ao_flash_block_dirty = 0;
222         }
223 }
224
225 static void
226 ao_flash_fill(uint16_t block)
227 {
228         if (block != ao_flash_block) {
229                 ao_flash_flush_internal();
230                 ao_flash_block = block;
231                 ao_flash_read_block();
232         }
233 }
234
235 uint8_t
236 ao_storage_device_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
237 {
238         uint16_t block = (uint16_t) (pos >> ao_flash_block_shift);
239
240         /* Transfer the data */
241         ao_mutex_get(&ao_flash_mutex); {
242                 if (len != ao_flash_block_size)
243                         ao_flash_fill(block);
244                 else {
245                         ao_flash_flush_internal();
246                         ao_flash_block = block;
247                 }
248                 memcpy(ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
249                        buf,
250                        len);
251                 ao_flash_block_dirty = 1;
252         } ao_mutex_put(&ao_flash_mutex);
253         return 1;
254 }
255
256 uint8_t
257 ao_storage_device_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
258 {
259         uint16_t block = (uint16_t) (pos >> ao_flash_block_shift);
260
261         /* Transfer the data */
262         ao_mutex_get(&ao_flash_mutex); {
263                 ao_flash_fill(block);
264                 memcpy(buf,
265                        ao_flash_data + (uint16_t) (pos & ao_flash_block_mask),
266                        len);
267         } ao_mutex_put(&ao_flash_mutex);
268         return 1;
269 }
270
271 void
272 ao_storage_flush(void) __reentrant
273 {
274         ao_mutex_get(&ao_flash_mutex); {
275                 ao_flash_flush_internal();
276         } ao_mutex_put(&ao_flash_mutex);
277 }
278
279 uint8_t
280 ao_storage_erase(uint32_t pos) __reentrant
281 {
282         ao_mutex_get(&ao_flash_mutex); {
283                 ao_flash_flush_internal();
284                 ao_flash_block = (uint16_t) (pos >> ao_flash_block_shift);
285                 memset(ao_flash_data, 0xff, ao_flash_block_size);
286                 ao_flash_block_dirty = 1;
287         } ao_mutex_put(&ao_flash_mutex);
288         return 1;
289 }
290
291 void
292 ao_storage_device_info(void) __reentrant
293 {
294         uint8_t status;
295
296         ao_storage_setup();
297         ao_mutex_get(&ao_flash_mutex); {
298                 status = ao_flash_read_status();
299                 printf ("Flash status: 0x%02x\n", status);
300                 printf ("Flash block shift: %d\n", ao_flash_block_shift);
301                 printf ("Flash block size: %d\n", ao_flash_block_size);
302                 printf ("Flash block mask: %d\n", ao_flash_block_mask);
303                 printf ("Flash device size: %ld\n", ao_storage_total);
304         } ao_mutex_put(&ao_flash_mutex);
305 }
306
307 /*
308  * To initialize the chip, set up the CS line and
309  * the SPI interface
310  */
311 void
312 ao_storage_device_init(void)
313 {
314         /* set up CS */
315         FLASH_CS = 1;
316         P1DIR |= (1 << FLASH_CS_INDEX);
317         P1SEL &= ~(1 << FLASH_CS_INDEX);
318 }