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