]> git.sur5r.net Git - openocd/blob - src/flash/lpc288x.c
Karl RobinSod <karl.robinsod@gmail.com> added lpc288x support. Some work remaining...
[openocd] / src / flash / lpc288x.c
1 /***************************************************************************\r
2  *   Copyright (C) 2008 by                                                             *\r
3  *   Karl RobinSod <karl.robinsod@gmail.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 \r
21 /***************************************************************************\r
22 * There are some things to notice\r
23 *\r
24 * You need to unprotect flash sectors each time you connect the OpenOCD\r
25 * Dumping 1MB takes about 60 Seconds\r
26 * Full erase (sectors 0-22 inclusive) takes 2-4 seconds\r
27 * Writing 1MB takes 88 seconds\r
28 *\r
29  ***************************************************************************/\r
30 #ifdef HAVE_CONFIG_H\r
31 #include "config.h"\r
32 #endif\r
33 \r
34 #include "replacements.h"\r
35 \r
36 #include "lpc288x.h"\r
37 \r
38 #include "flash.h"\r
39 #include "target.h"\r
40 #include "log.h"\r
41 #include "binarybuffer.h"\r
42 #include "types.h"\r
43 \r
44 #include <stdlib.h>\r
45 #include <string.h>\r
46 #include <unistd.h>\r
47 \r
48 #define LOAD_TIMER_ERASE    0\r
49 #define LOAD_TIMER_WRITE    1\r
50 \r
51 #define FLASH_PAGE_SIZE     512\r
52 \r
53 /* LPC288X control registers */\r
54 #define DBGU_CIDR     0x8000507C\r
55 /* LPC288X flash registers */\r
56 #define F_CTRL         0x80102000  /* Flash control register R/W 0x5 */\r
57 #define F_STAT         0x80102004  /* Flash status register RO 0x45 */\r
58 #define F_PROG_TIME 0x80102008  /* Flash program time register R/W 0 */\r
59 #define F_WAIT         0x80102010  /* Flash read wait state register R/W 0xC004 */\r
60 #define F_CLK_TIME     0x8010201C     /* Flash clock divider for 66 kHz generation R/W 0 */\r
61 #define F_INTEN_CLR 0x80102FD8     /* Clear interrupt enable bits WO - */\r
62 #define F_INTEN_SET 0x80102FDC  /* Set interrupt enable bits WO - */\r
63 #define F_INT_STAT  0x80102FE0  /* Interrupt status bits RO 0 */\r
64 #define F_INTEN     0x80102FE4    /* Interrupt enable bits RO 0 */\r
65 #define F_INT_CLR     0x80102FE8  /* Clear interrupt status bits WO */\r
66 #define F_INT_SET     0x80102FEC  /* Set interrupt status bits WO - */\r
67 #define FLASH_PD     0x80005030  /* Allows turning off the Flash memory for power savings. R/W 1*/\r
68 #define FLASH_INIT     0x80005034  /* Monitors Flash readiness, such as recovery from Power Down mode. R/W -*/\r
69 \r
70 /* F_CTRL bits */\r
71 #define FC_CS         0x0001    \r
72 #define FC_FUNC     0x0002   \r
73 #define FC_WEN         0x0004   \r
74 #define FC_RD_LATCH 0x0020   \r
75 #define FC_PROTECT    0x0080   \r
76 #define FC_SET_DATA 0x0400   \r
77 #define FC_RSSL     0x0800   \r
78 #define FC_PROG_REQ 0x1000   \r
79 #define FC_CLR_BUF  0x4000   \r
80 #define FC_LOAD_REQ 0x8000   \r
81 /* F_STAT bits */\r
82 #define FS_DONE     0x0001   \r
83 #define FS_PROGGNT     0x0002   \r
84 #define FS_RDY         0x0004   \r
85 #define FS_ERR         0x0020   \r
86 /* F_PROG_TIME */\r
87 #define FPT_TIME_MASK    0x7FFF   \r
88 \r
89 #define FPT_ENABLE         0x8000   \r
90 /* F_WAIT */\r
91 #define FW_WAIT_STATES_MASK    0x00FF\r
92 #define FW_SET_MASK            0xC000\r
93 \r
94 /* F_CLK_TIME */\r
95 #define FCT_CLK_DIV_MASK    0x0FFF\r
96 \r
97 \r
98 \r
99 int lpc288x_register_commands(struct command_context_s *cmd_ctx);\r
100 int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);\r
101 int lpc288x_erase(struct flash_bank_s *bank, int first, int last);\r
102 int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last);\r
103 int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);\r
104 int lpc288x_probe(struct flash_bank_s *bank);\r
105 int lpc288x_auto_probe(struct flash_bank_s *bank);\r
106 int lpc288x_erase_check(struct flash_bank_s *bank);\r
107 int lpc288x_protect_check(struct flash_bank_s *bank);\r
108 int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size);\r
109 void lpc288x_set_flash_mode(flash_bank_t *bank, u8 flashplane, int mode);\r
110 u32 lpc288x_wait_status_busy(flash_bank_t *bank, int timeout);\r
111 void lpc288x_load_timer(int erase, struct target_s *target);\r
112 void lpc288x_set_flash_clk(struct flash_bank_s *bank);\r
113 u32 lpc288x_system_ready(struct flash_bank_s *bank);\r
114 int lpc288x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);\r
115 \r
116 flash_driver_t lpc288x_flash =\r
117 {\r
118     .name = "lpc288x",\r
119     .register_commands = lpc288x_register_commands,\r
120     .flash_bank_command = lpc288x_flash_bank_command,\r
121     .erase = lpc288x_erase,\r
122     .protect = lpc288x_protect,\r
123     .write = lpc288x_write,\r
124     .probe = lpc288x_probe,\r
125     .auto_probe = lpc288x_probe,\r
126     .erase_check = lpc288x_erase_check,\r
127     .protect_check = lpc288x_protect_check,\r
128     .info = lpc288x_info\r
129 };\r
130 \r
131 \r
132 int lpc288x_register_commands(struct command_context_s *cmd_ctx)\r
133 {\r
134     return ERROR_OK;\r
135 }\r
136 \r
137 \r
138 \r
139 u32 lpc288x_wait_status_busy(flash_bank_t *bank, int timeout)\r
140 {\r
141     u32 status;\r
142     target_t *target = bank->target;\r
143     do\r
144     {\r
145         usleep(1000);\r
146         timeout--;\r
147         target_read_u32(target, F_STAT, &status);\r
148     }while (((status & FS_DONE) == 0) && timeout);\r
149 \r
150     if(timeout == 0)\r
151     {\r
152         LOG_DEBUG("Timedout!");\r
153         return ERROR_FLASH_OPERATION_FAILED;\r
154     }\r
155     return ERROR_OK;\r
156 }\r
157 \r
158 /* Read device id register and fill in driver info structure */\r
159 int lpc288x_read_part_info(struct flash_bank_s *bank)\r
160 {\r
161     lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;\r
162     target_t *target = bank->target;\r
163     u32 cidr, status;\r
164     int sectornum;\r
165 \r
166     int i = 0;\r
167     u32 offset;\r
168 \r
169     if (lpc288x_info->cidr == 0x0102100A)\r
170         return ERROR_OK; /* already probed, multiple probes may cause memory leak, not allowed */\r
171    \r
172     /* Read and parse chip identification register */\r
173     target_read_u32(target, DBGU_CIDR, &cidr);\r
174    \r
175     if (cidr != 0x0102100A)\r
176     {\r
177         LOG_WARNING("Cannot identify target as an LPC288X (%08X)",cidr);\r
178         return ERROR_FLASH_OPERATION_FAILED;\r
179     }\r
180 \r
181     lpc288x_info->cidr                 = cidr;\r
182     lpc288x_info->sector_size_break = 0x000F0000;\r
183     lpc288x_info->target_name         = "LPC288x";\r
184 \r
185     /* setup the sector info... */\r
186     offset = bank->base;\r
187     bank->num_sectors = 23;\r
188     bank->sectors = malloc(sizeof(flash_sector_t) * 23);\r
189 \r
190     for (i = 0; i < 15; i++)\r
191     {\r
192         bank->sectors[i].offset = offset;\r
193         bank->sectors[i].size = 64 * 1024;\r
194         offset += bank->sectors[i].size;\r
195         bank->sectors[i].is_erased = -1;\r
196         bank->sectors[i].is_protected = 1;\r
197     }\r
198     for (i = 15; i < 23; i++)\r
199     {\r
200         bank->sectors[i].offset = offset;\r
201         bank->sectors[i].size = 8 * 1024;\r
202         offset += bank->sectors[i].size;\r
203         bank->sectors[i].is_erased = -1;\r
204         bank->sectors[i].is_protected = 1;\r
205     }\r
206 \r
207     return ERROR_OK;\r
208 }\r
209 \r
210 int lpc288x_protect_check(struct flash_bank_s *bank)\r
211 {\r
212     return ERROR_OK;\r
213 }\r
214 \r
215 /* flash_bank LPC288x 0 0 0 0 <target#> <cclk>\r
216  */\r
217 int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)\r
218 {\r
219     lpc288x_flash_bank_t *lpc288x_info;\r
220     int i;\r
221    \r
222     if (argc < 6)\r
223     {\r
224         LOG_WARNING("incomplete flash_bank LPC288x configuration");\r
225         return ERROR_FLASH_BANK_INVALID;\r
226     }\r
227    \r
228     lpc288x_info = malloc(sizeof(lpc288x_flash_bank_t));\r
229     bank->driver_priv = lpc288x_info;\r
230    \r
231     /* part wasn't probed for info yet */\r
232     lpc288x_info->cidr = 0;\r
233     lpc288x_info->cclk = strtoul(args[6], NULL, 0);\r
234 \r
235     return ERROR_OK;\r
236 }\r
237 \r
238 /*\r
239 The frequency is the AHB clock frequency divided by (CLK_DIV Ã—\r
240 3) + 1. This must be programmed such that the Flash\r
241 Programming clock frequency is 66 kHz Â± 20%.\r
242     AHB = 12 MHz ?\r
243     12000000/66000 = 182\r
244     CLK_DIV = 60 ?\r
245 */\r
246 void lpc288x_set_flash_clk(struct flash_bank_s *bank)\r
247 {\r
248     u32 clk_time;\r
249     lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;\r
250     clk_time = (lpc288x_info->cclk / 66000) / 3;\r
251     target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN );\r
252     target_write_u32(bank->target, F_CLK_TIME, clk_time);\r
253 }\r
254 \r
255 /*\r
256 AHB tcyc (in ns) 83 ns\r
257 \r
258 LOAD_TIMER_ERASE    FPT_TIME     = ((400,000,000 / AHB tcyc (in ns)) - 2) / 512\r
259                                 = 9412 (9500) (AN10548 9375)\r
260 LOAD_TIMER_WRITE    FPT_TIME     = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512\r
261                                 = 23 (75) (AN10548 72 - is this wrong?)\r
262                                \r
263 TODO: Sort out timing calcs ;)\r
264 */\r
265 void lpc288x_load_timer(int erase, struct target_s *target)\r
266 {\r
267     if(erase == LOAD_TIMER_ERASE)\r
268     {\r
269         target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500);\r
270     }\r
271     else\r
272     {\r
273         target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75);\r
274     }\r
275 }\r
276 \r
277 \r
278 \r
279 u32 lpc288x_system_ready(struct flash_bank_s *bank)\r
280 {\r
281     lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;\r
282     if (lpc288x_info->cidr == 0)\r
283     {\r
284         return ERROR_FLASH_BANK_NOT_PROBED;\r
285     }\r
286 \r
287     if (bank->target->state != TARGET_HALTED)\r
288     {\r
289         return ERROR_TARGET_NOT_HALTED;\r
290     }\r
291     return ERROR_OK;\r
292 }\r
293 \r
294 int lpc288x_erase_check(struct flash_bank_s *bank)\r
295 {\r
296     u32 buffer, test_bytes;\r
297     u32 addr, sector, i, status = lpc288x_system_ready(bank);    /* probed? halted? */\r
298     if(status != ERROR_OK)\r
299     {\r
300         LOG_INFO("Processor not halted/not probed");\r
301         return status;\r
302     }\r
303 \r
304     return ERROR_OK;\r
305 }\r
306 \r
307 int lpc288x_erase(struct flash_bank_s *bank, int first, int last)\r
308 {\r
309     u32 status;\r
310     int sector;\r
311     target_t *target = bank->target;\r
312 \r
313     status = lpc288x_system_ready(bank);    /* probed? halted? */\r
314     if(status != ERROR_OK)\r
315     {\r
316         return status;\r
317     }\r
318    \r
319     if ((first < 0) || (last < first) || (last >= bank->num_sectors))\r
320     {\r
321         LOG_INFO("Bad sector range");\r
322         return ERROR_FLASH_SECTOR_INVALID;\r
323     }\r
324 \r
325     /* Configure the flash controller timing */\r
326     lpc288x_set_flash_clk(bank);\r
327 \r
328     for (sector = first; sector <= last; sector++)\r
329     {\r
330         if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)\r
331         {\r
332             return ERROR_FLASH_OPERATION_FAILED;\r
333         }\r
334 \r
335         lpc288x_load_timer(LOAD_TIMER_ERASE,target);\r
336    \r
337         target_write_u32(    target,\r
338                             bank->sectors[sector].offset,\r
339                             0x00);\r
340        \r
341         target_write_u32(    target,\r
342                             F_CTRL,\r
343                             FC_PROG_REQ |\r
344                             FC_PROTECT    |\r
345                             FC_CS);\r
346     }\r
347     if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)\r
348     {\r
349         return ERROR_FLASH_OPERATION_FAILED;\r
350     }\r
351     return ERROR_OK;\r
352 \r
353 }\r
354 \r
355 \r
356 int lpc288x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)\r
357 {\r
358     u8 page_buffer[FLASH_PAGE_SIZE];\r
359     u32 i, status, source_offset,dest_offset;\r
360     target_t *target = bank->target;\r
361     u32 bytes_remaining = count;\r
362     u32 first_sector, last_sector, sector, page;\r
363 \r
364     /* probed? halted? */\r
365     status = lpc288x_system_ready(bank);   \r
366     if(status != ERROR_OK)\r
367     {\r
368         return status;\r
369     }\r
370 \r
371     /* Initialise search indices */\r
372     first_sector = last_sector = 0xffffffff;\r
373    \r
374     /* validate the write range... */\r
375     for(i = 0; i < bank->num_sectors; i++)\r
376     {\r
377         if((offset >= bank->sectors[i].offset) &&\r
378            (offset < (bank->sectors[i].offset + bank->sectors[i].size)) &&\r
379            (first_sector == 0xffffffff))\r
380         {\r
381            first_sector = i;\r
382            /* all writes must start on a sector boundary...  */\r
383            if (offset % bank->sectors[i].size)\r
384            {\r
385                LOG_INFO("offset 0x%x breaks required alignment 0x%x", offset, bank->sectors[i].size);\r
386                return ERROR_FLASH_DST_BREAKS_ALIGNMENT;\r
387            }\r
388         }\r
389         if(((offset + count) > bank->sectors[i].offset) &&\r
390            ((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) &&\r
391            (last_sector == 0xffffffff))\r
392         {\r
393            last_sector = i;\r
394         }\r
395     }\r
396        \r
397     /* Range check... */\r
398     if (first_sector == 0xffffffff || last_sector == 0xffffffff)\r
399     {\r
400           LOG_INFO("Range check failed %x %x", offset, count);\r
401         return ERROR_FLASH_DST_OUT_OF_BANK;\r
402     }\r
403    \r
404     /* Configure the flash controller timing */\r
405     lpc288x_set_flash_clk(bank);   \r
406 \r
407     /* initialise the offsets */\r
408     source_offset = 0;\r
409     dest_offset   = 0;\r
410    \r
411     for (sector=first_sector; sector<=last_sector; sector++)\r
412     {\r
413         for(page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++)\r
414         {\r
415             if(bytes_remaining == 0)\r
416             {\r
417                 count = 0;\r
418                 memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);\r
419             }\r
420             else if (bytes_remaining < FLASH_PAGE_SIZE)\r
421             {\r
422                 count = bytes_remaining;\r
423                 memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);\r
424                 memcpy(page_buffer, &buffer[source_offset], count);\r
425             }\r
426             else\r
427             {\r
428                 count = FLASH_PAGE_SIZE;\r
429                 memcpy(page_buffer, &buffer[source_offset], count);\r
430             }\r
431 \r
432             /* Wait for flash to become ready */\r
433             if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)\r
434             {\r
435                 return ERROR_FLASH_OPERATION_FAILED;\r
436             }\r
437            \r
438             /* fill flash data latches with 1's */\r
439             target_write_u32(target,     F_CTRL,\r
440                                         FC_CS             |\r
441                                         FC_SET_DATA        |\r
442                                         FC_WEN            |\r
443                                         FC_FUNC    );\r
444 \r
445             target_write_u32(target,     F_CTRL,\r
446                                         FC_CS             |\r
447                                         FC_WEN            |\r
448                                         FC_FUNC    );\r
449             /*would be better to use the clean target_write_buffer() interface but\r
450               it seems not to be a LOT slower....\r
451               bulk_write_memory() is no quicker :(*/\r
452 #if 1\r
453             if (target->type->write_memory(target, offset + dest_offset, 4, 128, page_buffer) != ERROR_OK)\r
454             {\r
455                 LOG_ERROR("Write failed s %x p %x", sector, page);\r
456                 return ERROR_FLASH_OPERATION_FAILED;\r
457             }\r
458 #else\r
459             if(target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE, page_buffer) != ERROR_OK)\r
460             {\r
461                 LOG_INFO("Write to flash buffer failed");\r
462                 return ERROR_FLASH_OPERATION_FAILED;\r
463             }\r
464 #endif\r
465             dest_offset       += FLASH_PAGE_SIZE;\r
466             source_offset    += count;\r
467             bytes_remaining -= count;\r
468 \r
469             lpc288x_load_timer(LOAD_TIMER_WRITE, target);\r
470            \r
471             target_write_u32(    target,\r
472                                 F_CTRL,\r
473                                 FC_PROG_REQ |\r
474                                 FC_PROTECT    |\r
475                                 FC_FUNC        |\r
476                                 FC_CS);\r
477            \r
478            \r
479         }           \r
480     }\r
481        \r
482     return ERROR_OK;\r
483 }\r
484 \r
485 \r
486 int lpc288x_probe(struct flash_bank_s *bank)\r
487 {\r
488     /* we only deal with LPC2888 so flash config is fixed\r
489      */\r
490     lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;\r
491     int retval;\r
492 \r
493     if (lpc288x_info->cidr != 0)\r
494     {\r
495         return ERROR_OK; /* already probed */\r
496     }\r
497 \r
498     if (bank->target->state != TARGET_HALTED)\r
499     {\r
500         return ERROR_TARGET_NOT_HALTED;\r
501     }\r
502 \r
503     retval = lpc288x_read_part_info(bank);\r
504     if (retval != ERROR_OK)\r
505         return retval;\r
506    \r
507     return ERROR_OK;\r
508 }\r
509 \r
510 \r
511 int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size)\r
512 {\r
513     snprintf(buf, buf_size, "lpc288x flash driver");\r
514     return ERROR_OK;\r
515 }\r
516 \r
517 int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last)\r
518 {\r
519     int lockregion, status;\r
520     u32 value;\r
521     target_t *target = bank->target;\r
522    \r
523     /* probed? halted? */\r
524     status = lpc288x_system_ready(bank);   \r
525     if(status != ERROR_OK)\r
526     {\r
527         return status;\r
528     }\r
529    \r
530     if ((first < 0) || (last < first) || (last >= bank->num_sectors))\r
531     {\r
532         return ERROR_FLASH_SECTOR_INVALID;\r
533     }\r
534 \r
535     /* Configure the flash controller timing */\r
536     lpc288x_set_flash_clk(bank);   \r
537 \r
538     for (lockregion = first; lockregion <= last; lockregion++)\r
539     {\r
540         if(set)\r
541         {\r
542             /* write an odd value to base addy to protect... */\r
543             value = 0x01;\r
544         }\r
545         else\r
546         {\r
547             /* write an even value to base addy to unprotect... */\r
548             value = 0x00;\r
549         }\r
550         target_write_u32(    target,\r
551                             bank->sectors[lockregion].offset,\r
552                             value);\r
553        \r
554         target_write_u32(    target,\r
555                             F_CTRL,\r
556                             FC_LOAD_REQ |\r
557                             FC_PROTECT    |\r
558                             FC_WEN        |\r
559                             FC_FUNC        |\r
560                             FC_CS);\r
561     }\r
562    \r
563     return ERROR_OK;\r
564 }\r
565 \r