bc8b56ad7b32bfb6ba569c926a244bb587aaf853
[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 __xdata uint32_t        ao_storage_total;
23
24 /* Block size - device is erased in these units. At least 256 bytes */
25 __xdata uint32_t        ao_storage_block;
26
27 /* Byte offset of config block. Will be ao_storage_block bytes long */
28 __xdata uint32_t        ao_storage_config;
29
30 #define FLASH_CS                P1_1
31 #define FLASH_CS_INDEX          1
32
33 #define FLASH_BLOCK_SIZE_MAX    512
34
35 __xdata uint8_t ao_flash_mutex;
36
37 #define ao_flash_delay() do { \
38         _asm nop _endasm; \
39         _asm nop _endasm; \
40         _asm nop _endasm; \
41 } while(0)
42
43 void ao_flash_cs_low(void)
44 {
45         ao_flash_delay();
46         FLASH_CS = 0;
47         ao_flash_delay();
48 }
49
50 void ao_flash_cs_high(void)
51 {
52         ao_flash_delay();
53         FLASH_CS = 1;
54         ao_flash_delay();
55 }
56
57 struct ao_flash_instruction {
58         uint8_t instruction;
59         uint8_t address[3];
60 } __xdata ao_flash_instruction;
61
62 static void
63 ao_flash_set_pagesize_512(void)
64 {
65         ao_flash_cs_low();
66         ao_flash_instruction.instruction = FLASH_SET_CONFIG;
67         ao_flash_instruction.address[0] = FLASH_SET_512_BYTE_0;
68         ao_flash_instruction.address[1] = FLASH_SET_512_BYTE_1;
69         ao_flash_instruction.address[2] = FLASH_SET_512_BYTE_2;
70         ao_spi_send(&ao_flash_instruction, 4);
71         ao_flash_cs_high();
72 }
73
74
75 static uint8_t
76 ao_flash_read_status(void)
77 {
78         ao_flash_cs_low();
79         ao_flash_instruction.instruction = FLASH_READ_STATUS;
80         ao_spi_send(&ao_flash_instruction, 1);
81         ao_spi_recv(&ao_flash_instruction, 1);
82         ao_flash_cs_high();
83         return ao_flash_instruction.instruction;
84 }
85
86 #define FLASH_BLOCK_NONE        0xffff
87
88 static __xdata uint8_t ao_flash_data[FLASH_BLOCK_SIZE_MAX];
89 static __pdata uint16_t ao_flash_block = FLASH_BLOCK_NONE;
90 static __pdata uint8_t  ao_flash_block_dirty;
91 static __pdata uint8_t  ao_flash_write_pending;
92 static __pdata uint8_t  ao_flash_setup_done;
93 static __data uint8_t   ao_flash_block_shift;
94 static __data uint16_t  ao_flash_block_size;
95 static __data uint16_t  ao_flash_block_mask;
96
97 void
98 ao_storage_setup(void)
99 {
100         uint8_t status;
101
102         if (ao_flash_setup_done)
103                 return;
104
105         ao_mutex_get(&ao_flash_mutex);
106         if (ao_flash_setup_done) {
107                 ao_mutex_put(&ao_flash_mutex);
108                 return;
109         }
110
111         /* On first use, check to see if the flash chip has
112          * been programmed to use 512 byte pages. If not, do so.
113          * And then, because the flash part must be power cycled
114          * for that change to take effect, panic.
115          */
116         status = ao_flash_read_status();
117
118         if (!(status & FLASH_STATUS_PAGESIZE_512)) {
119                 ao_flash_set_pagesize_512();
120                 ao_panic(AO_PANIC_FLASH);
121         }
122
123         switch (status & 0x3c) {
124
125         /* AT45DB321D */
126         case 0x34:
127                 ao_flash_block_shift = 9;
128                 ao_storage_total = ((uint32_t) 4 * (uint32_t) 1024 * (uint32_t) 1024);
129                 break;
130
131         /* AT45DB161D */
132         case 0x2c:
133                 ao_flash_block_shift = 9;
134                 ao_storage_total = ((uint32_t) 2 * (uint32_t) 1024 * (uint32_t) 1024);
135                 break;
136
137         /* AT45DB081D */
138         case 0x24:
139                 ao_flash_block_shift = 8;
140                 ao_storage_total = ((uint32_t) 1024 * (uint32_t) 1024);
141                 break;
142
143         /* AT45DB041D */
144         case 0x1c:
145                 ao_flash_block_shift = 8;
146                 ao_storage_total = ((uint32_t) 512 * (uint32_t) 1024);
147                 break;
148
149         /* AT45DB021D */
150         case 0x14:
151                 ao_flash_block_shift = 8;
152                 ao_storage_total = ((uint32_t) 256 * (uint32_t) 1024);
153                 break;
154
155         /* AT45DB011D */
156         case 0x0c:
157                 ao_flash_block_shift = 8;
158                 ao_storage_total = ((uint32_t) 128 * (uint32_t) 1024);
159                 break;
160
161         default:
162                 ao_panic(AO_PANIC_FLASH);
163         }
164         ao_flash_block_size = 1 << ao_flash_block_shift;
165
166         ao_storage_block = ao_flash_block_size;
167         ao_storage_config = ao_storage_total - ao_storage_block;
168
169         ao_flash_setup_done = 1;
170         ao_mutex_put(&ao_flash_mutex);
171 }
172
173 static void
174 ao_flash_wait_write(void)
175 {
176         if (ao_flash_write_pending) {
177                 for (;;) {
178                         uint8_t status = ao_flash_read_status();
179                         if ((status & FLASH_STATUS_RDY))
180                                 break;
181                 }
182                 ao_flash_write_pending = 0;
183         }
184 }
185
186 /* Write the current block to the FLASHPROM */
187 static void
188 ao_flash_write_block(void)
189 {
190         ao_flash_wait_write();
191         ao_flash_cs_low();
192         ao_flash_instruction.instruction = FLASH_WRITE;
193
194         /* 13/14 block bits + 9/8 byte bits (always 0) */
195         ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
196         ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
197         ao_flash_instruction.address[2] = 0;
198         ao_spi_send(&ao_flash_instruction, 4);
199         ao_spi_send(ao_flash_data, ao_storage_block);
200         ao_flash_cs_high();
201         ao_flash_write_pending = 1;
202 }
203
204 /* Read the current block from the FLASHPROM */
205 static void
206 ao_flash_read_block(void)
207 {
208         ao_flash_wait_write();
209         ao_flash_cs_low();
210         ao_flash_instruction.instruction = FLASH_READ;
211
212         /* 13/14 block bits + 9/8 byte bits (always 0) */
213         ao_flash_instruction.address[0] = ao_flash_block >> (16 - ao_flash_block_shift);
214         ao_flash_instruction.address[1] = ao_flash_block << (ao_flash_block_shift - 8);
215         ao_flash_instruction.address[2] = 0;
216         ao_spi_send(&ao_flash_instruction, 4);
217         ao_spi_recv(ao_flash_data, ao_flash_block_size);
218         ao_flash_cs_high();
219 }
220
221 static void
222 ao_flash_flush_internal(void)
223 {
224         if (ao_flash_block_dirty) {
225                 ao_flash_write_block();
226                 ao_flash_block_dirty = 0;
227         }
228 }
229
230 static void
231 ao_flash_fill(uint16_t block)
232 {
233         if (block != ao_flash_block) {
234                 ao_flash_flush_internal();
235                 ao_flash_block = block;
236                 ao_flash_read_block();
237         }
238 }
239
240 uint8_t
241 ao_storage_write(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
242 {
243         uint16_t block;
244         uint16_t this_len;
245         uint16_t        this_off;
246
247         ao_storage_setup();
248         if (pos >= ao_storage_total || pos + len > ao_storage_total)
249                 return 0;
250         while (len) {
251
252                 /* Compute portion of transfer within
253                  * a single block
254                  */
255                 this_off = (uint16_t) pos & ao_flash_block_mask;
256                 this_len = ao_flash_block_size - this_off;
257                 block = (uint16_t) (pos >> ao_flash_block_shift);
258                 if (this_len > len)
259                         this_len = len;
260
261                 /* Transfer the data */
262                 ao_mutex_get(&ao_flash_mutex); {
263                         if (this_len != ao_flash_block_size)
264                                 ao_flash_fill(block);
265                         else {
266                                 ao_flash_flush_internal();
267                                 ao_flash_block = block;
268                         }
269                         memcpy(ao_flash_data + this_off, buf, this_len);
270                         ao_flash_block_dirty = 1;
271                 } ao_mutex_put(&ao_flash_mutex);
272
273                 /* See how much is left */
274                 buf += this_len;
275                 len -= this_len;
276                 pos += this_len;
277         }
278         return 1;
279 }
280
281 uint8_t
282 ao_storage_read(uint32_t pos, __xdata void *buf, uint16_t len) __reentrant
283 {
284         uint16_t block;
285         uint16_t this_len;
286         uint16_t this_off;
287
288         ao_storage_setup();
289         if (pos >= ao_storage_total || pos + len > ao_storage_total)
290                 return 0;
291         while (len) {
292
293
294                 /* Compute portion of transfer within
295                  * a single block
296                  */
297                 this_off = (uint16_t) pos & ao_flash_block_mask;
298                 this_len = ao_flash_block_size - this_off;
299                 block = (uint16_t) (pos >> ao_flash_block_shift);
300                 if (this_len > len)
301                         this_len = len;
302
303                 /* Transfer the data */
304                 ao_mutex_get(&ao_flash_mutex); {
305                         ao_flash_fill(block);
306                         memcpy(buf, ao_flash_data + this_off, this_len);
307                 } ao_mutex_put(&ao_flash_mutex);
308
309                 /* See how much is left */
310                 buf += this_len;
311                 len -= this_len;
312                 pos += this_len;
313         }
314         return 1;
315 }
316
317 void
318 ao_storage_flush(void) __reentrant
319 {
320         ao_mutex_get(&ao_flash_mutex); {
321                 ao_flash_flush_internal();
322         } ao_mutex_put(&ao_flash_mutex);
323 }
324
325 uint8_t
326 ao_storage_erase(uint32_t pos) __reentrant
327 {
328         ao_mutex_get(&ao_flash_mutex); {
329                 uint16_t block = (uint16_t) (pos >> ao_flash_block_shift);
330                 ao_flash_fill(block);
331                 memset(ao_flash_data, 0xff, ao_flash_block_size);
332                 ao_flash_block_dirty = 1;
333         } ao_mutex_put(&ao_flash_mutex);
334         return 1;
335 }
336
337 static void
338 flash_dump(void) __reentrant
339 {
340         static __xdata uint8_t  b;
341         uint16_t block;
342         uint8_t i;
343
344         ao_cmd_hex();
345         block = ao_cmd_lex_i;
346         if (ao_cmd_status != ao_cmd_success)
347                 return;
348         i = 0;
349         do {
350                 if ((i & 7) == 0) {
351                         if (i)
352                                 putchar('\n');
353                         ao_cmd_put16((uint16_t) i);
354                 }
355                 putchar(' ');
356                 ao_storage_read(((uint32_t) block << 8) | i, &b, 1);
357                 ao_cmd_put8(b);
358                 ++i;
359         } while (i != 0);
360         putchar('\n');
361 }
362
363 static void
364 flash_store(void) __reentrant
365 {
366         uint16_t block;
367         uint8_t i;
368         uint16_t len;
369         static __xdata uint8_t b;
370         uint32_t addr;
371
372         ao_cmd_hex();
373         block = ao_cmd_lex_i;
374         ao_cmd_hex();
375         i = ao_cmd_lex_i;
376         addr = ((uint32_t) block << 8) | i;
377         ao_cmd_hex();
378         len = ao_cmd_lex_i;
379         if (ao_cmd_status != ao_cmd_success)
380                 return;
381         while (len--) {
382                 ao_cmd_hex();
383                 if (ao_cmd_status != ao_cmd_success)
384                         return;
385                 b = ao_cmd_lex_i;
386                 ao_storage_write(addr, &b, 1);
387                 addr++;
388         }
389         ao_storage_flush();
390 }
391
392 static void
393 flash_status(void) __reentrant
394 {
395         uint8_t status;
396
397         ao_storage_setup();
398         ao_mutex_get(&ao_flash_mutex); {
399                 status = ao_flash_read_status();
400                 printf ("Flash status: 0x%02x\n", status);
401                 printf ("Flash block shift: %d\n", ao_flash_block_shift);
402                 printf ("Flash block size: %d\n", ao_flash_block_size);
403                 printf ("Flash block mask: %d\n", ao_flash_block_mask);
404                 printf ("Flash device size: %ld\n", ao_storage_total);
405         } ao_mutex_put(&ao_flash_mutex);
406 }
407
408 __code struct ao_cmds ao_flash_cmds[] = {
409         { 'e', flash_dump,      "e <block>                          Dump a block of flash data" },
410         { 'w', flash_store,     "w <block> <start> <len> <data> ... Write data to flash" },
411         { 'f', flash_status,    "f                                  Show flash status register" },
412         { 0,   flash_store, NULL },
413 };
414
415 /*
416  * To initialize the chip, set up the CS line and
417  * the SPI interface
418  */
419 void
420 ao_storage_init(void)
421 {
422         /* set up CS */
423         FLASH_CS = 1;
424         P1DIR |= (1 << FLASH_CS_INDEX);
425         P1SEL &= ~(1 << FLASH_CS_INDEX);
426         ao_cmd_register(&ao_flash_cmds[0]);
427 }