]> git.sur5r.net Git - openocd/blob - src/flash/nor/mini51.c
flash/kinetis: Fix bug in odd byte count padding
[openocd] / src / flash / nor / mini51.c
1 /***************************************************************************
2  *   Copyright (C) 2013 Cosmin Gorgovan                                    *
3  *   cosmin [at] linux-geek [dot] org                                      *
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  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
19  ***************************************************************************/
20
21 /*
22         Flash driver for the Nuvoton NuMicro Mini51 series microcontrollers
23
24         Part             |APROM Size |Part ID (at 0x5000_0000)
25         ----------------------------------------------
26         MINI51LAN        4 KB                   0x00205100
27         MINI51ZAN        4 KB                   0x00205103
28         MINI51TAN        4 KB                   0x00205104
29         MINI52LAN        8 KB                   0x00205200
30         MINI52ZAN        8 KB                   0x00205203
31         MINI52TAN        8 KB                   0x00205204
32         MINI54LAN        16 KB           0x00205400
33         MINI54ZAN        16 KB           0x00205403
34         MINI54TAN        16 KB           0x00205404
35
36         Datasheet & TRM
37         ---------------
38
39         The ISP flash programming procedure is described on pages 130 and 131 of the (not very verbose) TRM.
40
41         http://www.keil.com/dd/docs/datashts/nuvoton/mini51/da00-mini51_52_54c1.pdf
42
43         This driver
44         -----------
45
46         * Only erase and write operations have been implemented;
47         * Both operations only support the APROM, not the LDROM;
48         * The TRM suggests that after the boot source has been selected, a software reset should be performed by
49           setting bit SWRST in ISPCON. However, this doesn't seem to have any effect on the MCU I'm using. At the
50           moment, the ARM core is reset using the IPRSTC1 register, which seems to do the trick.
51
52         Flash access limitations
53         ------------------------
54
55         APROM can only be modified when the MCU has booted off the LDROM. For write and erase operations, the
56         microcontroller will probably need to be rebooted. Pseudocode:
57
58         * If operation is write or erase, check bit BS (1) in ISPCON (0x5000_C000);
59         * If BS is 0 (APROM):
60                 * unlock protected registers by writing 0x59, 0x16, 0x88 to RegLockAddr(0x5000_0100);
61                 * set BS to 1 (LDROM);
62                 * reboot by setting bit CPU_RST(1) in IPRSTC1 (0x50000008);
63                 * poll CPU_RST until it is reset (not sure it's necessary);
64                 * <Perform flash operation>
65                 * reboot from APROM using the same procedure but writing 0 to BS
66
67
68         For implementing the read operation, please note that the APROM isn't memory mapped when booted from LDROM.
69 */
70
71 #ifdef HAVE_CONFIG_H
72 #include "config.h"
73 #endif
74
75 #include "imp.h"
76
77 #define PART_ID_REG     0x50000000
78 #define IPRSTC1         0x50000008
79 #define REGLOCKADDR     0x50000100
80 #define ISPCON          0x5000C000
81 #define ISPADR          0x5000C004
82 #define ISPDAT          0x5000C008
83 #define ISPCMD          0x5000C00C
84 #define ISPTRG          0x5000C010
85
86 #define PART_ID_MAIN_MASK   0xFFFFFFF8
87 #define IPRSTC_CPU_RST      0x02
88 #define ISPCON_BS_LDROM     0x02
89 #define ISPCON_ISPEN        0x01
90 #define ISPCON_SWRST        0x80
91 #define ISPCON_ISPFF        0x40
92 #define ISPCMD_PROGRAM      0x21
93 #define ISPCMD_ERASE        0x22
94 #define ISPTRG_ISPGO        0x01
95
96 #define MINI51 0x00205100
97 #define MINI52 0x00205200
98 #define MINI54 0x00205400
99
100 #define MINI51_APROM_BASE  0x00000000
101 #define MINI51_KB          1024
102 #define MINI51_PAGE_SIZE   512
103 #define MINI51_TIMEOUT     1000
104
105 struct mini51_flash_bank {
106         bool probed;
107 };
108
109 enum mini51_boot_source {
110         APROM = 0,
111         LDROM = 1
112 };
113
114 /* Private methods */
115
116 static int mini51_unlock_reg(struct flash_bank *bank)
117 {
118         int status;
119         struct target *target = bank->target;
120
121         status = target_write_u32(target, REGLOCKADDR, 0x59);
122         if (status != ERROR_OK)
123                 return status;
124         status = target_write_u32(target, REGLOCKADDR, 0x16);
125         if (status != ERROR_OK)
126                 return status;
127         status = target_write_u32(target, REGLOCKADDR, 0x88);
128         if (status != ERROR_OK)
129                 return status;
130
131         return ERROR_OK;
132 }
133
134 static int mini51_reboot_with_source(struct flash_bank *bank,
135                                 enum mini51_boot_source new_source,
136                                 enum mini51_boot_source *prev_source)
137 {
138         uint32_t ispcon;
139         uint32_t isprtc1;
140         bool mini51_reboot = false;
141         int status;
142         int timeout = MINI51_TIMEOUT;
143
144         /* Read current boot source */
145         struct target *target = bank->target;
146         status = target_read_u32(target, ISPCON, &ispcon);
147         if (status != ERROR_OK)
148                 return status;
149
150         *prev_source = (ispcon >> 1) & 1;
151
152         if ((new_source == APROM) && (*prev_source != APROM)) {
153                 ispcon &= ~ISPCON_BS_LDROM;
154                 mini51_reboot = true;
155         } else if ((new_source == LDROM) && (*prev_source != LDROM)) {
156                 ispcon |= ISPCON_BS_LDROM;
157                 mini51_reboot = true;
158         }
159
160         if (mini51_reboot) {
161                 mini51_unlock_reg(bank);
162                 status = target_write_u32(target, ISPCON, ispcon);
163                 if (status != ERROR_OK)
164                         return status;
165
166                 status = target_write_u32(target, IPRSTC1, IPRSTC_CPU_RST);
167                 if (status != ERROR_OK)
168                         return status;
169
170                 do {
171                         target_read_u32(target, IPRSTC1, &isprtc1);
172                         timeout--;
173                 } while ((isprtc1 & IPRSTC_CPU_RST) && timeout > 0);
174
175                 if (timeout == 0) {
176                         LOG_WARNING("Mini51 flash driver: timeout attempting to reboot\n");
177                         return ERROR_FLASH_OPERATION_FAILED;
178                 }
179         }
180
181         return ERROR_OK;
182 }
183
184 static int mini51_get_part_id(struct flash_bank *bank, uint32_t *part_id)
185 {
186         return target_read_u32(bank->target, PART_ID_REG, part_id);
187 }
188
189 static int mini51_get_flash_size(struct flash_bank *bank, uint32_t *flash_size)
190 {
191         uint32_t part_id;
192         int status;
193
194         status = mini51_get_part_id(bank, &part_id);
195         if (status != ERROR_OK)
196                 return status;
197
198         switch (part_id & PART_ID_MAIN_MASK) {
199                 case MINI51:
200                         *flash_size = 4 * MINI51_KB;
201                         break;
202                 case MINI52:
203                         *flash_size = 8 * MINI51_KB;
204                         break;
205                 case MINI54:
206                         *flash_size = 16 * MINI51_KB;
207                         break;
208                 default:
209                         *flash_size = 0;
210                         break;
211         }
212
213         return ERROR_OK;
214 }
215
216 /* Public (API) methods */
217
218 FLASH_BANK_COMMAND_HANDLER(mini51_flash_bank_command)
219 {
220         struct mini51_flash_bank *mini51_info;
221         mini51_info = malloc(sizeof(struct mini51_flash_bank));
222         mini51_info->probed = false;
223         bank->driver_priv = mini51_info;
224
225         return ERROR_OK;
226 }
227
228 static int mini51_protect_check(struct flash_bank *bank)
229 {
230         LOG_WARNING("Mini51 flash driver: protect_check not implemented yet\n");
231
232         return ERROR_FLASH_OPERATION_FAILED;
233 }
234
235 static int mini51_erase(struct flash_bank *bank, int first, int last)
236 {
237         int status;
238         int timeout;
239         uint32_t ispcon;
240         uint32_t isptrg;
241         enum mini51_boot_source new_source;
242         enum mini51_boot_source prev_source;
243         struct target *target = bank->target;
244
245         if (target->state != TARGET_HALTED) {
246                 LOG_ERROR("Target not halted");
247                 return ERROR_TARGET_NOT_HALTED;
248         }
249
250         /* TODO: add support for erasing the LDROM */
251         new_source = LDROM;
252         status = mini51_reboot_with_source(bank, new_source, &prev_source);
253         if (status != ERROR_OK)
254                 return status;
255
256         /* Enable ISP */
257         status = target_read_u32(target, ISPCON, &ispcon);
258         if (status != ERROR_OK)
259                 return status;
260         ispcon |= ISPCON_ISPEN;
261         status = target_write_u32(target, ISPCON, ispcon);
262
263         for (int page_start = first; page_start <= last; page_start++) {
264                 /* Set up erase command */
265                 status = target_write_u32(target, ISPADR, page_start*MINI51_PAGE_SIZE);
266                 if (status != ERROR_OK)
267                         return status;
268                 status = target_write_u32(target, ISPCMD, ISPCMD_ERASE);
269                 if (status != ERROR_OK)
270                         return status;
271
272                 /* Erase the selected page */
273                 status = target_write_u32(target, ISPTRG, ISPTRG_ISPGO);
274                 if (status != ERROR_OK)
275                         return status;
276
277                 /* Wait for for command to finish executing */
278                 timeout = MINI51_TIMEOUT;
279                 do {
280                         target_read_u32(target, ISPTRG, &isptrg);
281                         timeout--;
282                 } while ((isptrg & ISPTRG_ISPGO) && (timeout > 0));
283                 if (timeout == 0) {
284                         LOG_WARNING("Mini51 flash driver: Timeout erasing flash\n");
285                         return ERROR_FLASH_OPERATION_FAILED;
286                 }
287
288                 /* Check for errors */
289                 status = target_read_u32(target, ISPCON, &ispcon);
290                 if (status != ERROR_OK)
291                         return status;
292                 if (ispcon & ISPCON_ISPFF) {
293                         LOG_WARNING("Mini51 flash driver: Erase operation failed\n");
294                         return ERROR_FLASH_OPERATION_FAILED;
295                 }
296         }
297
298         /* Reboot from previous source */
299         if (prev_source != new_source) {
300                 status = mini51_reboot_with_source(bank, prev_source, &new_source);
301                 if (status != ERROR_OK)
302                         return status;
303         }
304
305         return ERROR_OK;
306 }
307
308 static int mini51_protect(struct flash_bank *bank, int set, int first, int last)
309 {
310         LOG_WARNING("Mini51 flash driver: protect operation not implemented yet\n");
311
312         return ERROR_FLASH_OPERATION_FAILED;
313 }
314
315 static int mini51_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
316 {
317         int status;
318         int timeout;
319         uint32_t ispcon;
320         uint32_t isptrg;
321         uint32_t ispdat;
322         enum mini51_boot_source new_source;
323         enum mini51_boot_source prev_source;
324         struct target *target = bank->target;
325
326         if (target->state != TARGET_HALTED) {
327                 LOG_ERROR("Target not halted");
328                 return ERROR_TARGET_NOT_HALTED;
329         }
330
331         if ((offset & 0x3) || (count & 0x3)) {
332                 LOG_WARNING("Mini51 flash driver: unaligned access not supported\n");
333                 return ERROR_FLASH_OPERATION_FAILED;
334         }
335
336         /* TODO: add support for writing to LDROM */
337         new_source = LDROM;
338         status = mini51_reboot_with_source(bank, new_source, &prev_source);
339         if (status != ERROR_OK)
340                 return status;
341
342         /* Enable ISP */
343         status = target_read_u32(target, ISPCON, &ispcon);
344         if (status != ERROR_OK)
345                 return status;
346         ispcon |= ISPCON_ISPEN;
347         status = target_write_u32(target, ISPCON, ispcon);
348
349         for (uint32_t i = offset; i < offset + count; i += 4) {
350                 /* Set up program command */
351                 status = target_write_u32(target, ISPADR, i);
352                 if (status != ERROR_OK)
353                         return status;
354                 status = target_write_u32(target, ISPCMD, ISPCMD_PROGRAM);
355                 if (status != ERROR_OK)
356                         return status;
357                 memcpy(&ispdat, buffer, sizeof(ispdat));
358                 buffer += sizeof(ispdat);
359                 status = target_write_u32(target, ISPDAT, ispdat);
360                 if (status != ERROR_OK)
361                         return status;
362
363                 /* Write the selected word */
364                 status = target_write_u32(target, ISPTRG, ISPTRG_ISPGO);
365                 if (status != ERROR_OK)
366                         return status;
367
368                 /* Wait for for command to finish executing */
369                 timeout = MINI51_TIMEOUT;
370                 do {
371                         target_read_u32(target, ISPTRG, &isptrg);
372                         timeout--;
373                 } while ((isptrg & ISPTRG_ISPGO) && (timeout > 0));
374                 if (timeout == 0) {
375                         LOG_WARNING("Mini51 flash driver: Timeout programming flash\n");
376                         return ERROR_FLASH_OPERATION_FAILED;
377                 }
378
379                 /* Check for errors */
380                 status = target_read_u32(target, ISPCON, &ispcon);
381                 if (status != ERROR_OK)
382                         return status;
383                 if (ispcon & ISPCON_ISPFF) {
384                         LOG_WARNING("Mini51 flash driver: Programming operation failed\n");
385                         return ERROR_FLASH_OPERATION_FAILED;
386                 }
387         }
388
389         if (prev_source != new_source) {
390                 status = mini51_reboot_with_source(bank, prev_source, &new_source);
391                 if (status != ERROR_OK)
392                         return status;
393         }
394
395         return ERROR_OK;
396 }
397
398 static int mini51_probe(struct flash_bank *bank)
399 {
400         uint32_t flash_size;
401         int retval;
402         int num_pages;
403         uint32_t offset = 0;
404
405         retval = mini51_get_flash_size(bank, &flash_size);
406         if (retval != ERROR_OK || flash_size == 0) {
407                 LOG_WARNING("Mini51 flash driver: Failed to detect a known part\n");
408                 return ERROR_FLASH_OPERATION_FAILED;
409         }
410
411         num_pages = flash_size / MINI51_PAGE_SIZE;
412
413         bank->base = MINI51_APROM_BASE;
414         bank->num_sectors = num_pages;
415         bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
416         bank->size = flash_size;
417
418         for (int i = 0; i < num_pages; i++) {
419                 bank->sectors[i].offset = offset;
420                 bank->sectors[i].size = MINI51_PAGE_SIZE;
421                 bank->sectors[i].is_erased = -1;
422                 bank->sectors[i].is_protected = 0;
423                 offset += MINI51_PAGE_SIZE;
424         }
425
426         struct mini51_flash_bank *mini51_info = bank->driver_priv;
427         mini51_info->probed = true;
428
429         return ERROR_OK;
430 }
431
432 static int mini51_auto_probe(struct flash_bank *bank)
433 {
434         struct mini51_flash_bank *mini51_info = bank->driver_priv;
435         if (mini51_info->probed)
436                 return ERROR_OK;
437         return mini51_probe(bank);
438 }
439
440 struct flash_driver mini51_flash = {
441         .name = "mini51",
442         .flash_bank_command = mini51_flash_bank_command,
443         .erase = mini51_erase,
444         .protect = mini51_protect,
445         .write = mini51_write,
446         .read = default_flash_read,
447         .probe = mini51_probe,
448         .auto_probe = mini51_auto_probe,
449         .erase_check = default_flash_blank_check,
450         .protect_check = mini51_protect_check,
451 };