b602619d8e56c24ac852f0e5a3f9af09b038afa7
[openocd.git] / src / flash / nor / lpc288x.c
1 /***************************************************************************
2 * Copyright (C) 2008 by *
3 * Karl RobinSod <karl.robinsod@gmail.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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
19 ***************************************************************************/
20
21 /***************************************************************************
22 * There are some things to notice
23 *
24 * You need to unprotect flash sectors each time you connect the OpenOCD
25 * Dumping 1MB takes about 60 Seconds
26 * Full erase (sectors 0-22 inclusive) takes 2-4 seconds
27 * Writing 1MB takes 88 seconds
28 *
29 ***************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "imp.h"
35 #include <helper/binarybuffer.h>
36
37 #define LOAD_TIMER_ERASE 0
38 #define LOAD_TIMER_WRITE 1
39
40 #define FLASH_PAGE_SIZE 512
41
42 /* LPC288X control registers */
43 #define DBGU_CIDR 0x8000507C
44 /* LPC288X flash registers */
45 #define F_CTRL 0x80102000 /* Flash control register R/W 0x5 */
46 #define F_STAT 0x80102004 /* Flash status register RO 0x45 */
47 #define F_PROG_TIME 0x80102008 /* Flash program time register R/W 0 */
48 #define F_WAIT 0x80102010 /* Flash read wait state register R/W 0xC004 */
49 #define F_CLK_TIME 0x8010201C /* Flash clock divider for 66 kHz generation R/W 0
50 **/
51 #define F_INTEN_CLR 0x80102FD8 /* Clear interrupt enable bits WO - */
52 #define F_INTEN_SET 0x80102FDC /* Set interrupt enable bits WO - */
53 #define F_INT_STAT 0x80102FE0 /* Interrupt status bits RO 0 */
54 #define F_INTEN 0x80102FE4 /* Interrupt enable bits RO 0 */
55 #define F_INT_CLR 0x80102FE8 /* Clear interrupt status bits WO */
56 #define F_INT_SET 0x80102FEC /* Set interrupt status bits WO - */
57 #define FLASH_PD 0x80005030 /* Allows turning off the Flash memory for power
58 *savings. R/W 1*/
59 #define FLASH_INIT 0x80005034 /* Monitors Flash readiness, such as recovery from
60 *Power Down mode. R/W -*/
61
62 /* F_CTRL bits */
63 #define FC_CS 0x0001
64 #define FC_FUNC 0x0002
65 #define FC_WEN 0x0004
66 #define FC_RD_LATCH 0x0020
67 #define FC_PROTECT 0x0080
68 #define FC_SET_DATA 0x0400
69 #define FC_RSSL 0x0800
70 #define FC_PROG_REQ 0x1000
71 #define FC_CLR_BUF 0x4000
72 #define FC_LOAD_REQ 0x8000
73 /* F_STAT bits */
74 #define FS_DONE 0x0001
75 #define FS_PROGGNT 0x0002
76 #define FS_RDY 0x0004
77 #define FS_ERR 0x0020
78 /* F_PROG_TIME */
79 #define FPT_TIME_MASK 0x7FFF
80
81 #define FPT_ENABLE 0x8000
82 /* F_WAIT */
83 #define FW_WAIT_STATES_MASK 0x00FF
84 #define FW_SET_MASK 0xC000
85
86 /* F_CLK_TIME */
87 #define FCT_CLK_DIV_MASK 0x0FFF
88
89 struct lpc288x_flash_bank {
90 uint32_t working_area;
91 uint32_t working_area_size;
92
93 /* chip id register */
94 uint32_t cidr;
95 const char *target_name;
96 uint32_t cclk;
97
98 uint32_t sector_size_break;
99 };
100
101 static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout);
102 static void lpc288x_load_timer(int erase, struct target *target);
103 static void lpc288x_set_flash_clk(struct flash_bank *bank);
104 static uint32_t lpc288x_system_ready(struct flash_bank *bank);
105
106 static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout)
107 {
108 uint32_t status;
109 struct target *target = bank->target;
110 do {
111 alive_sleep(1);
112 timeout--;
113 target_read_u32(target, F_STAT, &status);
114 } while (((status & FS_DONE) == 0) && timeout);
115
116 if (timeout == 0) {
117 LOG_DEBUG("Timedout!");
118 return ERROR_FLASH_OPERATION_FAILED;
119 }
120 return ERROR_OK;
121 }
122
123 /* Read device id register and fill in driver info structure */
124 static int lpc288x_read_part_info(struct flash_bank *bank)
125 {
126 struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
127 struct target *target = bank->target;
128 uint32_t cidr;
129
130 int i = 0;
131 uint32_t offset;
132
133 if (lpc288x_info->cidr == 0x0102100A)
134 return ERROR_OK;/* already probed, multiple probes may cause memory leak, not
135 *allowed */
136
137 /* Read and parse chip identification register */
138 target_read_u32(target, DBGU_CIDR, &cidr);
139
140 if (cidr != 0x0102100A) {
141 LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")", cidr);
142 return ERROR_FLASH_OPERATION_FAILED;
143 }
144
145 lpc288x_info->cidr = cidr;
146 lpc288x_info->sector_size_break = 0x000F0000;
147 lpc288x_info->target_name = "LPC288x";
148
149 /* setup the sector info... */
150 offset = bank->base;
151 bank->num_sectors = 23;
152 bank->sectors = malloc(sizeof(struct flash_sector) * 23);
153
154 for (i = 0; i < 15; i++) {
155 bank->sectors[i].offset = offset;
156 bank->sectors[i].size = 64 * 1024;
157 offset += bank->sectors[i].size;
158 bank->sectors[i].is_erased = -1;
159 bank->sectors[i].is_protected = 1;
160 }
161 for (i = 15; i < 23; i++) {
162 bank->sectors[i].offset = offset;
163 bank->sectors[i].size = 8 * 1024;
164 offset += bank->sectors[i].size;
165 bank->sectors[i].is_erased = -1;
166 bank->sectors[i].is_protected = 1;
167 }
168
169 return ERROR_OK;
170 }
171
172 static int lpc288x_protect_check(struct flash_bank *bank)
173 {
174 return ERROR_OK;
175 }
176
177 /* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */
178 FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
179 {
180 struct lpc288x_flash_bank *lpc288x_info;
181
182 if (CMD_ARGC < 6)
183 return ERROR_COMMAND_SYNTAX_ERROR;
184
185 lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
186 bank->driver_priv = lpc288x_info;
187
188 /* part wasn't probed for info yet */
189 lpc288x_info->cidr = 0;
190 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk);
191
192 return ERROR_OK;
193 }
194
195 /* The frequency is the AHB clock frequency divided by (CLK_DIV ×3) + 1.
196 * This must be programmed such that the Flash Programming clock frequency is 66 kHz ± 20%.
197 * AHB = 12 MHz ?
198 * 12000000/66000 = 182
199 * CLK_DIV = 60 ? */
200 static void lpc288x_set_flash_clk(struct flash_bank *bank)
201 {
202 uint32_t clk_time;
203 struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
204 clk_time = (lpc288x_info->cclk / 66000) / 3;
205 target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN);
206 target_write_u32(bank->target, F_CLK_TIME, clk_time);
207 }
208
209 /* AHB tcyc (in ns) 83 ns
210 * LOAD_TIMER_ERASE FPT_TIME = ((400,000,000 / AHB tcyc (in ns)) - 2) / 512
211 * = 9412 (9500) (AN10548 9375)
212 * LOAD_TIMER_WRITE FPT_TIME = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512
213 * = 23 (75) (AN10548 72 - is this wrong?)
214 * TODO: Sort out timing calcs ;) */
215 static void lpc288x_load_timer(int erase, struct target *target)
216 {
217 if (erase == LOAD_TIMER_ERASE)
218 target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500);
219 else
220 target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75);
221 }
222
223 static uint32_t lpc288x_system_ready(struct flash_bank *bank)
224 {
225 struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
226 if (lpc288x_info->cidr == 0)
227 return ERROR_FLASH_BANK_NOT_PROBED;
228
229 if (bank->target->state != TARGET_HALTED) {
230 LOG_ERROR("Target not halted");
231 return ERROR_TARGET_NOT_HALTED;
232 }
233 return ERROR_OK;
234 }
235
236 static int lpc288x_erase_check(struct flash_bank *bank)
237 {
238 uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
239 if (status != ERROR_OK) {
240 LOG_INFO("Processor not halted/not probed");
241 return status;
242 }
243
244 return ERROR_OK;
245 }
246
247 static int lpc288x_erase(struct flash_bank *bank, int first, int last)
248 {
249 uint32_t status;
250 int sector;
251 struct target *target = bank->target;
252
253 status = lpc288x_system_ready(bank); /* probed? halted? */
254 if (status != ERROR_OK)
255 return status;
256
257 if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
258 LOG_INFO("Bad sector range");
259 return ERROR_FLASH_SECTOR_INVALID;
260 }
261
262 /* Configure the flash controller timing */
263 lpc288x_set_flash_clk(bank);
264
265 for (sector = first; sector <= last; sector++) {
266 if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
267 return ERROR_FLASH_OPERATION_FAILED;
268
269 lpc288x_load_timer(LOAD_TIMER_ERASE, target);
270
271 target_write_u32(target, bank->sectors[sector].offset, 0x00);
272
273 target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_CS);
274 }
275 if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
276 return ERROR_FLASH_OPERATION_FAILED;
277 return ERROR_OK;
278 }
279
280 static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
281 {
282 uint8_t page_buffer[FLASH_PAGE_SIZE];
283 uint32_t status, source_offset, dest_offset;
284 struct target *target = bank->target;
285 uint32_t bytes_remaining = count;
286 uint32_t first_sector, last_sector, sector, page;
287 int i;
288
289 /* probed? halted? */
290 status = lpc288x_system_ready(bank);
291 if (status != ERROR_OK)
292 return status;
293
294 /* Initialise search indices */
295 first_sector = last_sector = 0xffffffff;
296
297 /* validate the write range... */
298 for (i = 0; i < bank->num_sectors; i++) {
299 if ((offset >= bank->sectors[i].offset) &&
300 (offset < (bank->sectors[i].offset + bank->sectors[i].size)) &&
301 (first_sector == 0xffffffff)) {
302 first_sector = i;
303 /* all writes must start on a sector boundary... */
304 if (offset % bank->sectors[i].size) {
305 LOG_INFO(
306 "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "",
307 offset,
308 bank->sectors[i].size);
309 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
310 }
311 }
312 if (((offset + count) > bank->sectors[i].offset) &&
313 ((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) &&
314 (last_sector == 0xffffffff))
315 last_sector = i;
316 }
317
318 /* Range check... */
319 if (first_sector == 0xffffffff || last_sector == 0xffffffff) {
320 LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count);
321 return ERROR_FLASH_DST_OUT_OF_BANK;
322 }
323
324 /* Configure the flash controller timing */
325 lpc288x_set_flash_clk(bank);
326
327 /* initialise the offsets */
328 source_offset = 0;
329 dest_offset = 0;
330
331 for (sector = first_sector; sector <= last_sector; sector++) {
332 for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++) {
333 if (bytes_remaining == 0) {
334 count = 0;
335 memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
336 } else if (bytes_remaining < FLASH_PAGE_SIZE) {
337 count = bytes_remaining;
338 memset(page_buffer, 0xFF, FLASH_PAGE_SIZE);
339 memcpy(page_buffer, &buffer[source_offset], count);
340 } else {
341 count = FLASH_PAGE_SIZE;
342 memcpy(page_buffer, &buffer[source_offset], count);
343 }
344
345 /* Wait for flash to become ready */
346 if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK)
347 return ERROR_FLASH_OPERATION_FAILED;
348
349 /* fill flash data latches with 1's */
350 target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC);
351
352 target_write_u32(target, F_CTRL, FC_CS | FC_WEN | FC_FUNC);
353
354 if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE,
355 page_buffer) != ERROR_OK) {
356 LOG_INFO("Write to flash buffer failed");
357 return ERROR_FLASH_OPERATION_FAILED;
358 }
359
360 dest_offset += FLASH_PAGE_SIZE;
361 source_offset += count;
362 bytes_remaining -= count;
363
364 lpc288x_load_timer(LOAD_TIMER_WRITE, target);
365
366 target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC |
367 FC_CS);
368 }
369 }
370
371 return ERROR_OK;
372 }
373
374 static int lpc288x_probe(struct flash_bank *bank)
375 {
376 /* we only deal with LPC2888 so flash config is fixed */
377 struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
378 int retval;
379
380 if (lpc288x_info->cidr != 0)
381 return ERROR_OK;/* already probed */
382
383 if (bank->target->state != TARGET_HALTED) {
384 LOG_ERROR("Target not halted");
385 return ERROR_TARGET_NOT_HALTED;
386 }
387
388 retval = lpc288x_read_part_info(bank);
389 if (retval != ERROR_OK)
390 return retval;
391 return ERROR_OK;
392 }
393
394 static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last)
395 {
396 int lockregion, status;
397 uint32_t value;
398 struct target *target = bank->target;
399
400 /* probed? halted? */
401 status = lpc288x_system_ready(bank);
402 if (status != ERROR_OK)
403 return status;
404
405 if ((first < 0) || (last < first) || (last >= bank->num_sectors))
406 return ERROR_FLASH_SECTOR_INVALID;
407
408 /* Configure the flash controller timing */
409 lpc288x_set_flash_clk(bank);
410
411 for (lockregion = first; lockregion <= last; lockregion++) {
412 if (set) {
413 /* write an odd value to base addy to protect... */
414 value = 0x01;
415 } else {
416 /* write an even value to base addy to unprotect... */
417 value = 0x00;
418 }
419 target_write_u32(target, bank->sectors[lockregion].offset, value);
420 target_write_u32(target, F_CTRL, FC_LOAD_REQ | FC_PROTECT | FC_WEN | FC_FUNC |
421 FC_CS);
422 }
423
424 return ERROR_OK;
425 }
426
427 struct flash_driver lpc288x_flash = {
428 .name = "lpc288x",
429 .flash_bank_command = lpc288x_flash_bank_command,
430 .erase = lpc288x_erase,
431 .protect = lpc288x_protect,
432 .write = lpc288x_write,
433 .read = default_flash_read,
434 .probe = lpc288x_probe,
435 .auto_probe = lpc288x_probe,
436 .erase_check = lpc288x_erase_check,
437 .protect_check = lpc288x_protect_check,
438 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)