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