2 * PSoC 5LP flash driver
4 * Copyright (c) 2016 Andreas Färber
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.
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.
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/>.
25 #include <helper/time_support.h>
26 #include <target/armv7m.h>
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
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
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
71 #define SPC_ROW_PROTECTION 0
73 #define SPC_OPCODE_LEN 3
75 #define SPC_SR_DATA_READY (1 << 0)
76 #define SPC_SR_IDLE (1 << 1)
78 #define PM_ACT_CFG0_EN_CLK_SPC (1 << 3)
80 #define PHUB_CHx_BASIC_CFG_EN (1 << 0)
81 #define PHUB_CHx_BASIC_CFG_WORK_SEP (1 << 5)
83 #define PHUB_CHx_ACTION_CPU_REQ (1 << 0)
85 #define PHUB_CFGMEMx_CFG0 (1 << 7)
87 #define PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST (0xff << 16)
88 #define PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR (1 << 24)
90 #define NVL_3_ECCEN (1 << 3)
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)
100 #define PART_NUMBER_LEN (17 + 1)
102 struct psoc5lp_device
{
111 * Device information collected from datasheets.
112 * Different temperature ranges (C/I/Q/A) may share IDs, not differing otherwise.
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 },
131 { .id
= 0x2E161069, .fam
= 8, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
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 },
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 },
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 },
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 },
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 },
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 },
189 static void psoc5lp_get_part_number(const struct psoc5lp_device
*dev
, char *str
)
191 strcpy(str
, "CY8Cabcdefg-LPxxx");
194 str
[5] = '0' + dev
->fam
;
196 switch (dev
->speed_mhz
) {
207 switch (dev
->flash_kb
) {
224 /* Package does not matter. */
225 strncpy(str
+ 8, "xx", 2);
227 /* Temperate range cannot uniquely be identified. */
231 static int psoc5lp_get_device_id(struct target
*target
, uint32_t *id
)
235 retval
= target_read_u32(target
, PANTHER_DEVICE_ID
, id
); /* dummy read */
236 if (retval
!= ERROR_OK
)
238 retval
= target_read_u32(target
, PANTHER_DEVICE_ID
, id
);
242 static int psoc5lp_find_device(struct target
*target
,
243 const struct psoc5lp_device
**device
)
251 retval
= psoc5lp_get_device_id(target
, &device_id
);
252 if (retval
!= ERROR_OK
)
254 LOG_DEBUG("PANTHER_DEVICE_ID = 0x%08" PRIX32
, device_id
);
256 for (i
= 0; i
< ARRAY_SIZE(psoc5lp_devices
); i
++) {
257 if (psoc5lp_devices
[i
].id
== device_id
) {
258 *device
= &psoc5lp_devices
[i
];
263 LOG_ERROR("Device 0x%08" PRIX32
" not supported", device_id
);
264 return ERROR_FLASH_OPER_UNSUPPORTED
;
267 static int psoc5lp_spc_enable_clock(struct target
*target
)
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");
278 if (pm_act_cfg0
& PM_ACT_CFG0_EN_CLK_SPC
)
279 return ERROR_OK
; /* clock already enabled */
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");
288 static int psoc5lp_spc_write_opcode(struct target
*target
, uint8_t opcode
)
292 retval
= target_write_u8(target
, SPC_CPU_DATA
, SPC_KEY1
);
293 if (retval
!= ERROR_OK
)
295 retval
= target_write_u8(target
, SPC_CPU_DATA
, SPC_KEY2
+ opcode
);
296 if (retval
!= ERROR_OK
)
298 retval
= target_write_u8(target
, SPC_CPU_DATA
, opcode
);
302 static void psoc5lp_spc_write_opcode_buffer(struct target
*target
,
303 uint8_t *buf
, uint8_t opcode
)
306 buf
[1] = SPC_KEY2
+ opcode
;
310 static int psoc5lp_spc_busy_wait_data(struct target
*target
)
316 retval
= target_read_u8(target
, SPC_SR
, &sr
); /* dummy read */
317 if (retval
!= ERROR_OK
)
320 endtime
= timeval_ms() + 1000; /* 1 second timeout */
323 retval
= target_read_u8(target
, SPC_SR
, &sr
);
324 if (retval
!= ERROR_OK
)
326 if (sr
== SPC_SR_DATA_READY
)
328 } while (timeval_ms() < endtime
);
330 return ERROR_FLASH_OPERATION_FAILED
;
333 static int psoc5lp_spc_busy_wait_idle(struct target
*target
)
339 retval
= target_read_u8(target
, SPC_SR
, &sr
); /* dummy read */
340 if (retval
!= ERROR_OK
)
343 endtime
= timeval_ms() + 1000; /* 1 second timeout */
346 retval
= target_read_u8(target
, SPC_SR
, &sr
);
347 if (retval
!= ERROR_OK
)
349 if (sr
== SPC_SR_IDLE
)
351 } while (timeval_ms() < endtime
);
353 return ERROR_FLASH_OPERATION_FAILED
;
356 static int psoc5lp_spc_read_byte(struct target
*target
,
357 uint8_t array_id
, uint8_t offset
, uint8_t *data
)
361 retval
= psoc5lp_spc_write_opcode(target
, SPC_READ_BYTE
);
362 if (retval
!= ERROR_OK
)
364 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
365 if (retval
!= ERROR_OK
)
367 retval
= target_write_u8(target
, SPC_CPU_DATA
, offset
);
368 if (retval
!= ERROR_OK
)
371 retval
= psoc5lp_spc_busy_wait_data(target
);
372 if (retval
!= ERROR_OK
)
375 retval
= target_read_u8(target
, SPC_CPU_DATA
, data
);
376 if (retval
!= ERROR_OK
)
379 retval
= psoc5lp_spc_busy_wait_idle(target
);
380 if (retval
!= ERROR_OK
)
386 static int psoc5lp_spc_erase_sector(struct target
*target
,
387 uint8_t array_id
, uint8_t row_id
)
391 retval
= psoc5lp_spc_write_opcode(target
, SPC_ERASE_SECTOR
);
392 if (retval
!= ERROR_OK
)
394 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
395 if (retval
!= ERROR_OK
)
397 retval
= target_write_u8(target
, SPC_CPU_DATA
, row_id
);
398 if (retval
!= ERROR_OK
)
401 retval
= psoc5lp_spc_busy_wait_idle(target
);
402 if (retval
!= ERROR_OK
)
408 static int psoc5lp_spc_erase_all(struct target
*target
)
412 retval
= psoc5lp_spc_write_opcode(target
, SPC_ERASE_ALL
);
413 if (retval
!= ERROR_OK
)
416 retval
= psoc5lp_spc_busy_wait_idle(target
);
417 if (retval
!= ERROR_OK
)
423 static int psoc5lp_spc_read_hidden_row(struct target
*target
,
424 uint8_t array_id
, uint8_t row_id
, uint8_t *data
)
428 retval
= psoc5lp_spc_write_opcode(target
, SPC_READ_HIDDEN_ROW
);
429 if (retval
!= ERROR_OK
)
431 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
432 if (retval
!= ERROR_OK
)
434 retval
= target_write_u8(target
, SPC_CPU_DATA
, row_id
);
435 if (retval
!= ERROR_OK
)
438 retval
= psoc5lp_spc_busy_wait_data(target
);
439 if (retval
!= ERROR_OK
)
442 for (i
= 0; i
< ROW_SIZE
; i
++) {
443 retval
= target_read_u8(target
, SPC_CPU_DATA
, &data
[i
]);
444 if (retval
!= ERROR_OK
)
448 retval
= psoc5lp_spc_busy_wait_idle(target
);
449 if (retval
!= ERROR_OK
)
455 static int psoc5lp_spc_get_temp(struct target
*target
, uint8_t samples
,
460 retval
= psoc5lp_spc_write_opcode(target
, SPC_GET_TEMP
);
461 if (retval
!= ERROR_OK
)
463 retval
= target_write_u8(target
, SPC_CPU_DATA
, samples
);
464 if (retval
!= ERROR_OK
)
467 retval
= psoc5lp_spc_busy_wait_data(target
);
468 if (retval
!= ERROR_OK
)
471 retval
= target_read_u8(target
, SPC_CPU_DATA
, &data
[0]);
472 if (retval
!= ERROR_OK
)
474 retval
= target_read_u8(target
, SPC_CPU_DATA
, &data
[1]);
475 if (retval
!= ERROR_OK
)
478 retval
= psoc5lp_spc_busy_wait_idle(target
);
479 if (retval
!= ERROR_OK
)
489 struct psoc5lp_flash_bank
{
491 const struct psoc5lp_device
*device
;
495 static int psoc5lp_erase(struct flash_bank
*bank
, int first
, int last
)
497 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
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;
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;
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
)
525 /* Derived from core.c:default_flash_blank_check() */
526 static int psoc5lp_erase_check(struct flash_bank
*bank
)
528 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
529 struct target
*target
= bank
->target
;
531 int i
, num_sectors
, retval
;
533 if (target
->state
!= TARGET_HALTED
) {
534 LOG_ERROR("Target not halted");
535 return ERROR_TARGET_NOT_HALTED
;
538 num_sectors
= bank
->num_sectors
;
539 if (!psoc_bank
->ecc_enabled
)
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
;
546 retval
= armv7m_blank_check_memory(target
, address
, size
,
547 &blank
, bank
->erased_value
);
548 if (retval
!= ERROR_OK
)
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
;
555 retval
= armv7m_blank_check_memory(target
, address
, size
,
556 &blank
, bank
->erased_value
);
557 if (retval
!= ERROR_OK
)
562 bank
->sectors
[i
].is_erased
= 1;
563 bank
->sectors
[num_sectors
+ i
].is_erased
= 1;
565 bank
->sectors
[i
].is_erased
= 0;
566 bank
->sectors
[num_sectors
+ i
].is_erased
= 0;
573 static int psoc5lp_write(struct flash_bank
*bank
, const uint8_t *buffer
,
574 uint32_t offset
, uint32_t byte_count
)
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
;
580 uint8_t temp
[2], buf
[12], ecc_bytes
[ROW_ECC_SIZE
];
581 unsigned array_id
, row
;
584 if (offset
+ byte_count
> bank
->size
) {
585 LOG_ERROR("Writing to ECC not supported");
586 return ERROR_FLASH_DST_OUT_OF_BANK
;
589 if (offset
% ROW_SIZE
!= 0) {
590 LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32
,
592 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
596 if (!psoc_bank
->ecc_enabled
) {
597 row_size
+= ROW_ECC_SIZE
;
598 memset(ecc_bytes
, bank
->default_padded_value
, ROW_ECC_SIZE
);
601 retval
= psoc5lp_spc_get_temp(target
, 3, temp
);
602 if (retval
!= ERROR_OK
) {
603 LOG_ERROR("Unable to read Die temperature");
606 LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8
", magnitude 0x%02" PRIx8
,
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");
616 assert(code_area
->address
< 0x20000000);
618 retval
= target_alloc_working_area(target
,
619 SPC_OPCODE_LEN
+ 1 + row_size
+ 3 + SPC_OPCODE_LEN
+ 6,
621 if (retval
!= ERROR_OK
) {
622 LOG_ERROR("Could not allocate working area for even row");
625 assert(even_row_area
->address
>= 0x20000000);
627 retval
= target_alloc_working_area(target
, even_row_area
->size
,
629 if (retval
!= ERROR_OK
) {
630 LOG_ERROR("Could not allocate working area for odd row");
633 assert(odd_row_area
->address
>= 0x20000000);
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
);
642 LOG_DEBUG("Writing load command for array %u row %u at 0x%08" TARGET_PRIxADDR
,
643 array_id
, row
, data_area
->address
);
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
)
651 retval
= target_write_buffer(target
,
652 data_area
->address
+ SPC_OPCODE_LEN
+ 1,
654 if (retval
!= ERROR_OK
)
660 if (len
< ROW_SIZE
) {
661 uint8_t padding
[ROW_SIZE
];
663 memset(padding
, bank
->default_padded_value
, ROW_SIZE
);
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
)
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
)
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
,
692 if (retval
!= ERROR_OK
)
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
)
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
)
707 retval
= target_write_u32(target
,
708 even_row
? PHUB_CFGMEM0_CFG0
: PHUB_CFGMEM1_CFG0
,
710 if (retval
!= ERROR_OK
)
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
)
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
)
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
)
733 retval
= psoc5lp_spc_busy_wait_idle(target
);
734 if (retval
!= ERROR_OK
)
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
)
745 retval
= psoc5lp_spc_busy_wait_idle(target
);
751 target_free_working_area(target
, odd_row_area
);
753 target_free_working_area(target
, even_row_area
);
755 target_free_working_area(target
, code_area
);
760 static int psoc5lp_protect_check(struct flash_bank
*bank
)
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
;
768 if (bank
->target
->state
!= TARGET_HALTED
) {
769 LOG_ERROR("Target not halted");
770 return ERROR_TARGET_NOT_HALTED
;
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
)
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
;
783 num_sectors
= SECTORS_PER_BLOCK
;
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
;
790 if (psoc_bank
->ecc_enabled
)
791 ecc_sector
= &bank
->sectors
[bank
->num_sectors
+ sector_nr
];
793 ecc_sector
= &bank
->sectors
[bank
->num_sectors
/ 2 + sector_nr
];
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;
811 static int psoc5lp_get_info_command(struct flash_bank
*bank
, char *buf
, int buf_size
)
813 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
814 char part_number
[PART_NUMBER_LEN
];
817 psoc5lp_get_part_number(psoc_bank
->device
, part_number
);
818 ecc
= psoc_bank
->ecc_enabled
? "ECC enabled" : "ECC disabled";
820 snprintf(buf
, buf_size
, "%s %s", part_number
, ecc
);
825 static int psoc5lp_probe(struct flash_bank
*bank
)
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];
833 if (target
->state
!= TARGET_HALTED
) {
834 LOG_ERROR("Target not halted");
835 return ERROR_TARGET_NOT_HALTED
;
838 if (!psoc_bank
->device
) {
839 retval
= psoc5lp_find_device(target
, &psoc_bank
->device
);
840 if (retval
!= ERROR_OK
)
843 bank
->size
= psoc_bank
->device
->flash_kb
* 1024;
846 bank
->num_sectors
= DIV_ROUND_UP(bank
->size
, SECTOR_SIZE
);
848 if (!psoc_bank
->probed
) {
849 retval
= psoc5lp_spc_enable_clock(target
);
850 if (retval
!= ERROR_OK
)
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");
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;
868 flash_addr
+= bank
->sectors
[i
].size
;
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;
877 flash_addr
+= bank
->sectors
[i
].size
;
880 bank
->default_padded_value
= bank
->erased_value
= 0x00;
882 psoc_bank
->probed
= true;
885 retval
= psoc5lp_spc_read_byte(target
, SPC_ARRAY_NVL_USER
, 3, &nvl
[3]);
886 if (retval
!= ERROR_OK
)
888 LOG_DEBUG("NVL[%d] = 0x%02" PRIx8
, 3, nvl
[3]);
889 psoc_bank
->ecc_enabled
= nvl
[3] & NVL_3_ECCEN
;
891 if (!psoc_bank
->ecc_enabled
)
892 bank
->num_sectors
*= 2;
897 static int psoc5lp_auto_probe(struct flash_bank
*bank
)
899 return psoc5lp_probe(bank
);
902 COMMAND_HANDLER(psoc5lp_handle_mass_erase_command
)
904 struct flash_bank
*bank
;
908 return ERROR_COMMAND_SYNTAX_ERROR
;
910 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
911 if (retval
!= ERROR_OK
)
914 retval
= psoc5lp_spc_erase_all(bank
->target
);
915 if (retval
== ERROR_OK
)
916 command_print(CMD_CTX
, "PSoC 5LP erase succeeded");
918 command_print(CMD_CTX
, "PSoC 5LP erase failed");
923 FLASH_BANK_COMMAND_HANDLER(psoc5lp_flash_bank_command
)
925 struct psoc5lp_flash_bank
*psoc_bank
;
927 psoc_bank
= malloc(sizeof(struct psoc5lp_flash_bank
));
929 return ERROR_FLASH_OPERATION_FAILED
;
931 psoc_bank
->probed
= false;
932 psoc_bank
->device
= NULL
;
934 bank
->driver_priv
= psoc_bank
;
939 static const struct command_registration psoc5lp_exec_command_handlers
[] = {
941 .name
= "mass_erase",
942 .handler
= psoc5lp_handle_mass_erase_command
,
943 .mode
= COMMAND_EXEC
,
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.",
949 COMMAND_REGISTRATION_DONE
952 static const struct command_registration psoc5lp_command_handlers
[] = {
956 .help
= "PSoC 5LP flash command group",
958 .chain
= psoc5lp_exec_command_handlers
,
960 COMMAND_REGISTRATION_DONE
963 struct flash_driver psoc5lp_flash
= {
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
,
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)