lingering change for eCos flash driver
[fw/openocd] / src / flash / ecos.c
1 /***************************************************************************\r
2  *   Copyright (C) 2008 Ã˜yvind Harboe                                      *\r
3  *   oyvind.harboe@zylin.com                                               *\r
4  *                                                                         *\r
5  *   This program is free software; you can redistribute it and/or modify  *\r
6  *   it under the terms of the GNU General Public License as published by  *\r
7  *   the Free Software Foundation; either version 2 of the License, or     *\r
8  *   (at your option) any later version.                                   *\r
9  *                                                                         *\r
10  *   This program is distributed in the hope that it will be useful,       *\r
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
13  *   GNU General Public License for more details.                          *\r
14  *                                                                         *\r
15  *   You should have received a copy of the GNU General Public License     *\r
16  *   along with this program; if not, write to the                         *\r
17  *   Free Software Foundation, Inc.,                                       *\r
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
19  ***************************************************************************/\r
20 #ifdef HAVE_CONFIG_H\r
21 #include "config.h"\r
22 #endif\r
23 \r
24 #include "replacements.h"\r
25 \r
26 \r
27 #include "flash.h"\r
28 \r
29 #include "target.h"\r
30 \r
31 #include "flash.h"\r
32 #include "target.h"\r
33 #include "log.h"\r
34 #include "binarybuffer.h"\r
35 #include "../target/embeddedice.h"\r
36 #include "types.h"\r
37 \r
38 \r
39 \r
40 int ecosflash_register_commands(struct command_context_s *cmd_ctx);\r
41 int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
42 int ecosflash_erase(struct flash_bank_s *bank, int first, int last);\r
43 int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last);\r
44 int ecosflash_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
45 int ecosflash_probe(struct flash_bank_s *bank);\r
46 int ecosflash_erase_check(struct flash_bank_s *bank);\r
47 int ecosflash_protect_check(struct flash_bank_s *bank);\r
48 int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
49 \r
50 u32 ecosflash_get_flash_status(flash_bank_t *bank);\r
51 void ecosflash_set_flash_mode(flash_bank_t *bank,int mode);\r
52 u32 ecosflash_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout);\r
53 int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
54 \r
55 flash_driver_t ecosflash_flash =\r
56 {\r
57         .name = "ecosflash",\r
58         .register_commands = ecosflash_register_commands,\r
59         .flash_bank_command = ecosflash_flash_bank_command,\r
60         .erase = ecosflash_erase,\r
61         .protect = ecosflash_protect,\r
62         .write = ecosflash_write,\r
63         .probe = ecosflash_probe,\r
64         .auto_probe = ecosflash_probe,\r
65         .erase_check = ecosflash_erase_check,\r
66         .protect_check = ecosflash_protect_check,\r
67         .info = ecosflash_info\r
68 };\r
69 \r
70 typedef struct ecosflash_flash_bank_s\r
71 {\r
72         struct target_s *target;\r
73         working_area_t *write_algorithm;\r
74         working_area_t *erase_check_algorithm;\r
75         char *driverPath;\r
76         u32 start_address;\r
77 } ecosflash_flash_bank_t;\r
78 \r
79 static const int sectorSize=0x10000;\r
80 \r
81 char *\r
82 flash_errmsg(int err);\r
83 \r
84 #ifndef __ECOS\r
85 #define FLASH_ERR_OK              0x00  // No error - operation complete\r
86 #define FLASH_ERR_INVALID         0x01  // Invalid FLASH address\r
87 #define FLASH_ERR_ERASE           0x02  // Error trying to erase\r
88 #define FLASH_ERR_LOCK            0x03  // Error trying to lock/unlock\r
89 #define FLASH_ERR_PROGRAM         0x04  // Error trying to program\r
90 #define FLASH_ERR_PROTOCOL        0x05  // Generic error\r
91 #define FLASH_ERR_PROTECT         0x06  // Device/region is write-protected\r
92 #define FLASH_ERR_NOT_INIT        0x07  // FLASH info not yet initialized\r
93 #define FLASH_ERR_HWR             0x08  // Hardware (configuration?) problem\r
94 #define FLASH_ERR_ERASE_SUSPEND   0x09  // Device is in erase suspend mode\r
95 #define FLASH_ERR_PROGRAM_SUSPEND 0x0a  // Device is in in program suspend mode\r
96 #define FLASH_ERR_DRV_VERIFY      0x0b  // Driver failed to verify data\r
97 #define FLASH_ERR_DRV_TIMEOUT     0x0c  // Driver timed out waiting for device\r
98 #define FLASH_ERR_DRV_WRONG_PART  0x0d  // Driver does not support device\r
99 #define FLASH_ERR_LOW_VOLTAGE     0x0e  // Not enough juice to complete job\r
100 \r
101 \r
102 char *\r
103 flash_errmsg(int err)\r
104 {\r
105     switch (err) {\r
106     case FLASH_ERR_OK:\r
107         return "No error - operation complete";\r
108     case FLASH_ERR_ERASE_SUSPEND:\r
109         return "Device is in erase suspend state";\r
110     case FLASH_ERR_PROGRAM_SUSPEND:\r
111         return "Device is in program suspend state";\r
112     case FLASH_ERR_INVALID:\r
113         return "Invalid FLASH address";\r
114     case FLASH_ERR_ERASE:\r
115         return "Error trying to erase";\r
116     case FLASH_ERR_LOCK:\r
117         return "Error trying to lock/unlock";\r
118     case FLASH_ERR_PROGRAM:\r
119         return "Error trying to program";\r
120     case FLASH_ERR_PROTOCOL:\r
121         return "Generic error";\r
122     case FLASH_ERR_PROTECT:\r
123         return "Device/region is write-protected";\r
124     case FLASH_ERR_NOT_INIT:\r
125         return "FLASH sub-system not initialized";\r
126     case FLASH_ERR_DRV_VERIFY:\r
127         return "Data verify failed after operation";\r
128     case FLASH_ERR_DRV_TIMEOUT:\r
129         return "Driver timed out waiting for device";\r
130     case FLASH_ERR_DRV_WRONG_PART:\r
131         return "Driver does not support device";\r
132     case FLASH_ERR_LOW_VOLTAGE:\r
133         return "Device reports low voltage";\r
134     default:\r
135         return "Unknown error";\r
136     }\r
137 }\r
138 #endif\r
139 \r
140 /* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>\r
141  */\r
142 int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
143 {\r
144         ecosflash_flash_bank_t *info;\r
145         \r
146         if (argc < 7)\r
147         {\r
148                 WARNING("incomplete flash_bank ecosflash configuration");\r
149                 return ERROR_FLASH_BANK_INVALID;\r
150         }\r
151         \r
152         info = malloc(sizeof(ecosflash_flash_bank_t));\r
153         if(info == NULL)\r
154         {\r
155                 ERROR("no memory for flash bank info");\r
156                 exit(-1);\r
157         }\r
158         bank->driver_priv = info;\r
159         info->driverPath=strdup(args[6]);\r
160 \r
161         // eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as \r
162         // a way to improve impeadance matach between OpenOCD and eCos flash\r
163         // driver\r
164         int i = 0;\r
165         u32 offset = 0;\r
166         bank->num_sectors=bank->size/sectorSize;\r
167         bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);\r
168         for (i = 0; i < bank->num_sectors; i++)\r
169         {\r
170                 bank->sectors[i].offset = offset;\r
171                 bank->sectors[i].size = sectorSize;\r
172                 offset += bank->sectors[i].size;\r
173                 bank->sectors[i].is_erased = -1;\r
174                 bank->sectors[i].is_protected = 0;\r
175         }\r
176         \r
177         info->target = get_target_by_num(strtoul(args[5], NULL, 0));\r
178         if (info->target == NULL)\r
179         {\r
180                 ERROR("no target '%i' configured", (int)strtoul(args[5], NULL, 0));\r
181                 exit(-1);\r
182         }\r
183         return ERROR_OK;\r
184 }\r
185 \r
186 \r
187 int loadDriver(ecosflash_flash_bank_t *info)\r
188 {\r
189         u32 buf_cnt;\r
190         u32 image_size;\r
191         image_t image;  \r
192         \r
193         image.base_address_set = 0;\r
194         image.start_address_set = 0;\r
195         target_t *target=info->target;\r
196         \r
197         if (image_open(&image, info->driverPath, NULL) != ERROR_OK)\r
198         {\r
199                 ERROR("load_image error: %s", image.error_str);\r
200                 return ERROR_FLASH_BANK_INVALID;\r
201         }\r
202         \r
203         info->start_address=image.start_address;\r
204         \r
205         image_size = 0x0;\r
206         int i;\r
207         for (i = 0; i < image.num_sections; i++)\r
208         {\r
209                 void *buffer = malloc(image.sections[i].size);\r
210                 int retval;\r
211                 if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)\r
212                 {\r
213                         ERROR("image_read_section failed with error code: %i", retval);\r
214                         free(buffer);\r
215                         image_close(&image);\r
216                         return ERROR_FLASH_BANK_INVALID;\r
217                 }\r
218                 target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);\r
219                 image_size += buf_cnt;\r
220                 DEBUG("%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address);\r
221                 \r
222                 free(buffer);\r
223         }\r
224 \r
225         image_close(&image);\r
226 \r
227         return ERROR_OK;\r
228 }\r
229 \r
230 \r
231 static int const OFFSET_ERASE=0x0;\r
232 static int const OFFSET_ERASE_SIZE=0x8;\r
233 static int const OFFSET_FLASH=0xc;\r
234 static int const OFFSET_FLASH_SIZE=0x8;\r
235 static int const OFFSET_GET_WORKAREA=0x18;\r
236 static int const OFFSET_GET_WORKAREA_SIZE=0x4;\r
237 \r
238 \r
239 int runCode(ecosflash_flash_bank_t *info, \r
240                 u32 codeStart, u32 codeStop, u32 r0, u32 r1, u32 r2, \r
241                 u32 *result,\r
242                 // timeout in ms\r
243                 int timeout)\r
244 {\r
245         target_t *target=info->target;\r
246 \r
247         reg_param_t reg_params[3];\r
248         armv4_5_algorithm_t armv4_5_info;\r
249         armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;\r
250         armv4_5_info.core_mode = ARMV4_5_MODE_SVC;\r
251         armv4_5_info.core_state = ARMV4_5_STATE_ARM;\r
252         \r
253         init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);\r
254         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);\r
255         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);\r
256         \r
257         buf_set_u32(reg_params[0].value, 0, 32, r0);\r
258         buf_set_u32(reg_params[1].value, 0, 32, r1);\r
259         buf_set_u32(reg_params[2].value, 0, 32, r2);\r
260         \r
261         int retval;\r
262         if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params,\r
263                         codeStart,\r
264                         codeStop, timeout, \r
265                         &armv4_5_info)) != ERROR_OK)\r
266         {\r
267                 ERROR("error executing eCos flash algorithm");\r
268                 return retval;\r
269         }\r
270         \r
271         *result=buf_get_u32(reg_params[0].value, 0, 32);\r
272         \r
273         destroy_reg_param(&reg_params[0]);\r
274         destroy_reg_param(&reg_params[1]);\r
275         destroy_reg_param(&reg_params[2]);\r
276         \r
277         return ERROR_OK;\r
278 }\r
279 \r
280 int eCosBoard_erase(ecosflash_flash_bank_t *info, u32 address, u32 len)\r
281 {\r
282         int retval;\r
283         int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/ \r
284 \r
285         retval=loadDriver(info);\r
286         if (retval!=ERROR_OK)\r
287                 return retval;\r
288         \r
289         u32 flashErr;\r
290         retval=runCode(info, \r
291                         info->start_address+OFFSET_ERASE,\r
292                         info->start_address+OFFSET_ERASE+OFFSET_ERASE_SIZE,\r
293                         address,\r
294                         len,\r
295                         0,\r
296                         &flashErr,\r
297                         timeout\r
298                         );\r
299         if (retval!=ERROR_OK)\r
300                 return retval;\r
301         \r
302         if (flashErr != 0x0)\r
303         {\r
304                 ERROR("Flash erase failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));\r
305                 return ERROR_JTAG_DEVICE_ERROR;\r
306         }\r
307 \r
308         return ERROR_OK;\r
309 }\r
310 \r
311 int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, u32 address, u32 len)\r
312 {\r
313         target_t *target=info->target;\r
314         const int chunk=8192;\r
315         int retval=ERROR_OK;\r
316         int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/\r
317         \r
318         retval=loadDriver(info);\r
319         if (retval!=ERROR_OK)\r
320                 return retval;\r
321         \r
322         u32 buffer;\r
323         retval=runCode(info, \r
324                         info->start_address+OFFSET_GET_WORKAREA,\r
325                         info->start_address+OFFSET_GET_WORKAREA+OFFSET_GET_WORKAREA_SIZE,\r
326                         0,\r
327                         0,\r
328                         0,\r
329                         &buffer,\r
330                         1000);\r
331         if (retval!=ERROR_OK)\r
332                 return retval;\r
333         \r
334         \r
335         int i;\r
336     for (i=0; i<len; i+=chunk)\r
337     {\r
338                 int t=len-i;\r
339                 if (t>chunk)\r
340                 {\r
341                         t=chunk;\r
342                 }\r
343                 \r
344                 int retval;\r
345         retval=target_write_buffer(target, buffer, t, ((char *)data)+i);\r
346         if (retval != ERROR_OK)\r
347                 return retval;\r
348         \r
349         u32 flashErr;\r
350         retval=runCode(info, \r
351                         info->start_address+OFFSET_FLASH,\r
352                         info->start_address+OFFSET_FLASH+OFFSET_FLASH_SIZE,\r
353                         buffer,\r
354                         address+i,\r
355                         t,\r
356                         &flashErr,\r
357                         timeout);\r
358         if (retval != ERROR_OK)\r
359                 return retval;\r
360 \r
361                 if (flashErr != 0x0)\r
362                 {\r
363                         ERROR("Flash prog failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));\r
364                         return ERROR_JTAG_DEVICE_ERROR;\r
365                 }\r
366     }\r
367         return ERROR_OK;\r
368 }\r
369 \r
370 \r
371 int ecosflash_probe(struct flash_bank_s *bank)\r
372 {\r
373         return ERROR_OK;\r
374 }\r
375 \r
376 \r
377 int ecosflash_register_commands(struct command_context_s *cmd_ctx)\r
378 {\r
379         register_command(cmd_ctx, NULL, "ecosflash", NULL, COMMAND_ANY, NULL);\r
380         \r
381         return ERROR_OK;\r
382 }\r
383 \r
384 /*\r
385 static void command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)\r
386 {\r
387         ecosflash_flash_bank_t *info = bank->driver_priv;\r
388         int i;\r
389         \r
390         if (info->target->endianness == TARGET_LITTLE_ENDIAN)\r
391         {\r
392                 for (i = bank->bus_width; i > 0; i--)\r
393                 {\r
394                         *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;\r
395                 }\r
396         }\r
397         else\r
398         {\r
399                 for (i = 1; i <= bank->bus_width; i++)\r
400                 {\r
401                         *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;\r
402                 }\r
403         }\r
404 }\r
405 */\r
406 \r
407 u32 ecosflash_address(struct flash_bank_s *bank, u32 address)\r
408 {\r
409         u32 retval = 0;\r
410         switch(bank->bus_width)\r
411         {\r
412                 case 4:\r
413                         retval = address & 0xfffffffc;\r
414                 case 2:\r
415                         retval = address & 0xfffffffe;\r
416                 case 1:\r
417                         retval = address;\r
418         }\r
419         \r
420         return retval + bank->base;\r
421\r
422 \r
423 \r
424 int ecosflash_erase(struct flash_bank_s *bank, int first, int last)\r
425 {\r
426         struct flash_bank_s *c=bank;\r
427         ecosflash_flash_bank_t *info = bank->driver_priv;\r
428         return eCosBoard_erase(info, c->base+first*sectorSize, sectorSize*(last-first+1)); \r
429 }\r
430 \r
431 int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last)\r
432 {\r
433         return ERROR_OK;\r
434 }\r
435 \r
436 \r
437 int ecosflash_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
438 {\r
439         ecosflash_flash_bank_t *info = bank->driver_priv;\r
440         struct flash_bank_s *c=bank;\r
441         return eCosBoard_flash(info, buffer, c->base+offset, count);\r
442 }\r
443 \r
444 \r
445 int ecosflash_erase_check(struct flash_bank_s *bank)\r
446 {\r
447         return ERROR_OK;\r
448 }\r
449 \r
450 int ecosflash_protect_check(struct flash_bank_s *bank)\r
451 {\r
452         return ERROR_OK;\r
453 }\r
454 \r
455 int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
456 {\r
457         ecosflash_flash_bank_t *info = bank->driver_priv;\r
458         snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);\r
459         return ERROR_OK;\r
460 }\r
461 \r
462 \r
463 u32 ecosflash_get_flash_status(flash_bank_t *bank)\r
464 {\r
465         return ERROR_OK;\r
466 }\r
467 \r
468 void ecosflash_set_flash_mode(flash_bank_t *bank,int mode)\r
469 {\r
470         \r
471 }\r
472 \r
473 u32 ecosflash_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)\r
474 {\r
475         return ERROR_OK;\r
476 }\r
477 \r
478 int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
479 {\r
480         return ERROR_OK;\r
481 }\r
482 \r
483 \r
484 \r
485 \r