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

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)