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 #define FLASH_ERR_OK              0x00  // No error - operation complete\r
82 #define FLASH_ERR_INVALID         0x01  // Invalid FLASH address\r
83 #define FLASH_ERR_ERASE           0x02  // Error trying to erase\r
84 #define FLASH_ERR_LOCK            0x03  // Error trying to lock/unlock\r
85 #define FLASH_ERR_PROGRAM         0x04  // Error trying to program\r
86 #define FLASH_ERR_PROTOCOL        0x05  // Generic error\r
87 #define FLASH_ERR_PROTECT         0x06  // Device/region is write-protected\r
88 #define FLASH_ERR_NOT_INIT        0x07  // FLASH info not yet initialized\r
89 #define FLASH_ERR_HWR             0x08  // Hardware (configuration?) problem\r
90 #define FLASH_ERR_ERASE_SUSPEND   0x09  // Device is in erase suspend mode\r
91 #define FLASH_ERR_PROGRAM_SUSPEND 0x0a  // Device is in in program suspend mode\r
92 #define FLASH_ERR_DRV_VERIFY      0x0b  // Driver failed to verify data\r
93 #define FLASH_ERR_DRV_TIMEOUT     0x0c  // Driver timed out waiting for device\r
94 #define FLASH_ERR_DRV_WRONG_PART  0x0d  // Driver does not support device\r
95 #define FLASH_ERR_LOW_VOLTAGE     0x0e  // Not enough juice to complete job\r
96 \r
97 \r
98 char *\r
99 flash_errmsg(int err)\r
100 {\r
101     switch (err) {\r
102     case FLASH_ERR_OK:\r
103         return "No error - operation complete";\r
104     case FLASH_ERR_ERASE_SUSPEND:\r
105         return "Device is in erase suspend state";\r
106     case FLASH_ERR_PROGRAM_SUSPEND:\r
107         return "Device is in program suspend state";\r
108     case FLASH_ERR_INVALID:\r
109         return "Invalid FLASH address";\r
110     case FLASH_ERR_ERASE:\r
111         return "Error trying to erase";\r
112     case FLASH_ERR_LOCK:\r
113         return "Error trying to lock/unlock";\r
114     case FLASH_ERR_PROGRAM:\r
115         return "Error trying to program";\r
116     case FLASH_ERR_PROTOCOL:\r
117         return "Generic error";\r
118     case FLASH_ERR_PROTECT:\r
119         return "Device/region is write-protected";\r
120     case FLASH_ERR_NOT_INIT:\r
121         return "FLASH sub-system not initialized";\r
122     case FLASH_ERR_DRV_VERIFY:\r
123         return "Data verify failed after operation";\r
124     case FLASH_ERR_DRV_TIMEOUT:\r
125         return "Driver timed out waiting for device";\r
126     case FLASH_ERR_DRV_WRONG_PART:\r
127         return "Driver does not support device";\r
128     case FLASH_ERR_LOW_VOLTAGE:\r
129         return "Device reports low voltage";\r
130     default:\r
131         return "Unknown error";\r
132     }\r
133 }\r
134 \r
135 \r
136 /* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>\r
137  */\r
138 int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
139 {\r
140         ecosflash_flash_bank_t *info;\r
141         \r
142         if (argc < 7)\r
143         {\r
144                 WARNING("incomplete flash_bank ecosflash configuration");\r
145                 return ERROR_FLASH_BANK_INVALID;\r
146         }\r
147         \r
148         info = malloc(sizeof(ecosflash_flash_bank_t));\r
149         if(info == NULL)\r
150         {\r
151                 ERROR("no memory for flash bank info");\r
152                 exit(-1);\r
153         }\r
154         bank->driver_priv = info;\r
155         info->driverPath=strdup(args[6]);\r
156 \r
157         // eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as \r
158         // a way to improve impeadance matach between OpenOCD and eCos flash\r
159         // driver\r
160         int i = 0;\r
161         u32 offset = 0;\r
162         bank->num_sectors=bank->size/sectorSize;\r
163         bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);\r
164         for (i = 0; i < bank->num_sectors; i++)\r
165         {\r
166                 bank->sectors[i].offset = offset;\r
167                 bank->sectors[i].size = sectorSize;\r
168                 offset += bank->sectors[i].size;\r
169                 bank->sectors[i].is_erased = -1;\r
170                 bank->sectors[i].is_protected = 0;\r
171         }\r
172         \r
173         info->target = get_target_by_num(strtoul(args[5], NULL, 0));\r
174         if (info->target == NULL)\r
175         {\r
176                 ERROR("no target '%i' configured", (int)strtoul(args[5], NULL, 0));\r
177                 exit(-1);\r
178         }\r
179         return ERROR_OK;\r
180 }\r
181 \r
182 \r
183 int loadDriver(ecosflash_flash_bank_t *info)\r
184 {\r
185         u32 buf_cnt;\r
186         u32 image_size;\r
187         image_t image;  \r
188         \r
189         image.base_address_set = 0;\r
190         image.start_address_set = 0;\r
191         target_t *target=info->target;\r
192         \r
193         if (image_open(&image, info->driverPath, NULL) != ERROR_OK)\r
194         {\r
195                 ERROR("load_image error: %s", image.error_str);\r
196                 return ERROR_FLASH_BANK_INVALID;\r
197         }\r
198         \r
199         info->start_address=image.start_address;\r
200         \r
201         image_size = 0x0;\r
202         int i;\r
203         for (i = 0; i < image.num_sections; i++)\r
204         {\r
205                 void *buffer = malloc(image.sections[i].size);\r
206                 int retval;\r
207                 if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)\r
208                 {\r
209                         ERROR("image_read_section failed with error code: %i", retval);\r
210                         free(buffer);\r
211                         image_close(&image);\r
212                         return ERROR_FLASH_BANK_INVALID;\r
213                 }\r
214                 target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);\r
215                 image_size += buf_cnt;\r
216                 DEBUG("%u byte written at address 0x%8.8x", buf_cnt, image.sections[i].base_address);\r
217                 \r
218                 free(buffer);\r
219         }\r
220 \r
221         image_close(&image);\r
222 \r
223         return ERROR_OK;\r
224 }\r
225 \r
226 \r
227 static int const OFFSET_ERASE=0x0;\r
228 static int const OFFSET_ERASE_SIZE=0x8;\r
229 static int const OFFSET_FLASH=0xc;\r
230 static int const OFFSET_FLASH_SIZE=0x8;\r
231 static int const OFFSET_GET_WORKAREA=0x18;\r
232 static int const OFFSET_GET_WORKAREA_SIZE=0x4;\r
233 \r
234 \r
235 int runCode(ecosflash_flash_bank_t *info, \r
236                 u32 codeStart, u32 codeStop, u32 r0, u32 r1, u32 r2, \r
237                 u32 *result,\r
238                 // timeout in ms\r
239                 int timeout)\r
240 {\r
241         target_t *target=info->target;\r
242 \r
243         reg_param_t reg_params[3];\r
244         armv4_5_algorithm_t armv4_5_info;\r
245         armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;\r
246         armv4_5_info.core_mode = ARMV4_5_MODE_SVC;\r
247         armv4_5_info.core_state = ARMV4_5_STATE_ARM;\r
248         \r
249         init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);\r
250         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);\r
251         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);\r
252         \r
253         buf_set_u32(reg_params[0].value, 0, 32, r0);\r
254         buf_set_u32(reg_params[1].value, 0, 32, r1);\r
255         buf_set_u32(reg_params[2].value, 0, 32, r2);\r
256         \r
257         int retval;\r
258         if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params,\r
259                         codeStart,\r
260                         codeStop, timeout, \r
261                         &armv4_5_info)) != ERROR_OK)\r
262         {\r
263                 ERROR("error executing eCos flash algorithm");\r
264                 return retval;\r
265         }\r
266         \r
267         *result=buf_get_u32(reg_params[0].value, 0, 32);\r
268         \r
269         destroy_reg_param(&reg_params[0]);\r
270         destroy_reg_param(&reg_params[1]);\r
271         destroy_reg_param(&reg_params[2]);\r
272         \r
273         return ERROR_OK;\r
274 }\r
275 \r
276 int eCosBoard_erase(ecosflash_flash_bank_t *info, u32 address, u32 len)\r
277 {\r
278         int retval;\r
279         int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/ \r
280 \r
281         retval=loadDriver(info);\r
282         if (retval!=ERROR_OK)\r
283                 return retval;\r
284         \r
285         u32 flashErr;\r
286         retval=runCode(info, \r
287                         info->start_address+OFFSET_ERASE,\r
288                         info->start_address+OFFSET_ERASE+OFFSET_ERASE_SIZE,\r
289                         address,\r
290                         len,\r
291                         0,\r
292                         &flashErr,\r
293                         timeout\r
294                         );\r
295         if (retval!=ERROR_OK)\r
296                 return retval;\r
297         \r
298         if (flashErr != 0x0)\r
299         {\r
300                 ERROR("Flash erase failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));\r
301                 return ERROR_JTAG_DEVICE_ERROR;\r
302         }\r
303 \r
304         return ERROR_OK;\r
305 }\r
306 \r
307 int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, u32 address, u32 len)\r
308 {\r
309         target_t *target=info->target;\r
310         const int chunk=8192;\r
311         int retval=ERROR_OK;\r
312         int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/\r
313         \r
314         retval=loadDriver(info);\r
315         if (retval!=ERROR_OK)\r
316                 return retval;\r
317         \r
318         u32 buffer;\r
319         retval=runCode(info, \r
320                         info->start_address+OFFSET_GET_WORKAREA,\r
321                         info->start_address+OFFSET_GET_WORKAREA+OFFSET_GET_WORKAREA_SIZE,\r
322                         0,\r
323                         0,\r
324                         0,\r
325                         &buffer,\r
326                         1000);\r
327         if (retval!=ERROR_OK)\r
328                 return retval;\r
329         \r
330         \r
331         int i;\r
332     for (i=0; i<len; i+=chunk)\r
333     {\r
334                 int t=len-i;\r
335                 if (t>chunk)\r
336                 {\r
337                         t=chunk;\r
338                 }\r
339                 \r
340                 int retval;\r
341         retval=target_write_buffer(target, buffer, t, ((char *)data)+i);\r
342         if (retval != ERROR_OK)\r
343                 return retval;\r
344         \r
345         u32 flashErr;\r
346         retval=runCode(info, \r
347                         info->start_address+OFFSET_FLASH,\r
348                         info->start_address+OFFSET_FLASH+OFFSET_FLASH_SIZE,\r
349                         buffer,\r
350                         address+i,\r
351                         t,\r
352                         &flashErr,\r
353                         timeout);\r
354         if (retval != ERROR_OK)\r
355                 return retval;\r
356 \r
357                 if (flashErr != 0x0)\r
358                 {\r
359                         ERROR("Flash prog failed with %d (%s)\n", flashErr, flash_errmsg(flashErr));\r
360                         return ERROR_JTAG_DEVICE_ERROR;\r
361                 }\r
362     }\r
363         return ERROR_OK;\r
364 }\r
365 \r
366 \r
367 int ecosflash_probe(struct flash_bank_s *bank)\r
368 {\r
369         return ERROR_OK;\r
370 }\r
371 \r
372 \r
373 int ecosflash_register_commands(struct command_context_s *cmd_ctx)\r
374 {\r
375         register_command(cmd_ctx, NULL, "ecosflash", NULL, COMMAND_ANY, NULL);\r
376         \r
377         return ERROR_OK;\r
378 }\r
379 \r
380 /*\r
381 static void command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)\r
382 {\r
383         ecosflash_flash_bank_t *info = bank->driver_priv;\r
384         int i;\r
385         \r
386         if (info->target->endianness == TARGET_LITTLE_ENDIAN)\r
387         {\r
388                 for (i = bank->bus_width; i > 0; i--)\r
389                 {\r
390                         *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;\r
391                 }\r
392         }\r
393         else\r
394         {\r
395                 for (i = 1; i <= bank->bus_width; i++)\r
396                 {\r
397                         *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;\r
398                 }\r
399         }\r
400 }\r
401 */\r
402 \r
403 u32 ecosflash_address(struct flash_bank_s *bank, u32 address)\r
404 {\r
405         u32 retval = 0;\r
406         switch(bank->bus_width)\r
407         {\r
408                 case 4:\r
409                         retval = address & 0xfffffffc;\r
410                 case 2:\r
411                         retval = address & 0xfffffffe;\r
412                 case 1:\r
413                         retval = address;\r
414         }\r
415         \r
416         return retval + bank->base;\r
417\r
418 \r
419 \r
420 int ecosflash_erase(struct flash_bank_s *bank, int first, int last)\r
421 {\r
422         struct flash_bank_s *c=bank;\r
423         ecosflash_flash_bank_t *info = bank->driver_priv;\r
424         return eCosBoard_erase(info, c->base+first*sectorSize, sectorSize*(last-first+1)); \r
425 }\r
426 \r
427 int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last)\r
428 {\r
429         return ERROR_OK;\r
430 }\r
431 \r
432 \r
433 int ecosflash_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
434 {\r
435         ecosflash_flash_bank_t *info = bank->driver_priv;\r
436         struct flash_bank_s *c=bank;\r
437         return eCosBoard_flash(info, buffer, c->base+offset, count);\r
438 }\r
439 \r
440 \r
441 int ecosflash_erase_check(struct flash_bank_s *bank)\r
442 {\r
443         return ERROR_OK;\r
444 }\r
445 \r
446 int ecosflash_protect_check(struct flash_bank_s *bank)\r
447 {\r
448         return ERROR_OK;\r
449 }\r
450 \r
451 int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
452 {\r
453         ecosflash_flash_bank_t *info = bank->driver_priv;\r
454         snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);\r
455         return ERROR_OK;\r
456 }\r
457 \r
458 \r
459 u32 ecosflash_get_flash_status(flash_bank_t *bank)\r
460 {\r
461         return ERROR_OK;\r
462 }\r
463 \r
464 void ecosflash_set_flash_mode(flash_bank_t *bank,int mode)\r
465 {\r
466         \r
467 }\r
468 \r
469 u32 ecosflash_wait_status_busy(flash_bank_t *bank, u32 waitbits, int timeout)\r
470 {\r
471         return ERROR_OK;\r
472 }\r
473 \r
474 int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
475 {\r
476         return ERROR_OK;\r
477 }\r
478 \r
479 \r
480 \r
481 \r