44eb952baaa1236400cb3f8c690cc793989941cb
[fw/altos] / ao-tools / lib / ccdbg-flash.c
1 /*
2  * Copyright © 2008 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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ccdbg.h"
20
21 /* From SWRA124 section 3.1.6 */
22
23 static uint8_t flash_page[] = {
24
25         MOV_direct_data, P1DIR, 0x02,
26         MOV_direct_data, P1,    0xFF,
27
28         MOV_direct_data, FADDRH, 0,
29 #define FLASH_ADDR_HIGH 8
30
31         MOV_direct_data, FADDRL, 0,
32 #define FLASH_ADDR_LOW  11
33
34         MOV_DPTR_data16, 0, 0,
35 #define RAM_ADDR_HIGH   13
36 #define RAM_ADDR_LOW    14
37
38         MOV_Rn_data(7), 0,
39 #define FLASH_WORDS_HIGH        16
40
41         MOV_Rn_data(6), 0,
42 #define FLASH_WORDS_LOW         18
43
44         MOV_direct_data, FWT, 0x20,
45 #define FLASH_TIMING            21
46
47         MOV_direct_data, FCTL, FCTL_ERASE,
48 /* eraseWaitLoop: */
49                 MOV_A_direct,           FCTL,
50         JB, ACC(FCTL_BUSY_BIT), 0xfb,
51
52         MOV_direct_data, P1, 0xfd,
53
54         MOV_direct_data, FCTL, FCTL_WRITE,
55 /* writeLoop: */
56                 MOV_Rn_data(5), 2,
57 /* writeWordLoop: */
58                         MOVX_A_atDPTR,
59                         INC_DPTR,
60                         MOV_direct_A, FWDATA,
61                 DJNZ_Rn_rel(5), 0xfa,           /* writeWordLoop */
62 /* writeWaitLoop: */
63                         MOV_A_direct, FCTL,
64                 JB, ACC(FCTL_SWBSY_BIT), 0xfb,          /* writeWaitLoop */
65         DJNZ_Rn_rel(6), 0xf1,                   /* writeLoop */
66         DJNZ_Rn_rel(7), 0xef,                   /* writeLoop */
67
68         MOV_direct_data, P1DIR, 0x00,
69         MOV_direct_data, P1,    0xFF,
70         TRAP,
71 };
72
73 #define FLASH_RAM       0xf000
74
75 #if 0
76 static uint8_t  flash_erase_page[] = {
77         3,      MOV_direct_data, FADDRH, 0,
78 #define ERASE_PAGE_HIGH 3
79
80         3,      MOV_direct_data, FADDRL, 0,
81 #define ERASE_PAGE_LOW  7
82
83         3,      MOV_direct_data, FWT, 0x2A,
84         3,      MOV_direct_data, FCTL, FCTL_ERASE,
85         0
86 };
87
88 static uint8_t  flash_read_control[] = {
89         2,      MOV_A_direct,   FCTL,
90         0
91 };
92 #endif
93
94 #if 0
95 static uint8_t  flash_control_clear[] = {
96         3,      MOV_direct_data,        FCTL, 0,
97         2,      MOV_A_direct,           FCTL,
98         0
99 };
100 #endif
101
102 #if 0
103 static uint8_t
104 ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr)
105 {
106         uint16_t        page_addr = addr >> 1;
107         uint8_t         status;
108         uint8_t         old[0x10], new[0x10];
109         int             i;
110
111         ccdbg_read_memory(dbg, addr, old, 0x10);
112         flash_erase_page[ERASE_PAGE_HIGH] = page_addr >> 8;
113         flash_erase_page[ERASE_PAGE_LOW] = page_addr & 0xff;
114         status = ccdbg_execute(dbg, flash_erase_page);
115         ccdbg_debug(CC_DEBUG_FLASH, "erase status 0x%02x\n", status);
116         do {
117                 status = ccdbg_execute(dbg, flash_read_control);
118                 ccdbg_debug(CC_DEBUG_FLASH, "fctl 0x%02x\n", status);
119         } while (status & FCTL_BUSY);
120         ccdbg_read_memory(dbg, addr, new, 0x10);
121         for (i = 0; i < 0x10; i++)
122                 ccdbg_debug(CC_DEBUG_FLASH, "0x%02x -> 0x%02x\n", old[i], new[i]);
123         status = ccdbg_execute(dbg, flash_control_clear);
124         ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status);
125         return 0;
126 }
127 #endif
128
129 #if 0
130 static uint8_t flash_write[] = {
131         MOV_direct_data, P1DIR, 0x02,
132         MOV_direct_data, P1,    0xFD,
133
134         MOV_A_direct, FCTL,
135         JB,     ACC(FCTL_BUSY_BIT), 0xf1,
136
137         MOV_direct_data, FCTL, 0x20,
138
139         MOV_direct_data, FADDRH, 0,
140 #define WRITE_PAGE_HIGH 16
141
142         MOV_direct_data, FADDRL, 0,
143 #define WRITE_PAGE_LOW  19
144
145         MOV_direct_data, FCTL, FCTL_WRITE,
146         MOV_direct_data, FWDATA, 0,
147 #define WRITE_BYTE_0    25
148         MOV_direct_data, FWDATA, 0,
149 #define WRITE_BYTE_1    28
150         MOV_A_direct, FCTL,
151         JB,     ACC(FCTL_SWBSY_BIT), 0xf1,
152
153         MOV_direct_data, P1,    0xFF,
154         TRAP,
155 };
156 #endif
157
158 static uint8_t
159 ccdbg_clock_init(struct ccdbg *dbg)
160 {
161         static uint8_t set_clkcon_fast[] = {
162                 3,      MOV_direct_data,        CLKCON, 0x00,
163                 0
164         };
165
166         static uint8_t get_sleep[] = {
167                 2,      MOV_A_direct, SLEEP,
168                 0
169         };
170
171         uint8_t status;
172
173         ccdbg_execute(dbg, set_clkcon_fast);
174         do {
175                 status = ccdbg_execute(dbg, get_sleep);
176         } while (!(status & 0x40));
177         return 0;
178 }
179
180 #if 0
181 static uint8_t
182 ccdbg_flash_write_word(struct ccdbg *dbg, uint16_t addr, uint8_t data[2])
183 {
184         uint16_t page_addr = addr >> 1;
185         uint8_t check[2];
186         uint8_t status;
187         int i;
188
189         flash_write[WRITE_PAGE_HIGH] = page_addr >> 8;
190         flash_write[WRITE_PAGE_LOW] = page_addr & 0xff;
191         flash_write[WRITE_BYTE_0] = data[0];
192         flash_write[WRITE_BYTE_1] = data[1];
193         ccdbg_debug(CC_DEBUG_FLASH, "upload flash write\n");
194         ccdbg_write_memory(dbg, 0xf000, flash_write, sizeof(flash_write));
195         ccdbg_set_pc(dbg, 0xf000);
196         ccdbg_resume(dbg);
197         for (;;) {
198                 status = ccdbg_read_status(dbg);
199                 ccdbg_debug(CC_DEBUG_FLASH, "waiting for write 0x%02x\n", status);
200                 if ((status & CC_STATUS_CPU_HALTED) != 0)
201                         break;
202                 sleep (1);
203         }
204         status = ccdbg_execute(dbg, flash_control_clear);
205         ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status);
206         ccdbg_read_memory(dbg, addr, check, 2);
207         for (i = 0; i < 2; i++)
208                 ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", data[i], check[i]);
209         return 0;
210 }
211 #endif
212
213 #define TIMERS_OFF              0x08
214 #define DMA_PAUSE               0x04
215 #define TIMER_SUSPEND           0x02
216 #define SEL_FLASH_INFO_PAGE     0x01
217
218 #if 0
219 static uint8_t
220 ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock)
221 {
222         uint8_t config;
223         uint8_t bytes[2];
224         uint8_t old[1], new[1];
225
226         config = ccdbg_rd_config(dbg);
227         ccdbg_wr_config(dbg, config|SEL_FLASH_INFO_PAGE);
228         bytes[0] = lock;
229         bytes[1] = 0;
230         ccdbg_flash_erase_page(dbg, 0);
231         ccdbg_read_memory(dbg, 0, old, 1);
232         ccdbg_flash_write_word(dbg, 0, bytes);
233         ccdbg_read_memory(dbg, 0, new, 1);
234         ccdbg_debug(CC_DEBUG_FLASH, "flash lock 0x%02x -> 0x%02x\n", old[0], new[0]);
235         ccdbg_wr_config(dbg, config & ~SEL_FLASH_INFO_PAGE);
236         return 0;
237 }
238 #endif
239
240 uint8_t
241 ccdbg_flash_hex_image(struct ccdbg *dbg, struct ao_hex_image *image)
242 {
243         uint16_t flash_prog;
244         uint16_t flash_len;
245         uint8_t fwt;
246         uint16_t flash_addr;
247         uint16_t flash_word_addr;
248         uint16_t flash_words;
249         uint8_t flash_words_high, flash_words_low;
250         uint16_t ram_addr;
251         uint8_t status;
252         uint16_t remain, this_time, start;
253         uint8_t verify[0x400];
254         int times;
255
256         ccdbg_clock_init(dbg);
257         if (image->address + image->length > 0x8000) {
258                 fprintf(stderr, "cannot flash image from 0x%04x to 0x%04x\n",
259                         image->address, image->address + image->length);
260                 return 1;
261         }
262         if (image->address & 0x3ff) {
263                 fprintf(stderr, "flash image must start on page boundary\n");
264                 return 1;
265         }
266         ram_addr = 0xf000;
267
268
269         flash_prog = 0xf400;
270
271         fwt = 0x20;
272
273         flash_page[FLASH_TIMING] = fwt;
274         ccdbg_debug(CC_DEBUG_FLASH, "Upload %d flash program bytes to 0x%04x\n",
275                sizeof (flash_page), flash_prog);
276         ccdbg_write_memory(dbg, flash_prog, flash_page, sizeof(flash_page));
277
278         remain = image->length;
279         start = 0;
280         while (remain) {
281                 this_time = remain;
282                 if (this_time > 0x400)
283                         this_time = 0x400;
284
285                 ccdbg_debug(CC_DEBUG_FLASH, "Upload %d bytes at 0x%04x\n", this_time, ram_addr);
286                 ccdbg_write_memory(dbg, ram_addr, image->data + start, this_time);
287 #if 0
288                 ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in ram\n", this_time);
289                 ccdbg_read_memory(dbg, ram_addr, verify, this_time);
290                 if (memcmp (image->data + start, verify, this_time) != 0) {
291                         fprintf(stderr, "ram verify failed\n");
292                         return 1;
293                 }
294 #endif
295
296                 flash_addr = image->address + start;
297                 flash_word_addr = flash_addr >> 1;
298                 flash_len = this_time + (this_time & 1);
299                 flash_words = flash_len >> 1;
300
301                 flash_words_low = flash_words & 0xff;
302                 flash_words_high = flash_words >> 8;
303
304                 /* The flash code above is lame */
305                 if (flash_words_low)
306                         flash_words_high++;
307
308                 ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_HIGH, flash_word_addr >> 8);
309                 ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_LOW, flash_word_addr & 0xff);
310
311                 ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_HIGH, ram_addr >> 8);
312                 ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_LOW, ram_addr & 0xff);
313
314                 ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_HIGH, flash_words_high);
315                 ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words_low);
316
317                 ccdbg_set_pc(dbg, flash_prog);
318                 ccdbg_debug(CC_DEBUG_FLASH, "Flashing %d bytes at 0x%04x\n",
319                             this_time, flash_addr);
320                 status = ccdbg_resume(dbg);
321                 for (times = 0; times < 10; times++) {
322                         status = ccdbg_read_status(dbg);
323                         ccdbg_debug(CC_DEBUG_FLASH, ".");
324                         ccdbg_flush(CC_DEBUG_FLASH);
325                         if ((status & CC_STATUS_CPU_HALTED) != 0)
326                                 break;
327                         usleep(10000);
328                 }
329                 ccdbg_debug(CC_DEBUG_FLASH, "\n");
330                 if (times == 10) {
331                         fprintf(stderr, "flash page timed out\n");
332                         return 1;
333                 }
334
335                 ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in flash\n", this_time);
336                 ccdbg_read_memory(dbg, flash_addr, verify, this_time);
337                 if (memcmp (image->data + start, verify, this_time) != 0) {
338                         int i;
339                         fprintf(stderr, "flash verify failed\n");
340                         for (i = 0; i < this_time; i++) {
341                                 if (image->data[start + i] != verify[i])
342                                         fprintf(stderr, "0x%04x: 0x%02x != 0x%02x\n",
343                                                 start + i, image->data[start+i], verify[i]);
344                         }
345                         return 1;
346                 }
347                 remain -= this_time;
348                 start += this_time;
349         }
350         return 0;
351 }