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,