altos: Add nickle kalman implementation.
[fw/altos] / src / ao_intflash.c
1 /*
2  * Copyright © 2011  Anthony Towns <aj@erisian.com.au>
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 "cc1111.h"
20
21 #define ENDOFCODE  (CODESIZE)
22 #define AO_INTFLASH_BLOCK       1024
23 #define AO_INTFLASH_BLOCKS      ((0x8000 - ENDOFCODE)/AO_INTFLASH_BLOCK)
24 #define AO_INTFLASH_SIZE        (AO_INTFLASH_BLOCK * AO_INTFLASH_BLOCKS)
25 #define AO_INTFLASH_LOCATION    (0x8000 - AO_INTFLASH_SIZE)
26
27 /*
28  *       21000 * 24e6
29  * FWT = ------------
30  *           16e9
31  *
32  *     = 31.5
33  *
34  * Round up and use 32
35  */
36
37 #define FLASH_TIMING    0x20
38
39 #if AO_INTFLASH_BLOCKS < 2
40 #error "Too few pages"
41 #endif
42
43 #if AO_INFTLASH_LOCATION % 1024 != 0
44 #error "Pages aren't aligned properly"
45 #endif
46
47 __xdata __at(AO_INTFLASH_LOCATION) uint8_t ao_intflash[AO_INTFLASH_SIZE];
48
49 /* Total bytes of available storage */
50 __xdata uint32_t        ao_storage_total = sizeof(ao_intflash);
51
52 /* Block size - device is erased in these units. */
53 __xdata uint32_t        ao_storage_block = AO_INTFLASH_BLOCK;
54
55 /* Byte offset of config block. Will be ao_storage_block bytes long */
56 __xdata uint32_t        ao_storage_config = sizeof(ao_intflash) - AO_INTFLASH_BLOCK;
57
58 /* Storage unit size - device reads and writes must be within blocks of this size. */
59 __xdata uint16_t        ao_storage_unit = AO_INTFLASH_BLOCK;
60
61 __xdata static uint8_t  ao_intflash_dma_done;
62 static uint8_t ao_intflash_dma;
63
64 /*
65  * The internal flash chip is arranged in 1kB sectors; the
66  * chip cannot erase in units smaller than that.
67  *
68  * Writing happens in units of 2 bytes and
69  * can only change bits from 1 to 0. So, you can rewrite
70  * the same contents, or append to an existing page easily enough
71  */
72
73 /*
74  * Erase the specified sector
75  */
76 uint8_t
77 ao_storage_erase(uint32_t pos) __reentrant
78 {
79         uint16_t addr;
80
81         if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
82                 return 0;
83
84         addr = ((uint16_t)(ao_intflash + pos) >> 1);
85
86         FADDRH = addr >> 8;
87         FADDRL = addr;
88
89         __critical {
90                 _asm
91                 .even
92                 orl _FCTL, #FCTL_ERASE;         ; FCTL |=  FCTL_ERASE
93                 nop                             ; Required, see datasheet.
94                 _endasm;
95         }
96
97         return 1;
98 }
99
100 /*
101  * Write to flash
102  */
103
104 static void
105 ao_intflash_write_aligned(uint16_t pos, __xdata void *d, uint16_t len) __reentrant
106 {
107         pos = ((uint16_t) ao_intflash + pos) >> 1;
108
109         ao_dma_set_transfer(ao_intflash_dma,
110                             d,
111                             &FWDATAXADDR,
112                             len,
113                             DMA_CFG0_WORDSIZE_8 |
114                             DMA_CFG0_TMODE_SINGLE |
115                             DMA_CFG0_TRIGGER_FLASH,
116                             DMA_CFG1_SRCINC_1 |
117                             DMA_CFG1_DESTINC_0 |
118                             DMA_CFG1_PRIORITY_HIGH);
119
120         FADDRH = pos >> 8;
121         FADDRL = pos;
122
123         ao_dma_start(ao_intflash_dma);
124
125         __critical {
126                 _asm
127                 .even
128                 orl _FCTL, #FCTL_WRITE;         ; FCTL |=  FCTL_WRITE
129                 nop
130                 _endasm;
131         }
132 }
133
134 static void
135 ao_intflash_write_byte(uint16_t pos, uint8_t byte) __reentrant
136 {
137         static __xdata uint8_t b[2];
138
139         if (pos & 1) {
140                 b[0] = 0xff;
141                 b[1] = byte;
142         } else {
143                 b[0] = byte;
144                 b[1] = 0xff;
145         }
146         ao_intflash_write_aligned(pos, b, 2);
147 }
148
149 uint8_t
150 ao_storage_device_write(uint32_t pos32, __xdata void *v, uint16_t len) __reentrant
151 {
152         uint16_t pos = pos32;
153         __xdata uint8_t *d = v;
154         uint8_t oddlen;
155
156         if (pos >= ao_storage_total || pos + len > ao_storage_total)
157                 return 0;
158         if (len == 0)
159                 return 1;
160
161         if (pos & 1) {
162                 ao_intflash_write_byte(pos++, *d++);
163                 len--;
164         }
165         oddlen = len & 1;
166         len -= oddlen;
167         if (len)
168                 ao_intflash_write_aligned(pos, d, len);
169         if (oddlen)
170                 ao_intflash_write_byte(pos + len, d[len]);
171
172         return 1;
173 }
174
175 /*
176  * Read from flash
177  */
178 uint8_t
179 ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
180 {
181         if (pos >= ao_storage_total || pos + len > ao_storage_total)
182                 return 0;
183         memcpy(d, ao_intflash+pos, len);
184         return 1;
185 }
186
187 void
188 ao_storage_flush(void) __reentrant
189 {
190 }
191
192 void
193 ao_storage_setup(void)
194 {
195 }
196
197 void
198 ao_storage_device_info(void) __reentrant
199 {
200         printf ("Using internal flash, starting at 0x%04x\n", AO_INTFLASH_LOCATION);
201 }
202
203 void
204 ao_storage_device_init(void)
205 {
206         ao_intflash_dma = ao_dma_alloc(&ao_intflash_dma_done);
207
208         FWT = FLASH_TIMING;
209 }