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
;
803 if (target
->state
!= TARGET_HALTED
) {
804 LOG_ERROR("Target not halted");
805 return ERROR_TARGET_NOT_HALTED
;
808 struct target_memory_check_block
*block_array
;
809 block_array
= malloc(bank
->num_sectors
* sizeof(struct target_memory_check_block
));
810 if (block_array
== NULL
)
813 for (i
= 0; i
< bank
->num_sectors
; i
++) {
814 block_array
[i
].address
= bank
->base
+ bank
->sectors
[i
].offset
;
815 block_array
[i
].size
= bank
->sectors
[i
].size
;
816 block_array
[i
].result
= UINT32_MAX
; /* erase state unknown */
819 bool fast_check
= true;
820 for (i
= 0; i
< bank
->num_sectors
; ) {
821 retval
= armv7m_blank_check_memory(target
,
822 block_array
+ i
, bank
->num_sectors
- i
,
825 /* Run slow fallback if the first run gives no result
826 * otherwise use possibly incomplete results */
831 i
+= retval
; /* add number of blocks done this round */
835 if (!psoc_bank
->ecc_enabled
) {
836 int half_sectors
= bank
->num_sectors
/ 2;
837 for (i
= 0; i
< half_sectors
/ 2; i
++)
838 bank
->sectors
[i
].is_erased
=
839 (block_array
[i
].result
!= 1)
840 ? block_array
[i
+ half_sectors
].result
841 : block_array
[i
].result
;
843 for (i
= 0; i
< bank
->num_sectors
; i
++)
844 bank
->sectors
[i
].is_erased
= block_array
[i
].result
;
848 LOG_ERROR("Can't run erase check - add working memory");
856 static int psoc5lp_write(struct flash_bank
*bank
, const uint8_t *buffer
,
857 uint32_t offset
, uint32_t byte_count
)
859 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
860 struct target
*target
= bank
->target
;
861 struct working_area
*code_area
, *even_row_area
, *odd_row_area
;
863 uint8_t temp
[2], buf
[12], ecc_bytes
[ROW_ECC_SIZE
];
864 unsigned array_id
, row
;
867 if (offset
+ byte_count
> bank
->size
) {
868 LOG_ERROR("Writing to ECC not supported");
869 return ERROR_FLASH_DST_OUT_OF_BANK
;
872 if (offset
% ROW_SIZE
!= 0) {
873 LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32
,
875 return ERROR_FLASH_DST_BREAKS_ALIGNMENT
;
879 if (!psoc_bank
->ecc_enabled
) {
880 row_size
+= ROW_ECC_SIZE
;
881 memset(ecc_bytes
, bank
->default_padded_value
, ROW_ECC_SIZE
);
884 retval
= psoc5lp_spc_get_temp(target
, 3, temp
);
885 if (retval
!= ERROR_OK
) {
886 LOG_ERROR("Unable to read Die temperature");
889 LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8
", magnitude 0x%02" PRIx8
,
892 assert(target_get_working_area_avail(target
) == target
->working_area_size
);
893 retval
= target_alloc_working_area(target
,
894 target_get_working_area_avail(target
) / 2, &code_area
);
895 if (retval
!= ERROR_OK
) {
896 LOG_ERROR("Could not allocate working area for program SRAM");
899 assert(code_area
->address
< 0x20000000);
901 retval
= target_alloc_working_area(target
,
902 SPC_OPCODE_LEN
+ 1 + row_size
+ 3 + SPC_OPCODE_LEN
+ 6,
904 if (retval
!= ERROR_OK
) {
905 LOG_ERROR("Could not allocate working area for even row");
908 assert(even_row_area
->address
>= 0x20000000);
910 retval
= target_alloc_working_area(target
, even_row_area
->size
,
912 if (retval
!= ERROR_OK
) {
913 LOG_ERROR("Could not allocate working area for odd row");
916 assert(odd_row_area
->address
>= 0x20000000);
918 for (array_id
= offset
/ BLOCK_SIZE
; byte_count
> 0; array_id
++) {
919 for (row
= (offset
/ ROW_SIZE
) % ROWS_PER_BLOCK
;
920 row
< ROWS_PER_BLOCK
&& byte_count
> 0; row
++) {
921 bool even_row
= (row
% 2 == 0);
922 struct working_area
*data_area
= even_row
? even_row_area
: odd_row_area
;
923 unsigned len
= MIN(ROW_SIZE
, byte_count
);
925 LOG_DEBUG("Writing load command for array %u row %u at 0x%08" TARGET_PRIxADDR
,
926 array_id
, row
, data_area
->address
);
928 psoc5lp_spc_write_opcode_buffer(target
, buf
, SPC_LOAD_ROW
);
929 buf
[SPC_OPCODE_LEN
] = array_id
;
930 retval
= target_write_buffer(target
, data_area
->address
, 4, buf
);
931 if (retval
!= ERROR_OK
)
934 retval
= target_write_buffer(target
,
935 data_area
->address
+ SPC_OPCODE_LEN
+ 1,
937 if (retval
!= ERROR_OK
)
943 if (len
< ROW_SIZE
) {
944 uint8_t padding
[ROW_SIZE
];
946 memset(padding
, bank
->default_padded_value
, ROW_SIZE
);
948 LOG_DEBUG("Padding %d bytes", ROW_SIZE
- len
);
949 retval
= target_write_buffer(target
,
950 data_area
->address
+ SPC_OPCODE_LEN
+ 1 + len
,
951 ROW_SIZE
- len
, padding
);
952 if (retval
!= ERROR_OK
)
956 if (!psoc_bank
->ecc_enabled
) {
957 retval
= target_write_buffer(target
,
958 data_area
->address
+ SPC_OPCODE_LEN
+ 1 + ROW_SIZE
,
959 sizeof(ecc_bytes
), ecc_bytes
);
960 if (retval
!= ERROR_OK
)
964 for (i
= 0; i
< 3; i
++)
965 buf
[i
] = 0x00; /* 3 NOPs for short delay */
966 psoc5lp_spc_write_opcode_buffer(target
, buf
+ 3, SPC_PRG_ROW
);
967 buf
[3 + SPC_OPCODE_LEN
] = array_id
;
968 buf
[3 + SPC_OPCODE_LEN
+ 1] = row
>> 8;
969 buf
[3 + SPC_OPCODE_LEN
+ 2] = row
& 0xff;
970 memcpy(buf
+ 3 + SPC_OPCODE_LEN
+ 3, temp
, 2);
971 buf
[3 + SPC_OPCODE_LEN
+ 5] = 0x00; /* padding */
972 retval
= target_write_buffer(target
,
973 data_area
->address
+ SPC_OPCODE_LEN
+ 1 + row_size
,
975 if (retval
!= ERROR_OK
)
978 retval
= target_write_u32(target
,
979 even_row
? PHUB_CH0_BASIC_STATUS
: PHUB_CH1_BASIC_STATUS
,
980 (even_row
? 0 : 1) << 8);
981 if (retval
!= ERROR_OK
)
984 retval
= target_write_u32(target
,
985 even_row
? PHUB_CH0_BASIC_CFG
: PHUB_CH1_BASIC_CFG
,
986 PHUB_CHx_BASIC_CFG_WORK_SEP
| PHUB_CHx_BASIC_CFG_EN
);
987 if (retval
!= ERROR_OK
)
990 retval
= target_write_u32(target
,
991 even_row
? PHUB_CFGMEM0_CFG0
: PHUB_CFGMEM1_CFG0
,
993 if (retval
!= ERROR_OK
)
996 retval
= target_write_u32(target
,
997 even_row
? PHUB_CFGMEM0_CFG1
: PHUB_CFGMEM1_CFG1
,
998 ((SPC_CPU_DATA
>> 16) << 16) | (data_area
->address
>> 16));
999 if (retval
!= ERROR_OK
)
1002 retval
= target_write_u32(target
,
1003 even_row
? PHUB_TDMEM0_ORIG_TD0
: PHUB_TDMEM1_ORIG_TD0
,
1004 PHUB_TDMEMx_ORIG_TD0_INC_SRC_ADDR
|
1005 PHUB_TDMEMx_ORIG_TD0_NEXT_TD_PTR_LAST
|
1006 ((SPC_OPCODE_LEN
+ 1 + row_size
+ 3 + SPC_OPCODE_LEN
+ 5) & 0xfff));
1007 if (retval
!= ERROR_OK
)
1010 retval
= target_write_u32(target
,
1011 even_row
? PHUB_TDMEM0_ORIG_TD1
: PHUB_TDMEM1_ORIG_TD1
,
1012 ((SPC_CPU_DATA
& 0xffff) << 16) | (data_area
->address
& 0xffff));
1013 if (retval
!= ERROR_OK
)
1016 retval
= psoc5lp_spc_busy_wait_idle(target
);
1017 if (retval
!= ERROR_OK
)
1020 retval
= target_write_u32(target
,
1021 even_row
? PHUB_CH0_ACTION
: PHUB_CH1_ACTION
,
1022 PHUB_CHx_ACTION_CPU_REQ
);
1023 if (retval
!= ERROR_OK
)
1024 goto err_dma_action
;
1028 retval
= psoc5lp_spc_busy_wait_idle(target
);
1034 target_free_working_area(target
, odd_row_area
);
1036 target_free_working_area(target
, even_row_area
);
1038 target_free_working_area(target
, code_area
);
1043 static int psoc5lp_protect_check(struct flash_bank
*bank
)
1045 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
1046 uint8_t row_data
[ROW_SIZE
];
1047 const unsigned protection_bytes_per_sector
= ROWS_PER_SECTOR
* 2 / 8;
1048 unsigned i
, j
, k
, num_sectors
;
1051 if (bank
->target
->state
!= TARGET_HALTED
) {
1052 LOG_ERROR("Target not halted");
1053 return ERROR_TARGET_NOT_HALTED
;
1056 for (i
= 0; i
< DIV_ROUND_UP(bank
->size
, BLOCK_SIZE
); i
++) {
1057 retval
= psoc5lp_spc_read_hidden_row(bank
->target
, i
,
1058 SPC_ROW_PROTECTION
, row_data
);
1059 if (retval
!= ERROR_OK
)
1062 /* Last flash array may have less rows, but in practice full sectors. */
1063 if (i
== bank
->size
/ BLOCK_SIZE
)
1064 num_sectors
= (bank
->size
% BLOCK_SIZE
) / SECTOR_SIZE
;
1066 num_sectors
= SECTORS_PER_BLOCK
;
1068 for (j
= 0; j
< num_sectors
; j
++) {
1069 int sector_nr
= i
* SECTORS_PER_BLOCK
+ j
;
1070 struct flash_sector
*sector
= &bank
->sectors
[sector_nr
];
1071 struct flash_sector
*ecc_sector
;
1073 if (psoc_bank
->ecc_enabled
)
1074 ecc_sector
= &bank
->sectors
[bank
->num_sectors
+ sector_nr
];
1076 ecc_sector
= &bank
->sectors
[bank
->num_sectors
/ 2 + sector_nr
];
1078 sector
->is_protected
= ecc_sector
->is_protected
= 0;
1079 for (k
= protection_bytes_per_sector
* j
;
1080 k
< protection_bytes_per_sector
* (j
+ 1); k
++) {
1081 assert(k
< protection_bytes_per_sector
* SECTORS_PER_BLOCK
);
1082 LOG_DEBUG("row[%u][%02u] = 0x%02" PRIx8
, i
, k
, row_data
[k
]);
1083 if (row_data
[k
] != 0x00) {
1084 sector
->is_protected
= ecc_sector
->is_protected
= 1;
1094 static int psoc5lp_get_info_command(struct flash_bank
*bank
, char *buf
, int buf_size
)
1096 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
1097 char part_number
[PART_NUMBER_LEN
];
1100 psoc5lp_get_part_number(psoc_bank
->device
, part_number
);
1101 ecc
= psoc_bank
->ecc_enabled
? "ECC enabled" : "ECC disabled";
1103 snprintf(buf
, buf_size
, "%s %s", part_number
, ecc
);
1108 static int psoc5lp_probe(struct flash_bank
*bank
)
1110 struct target
*target
= bank
->target
;
1111 struct psoc5lp_flash_bank
*psoc_bank
= bank
->driver_priv
;
1112 uint32_t flash_addr
= bank
->base
;
1113 uint8_t nvl
[4], temp
[2];
1116 if (target
->state
!= TARGET_HALTED
) {
1117 LOG_ERROR("Target not halted");
1118 return ERROR_TARGET_NOT_HALTED
;
1121 if (!psoc_bank
->device
) {
1122 retval
= psoc5lp_find_device(target
, &psoc_bank
->device
);
1123 if (retval
!= ERROR_OK
)
1126 bank
->size
= psoc_bank
->device
->flash_kb
* 1024;
1129 bank
->num_sectors
= DIV_ROUND_UP(bank
->size
, SECTOR_SIZE
);
1131 if (!psoc_bank
->probed
) {
1132 retval
= psoc5lp_spc_enable_clock(target
);
1133 if (retval
!= ERROR_OK
)
1136 /* First values read are inaccurate, so do it once now. */
1137 retval
= psoc5lp_spc_get_temp(target
, 3, temp
);
1138 if (retval
!= ERROR_OK
) {
1139 LOG_ERROR("Unable to read Die temperature");
1143 bank
->sectors
= calloc(bank
->num_sectors
* 2,
1144 sizeof(struct flash_sector
));
1145 for (i
= 0; i
< bank
->num_sectors
; i
++) {
1146 bank
->sectors
[i
].size
= SECTOR_SIZE
;
1147 bank
->sectors
[i
].offset
= flash_addr
- bank
->base
;
1148 bank
->sectors
[i
].is_erased
= -1;
1149 bank
->sectors
[i
].is_protected
= -1;
1151 flash_addr
+= bank
->sectors
[i
].size
;
1153 flash_addr
= 0x48000000;
1154 for (i
= bank
->num_sectors
; i
< bank
->num_sectors
* 2; i
++) {
1155 bank
->sectors
[i
].size
= ROWS_PER_SECTOR
* ROW_ECC_SIZE
;
1156 bank
->sectors
[i
].offset
= flash_addr
- bank
->base
;
1157 bank
->sectors
[i
].is_erased
= -1;
1158 bank
->sectors
[i
].is_protected
= -1;
1160 flash_addr
+= bank
->sectors
[i
].size
;
1163 bank
->default_padded_value
= bank
->erased_value
= 0x00;
1165 psoc_bank
->probed
= true;
1168 retval
= psoc5lp_spc_read_byte(target
, SPC_ARRAY_NVL_USER
, 3, &nvl
[3]);
1169 if (retval
!= ERROR_OK
)
1171 LOG_DEBUG("NVL[%d] = 0x%02" PRIx8
, 3, nvl
[3]);
1172 psoc_bank
->ecc_enabled
= nvl
[3] & NVL_3_ECCEN
;
1174 if (!psoc_bank
->ecc_enabled
)
1175 bank
->num_sectors
*= 2;
1180 static int psoc5lp_auto_probe(struct flash_bank
*bank
)
1182 return psoc5lp_probe(bank
);
1185 COMMAND_HANDLER(psoc5lp_handle_mass_erase_command
)
1187 struct flash_bank
*bank
;
1191 return ERROR_COMMAND_SYNTAX_ERROR
;
1193 retval
= CALL_COMMAND_HANDLER(flash_command_get_bank
, 0, &bank
);
1194 if (retval
!= ERROR_OK
)
1197 retval
= psoc5lp_spc_erase_all(bank
->target
);
1198 if (retval
== ERROR_OK
)
1199 command_print(CMD_CTX
, "PSoC 5LP erase succeeded");
1201 command_print(CMD_CTX
, "PSoC 5LP erase failed");
1206 FLASH_BANK_COMMAND_HANDLER(psoc5lp_flash_bank_command
)
1208 struct psoc5lp_flash_bank
*psoc_bank
;
1210 psoc_bank
= malloc(sizeof(struct psoc5lp_flash_bank
));
1212 return ERROR_FLASH_OPERATION_FAILED
;
1214 psoc_bank
->probed
= false;
1215 psoc_bank
->device
= NULL
;
1217 bank
->driver_priv
= psoc_bank
;
1222 static const struct command_registration psoc5lp_exec_command_handlers
[] = {
1224 .name
= "mass_erase",
1225 .handler
= psoc5lp_handle_mass_erase_command
,
1226 .mode
= COMMAND_EXEC
,
1228 .help
= "Erase all flash data and ECC/configuration bytes, "
1229 "all flash protection rows, "
1230 "and all row latches in all flash arrays on the device.",
1232 COMMAND_REGISTRATION_DONE
1235 static const struct command_registration psoc5lp_command_handlers
[] = {
1238 .mode
= COMMAND_ANY
,
1239 .help
= "PSoC 5LP flash command group",
1241 .chain
= psoc5lp_exec_command_handlers
,
1243 COMMAND_REGISTRATION_DONE
1246 struct flash_driver psoc5lp_flash
= {
1248 .commands
= psoc5lp_command_handlers
,
1249 .flash_bank_command
= psoc5lp_flash_bank_command
,
1250 .info
= psoc5lp_get_info_command
,
1251 .probe
= psoc5lp_probe
,
1252 .auto_probe
= psoc5lp_auto_probe
,
1253 .protect_check
= psoc5lp_protect_check
,
1254 .read
= default_flash_read
,
1255 .erase
= psoc5lp_erase
,
1256 .erase_check
= psoc5lp_erase_check
,
1257 .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)