flash/nor: Add PSoC 5LP flash driver
[openocd.git] / src / flash / nor / psoc5lp.c
1 /*
2 * PSoC 5LP flash driver
3 *
4 * Copyright (c) 2016 Andreas Färber
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "imp.h"
25 #include <helper/time_support.h>
26 #include <target/armv7m.h>
27
28 #define PM_ACT_CFG0 0x400043A0
29 #define SPC_CPU_DATA 0x40004720
30 #define SPC_SR 0x40004722
31 #define PHUB_CH0_BASIC_CFG 0x40007010
32 #define PHUB_CH0_ACTION 0x40007014
33 #define PHUB_CH0_BASIC_STATUS 0x40007018
34 #define PHUB_CH1_BASIC_CFG 0x40007020
35 #define PHUB_CH1_ACTION 0x40007024
36 #define PHUB_CH1_BASIC_STATUS 0x40007028
37 #define PHUB_CFGMEM0_CFG0 0x40007600
38 #define PHUB_CFGMEM0_CFG1 0x40007604
39 #define PHUB_CFGMEM1_CFG0 0x40007608
40 #define PHUB_CFGMEM1_CFG1 0x4000760C
41 #define PHUB_TDMEM0_ORIG_TD0 0x40007800
42 #define PHUB_TDMEM0_ORIG_TD1 0x40007804
43 #define PHUB_TDMEM1_ORIG_TD0 0x40007808
44 #define PHUB_TDMEM1_ORIG_TD1 0x4000780C
45 #define PANTHER_DEVICE_ID 0x4008001C
46
47 #define SPC_KEY1 0xB6
48 #define SPC_KEY2 0xD3
49
50 #define SPC_LOAD_BYTE 0x00
51 #define SPC_LOAD_MULTI_BYTE 0x01
52 #define SPC_LOAD_ROW 0x02
53 #define SPC_READ_BYTE 0x03
54 #define SPC_READ_MULTI_BYTE 0x04
55 #define SPC_WRITE_ROW 0x05
56 #define SPC_WRITE_USER_NVL 0x06
57 #define SPC_PRG_ROW 0x07
58 #define SPC_ERASE_SECTOR 0x08
59 #define SPC_ERASE_ALL 0x09
60 #define SPC_READ_HIDDEN_ROW 0x0A
61 #define SPC_PROGRAM_PROTECT_ROW 0x0B
62 #define SPC_GET_CHECKSUM 0x0C
63 #define SPC_GET_TEMP 0x0E
64 #define SPC_READ_VOLATILE_BYTE 0x10
65
66 #define SPC_ARRAY_ALL 0x3F
67 #define SPC_ARRAY_EEPROM 0x40
68 #define SPC_ARRAY_NVL_USER 0x80
69 #define SPC_ARRAY_NVL_WO 0xF8
70
71 #define SPC_ROW_PROTECTION 0
72
73 #define SPC_OPCODE_LEN 3
74
75 #define SPC_SR_DATA_READY (1 << 0)
76 #define SPC_SR_IDLE (1 << 1)
77
78 #define PM_ACT_CFG0_EN_CLK_SPC (1 << 3)
79
80 #define PHUB_CHx_BASIC_CFG_EN (1 << 0)
81 #define PHUB_CHx_BASIC_CFG_WORK_SEP (1 << 5)
82
83 #define PHUB_CHx_ACTION_CPU_REQ (1 << 0)
84
85 #define PHUB_CFGMEMx_CFG0 (1 << 7)
86
87 #define PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST (0xff << 16)
88 #define PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR (1 << 24)
89
90 #define NVL_3_ECCEN (1 << 3)
91
92 #define ROW_SIZE 256
93 #define ROW_ECC_SIZE 32
94 #define ROWS_PER_SECTOR 64
95 #define SECTOR_SIZE (ROWS_PER_SECTOR * ROW_SIZE)
96 #define ROWS_PER_BLOCK 256
97 #define BLOCK_SIZE (ROWS_PER_BLOCK * ROW_SIZE)
98 #define SECTORS_PER_BLOCK (BLOCK_SIZE / SECTOR_SIZE)
99
100 #define PART_NUMBER_LEN (17 + 1)
101
102 struct psoc5lp_device {
103 uint32_t id;
104 unsigned fam;
105 unsigned speed_mhz;
106 unsigned flash_kb;
107 unsigned eeprom_kb;
108 };
109
110 /*
111 * Device information collected from datasheets.
112 * Different temperature ranges (C/I/Q/A) may share IDs, not differing otherwise.
113 */
114 static const struct psoc5lp_device psoc5lp_devices[] = {
115 /* CY8C58LP Family Datasheet */
116 { .id = 0x2E11F069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
117 { .id = 0x2E120069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
118 { .id = 0x2E123069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
119 { .id = 0x2E124069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
120 { .id = 0x2E126069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
121 { .id = 0x2E127069, .fam = 8, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
122 { .id = 0x2E117069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
123 { .id = 0x2E118069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
124 { .id = 0x2E119069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
125 { .id = 0x2E11C069, .fam = 8, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
126 { .id = 0x2E114069, .fam = 8, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
127 { .id = 0x2E115069, .fam = 8, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
128 { .id = 0x2E116069, .fam = 8, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
129 { .id = 0x2E160069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
130 /* '' */
131 { .id = 0x2E161069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
132 /* '' */
133 { .id = 0x2E1D2069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
134 { .id = 0x2E1D6069, .fam = 8, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
135
136 /* CY8C56LP Family Datasheet */
137 { .id = 0x2E10A069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
138 { .id = 0x2E10D069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
139 { .id = 0x2E10E069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
140 { .id = 0x2E106069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
141 { .id = 0x2E108069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
142 { .id = 0x2E109069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
143 { .id = 0x2E101069, .fam = 6, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
144 { .id = 0x2E104069, .fam = 6, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
145 /* '' */
146 { .id = 0x2E105069, .fam = 6, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
147 { .id = 0x2E128069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
148 /* '' */
149 { .id = 0x2E122069, .fam = 6, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
150 { .id = 0x2E129069, .fam = 6, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
151 { .id = 0x2E163069, .fam = 6, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
152 { .id = 0x2E156069, .fam = 6, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
153 { .id = 0x2E1D3069, .fam = 6, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
154
155 /* CY8C54LP Family Datasheet */
156 { .id = 0x2E11A069, .fam = 4, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
157 { .id = 0x2E16A069, .fam = 4, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
158 { .id = 0x2E12A069, .fam = 4, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
159 { .id = 0x2E103069, .fam = 4, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
160 { .id = 0x2E16C069, .fam = 4, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
161 { .id = 0x2E102069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
162 { .id = 0x2E148069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
163 { .id = 0x2E155069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
164 { .id = 0x2E16B069, .fam = 4, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
165 { .id = 0x2E12B069, .fam = 4, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 },
166 { .id = 0x2E168069, .fam = 4, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 },
167 { .id = 0x2E178069, .fam = 4, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
168 { .id = 0x2E15D069, .fam = 4, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
169 { .id = 0x2E1D4069, .fam = 4, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
170
171 /* CY8C52LP Family Datasheet */
172 { .id = 0x2E11E069, .fam = 2, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
173 { .id = 0x2E12F069, .fam = 2, .speed_mhz = 67, .flash_kb = 256, .eeprom_kb = 2 },
174 { .id = 0x2E133069, .fam = 2, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
175 { .id = 0x2E159069, .fam = 2, .speed_mhz = 67, .flash_kb = 128, .eeprom_kb = 2 },
176 { .id = 0x2E11D069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
177 { .id = 0x2E121069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
178 { .id = 0x2E184069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
179 { .id = 0x2E196069, .fam = 2, .speed_mhz = 67, .flash_kb = 64, .eeprom_kb = 2 },
180 { .id = 0x2E132069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 },
181 { .id = 0x2E138069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 },
182 { .id = 0x2E13A069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 },
183 { .id = 0x2E152069, .fam = 2, .speed_mhz = 67, .flash_kb = 32, .eeprom_kb = 2 },
184 { .id = 0x2E15F069, .fam = 2, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
185 { .id = 0x2E15A069, .fam = 2, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
186 { .id = 0x2E1D5069, .fam = 2, .speed_mhz = 80, .flash_kb = 256, .eeprom_kb = 2 },
187 };
188
189 static void psoc5lp_get_part_number(const struct psoc5lp_device *dev, char *str)
190 {
191 strcpy(str, "CY8Cabcdefg-LPxxx");
192
193 str[4] = '5';
194 str[5] = '0' + dev->fam;
195
196 switch (dev->speed_mhz) {
197 case 67:
198 str[6] = '6';
199 break;
200 case 80:
201 str[6] = '8';
202 break;
203 default:
204 str[6] = '?';
205 }
206
207 switch (dev->flash_kb) {
208 case 32:
209 str[7] = '5';
210 break;
211 case 64:
212 str[7] = '6';
213 break;
214 case 128:
215 str[7] = '7';
216 break;
217 case 256:
218 str[7] = '8';
219 break;
220 default:
221 str[7] = '?';
222 }
223
224 /* Package does not matter. */
225 strncpy(str + 8, "xx", 2);
226
227 /* Temperate range cannot uniquely be identified. */
228 str[10] = 'x';
229 }
230
231 static int psoc5lp_get_device_id(struct target *target, uint32_t *id)
232 {
233 int retval;
234
235 retval = target_read_u32(target, PANTHER_DEVICE_ID, id); /* dummy read */
236 if (retval != ERROR_OK)
237 return retval;
238 retval = target_read_u32(target, PANTHER_DEVICE_ID, id);
239 return retval;
240 }
241
242 static int psoc5lp_find_device(struct target *target,
243 const struct psoc5lp_device **device)
244 {
245 uint32_t device_id;
246 unsigned i;
247 int retval;
248
249 *device = NULL;
250
251 retval = psoc5lp_get_device_id(target, &device_id);
252 if (retval != ERROR_OK)
253 return retval;
254 LOG_DEBUG("PANTHER_DEVICE_ID = 0x%08" PRIX32, device_id);
255
256 for (i = 0; i < ARRAY_SIZE(psoc5lp_devices); i++) {
257 if (psoc5lp_devices[i].id == device_id) {
258 *device = &psoc5lp_devices[i];
259 return ERROR_OK;
260 }
261 }
262
263 LOG_ERROR("Device 0x%08" PRIX32 " not supported", device_id);
264 return ERROR_FLASH_OPER_UNSUPPORTED;
265 }
266
267 static int psoc5lp_spc_enable_clock(struct target *target)
268 {
269 int retval;
270 uint8_t pm_act_cfg0;
271
272 retval = target_read_u8(target, PM_ACT_CFG0, &pm_act_cfg0);
273 if (retval != ERROR_OK) {
274 LOG_ERROR("Cannot read PM_ACT_CFG0");
275 return retval;
276 }
277
278 if (pm_act_cfg0 & PM_ACT_CFG0_EN_CLK_SPC)
279 return ERROR_OK; /* clock already enabled */
280
281 retval = target_write_u8(target, PM_ACT_CFG0, pm_act_cfg0 | PM_ACT_CFG0_EN_CLK_SPC);
282 if (retval != ERROR_OK)
283 LOG_ERROR("Cannot enable SPC clock");
284
285 return retval;
286 }
287
288 static int psoc5lp_spc_write_opcode(struct target *target, uint8_t opcode)
289 {
290 int retval;
291
292 retval = target_write_u8(target, SPC_CPU_DATA, SPC_KEY1);
293 if (retval != ERROR_OK)
294 return retval;
295 retval = target_write_u8(target, SPC_CPU_DATA, SPC_KEY2 + opcode);
296 if (retval != ERROR_OK)
297 return retval;
298 retval = target_write_u8(target, SPC_CPU_DATA, opcode);
299 return retval;
300 }
301
302 static void psoc5lp_spc_write_opcode_buffer(struct target *target,
303 uint8_t *buf, uint8_t opcode)
304 {
305 buf[0] = SPC_KEY1;
306 buf[1] = SPC_KEY2 + opcode;
307 buf[2] = opcode;
308 }
309
310 static int psoc5lp_spc_busy_wait_data(struct target *target)
311 {
312 int64_t endtime;
313 uint8_t sr;
314 int retval;
315
316 retval = target_read_u8(target, SPC_SR, &sr); /* dummy read */
317 if (retval != ERROR_OK)
318 return retval;
319
320 endtime = timeval_ms() + 1000; /* 1 second timeout */
321 do {
322 alive_sleep(1);
323 retval = target_read_u8(target, SPC_SR, &sr);
324 if (retval != ERROR_OK)
325 return retval;
326 if (sr == SPC_SR_DATA_READY)
327 return ERROR_OK;
328 } while (timeval_ms() < endtime);
329
330 return ERROR_FLASH_OPERATION_FAILED;
331 }
332
333 static int psoc5lp_spc_busy_wait_idle(struct target *target)
334 {
335 int64_t endtime;
336 uint8_t sr;
337 int retval;
338
339 retval = target_read_u8(target, SPC_SR, &sr); /* dummy read */
340 if (retval != ERROR_OK)
341 return retval;
342
343 endtime = timeval_ms() + 1000; /* 1 second timeout */
344 do {
345 alive_sleep(1);
346 retval = target_read_u8(target, SPC_SR, &sr);
347 if (retval != ERROR_OK)
348 return retval;
349 if (sr == SPC_SR_IDLE)
350 return ERROR_OK;
351 } while (timeval_ms() < endtime);
352
353 return ERROR_FLASH_OPERATION_FAILED;
354 }
355
356 static int psoc5lp_spc_read_byte(struct target *target,
357 uint8_t array_id, uint8_t offset, uint8_t *data)
358 {
359 int retval;
360
361 retval = psoc5lp_spc_write_opcode(target, SPC_READ_BYTE);
362 if (retval != ERROR_OK)
363 return retval;
364 retval = target_write_u8(target, SPC_CPU_DATA, array_id);
365 if (retval != ERROR_OK)
366 return retval;
367 retval = target_write_u8(target, SPC_CPU_DATA, offset);
368 if (retval != ERROR_OK)
369 return retval;
370
371 retval = psoc5lp_spc_busy_wait_data(target);
372 if (retval != ERROR_OK)
373 return retval;
374
375 retval = target_read_u8(target, SPC_CPU_DATA, data);
376 if (retval != ERROR_OK)
377 return retval;
378
379 retval = psoc5lp_spc_busy_wait_idle(target);
380 if (retval != ERROR_OK)
381 return retval;
382
383 return ERROR_OK;
384 }
385
386 static int psoc5lp_spc_erase_sector(struct target *target,
387 uint8_t array_id, uint8_t row_id)
388 {
389 int retval;
390
391 retval = psoc5lp_spc_write_opcode(target, SPC_ERASE_SECTOR);
392 if (retval != ERROR_OK)
393 return retval;
394 retval = target_write_u8(target, SPC_CPU_DATA, array_id);
395 if (retval != ERROR_OK)
396 return retval;
397 retval = target_write_u8(target, SPC_CPU_DATA, row_id);
398 if (retval != ERROR_OK)
399 return retval;
400
401 retval = psoc5lp_spc_busy_wait_idle(target);
402 if (retval != ERROR_OK)
403 return retval;
404
405 return ERROR_OK;
406 }
407
408 static int psoc5lp_spc_erase_all(struct target *target)
409 {
410 int retval;
411
412 retval = psoc5lp_spc_write_opcode(target, SPC_ERASE_ALL);
413 if (retval != ERROR_OK)
414 return retval;
415
416 retval = psoc5lp_spc_busy_wait_idle(target);
417 if (retval != ERROR_OK)
418 return retval;
419
420 return ERROR_OK;
421 }
422
423 static int psoc5lp_spc_read_hidden_row(struct target *target,
424 uint8_t array_id, uint8_t row_id, uint8_t *data)
425 {
426 int i, retval;
427
428 retval = psoc5lp_spc_write_opcode(target, SPC_READ_HIDDEN_ROW);
429 if (retval != ERROR_OK)
430 return retval;
431 retval = target_write_u8(target, SPC_CPU_DATA, array_id);
432 if (retval != ERROR_OK)
433 return retval;
434 retval = target_write_u8(target, SPC_CPU_DATA, row_id);
435 if (retval != ERROR_OK)
436 return retval;
437
438 retval = psoc5lp_spc_busy_wait_data(target);
439 if (retval != ERROR_OK)
440 return retval;
441
442 for (i = 0; i < ROW_SIZE; i++) {
443 retval = target_read_u8(target, SPC_CPU_DATA, &data[i]);
444 if (retval != ERROR_OK)
445 return retval;
446 }
447
448 retval = psoc5lp_spc_busy_wait_idle(target);
449 if (retval != ERROR_OK)
450 return retval;
451
452 return ERROR_OK;
453 }
454
455 static int psoc5lp_spc_get_temp(struct target *target, uint8_t samples,
456 uint8_t *data)
457 {
458 int retval;
459
460 retval = psoc5lp_spc_write_opcode(target, SPC_GET_TEMP);
461 if (retval != ERROR_OK)
462 return retval;
463 retval = target_write_u8(target, SPC_CPU_DATA, samples);
464 if (retval != ERROR_OK)
465 return retval;
466
467 retval = psoc5lp_spc_busy_wait_data(target);
468 if (retval != ERROR_OK)
469 return retval;
470
471 retval = target_read_u8(target, SPC_CPU_DATA, &data[0]);
472 if (retval != ERROR_OK)
473 return retval;
474 retval = target_read_u8(target, SPC_CPU_DATA, &data[1]);
475 if (retval != ERROR_OK)
476 return retval;
477
478 retval = psoc5lp_spc_busy_wait_idle(target);
479 if (retval != ERROR_OK)
480 return retval;
481
482 return ERROR_OK;
483 }
484
485 /*
486 * Program Flash
487 */
488
489 struct psoc5lp_flash_bank {
490 bool probed;
491 const struct psoc5lp_device *device;
492 bool ecc_enabled;
493 };
494
495 static int psoc5lp_erase(struct flash_bank *bank, int first, int last)
496 {
497 struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv;
498 int i, retval;
499
500 if (!psoc_bank->ecc_enabled) {
501 /* Silently avoid erasing sectors twice */
502 if (last >= first + bank->num_sectors / 2) {
503 LOG_DEBUG("Skipping duplicate erase of sectors %d to %d",
504 first + bank->num_sectors / 2, last);
505 last = first + (bank->num_sectors / 2) - 1;
506 }
507 /* Check for any remaining ECC sectors */
508 if (last >= bank->num_sectors / 2) {
509 LOG_WARNING("Skipping erase of ECC region sectors %d to %d",
510 bank->num_sectors / 2, last);
511 last = (bank->num_sectors / 2) - 1;
512 }
513 }
514
515 for (i = first; i <= last; i++) {
516 retval = psoc5lp_spc_erase_sector(bank->target,
517 i / SECTORS_PER_BLOCK, i % SECTORS_PER_BLOCK);
518 if (retval != ERROR_OK)
519 return retval;
520 }
521
522 return ERROR_OK;
523 }
524
525 /* Derived from core.c:default_flash_blank_check() */
526 static int psoc5lp_erase_check(struct flash_bank *bank)
527 {
528 struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv;
529 struct target *target = bank->target;
530 uint32_t blank;
531 int i, num_sectors, retval;
532
533 if (target->state != TARGET_HALTED) {
534 LOG_ERROR("Target not halted");
535 return ERROR_TARGET_NOT_HALTED;
536 }
537
538 num_sectors = bank->num_sectors;
539 if (!psoc_bank->ecc_enabled)
540 num_sectors /= 2;
541
542 for (i = 0; i < num_sectors; i++) {
543 uint32_t address = bank->base + bank->sectors[i].offset;
544 uint32_t size = bank->sectors[i].size;
545
546 retval = armv7m_blank_check_memory(target, address, size,
547 &blank, bank->erased_value);
548 if (retval != ERROR_OK)
549 return retval;
550
551 if (blank == 0x00 && !psoc_bank->ecc_enabled) {
552 address = bank->base + bank->sectors[num_sectors + i].offset;
553 size = bank->sectors[num_sectors + i].size;
554
555 retval = armv7m_blank_check_memory(target, address, size,
556 &blank, bank->erased_value);
557 if (retval != ERROR_OK)
558 return retval;
559 }
560
561 if (blank == 0x00) {
562 bank->sectors[i].is_erased = 1;
563 bank->sectors[num_sectors + i].is_erased = 1;
564 } else {
565 bank->sectors[i].is_erased = 0;
566 bank->sectors[num_sectors + i].is_erased = 0;
567 }
568 }
569
570 return ERROR_OK;
571 }
572
573 static int psoc5lp_write(struct flash_bank *bank, const uint8_t *buffer,
574 uint32_t offset, uint32_t byte_count)
575 {
576 struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv;
577 struct target *target = bank->target;
578 struct working_area *code_area, *even_row_area, *odd_row_area;
579 uint32_t row_size;
580 uint8_t temp[2], buf[12], ecc_bytes[ROW_ECC_SIZE];
581 unsigned array_id, row;
582 int i, retval;
583
584 if (offset + byte_count > bank->size) {
585 LOG_ERROR("Writing to ECC not supported");
586 return ERROR_FLASH_DST_OUT_OF_BANK;
587 }
588
589 if (offset % ROW_SIZE != 0) {
590 LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32,
591 offset);
592 return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
593 }
594
595 row_size = ROW_SIZE;
596 if (!psoc_bank->ecc_enabled) {
597 row_size += ROW_ECC_SIZE;
598 memset(ecc_bytes, bank->default_padded_value, ROW_ECC_SIZE);
599 }
600
601 retval = psoc5lp_spc_get_temp(target, 3, temp);
602 if (retval != ERROR_OK) {
603 LOG_ERROR("Unable to read Die temperature");
604 return retval;
605 }
606 LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8 ", magnitude 0x%02" PRIx8,
607 temp[0], temp[1]);
608
609 assert(target_get_working_area_avail(target) == target->working_area_size);
610 retval = target_alloc_working_area(target,
611 target_get_working_area_avail(target) / 2, &code_area);
612 if (retval != ERROR_OK) {
613 LOG_ERROR("Could not allocate working area for program SRAM");
614 return retval;
615 }
616 assert(code_area->address < 0x20000000);
617
618 retval = target_alloc_working_area(target,
619 SPC_OPCODE_LEN + 1 + row_size + 3 + SPC_OPCODE_LEN + 6,
620 &even_row_area);
621 if (retval != ERROR_OK) {
622 LOG_ERROR("Could not allocate working area for even row");
623 goto err_alloc_even;
624 }
625 assert(even_row_area->address >= 0x20000000);
626
627 retval = target_alloc_working_area(target, even_row_area->size,
628 &odd_row_area);
629 if (retval != ERROR_OK) {
630 LOG_ERROR("Could not allocate working area for odd row");
631 goto err_alloc_odd;
632 }
633 assert(odd_row_area->address >= 0x20000000);
634
635 for (array_id = offset / BLOCK_SIZE; byte_count > 0; array_id++) {
636 for (row = (offset / ROW_SIZE) % ROWS_PER_BLOCK;
637 row < ROWS_PER_BLOCK && byte_count > 0; row++) {
638 bool even_row = (row % 2 == 0);
639 struct working_area *data_area = even_row ? even_row_area : odd_row_area;
640 unsigned len = MIN(ROW_SIZE, byte_count);
641
642 LOG_DEBUG("Writing load command for array %u row %u at 0x%08" TARGET_PRIxADDR,
643 array_id, row, data_area->address);
644
645 psoc5lp_spc_write_opcode_buffer(target, buf, SPC_LOAD_ROW);
646 buf[SPC_OPCODE_LEN] = array_id;
647 retval = target_write_buffer(target, data_area->address, 4, buf);
648 if (retval != ERROR_OK)
649 goto err_write;
650
651 retval = target_write_buffer(target,
652 data_area->address + SPC_OPCODE_LEN + 1,
653 len, buffer);
654 if (retval != ERROR_OK)
655 goto err_write;
656 buffer += len;
657 byte_count -= len;
658 offset += len;
659
660 if (len < ROW_SIZE) {
661 uint8_t padding[ROW_SIZE];
662
663 memset(padding, bank->default_padded_value, ROW_SIZE);
664
665 LOG_DEBUG("Padding %d bytes", ROW_SIZE - len);
666 retval = target_write_buffer(target,
667 data_area->address + SPC_OPCODE_LEN + 1 + len,
668 ROW_SIZE - len, padding);
669 if (retval != ERROR_OK)
670 goto err_write;
671 }
672
673 if (!psoc_bank->ecc_enabled) {
674 retval = target_write_buffer(target,
675 data_area->address + SPC_OPCODE_LEN + 1 + ROW_SIZE,
676 sizeof(ecc_bytes), ecc_bytes);
677 if (retval != ERROR_OK)
678 goto err_write;
679 }
680
681 for (i = 0; i < 3; i++)
682 buf[i] = 0x00; /* 3 NOPs for short delay */
683 psoc5lp_spc_write_opcode_buffer(target, buf + 3, SPC_PRG_ROW);
684 buf[3 + SPC_OPCODE_LEN] = array_id;
685 buf[3 + SPC_OPCODE_LEN + 1] = row >> 8;
686 buf[3 + SPC_OPCODE_LEN + 2] = row & 0xff;
687 memcpy(buf + 3 + SPC_OPCODE_LEN + 3, temp, 2);
688 buf[3 + SPC_OPCODE_LEN + 5] = 0x00; /* padding */
689 retval = target_write_buffer(target,
690 data_area->address + SPC_OPCODE_LEN + 1 + row_size,
691 12, buf);
692 if (retval != ERROR_OK)
693 goto err_write;
694
695 retval = target_write_u32(target,
696 even_row ? PHUB_CH0_BASIC_STATUS : PHUB_CH1_BASIC_STATUS,
697 (even_row ? 0 : 1) << 8);
698 if (retval != ERROR_OK)
699 goto err_dma;
700
701 retval = target_write_u32(target,
702 even_row ? PHUB_CH0_BASIC_CFG : PHUB_CH1_BASIC_CFG,
703 PHUB_CHx_BASIC_CFG_WORK_SEP | PHUB_CHx_BASIC_CFG_EN);
704 if (retval != ERROR_OK)
705 goto err_dma;
706
707 retval = target_write_u32(target,
708 even_row ? PHUB_CFGMEM0_CFG0 : PHUB_CFGMEM1_CFG0,
709 PHUB_CFGMEMx_CFG0);
710 if (retval != ERROR_OK)
711 goto err_dma;
712
713 retval = target_write_u32(target,
714 even_row ? PHUB_CFGMEM0_CFG1 : PHUB_CFGMEM1_CFG1,
715 ((SPC_CPU_DATA >> 16) << 16) | (data_area->address >> 16));
716 if (retval != ERROR_OK)
717 goto err_dma;
718
719 retval = target_write_u32(target,
720 even_row ? PHUB_TDMEM0_ORIG_TD0 : PHUB_TDMEM1_ORIG_TD0,
721 PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR |
722 PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST |
723 ((SPC_OPCODE_LEN + 1 + row_size + 3 + SPC_OPCODE_LEN + 5) & 0xfff));
724 if (retval != ERROR_OK)
725 goto err_dma;
726
727 retval = target_write_u32(target,
728 even_row ? PHUB_TDMEM0_ORIG_TD1 : PHUB_TDMEM1_ORIG_TD1,
729 ((SPC_CPU_DATA & 0xffff) << 16) | (data_area->address & 0xffff));
730 if (retval != ERROR_OK)
731 goto err_dma;
732
733 retval = psoc5lp_spc_busy_wait_idle(target);
734 if (retval != ERROR_OK)
735 goto err_idle;
736
737 retval = target_write_u32(target,
738 even_row ? PHUB_CH0_ACTION : PHUB_CH1_ACTION,
739 PHUB_CHx_ACTION_CPU_REQ);
740 if (retval != ERROR_OK)
741 goto err_dma_action;
742 }
743 }
744
745 retval = psoc5lp_spc_busy_wait_idle(target);
746
747 err_dma_action:
748 err_idle:
749 err_dma:
750 err_write:
751 target_free_working_area(target, odd_row_area);
752 err_alloc_odd:
753 target_free_working_area(target, even_row_area);
754 err_alloc_even:
755 target_free_working_area(target, code_area);
756
757 return retval;
758 }
759
760 static int psoc5lp_protect_check(struct flash_bank *bank)
761 {
762 struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv;
763 uint8_t row_data[ROW_SIZE];
764 const unsigned protection_bytes_per_sector = ROWS_PER_SECTOR * 2 / 8;
765 unsigned i, j, k, num_sectors;
766 int retval;
767
768 if (bank->target->state != TARGET_HALTED) {
769 LOG_ERROR("Target not halted");
770 return ERROR_TARGET_NOT_HALTED;
771 }
772
773 for (i = 0; i < DIV_ROUND_UP(bank->size, BLOCK_SIZE); i++) {
774 retval = psoc5lp_spc_read_hidden_row(bank->target, i,
775 SPC_ROW_PROTECTION, row_data);
776 if (retval != ERROR_OK)
777 return retval;
778
779 /* Last flash array may have less rows, but in practice full sectors. */
780 if (i == bank->size / BLOCK_SIZE)
781 num_sectors = (bank->size % BLOCK_SIZE) / SECTOR_SIZE;
782 else
783 num_sectors = SECTORS_PER_BLOCK;
784
785 for (j = 0; j < num_sectors; j++) {
786 int sector_nr = i * SECTORS_PER_BLOCK + j;
787 struct flash_sector *sector = &bank->sectors[sector_nr];
788 struct flash_sector *ecc_sector;
789
790 if (psoc_bank->ecc_enabled)
791 ecc_sector = &bank->sectors[bank->num_sectors + sector_nr];
792 else
793 ecc_sector = &bank->sectors[bank->num_sectors / 2 + sector_nr];
794
795 sector->is_protected = ecc_sector->is_protected = 0;
796 for (k = protection_bytes_per_sector * j;
797 k < protection_bytes_per_sector * (j + 1); k++) {
798 assert(k < protection_bytes_per_sector * SECTORS_PER_BLOCK);
799 LOG_DEBUG("row[%u][%02u] = 0x%02" PRIx8, i, k, row_data[k]);
800 if (row_data[k] != 0x00) {
801 sector->is_protected = ecc_sector->is_protected = 1;
802 break;
803 }
804 }
805 }
806 }
807
808 return ERROR_OK;
809 }
810
811 static int psoc5lp_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
812 {
813 struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv;
814 char part_number[PART_NUMBER_LEN];
815 const char *ecc;
816
817 psoc5lp_get_part_number(psoc_bank->device, part_number);
818 ecc = psoc_bank->ecc_enabled ? "ECC enabled" : "ECC disabled";
819
820 snprintf(buf, buf_size, "%s %s", part_number, ecc);
821
822 return ERROR_OK;
823 }
824
825 static int psoc5lp_probe(struct flash_bank *bank)
826 {
827 struct target *target = bank->target;
828 struct psoc5lp_flash_bank *psoc_bank = bank->driver_priv;
829 uint32_t flash_addr = bank->base;
830 uint8_t nvl[4], temp[2];
831 int i, retval;
832
833 if (target->state != TARGET_HALTED) {
834 LOG_ERROR("Target not halted");
835 return ERROR_TARGET_NOT_HALTED;
836 }
837
838 if (!psoc_bank->device) {
839 retval = psoc5lp_find_device(target, &psoc_bank->device);
840 if (retval != ERROR_OK)
841 return retval;
842
843 bank->size = psoc_bank->device->flash_kb * 1024;
844 }
845
846 bank->num_sectors = DIV_ROUND_UP(bank->size, SECTOR_SIZE);
847
848 if (!psoc_bank->probed) {
849 retval = psoc5lp_spc_enable_clock(target);
850 if (retval != ERROR_OK)
851 return retval;
852
853 /* First values read are inaccurate, so do it once now. */
854 retval = psoc5lp_spc_get_temp(target, 3, temp);
855 if (retval != ERROR_OK) {
856 LOG_ERROR("Unable to read Die temperature");
857 return retval;
858 }
859
860 bank->sectors = calloc(bank->num_sectors * 2,
861 sizeof(struct flash_sector));
862 for (i = 0; i < bank->num_sectors; i++) {
863 bank->sectors[i].size = SECTOR_SIZE;
864 bank->sectors[i].offset = flash_addr - bank->base;
865 bank->sectors[i].is_erased = -1;
866 bank->sectors[i].is_protected = -1;
867
868 flash_addr += bank->sectors[i].size;
869 }
870 flash_addr = 0x48000000;
871 for (i = bank->num_sectors; i < bank->num_sectors * 2; i++) {
872 bank->sectors[i].size = ROWS_PER_SECTOR * ROW_ECC_SIZE;
873 bank->sectors[i].offset = flash_addr - bank->base;
874 bank->sectors[i].is_erased = -1;
875 bank->sectors[i].is_protected = -1;
876
877 flash_addr += bank->sectors[i].size;
878 }
879
880 bank->default_padded_value = bank->erased_value = 0x00;
881
882 psoc_bank->probed = true;
883 }
884
885 retval = psoc5lp_spc_read_byte(target, SPC_ARRAY_NVL_USER, 3, &nvl[3]);
886 if (retval != ERROR_OK)
887 return retval;
888 LOG_DEBUG("NVL[%d] = 0x%02" PRIx8, 3, nvl[3]);
889 psoc_bank->ecc_enabled = nvl[3] & NVL_3_ECCEN;
890
891 if (!psoc_bank->ecc_enabled)
892 bank->num_sectors *= 2;
893
894 return ERROR_OK;
895 }
896
897 static int psoc5lp_auto_probe(struct flash_bank *bank)
898 {
899 return psoc5lp_probe(bank);
900 }
901
902 COMMAND_HANDLER(psoc5lp_handle_mass_erase_command)
903 {
904 struct flash_bank *bank;
905 int retval;
906
907 if (CMD_ARGC < 1)
908 return ERROR_COMMAND_SYNTAX_ERROR;
909
910 retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
911 if (retval != ERROR_OK)
912 return retval;
913
914 retval = psoc5lp_spc_erase_all(bank->target);
915 if (retval == ERROR_OK)
916 command_print(CMD_CTX, "PSoC 5LP erase succeeded");
917 else
918 command_print(CMD_CTX, "PSoC 5LP erase failed");
919
920 return retval;
921 }
922
923 FLASH_BANK_COMMAND_HANDLER(psoc5lp_flash_bank_command)
924 {
925 struct psoc5lp_flash_bank *psoc_bank;
926
927 psoc_bank = malloc(sizeof(struct psoc5lp_flash_bank));
928 if (!psoc_bank)
929 return ERROR_FLASH_OPERATION_FAILED;
930
931 psoc_bank->probed = false;
932 psoc_bank->device = NULL;
933
934 bank->driver_priv = psoc_bank;
935
936 return ERROR_OK;
937 }
938
939 static const struct command_registration psoc5lp_exec_command_handlers[] = {
940 {
941 .name = "mass_erase",
942 .handler = psoc5lp_handle_mass_erase_command,
943 .mode = COMMAND_EXEC,
944 .usage = "bank_id",
945 .help = "Erase all flash data and ECC/configuration bytes, "
946 "all flash protection rows, "
947 "and all row latches in all flash arrays on the device.",
948 },
949 COMMAND_REGISTRATION_DONE
950 };
951
952 static const struct command_registration psoc5lp_command_handlers[] = {
953 {
954 .name = "psoc5lp",
955 .mode = COMMAND_ANY,
956 .help = "PSoC 5LP flash command group",
957 .usage = "",
958 .chain = psoc5lp_exec_command_handlers,
959 },
960 COMMAND_REGISTRATION_DONE
961 };
962
963 struct flash_driver psoc5lp_flash = {
964 .name = "psoc5lp",
965 .commands = psoc5lp_command_handlers,
966 .flash_bank_command = psoc5lp_flash_bank_command,
967 .info = psoc5lp_get_info_command,
968 .probe = psoc5lp_probe,
969 .auto_probe = psoc5lp_auto_probe,
970 .protect_check = psoc5lp_protect_check,
971 .read = default_flash_read,
972 .erase = psoc5lp_erase,
973 .erase_check = psoc5lp_erase_check,
974 .write = psoc5lp_write,
975 };

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)