psoc5lp: Add EEPROM flash driver 33/3433/19
authorAndreas Färber <afaerber@suse.de>
Mon, 2 May 2016 23:47:54 +0000 (01:47 +0200)
committerTomas Vanek <vanekt@fbl.cz>
Wed, 6 Jun 2018 14:49:14 +0000 (15:49 +0100)
Tested on CY8CKIT-059.

Change-Id: Ib02262e8eebf0df3d29492b8a7daa65b262da580
Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3433
Tested-by: jenkins
doc/openocd.texi
src/flash/nor/drivers.c
src/flash/nor/psoc5lp.c
tcl/target/psoc5lp.cfg

index 5c8283838eaed165341539bfb259ae7fd908a784..d8a7bb9236acd7e250a9afb5b7de7656eb41056d 100644 (file)
@@ -6168,6 +6168,17 @@ and all row latches in all flash arrays on the device.
 @end deffn
 @end deffn
 
 @end deffn
 @end deffn
 
+@deffn {Flash Driver} psoc5lp_eeprom
+All members of the PSoC 5LP microcontroller family from Cypress
+include internal EEPROM and use ARM Cortex-M3 cores.
+The driver probes for a number of these chips and autoconfigures itself,
+apart from the base address.
+
+@example
+flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 $_TARGETNAME
+@end example
+@end deffn
+
 @deffn {Flash Driver} psoc6
 Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers.
 PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share
 @deffn {Flash Driver} psoc6
 Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers.
 PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share
index f777df624aaa0cc83440a25024c233bfc6dd3881..2d391d28c3a4d8fa57cfa49aa728fb6d81a54f3b 100644 (file)
@@ -57,6 +57,7 @@ extern struct flash_driver ocl_flash;
 extern struct flash_driver pic32mx_flash;
 extern struct flash_driver psoc4_flash;
 extern struct flash_driver psoc5lp_flash;
 extern struct flash_driver pic32mx_flash;
 extern struct flash_driver psoc4_flash;
 extern struct flash_driver psoc5lp_flash;
+extern struct flash_driver psoc5lp_eeprom_flash;
 extern struct flash_driver psoc6_flash;
 extern struct flash_driver sim3x_flash;
 extern struct flash_driver stellaris_flash;
 extern struct flash_driver psoc6_flash;
 extern struct flash_driver sim3x_flash;
 extern struct flash_driver stellaris_flash;
@@ -117,6 +118,7 @@ static struct flash_driver *flash_drivers[] = {
        &pic32mx_flash,
        &psoc4_flash,
        &psoc5lp_flash,
        &pic32mx_flash,
        &psoc4_flash,
        &psoc5lp_flash,
+       &psoc5lp_eeprom_flash,
        &psoc6_flash,
        &sim3x_flash,
        &stellaris_flash,
        &psoc6_flash,
        &sim3x_flash,
        &stellaris_flash,
index 44fd033b1e23b439c632b99950a49687f337ac6b..87e130fb717ae1ae1ad54b8ba88084ee59b6f174 100644 (file)
@@ -26,6 +26,7 @@
 #include <target/armv7m.h>
 
 #define PM_ACT_CFG0             0x400043A0
 #include <target/armv7m.h>
 
 #define PM_ACT_CFG0             0x400043A0
+#define PM_ACT_CFG12            0x400043AC
 #define SPC_CPU_DATA            0x40004720
 #define SPC_SR                  0x40004722
 #define PHUB_CH0_BASIC_CFG      0x40007010
 #define SPC_CPU_DATA            0x40004720
 #define SPC_SR                  0x40004722
 #define PHUB_CH0_BASIC_CFG      0x40007010
@@ -44,6 +45,8 @@
 #define PHUB_TDMEM1_ORIG_TD1    0x4000780C
 #define PANTHER_DEVICE_ID       0x4008001C
 
 #define PHUB_TDMEM1_ORIG_TD1    0x4000780C
 #define PANTHER_DEVICE_ID       0x4008001C
 
+#define PM_ACT_CFG12_EN_EE (1 << 4)
+
 #define SPC_KEY1 0xB6
 #define SPC_KEY2 0xD3
 
 #define SPC_KEY1 0xB6
 #define SPC_KEY2 0xD3
 
@@ -96,6 +99,9 @@
 #define ROWS_PER_BLOCK     256
 #define BLOCK_SIZE         (ROWS_PER_BLOCK * ROW_SIZE)
 #define SECTORS_PER_BLOCK  (BLOCK_SIZE / SECTOR_SIZE)
 #define ROWS_PER_BLOCK     256
 #define BLOCK_SIZE         (ROWS_PER_BLOCK * ROW_SIZE)
 #define SECTORS_PER_BLOCK  (BLOCK_SIZE / SECTOR_SIZE)
+#define EEPROM_ROW_SIZE    16
+#define EEPROM_SECTOR_SIZE (ROWS_PER_SECTOR * EEPROM_ROW_SIZE)
+#define EEPROM_BLOCK_SIZE  (ROWS_PER_BLOCK * EEPROM_ROW_SIZE)
 
 #define PART_NUMBER_LEN (17 + 1)
 
 
 #define PART_NUMBER_LEN (17 + 1)
 
@@ -353,6 +359,32 @@ static int psoc5lp_spc_busy_wait_idle(struct target *target)
        return ERROR_FLASH_OPERATION_FAILED;
 }
 
        return ERROR_FLASH_OPERATION_FAILED;
 }
 
+static int psoc5lp_spc_load_row(struct target *target,
+       uint8_t array_id, const uint8_t *data, unsigned row_size)
+{
+       unsigned i;
+       int retval;
+
+       retval = psoc5lp_spc_write_opcode(target, SPC_LOAD_ROW);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u8(target, SPC_CPU_DATA, array_id);
+       if (retval != ERROR_OK)
+               return retval;
+
+       for (i = 0; i < row_size; i++) {
+               retval = target_write_u8(target, SPC_CPU_DATA, data[i]);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       retval = psoc5lp_spc_busy_wait_idle(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
 static int psoc5lp_spc_read_byte(struct target *target,
        uint8_t array_id, uint8_t offset, uint8_t *data)
 {
 static int psoc5lp_spc_read_byte(struct target *target,
        uint8_t array_id, uint8_t offset, uint8_t *data)
 {
@@ -383,6 +415,37 @@ static int psoc5lp_spc_read_byte(struct target *target,
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
+static int psoc5lp_spc_write_row(struct target *target,
+       uint8_t array_id, uint16_t row_id, const uint8_t *temp)
+{
+       int retval;
+
+       retval = psoc5lp_spc_write_opcode(target, SPC_WRITE_ROW);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u8(target, SPC_CPU_DATA, array_id);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u8(target, SPC_CPU_DATA, row_id >> 8);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u8(target, SPC_CPU_DATA, row_id & 0xff);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u8(target, SPC_CPU_DATA, temp[0]);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = target_write_u8(target, SPC_CPU_DATA, temp[1]);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = psoc5lp_spc_busy_wait_idle(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return ERROR_OK;
+}
+
 static int psoc5lp_spc_erase_sector(struct target *target,
        uint8_t array_id, uint8_t row_id)
 {
 static int psoc5lp_spc_erase_sector(struct target *target,
        uint8_t array_id, uint8_t row_id)
 {
@@ -482,6 +545,214 @@ static int psoc5lp_spc_get_temp(struct target *target, uint8_t samples,
        return ERROR_OK;
 }
 
        return ERROR_OK;
 }
 
+/*
+ * EEPROM
+ */
+
+struct psoc5lp_eeprom_flash_bank {
+       bool probed;
+       const struct psoc5lp_device *device;
+};
+
+static int psoc5lp_eeprom_erase(struct flash_bank *bank, int first, int last)
+{
+       int i, retval;
+
+       for (i = first; i <= last; i++) {
+               retval = psoc5lp_spc_erase_sector(bank->target,
+                               SPC_ARRAY_EEPROM, i);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static int psoc5lp_eeprom_write(struct flash_bank *bank,
+       const uint8_t *buffer, uint32_t offset, uint32_t byte_count)
+{
+       struct target *target = bank->target;
+       uint8_t temp[2];
+       unsigned row;
+       int retval;
+
+       if (offset % EEPROM_ROW_SIZE != 0) {
+               LOG_ERROR("Writes must be row-aligned, got offset 0x%08" PRIx32,
+                       offset);
+               return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+       }
+
+       retval = psoc5lp_spc_get_temp(target, 3, temp);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Unable to read Die temperature");
+               return retval;
+       }
+       LOG_DEBUG("Get_Temp: sign 0x%02" PRIx8 ", magnitude 0x%02" PRIx8,
+               temp[0], temp[1]);
+
+       for (row = offset / EEPROM_ROW_SIZE; byte_count >= EEPROM_ROW_SIZE; row++) {
+               retval = psoc5lp_spc_load_row(target, SPC_ARRAY_EEPROM,
+                               buffer, EEPROM_ROW_SIZE);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = psoc5lp_spc_write_row(target, SPC_ARRAY_EEPROM,
+                               row, temp);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               buffer += EEPROM_ROW_SIZE;
+               byte_count -= EEPROM_ROW_SIZE;
+               offset += EEPROM_ROW_SIZE;
+       }
+       if (byte_count > 0) {
+               uint8_t buf[EEPROM_ROW_SIZE];
+
+               memcpy(buf, buffer, byte_count);
+               memset(buf + byte_count, bank->default_padded_value,
+                               EEPROM_ROW_SIZE - byte_count);
+
+               LOG_DEBUG("Padding %d bytes", EEPROM_ROW_SIZE - byte_count);
+               retval = psoc5lp_spc_load_row(target, SPC_ARRAY_EEPROM,
+                               buf, EEPROM_ROW_SIZE);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               retval = psoc5lp_spc_write_row(target, SPC_ARRAY_EEPROM,
+                               row, temp);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return ERROR_OK;
+}
+
+static int psoc5lp_eeprom_protect_check(struct flash_bank *bank)
+{
+       int i;
+
+       for (i = 0; i < bank->num_sectors; i++)
+               bank->sectors[i].is_protected = -1;
+
+       return ERROR_OK;
+}
+
+static int psoc5lp_eeprom_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
+{
+       struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv;
+       char part_number[PART_NUMBER_LEN];
+
+       psoc5lp_get_part_number(psoc_eeprom_bank->device, part_number);
+
+       snprintf(buf, buf_size, "%s", part_number);
+
+       return ERROR_OK;
+}
+
+static int psoc5lp_eeprom_probe(struct flash_bank *bank)
+{
+       struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv;
+       uint32_t flash_addr = bank->base;
+       uint32_t val;
+       int i, retval;
+
+       if (psoc_eeprom_bank->probed)
+               return ERROR_OK;
+
+       if (bank->target->state != TARGET_HALTED) {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       retval = psoc5lp_find_device(bank->target, &psoc_eeprom_bank->device);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = target_read_u32(bank->target, PM_ACT_CFG12, &val);
+       if (retval != ERROR_OK)
+               return retval;
+       if (!(val & PM_ACT_CFG12_EN_EE)) {
+               val |= PM_ACT_CFG12_EN_EE;
+               retval = target_write_u32(bank->target, PM_ACT_CFG12, val);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       bank->size = psoc_eeprom_bank->device->eeprom_kb * 1024;
+       bank->num_sectors = DIV_ROUND_UP(bank->size, EEPROM_SECTOR_SIZE);
+       bank->sectors = calloc(bank->num_sectors,
+                              sizeof(struct flash_sector));
+       for (i = 0; i < bank->num_sectors; i++) {
+               bank->sectors[i].size = EEPROM_SECTOR_SIZE;
+               bank->sectors[i].offset = flash_addr - bank->base;
+               bank->sectors[i].is_erased = -1;
+               bank->sectors[i].is_protected = -1;
+
+               flash_addr += bank->sectors[i].size;
+       }
+
+       bank->default_padded_value = bank->erased_value = 0x00;
+
+       psoc_eeprom_bank->probed = true;
+
+       return ERROR_OK;
+}
+
+static int psoc5lp_eeprom_auto_probe(struct flash_bank *bank)
+{
+       struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv;
+
+       if (psoc_eeprom_bank->probed)
+               return ERROR_OK;
+
+       return psoc5lp_eeprom_probe(bank);
+}
+
+FLASH_BANK_COMMAND_HANDLER(psoc5lp_eeprom_flash_bank_command)
+{
+       struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank;
+
+       psoc_eeprom_bank = malloc(sizeof(struct psoc5lp_eeprom_flash_bank));
+       if (!psoc_eeprom_bank)
+               return ERROR_FLASH_OPERATION_FAILED;
+
+       psoc_eeprom_bank->probed = false;
+       psoc_eeprom_bank->device = NULL;
+
+       bank->driver_priv = psoc_eeprom_bank;
+
+       return ERROR_OK;
+}
+
+static const struct command_registration psoc5lp_eeprom_exec_command_handlers[] = {
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration psoc5lp_eeprom_command_handlers[] = {
+       {
+               .name = "psoc5lp_eeprom",
+               .mode = COMMAND_ANY,
+               .help = "PSoC 5LP EEPROM command group",
+               .usage = "",
+               .chain = psoc5lp_eeprom_exec_command_handlers,
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver psoc5lp_eeprom_flash = {
+       .name = "psoc5lp_eeprom",
+       .commands = psoc5lp_eeprom_command_handlers,
+       .flash_bank_command = psoc5lp_eeprom_flash_bank_command,
+       .info = psoc5lp_eeprom_get_info_command,
+       .probe = psoc5lp_eeprom_probe,
+       .auto_probe = psoc5lp_eeprom_auto_probe,
+       .protect_check = psoc5lp_eeprom_protect_check,
+       .read = default_flash_read,
+       .erase = psoc5lp_eeprom_erase,
+       .erase_check = default_flash_blank_check,
+       .write = psoc5lp_eeprom_write,
+};
+
 /*
  * Program Flash
  */
 /*
  * Program Flash
  */
index 68d83b022bd7b242f8f2891a4ad167940e772ab6..2089158e2b3ba3421625857aac2f99c71ee7d9ed 100644 (file)
@@ -57,6 +57,7 @@ $_TARGETNAME configure -event reset-init {
 
 set _FLASHNAME $_CHIPNAME.flash
 flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME
 
 set _FLASHNAME $_CHIPNAME.flash
 flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 $_TARGETNAME
 
 if {![using_hla]} {
        cortex_m reset_config sysresetreq
 
 if {![using_hla]} {
        cortex_m reset_config sysresetreq

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)