John McCarthy <jgmcc@magma.ca> pic32mx flash wip
[fw/openocd] / src / flash / pic32mx.c
1 /***************************************************************************\r
2  *   Copyright (C) 2005 by Dominic Rath                                    *\r
3  *   Dominic.Rath@gmx.de                                                   *\r
4  *                                                                         *\r
5  *   Copyright (C) 2008 by Spencer Oliver                                  *\r
6  *   spen@spen-soft.co.uk                                                  *\r
7  *                                                                         *\r
8  *   Copyright (C) 2008 by John McCarthy                                   *\r
9  *   jgmcc@magma.ca                                                        *\r
10  *                                                                         *\r
11  *   This program is free software; you can redistribute it and/or modify  *\r
12  *   it under the terms of the GNU General Public License as published by  *\r
13  *   the Free Software Foundation; either version 2 of the License, or     *\r
14  *   (at your option) any later version.                                   *\r
15  *                                                                         *\r
16  *   This program is distributed in the hope that it will be useful,       *\r
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
19  *   GNU General Public License for more details.                          *\r
20  *                                                                         *\r
21  *   You should have received a copy of the GNU General Public License     *\r
22  *   along with this program; if not, write to the                         *\r
23  *   Free Software Foundation, Inc.,                                       *\r
24  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *\r
25  ***************************************************************************/\r
26 #ifdef HAVE_CONFIG_H\r
27 #include "config.h"\r
28 #endif\r
29 \r
30 #include "replacements.h"\r
31 \r
32 #include "pic32mx.h"\r
33 #include "flash.h"\r
34 #include "target.h"\r
35 #include "log.h"\r
36 #include "mips32.h"\r
37 #include "algorithm.h"\r
38 #include "binarybuffer.h"\r
39 \r
40 #include <stdlib.h>\r
41 #include <string.h>\r
42 \r
43 static\r
44 struct pic32mx_devs_s {\r
45         u8      devid;\r
46         char    *name;\r
47         u32     pfm_size;\r
48 } pic32mx_devs[] = {\r
49         { 0x78, "460F512L USB", 512 },\r
50         { 0x74, "460F256L USB", 256 },\r
51         { 0x6D, "440F128L USB", 128 },\r
52         { 0x56, "440F512H USB", 512 },\r
53         { 0x52, "440F256H USB", 256 },\r
54         { 0x4D, "440F128H USB", 128 },\r
55         { 0x42, "420F032H USB",  32 },\r
56         { 0x38, "360F512L",     512 },\r
57         { 0x34, "360F256L",     256 },\r
58         { 0x2D, "340F128L",     128 },\r
59         { 0x2A, "320F128L",     128 },\r
60         { 0x16, "340F512H",     512 },\r
61         { 0x12, "340F256H",     256 },\r
62         { 0x0D, "340F128H",     128 },\r
63         { 0x0A, "320F128H",     128 },\r
64         { 0x06, "320F064H",      64 },\r
65         { 0x02, "320F032H",      32 },\r
66         { 0x00, NULL, 0 }\r
67 };\r
68 \r
69 int pic32mx_register_commands(struct command_context_s *cmd_ctx);\r
70 int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
71 int pic32mx_erase(struct flash_bank_s *bank, int first, int last);\r
72 int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last);\r
73 int pic32mx_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
74 int pic32mx_probe(struct flash_bank_s *bank);\r
75 int pic32mx_auto_probe(struct flash_bank_s *bank);\r
76 int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
77 int pic32mx_protect_check(struct flash_bank_s *bank);\r
78 int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
79 \r
80 #if 0\r
81 int pic32mx_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
82 int pic32mx_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
83 #endif\r
84 int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
85 int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
86 int pic32mx_chip_erase(struct flash_bank_s *bank);\r
87 \r
88 flash_driver_t pic32mx_flash =\r
89 {\r
90         .name = "pic32mx",\r
91         .register_commands = pic32mx_register_commands,\r
92         .flash_bank_command = pic32mx_flash_bank_command,\r
93         .erase = pic32mx_erase,\r
94         .protect = pic32mx_protect,\r
95         .write = pic32mx_write,\r
96         .probe = pic32mx_probe,\r
97         .auto_probe = pic32mx_auto_probe,\r
98         .erase_check = default_flash_mem_blank_check,\r
99         .protect_check = pic32mx_protect_check,\r
100         .info = pic32mx_info\r
101 };\r
102 \r
103 int pic32mx_register_commands(struct command_context_s *cmd_ctx)\r
104 {\r
105         command_t *pic32mx_cmd = register_command(cmd_ctx, NULL, "pic32mx", NULL, COMMAND_ANY, "pic32mx flash specific commands");\r
106 \r
107 #if 0\r
108         register_command(cmd_ctx, pic32mx_cmd, "lock", pic32mx_handle_lock_command, COMMAND_EXEC,\r
109                                          "lock device");\r
110         register_command(cmd_ctx, pic32mx_cmd, "unlock", pic32mx_handle_unlock_command, COMMAND_EXEC,\r
111                                          "unlock protected device");\r
112 #endif\r
113         register_command(cmd_ctx, pic32mx_cmd, "chip_erase", pic32mx_handle_chip_erase_command, COMMAND_EXEC,\r
114                                          "erase device");\r
115         register_command(cmd_ctx, pic32mx_cmd, "pgm_word", pic32mx_handle_pgm_word_command, COMMAND_EXEC,\r
116                                          "program a word");\r
117         return ERROR_OK;\r
118 }\r
119 \r
120 /* flash bank pic32mx <base> <size> 0 0 <target#>\r
121  */\r
122 int pic32mx_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
123 {\r
124         pic32mx_flash_bank_t *pic32mx_info;\r
125 \r
126         if (argc < 6)\r
127         {\r
128                 LOG_WARNING("incomplete flash_bank pic32mx configuration");\r
129                 return ERROR_FLASH_BANK_INVALID;\r
130         }\r
131 \r
132         pic32mx_info = malloc(sizeof(pic32mx_flash_bank_t));\r
133         bank->driver_priv = pic32mx_info;\r
134 \r
135         pic32mx_info->write_algorithm = NULL;\r
136         pic32mx_info->probed = 0;\r
137 \r
138         return ERROR_OK;\r
139 }\r
140 \r
141 u32 pic32mx_get_flash_status(flash_bank_t *bank)\r
142 {\r
143         target_t *target = bank->target;\r
144         u32 status;\r
145 \r
146         target_read_u32(target, PIC32MX_NVMCON, &status);\r
147 \r
148         return status;\r
149 }\r
150 \r
151 u32 pic32mx_wait_status_busy(flash_bank_t *bank, int timeout)\r
152 {\r
153         u32 status;\r
154 \r
155         /* wait for busy to clear */\r
156         while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0))\r
157         {\r
158                 LOG_DEBUG("status: 0x%x", status);\r
159                 alive_sleep(1);\r
160         }\r
161         if(timeout <= 0)\r
162                 LOG_DEBUG("timeout: status: 0x%x", status);\r
163 \r
164         return status;\r
165 }\r
166 \r
167 int pic32mx_nvm_exec(struct flash_bank_s *bank, u32 op, u32 timeout)\r
168 {\r
169         target_t *target = bank->target;\r
170         u32 status;\r
171 \r
172         target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN|op);\r
173 \r
174         /* unlock flash registers */\r
175         target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1);\r
176         target_write_u32(target, PIC32MX_NVMKEY, NVMKEY2);\r
177 \r
178         /* start operation */\r
179         target_write_u32(target, PIC32MX_NVMCONSET, NVMCON_NVMWR);\r
180 \r
181         status = pic32mx_wait_status_busy(bank, timeout);\r
182 \r
183         /* lock flash registers */\r
184         target_write_u32(target, PIC32MX_NVMCONCLR, NVMCON_NVMWREN);\r
185 \r
186         return status;\r
187 }\r
188 \r
189 int pic32mx_protect_check(struct flash_bank_s *bank)\r
190 {\r
191         target_t *target = bank->target;\r
192         pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;\r
193 \r
194         u32 devcfg0;\r
195         int s;\r
196         int num_pages;\r
197 \r
198         if (target->state != TARGET_HALTED)\r
199         {\r
200                 LOG_ERROR("Target not halted");\r
201                 return ERROR_TARGET_NOT_HALTED;\r
202         }\r
203 \r
204         target_read_u32(target, PIC32MX_DEVCFG0, &devcfg0);\r
205         if((devcfg0 & (1<<28)) == 0) /* code protect bit */\r
206                 num_pages = 0xffff;  /* All pages protected */\r
207         else if(bank->base == PIC32MX_KSEG1_BOOT_FLASH)\r
208         {\r
209                 if(devcfg0 & (1<<24))\r
210                         num_pages = 0;       /* All pages unprotected */\r
211                 else\r
212                         num_pages = 0xffff;  /* All pages protected */\r
213         }\r
214         else /* pgm flash */\r
215                 num_pages = (~devcfg0 >> 12) & 0xff;\r
216         for (s = 0; s < bank->num_sectors && s < num_pages; s++)\r
217                 bank->sectors[s].is_protected = 1;\r
218         for (; s < bank->num_sectors; s++)\r
219                 bank->sectors[s].is_protected = 0;\r
220 \r
221         return ERROR_OK;\r
222 }\r
223 \r
224 int pic32mx_erase(struct flash_bank_s *bank, int first, int last)\r
225 {\r
226         target_t *target = bank->target;\r
227         int i;\r
228         u32 status;\r
229 \r
230         if (bank->target->state != TARGET_HALTED)\r
231         {\r
232                 LOG_ERROR("Target not halted");\r
233                 return ERROR_TARGET_NOT_HALTED;\r
234         }\r
235 \r
236 #if 0\r
237         if ((first == 0) && (last == (bank->num_sectors - 1)) && (bank->base == PIC32MX_KSEG0_PGM_FLASH || bank->base == PIC32MX_KSEG1_PGM_FLASH))\r
238         {\r
239                 status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50);\r
240                 if( status & NVMCON_NVMERR )\r
241                         return ERROR_FLASH_OPERATION_FAILED;\r
242                 if( status & NVMCON_LVDERR )\r
243                         return ERROR_FLASH_OPERATION_FAILED;\r
244                 return ERROR_OK;\r
245         }\r
246 #endif\r
247 \r
248         for (i = first; i <= last; i++)\r
249         {\r
250                 target_write_u32(target, PIC32MX_NVMADDR, bank->base + bank->sectors[i].offset);\r
251 \r
252                 status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10);\r
253 \r
254                 if( status & NVMCON_NVMERR )\r
255                         return ERROR_FLASH_OPERATION_FAILED;\r
256                 if( status & NVMCON_LVDERR )\r
257                         return ERROR_FLASH_OPERATION_FAILED;\r
258                 bank->sectors[i].is_erased = 1;\r
259         }\r
260 \r
261         return ERROR_OK;\r
262 }\r
263 \r
264 int pic32mx_protect(struct flash_bank_s *bank, int set, int first, int last)\r
265 {\r
266         pic32mx_flash_bank_t *pic32mx_info = NULL;\r
267         target_t *target = bank->target;\r
268         u16 prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};\r
269         int i, reg, bit;\r
270         int status;\r
271         u32 protection;\r
272 \r
273         pic32mx_info = bank->driver_priv;\r
274 \r
275         if (target->state != TARGET_HALTED)\r
276         {\r
277                 LOG_ERROR("Target not halted");\r
278                 return ERROR_TARGET_NOT_HALTED;\r
279         }\r
280 \r
281 #if 0\r
282         if ((first && (first % pic32mx_info->ppage_size)) || ((last + 1) && (last + 1) % pic32mx_info->ppage_size))\r
283         {\r
284                 LOG_WARNING("sector start/end incorrect - stm32 has %dK sector protection", pic32mx_info->ppage_size);\r
285                 return ERROR_FLASH_SECTOR_INVALID;\r
286         }\r
287 \r
288         /* medium density - each bit refers to a 4bank protection\r
289          * high density - each bit refers to a 2bank protection */\r
290         target_read_u32(target, PIC32MX_FLASH_WRPR, &protection);\r
291 \r
292         prot_reg[0] = (u16)protection;\r
293         prot_reg[1] = (u16)(protection >> 8);\r
294         prot_reg[2] = (u16)(protection >> 16);\r
295         prot_reg[3] = (u16)(protection >> 24);\r
296 \r
297         if (pic32mx_info->ppage_size == 2)\r
298         {\r
299                 /* high density flash */\r
300 \r
301                 /* bit 7 controls sector 62 - 255 protection */\r
302                 if (last > 61)\r
303                 {\r
304                         if (set)\r
305                                 prot_reg[3] &= ~(1 << 7);\r
306                         else\r
307                                 prot_reg[3] |= (1 << 7);\r
308                 }\r
309 \r
310                 if (first > 61)\r
311                         first = 62;\r
312                 if (last > 61)\r
313                         last = 61;\r
314 \r
315                 for (i = first; i <= last; i++)\r
316                 {\r
317                         reg = (i / pic32mx_info->ppage_size) / 8;\r
318                         bit = (i / pic32mx_info->ppage_size) - (reg * 8);\r
319 \r
320                         if( set )\r
321                                 prot_reg[reg] &= ~(1 << bit);\r
322                         else\r
323                                 prot_reg[reg] |= (1 << bit);\r
324                 }\r
325         }\r
326         else\r
327         {\r
328                 /* medium density flash */\r
329                 for (i = first; i <= last; i++)\r
330                 {\r
331                         reg = (i / pic32mx_info->ppage_size) / 8;\r
332                         bit = (i / pic32mx_info->ppage_size) - (reg * 8);\r
333 \r
334                         if( set )\r
335                                 prot_reg[reg] &= ~(1 << bit);\r
336                         else\r
337                                 prot_reg[reg] |= (1 << bit);\r
338                 }\r
339         }\r
340 \r
341         if ((status = pic32mx_erase_options(bank)) != ERROR_OK)\r
342                 return status;\r
343 \r
344         pic32mx_info->option_bytes.protection[0] = prot_reg[0];\r
345         pic32mx_info->option_bytes.protection[1] = prot_reg[1];\r
346         pic32mx_info->option_bytes.protection[2] = prot_reg[2];\r
347         pic32mx_info->option_bytes.protection[3] = prot_reg[3];\r
348 \r
349         return pic32mx_write_options(bank);\r
350 #else\r
351         return ERROR_OK;\r
352 #endif\r
353 }\r
354 \r
355 int pic32mx_write_block(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
356 {\r
357         pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;\r
358         target_t *target = bank->target;\r
359         u32 buffer_size = 8192;\r
360         working_area_t *source;\r
361         u32 address = bank->base + offset;\r
362         reg_param_t reg_params[4];\r
363 #if 0\r
364         armv7m_algorithm_t armv7m_info;\r
365         int retval = ERROR_OK;\r
366 \r
367         u8 pic32mx_flash_write_code[] = {\r
368                                                                         /* write: */\r
369                 0xDF, 0xF8, 0x24, 0x40,         /* ldr  r4, PIC32MX_FLASH_CR */\r
370                 0x09, 0x4D,                                     /* ldr  r5, PIC32MX_FLASH_SR */\r
371                 0x4F, 0xF0, 0x01, 0x03,         /* mov  r3, #1 */\r
372                 0x23, 0x60,                                     /* str  r3, [r4, #0] */\r
373                 0x30, 0xF8, 0x02, 0x3B,         /* ldrh r3, [r0], #2 */\r
374                 0x21, 0xF8, 0x02, 0x3B,         /* strh r3, [r1], #2 */\r
375                                                                         /* busy: */\r
376                 0x2B, 0x68,                                     /* ldr  r3, [r5, #0] */\r
377                 0x13, 0xF0, 0x01, 0x0F,         /* tst  r3, #0x01 */\r
378                 0xFB, 0xD0,                                     /* beq  busy */\r
379                 0x13, 0xF0, 0x14, 0x0F,         /* tst  r3, #0x14 */\r
380                 0x01, 0xD1,                                     /* bne  exit */\r
381                 0x01, 0x3A,                                     /* subs r2, r2, #1 */\r
382                 0xED, 0xD1,                                     /* bne  write */\r
383                                                                         /* exit: */\r
384                 0xFE, 0xE7,                                     /* b exit */\r
385                 0x10, 0x20, 0x02, 0x40,         /* PIC32MX_FLASH_CR:    .word 0x40022010 */\r
386                 0x0C, 0x20, 0x02, 0x40          /* PIC32MX_FLASH_SR:    .word 0x4002200C */\r
387         };\r
388 \r
389         /* flash write code */\r
390         if (target_alloc_working_area(target, sizeof(pic32mx_flash_write_code), &pic32mx_info->write_algorithm) != ERROR_OK)\r
391         {\r
392                 LOG_WARNING("no working area available, can't do block memory writes");\r
393                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
394         };\r
395 \r
396         if ((retval=target_write_buffer(target, pic32mx_info->write_algorithm->address, sizeof(pic32mx_flash_write_code), pic32mx_flash_write_code))!=ERROR_OK)\r
397                 return retval;\r
398 \r
399         /* memory buffer */\r
400         while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)\r
401         {\r
402                 buffer_size /= 2;\r
403                 if (buffer_size <= 256)\r
404                 {\r
405                         /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */\r
406                         if (pic32mx_info->write_algorithm)\r
407                                 target_free_working_area(target, pic32mx_info->write_algorithm);\r
408 \r
409                         LOG_WARNING("no large enough working area available, can't do block memory writes");\r
410                         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
411                 }\r
412         };\r
413 \r
414         armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;\r
415         armv7m_info.core_mode = ARMV7M_MODE_ANY;\r
416 \r
417         init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);\r
418         init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);\r
419         init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);\r
420         init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);\r
421 \r
422         while (count > 0)\r
423         {\r
424                 u32 thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;\r
425 \r
426                 if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer))!=ERROR_OK)\r
427                         break;\r
428 \r
429                 buf_set_u32(reg_params[0].value, 0, 32, source->address);\r
430                 buf_set_u32(reg_params[1].value, 0, 32, address);\r
431                 buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);\r
432 \r
433                 if ((retval = target->type->run_algorithm(target, 0, NULL, 4, reg_params, pic32mx_info->write_algorithm->address, \\r
434                                 pic32mx_info->write_algorithm->address + (sizeof(pic32mx_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)\r
435                 {\r
436                         LOG_ERROR("error executing pic32mx flash write algorithm");\r
437                         retval = ERROR_FLASH_OPERATION_FAILED;\r
438                         break;\r
439                 }\r
440 \r
441                 if (buf_get_u32(reg_params[3].value, 0, 32) & 0x14)\r
442                 {\r
443                         retval = ERROR_FLASH_OPERATION_FAILED;\r
444                         break;\r
445                 }\r
446 \r
447                 buffer += thisrun_count * 2;\r
448                 address += thisrun_count * 2;\r
449                 count -= thisrun_count;\r
450         }\r
451 \r
452         target_free_working_area(target, source);\r
453         target_free_working_area(target, pic32mx_info->write_algorithm);\r
454 \r
455         destroy_reg_param(&reg_params[0]);\r
456         destroy_reg_param(&reg_params[1]);\r
457         destroy_reg_param(&reg_params[2]);\r
458         destroy_reg_param(&reg_params[3]);\r
459 \r
460         return retval;\r
461 #else\r
462         return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;\r
463 #endif\r
464 }\r
465 \r
466 int pic32mx_write_word(struct flash_bank_s *bank, u32 address, u32 word)\r
467 {\r
468         target_t *target = bank->target;\r
469 \r
470         target_write_u32(target, PIC32MX_NVMADDR, address);\r
471         target_write_u32(target, PIC32MX_NVMDATA, word);\r
472 \r
473         return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5);\r
474 }\r
475 \r
476 int pic32mx_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
477 {\r
478         target_t *target = bank->target;\r
479         u32 words_remaining = (count / 4);\r
480         u32 bytes_remaining = (count & 0x00000003);\r
481         u32 address = bank->base + offset;\r
482         u32 bytes_written = 0;\r
483         u32 status;\r
484         u32 retval;\r
485 \r
486         if (bank->target->state != TARGET_HALTED)\r
487         {\r
488                 LOG_ERROR("Target not halted");\r
489                 return ERROR_TARGET_NOT_HALTED;\r
490         }\r
491 \r
492         if (offset & 0x3)\r
493         {\r
494                 LOG_WARNING("offset 0x%x breaks required 4-byte alignment", offset);\r
495                 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
496         }\r
497 \r
498         /* multiple words (4-byte) to be programmed? */\r
499         if (words_remaining > 0)\r
500         {\r
501                 /* try using a block write */\r
502                 if ((retval = pic32mx_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK)\r
503                 {\r
504                         if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)\r
505                         {\r
506                                 /* if block write failed (no sufficient working area),\r
507                                  * we use normal (slow) single dword accesses */\r
508                                 LOG_WARNING("couldn't use block writes, falling back to single memory accesses");\r
509                         }\r
510                         else if (retval == ERROR_FLASH_OPERATION_FAILED)\r
511                         {\r
512                                 LOG_ERROR("flash writing failed with error code: 0x%x", retval);\r
513                                 return ERROR_FLASH_OPERATION_FAILED;\r
514                         }\r
515                 }\r
516                 else\r
517                 {\r
518                         buffer += words_remaining * 4;\r
519                         address += words_remaining * 4;\r
520                         words_remaining = 0;\r
521                 }\r
522         }\r
523 \r
524         while (words_remaining > 0)\r
525         {\r
526                 status = pic32mx_write_word(bank, address, *(u32*)(buffer + bytes_written));\r
527 \r
528                 if( status & NVMCON_NVMERR )\r
529                         return ERROR_FLASH_OPERATION_FAILED;\r
530                 if( status & NVMCON_LVDERR )\r
531                         return ERROR_FLASH_OPERATION_FAILED;\r
532 \r
533                 bytes_written += 4;\r
534                 words_remaining--;\r
535                 address += 4;\r
536         }\r
537 \r
538         if (bytes_remaining)\r
539         {\r
540                 u8 last_word[4] = {0xff, 0xff, 0xff, 0xff};\r
541                 int i = 0;\r
542 \r
543                 while(bytes_remaining > 0)\r
544                 {\r
545                         /* Assumes little endian */\r
546                         last_word[i++] = *(buffer + bytes_written);\r
547                         bytes_remaining--;\r
548                         bytes_written++;\r
549                 }\r
550 \r
551                 status = pic32mx_write_word(bank, address, *(u32*)last_word);\r
552 \r
553                 if( status & NVMCON_NVMERR )\r
554                         return ERROR_FLASH_OPERATION_FAILED;\r
555                 if( status & NVMCON_LVDERR )\r
556                         return ERROR_FLASH_OPERATION_FAILED;\r
557         }\r
558 \r
559         return ERROR_OK;\r
560 }\r
561 \r
562 int pic32mx_probe(struct flash_bank_s *bank)\r
563 {\r
564         target_t *target = bank->target;\r
565         pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;\r
566         mips32_common_t *mips32 = target->arch_info;\r
567         mips_ejtag_t *ejtag_info = &mips32->ejtag_info;\r
568         int i;\r
569         u16 num_pages;\r
570         u32 device_id;\r
571         int page_size;\r
572 \r
573         pic32mx_info->probed = 0;\r
574 \r
575         device_id = ejtag_info->idcode;\r
576         LOG_INFO( "device id = 0x%08x (manuf 0x%03x dev 0x%02x, ver 0x%03x)", device_id, (device_id>>1)&0x7ff, (device_id>>12)&0xff, (device_id>>20)&0xfff );\r
577 \r
578         if(((device_id>>1)&0x7ff) != PIC32MX_MANUF_ID) {\r
579                 LOG_WARNING( "Cannot identify target as a PIC32MX family." );\r
580                 return ERROR_FLASH_OPERATION_FAILED;\r
581         }\r
582 \r
583         page_size = 4096;\r
584         if(bank->base == PIC32MX_KSEG1_BOOT_FLASH || bank->base == 1) {\r
585                 /* 0xBFC00000: Boot flash size fixed at 12k */\r
586                 num_pages = 12;\r
587         } else {\r
588                 /* 0xBD000000: Program flash size varies with device */\r
589                 for(i=0; pic32mx_devs[i].name != NULL; i++)\r
590                         if(pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {\r
591                                 num_pages = pic32mx_devs[i].pfm_size;\r
592                                 break;\r
593                         }\r
594                 if(pic32mx_devs[i].name == NULL) {\r
595                         LOG_WARNING( "Cannot identify target as a PIC32MX family." );\r
596                         return ERROR_FLASH_OPERATION_FAILED;\r
597                 }\r
598         }\r
599 \r
600 #if 0\r
601         if (bank->target->state != TARGET_HALTED)\r
602         {\r
603                 LOG_ERROR("Target not halted");\r
604                 return ERROR_TARGET_NOT_HALTED;\r
605         }\r
606 \r
607         /* get flash size from target */\r
608         if (target_read_u16(target, 0x1FFFF7E0, &num_pages) != ERROR_OK)\r
609         {\r
610                 /* failed reading flash size, default to max target family */\r
611                 num_pages = 0xffff;\r
612         }\r
613 #endif\r
614 \r
615         LOG_INFO( "flash size = %dkbytes", num_pages );\r
616 \r
617         /* calculate numbers of pages */\r
618         num_pages /= (page_size / 1024);\r
619 \r
620         if(bank->base == 0) bank->base = PIC32MX_KSEG1_PGM_FLASH;\r
621         if(bank->base == 1) bank->base = PIC32MX_KSEG1_BOOT_FLASH;\r
622         bank->size = (num_pages * page_size);\r
623         bank->num_sectors = num_pages;\r
624         bank->chip_width = 4;\r
625         bank->bus_width  = 4;\r
626         bank->sectors = malloc(sizeof(flash_sector_t) * num_pages);\r
627 \r
628         for (i = 0; i < num_pages; i++)\r
629         {\r
630                 bank->sectors[i].offset = i * page_size;\r
631                 bank->sectors[i].size = page_size;\r
632                 bank->sectors[i].is_erased = -1;\r
633                 bank->sectors[i].is_protected = 1;\r
634         }\r
635 \r
636         pic32mx_info->probed = 1;\r
637 \r
638         return ERROR_OK;\r
639 }\r
640 \r
641 int pic32mx_auto_probe(struct flash_bank_s *bank)\r
642 {\r
643         pic32mx_flash_bank_t *pic32mx_info = bank->driver_priv;\r
644         if (pic32mx_info->probed)\r
645                 return ERROR_OK;\r
646         return pic32mx_probe(bank);\r
647 }\r
648 \r
649 int pic32mx_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
650 {\r
651         return ERROR_OK;\r
652 }\r
653 \r
654 int pic32mx_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
655 {\r
656         target_t *target = bank->target;\r
657         mips32_common_t *mips32 = target->arch_info;\r
658         mips_ejtag_t *ejtag_info = &mips32->ejtag_info;\r
659         u32 device_id;\r
660         int printed, i;\r
661 \r
662         device_id = ejtag_info->idcode;\r
663 \r
664         if(((device_id>>1)&0x7ff) != PIC32MX_MANUF_ID) {\r
665                 snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n", (device_id>>1)&0x7ff, PIC32MX_MANUF_ID);\r
666                 return ERROR_FLASH_OPERATION_FAILED;\r
667         }\r
668         for(i=0; pic32mx_devs[i].name != NULL; i++)\r
669                 if(pic32mx_devs[i].devid == ((device_id >> 12) & 0xff)) {\r
670                         printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name);\r
671                         break;\r
672                 }\r
673         if(pic32mx_devs[i].name == NULL) {\r
674                 snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family\n");\r
675                 return ERROR_FLASH_OPERATION_FAILED;\r
676         }\r
677         buf += printed;\r
678         buf_size -= printed;\r
679         printed = snprintf(buf, buf_size, "  Ver: 0x%03x", (device_id>>20)&0xfff);\r
680 \r
681         return ERROR_OK;\r
682 }\r
683 \r
684 #if 0\r
685 int pic32mx_handle_lock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
686 {\r
687         flash_bank_t *bank;\r
688         target_t *target = NULL;\r
689         pic32mx_flash_bank_t *pic32mx_info = NULL;\r
690 \r
691         if (argc < 1)\r
692         {\r
693                 command_print(cmd_ctx, "pic32mx lock <bank>");\r
694                 return ERROR_OK;\r
695         }\r
696 \r
697         bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
698         if (!bank)\r
699         {\r
700                 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
701                 return ERROR_OK;\r
702         }\r
703 \r
704         pic32mx_info = bank->driver_priv;\r
705 \r
706         target = bank->target;\r
707 \r
708         if (target->state != TARGET_HALTED)\r
709         {\r
710                 LOG_ERROR("Target not halted");\r
711                 return ERROR_TARGET_NOT_HALTED;\r
712         }\r
713 \r
714         if (pic32mx_erase_options(bank) != ERROR_OK)\r
715         {\r
716                 command_print(cmd_ctx, "pic32mx failed to erase options");\r
717                 return ERROR_OK;\r
718         }\r
719 \r
720         /* set readout protection */\r
721         pic32mx_info->option_bytes.RDP = 0;\r
722 \r
723         if (pic32mx_write_options(bank) != ERROR_OK)\r
724         {\r
725                 command_print(cmd_ctx, "pic32mx failed to lock device");\r
726                 return ERROR_OK;\r
727         }\r
728 \r
729         command_print(cmd_ctx, "pic32mx locked");\r
730 \r
731         return ERROR_OK;\r
732 }\r
733 \r
734 int pic32mx_handle_unlock_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
735 {\r
736         flash_bank_t *bank;\r
737         target_t *target = NULL;\r
738         pic32mx_flash_bank_t *pic32mx_info = NULL;\r
739 \r
740         if (argc < 1)\r
741         {\r
742                 command_print(cmd_ctx, "pic32mx unlock <bank>");\r
743                 return ERROR_OK;\r
744         }\r
745 \r
746         bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
747         if (!bank)\r
748         {\r
749                 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
750                 return ERROR_OK;\r
751         }\r
752 \r
753         pic32mx_info = bank->driver_priv;\r
754 \r
755         target = bank->target;\r
756 \r
757         if (target->state != TARGET_HALTED)\r
758         {\r
759                 LOG_ERROR("Target not halted");\r
760                 return ERROR_TARGET_NOT_HALTED;\r
761         }\r
762 \r
763         if (pic32mx_erase_options(bank) != ERROR_OK)\r
764         {\r
765                 command_print(cmd_ctx, "pic32mx failed to unlock device");\r
766                 return ERROR_OK;\r
767         }\r
768 \r
769         if (pic32mx_write_options(bank) != ERROR_OK)\r
770         {\r
771                 command_print(cmd_ctx, "pic32mx failed to lock device");\r
772                 return ERROR_OK;\r
773         }\r
774 \r
775         command_print(cmd_ctx, "pic32mx unlocked");\r
776 \r
777         return ERROR_OK;\r
778 }\r
779 #endif\r
780 \r
781 int pic32mx_chip_erase(struct flash_bank_s *bank)\r
782 {\r
783         target_t *target = bank->target;\r
784         u32 status;\r
785 \r
786         if (target->state != TARGET_HALTED)\r
787         {\r
788                 LOG_ERROR("Target not halted");\r
789                 return ERROR_TARGET_NOT_HALTED;\r
790         }\r
791 \r
792         LOG_INFO("PIC32MX chip erase called");\r
793 \r
794 #if 0\r
795         /* unlock option flash registers */\r
796         target_write_u32(target, PIC32MX_FLASH_KEYR, KEY1);\r
797         target_write_u32(target, PIC32MX_FLASH_KEYR, KEY2);\r
798 \r
799         /* chip erase flash memory */\r
800         target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER);\r
801         target_write_u32(target, PIC32MX_FLASH_CR, FLASH_MER|FLASH_STRT);\r
802 \r
803         status = pic32mx_wait_status_busy(bank, 10);\r
804 \r
805         target_write_u32(target, PIC32MX_FLASH_CR, FLASH_LOCK);\r
806 \r
807         if( status & FLASH_WRPRTERR )\r
808         {\r
809                 LOG_ERROR("pic32mx device protected");\r
810                 return ERROR_OK;\r
811         }\r
812 \r
813         if( status & FLASH_PGERR )\r
814         {\r
815                 LOG_ERROR("pic32mx device programming failed");\r
816                 return ERROR_OK;\r
817         }\r
818 #endif\r
819 \r
820         return ERROR_OK;\r
821 }\r
822 \r
823 int pic32mx_handle_chip_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
824 {\r
825         flash_bank_t *bank;\r
826         int i;\r
827 \r
828 #if 0\r
829         if (argc != 0)\r
830         {\r
831                 command_print(cmd_ctx, "pic32mx chip_erase");\r
832                 return ERROR_OK;\r
833         }\r
834 \r
835         bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));\r
836         if (!bank)\r
837         {\r
838                 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);\r
839                 return ERROR_OK;\r
840         }\r
841 \r
842         if (pic32mx_chip_erase(bank) == ERROR_OK)\r
843         {\r
844                 /* set all sectors as erased */\r
845                 for (i = 0; i < bank->num_sectors; i++)\r
846                 {\r
847                         bank->sectors[i].is_erased = 1;\r
848                 }\r
849 \r
850                 command_print(cmd_ctx, "pic32mx chip erase complete");\r
851         }\r
852         else\r
853         {\r
854                 command_print(cmd_ctx, "pic32mx chip erase failed");\r
855         }\r
856 #endif\r
857 \r
858         return ERROR_OK;\r
859 }\r
860 \r
861 int pic32mx_handle_pgm_word_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)\r
862 {\r
863         flash_bank_t *bank;\r
864         u32 address, value;\r
865         int i;\r
866         int status, res;\r
867 \r
868         if (argc != 3)\r
869         {\r
870                 command_print(cmd_ctx, "pic32mx pgm_word <addr> <value> <bank>");\r
871                 return ERROR_OK;\r
872         }\r
873 \r
874         address = strtoul(args[0], NULL, 0);\r
875         value   = strtoul(args[1], NULL, 0);\r
876 \r
877         bank = get_flash_bank_by_num(strtoul(args[2], NULL, 0));\r
878         if (!bank)\r
879         {\r
880                 command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[2]);\r
881                 return ERROR_OK;\r
882         }\r
883         if (address < bank->base || address >= (bank->base+bank->size))\r
884         {\r
885                 command_print(cmd_ctx, "flash address '%s' is out of bounds", args[0]);\r
886                 return ERROR_OK;\r
887         }\r
888 \r
889         res = ERROR_OK;\r
890         status = pic32mx_write_word(bank, address, value);\r
891         if( status & NVMCON_NVMERR )\r
892                 res = ERROR_FLASH_OPERATION_FAILED;\r
893         if( status & NVMCON_LVDERR )\r
894                 res = ERROR_FLASH_OPERATION_FAILED;\r
895 \r
896         if (res == ERROR_OK)\r
897                 command_print(cmd_ctx, "pic32mx pgm word complete");\r
898         else\r
899                 command_print(cmd_ctx, "pic32mx pgm word failed (status=0x%x)", status);\r
900 \r
901         return ERROR_OK;\r
902 }\r