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 PM_ACT_CFG12 0x400043AC
30 #define SPC_CPU_DATA 0x40004720
31 #define SPC_SR 0x40004722
32 #define PHUB_CH0_BASIC_CFG 0x40007010
33 #define PHUB_CH0_ACTION 0x40007014
34 #define PHUB_CH0_BASIC_STATUS 0x40007018
35 #define PHUB_CH1_BASIC_CFG 0x40007020
36 #define PHUB_CH1_ACTION 0x40007024
37 #define PHUB_CH1_BASIC_STATUS 0x40007028
38 #define PHUB_CFGMEM0_CFG0 0x40007600
39 #define PHUB_CFGMEM0_CFG1 0x40007604
40 #define PHUB_CFGMEM1_CFG0 0x40007608
41 #define PHUB_CFGMEM1_CFG1 0x4000760C
42 #define PHUB_TDMEM0_ORIG_TD0 0x40007800
43 #define PHUB_TDMEM0_ORIG_TD1 0x40007804
44 #define PHUB_TDMEM1_ORIG_TD0 0x40007808
45 #define PHUB_TDMEM1_ORIG_TD1 0x4000780C
46 #define PANTHER_DEVICE_ID 0x4008001C
48 #define PM_ACT_CFG12_EN_EE (1 << 4)
53 #define SPC_LOAD_BYTE 0x00
54 #define SPC_LOAD_MULTI_BYTE 0x01
55 #define SPC_LOAD_ROW 0x02
56 #define SPC_READ_BYTE 0x03
57 #define SPC_READ_MULTI_BYTE 0x04
58 #define SPC_WRITE_ROW 0x05
59 #define SPC_WRITE_USER_NVL 0x06
60 #define SPC_PRG_ROW 0x07
61 #define SPC_ERASE_SECTOR 0x08
62 #define SPC_ERASE_ALL 0x09
63 #define SPC_READ_HIDDEN_ROW 0x0A
64 #define SPC_PROGRAM_PROTECT_ROW 0x0B
65 #define SPC_GET_CHECKSUM 0x0C
66 #define SPC_GET_TEMP 0x0E
67 #define SPC_READ_VOLATILE_BYTE 0x10
69 #define SPC_ARRAY_ALL 0x3F
70 #define SPC_ARRAY_EEPROM 0x40
71 #define SPC_ARRAY_NVL_USER 0x80
72 #define SPC_ARRAY_NVL_WO 0xF8
74 #define SPC_ROW_PROTECTION 0
76 #define SPC_OPCODE_LEN 3
78 #define SPC_SR_DATA_READY (1 << 0)
79 #define SPC_SR_IDLE (1 << 1)
81 #define PM_ACT_CFG0_EN_CLK_SPC (1 << 3)
83 #define PHUB_CHx_BASIC_CFG_EN (1 << 0)
84 #define PHUB_CHx_BASIC_CFG_WORK_SEP (1 << 5)
86 #define PHUB_CHx_ACTION_CPU_REQ (1 << 0)
88 #define PHUB_CFGMEMx_CFG0 (1 << 7)
90 #define PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST (0xff << 16)
91 #define PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR (1 << 24)
93 #define NVL_3_ECCEN (1 << 3)
96 #define ROW_ECC_SIZE 32
97 #define ROWS_PER_SECTOR 64
98 #define SECTOR_SIZE (ROWS_PER_SECTOR * ROW_SIZE)
99 #define ROWS_PER_BLOCK 256
100 #define BLOCK_SIZE (ROWS_PER_BLOCK * ROW_SIZE)
101 #define SECTORS_PER_BLOCK (BLOCK_SIZE / SECTOR_SIZE)
102 #define EEPROM_ROW_SIZE 16
103 #define EEPROM_SECTOR_SIZE (ROWS_PER_SECTOR * EEPROM_ROW_SIZE)
104 #define EEPROM_BLOCK_SIZE (ROWS_PER_BLOCK * EEPROM_ROW_SIZE)
106 #define PART_NUMBER_LEN (17 + 1)
108 struct psoc5lp_device
{
117 * Device information collected from datasheets.
118 * Different temperature ranges (C/I/Q/A) may share IDs, not differing otherwise.
120 static const struct psoc5lp_device psoc5lp_devices
[] = {
121 /* CY8C58LP Family Datasheet */
122 { .id
= 0x2E11F069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
123 { .id
= 0x2E120069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
124 { .id
= 0x2E123069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
125 { .id
= 0x2E124069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
126 { .id
= 0x2E126069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
127 { .id
= 0x2E127069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
128 { .id
= 0x2E117069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
129 { .id
= 0x2E118069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
130 { .id
= 0x2E119069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
131 { .id
= 0x2E11C069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
132 { .id
= 0x2E114069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
133 { .id
= 0x2E115069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
134 { .id
= 0x2E116069, .fam
= 8, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
135 { .id
= 0x2E160069, .fam
= 8, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
137 { .id
= 0x2E161069, .fam
= 8, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
139 { .id
= 0x2E1D2069, .fam
= 8, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
140 { .id
= 0x2E1D6069, .fam
= 8, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
142 /* CY8C56LP Family Datasheet */
143 { .id
= 0x2E10A069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
144 { .id
= 0x2E10D069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
145 { .id
= 0x2E10E069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
146 { .id
= 0x2E106069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
147 { .id
= 0x2E108069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
148 { .id
= 0x2E109069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
149 { .id
= 0x2E101069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
150 { .id
= 0x2E104069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
152 { .id
= 0x2E105069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
153 { .id
= 0x2E128069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
155 { .id
= 0x2E122069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
156 { .id
= 0x2E129069, .fam
= 6, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
157 { .id
= 0x2E163069, .fam
= 6, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
158 { .id
= 0x2E156069, .fam
= 6, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
159 { .id
= 0x2E1D3069, .fam
= 6, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
161 /* CY8C54LP Family Datasheet */
162 { .id
= 0x2E11A069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
163 { .id
= 0x2E16A069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
164 { .id
= 0x2E12A069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
165 { .id
= 0x2E103069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
166 { .id
= 0x2E16C069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
167 { .id
= 0x2E102069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
168 { .id
= 0x2E148069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
169 { .id
= 0x2E155069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
170 { .id
= 0x2E16B069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
171 { .id
= 0x2E12B069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 32, .eeprom_kb
= 2 },
172 { .id
= 0x2E168069, .fam
= 4, .speed_mhz
= 67, .flash_kb
= 32, .eeprom_kb
= 2 },
173 { .id
= 0x2E178069, .fam
= 4, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
174 { .id
= 0x2E15D069, .fam
= 4, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
175 { .id
= 0x2E1D4069, .fam
= 4, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
177 /* CY8C52LP Family Datasheet */
178 { .id
= 0x2E11E069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
179 { .id
= 0x2E12F069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 256, .eeprom_kb
= 2 },
180 { .id
= 0x2E133069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
181 { .id
= 0x2E159069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 128, .eeprom_kb
= 2 },
182 { .id
= 0x2E11D069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
183 { .id
= 0x2E121069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
184 { .id
= 0x2E184069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
185 { .id
= 0x2E196069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 64, .eeprom_kb
= 2 },
186 { .id
= 0x2E132069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 32, .eeprom_kb
= 2 },
187 { .id
= 0x2E138069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 32, .eeprom_kb
= 2 },
188 { .id
= 0x2E13A069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 32, .eeprom_kb
= 2 },
189 { .id
= 0x2E152069, .fam
= 2, .speed_mhz
= 67, .flash_kb
= 32, .eeprom_kb
= 2 },
190 { .id
= 0x2E15F069, .fam
= 2, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
191 { .id
= 0x2E15A069, .fam
= 2, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
192 { .id
= 0x2E1D5069, .fam
= 2, .speed_mhz
= 80, .flash_kb
= 256, .eeprom_kb
= 2 },
195 static void psoc5lp_get_part_number(const struct psoc5lp_device
*dev
, char *str
)
197 strcpy(str
, "CY8Cabcdefg-LPxxx");
200 str
[5] = '0' + dev
->fam
;
202 switch (dev
->speed_mhz
) {
213 switch (dev
->flash_kb
) {
230 /* Package does not matter. */
231 strncpy(str
+ 8, "xx", 2);
233 /* Temperate range cannot uniquely be identified. */
237 static int psoc5lp_get_device_id(struct target
*target
, uint32_t *id
)
241 retval
= target_read_u32(target
, PANTHER_DEVICE_ID
, id
); /* dummy read */
242 if (retval
!= ERROR_OK
)
244 retval
= target_read_u32(target
, PANTHER_DEVICE_ID
, id
);
248 static int psoc5lp_find_device(struct target
*target
,
249 const struct psoc5lp_device
**device
)
257 retval
= psoc5lp_get_device_id(target
, &device_id
);
258 if (retval
!= ERROR_OK
)
260 LOG_DEBUG("PANTHER_DEVICE_ID = 0x%08" PRIX32
, device_id
);
262 for (i
= 0; i
< ARRAY_SIZE(psoc5lp_devices
); i
++) {
263 if (psoc5lp_devices
[i
].id
== device_id
) {
264 *device
= &psoc5lp_devices
[i
];
269 LOG_ERROR("Device 0x%08" PRIX32
" not supported", device_id
);
270 return ERROR_FLASH_OPER_UNSUPPORTED
;
273 static int psoc5lp_spc_enable_clock(struct target
*target
)
278 retval
= target_read_u8(target
, PM_ACT_CFG0
, &pm_act_cfg0
);
279 if (retval
!= ERROR_OK
) {
280 LOG_ERROR("Cannot read PM_ACT_CFG0");
284 if (pm_act_cfg0
& PM_ACT_CFG0_EN_CLK_SPC
)
285 return ERROR_OK
; /* clock already enabled */
287 retval
= target_write_u8(target
, PM_ACT_CFG0
, pm_act_cfg0
| PM_ACT_CFG0_EN_CLK_SPC
);
288 if (retval
!= ERROR_OK
)
289 LOG_ERROR("Cannot enable SPC clock");
294 static int psoc5lp_spc_write_opcode(struct target
*target
, uint8_t opcode
)
298 retval
= target_write_u8(target
, SPC_CPU_DATA
, SPC_KEY1
);
299 if (retval
!= ERROR_OK
)
301 retval
= target_write_u8(target
, SPC_CPU_DATA
, SPC_KEY2
+ opcode
);
302 if (retval
!= ERROR_OK
)
304 retval
= target_write_u8(target
, SPC_CPU_DATA
, opcode
);
308 static void psoc5lp_spc_write_opcode_buffer(struct target
*target
,
309 uint8_t *buf
, uint8_t opcode
)
312 buf
[1] = SPC_KEY2
+ opcode
;
316 static int psoc5lp_spc_busy_wait_data(struct target
*target
)
322 retval
= target_read_u8(target
, SPC_SR
, &sr
); /* dummy read */
323 if (retval
!= ERROR_OK
)
326 endtime
= timeval_ms() + 1000; /* 1 second timeout */
329 retval
= target_read_u8(target
, SPC_SR
, &sr
);
330 if (retval
!= ERROR_OK
)
332 if (sr
== SPC_SR_DATA_READY
)
334 } while (timeval_ms() < endtime
);
336 return ERROR_FLASH_OPERATION_FAILED
;
339 static int psoc5lp_spc_busy_wait_idle(struct target
*target
)
345 retval
= target_read_u8(target
, SPC_SR
, &sr
); /* dummy read */
346 if (retval
!= ERROR_OK
)
349 endtime
= timeval_ms() + 1000; /* 1 second timeout */
352 retval
= target_read_u8(target
, SPC_SR
, &sr
);
353 if (retval
!= ERROR_OK
)
355 if (sr
== SPC_SR_IDLE
)
357 } while (timeval_ms() < endtime
);
359 return ERROR_FLASH_OPERATION_FAILED
;
362 static int psoc5lp_spc_load_row(struct target
*target
,
363 uint8_t array_id
, const uint8_t *data
, unsigned row_size
)
368 retval
= psoc5lp_spc_write_opcode(target
, SPC_LOAD_ROW
);
369 if (retval
!= ERROR_OK
)
371 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
372 if (retval
!= ERROR_OK
)
375 for (i
= 0; i
< row_size
; i
++) {
376 retval
= target_write_u8(target
, SPC_CPU_DATA
, data
[i
]);
377 if (retval
!= ERROR_OK
)
381 retval
= psoc5lp_spc_busy_wait_idle(target
);
382 if (retval
!= ERROR_OK
)
388 static int psoc5lp_spc_read_byte(struct target
*target
,
389 uint8_t array_id
, uint8_t offset
, uint8_t *data
)
393 retval
= psoc5lp_spc_write_opcode(target
, SPC_READ_BYTE
);
394 if (retval
!= ERROR_OK
)
396 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
397 if (retval
!= ERROR_OK
)
399 retval
= target_write_u8(target
, SPC_CPU_DATA
, offset
);
400 if (retval
!= ERROR_OK
)
403 retval
= psoc5lp_spc_busy_wait_data(target
);
404 if (retval
!= ERROR_OK
)
407 retval
= target_read_u8(target
, SPC_CPU_DATA
, data
);
408 if (retval
!= ERROR_OK
)
411 retval
= psoc5lp_spc_busy_wait_idle(target
);
412 if (retval
!= ERROR_OK
)
418 static int psoc5lp_spc_write_row(struct target
*target
,
419 uint8_t array_id
, uint16_t row_id
, const uint8_t *temp
)
423 retval
= psoc5lp_spc_write_opcode(target
, SPC_WRITE_ROW
);
424 if (retval
!= ERROR_OK
)
426 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
427 if (retval
!= ERROR_OK
)
429 retval
= target_write_u8(target
, SPC_CPU_DATA
, row_id
>> 8);
430 if (retval
!= ERROR_OK
)
432 retval
= target_write_u8(target
, SPC_CPU_DATA
, row_id
& 0xff);
433 if (retval
!= ERROR_OK
)
435 retval
= target_write_u8(target
, SPC_CPU_DATA
, temp
[0]);
436 if (retval
!= ERROR_OK
)
438 retval
= target_write_u8(target
, SPC_CPU_DATA
, temp
[1]);
439 if (retval
!= ERROR_OK
)
442 retval
= psoc5lp_spc_busy_wait_idle(target
);
443 if (retval
!= ERROR_OK
)
449 static int psoc5lp_spc_erase_sector(struct target
*target
,
450 uint8_t array_id
, uint8_t row_id
)
454 retval
= psoc5lp_spc_write_opcode(target
, SPC_ERASE_SECTOR
);
455 if (retval
!= ERROR_OK
)
457 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
458 if (retval
!= ERROR_OK
)
460 retval
= target_write_u8(target
, SPC_CPU_DATA
, row_id
);
461 if (retval
!= ERROR_OK
)
464 retval
= psoc5lp_spc_busy_wait_idle(target
);
465 if (retval
!= ERROR_OK
)
471 static int psoc5lp_spc_erase_all(struct target
*target
)
475 retval
= psoc5lp_spc_write_opcode(target
, SPC_ERASE_ALL
);
476 if (retval
!= ERROR_OK
)
479 retval
= psoc5lp_spc_busy_wait_idle(target
);
480 if (retval
!= ERROR_OK
)
486 static int psoc5lp_spc_read_hidden_row(struct target
*target
,
487 uint8_t array_id
, uint8_t row_id
, uint8_t *data
)
491 retval
= psoc5lp_spc_write_opcode(target
, SPC_READ_HIDDEN_ROW
);
492 if (retval
!= ERROR_OK
)
494 retval
= target_write_u8(target
, SPC_CPU_DATA
, array_id
);
495 if (retval
!= ERROR_OK
)
497 retval
= target_write_u8(target
, SPC_CPU_DATA
, row_id
);
498 if (retval
!= ERROR_OK
)
501 retval
= psoc5lp_spc_busy_wait_data(target
);
502 if (retval
!= ERROR_OK
)
505 for (i
= 0; i
< ROW_SIZE
; i
++) {
506 retval
= target_read_u8(target
, SPC_CPU_DATA
, &data
[i
]);
507 if (retval
!= ERROR_OK
)
511 retval
= psoc5lp_spc_busy_wait_idle(target
);
512 if (retval
!= ERROR_OK
)
518 static int psoc5lp_spc_get_temp(struct target
*target
, uint8_t samples
,
523 retval
= psoc5lp_spc_write_opcode(target
, SPC_GET_TEMP
);
524 if (retval
!= ERROR_OK
)
526 retval
= target_write_u8(target
, SPC_CPU_DATA
, samples
);
527 if (retval
!= ERROR_OK
)
530 retval
= psoc5lp_spc_busy_wait_data(target
);
531 if (retval
!= ERROR_OK
)
534 retval
= target_read_u8(target
, SPC_CPU_DATA
, &data
[0]);
535 if (retval
!= ERROR_OK
)
537 retval
= target_read_u8(target
, SPC_CPU_DATA
, &data
[1]);
538 if (retval
!= ERROR_OK
)
541 retval
= psoc5lp_spc_busy_wait_idle(target
);
542 if (retval
!= ERROR_OK
)
552 struct psoc5lp_eeprom_flash_bank
{
554 const struct psoc5lp_device
*device
;
557 static int psoc5lp_eeprom_erase(struct flash_bank
*bank
, int first
, int last
)
561 for (i
= first
; i
<= last
; i
++) {
562 retval
= psoc5lp_spc_erase_sector(bank
->target
,
563 SPC_ARRAY_EEPROM
, i
);
564 if (retval
!= ERROR_OK
)
571 static int psoc5lp_eeprom_write(struct flash_bank
*bank
,
572 const uint8_t *buffer
, uint32_t offset
, uint32_t byte_count
)
574 struct target
*target
= bank
->target
;
579 if (offset
% EEPROM_ROW_SIZE
!= 0) {
580 LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32
,
582 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
585 retval
= psoc5lp_spc_get_temp(target
, 3, temp
);
586 if (retval
!= ERROR_OK
) {
587 LOG_ERROR("Unable to read Die temperature");
590 LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8
", magnitude 0x%02" PRIx8
,
593 for (row
= offset
/ EEPROM_ROW_SIZE
; byte_count
>= EEPROM_ROW_SIZE
; row
++) {
594 retval
= psoc5lp_spc_load_row(target
, SPC_ARRAY_EEPROM
,
595 buffer
, EEPROM_ROW_SIZE
);
596 if (retval
!= ERROR_OK
)
599 retval
= psoc5lp_spc_write_row(target
, SPC_ARRAY_EEPROM
,
601 if (retval
!= ERROR_OK
)
604 buffer
+= EEPROM_ROW_SIZE
;
605 byte_count
-= EEPROM_ROW_SIZE
;
606 offset
+= EEPROM_ROW_SIZE
;
608 if (byte_count
> 0) {
609 uint8_t buf
[EEPROM_ROW_SIZE
];
611 memcpy(buf
, buffer
, byte_count
);
612 memset(buf
+ byte_count
, bank
->default_padded_value
,
613 EEPROM_ROW_SIZE
- byte_count
);
615 LOG_DEBUG("Padding %d bytes", EEPROM_ROW_SIZE
- byte_count
);
616 retval
= psoc5lp_spc_load_row(target
, SPC_ARRAY_EEPROM
,
617 buf
, EEPROM_ROW_SIZE
);
618 if (retval
!= ERROR_OK
)
621 retval
= psoc5lp_spc_write_row(target
, SPC_ARRAY_EEPROM
,
623 if (retval
!= ERROR_OK
)
630 static int psoc5lp_eeprom_protect_check(struct flash_bank
*bank
)
634 for (i
= 0; i
< bank
->num_sectors
; i
++)
635 bank
->sectors
[i
].is_protected
= -1;
640 static int psoc5lp_eeprom_get_info_command(struct flash_bank
*bank
, char *buf
, int buf_size
)
642 struct psoc5lp_eeprom_flash_bank
*psoc_eeprom_bank
= bank
->driver_priv
;
643 char part_number
[PART_NUMBER_LEN
];
645 psoc5lp_get_part_number(psoc_eeprom_bank
->device
, part_number
);
647 snprintf(buf
, buf_size
, "%s", part_number
);
652 static int psoc5lp_eeprom_probe(struct flash_bank
*bank
)
654 struct psoc5lp_eeprom_flash_bank
*psoc_eeprom_bank
= bank
->driver_priv
;
655 uint32_t flash_addr
= bank
->base
;
659 if (psoc_eeprom_bank
->probed
)
662 if (bank
->target
->state
!= TARGET_HALTED
) {
663 LOG_ERROR("Target not halted");
664 return ERROR_TARGET_NOT_HALTED
;
667 retval
= psoc5lp_find_device(bank
->target
, &psoc_eeprom_bank
->device
);
668 if (retval
!= ERROR_OK
)
671 retval
= target_read_u32(bank
->target
, PM_ACT_CFG12
, &val
);
672 if (retval
!= ERROR_OK
)
674 if (!(val
& PM_ACT_CFG12_EN_EE
)) {
675 val
|= PM_ACT_CFG12_EN_EE
;
676 retval
= target_write_u32(bank
->target
, PM_ACT_CFG12
, val
);
677 if (retval
!= ERROR_OK
)
681 bank
->size
= psoc_eeprom_bank
->device
->eeprom_kb
* 1024;
682 bank
->num_sectors
= DIV_ROUND_UP(bank
->size
, EEPROM_SECTOR_SIZE
);
683 bank
->sectors
= calloc(bank
->num_sectors
,
684 sizeof(struct flash_sector
));
685 for (i
= 0; i
< bank
->num_sectors
; i
++) {
686 bank
->sectors
[i
].size
= EEPROM_SECTOR_SIZE
;
687 bank
->sectors
[i
].offset
= flash_addr
- bank
->base
;
688 bank
->sectors
[i
].is_erased
= -1;
689 bank
->sectors
[i
].is_protected
= -1;
691 flash_addr
+= bank
->sectors
[i
].size
;
694 bank
->default_padded_value
= bank
->erased_value
= 0x00;
696 psoc_eeprom_bank
->probed
= true;
701 static int psoc5lp_eeprom_auto_probe(struct flash_bank
*bank
)
703 struct psoc5lp_eeprom_flash_bank
*psoc_eeprom_bank
= bank
->driver_priv
;
705 if (psoc_eeprom_bank
->probed
)
708 return psoc5lp_eeprom_probe(bank
);
711 FLASH_BANK_COMMAND_HANDLER(psoc5lp_eeprom_flash_bank_command
)
713 struct psoc5lp_eeprom_flash_bank
*psoc_eeprom_bank
;
715 psoc_eeprom_bank
= malloc(sizeof(struct psoc5lp_eeprom_flash_bank
));
716 if (!psoc_eeprom_bank
)
717 return ERROR_FLASH_OPERATION_FAILED
;
719 psoc_eeprom_bank
->probed
= false;
720 psoc_eeprom_bank
->device
= NULL
;
722 bank
->driver_priv
= psoc_eeprom_bank
;
727 static const struct command_registration psoc5lp_eeprom_exec_command_handlers
[] = {
728 COMMAND_REGISTRATION_DONE
731 static const struct command_registration psoc5lp_eeprom_command_handlers
[] = {
733 .name
= "psoc5lp_eeprom",
735 .help
= "PSoC 5LP EEPROM command group",
737 .chain
= psoc5lp_eeprom_exec_command_handlers
,
739 COMMAND_REGISTRATION_DONE
742 struct flash_driver psoc5lp_eeprom_flash
= {
743 .name
= "psoc5lp_eeprom",
744 .commands
= psoc5lp_eeprom_command_handlers
,
745 .flash_bank_command
= psoc5lp_eeprom_flash_bank_command
,
746 .info
= psoc5lp_eeprom_get_info_command
,
747 .probe
= psoc5lp_eeprom_probe
,
748 .auto_probe
= psoc5lp_eeprom_auto_probe
,
749 .protect_check
= psoc5lp_eeprom_protect_check
,
750 .read
= default_flash_read
,
751 .erase
= psoc5lp_eeprom_erase
,
752 .erase_check
= default_flash_blank_check
,
753 .write
= psoc5lp_eeprom_write
,
760 struct psoc5lp_flash_bank
{
762 const struct psoc5lp_device
*device
;
766 static int psoc5lp_erase(struct flash_bank
*bank
, int first
, int last
)
768 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
771 if (!psoc_bank
->ecc_enabled
) {
772 /* Silently avoid erasing sectors twice */
773 if (last
>= first
+ bank
->num_sectors
/ 2) {
774 LOG_DEBUG("Skipping duplicate erase of sectors %d to %d",
775 first
+ bank
->num_sectors
/ 2, last
);
776 last
= first
+ (bank
->num_sectors
/ 2) - 1;
778 /* Check for any remaining ECC sectors */
779 if (last
>= bank
->num_sectors
/ 2) {
780 LOG_WARNING("Skipping erase of ECC region sectors %d to %d",
781 bank
->num_sectors
/ 2, last
);
782 last
= (bank
->num_sectors
/ 2) - 1;
786 for (i
= first
; i
<= last
; i
++) {
787 retval
= psoc5lp_spc_erase_sector(bank
->target
,
788 i
/ SECTORS_PER_BLOCK
, i
% SECTORS_PER_BLOCK
);
789 if (retval
!= ERROR_OK
)
796 /* Derived from core.c:default_flash_blank_check() */
797 static int psoc5lp_erase_check(struct flash_bank
*bank
)
799 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
800 struct target
*target
= bank
->target
;
802 int i
, num_sectors
, retval
;
804 if (target
->state
!= TARGET_HALTED
) {
805 LOG_ERROR("Target not halted");
806 return ERROR_TARGET_NOT_HALTED
;
809 num_sectors
= bank
->num_sectors
;
810 if (!psoc_bank
->ecc_enabled
)
813 for (i
= 0; i
< num_sectors
; i
++) {
814 uint32_t address
= bank
->base
+ bank
->sectors
[i
].offset
;
815 uint32_t size
= bank
->sectors
[i
].size
;
817 retval
= armv7m_blank_check_memory(target
, address
, size
,
818 &blank
, bank
->erased_value
);
819 if (retval
!= ERROR_OK
)
822 if (blank
== 0x00 && !psoc_bank
->ecc_enabled
) {
823 address
= bank
->base
+ bank
->sectors
[num_sectors
+ i
].offset
;
824 size
= bank
->sectors
[num_sectors
+ i
].size
;
826 retval
= armv7m_blank_check_memory(target
, address
, size
,
827 &blank
, bank
->erased_value
);
828 if (retval
!= ERROR_OK
)
833 bank
->sectors
[i
].is_erased
= 1;
834 bank
->sectors
[num_sectors
+ i
].is_erased
= 1;
836 bank
->sectors
[i
].is_erased
= 0;
837 bank
->sectors
[num_sectors
+ i
].is_erased
= 0;
844 static int psoc5lp_write(struct flash_bank
*bank
, const uint8_t *buffer
,
845 uint32_t offset
, uint32_t byte_count
)
847 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
848 struct target
*target
= bank
->target
;
849 struct working_area
*code_area
, *even_row_area
, *odd_row_area
;
851 uint8_t temp
[2], buf
[12], ecc_bytes
[ROW_ECC_SIZE
];
852 unsigned array_id
, row
;
855 if (offset
+ byte_count
> bank
->size
) {
856 LOG_ERROR("Writing to ECC not supported");
857 return ERROR_FLASH_DST_OUT_OF_BANK
;
860 if (offset
% ROW_SIZE
!= 0) {
861 LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32
,
863 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
867 if (!psoc_bank
->ecc_enabled
) {
868 row_size
+= ROW_ECC_SIZE
;
869 memset(ecc_bytes
, bank
->default_padded_value
, ROW_ECC_SIZE
);
872 retval
= psoc5lp_spc_get_temp(target
, 3, temp
);
873 if (retval
!= ERROR_OK
) {
874 LOG_ERROR("Unable to read Die temperature");
877 LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8
", magnitude 0x%02" PRIx8
,
880 assert(target_get_working_area_avail(target
) == target
->working_area_size
);
881 retval
= target_alloc_working_area(target
,
882 target_get_working_area_avail(target
) / 2, &code_area
);
883 if (retval
!= ERROR_OK
) {
884 LOG_ERROR("Could not allocate working area for program SRAM");
887 assert(code_area
->address
< 0x20000000);
889 retval
= target_alloc_working_area(target
,
890 SPC_OPCODE_LEN
+ 1 + row_size
+ 3 + SPC_OPCODE_LEN
+ 6,
892 if (retval
!= ERROR_OK
) {
893 LOG_ERROR("Could not allocate working area for even row");
896 assert(even_row_area
->address
>= 0x20000000);
898 retval
= target_alloc_working_area(target
, even_row_area
->size
,
900 if (retval
!= ERROR_OK
) {
901 LOG_ERROR("Could not allocate working area for odd row");
904 assert(odd_row_area
->address
>= 0x20000000);
906 for (array_id
= offset
/ BLOCK_SIZE
; byte_count
> 0; array_id
++) {
907 for (row
= (offset
/ ROW_SIZE
) % ROWS_PER_BLOCK
;
908 row
< ROWS_PER_BLOCK
&& byte_count
> 0; row
++) {
909 bool even_row
= (row
% 2 == 0);
910 struct working_area
*data_area
= even_row
? even_row_area
: odd_row_area
;
911 unsigned len
= MIN(ROW_SIZE
, byte_count
);
913 LOG_DEBUG("Writing load command for array %u row %u at 0x%08" TARGET_PRIxADDR
,
914 array_id
, row
, data_area
->address
);
916 psoc5lp_spc_write_opcode_buffer(target
, buf
, SPC_LOAD_ROW
);
917 buf
[SPC_OPCODE_LEN
] = array_id
;
918 retval
= target_write_buffer(target
, data_area
->address
, 4, buf
);
919 if (retval
!= ERROR_OK
)
922 retval
= target_write_buffer(target
,
923 data_area
->address
+ SPC_OPCODE_LEN
+ 1,
925 if (retval
!= ERROR_OK
)
931 if (len
< ROW_SIZE
) {
932 uint8_t padding
[ROW_SIZE
];
934 memset(padding
, bank
->default_padded_value
, ROW_SIZE
);
936 LOG_DEBUG("Padding %d bytes", ROW_SIZE
- len
);
937 retval
= target_write_buffer(target
,
938 data_area
->address
+ SPC_OPCODE_LEN
+ 1 + len
,
939 ROW_SIZE
- len
, padding
);
940 if (retval
!= ERROR_OK
)
944 if (!psoc_bank
->ecc_enabled
) {
945 retval
= target_write_buffer(target
,
946 data_area
->address
+ SPC_OPCODE_LEN
+ 1 + ROW_SIZE
,
947 sizeof(ecc_bytes
), ecc_bytes
);
948 if (retval
!= ERROR_OK
)
952 for (i
= 0; i
< 3; i
++)
953 buf
[i
] = 0x00; /* 3 NOPs for short delay */
954 psoc5lp_spc_write_opcode_buffer(target
, buf
+ 3, SPC_PRG_ROW
);
955 buf
[3 + SPC_OPCODE_LEN
] = array_id
;
956 buf
[3 + SPC_OPCODE_LEN
+ 1] = row
>> 8;
957 buf
[3 + SPC_OPCODE_LEN
+ 2] = row
& 0xff;
958 memcpy(buf
+ 3 + SPC_OPCODE_LEN
+ 3, temp
, 2);
959 buf
[3 + SPC_OPCODE_LEN
+ 5] = 0x00; /* padding */
960 retval
= target_write_buffer(target
,
961 data_area
->address
+ SPC_OPCODE_LEN
+ 1 + row_size
,
963 if (retval
!= ERROR_OK
)
966 retval
= target_write_u32(target
,
967 even_row
? PHUB_CH0_BASIC_STATUS
: PHUB_CH1_BASIC_STATUS
,
968 (even_row
? 0 : 1) << 8);
969 if (retval
!= ERROR_OK
)
972 retval
= target_write_u32(target
,
973 even_row
? PHUB_CH0_BASIC_CFG
: PHUB_CH1_BASIC_CFG
,
974 PHUB_CHx_BASIC_CFG_WORK_SEP
| PHUB_CHx_BASIC_CFG_EN
);
975 if (retval
!= ERROR_OK
)
978 retval
= target_write_u32(target
,
979 even_row
? PHUB_CFGMEM0_CFG0
: PHUB_CFGMEM1_CFG0
,
981 if (retval
!= ERROR_OK
)
984 retval
= target_write_u32(target
,
985 even_row
? PHUB_CFGMEM0_CFG1
: PHUB_CFGMEM1_CFG1
,
986 ((SPC_CPU_DATA
>> 16) << 16) | (data_area
->address
>> 16));
987 if (retval
!= ERROR_OK
)
990 retval
= target_write_u32(target
,
991 even_row
? PHUB_TDMEM0_ORIG_TD0
: PHUB_TDMEM1_ORIG_TD0
,
992 PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR
|
993 PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST
|
994 ((SPC_OPCODE_LEN
+ 1 + row_size
+ 3 + SPC_OPCODE_LEN
+ 5) & 0xfff));
995 if (retval
!= ERROR_OK
)
998 retval
= target_write_u32(target
,
999 even_row
? PHUB_TDMEM0_ORIG_TD1
: PHUB_TDMEM1_ORIG_TD1
,
1000 ((SPC_CPU_DATA
& 0xffff) << 16) | (data_area
->address
& 0xffff));
1001 if (retval
!= ERROR_OK
)
1004 retval
= psoc5lp_spc_busy_wait_idle(target
);
1005 if (retval
!= ERROR_OK
)
1008 retval
= target_write_u32(target
,
1009 even_row
? PHUB_CH0_ACTION
: PHUB_CH1_ACTION
,
1010 PHUB_CHx_ACTION_CPU_REQ
);
1011 if (retval
!= ERROR_OK
)
1012 goto err_dma_action
;
1016 retval
= psoc5lp_spc_busy_wait_idle(target
);
1022 target_free_working_area(target
, odd_row_area
);
1024 target_free_working_area(target
, even_row_area
);
1026 target_free_working_area(target
, code_area
);
1031 static int psoc5lp_protect_check(struct flash_bank
*bank
)
1033 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
1034 uint8_t row_data
[ROW_SIZE
];
1035 const unsigned protection_bytes_per_sector
= ROWS_PER_SECTOR
* 2 / 8;
1036 unsigned i
, j
, k
, num_sectors
;
1039 if (bank
->target
->state
!= TARGET_HALTED
) {
1040 LOG_ERROR("Target not halted");
1041 return ERROR_TARGET_NOT_HALTED
;
1044 for (i
= 0; i
< DIV_ROUND_UP(bank
->size
, BLOCK_SIZE
); i
++) {
1045 retval
= psoc5lp_spc_read_hidden_row(bank
->target
, i
,
1046 SPC_ROW_PROTECTION
, row_data
);
1047 if (retval
!= ERROR_OK
)
1050 /* Last flash array may have less rows, but in practice full sectors. */
1051 if (i
== bank
->size
/ BLOCK_SIZE
)
1052 num_sectors
= (bank
->size
% BLOCK_SIZE
) / SECTOR_SIZE
;
1054 num_sectors
= SECTORS_PER_BLOCK
;
1056 for (j
= 0; j
< num_sectors
; j
++) {
1057 int sector_nr
= i
* SECTORS_PER_BLOCK
+ j
;
1058 struct flash_sector
*sector
= &bank
->sectors
[sector_nr
];
1059 struct flash_sector
*ecc_sector
;
1061 if (psoc_bank
->ecc_enabled
)
1062 ecc_sector
= &bank
->sectors
[bank
->num_sectors
+ sector_nr
];
1064 ecc_sector
= &bank
->sectors
[bank
->num_sectors
/ 2 + sector_nr
];
1066 sector
->is_protected
= ecc_sector
->is_protected
= 0;
1067 for (k
= protection_bytes_per_sector
* j
;
1068 k
< protection_bytes_per_sector
* (j
+ 1); k
++) {
1069 assert(k
< protection_bytes_per_sector
* SECTORS_PER_BLOCK
);
1070 LOG_DEBUG("row[%u][%02u] = 0x%02" PRIx8
, i
, k
, row_data
[k
]);
1071 if (row_data
[k
] != 0x00) {
1072 sector
->is_protected
= ecc_sector
->is_protected
= 1;
1082 static int psoc5lp_get_info_command(struct flash_bank
*bank
, char *buf
, int buf_size
)
1084 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
1085 char part_number
[PART_NUMBER_LEN
];
1088 psoc5lp_get_part_number(psoc_bank
->device
, part_number
);
1089 ecc
= psoc_bank
->ecc_enabled
? "ECC enabled" : "ECC disabled";
1091 snprintf(buf
, buf_size
, "%s %s", part_number
, ecc
);
1096 static int psoc5lp_probe(struct flash_bank
*bank
)
1098 struct target
*target
= bank
->target
;
1099 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
1100 uint32_t flash_addr
= bank
->base
;
1101 uint8_t nvl
[4], temp
[2];
1104 if (target
->state
!= TARGET_HALTED
) {
1105 LOG_ERROR("Target not halted");
1106 return ERROR_TARGET_NOT_HALTED
;
1109 if (!psoc_bank
->device
) {
1110 retval
= psoc5lp_find_device(target
, &psoc_bank
->device
);
1111 if (retval
!= ERROR_OK
)
1114 bank
->size
= psoc_bank
->device
->flash_kb
* 1024;
1117 bank
->num_sectors
= DIV_ROUND_UP(bank
->size
, SECTOR_SIZE
);
1119 if (!psoc_bank
->probed
) {
1120 retval
= psoc5lp_spc_enable_clock(target
);
1121 if (retval
!= ERROR_OK
)
1124 /* First values read are inaccurate, so do it once now. */
1125 retval
= psoc5lp_spc_get_temp(target
, 3, temp
);
1126 if (retval
!= ERROR_OK
) {
1127 LOG_ERROR("Unable to read Die temperature");
1131 bank
->sectors
= calloc(bank
->num_sectors
* 2,
1132 sizeof(struct flash_sector
));
1133 for (i
= 0; i
< bank
->num_sectors
; i
++) {
1134 bank
->sectors
[i
].size
= SECTOR_SIZE
;
1135 bank
->sectors
[i
].offset
= flash_addr
- bank
->base
;
1136 bank
->sectors
[i
].is_erased
= -1;
1137 bank
->sectors
[i
].is_protected
= -1;
1139 flash_addr
+= bank
->sectors
[i
].size
;
1141 flash_addr
= 0x48000000;
1142 for (i
= bank
->num_sectors
; i
< bank
->num_sectors
* 2; i
++) {
1143 bank
->sectors
[i
].size
= ROWS_PER_SECTOR
* ROW_ECC_SIZE
;
1144 bank
->sectors
[i
].offset
= flash_addr
- bank
->base
;
1145 bank
->sectors
[i
].is_erased
= -1;
1146 bank
->sectors
[i
].is_protected
= -1;
1148 flash_addr
+= bank
->sectors
[i
].size
;
1151 bank
->default_padded_value
= bank
->erased_value
= 0x00;
1153 psoc_bank
->probed
= true;
1156 retval
= psoc5lp_spc_read_byte(target
, SPC_ARRAY_NVL_USER
, 3, &nvl
[3]);
1157 if (retval
!= ERROR_OK
)
1159 LOG_DEBUG("NVL[%d] = 0x%02" PRIx8
, 3, nvl
[3]);
1160 psoc_bank
->ecc_enabled
= nvl
[3] & NVL_3_ECCEN
;
1162 if (!psoc_bank
->ecc_enabled
)
1163 bank
->num_sectors
*= 2;
1168 static int psoc5lp_auto_probe(struct flash_bank
*bank
)
1170 return psoc5lp_probe(bank
);
1173 COMMAND_HANDLER(psoc5lp_handle_mass_erase_command
)
1175 struct flash_bank
*bank
;
1179 return ERROR_COMMAND_SYNTAX_ERROR
;
1181 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
1182 if (retval
!= ERROR_OK
)
1185 retval
= psoc5lp_spc_erase_all(bank
->target
);
1186 if (retval
== ERROR_OK
)
1187 command_print(CMD_CTX
, "PSoC 5LP erase succeeded");
1189 command_print(CMD_CTX
, "PSoC 5LP erase failed");
1194 FLASH_BANK_COMMAND_HANDLER(psoc5lp_flash_bank_command
)
1196 struct psoc5lp_flash_bank
*psoc_bank
;
1198 psoc_bank
= malloc(sizeof(struct psoc5lp_flash_bank
));
1200 return ERROR_FLASH_OPERATION_FAILED
;
1202 psoc_bank
->probed
= false;
1203 psoc_bank
->device
= NULL
;
1205 bank
->driver_priv
= psoc_bank
;
1210 static const struct command_registration psoc5lp_exec_command_handlers
[] = {
1212 .name
= "mass_erase",
1213 .handler
= psoc5lp_handle_mass_erase_command
,
1214 .mode
= COMMAND_EXEC
,
1216 .help
= "Erase all flash data and ECC/configuration bytes, "
1217 "all flash protection rows, "
1218 "and all row latches in all flash arrays on the device.",
1220 COMMAND_REGISTRATION_DONE
1223 static const struct command_registration psoc5lp_command_handlers
[] = {
1226 .mode
= COMMAND_ANY
,
1227 .help
= "PSoC 5LP flash command group",
1229 .chain
= psoc5lp_exec_command_handlers
,
1231 COMMAND_REGISTRATION_DONE
1234 struct flash_driver psoc5lp_flash
= {
1236 .commands
= psoc5lp_command_handlers
,
1237 .flash_bank_command
= psoc5lp_flash_bank_command
,
1238 .info
= psoc5lp_get_info_command
,
1239 .probe
= psoc5lp_probe
,
1240 .auto_probe
= psoc5lp_auto_probe
,
1241 .protect_check
= psoc5lp_protect_check
,
1242 .read
= default_flash_read
,
1243 .erase
= psoc5lp_erase
,
1244 .erase_check
= psoc5lp_erase_check
,
1245 .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)