diff --git a/contrib/loaders/watchdog/Makefile b/contrib/loaders/watchdog/Makefile index 623e74407..ed6d8f4e5 100644 --- a/contrib/loaders/watchdog/Makefile +++ b/contrib/loaders/watchdog/Makefile @@ -6,7 +6,7 @@ ARM_OBJCOPY ?= $(ARM_CROSS_COMPILE)objcopy ARM_AFLAGS = -EL -mthumb -arm: armv7m_kinetis_wdog.inc +arm: armv7m_kinetis_wdog.inc armv7m_kinetis_wdog32.inc armv7m_%.elf: armv7m_%.s $(ARM_AS) $(ARM_AFLAGS) $< -o $@ diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog.inc b/contrib/loaders/watchdog/armv7m_kinetis_wdog.inc index 4b6579e0c..317d084dd 100644 --- a/contrib/loaders/watchdog/armv7m_kinetis_wdog.inc +++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog.inc @@ -1,4 +1,3 @@ /* Autogenerated with ../../../src/helper/bin2char.sh */ -0x04,0x4b,0x05,0x4a,0xda,0x81,0x05,0x4a,0xda,0x81,0x01,0x24,0x1a,0x88,0xa2,0x43, -0x1a,0x80,0x06,0xe0,0x00,0x20,0x05,0x40,0x20,0xc5,0x00,0x00,0x28,0xd9,0x00,0x00, -0x00,0x00,0x00,0xbe, +0x04,0x4a,0xc2,0x81,0x04,0x4a,0xc2,0x81,0x01,0x24,0x02,0x88,0xa2,0x43,0x02,0x80, +0x05,0xe0,0x00,0x00,0x20,0xc5,0x00,0x00,0x28,0xd9,0x00,0x00,0x00,0x00,0x00,0xbe, diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog.s b/contrib/loaders/watchdog/armv7m_kinetis_wdog.s index bac924ab8..d7241927c 100644 --- a/contrib/loaders/watchdog/armv7m_kinetis_wdog.s +++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog.s @@ -19,7 +19,9 @@ /* Disable watchdog for Kinetis Kx and KVx - Parameters: none + Parameters: + r0 ... WDOG base (in) + Used instruction set should work on both Cortex-M4 and M0+ */ @@ -28,7 +30,6 @@ .cpu cortex-m0 .thumb -WDOG_ADDR = 0x40052000 /* WDOG registers offsets */ WDOG_STCTRLH = 0 WDOG_UNLOCK = 0x0e @@ -39,17 +40,16 @@ WDOG_KEY2 = 0xd928 .thumb_func start: /* WDOG_UNLOCK = 0xC520 */ - ldr r3, =WDOG_ADDR ldr r2, =WDOG_KEY1 - strh r2, [r3, WDOG_UNLOCK] + strh r2, [r0, WDOG_UNLOCK] /* WDOG_UNLOCK = 0xD928 */ ldr r2, =WDOG_KEY2 - strh r2, [r3, WDOG_UNLOCK] + strh r2, [r0, WDOG_UNLOCK] /* WDOG_STCTRLH clear bit 0 */ movs r4, #1 - ldrh r2, [r3, WDOG_STCTRLH] + ldrh r2, [r0, WDOG_STCTRLH] bics r2, r4 - strh r2, [r3, WDOG_STCTRLH] + strh r2, [r0, WDOG_STCTRLH] /* OpenOCD checks exit point address. Jump to the very end. */ b done diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog32.inc b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.inc new file mode 100644 index 000000000..4ee06ed1f --- /dev/null +++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.inc @@ -0,0 +1,5 @@ +/* Autogenerated with ../../../src/helper/bin2char.sh */ +0x02,0x68,0x08,0x4b,0x1a,0x42,0x08,0x4b,0x01,0xd0,0x43,0x60,0x02,0xe0,0x83,0x80, +0x1b,0x0c,0x83,0x80,0x80,0x24,0xa2,0x43,0x20,0x24,0x22,0x43,0x02,0x60,0x03,0x4b, +0x83,0x60,0x06,0xe0,0x00,0x20,0x00,0x00,0x20,0xc5,0x28,0xd9,0x00,0x04,0x00,0x00, +0x00,0x00,0x00,0xbe, diff --git a/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s new file mode 100644 index 000000000..bf58327e9 --- /dev/null +++ b/contrib/loaders/watchdog/armv7m_kinetis_wdog32.s @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (C) 2017 Tomas Vanek * + * vanekt@fbl.cz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc. * + ***************************************************************************/ + +/* + Disable watchdog, 32-bit version for newer Kinetis + Parameters: + r0 ... WDOG32 base (in) + + Used instruction set should work on both Cortex-M4 and M0+ +*/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + +/* WDOG registers offsets */ +WDOG_CS = 0 +WDOG_CNT = 4 +WDOG_TOVAL = 8 + +WDOG_KEY = 0xd928c520 + + .thumb_func +start: +/* test WDOG_CS bit CMD32EN */ + ldr r2, [r0, WDOG_CS] + ldr r3, =0x2000 + tst r2, r3 + ldr r3, =WDOG_KEY + beq cmd16 + +/* WDOG_CNT = key */ + str r3, [r0, WDOG_CNT] + b unlocked + +cmd16: +/* WDOG_CNT = key, halfword by halfword */ + strh r3, [r0, WDOG_CNT] + lsrs r3, r3, #16 + strh r3, [r0, WDOG_CNT] + +/* WDOG_CS: clear EN bit 7, set UPDATE bit 5 */ +unlocked: + movs r4, #0x80 + bics r2, r4 + movs r4, #0x20 + orrs r2, r4 + str r2, [r0, WDOG_CS] +/* All active WDOG registers have to be updated, set dummy timeout */ +/* WDOG_TOVAL = 0x400 */ + ldr r3, =0x400 + str r3, [r0, WDOG_TOVAL] +/* OpenOCD checks exit point address. Jump to the very end. */ + b done + + .pool + +/* Avoid padding at .text segment end. Otherwise exit point check fails. */ + .skip ( . - start + 2) & 2, 0 +done: + bkpt #0 + + .end + diff --git a/doc/openocd.texi b/doc/openocd.texi index 59d2d4f1a..89ee5eb45 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -682,7 +682,8 @@ bash$ openocd --help --version | -v display OpenOCD version --file | -f use configuration file --search | -s dir to search for config files and scripts ---debug | -d set debug level <0-3> +--debug | -d set debug level to 3 + | -d set debug level to --log_output | -l redirect log output to file --command | -c run @end verbatim @@ -4715,15 +4716,18 @@ each block, and the specified length must stay within that bank. @end deffn @comment no current checks for errors if fill blocks touch multiple banks! -@deffn Command {flash write_bank} num filename offset +@deffn Command {flash write_bank} num filename [offset] Write the binary @file{filename} to flash bank @var{num}, -starting at @var{offset} bytes from the beginning of the bank. +starting at @var{offset} bytes from the beginning of the bank. If @var{offset} +is omitted, start at the beginning of the flash bank. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash read_bank} num filename offset length +@deffn Command {flash read_bank} num filename [offset [length]] Read @var{length} bytes from the flash bank @var{num} starting at @var{offset} -and write the contents to the binary @file{filename}. +and write the contents to the binary @file{filename}. If @var{offset} is +omitted, start at the beginning of the flash bank. If @var{length} is omitted, +read the remaining bytes from the flash bank. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -5361,15 +5365,28 @@ nor is Chip Erase (only Sector Erase is implemented).} @deffn {Flash Driver} kinetis @cindex kinetis -Kx and KLx members of the Kinetis microcontroller family from Freescale include +Kx, KLx, KVx and KE1x members of the Kinetis microcontroller family +from NXP (former Freescale) include internal flash and use ARM Cortex-M0+ or M4 cores. The driver automatically recognizes flash size and a number of flash banks (1-4) using the chip identification register, and autoconfigures itself. +Use kinetis_ke driver for KE0x devices. + +The @var{kinetis} driver defines option: +@itemize +@item -sim-base @var{addr} ... base of System Integration Module where chip identification resides. Driver tries two known locations if option is omitted. +@end itemize @example flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME @end example +@deffn Command {kinetis create_banks} +Configuration command enables automatic creation of additional flash banks +based on real flash layout of device. Banks are created during device probe. +Use 'flash probe 0' to force probe. +@end deffn + @deffn Command {kinetis fcf_source} [protection|write] Select what source is used when writing to a Flash Configuration Field. @option{protection} mode builds FCF content from protection bits previously @@ -5446,10 +5463,11 @@ Command disables watchdog timer. @deffn {Flash Driver} kinetis_ke @cindex kinetis_ke -KE members of the Kinetis microcontroller family from Freescale include +KE0x members of the Kinetis microcontroller family from Freescale include internal flash and use ARM Cortex-M0+. The driver automatically recognizes -the KE family and sub-family using the chip identification register, and +the KE0x sub-family using the chip identification register, and autoconfigures itself. +Use kinetis (not kinetis_ke) driver for KE1x devices. @example flash bank $_FLASHNAME kinetis_ke 0 0 0 0 $_TARGETNAME @@ -5971,16 +5989,21 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f2x options_read} num -Reads and displays user options and (where implemented) boot_addr0 and boot_addr1. +Reads and displays user options and (where implemented) boot_addr0, boot_addr1, optcr2. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f2x options_write} num user_options boot_addr0 boot_addr1 Writes user options and (where implemented) boot_addr0 and boot_addr1 in raw format. Warning: The meaning of the various bits depends on the device, always check datasheet! -The @var{num} parameter is a value shown by @command{flash banks}, user_options a -12 bit value, consisting of bits 31-28 and 7-0 of FLASH_OPTCR, boot_addr0 and boot_addr1 -two halfwords (of FLASH_OPTCR1). +The @var{num} parameter is a value shown by @command{flash banks}, @var{user_options} a +12 bit value, consisting of bits 31-28 and 7-0 of FLASH_OPTCR, @var{boot_addr0} and +@var{boot_addr1} two halfwords (of FLASH_OPTCR1). +@end deffn + +@deffn Command {stm32f2x optcr2_write} num optcr2 +Writes FLASH_OPTCR2 options. Warning: Clearing PCROPi bits requires a full mass erase! +The @var{num} parameter is a value shown by @command{flash banks}, @var{optcr2} a 32-bit word. @end deffn @end deffn @@ -6832,12 +6855,13 @@ non-zero exit code to the parent process. @deffn Command debug_level [n] @cindex message level Display debug level. -If @var{n} (from 0..3) is provided, then set it to that level. +If @var{n} (from 0..4) is provided, then set it to that level. This affects the kind of messages sent to the server log. Level 0 is error messages only; level 1 adds warnings; level 2 adds informational messages; -and level 3 adds debugging messages. +level 3 adds debugging messages; +and level 4 adds verbose low-level debug messages. The default is level 2, but that can be overridden on the command line along with the location of that log file (which is normally the server's standard output). diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index ff75b4188..d101c9b4c 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -464,7 +464,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, @@ -499,7 +499,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, @@ -532,7 +532,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, @@ -565,7 +565,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, @@ -598,7 +598,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, @@ -631,7 +631,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, @@ -1279,7 +1279,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, @@ -1295,7 +1295,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 1, .base_address = FLASH_BANK1_BASE_1024K_SD, .controller_address = 0x400e0c00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, @@ -1305,10 +1305,10 @@ static const struct sam4_chip_details all_sam4_details[] = { }, }, - /* at91samg53n19 */ + /* atsamg53n19 */ { .chipid_cidr = 0x247e0ae0, - .name = "at91samg53n19", + .name = "atsamg53n19", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 2, @@ -1323,7 +1323,7 @@ static const struct sam4_chip_details all_sam4_details[] = { .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, - .flash_wait_states = 6, /* workaround silicon bug */ + .flash_wait_states = 5, .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index f018e893d..ad88c5143 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -25,7 +25,7 @@ #include -#define SAMD_NUM_SECTORS 16 +#define SAMD_NUM_PROT_BLOCKS 16 #define SAMD_PAGE_SIZE_MAX 1024 #define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */ @@ -286,6 +286,7 @@ struct samd_info { uint32_t page_size; int num_pages; int sector_size; + int prot_block_size; bool probed; struct target *target; @@ -319,7 +320,7 @@ static const struct samd_part *samd_find_part(uint32_t id) static int samd_protect_check(struct flash_bank *bank) { - int res; + int res, prot_block; uint16_t lock; res = target_read_u16(bank->target, @@ -328,8 +329,8 @@ static int samd_protect_check(struct flash_bank *bank) return res; /* Lock bits are active-low */ - for (int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_protected = !(lock & (1<num_prot_blocks; prot_block++) + bank->prot_blocks[prot_block].is_protected = !(lock & (1u<size = part->flash_kb * 1024; - chip->sector_size = bank->size / SAMD_NUM_SECTORS; - res = samd_get_flash_page_info(bank->target, &chip->page_size, &chip->num_pages); if (res != ERROR_OK) { @@ -397,21 +396,23 @@ static int samd_probe(struct flash_bank *bank) part->flash_kb, chip->num_pages, chip->page_size); } + /* Erase granularity = 1 row = 4 pages */ + chip->sector_size = chip->page_size * 4; + /* Allocate the sector table */ - bank->num_sectors = SAMD_NUM_SECTORS; - bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0])); + bank->num_sectors = chip->num_pages / 4; + bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; - /* Fill out the sector information: all SAMD sectors are the same size and - * there is always a fixed number of them. */ - for (int i = 0; i < bank->num_sectors; i++) { - bank->sectors[i].size = chip->sector_size; - bank->sectors[i].offset = i * chip->sector_size; - /* mark as unknown */ - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = -1; - } + /* 16 protection blocks per device */ + chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS; + + /* Allocate the table of protection blocks */ + bank->num_prot_blocks = SAMD_NUM_PROT_BLOCKS; + bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks); + if (!bank->prot_blocks) + return ERROR_FAIL; samd_protect_check(bank); @@ -606,9 +607,10 @@ out_user_row: return res; } -static int samd_protect(struct flash_bank *bank, int set, int first, int last) +static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl) { - struct samd_info *chip = (struct samd_info *)bank->driver_priv; + int res = ERROR_OK; + int prot_block; /* We can issue lock/unlock region commands with the target running but * the settings won't persist unless we're able to modify the LOCK regions @@ -618,18 +620,16 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_TARGET_NOT_HALTED; } - int res = ERROR_OK; - - for (int s = first; s <= last; s++) { - if (set != bank->sectors[s].is_protected) { - /* Load an address that is within this sector (we use offset 0) */ + for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) { + if (set != bank->prot_blocks[prot_block].is_protected) { + /* Load an address that is within this protection block (we use offset 0) */ res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, - ((s * chip->sector_size) >> 1)); + bank->prot_blocks[prot_block].offset >> 1); if (res != ERROR_OK) goto exit; - /* Tell the controller to lock that sector */ + /* Tell the controller to lock that block */ res = samd_issue_nvmctrl_command(bank->target, set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR); if (res != ERROR_OK) @@ -644,7 +644,7 @@ static int samd_protect(struct flash_bank *bank, int set, int first, int last) * locked. See Table 9-3 in the SAMD20 datasheet for more details. */ res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF, - 48 + first, 48 + last); + 48 + first_prot_bl, 48 + last_prot_bl); if (res != ERROR_OK) LOG_WARNING("SAMD: protect settings were not made persistent!"); @@ -656,10 +656,9 @@ exit: return res; } -static int samd_erase(struct flash_bank *bank, int first, int last) +static int samd_erase(struct flash_bank *bank, int first_sect, int last_sect) { - int res; - int rows_in_sector; + int res, s; struct samd_info *chip = (struct samd_info *)bank->driver_priv; if (bank->target->state != TARGET_HALTED) { @@ -673,26 +672,12 @@ static int samd_erase(struct flash_bank *bank, int first, int last) return ERROR_FLASH_BANK_NOT_PROBED; } - /* The SAMD NVM has row erase granularity. There are four pages in a row - * and the number of rows in a sector depends on the sector size, which in - * turn depends on the Flash capacity as there is a fixed number of - * sectors. */ - rows_in_sector = chip->sector_size / (chip->page_size * 4); - /* For each sector to be erased */ - for (int s = first; s <= last; s++) { - if (bank->sectors[s].is_protected) { - LOG_ERROR("SAMD: failed to erase sector %d. That sector is write-protected", s); - return ERROR_FLASH_OPERATION_FAILED; - } - - /* For each row in that sector */ - for (int r = s * rows_in_sector; r < (s + 1) * rows_in_sector; r++) { - res = samd_erase_row(bank->target, r * chip->page_size * 4); - if (res != ERROR_OK) { - LOG_ERROR("SAMD: failed to erase sector %d", s); - return res; - } + for (s = first_sect; s <= last_sect; s++) { + res = samd_erase_row(bank->target, bank->sectors[s].offset); + if (res != ERROR_OK) { + LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset); + return res; } } diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 81c1a379c..117cd8a1b 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -48,6 +48,7 @@ #define EFM_FAMILY_ID_HAPPY_GECKO 77 #define EZR_FAMILY_ID_WONDER_GECKO 120 #define EZR_FAMILY_ID_LEOPARD_GECKO 121 +#define EZR_FAMILY_ID_HAPPY_GECKO 122 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 @@ -178,7 +179,8 @@ static int efm32x_read_info(struct flash_bank *bank, EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family) efm32_info->page_size = 512; else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family || - EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family) + EFM_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family || + EZR_FAMILY_ID_HAPPY_GECKO == efm32_info->part_family) efm32_info->page_size = 1024; else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family || EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) { @@ -236,6 +238,7 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) switch (info->part_family) { case EZR_FAMILY_ID_WONDER_GECKO: case EZR_FAMILY_ID_LEOPARD_GECKO: + case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "EZR32 "); break; default: @@ -270,6 +273,7 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) printed = snprintf(buf, buf_size, "Zero Gecko"); break; case EFM_FAMILY_ID_HAPPY_GECKO: + case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "Happy Gecko"); break; } diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 7e9bbdef4..4ef438507 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -89,21 +89,35 @@ #define FLEXRAM 0x14000000 +#define MSCM_OCMDR0 0x40001400 #define FMC_PFB01CR 0x4001f004 #define FTFx_FSTAT 0x40020000 #define FTFx_FCNFG 0x40020001 #define FTFx_FCCOB3 0x40020004 #define FTFx_FPROT3 0x40020010 #define FTFx_FDPROT 0x40020017 -#define SIM_SDID 0x40048024 -#define SIM_SOPT1 0x40047000 -#define SIM_FCFG1 0x4004804c -#define SIM_FCFG2 0x40048050 -#define WDOG_STCTRH 0x40052000 +#define SIM_BASE 0x40047000 +#define SIM_BASE_KL28 0x40074000 +#define SIM_COPC 0x40048100 + /* SIM_COPC does not exist on devices with changed SIM_BASE */ +#define WDOG_BASE 0x40052000 +#define WDOG32_KE1X 0x40052000 +#define WDOG32_KL28 0x40076000 #define SMC_PMCTRL 0x4007E001 #define SMC_PMSTAT 0x4007E003 +#define SMC32_PMCTRL 0x4007E00C +#define SMC32_PMSTAT 0x4007E014 #define MCM_PLACR 0xF000300C +/* Offsets */ +#define SIM_SOPT1_OFFSET 0x0000 +#define SIM_SDID_OFFSET 0x1024 +#define SIM_FCFG1_OFFSET 0x104c +#define SIM_FCFG2_OFFSET 0x1050 + +#define WDOG_STCTRLH_OFFSET 0 +#define WDOG32_CS_OFFSET 0 + /* Values */ #define PM_STAT_RUN 0x01 #define PM_STAT_VLPR 0x04 @@ -187,9 +201,11 @@ #define KINETIS_SDID_SERIESID_MASK 0x00F00000 #define KINETIS_SDID_SERIESID_K 0x00000000 #define KINETIS_SDID_SERIESID_KL 0x00100000 +#define KINETIS_SDID_SERIESID_KE 0x00200000 #define KINETIS_SDID_SERIESID_KW 0x00500000 #define KINETIS_SDID_SERIESID_KV 0x00600000 +#define KINETIS_SDID_SUBFAMID_SHIFT 24 #define KINETIS_SDID_SUBFAMID_MASK 0x0F000000 #define KINETIS_SDID_SUBFAMID_KX0 0x00000000 #define KINETIS_SDID_SUBFAMID_KX1 0x01000000 @@ -198,46 +214,146 @@ #define KINETIS_SDID_SUBFAMID_KX4 0x04000000 #define KINETIS_SDID_SUBFAMID_KX5 0x05000000 #define KINETIS_SDID_SUBFAMID_KX6 0x06000000 +#define KINETIS_SDID_SUBFAMID_KX7 0x07000000 +#define KINETIS_SDID_SUBFAMID_KX8 0x08000000 +#define KINETIS_SDID_FAMILYID_SHIFT 28 #define KINETIS_SDID_FAMILYID_MASK 0xF0000000 #define KINETIS_SDID_FAMILYID_K0X 0x00000000 #define KINETIS_SDID_FAMILYID_K1X 0x10000000 #define KINETIS_SDID_FAMILYID_K2X 0x20000000 #define KINETIS_SDID_FAMILYID_K3X 0x30000000 #define KINETIS_SDID_FAMILYID_K4X 0x40000000 +#define KINETIS_SDID_FAMILYID_K5X 0x50000000 #define KINETIS_SDID_FAMILYID_K6X 0x60000000 #define KINETIS_SDID_FAMILYID_K7X 0x70000000 #define KINETIS_SDID_FAMILYID_K8X 0x80000000 +#define KINETIS_SDID_FAMILYID_KL8X 0x90000000 + +/* The field originally named DIEID has new name/meaning on KE1x */ +#define KINETIS_SDID_PROJECTID_MASK KINETIS_SDID_DIEID_MASK +#define KINETIS_SDID_PROJECTID_KE1xF 0x00000080 +#define KINETIS_SDID_PROJECTID_KE1xZ 0x00000100 struct kinetis_flash_bank { + struct kinetis_chip *k_chip; bool probed; + unsigned bank_number; /* bank number in particular chip */ + struct flash_bank *bank; + uint32_t sector_size; - uint32_t max_flash_prog_size; uint32_t protection_size; uint32_t prog_base; /* base address for FTFx operations */ - /* same as bank->base for pflash, differs for FlexNVM */ + /* usually same as bank->base for pflash, differs for FlexNVM */ uint32_t protection_block; /* number of first protection block in this bank */ - uint32_t sim_sdid; - uint32_t sim_fcfg1; - uint32_t sim_fcfg2; - enum { FC_AUTO = 0, FC_PFLASH, FC_FLEX_NVM, FC_FLEX_RAM, } flash_class; +}; + +#define KINETIS_MAX_BANKS 4u + +struct kinetis_chip { + struct target *target; + bool probed; + + uint32_t sim_sdid; + uint32_t sim_fcfg1; + uint32_t sim_fcfg2; + uint32_t fcfg2_maxaddr0_shifted; + uint32_t fcfg2_maxaddr1_shifted; + + unsigned num_pflash_blocks, num_nvm_blocks; + unsigned pflash_sector_size, nvm_sector_size; + unsigned max_flash_prog_size; + + uint32_t pflash_base; + uint32_t pflash_size; + uint32_t nvm_base; + uint32_t nvm_size; /* whole FlexNVM */ + uint32_t dflash_size; /* accessible rest of FlexNVM if EEPROM backup uses part of FlexNVM */ + + uint32_t progr_accel_ram; + uint32_t sim_base; enum { FS_PROGRAM_SECTOR = 1, FS_PROGRAM_LONGWORD = 2, - FS_PROGRAM_PHRASE = 4, /* Unsupported */ - FS_INVALIDATE_CACHE_K = 8, - FS_INVALIDATE_CACHE_L = 0x10, + FS_PROGRAM_PHRASE = 4, /* Unsupported */ + + FS_NO_CMD_BLOCKSTAT = 0x40, + FS_WIDTH_256BIT = 0x80, } flash_support; + + enum { + KINETIS_CACHE_NONE, + KINETIS_CACHE_K, /* invalidate using FMC->PFB0CR/PFB01CR */ + KINETIS_CACHE_L, /* invalidate using MCM->PLACR */ + KINETIS_CACHE_MSCM, /* devices like KE1xF, invalidate MSCM->OCMDR0 */ + } cache_type; + + enum { + KINETIS_WDOG_NONE, + KINETIS_WDOG_K, + KINETIS_WDOG_COP, + KINETIS_WDOG32_KE1X, + KINETIS_WDOG32_KL28, + } watchdog_type; + + enum { + KINETIS_SMC, + KINETIS_SMC32, + } sysmodectrlr_type; + + char name[40]; + + unsigned num_banks; + struct kinetis_flash_bank banks[KINETIS_MAX_BANKS]; }; +struct kinetis_type { + uint32_t sdid; + char *name; +}; + +static const struct kinetis_type kinetis_types_old[] = { + { KINETIS_K_SDID_K10_M50, "MK10D%s5" }, + { KINETIS_K_SDID_K10_M72, "MK10D%s7" }, + { KINETIS_K_SDID_K10_M100, "MK10D%s10" }, + { KINETIS_K_SDID_K10_M120, "MK10F%s12" }, + { KINETIS_K_SDID_K11, "MK11D%s5" }, + { KINETIS_K_SDID_K12, "MK12D%s5" }, + + { KINETIS_K_SDID_K20_M50, "MK20D%s5" }, + { KINETIS_K_SDID_K20_M72, "MK20D%s7" }, + { KINETIS_K_SDID_K20_M100, "MK20D%s10" }, + { KINETIS_K_SDID_K20_M120, "MK20F%s12" }, + { KINETIS_K_SDID_K21_M50, "MK21D%s5" }, + { KINETIS_K_SDID_K21_M120, "MK21F%s12" }, + { KINETIS_K_SDID_K22_M50, "MK22D%s5" }, + { KINETIS_K_SDID_K22_M120, "MK22F%s12" }, + + { KINETIS_K_SDID_K30_M72, "MK30D%s7" }, + { KINETIS_K_SDID_K30_M100, "MK30D%s10" }, + + { KINETIS_K_SDID_K40_M72, "MK40D%s7" }, + { KINETIS_K_SDID_K40_M100, "MK40D%s10" }, + + { KINETIS_K_SDID_K50_M72, "MK50D%s7" }, + { KINETIS_K_SDID_K51_M72, "MK51D%s7" }, + { KINETIS_K_SDID_K53, "MK53D%s10" }, + + { KINETIS_K_SDID_K60_M100, "MK60D%s10" }, + { KINETIS_K_SDID_K60_M150, "MK60F%s15" }, + + { KINETIS_K_SDID_K70_M150, "MK70F%s15" }, +}; + + #define MDM_AP 1 #define MDM_REG_STAT 0x00 @@ -272,11 +388,13 @@ struct kinetis_flash_bank { static bool allow_fcf_writes; static uint8_t fcf_fopt = 0xff; +static bool create_banks; struct flash_driver kinetis_flash; static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count); +static int kinetis_probe_chip(struct kinetis_chip *k_chip); static int kinetis_auto_probe(struct flash_bank *bank); @@ -593,6 +711,7 @@ deassert_reset_and_exit: static const uint32_t kinetis_known_mdm_ids[] = { 0x001C0000, /* Kinetis-K Series */ 0x001C0020, /* Kinetis-L/M/V/E Series */ + 0x001C0030, /* Kinetis with a Cortex-M7, in time of writing KV58 */ }; /* @@ -715,29 +834,212 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) return ERROR_OK; } + +static struct kinetis_chip *kinetis_get_chip(struct target *target) +{ + struct flash_bank *bank_iter; + struct kinetis_flash_bank *k_bank; + + /* iterate over all kinetis banks */ + for (bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) { + if (bank_iter->driver != &kinetis_flash + || bank_iter->target != target) + continue; + + k_bank = bank_iter->driver_priv; + if (!k_bank) + continue; + + if (k_bank->k_chip) + return k_bank->k_chip; + } + return NULL; +} + +static int kinetis_chip_options(struct kinetis_chip *k_chip, int argc, const char *argv[]) +{ + int i; + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "-sim-base") == 0) { + if (i + 1 < argc) + k_chip->sim_base = strtoul(argv[++i], NULL, 0); + } else + LOG_ERROR("Unsupported flash bank option %s", argv[i]); + } + return ERROR_OK; +} + FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) { - struct kinetis_flash_bank *bank_info; + struct target *target = bank->target; + struct kinetis_chip *k_chip; + struct kinetis_flash_bank *k_bank; + int retval; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO("add flash_bank kinetis %s", bank->name); - bank_info = malloc(sizeof(struct kinetis_flash_bank)); + k_chip = kinetis_get_chip(target); - memset(bank_info, 0, sizeof(struct kinetis_flash_bank)); + if (k_chip == NULL) { + k_chip = calloc(sizeof(struct kinetis_chip), 1); + if (k_chip == NULL) { + LOG_ERROR("No memory"); + return ERROR_FAIL; + } - bank->driver_priv = bank_info; + k_chip->target = target; + + /* only the first defined bank can define chip options */ + retval = kinetis_chip_options(k_chip, CMD_ARGC - 6, CMD_ARGV + 6); + if (retval != ERROR_OK) + return retval; + } + + if (k_chip->num_banks >= KINETIS_MAX_BANKS) { + LOG_ERROR("Only %u Kinetis flash banks are supported", KINETIS_MAX_BANKS); + return ERROR_FAIL; + } + + bank->driver_priv = k_bank = &(k_chip->banks[k_chip->num_banks]); + k_bank->k_chip = k_chip; + k_bank->bank_number = k_chip->num_banks; + k_bank->bank = bank; + k_chip->num_banks++; return ERROR_OK; } -/* Disable the watchdog on Kinetis devices */ -int kinetis_disable_wdog(struct target *target, uint32_t sim_sdid) + +static int kinetis_create_missing_banks(struct kinetis_chip *k_chip) +{ + unsigned bank_idx; + unsigned num_blocks; + struct kinetis_flash_bank *k_bank; + struct flash_bank *bank; + char base_name[80], name[80], num[4]; + char *class, *p; + + num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; + if (num_blocks > KINETIS_MAX_BANKS) { + LOG_ERROR("Only %u Kinetis flash banks are supported", KINETIS_MAX_BANKS); + return ERROR_FAIL; + } + + bank = k_chip->banks[0].bank; + if (bank && bank->name) { + strncpy(base_name, bank->name, sizeof(base_name)); + p = strstr(base_name, ".pflash"); + if (p) { + *p = '\0'; + if (k_chip->num_pflash_blocks > 1) { + /* rename first bank if numbering is needed */ + snprintf(name, sizeof(name), "%s.pflash0", base_name); + free((void *)bank->name); + bank->name = strdup(name); + } + } + } else { + strncpy(base_name, target_name(k_chip->target), sizeof(base_name)); + p = strstr(base_name, ".cpu"); + if (p) + *p = '\0'; + } + + for (bank_idx = 1; bank_idx < num_blocks; bank_idx++) { + k_bank = &(k_chip->banks[bank_idx]); + bank = k_bank->bank; + + if (bank) + continue; + + num[0] = '\0'; + + if (bank_idx < k_chip->num_pflash_blocks) { + class = "pflash"; + if (k_chip->num_pflash_blocks > 1) + snprintf(num, sizeof(num), "%u", bank_idx); + } else { + class = "flexnvm"; + if (k_chip->num_nvm_blocks > 1) + snprintf(num, sizeof(num), "%u", + bank_idx - k_chip->num_pflash_blocks); + } + + bank = calloc(sizeof(struct flash_bank), 1); + if (bank == NULL) + return ERROR_FAIL; + + bank->target = k_chip->target; + bank->driver = &kinetis_flash; + bank->default_padded_value = bank->erased_value = 0xff; + + snprintf(name, sizeof(name), "%s.%s%s", + base_name, class, num); + bank->name = strdup(name); + + bank->driver_priv = k_bank = &(k_chip->banks[k_chip->num_banks]); + k_bank->k_chip = k_chip; + k_bank->bank_number = bank_idx; + k_bank->bank = bank; + if (k_chip->num_banks <= bank_idx) + k_chip->num_banks = bank_idx + 1; + + flash_bank_add(bank); + } + return ERROR_OK; +} + + +static int kinetis_disable_wdog_algo(struct target *target, size_t code_size, const uint8_t *code, uint32_t wdog_base) { struct working_area *wdog_algorithm; struct armv7m_algorithm armv7m_info; + struct reg_param reg_params[1]; + int retval; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = target_alloc_working_area(target, code_size, &wdog_algorithm); + if (retval != ERROR_OK) + return retval; + + retval = target_write_buffer(target, wdog_algorithm->address, + code_size, code); + if (retval == ERROR_OK) { + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN); + buf_set_u32(reg_params[0].value, 0, 32, wdog_base); + + retval = target_run_algorithm(target, 0, NULL, 1, reg_params, + wdog_algorithm->address, + wdog_algorithm->address + code_size - 2, + 500, &armv7m_info); + + destroy_reg_param(®_params[0]); + + if (retval != ERROR_OK) + LOG_ERROR("Error executing Kinetis WDOG unlock algorithm"); + } + + target_free_working_area(target, wdog_algorithm); + + return retval; +} + +/* Disable the watchdog on Kinetis devices + * Standard Kx WDOG peripheral checks timing and therefore requires to run algo. + */ +static int kinetis_disable_wdog_kx(struct target *target) +{ + const uint32_t wdog_base = WDOG_BASE; uint16_t wdog; int retval; @@ -745,14 +1047,7 @@ int kinetis_disable_wdog(struct target *target, uint32_t sim_sdid) #include "../../../contrib/loaders/watchdog/armv7m_kinetis_wdog.inc" }; - /* Decide whether the connected device needs watchdog disabling. - * Disable for all Kx and KVx devices, return if it is a KLx */ - - if ((sim_sdid & KINETIS_SDID_SERIESID_MASK) == KINETIS_SDID_SERIESID_KL) - return ERROR_OK; - - /* The connected device requires watchdog disabling. */ - retval = target_read_u16(target, WDOG_STCTRH, &wdog); + retval = target_read_u16(target, wdog_base + WDOG_STCTRLH_OFFSET, &wdog); if (retval != ERROR_OK) return retval; @@ -760,60 +1055,116 @@ int kinetis_disable_wdog(struct target *target, uint32_t sim_sdid) /* watchdog already disabled */ return ERROR_OK; } - LOG_INFO("Disabling Kinetis watchdog (initial WDOG_STCTRLH = 0x%x)", wdog); + LOG_INFO("Disabling Kinetis watchdog (initial WDOG_STCTRLH = 0x%04" PRIx16 ")", wdog); - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; + retval = kinetis_disable_wdog_algo(target, sizeof(kinetis_unlock_wdog_code), kinetis_unlock_wdog_code, wdog_base); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u16(target, wdog_base + WDOG_STCTRLH_OFFSET, &wdog); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("WDOG_STCTRLH = 0x%04" PRIx16, wdog); + return (wdog & 0x1) ? ERROR_FAIL : ERROR_OK; +} + +static int kinetis_disable_wdog32(struct target *target, uint32_t wdog_base) +{ + uint32_t wdog_cs; + int retval; + + static const uint8_t kinetis_unlock_wdog_code[] = { +#include "../../../contrib/loaders/watchdog/armv7m_kinetis_wdog32.inc" + }; + + retval = target_read_u32(target, wdog_base + WDOG32_CS_OFFSET, &wdog_cs); + if (retval != ERROR_OK) + return retval; + + if ((wdog_cs & 0x80) == 0) + return ERROR_OK; /* watchdog already disabled */ + + LOG_INFO("Disabling Kinetis watchdog (initial WDOG_CS 0x%08" PRIx32 ")", wdog_cs); + + retval = kinetis_disable_wdog_algo(target, sizeof(kinetis_unlock_wdog_code), kinetis_unlock_wdog_code, wdog_base); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, wdog_base + WDOG32_CS_OFFSET, &wdog_cs); + if (retval != ERROR_OK) + return retval; + + if ((wdog_cs & 0x80) == 0) + return ERROR_OK; /* watchdog disabled successfully */ + + LOG_ERROR("Cannot disable Kinetis watchdog (WDOG_CS 0x%08" PRIx32 "), issue 'reset init'", wdog_cs); + return ERROR_FAIL; +} + +static int kinetis_disable_wdog(struct kinetis_chip *k_chip) +{ + struct target *target = k_chip->target; + uint8_t sim_copc; + int retval; + + if (!k_chip->probed) { + retval = kinetis_probe_chip(k_chip); + if (retval != ERROR_OK) + return retval; } - retval = target_alloc_working_area(target, sizeof(kinetis_unlock_wdog_code), &wdog_algorithm); - if (retval != ERROR_OK) - return retval; + switch (k_chip->watchdog_type) { + case KINETIS_WDOG_K: + return kinetis_disable_wdog_kx(target); - retval = target_write_buffer(target, wdog_algorithm->address, - sizeof(kinetis_unlock_wdog_code), (uint8_t *)kinetis_unlock_wdog_code); - if (retval != ERROR_OK) { - target_free_working_area(target, wdog_algorithm); - return retval; + case KINETIS_WDOG_COP: + retval = target_read_u8(target, SIM_COPC, &sim_copc); + if (retval != ERROR_OK) + return retval; + + if ((sim_copc & 0xc) == 0) + return ERROR_OK; /* watchdog already disabled */ + + LOG_INFO("Disabling Kinetis watchdog (initial SIM_COPC 0x%02" PRIx8 ")", sim_copc); + retval = target_write_u8(target, SIM_COPC, sim_copc & ~0xc); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u8(target, SIM_COPC, &sim_copc); + if (retval != ERROR_OK) + return retval; + + if ((sim_copc & 0xc) == 0) + return ERROR_OK; /* watchdog disabled successfully */ + + LOG_ERROR("Cannot disable Kinetis watchdog (SIM_COPC 0x%02" PRIx8 "), issue 'reset init'", sim_copc); + return ERROR_FAIL; + + case KINETIS_WDOG32_KE1X: + return kinetis_disable_wdog32(target, WDOG32_KE1X); + + case KINETIS_WDOG32_KL28: + return kinetis_disable_wdog32(target, WDOG32_KL28); + + default: + return ERROR_OK; } - - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - - retval = target_run_algorithm(target, 0, NULL, 0, NULL, wdog_algorithm->address, - wdog_algorithm->address + (sizeof(kinetis_unlock_wdog_code) - 2), - 10000, &armv7m_info); - - if (retval != ERROR_OK) - LOG_ERROR("error executing kinetis wdog unlock algorithm"); - - retval = target_read_u16(target, WDOG_STCTRH, &wdog); - if (retval != ERROR_OK) - return retval; - LOG_INFO("WDOG_STCTRLH = 0x%x", wdog); - - target_free_working_area(target, wdog_algorithm); - - return retval; } COMMAND_HANDLER(kinetis_disable_wdog_handler) { int result; - uint32_t sim_sdid; struct target *target = get_current_target(CMD_CTX); + struct kinetis_chip *k_chip = kinetis_get_chip(target); + + if (k_chip == NULL) + return ERROR_FAIL; if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; - result = target_read_u32(target, SIM_SDID, &sim_sdid); - if (result != ERROR_OK) { - LOG_ERROR("Failed to read SIMSDID"); - return result; - } - - result = kinetis_disable_wdog(target, sim_sdid); + result = kinetis_disable_wdog(k_chip); return result; } @@ -839,6 +1190,12 @@ static int kinetis_ftfx_decode_error(uint8_t fstat) return ERROR_FLASH_OPERATION_FAILED; } +static int kinetis_ftfx_clear_error(struct target *target) +{ + /* reset error flags */ + return target_write_u8(target, FTFx_FSTAT, 0x70); +} + static int kinetis_ftfx_prepare(struct target *target) { @@ -861,7 +1218,7 @@ static int kinetis_ftfx_prepare(struct target *target) } if (fstat != 0x80) { /* reset error flags */ - result = target_write_u8(target, FTFx_FSTAT, 0x70); + result = kinetis_ftfx_clear_error(target); } return result; } @@ -879,8 +1236,8 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t buffer_size = 2048; /* Default minimum value */ struct working_area *write_algorithm; struct working_area *source; - struct kinetis_flash_bank *kinfo = bank->driver_priv; - uint32_t address = kinfo->prog_base + offset; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + uint32_t address = k_bank->prog_base + offset; uint32_t end_address; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; @@ -990,12 +1347,12 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last static int kinetis_protect_check(struct flash_bank *bank) { - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct kinetis_flash_bank *k_bank = bank->driver_priv; int result; int i, b; uint32_t fprot; - if (kinfo->flash_class == FC_PFLASH) { + if (k_bank->flash_class == FC_PFLASH) { /* read protection register */ result = target_read_u32(bank->target, FTFx_FPROT3, &fprot); @@ -1004,7 +1361,7 @@ static int kinetis_protect_check(struct flash_bank *bank) /* Every bit protects 1/32 of the full flash (not necessarily just this bank) */ - } else if (kinfo->flash_class == FC_FLEX_NVM) { + } else if (k_bank->flash_class == FC_FLEX_NVM) { uint8_t fdprot; /* read protection register */ @@ -1019,7 +1376,7 @@ static int kinetis_protect_check(struct flash_bank *bank) return ERROR_FLASH_BANK_INVALID; } - b = kinfo->protection_block; + b = k_bank->protection_block; for (i = 0; i < bank->num_prot_blocks; i++) { if ((fprot >> b) & 1) bank->prot_blocks[i].is_protected = 0; @@ -1039,10 +1396,13 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) uint8_t fsec = 0xfe; /* set MCU unsecure */ uint8_t fdprot = 0xff; int i; + unsigned bank_idx; + unsigned num_blocks; uint32_t pflash_bit; uint8_t dflash_bit; struct flash_bank *bank_iter; - struct kinetis_flash_bank *kinfo; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; memset(fcf, 0xff, FCF_SIZE); @@ -1051,18 +1411,19 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) /* iterate over all kinetis banks */ /* current bank is bank 0, it contains FCF */ - for (bank_iter = bank; bank_iter; bank_iter = bank_iter->next) { - if (bank_iter->driver != &kinetis_flash - || bank_iter->target != bank->target) + num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; + for (bank_idx = 0; bank_idx < num_blocks; bank_idx++) { + k_bank = &(k_chip->banks[bank_idx]); + bank_iter = k_bank->bank; + + if (bank_iter == NULL) { + LOG_WARNING("Missing bank %u configuration, FCF protection flags may be incomplette", bank_idx); continue; + } kinetis_auto_probe(bank_iter); - kinfo = bank->driver_priv; - if (!kinfo) - continue; - - if (kinfo->flash_class == FC_PFLASH) { + if (k_bank->flash_class == FC_PFLASH) { for (i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fprot &= ~pflash_bit; @@ -1070,7 +1431,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf) pflash_bit <<= 1; } - } else if (kinfo->flash_class == FC_FLEX_NVM) { + } else if (k_bank->flash_class == FC_FLEX_NVM) { for (i = 0; i < bank_iter->num_prot_blocks; i++) { if (bank_iter->prot_blocks[i].is_protected == 1) fdprot &= ~dflash_bit; @@ -1137,17 +1498,44 @@ static int kinetis_ftfx_command(struct target *target, uint8_t fcmd, uint32_t fa } -static int kinetis_check_run_mode(struct target *target) +static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat) +{ + int result; + uint32_t stat32; + struct target *target = k_chip->target; + + switch (k_chip->sysmodectrlr_type) { + case KINETIS_SMC: + result = target_read_u8(target, SMC_PMSTAT, pmstat); + return result; + + case KINETIS_SMC32: + result = target_read_u32(target, SMC32_PMSTAT, &stat32); + if (result == ERROR_OK) + *pmstat = stat32 & 0xff; + return result; + } + return ERROR_FAIL; +} + +static int kinetis_check_run_mode(struct kinetis_chip *k_chip) { int result, i; - uint8_t pmctrl, pmstat; + uint8_t pmstat; + struct target *target; + + if (k_chip == NULL) { + LOG_ERROR("Chip not probed."); + return ERROR_FAIL; + } + target = k_chip->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - result = target_read_u8(target, SMC_PMSTAT, &pmstat); + result = kinetis_read_pmstat(k_chip, &pmstat); if (result != ERROR_OK) return result; @@ -1157,13 +1545,21 @@ static int kinetis_check_run_mode(struct target *target) if (pmstat == PM_STAT_VLPR) { /* It is safe to switch from VLPR to RUN mode without changing clock */ LOG_INFO("Switching from VLPR to RUN mode."); - pmctrl = PM_CTRL_RUNM_RUN; - result = target_write_u8(target, SMC_PMCTRL, pmctrl); + + switch (k_chip->sysmodectrlr_type) { + case KINETIS_SMC: + result = target_write_u8(target, SMC_PMCTRL, PM_CTRL_RUNM_RUN); + break; + + case KINETIS_SMC32: + result = target_write_u32(target, SMC32_PMCTRL, PM_CTRL_RUNM_RUN); + break; + } if (result != ERROR_OK) return result; for (i = 100; i; i--) { - result = target_read_u8(target, SMC_PMSTAT, &pmstat); + result = kinetis_read_pmstat(k_chip, &pmstat); if (result != ERROR_OK) return result; @@ -1178,26 +1574,40 @@ static int kinetis_check_run_mode(struct target *target) } -static void kinetis_invalidate_flash_cache(struct flash_bank *bank) +static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip) { - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct target *target = k_chip->target; - if (kinfo->flash_support & FS_INVALIDATE_CACHE_K) - target_write_u8(bank->target, FMC_PFB01CR + 2, 0xf0); + switch (k_chip->cache_type) { + case KINETIS_CACHE_K: + target_write_u8(target, FMC_PFB01CR + 2, 0xf0); + /* Set CINV_WAY bits - request invalidate of all cache ways */ + /* FMC_PFB0CR has same address and CINV_WAY bits as FMC_PFB01CR */ + break; - else if (kinfo->flash_support & FS_INVALIDATE_CACHE_L) - target_write_u8(bank->target, MCM_PLACR + 1, 0x04); + case KINETIS_CACHE_L: + target_write_u8(target, MCM_PLACR + 1, 0x04); + /* set bit CFCC - Clear Flash Controller Cache */ + break; - return; + case KINETIS_CACHE_MSCM: + target_write_u32(target, MSCM_OCMDR0, 0x30); + /* disable data prefetch and flash speculate */ + break; + + default: + break; + } } static int kinetis_erase(struct flash_bank *bank, int first, int last) { int result, i; - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; - result = kinetis_check_run_mode(bank->target); + result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; @@ -1216,7 +1626,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) */ for (i = first; i <= last; i++) { /* set command and sector address */ - result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, kinfo->prog_base + bank->sectors[i].offset, + result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset, 0, 0, 0, 0, 0, 0, 0, 0, NULL); if (result != ERROR_OK) { @@ -1226,7 +1636,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) bank->sectors[i].is_erased = 1; - if (bank->base == 0 + if (k_bank->prog_base == 0 && bank->sectors[i].offset <= FCF_ADDRESS && bank->sectors[i].offset + bank->sectors[i].size > FCF_ADDRESS + FCF_SIZE) { if (allow_fcf_writes) { @@ -1244,7 +1654,7 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last) } } - kinetis_invalidate_flash_cache(bank); + kinetis_invalidate_flash_cache(k_bank->k_chip); return ERROR_OK; } @@ -1284,7 +1694,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer uint32_t offset, uint32_t count) { int result = ERROR_OK; - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; uint8_t *buffer_aligned = NULL; /* * Kinetis uses different terms for the granularity of @@ -1292,8 +1703,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer * the generic term "chunk". The largest possible * Kinetis "chunk" is 16 bytes (128 bits). */ - uint32_t prog_section_chunk_bytes = kinfo->sector_size >> 8; - uint32_t prog_size_bytes = kinfo->max_flash_prog_size; + uint32_t prog_section_chunk_bytes = k_bank->sector_size >> 8; + uint32_t prog_size_bytes = k_chip->max_flash_prog_size; while (count > 0) { uint32_t size = prog_size_bytes - offset % prog_size_bytes; @@ -1321,13 +1732,13 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer memset(buffer_aligned, 0xff, size_aligned); memcpy(buffer_aligned + align_begin, buffer, size); - result = target_write_memory(bank->target, FLEXRAM, + result = target_write_memory(bank->target, k_chip->progr_accel_ram, 4, size_aligned / 4, buffer_aligned); LOG_DEBUG("section @ %08" PRIx32 " aligned begin %" PRIu32 ", end %" PRIu32, bank->base + offset, align_begin, align_end); } else - result = target_write_memory(bank->target, FLEXRAM, + result = target_write_memory(bank->target, k_chip->progr_accel_ram, 4, size_aligned / 4, buffer); LOG_DEBUG("write section @ %08" PRIx32 " with length %" PRIu32 " bytes", @@ -1340,7 +1751,7 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer /* execute section-write command */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTWRITE, - kinfo->prog_base + offset - align_begin, + k_bank->prog_base + offset - align_begin, chunk_count>>8, chunk_count, 0, 0, 0, 0, 0, 0, &ftfx_fstat); @@ -1349,8 +1760,16 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer break; } - if (ftfx_fstat & 0x01) + if (ftfx_fstat & 0x01) { LOG_ERROR("Flash write error at %08" PRIx32, bank->base + offset); + if (k_bank->prog_base == 0 && offset == FCF_ADDRESS + FCF_SIZE + && (k_chip->flash_support & FS_WIDTH_256BIT)) { + LOG_ERROR("Flash write immediately after the end of Flash Config Field shows error"); + LOG_ERROR("because the flash memory is 256 bits wide (data were written correctly)."); + LOG_ERROR("Either change the linker script to add a gap of 16 bytes after FCF"); + LOG_ERROR("or set 'kinetis fcf_source write'"); + } + } buffer += size; offset += size; @@ -1366,9 +1785,10 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int result, fallback = 0; - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; - if (!(kinfo->flash_support & FS_PROGRAM_SECTOR)) { + if (!(k_chip->flash_support & FS_PROGRAM_SECTOR)) { /* fallback to longword write */ fallback = 1; LOG_INFO("This device supports Program Longword execution only."); @@ -1380,13 +1800,12 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, } } - LOG_DEBUG("flash write @08%" PRIx32, bank->base + offset); + LOG_DEBUG("flash write @ %08" PRIx32, bank->base + offset); if (fallback == 0) { /* program section command */ kinetis_write_sections(bank, buffer, offset, count); - } - else if (kinfo->flash_support & FS_PROGRAM_LONGWORD) { + } else if (k_chip->flash_support & FS_PROGRAM_LONGWORD) { /* program longword command, not supported in FTFE */ uint8_t *new_buffer = NULL; @@ -1413,7 +1832,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, uint32_t words_remaining = count / 4; - kinetis_disable_wdog(bank->target, kinfo->sim_sdid); + kinetis_disable_wdog(k_chip); /* try using a block write */ result = kinetis_write_block(bank, buffer, offset, words_remaining); @@ -1429,7 +1848,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, LOG_DEBUG("write longword @ %08" PRIx32, (uint32_t)(bank->base + offset)); - result = kinetis_ftfx_command(bank->target, FTFx_CMD_LWORDPROG, kinfo->prog_base + offset, + result = kinetis_ftfx_command(bank->target, FTFx_CMD_LWORDPROG, k_bank->prog_base + offset, buffer[3], buffer[2], buffer[1], buffer[0], 0, 0, 0, 0, &ftfx_fstat); @@ -1452,7 +1871,7 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer, return ERROR_FLASH_OPERATION_FAILED; } - kinetis_invalidate_flash_cache(bank); + kinetis_invalidate_flash_cache(k_chip); return result; } @@ -1463,8 +1882,10 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, int result; bool set_fcf = false; int sect = 0; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; - result = kinetis_check_run_mode(bank->target); + result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; @@ -1473,7 +1894,7 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, if (result != ERROR_OK) return result; - if (bank->base == 0 && !allow_fcf_writes) { + if (k_bank->prog_base == 0 && !allow_fcf_writes) { if (bank->sectors[1].offset <= FCF_ADDRESS) sect = 1; /* 1kb sector, FCF in 2nd sector */ @@ -1495,7 +1916,7 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, return result; } - result = target_read_memory(bank->target, FCF_ADDRESS, 4, FCF_SIZE / 4, fcf_current); + result = target_read_memory(bank->target, bank->base + FCF_ADDRESS, 4, FCF_SIZE / 4, fcf_current); if (result == ERROR_OK && memcmp(fcf_current, fcf_buffer, FCF_SIZE) == 0) set_fcf = false; @@ -1522,35 +1943,62 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, } -static int kinetis_probe(struct flash_bank *bank) +static int kinetis_probe_chip(struct kinetis_chip *k_chip) { - int result, i; + int result; uint8_t fcfg1_nvmsize, fcfg1_pfsize, fcfg1_eesize, fcfg1_depart; - uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1; - uint32_t nvm_size = 0, pf_size = 0, df_size = 0, ee_size = 0; - unsigned num_blocks = 0, num_pflash_blocks = 0, num_nvm_blocks = 0, first_nvm_bank = 0, - pflash_sector_size_bytes = 0, nvm_sector_size_bytes = 0; - struct target *target = bank->target; - struct kinetis_flash_bank *kinfo = bank->driver_priv; + uint8_t fcfg2_pflsh; + uint32_t ee_size = 0; + uint32_t pflash_size_k, nvm_size_k, dflash_size_k; + uint32_t pflash_size_m; + unsigned num_blocks = 0; + unsigned maxaddr_shift = 13; + struct target *target = k_chip->target; - kinfo->probed = false; + unsigned familyid = 0, subfamid = 0; + unsigned cpu_mhz = 120; + unsigned idx; + bool use_nvm_marking = false; + char flash_marking[8], nvm_marking[2]; + char name[40]; - result = target_read_u32(target, SIM_SDID, &kinfo->sim_sdid); + k_chip->probed = false; + k_chip->pflash_sector_size = 0; + k_chip->pflash_base = 0; + k_chip->nvm_base = 0x10000000; + k_chip->progr_accel_ram = FLEXRAM; + + name[0] = '\0'; + + if (k_chip->sim_base) + result = target_read_u32(target, k_chip->sim_base + SIM_SDID_OFFSET, &k_chip->sim_sdid); + else { + result = target_read_u32(target, SIM_BASE + SIM_SDID_OFFSET, &k_chip->sim_sdid); + if (result == ERROR_OK) + k_chip->sim_base = SIM_BASE; + else { + result = target_read_u32(target, SIM_BASE_KL28 + SIM_SDID_OFFSET, &k_chip->sim_sdid); + if (result == ERROR_OK) + k_chip->sim_base = SIM_BASE_KL28; + } + } if (result != ERROR_OK) return result; - if ((kinfo->sim_sdid & (~KINETIS_SDID_K_SERIES_MASK)) == 0) { + if ((k_chip->sim_sdid & (~KINETIS_SDID_K_SERIES_MASK)) == 0) { /* older K-series MCU */ - uint32_t mcu_type = kinfo->sim_sdid & KINETIS_K_SDID_TYPE_MASK; + uint32_t mcu_type = k_chip->sim_sdid & KINETIS_K_SDID_TYPE_MASK; + k_chip->cache_type = KINETIS_CACHE_K; + k_chip->watchdog_type = KINETIS_WDOG_K; switch (mcu_type) { case KINETIS_K_SDID_K10_M50: case KINETIS_K_SDID_K20_M50: /* 1kB sectors */ - pflash_sector_size_bytes = 1<<10; - nvm_sector_size_bytes = 1<<10; + k_chip->pflash_sector_size = 1<<10; + k_chip->nvm_sector_size = 1<<10; num_blocks = 2; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR; break; case KINETIS_K_SDID_K10_M72: case KINETIS_K_SDID_K20_M72: @@ -1560,11 +2008,11 @@ static int kinetis_probe(struct flash_bank *bank) case KINETIS_K_SDID_K40_M100: case KINETIS_K_SDID_K50_M72: /* 2kB sectors, 1kB FlexNVM sectors */ - pflash_sector_size_bytes = 2<<10; - nvm_sector_size_bytes = 1<<10; + k_chip->pflash_sector_size = 2<<10; + k_chip->nvm_sector_size = 1<<10; num_blocks = 2; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; - kinfo->max_flash_prog_size = 1<<10; + k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR; + k_chip->max_flash_prog_size = 1<<10; break; case KINETIS_K_SDID_K10_M100: case KINETIS_K_SDID_K20_M100: @@ -1576,171 +2024,335 @@ static int kinetis_probe(struct flash_bank *bank) case KINETIS_K_SDID_K53: case KINETIS_K_SDID_K60_M100: /* 2kB sectors */ - pflash_sector_size_bytes = 2<<10; - nvm_sector_size_bytes = 2<<10; + k_chip->pflash_sector_size = 2<<10; + k_chip->nvm_sector_size = 2<<10; num_blocks = 2; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_PROGRAM_SECTOR; break; case KINETIS_K_SDID_K21_M120: case KINETIS_K_SDID_K22_M120: /* 4kB sectors (MK21FN1M0, MK21FX512, MK22FN1M0, MK22FX512) */ - pflash_sector_size_bytes = 4<<10; - kinfo->max_flash_prog_size = 1<<10; - nvm_sector_size_bytes = 4<<10; + k_chip->pflash_sector_size = 4<<10; + k_chip->max_flash_prog_size = 1<<10; + k_chip->nvm_sector_size = 4<<10; num_blocks = 2; - kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; break; case KINETIS_K_SDID_K10_M120: case KINETIS_K_SDID_K20_M120: case KINETIS_K_SDID_K60_M150: case KINETIS_K_SDID_K70_M150: /* 4kB sectors */ - pflash_sector_size_bytes = 4<<10; - nvm_sector_size_bytes = 4<<10; + k_chip->pflash_sector_size = 4<<10; + k_chip->nvm_sector_size = 4<<10; num_blocks = 4; - kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; break; default: LOG_ERROR("Unsupported K-family FAMID"); } + + for (idx = 0; idx < ARRAY_SIZE(kinetis_types_old); idx++) { + if (kinetis_types_old[idx].sdid == mcu_type) { + strcpy(name, kinetis_types_old[idx].name); + use_nvm_marking = true; + break; + } + } + } else { /* Newer K-series or KL series MCU */ - switch (kinfo->sim_sdid & KINETIS_SDID_SERIESID_MASK) { + familyid = (k_chip->sim_sdid & KINETIS_SDID_FAMILYID_MASK) >> KINETIS_SDID_FAMILYID_SHIFT; + subfamid = (k_chip->sim_sdid & KINETIS_SDID_SUBFAMID_MASK) >> KINETIS_SDID_SUBFAMID_SHIFT; + + switch (k_chip->sim_sdid & KINETIS_SDID_SERIESID_MASK) { case KINETIS_SDID_SERIESID_K: - switch (kinfo->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { + use_nvm_marking = true; + k_chip->cache_type = KINETIS_CACHE_K; + k_chip->watchdog_type = KINETIS_WDOG_K; + + switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { case KINETIS_SDID_FAMILYID_K0X | KINETIS_SDID_SUBFAMID_KX2: /* K02FN64, K02FN128: FTFA, 2kB sectors */ - pflash_sector_size_bytes = 2<<10; + k_chip->pflash_sector_size = 2<<10; num_blocks = 1; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD; + cpu_mhz = 100; break; case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX2: { /* MK24FN1M reports as K22, this should detect it (according to errata note 1N83J) */ uint32_t sopt1; - result = target_read_u32(target, SIM_SOPT1, &sopt1); + result = target_read_u32(target, k_chip->sim_base + SIM_SOPT1_OFFSET, &sopt1); if (result != ERROR_OK) return result; - if (((kinfo->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN1M) && + if (((k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN1M) && ((sopt1 & KINETIS_SOPT1_RAMSIZE_MASK) == KINETIS_SOPT1_RAMSIZE_K24FN1M)) { /* MK24FN1M */ - pflash_sector_size_bytes = 4<<10; + k_chip->pflash_sector_size = 4<<10; num_blocks = 2; - kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; - kinfo->max_flash_prog_size = 1<<10; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + k_chip->max_flash_prog_size = 1<<10; + subfamid = 4; /* errata 1N83J fix */ break; } - if ((kinfo->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN128 - || (kinfo->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN256 - || (kinfo->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN512) { + if ((k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN128 + || (k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN256 + || (k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K22FN512) { /* K22 with new-style SDID - smaller pflash with FTFA, 2kB sectors */ - pflash_sector_size_bytes = 2<<10; + k_chip->pflash_sector_size = 2<<10; /* autodetect 1 or 2 blocks */ - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD; break; } LOG_ERROR("Unsupported Kinetis K22 DIEID"); break; } case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX4: - pflash_sector_size_bytes = 4<<10; - if ((kinfo->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN256) { + k_chip->pflash_sector_size = 4<<10; + if ((k_chip->sim_sdid & (KINETIS_SDID_DIEID_MASK)) == KINETIS_SDID_DIEID_K24FN256) { /* K24FN256 - smaller pflash with FTFA */ num_blocks = 1; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD; break; } /* K24FN1M without errata 7534 */ num_blocks = 2; - kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; - kinfo->max_flash_prog_size = 1<<10; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + k_chip->max_flash_prog_size = 1<<10; break; - case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX3: case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX1: /* errata 7534 - should be K63 */ + case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX2: /* errata 7534 - should be K64 */ + subfamid += 2; /* errata 7534 fix */ + case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX3: /* K63FN1M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX4: - case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX2: /* errata 7534 - should be K64 */ /* K64FN1M0, K64FX512 */ - pflash_sector_size_bytes = 4<<10; - nvm_sector_size_bytes = 4<<10; - kinfo->max_flash_prog_size = 1<<10; + k_chip->pflash_sector_size = 4<<10; + k_chip->nvm_sector_size = 4<<10; + k_chip->max_flash_prog_size = 1<<10; num_blocks = 2; - kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; break; case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX6: /* K26FN2M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX6: /* K66FN2M0, K66FX1M0 */ - pflash_sector_size_bytes = 4<<10; - nvm_sector_size_bytes = 4<<10; - kinfo->max_flash_prog_size = 1<<10; + k_chip->pflash_sector_size = 4<<10; + k_chip->nvm_sector_size = 4<<10; + k_chip->max_flash_prog_size = 1<<10; num_blocks = 4; - kinfo->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + cpu_mhz = 180; break; case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX0: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX1: case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX2: /* K80FN256, K81FN256, K82FN256 */ - pflash_sector_size_bytes = 4<<10; + k_chip->pflash_sector_size = 4<<10; num_blocks = 1; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_NO_CMD_BLOCKSTAT; + cpu_mhz = 150; + break; + + case KINETIS_SDID_FAMILYID_KL8X | KINETIS_SDID_SUBFAMID_KX1: + case KINETIS_SDID_FAMILYID_KL8X | KINETIS_SDID_SUBFAMID_KX2: + /* KL81Z128, KL82Z128 */ + k_chip->pflash_sector_size = 2<<10; + num_blocks = 1; + k_chip->flash_support = FS_PROGRAM_LONGWORD | FS_NO_CMD_BLOCKSTAT; + k_chip->cache_type = KINETIS_CACHE_L; + + use_nvm_marking = false; + snprintf(name, sizeof(name), "MKL8%uZ%%s7", + subfamid); break; default: LOG_ERROR("Unsupported Kinetis FAMILYID SUBFAMID"); } + + if (name[0] == '\0') + snprintf(name, sizeof(name), "MK%u%uF%%s%u", + familyid, subfamid, cpu_mhz / 10); break; case KINETIS_SDID_SERIESID_KL: /* KL-series */ - pflash_sector_size_bytes = 1<<10; - nvm_sector_size_bytes = 1<<10; + k_chip->pflash_sector_size = 1<<10; + k_chip->nvm_sector_size = 1<<10; /* autodetect 1 or 2 blocks */ - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L; + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_L; + k_chip->watchdog_type = KINETIS_WDOG_COP; + + cpu_mhz = 48; + switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX3: + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX3: + subfamid = 7; + break; + + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX8: + cpu_mhz = 72; + k_chip->pflash_sector_size = 2<<10; + num_blocks = 2; + k_chip->watchdog_type = KINETIS_WDOG32_KL28; + k_chip->sysmodectrlr_type = KINETIS_SMC32; + break; + } + + snprintf(name, sizeof(name), "MKL%u%uZ%%s%u", + familyid, subfamid, cpu_mhz / 10); + break; + + case KINETIS_SDID_SERIESID_KW: + /* Newer KW-series (all KW series except KW2xD, KW01Z) */ + cpu_mhz = 48; + switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { + case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX0: + /* KW40Z */ + case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX0: + /* KW30Z */ + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX0: + /* KW20Z */ + /* FTFA, 1kB sectors */ + k_chip->pflash_sector_size = 1<<10; + k_chip->nvm_sector_size = 1<<10; + /* autodetect 1 or 2 blocks */ + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_L; + k_chip->watchdog_type = KINETIS_WDOG_COP; + break; + case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX1: + /* KW41Z */ + case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX1: + /* KW31Z */ + case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX1: + /* KW21Z */ + /* FTFA, 2kB sectors */ + k_chip->pflash_sector_size = 2<<10; + k_chip->nvm_sector_size = 2<<10; + /* autodetect 1 or 2 blocks */ + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_L; + k_chip->watchdog_type = KINETIS_WDOG_COP; + break; + default: + LOG_ERROR("Unsupported KW FAMILYID SUBFAMID"); + } + snprintf(name, sizeof(name), "MKW%u%uZ%%s%u", + familyid, subfamid, cpu_mhz / 10); break; case KINETIS_SDID_SERIESID_KV: /* KV-series */ - switch (kinfo->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { + k_chip->watchdog_type = KINETIS_WDOG_K; + switch (k_chip->sim_sdid & (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK)) { case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX0: /* KV10: FTFA, 1kB sectors */ - pflash_sector_size_bytes = 1<<10; + k_chip->pflash_sector_size = 1<<10; num_blocks = 1; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L; + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_L; + strcpy(name, "MKV10Z%s7"); break; case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX1: /* KV11: FTFA, 2kB sectors */ - pflash_sector_size_bytes = 2<<10; + k_chip->pflash_sector_size = 2<<10; num_blocks = 1; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_L; + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_L; + strcpy(name, "MKV11Z%s7"); break; case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX0: /* KV30: FTFA, 2kB sectors, 1 block */ case KINETIS_SDID_FAMILYID_K3X | KINETIS_SDID_SUBFAMID_KX1: /* KV31: FTFA, 2kB sectors, 2 blocks */ - pflash_sector_size_bytes = 2<<10; + k_chip->pflash_sector_size = 2<<10; /* autodetect 1 or 2 blocks */ - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_K; break; case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX2: case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX4: case KINETIS_SDID_FAMILYID_K4X | KINETIS_SDID_SUBFAMID_KX6: /* KV4x: FTFA, 4kB sectors */ - pflash_sector_size_bytes = 4<<10; + k_chip->pflash_sector_size = 4<<10; num_blocks = 1; - kinfo->flash_support = FS_PROGRAM_LONGWORD | FS_INVALIDATE_CACHE_K; + k_chip->flash_support = FS_PROGRAM_LONGWORD; + k_chip->cache_type = KINETIS_CACHE_K; + cpu_mhz = 168; + break; + + case KINETIS_SDID_FAMILYID_K5X | KINETIS_SDID_SUBFAMID_KX6: + case KINETIS_SDID_FAMILYID_K5X | KINETIS_SDID_SUBFAMID_KX8: + /* KV5x: FTFE, 8kB sectors */ + k_chip->pflash_sector_size = 8<<10; + k_chip->max_flash_prog_size = 1<<10; + num_blocks = 1; + maxaddr_shift = 14; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT; + k_chip->pflash_base = 0x10000000; + k_chip->progr_accel_ram = 0x18000000; + cpu_mhz = 240; break; default: LOG_ERROR("Unsupported KV FAMILYID SUBFAMID"); } + + if (name[0] == '\0') + snprintf(name, sizeof(name), "MKV%u%uF%%s%u", + familyid, subfamid, cpu_mhz / 10); + break; + + case KINETIS_SDID_SERIESID_KE: + /* KE1x-series */ + k_chip->watchdog_type = KINETIS_WDOG32_KE1X; + switch (k_chip->sim_sdid & + (KINETIS_SDID_FAMILYID_MASK | KINETIS_SDID_SUBFAMID_MASK | KINETIS_SDID_PROJECTID_MASK)) { + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1xZ: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX5 | KINETIS_SDID_PROJECTID_KE1xZ: + /* KE1xZ: FTFE, 2kB sectors */ + k_chip->pflash_sector_size = 2<<10; + k_chip->nvm_sector_size = 2<<10; + k_chip->max_flash_prog_size = 1<<9; + num_blocks = 2; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + k_chip->cache_type = KINETIS_CACHE_L; + + cpu_mhz = 72; + snprintf(name, sizeof(name), "MKE%u%uZ%%s%u", + familyid, subfamid, cpu_mhz / 10); + break; + + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX4 | KINETIS_SDID_PROJECTID_KE1xF: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX6 | KINETIS_SDID_PROJECTID_KE1xF: + case KINETIS_SDID_FAMILYID_K1X | KINETIS_SDID_SUBFAMID_KX8 | KINETIS_SDID_PROJECTID_KE1xF: + /* KE1xF: FTFE, 4kB sectors */ + k_chip->pflash_sector_size = 4<<10; + k_chip->nvm_sector_size = 2<<10; + k_chip->max_flash_prog_size = 1<<10; + num_blocks = 2; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + k_chip->cache_type = KINETIS_CACHE_MSCM; + + cpu_mhz = 168; + snprintf(name, sizeof(name), "MKE%u%uF%%s%u", + familyid, subfamid, cpu_mhz / 10); + break; + + default: + LOG_ERROR("Unsupported KE FAMILYID SUBFAMID"); + } break; default: @@ -1748,37 +2360,39 @@ static int kinetis_probe(struct flash_bank *bank) } } - if (pflash_sector_size_bytes == 0) { - LOG_ERROR("MCU is unsupported, SDID 0x%08" PRIx32, kinfo->sim_sdid); + if (k_chip->pflash_sector_size == 0) { + LOG_ERROR("MCU is unsupported, SDID 0x%08" PRIx32, k_chip->sim_sdid); return ERROR_FLASH_OPER_UNSUPPORTED; } - result = target_read_u32(target, SIM_FCFG1, &kinfo->sim_fcfg1); + result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &k_chip->sim_fcfg1); if (result != ERROR_OK) return result; - result = target_read_u32(target, SIM_FCFG2, &kinfo->sim_fcfg2); + result = target_read_u32(target, k_chip->sim_base + SIM_FCFG2_OFFSET, &k_chip->sim_fcfg2); if (result != ERROR_OK) return result; - LOG_DEBUG("SDID: 0x%08" PRIX32 " FCFG1: 0x%08" PRIX32 " FCFG2: 0x%08" PRIX32, kinfo->sim_sdid, - kinfo->sim_fcfg1, kinfo->sim_fcfg2); + LOG_DEBUG("SDID: 0x%08" PRIX32 " FCFG1: 0x%08" PRIX32 " FCFG2: 0x%08" PRIX32, k_chip->sim_sdid, + k_chip->sim_fcfg1, k_chip->sim_fcfg2); - fcfg1_nvmsize = (uint8_t)((kinfo->sim_fcfg1 >> 28) & 0x0f); - fcfg1_pfsize = (uint8_t)((kinfo->sim_fcfg1 >> 24) & 0x0f); - fcfg1_eesize = (uint8_t)((kinfo->sim_fcfg1 >> 16) & 0x0f); - fcfg1_depart = (uint8_t)((kinfo->sim_fcfg1 >> 8) & 0x0f); + fcfg1_nvmsize = (uint8_t)((k_chip->sim_fcfg1 >> 28) & 0x0f); + fcfg1_pfsize = (uint8_t)((k_chip->sim_fcfg1 >> 24) & 0x0f); + fcfg1_eesize = (uint8_t)((k_chip->sim_fcfg1 >> 16) & 0x0f); + fcfg1_depart = (uint8_t)((k_chip->sim_fcfg1 >> 8) & 0x0f); - fcfg2_pflsh = (uint8_t)((kinfo->sim_fcfg2 >> 23) & 0x01); - fcfg2_maxaddr0 = (uint8_t)((kinfo->sim_fcfg2 >> 24) & 0x7f); - fcfg2_maxaddr1 = (uint8_t)((kinfo->sim_fcfg2 >> 16) & 0x7f); + fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01); + k_chip->fcfg2_maxaddr0_shifted = ((k_chip->sim_fcfg2 >> 24) & 0x7f) << maxaddr_shift; + k_chip->fcfg2_maxaddr1_shifted = ((k_chip->sim_fcfg2 >> 16) & 0x7f) << maxaddr_shift; if (num_blocks == 0) - num_blocks = fcfg2_maxaddr1 ? 2 : 1; - else if (fcfg2_maxaddr1 == 0 && num_blocks >= 2) { + num_blocks = k_chip->fcfg2_maxaddr1_shifted ? 2 : 1; + else if (k_chip->fcfg2_maxaddr1_shifted == 0 && num_blocks >= 2 && fcfg2_pflsh) { + /* fcfg2_maxaddr1 may be zero due to partitioning whole NVM as EEPROM backup + * Do not adjust block count in this case! */ num_blocks = 1; LOG_WARNING("MAXADDR1 is zero, number of flash banks adjusted to 1"); - } else if (fcfg2_maxaddr1 != 0 && num_blocks == 1) { + } else if (k_chip->fcfg2_maxaddr1_shifted != 0 && num_blocks == 1) { num_blocks = 2; LOG_WARNING("MAXADDR1 is non zero, number of flash banks adjusted to 2"); } @@ -1791,17 +2405,17 @@ static int kinetis_probe(struct flash_bank *bank) case 0x07: case 0x09: case 0x0b: - nvm_size = 1 << (14 + (fcfg1_nvmsize >> 1)); + k_chip->nvm_size = 1 << (14 + (fcfg1_nvmsize >> 1)); break; case 0x0f: - if (pflash_sector_size_bytes >= 4<<10) - nvm_size = 512<<10; + if (k_chip->pflash_sector_size >= 4<<10) + k_chip->nvm_size = 512<<10; else /* K20_100 */ - nvm_size = 256<<10; + k_chip->nvm_size = 256<<10; break; default: - nvm_size = 0; + k_chip->nvm_size = 0; break; } @@ -1830,136 +2444,204 @@ static int kinetis_probe(struct flash_bank *bank) case 0x04: case 0x05: case 0x06: - df_size = nvm_size - (4096 << fcfg1_depart); + k_chip->dflash_size = k_chip->nvm_size - (4096 << fcfg1_depart); break; + case 0x07: case 0x08: - df_size = 0; + k_chip->dflash_size = 0; break; case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: - df_size = 4096 << (fcfg1_depart & 0x7); + k_chip->dflash_size = 4096 << (fcfg1_depart & 0x7); break; default: - df_size = nvm_size; + k_chip->dflash_size = k_chip->nvm_size; break; } } switch (fcfg1_pfsize) { + case 0x00: + k_chip->pflash_size = 8192; + break; + case 0x01: case 0x03: case 0x05: case 0x07: case 0x09: case 0x0b: case 0x0d: - pf_size = 1 << (14 + (fcfg1_pfsize >> 1)); + k_chip->pflash_size = 1 << (14 + (fcfg1_pfsize >> 1)); break; case 0x0f: /* a peculiar case: Freescale states different sizes for 0xf + * KL03P24M48SF0RM 32 KB .... duplicate of code 0x3 * K02P64M100SFARM 128 KB ... duplicate of code 0x7 * K22P121M120SF8RM 256 KB ... duplicate of code 0x9 * K22P121M120SF7RM 512 KB ... duplicate of code 0xb * K22P100M120SF5RM 1024 KB ... duplicate of code 0xd * K26P169M180SF5RM 2048 KB ... the only unique value - * fcfg2_maxaddr0 seems to be the only clue to pf_size - * Checking fcfg2_maxaddr0 later in this routine is pointless then + * fcfg2_maxaddr0 seems to be the only clue to pflash_size + * Checking fcfg2_maxaddr0 in bank probe is pointless then */ if (fcfg2_pflsh) - pf_size = ((uint32_t)fcfg2_maxaddr0 << 13) * num_blocks; + k_chip->pflash_size = k_chip->fcfg2_maxaddr0_shifted * num_blocks; else - pf_size = ((uint32_t)fcfg2_maxaddr0 << 13) * num_blocks / 2; - if (pf_size != 2048<<10) - LOG_WARNING("SIM_FCFG1 PFSIZE = 0xf: please check if pflash is %u KB", pf_size>>10); + k_chip->pflash_size = k_chip->fcfg2_maxaddr0_shifted * num_blocks / 2; + if (k_chip->pflash_size != 2048<<10) + LOG_WARNING("SIM_FCFG1 PFSIZE = 0xf: please check if pflash is %u KB", k_chip->pflash_size>>10); break; default: - pf_size = 0; + k_chip->pflash_size = 0; break; } - LOG_DEBUG("FlexNVM: %" PRIu32 " PFlash: %" PRIu32 " FlexRAM: %" PRIu32 " PFLSH: %d", - nvm_size, pf_size, ee_size, fcfg2_pflsh); + if (k_chip->flash_support & FS_PROGRAM_SECTOR && k_chip->max_flash_prog_size == 0) { + k_chip->max_flash_prog_size = k_chip->pflash_sector_size; + /* Program section size is equal to sector size by default */ + } - num_pflash_blocks = num_blocks / (2 - fcfg2_pflsh); - first_nvm_bank = num_pflash_blocks; - num_nvm_blocks = num_blocks - num_pflash_blocks; + if (fcfg2_pflsh) { + k_chip->num_pflash_blocks = num_blocks; + k_chip->num_nvm_blocks = 0; + } else { + k_chip->num_pflash_blocks = (num_blocks + 1) / 2; + k_chip->num_nvm_blocks = num_blocks - k_chip->num_pflash_blocks; + } - LOG_DEBUG("%d blocks total: %d PFlash, %d FlexNVM", - num_blocks, num_pflash_blocks, num_nvm_blocks); + if (use_nvm_marking) { + nvm_marking[0] = k_chip->num_nvm_blocks ? 'X' : 'N'; + nvm_marking[1] = '\0'; + } else + nvm_marking[0] = '\0'; - LOG_INFO("Probing flash info for bank %d", bank->bank_number); + pflash_size_k = k_chip->pflash_size / 1024; + pflash_size_m = pflash_size_k / 1024; + if (pflash_size_m) + snprintf(flash_marking, sizeof(flash_marking), "%s%" PRIu32 "M0xxx", nvm_marking, pflash_size_m); + else + snprintf(flash_marking, sizeof(flash_marking), "%s%" PRIu32 "xxx", nvm_marking, pflash_size_k); - if ((unsigned)bank->bank_number < num_pflash_blocks) { + snprintf(k_chip->name, sizeof(k_chip->name), name, flash_marking); + LOG_INFO("Kinetis %s detected: %u flash blocks", k_chip->name, num_blocks); + LOG_INFO("%u PFlash banks: %" PRIu32 "k total", k_chip->num_pflash_blocks, pflash_size_k); + if (k_chip->num_nvm_blocks) { + nvm_size_k = k_chip->nvm_size / 1024; + dflash_size_k = k_chip->dflash_size / 1024; + LOG_INFO("%u FlexNVM banks: %" PRIu32 "k total, %" PRIu32 "k available as data flash, %" PRIu32 "bytes FlexRAM", + k_chip->num_nvm_blocks, nvm_size_k, dflash_size_k, ee_size); + } + + k_chip->probed = true; + + if (create_banks) + kinetis_create_missing_banks(k_chip); + + return ERROR_OK; +} + +static int kinetis_probe(struct flash_bank *bank) +{ + int result, i; + uint8_t fcfg2_maxaddr0, fcfg2_pflsh, fcfg2_maxaddr1; + unsigned num_blocks, first_nvm_bank; + uint32_t size_k; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; + + k_bank->probed = false; + + if (!k_chip->probed) { + result = kinetis_probe_chip(k_chip); + if (result != ERROR_OK) + return result; + } + + num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; + first_nvm_bank = k_chip->num_pflash_blocks; + + if (k_bank->bank_number < k_chip->num_pflash_blocks) { /* pflash, banks start at address zero */ - kinfo->flash_class = FC_PFLASH; - bank->size = (pf_size / num_pflash_blocks); - bank->base = 0x00000000 + bank->size * bank->bank_number; - kinfo->prog_base = bank->base; - kinfo->sector_size = pflash_sector_size_bytes; + k_bank->flash_class = FC_PFLASH; + bank->size = (k_chip->pflash_size / k_chip->num_pflash_blocks); + bank->base = k_chip->pflash_base + bank->size * k_bank->bank_number; + k_bank->prog_base = 0x00000000 + bank->size * k_bank->bank_number; + k_bank->sector_size = k_chip->pflash_sector_size; /* pflash is divided into 32 protection areas for * parts with more than 32K of PFlash. For parts with * less the protection unit is set to 1024 bytes */ - kinfo->protection_size = MAX(pf_size / 32, 1024); - bank->num_prot_blocks = 32 / num_pflash_blocks; - kinfo->protection_block = bank->num_prot_blocks * bank->bank_number; + k_bank->protection_size = MAX(k_chip->pflash_size / 32, 1024); + bank->num_prot_blocks = bank->size / k_bank->protection_size; + k_bank->protection_block = bank->num_prot_blocks * k_bank->bank_number; - } else if ((unsigned)bank->bank_number < num_blocks) { + size_k = bank->size / 1024; + LOG_DEBUG("Kinetis bank %u: %" PRIu32 "k PFlash, FTFx base 0x%08" PRIx32 ", sect %u", + k_bank->bank_number, size_k, k_bank->prog_base, k_bank->sector_size); + + } else if (k_bank->bank_number < num_blocks) { /* nvm, banks start at address 0x10000000 */ - unsigned nvm_ord = bank->bank_number - first_nvm_bank; + unsigned nvm_ord = k_bank->bank_number - first_nvm_bank; uint32_t limit; - kinfo->flash_class = FC_FLEX_NVM; - bank->size = (nvm_size / num_nvm_blocks); - bank->base = 0x10000000 + bank->size * nvm_ord; - kinfo->prog_base = 0x00800000 + bank->size * nvm_ord; - kinfo->sector_size = nvm_sector_size_bytes; - if (df_size == 0) { - kinfo->protection_size = 0; + k_bank->flash_class = FC_FLEX_NVM; + bank->size = k_chip->nvm_size / k_chip->num_nvm_blocks; + bank->base = k_chip->nvm_base + bank->size * nvm_ord; + k_bank->prog_base = 0x00800000 + bank->size * nvm_ord; + k_bank->sector_size = k_chip->nvm_sector_size; + if (k_chip->dflash_size == 0) { + k_bank->protection_size = 0; } else { - for (i = df_size; ~i & 1; i >>= 1) + for (i = k_chip->dflash_size; ~i & 1; i >>= 1) ; if (i == 1) - kinfo->protection_size = df_size / 8; /* data flash size = 2^^n */ + k_bank->protection_size = k_chip->dflash_size / 8; /* data flash size = 2^^n */ else - kinfo->protection_size = nvm_size / 8; /* TODO: verify on SF1, not documented in RM */ + k_bank->protection_size = k_chip->nvm_size / 8; /* TODO: verify on SF1, not documented in RM */ } - bank->num_prot_blocks = 8 / num_nvm_blocks; - kinfo->protection_block = bank->num_prot_blocks * nvm_ord; + bank->num_prot_blocks = 8 / k_chip->num_nvm_blocks; + k_bank->protection_block = bank->num_prot_blocks * nvm_ord; - /* EEPROM backup part of FlexNVM is not accessible, use df_size as a limit */ - if (df_size > bank->size * nvm_ord) - limit = df_size - bank->size * nvm_ord; + /* EEPROM backup part of FlexNVM is not accessible, use dflash_size as a limit */ + if (k_chip->dflash_size > bank->size * nvm_ord) + limit = k_chip->dflash_size - bank->size * nvm_ord; else limit = 0; if (bank->size > limit) { bank->size = limit; LOG_DEBUG("FlexNVM bank %d limited to 0x%08" PRIx32 " due to active EEPROM backup", - bank->bank_number, limit); + k_bank->bank_number, limit); } - } else if ((unsigned)bank->bank_number == num_blocks) { - LOG_ERROR("FlexRAM support not yet implemented"); - return ERROR_FLASH_OPER_UNSUPPORTED; + size_k = bank->size / 1024; + LOG_DEBUG("Kinetis bank %u: %" PRIu32 "k FlexNVM, FTFx base 0x%08" PRIx32 ", sect %u", + k_bank->bank_number, size_k, k_bank->prog_base, k_bank->sector_size); + } else { LOG_ERROR("Cannot determine parameters for bank %d, only %d banks on device", - bank->bank_number, num_blocks); + k_bank->bank_number, num_blocks); return ERROR_FLASH_BANK_INVALID; } - if (bank->bank_number == 0 && ((uint32_t)fcfg2_maxaddr0 << 13) != bank->size) + fcfg2_pflsh = (uint8_t)((k_chip->sim_fcfg2 >> 23) & 0x01); + fcfg2_maxaddr0 = (uint8_t)((k_chip->sim_fcfg2 >> 24) & 0x7f); + fcfg2_maxaddr1 = (uint8_t)((k_chip->sim_fcfg2 >> 16) & 0x7f); + + if (k_bank->bank_number == 0 && k_chip->fcfg2_maxaddr0_shifted != bank->size) LOG_WARNING("MAXADDR0 0x%02" PRIx8 " check failed," " please report to OpenOCD mailing list", fcfg2_maxaddr0); + if (fcfg2_pflsh) { - if (bank->bank_number == 1 && ((uint32_t)fcfg2_maxaddr1 << 13) != bank->size) + if (k_bank->bank_number == 1 && k_chip->fcfg2_maxaddr1_shifted != bank->size) LOG_WARNING("MAXADDR1 0x%02" PRIx8 " check failed," " please report to OpenOCD mailing list", fcfg2_maxaddr1); } else { - if ((unsigned)bank->bank_number == first_nvm_bank - && ((uint32_t)fcfg2_maxaddr1 << 13) != df_size) + if (k_bank->bank_number == first_nvm_bank + && k_chip->fcfg2_maxaddr1_shifted != k_chip->dflash_size) LOG_WARNING("FlexNVM MAXADDR1 0x%02" PRIx8 " check failed," " please report to OpenOCD mailing list", fcfg2_maxaddr1); } @@ -1973,26 +2655,20 @@ static int kinetis_probe(struct flash_bank *bank) bank->prot_blocks = NULL; } - if (kinfo->sector_size == 0) { + if (k_bank->sector_size == 0) { LOG_ERROR("Unknown sector size for bank %d", bank->bank_number); return ERROR_FLASH_BANK_INVALID; } - if (kinfo->flash_support & FS_PROGRAM_SECTOR - && kinfo->max_flash_prog_size == 0) { - kinfo->max_flash_prog_size = kinfo->sector_size; - /* Program section size is equal to sector size by default */ - } - - bank->num_sectors = bank->size / kinfo->sector_size; + bank->num_sectors = bank->size / k_bank->sector_size; if (bank->num_sectors > 0) { /* FlexNVM bank can be used for EEPROM backup therefore zero sized */ - bank->sectors = alloc_block_array(0, kinfo->sector_size, bank->num_sectors); + bank->sectors = alloc_block_array(0, k_bank->sector_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; - bank->prot_blocks = alloc_block_array(0, kinfo->protection_size, bank->num_prot_blocks); + bank->prot_blocks = alloc_block_array(0, k_bank->protection_size, bank->num_prot_blocks); if (!bank->prot_blocks) return ERROR_FAIL; @@ -2000,16 +2676,16 @@ static int kinetis_probe(struct flash_bank *bank) bank->num_prot_blocks = 0; } - kinfo->probed = true; + k_bank->probed = true; return ERROR_OK; } static int kinetis_auto_probe(struct flash_bank *bank) { - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct kinetis_flash_bank *k_bank = bank->driver_priv; - if (kinfo && kinfo->probed) + if (k_bank && k_bank->probed) return ERROR_OK; return kinetis_probe(bank); @@ -2021,23 +2697,27 @@ static int kinetis_info(struct flash_bank *bank, char *buf, int buf_size) "(ANY)", "PFlash", "FlexNVM", "FlexRAM" }; - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; + uint32_t size_k = bank->size / 1024; - (void) snprintf(buf, buf_size, - "%s driver for %s flash bank %s at 0x%8.8" PRIx32 "", - bank->driver->name, bank_class_names[kinfo->flash_class], - bank->name, bank->base); + snprintf(buf, buf_size, + "%s %s: %" PRIu32 "k %s bank %s at 0x%08" PRIx32, + bank->driver->name, k_chip->name, + size_k, bank_class_names[k_bank->flash_class], + bank->name, bank->base); return ERROR_OK; } static int kinetis_blank_check(struct flash_bank *bank) { - struct kinetis_flash_bank *kinfo = bank->driver_priv; + struct kinetis_flash_bank *k_bank = bank->driver_priv; + struct kinetis_chip *k_chip = k_bank->k_chip; int result; /* suprisingly blank check does not work in VLPR and HSRUN modes */ - result = kinetis_check_run_mode(bank->target); + result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; @@ -2046,24 +2726,27 @@ static int kinetis_blank_check(struct flash_bank *bank) if (result != ERROR_OK) return result; - if (kinfo->flash_class == FC_PFLASH || kinfo->flash_class == FC_FLEX_NVM) { - bool block_dirty = false; + if (k_bank->flash_class == FC_PFLASH || k_bank->flash_class == FC_FLEX_NVM) { + bool block_dirty = true; + bool use_block_cmd = !(k_chip->flash_support & FS_NO_CMD_BLOCKSTAT); uint8_t ftfx_fstat; - if (kinfo->flash_class == FC_FLEX_NVM) { - uint8_t fcfg1_depart = (uint8_t)((kinfo->sim_fcfg1 >> 8) & 0x0f); + if (use_block_cmd && k_bank->flash_class == FC_FLEX_NVM) { + uint8_t fcfg1_depart = (uint8_t)((k_chip->sim_fcfg1 >> 8) & 0x0f); /* block operation cannot be used on FlexNVM when EEPROM backup partition is set */ if (fcfg1_depart != 0xf && fcfg1_depart != 0) - block_dirty = true; + use_block_cmd = false; } - if (!block_dirty) { + if (use_block_cmd) { /* check if whole bank is blank */ - result = kinetis_ftfx_command(bank->target, FTFx_CMD_BLOCKSTAT, kinfo->prog_base, + result = kinetis_ftfx_command(bank->target, FTFx_CMD_BLOCKSTAT, k_bank->prog_base, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); - if (result != ERROR_OK || (ftfx_fstat & 0x01)) - block_dirty = true; + if (result != ERROR_OK) + kinetis_ftfx_clear_error(bank->target); + else if ((ftfx_fstat & 0x01) == 0) + block_dirty = false; } if (block_dirty) { @@ -2072,13 +2755,14 @@ static int kinetis_blank_check(struct flash_bank *bank) for (i = 0; i < bank->num_sectors; i++) { /* normal margin */ result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT, - kinfo->prog_base + bank->sectors[i].offset, + k_bank->prog_base + bank->sectors[i].offset, 1, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result == ERROR_OK) { bank->sectors[i].is_erased = !(ftfx_fstat & 0x01); } else { LOG_DEBUG("Ignoring errored PFlash sector blank-check"); + kinetis_ftfx_clear_error(bank->target); bank->sectors[i].is_erased = -1; } } @@ -2099,7 +2783,9 @@ static int kinetis_blank_check(struct flash_bank *bank) COMMAND_HANDLER(kinetis_nvm_partition) { - int result, i; + int result; + unsigned bank_idx; + unsigned num_blocks, first_nvm_bank; unsigned long par, log2 = 0, ee1 = 0, ee2 = 0; enum { SHOW_INFO, DF_SIZE, EEBKP_SIZE } sz_type = SHOW_INFO; bool enable; @@ -2108,10 +2794,11 @@ COMMAND_HANDLER(kinetis_nvm_partition) uint8_t flex_nvm_partition_code = 0; uint8_t ee_split = 3; struct target *target = get_current_target(CMD_CTX); - struct flash_bank *bank; - struct kinetis_flash_bank *kinfo; + struct kinetis_chip *k_chip; uint32_t sim_fcfg1; + k_chip = kinetis_get_chip(target); + if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[0], "dataflash") == 0) sz_type = DF_SIZE; @@ -2124,7 +2811,11 @@ COMMAND_HANDLER(kinetis_nvm_partition) } switch (sz_type) { case SHOW_INFO: - result = target_read_u32(target, SIM_FCFG1, &sim_fcfg1); + if (k_chip == NULL) { + LOG_ERROR("Chip not probed."); + return ERROR_FAIL; + } + result = target_read_u32(target, k_chip->sim_base + SIM_FCFG1_OFFSET, &sim_fcfg1); if (result != ERROR_OK) return result; @@ -2207,7 +2898,7 @@ COMMAND_HANDLER(kinetis_nvm_partition) LOG_INFO("DEPART 0x%" PRIx8 ", EEPROM size code 0x%" PRIx8, flex_nvm_partition_code, ee_size_code); - result = kinetis_check_run_mode(target); + result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) return result; @@ -2224,14 +2915,12 @@ COMMAND_HANDLER(kinetis_nvm_partition) command_print(CMD_CTX, "FlexNVM partition set. Please reset MCU."); - for (i = 1; i < 4; i++) { - bank = get_flash_bank_by_num_noprobe(i); - if (bank == NULL) - break; - - kinfo = bank->driver_priv; - if (kinfo && kinfo->flash_class == FC_FLEX_NVM) - kinfo->probed = false; /* re-probe before next use */ + if (k_chip) { + first_nvm_bank = k_chip->num_pflash_blocks; + num_blocks = k_chip->num_pflash_blocks + k_chip->num_nvm_blocks; + for (bank_idx = first_nvm_bank; bank_idx < num_blocks; bank_idx++) + k_chip->banks[bank_idx].probed = false; /* re-probe before next use */ + k_chip->probed = false; } command_print(CMD_CTX, "FlexNVM banks will be re-probed to set new data flash size."); @@ -2277,6 +2966,16 @@ COMMAND_HANDLER(kinetis_fopt_handler) return ERROR_OK; } +COMMAND_HANDLER(kinetis_create_banks_handler) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + create_banks = true; + + return ERROR_OK; +} + static const struct command_registration kinetis_security_command_handlers[] = { { @@ -2347,6 +3046,12 @@ static const struct command_registration kinetis_exec_command_handlers[] = { .usage = "[num]", .handler = kinetis_fopt_handler, }, + { + .name = "create_banks", + .mode = COMMAND_CONFIG, + .help = "Driver creates additional banks if device with two/four flash blocks is probed", + .handler = kinetis_create_banks_handler, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 4d750951c..0e4abb533 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -59,10 +59,14 @@ * * Sector sizes in kiBytes: * 1 MiByte part with 4 x 16, 1 x 64, 7 x 128. + * 1.5 MiByte part with 4 x 16, 1 x 64, 11 x 128. * 2 MiByte part with 4 x 16, 1 x 64, 7 x 128, 4 x 16, 1 x 64, 7 x 128. * 1 MiByte STM32F42x/43x part with DB1M Option set: * 4 x 16, 1 x 64, 3 x 128, 4 x 16, 1 x 64, 3 x 128. * + * STM32F7[2|3] + * 512 kiByte part with 4 x 16, 1 x 64, 3 x 128. + * * STM32F7[4|5] * 1 MiByte part with 4 x 32, 1 x 128, 3 x 256. * @@ -93,6 +97,12 @@ * RM0410 * http://www.st.com/resource/en/reference_manual/dm00224583.pdf * + * RM0430 + * http://www.st.com/resource/en/reference_manual/dm00305666.pdf + * + * RM0431 + * http://www.st.com/resource/en/reference_manual/dm00305990.pdf + * * STM32F1x series - notice that this code was copy, pasted and knocked * into a stm32f2x driver, so in case something has been converted or * bugs haven't been fixed, here are the original manuals: @@ -121,6 +131,7 @@ #define STM32_FLASH_CR 0x40023c10 #define STM32_FLASH_OPTCR 0x40023c14 #define STM32_FLASH_OPTCR1 0x40023c18 +#define STM32_FLASH_OPTCR2 0x40023c1c /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) @@ -152,6 +163,10 @@ #define OPTCR_START (1 << 1) #define OPTCR_NDBANK (1 << 29) /* not dual bank mode */ #define OPTCR_DB1M (1 << 30) /* 1 MiB devices dual flash bank option */ +#define OPTCR_SPRMOD (1 << 31) /* switches PCROPi/nWPRi interpretation */ + +/* STM32_FLASH_OPTCR2 register bits */ +#define OPTCR2_PCROP_RDP (1 << 31) /* erase PCROP zone when decreasing RDP */ /* register unlock keys */ #define KEY1 0x45670123 @@ -166,14 +181,17 @@ struct stm32x_options { uint16_t user_options; /* bit 0-7 usual options, bit 8-11 extra options */ uint32_t protection; uint32_t boot_addr; + uint32_t optcr2_pcrop; }; struct stm32x_flash_bank { struct stm32x_options option_bytes; int probed; bool has_large_mem; /* F42x/43x/469/479/7xx in dual bank mode */ - bool has_boot_addr; /* F7xx */ bool has_extra_options; /* F42x/43x/469/479/7xx */ + bool has_boot_addr; /* F7xx */ + bool has_optcr2_pcrop; /* F72x/73x */ + int protection_bits; /* F413/423 */ uint32_t user_bank_size; }; @@ -328,11 +346,13 @@ static int stm32x_read_options(struct flash_bank *bank) * whereas F7 6 bits (IWDG_SW and WWDG_SW) in user_options */ stm32x_info->option_bytes.user_options = optiondata & 0xfc; stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; - stm32x_info->option_bytes.protection = (optiondata >> 16) & 0xfff; + stm32x_info->option_bytes.protection = + (optiondata >> 16) & (~(0xffff << stm32x_info->protection_bits) & 0xffff); if (stm32x_info->has_extra_options) { /* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */ - stm32x_info->option_bytes.user_options |= (optiondata >> 20) & 0xf00; + stm32x_info->option_bytes.user_options |= (optiondata >> 20) & + ((0xf00 << (stm32x_info->protection_bits - 12)) & 0xf00); } if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) { @@ -350,6 +370,20 @@ static int stm32x_read_options(struct flash_bank *bank) } } + if (stm32x_info->has_optcr2_pcrop) { + retval = target_read_u32(target, STM32_FLASH_OPTCR2, &optiondata); + if (retval != ERROR_OK) + return retval; + + stm32x_info->option_bytes.optcr2_pcrop = optiondata; + if (stm32x_info->has_optcr2_pcrop && + (stm32x_info->option_bytes.optcr2_pcrop & ~OPTCR2_PCROP_RDP)) { + LOG_INFO("PCROP Engaged"); + } + } else { + stm32x_info->option_bytes.optcr2_pcrop = 0x0; + } + if (stm32x_info->option_bytes.RDP != 0xAA) LOG_INFO("Device Security Bit Set"); @@ -371,11 +405,13 @@ static int stm32x_write_options(struct flash_bank *bank) /* rebuild option data */ optiondata = stm32x_info->option_bytes.user_options & 0xfc; optiondata |= stm32x_info->option_bytes.RDP << 8; - optiondata |= (stm32x_info->option_bytes.protection & 0x0fff) << 16; + optiondata |= (stm32x_info->option_bytes.protection & + (~(0xffff << stm32x_info->protection_bits))) << 16; if (stm32x_info->has_extra_options) { /* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */ - optiondata |= (stm32x_info->option_bytes.user_options & 0xf00) << 20; + optiondata |= (stm32x_info->option_bytes.user_options & + ((0xf00 << (stm32x_info->protection_bits - 12)) & 0xf00)) << 20; } if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) { @@ -392,6 +428,14 @@ static int stm32x_write_options(struct flash_bank *bank) return retval; } + /* program extra pcrop register */ + if (stm32x_info->has_optcr2_pcrop) { + retval = target_write_u32(target, STM32_FLASH_OPTCR2, + stm32x_info->option_bytes.optcr2_pcrop); + if (retval != ERROR_OK) + return retval; + } + /* program options */ retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata); if (retval != ERROR_OK) @@ -418,6 +462,8 @@ static int stm32x_write_options(struct flash_bank *bank) static int stm32x_protect_check(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; + struct flash_sector *prot_blocks; + int num_prot_blocks; /* read write protection settings */ int retval = stm32x_read_options(bank); @@ -426,27 +472,18 @@ static int stm32x_protect_check(struct flash_bank *bank) return retval; } - if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) { - /* F76x/77x: bit k protects sectors 2*k and 2*k+1 */ - for (int i = 0; i < (bank->num_sectors >> 1); i++) { - if (stm32x_info->option_bytes.protection & (1 << i)) { - bank->sectors[i << 1].is_protected = 0; - bank->sectors[(i << 1) + 1].is_protected = 0; - } else { - bank->sectors[i << 1].is_protected = 1; - bank->sectors[(i << 1) + 1].is_protected = 1; - } - } + if (bank->prot_blocks) { + num_prot_blocks = bank->num_prot_blocks; + prot_blocks = bank->prot_blocks; } else { - /* one protection bit per sector */ - for (int i = 0; i < bank->num_sectors; i++) { - if (stm32x_info->option_bytes.protection & (1 << i)) - bank->sectors[i].is_protected = 0; - else - bank->sectors[i].is_protected = 1; - } + num_prot_blocks = bank->num_sectors; + prot_blocks = bank->sectors; } + for (int i = 0; i < num_prot_blocks; i++) + prot_blocks[i].is_protected = + ~(stm32x_info->option_bytes.protection >> i) & 1; + return ERROR_OK; } @@ -515,17 +552,6 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) return retval; } - if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) { - /* F76x/77x: bit k protects sectors 2*k and 2*k+1 */ - if ((first & 1) != 0 || (last & 1) != 1) { - LOG_ERROR("sector protection must be double sector aligned"); - return ERROR_FAIL; - } else { - first >>= 1; - last >>= 1; - } - } - for (int i = first; i <= last; i++) { if (set) stm32x_info->option_bytes.protection &= ~(1 << i); @@ -829,7 +855,7 @@ static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; - int i; + int i, num_prot_blocks; uint16_t flash_size_in_kb; uint32_t flash_size_reg = 0x1FFF7A22; uint16_t max_sector_size_in_kb = 128; @@ -841,15 +867,31 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->has_large_mem = false; stm32x_info->has_boot_addr = false; stm32x_info->has_extra_options = false; + stm32x_info->has_optcr2_pcrop = false; + stm32x_info->protection_bits = 12; /* max. number of nWRPi bits (in FLASH_OPTCR !!!) */ + num_prot_blocks = 0; + + if (bank->sectors) { + free(bank->sectors); + bank->num_sectors = 0; + bank->sectors = NULL; + } + + if (bank->prot_blocks) { + free(bank->prot_blocks); + bank->num_prot_blocks = 0; + bank->prot_blocks = NULL; + } /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &device_id); if (retval != ERROR_OK) return retval; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + device_id &= 0xfff; /* only bits 0-11 are used further on */ /* set max flash size depending on family, id taken from AN2606 */ - switch (device_id & 0xfff) { + switch (device_id) { case 0x411: /* F20x/21x */ case 0x413: /* F40x/41x */ max_flash_size_in_kb = 1024; @@ -892,6 +934,21 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->has_boot_addr = true; break; + case 0x452: /* F72x/73x */ + max_flash_size_in_kb = 512; + flash_size_reg = 0x1FF07A22; /* yes, 0x1FF*0*7A22, not 0x1FF*F*7A22 */ + stm32x_info->has_extra_options = true; + stm32x_info->has_boot_addr = true; + stm32x_info->has_optcr2_pcrop = true; + break; + + case 0x463: /* F413x/423x */ + max_flash_size_in_kb = 1536; + stm32x_info->has_extra_options = true; + stm32x_info->protection_bits = 15; + num_prot_blocks = 15; + break; + default: LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; @@ -920,12 +977,8 @@ static int stm32x_probe(struct flash_bank *bank) /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); - /* Devices with > 1024 kiByte always are dual-banked */ - if (flash_size_in_kb > 1024) - stm32x_info->has_large_mem = true; - /* F42x/43x/469/479 1024 kiByte devices have a dual bank option */ - if ((device_id & 0xfff) == 0x419 || (device_id & 0xfff) == 0x434) { + if ((device_id == 0x419) || (device_id == 0x434)) { uint32_t optiondata; retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); if (retval != ERROR_OK) { @@ -942,7 +995,7 @@ static int stm32x_probe(struct flash_bank *bank) } /* F76x/77x devices have a dual bank option */ - if ((device_id & 0xfff) == 0x451) { + if (device_id == 0x451) { uint32_t optiondata; retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); if (retval != ERROR_OK) { @@ -963,11 +1016,6 @@ static int stm32x_probe(struct flash_bank *bank) int num_pages = flash_size_in_kb / max_sector_size_in_kb + (stm32x_info->has_large_mem ? 8 : 4); - if (bank->sectors) { - free(bank->sectors); - bank->sectors = NULL; - } - bank->base = base_address; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); @@ -978,15 +1026,44 @@ static int stm32x_probe(struct flash_bank *bank) bank->size = 0; LOG_DEBUG("allocated %d sectors", num_pages); + /* F76x/77x in dual bank mode */ + if ((device_id == 0x451) && stm32x_info->has_large_mem) + num_prot_blocks = num_pages >> 1; + + if (num_prot_blocks) { + bank->prot_blocks = malloc(sizeof(struct flash_sector) * num_prot_blocks); + for (i = 0; i < num_prot_blocks; i++) + bank->prot_blocks[i].is_protected = 0; + LOG_DEBUG("allocated %d prot blocks", num_prot_blocks); + } + if (stm32x_info->has_large_mem) { /* dual-bank */ setup_bank(bank, 0, flash_size_in_kb >> 1, max_sector_size_in_kb); setup_bank(bank, num_pages >> 1, flash_size_in_kb >> 1, max_sector_size_in_kb); + + /* F767x/F77x in dual mode, one protection bit refers to two adjacent sectors */ + if (device_id == 0x451) { + for (i = 0; i < num_prot_blocks; i++) { + bank->prot_blocks[i].offset = bank->sectors[i << 1].offset; + bank->prot_blocks[i].size = bank->sectors[i << 1].size << 1; + } + } } else { /* single-bank */ setup_bank(bank, 0, flash_size_in_kb, max_sector_size_in_kb); + + /* F413/F423, sectors 14 and 15 share one common protection bit */ + if (device_id == 0x463) { + for (i = 0; i < num_prot_blocks; i++) { + bank->prot_blocks[i].offset = bank->sectors[i].offset; + bank->prot_blocks[i].size = bank->sectors[i].size; + } + bank->prot_blocks[num_prot_blocks - 1].size <<= 1; + } } + bank->num_prot_blocks = num_prot_blocks; assert((bank->size >> 10) == flash_size_in_kb); stm32x_info->probed = 1; @@ -1107,6 +1184,14 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) case 0x1001: rev_str = "Z"; break; + + case 0x2000: + rev_str = "B"; + break; + + case 0x3000: + rev_str = "C"; + break; } break; @@ -1134,6 +1219,26 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) } break; + case 0x452: + device_str = "STM32F7[2|3]x"; + + switch (rev_id) { + case 0x1000: + rev_str = "A"; + break; + } + break; + + case 0x463: + device_str = "STM32F4[1|2]3"; + + switch (rev_id) { + case 0x1000: + rev_str = "A"; + break; + } + break; + default: snprintf(buf, buf_size, "Cannot identify target as a STM32F2/4/7\n"); return ERROR_FAIL; @@ -1164,8 +1269,8 @@ COMMAND_HANDLER(stm32x_handle_lock_command) target = bank->target; if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; + LOG_INFO("Target not halted"); + /* return ERROR_TARGET_NOT_HALTED; */ } if (stm32x_read_options(bank) != ERROR_OK) { @@ -1203,8 +1308,8 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) target = bank->target; if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; + LOG_INFO("Target not halted"); + /* return ERROR_TARGET_NOT_HALTED; */ } if (stm32x_read_options(bank) != ERROR_OK) { @@ -1215,6 +1320,9 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) /* clear readout protection and complementary option bytes * this will also force a device unlock if set */ stm32x_info->option_bytes.RDP = 0xAA; + if (stm32x_info->has_optcr2_pcrop) { + stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1 << bank->num_sectors); + } if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); @@ -1327,8 +1435,12 @@ COMMAND_HANDLER(stm32f2x_handle_options_read_command) " boot_add0 0x%04X, boot_add1 0x%04X", stm32x_info->option_bytes.user_options, boot_addr & 0xffff, (boot_addr & 0xffff0000) >> 16); + if (stm32x_info->has_optcr2_pcrop) { + command_print(CMD_CTX, "stm32f2x optcr2_pcrop 0x%08X", + stm32x_info->option_bytes.optcr2_pcrop); + } } else { - command_print(CMD_CTX, "stm32f2x user_options 0x%03X,", + command_print(CMD_CTX, "stm32f2x user_options 0x%03X", stm32x_info->option_bytes.user_options); } } else { @@ -1345,7 +1457,7 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command) int retval; struct flash_bank *bank; struct stm32x_flash_bank *stm32x_info = NULL; - uint16_t user_options, boot_addr0, boot_addr1; + uint16_t user_options, boot_addr0, boot_addr1, options_mask; if (CMD_ARGC < 1) { command_print(CMD_CTX, "stm32f2x options_write ..."); @@ -1378,9 +1490,11 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command) } COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], user_options); - if (user_options & (stm32x_info->has_extra_options ? ~0xffc : ~0xfc)) { + options_mask = !stm32x_info->has_extra_options ? ~0xfc : + ~(((0xf00 << (stm32x_info->protection_bits - 12)) | 0xff) & 0xffc); + if (user_options & options_mask) { command_print(CMD_CTX, "stm32f2x invalid user_options"); - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_ARGUMENT_INVALID; } stm32x_info->option_bytes.user_options = user_options; @@ -1400,6 +1514,48 @@ COMMAND_HANDLER(stm32f2x_handle_options_write_command) return retval; } +COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command) +{ + int retval; + struct flash_bank *bank; + struct stm32x_flash_bank *stm32x_info = NULL; + uint32_t optcr2_pcrop; + + if (CMD_ARGC != 2) { + command_print(CMD_CTX, "stm32f2x optcr2_write "); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + stm32x_info = bank->driver_priv; + if (!stm32x_info->has_optcr2_pcrop) { + command_print(CMD_CTX, "no optcr2 register"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + command_print(CMD_CTX, "INFO: To disable PCROP, set PCROP_RDP" + " with PCROPi bits STILL SET, then\nlock device and" + " finally unlock it. Clears PCROP and mass erases flash."); + + retval = stm32x_read_options(bank); + if (ERROR_OK != retval) + return retval; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], optcr2_pcrop); + stm32x_info->option_bytes.optcr2_pcrop = optcr2_pcrop; + + if (stm32x_write_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "stm32f2x failed to write options"); + return ERROR_OK; + } + + command_print(CMD_CTX, "stm32f2x optcr2_write complete."); + return retval; +} + static const struct command_registration stm32x_exec_command_handlers[] = { { .name = "lock", @@ -1433,9 +1589,17 @@ static const struct command_registration stm32x_exec_command_handlers[] = { .name = "options_write", .handler = stm32f2x_handle_options_write_command, .mode = COMMAND_EXEC, - .usage = "bank_id user_options [ boot_add0 boot_add1]", + .usage = "bank_id user_options [ boot_add0 boot_add1 ]", .help = "Write option bytes", }, + { + .name = "optcr2_write", + .handler = stm32f2x_handle_optcr2_write_command, + .mode = COMMAND_EXEC, + .usage = "bank_id optcr2", + .help = "Write optcr2 word", + }, + COMMAND_REGISTRATION_DONE }; diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index e4f499d3c..0c2fddc92 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -790,6 +790,11 @@ static int stm32lx_probe(struct flash_bank *bank) flash_size_in_kb = 256; } + /* 0x429 devices only use the lowest 8 bits of the flash size register */ + if (retval == ERROR_OK && (device_id & 0xfff) == 0x429) { + flash_size_in_kb &= 0xff; + } + /* Failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index b93d12694..e5e280111 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -583,9 +583,10 @@ COMMAND_HANDLER(handle_flash_write_bank_command) { uint32_t offset; uint8_t *buffer; + size_t length; struct fileio *fileio; - if (CMD_ARGC != 3) + if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; struct duration bench; @@ -596,7 +597,16 @@ COMMAND_HANDLER(handle_flash_write_bank_command) if (ERROR_OK != retval) return retval; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); + offset = 0; + + if (CMD_ARGC > 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); + + if (offset > p->size) { + LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", + offset); + return ERROR_COMMAND_ARGUMENT_INVALID; + } if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) return ERROR_FAIL; @@ -608,20 +618,38 @@ COMMAND_HANDLER(handle_flash_write_bank_command) return retval; } - buffer = malloc(filesize); + length = MIN(filesize, p->size - offset); + + if (!length) { + LOG_INFO("Nothing to write to flash bank"); + fileio_close(fileio); + return ERROR_OK; + } + + if (length != filesize) + LOG_INFO("File content exceeds flash bank size. Only writing the " + "first %zu bytes of the file", length); + + buffer = malloc(length); if (buffer == NULL) { fileio_close(fileio); LOG_ERROR("Out of memory"); return ERROR_FAIL; } size_t buf_cnt; - if (fileio_read(fileio, filesize, buffer, &buf_cnt) != ERROR_OK) { + if (fileio_read(fileio, length, buffer, &buf_cnt) != ERROR_OK) { free(buffer); fileio_close(fileio); return ERROR_FAIL; } - retval = flash_driver_write(p, buffer, offset, buf_cnt); + if (buf_cnt != length) { + LOG_ERROR("Short read"); + free(buffer); + return ERROR_FAIL; + } + + retval = flash_driver_write(p, buffer, offset, length); free(buffer); buffer = NULL; @@ -629,8 +657,8 @@ COMMAND_HANDLER(handle_flash_write_bank_command) if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "wrote %zu bytes from file %s to flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", - filesize, CMD_ARGV[1], p->bank_number, offset, - duration_elapsed(&bench), duration_kbps(&bench, filesize)); + length, CMD_ARGV[1], p->bank_number, offset, + duration_elapsed(&bench), duration_kbps(&bench, length)); } fileio_close(fileio); @@ -646,7 +674,7 @@ COMMAND_HANDLER(handle_flash_read_bank_command) uint32_t length; size_t written; - if (CMD_ARGC != 4) + if (CMD_ARGC < 2 || CMD_ARGC > 4) return ERROR_COMMAND_SYNTAX_ERROR; struct duration bench; @@ -654,11 +682,31 @@ COMMAND_HANDLER(handle_flash_read_bank_command) struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); + if (ERROR_OK != retval) return retval; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length); + offset = 0; + + if (CMD_ARGC > 2) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); + + if (offset > p->size) { + LOG_ERROR("Offset 0x%8.8" PRIx32 " is out of range of the flash bank", + offset); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + length = p->size - offset; + + if (CMD_ARGC > 3) + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], length); + + if (offset + length > p->size) { + LOG_ERROR("Length of %" PRIu32 " bytes with offset 0x%8.8" PRIx32 + " is out of range of the flash bank", length, offset); + return ERROR_COMMAND_ARGUMENT_INVALID; + } buffer = malloc(length); if (buffer == NULL) { @@ -705,6 +753,7 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) struct fileio *fileio; size_t read_cnt; size_t filesize; + size_t length; int differ; if (CMD_ARGC < 2 || CMD_ARGC > 3) @@ -741,14 +790,26 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) return retval; } - buffer_file = malloc(filesize); + length = MIN(filesize, p->size - offset); + + if (!length) { + LOG_INFO("Nothing to compare with flash bank"); + fileio_close(fileio); + return ERROR_OK; + } + + if (length != filesize) + LOG_INFO("File content exceeds flash bank size. Only comparing the " + "first %zu bytes of the file", length); + + buffer_file = malloc(length); if (buffer_file == NULL) { LOG_ERROR("Out of memory"); fileio_close(fileio); return ERROR_FAIL; } - retval = fileio_read(fileio, filesize, buffer_file, &read_cnt); + retval = fileio_read(fileio, length, buffer_file, &read_cnt); fileio_close(fileio); if (retval != ERROR_OK) { LOG_ERROR("File read failure"); @@ -756,20 +817,20 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) return retval; } - if (read_cnt != filesize) { + if (read_cnt != length) { LOG_ERROR("Short read"); free(buffer_file); return ERROR_FAIL; } - buffer_flash = malloc(filesize); + buffer_flash = malloc(length); if (buffer_flash == NULL) { LOG_ERROR("Out of memory"); free(buffer_file); return ERROR_FAIL; } - retval = flash_driver_read(p, buffer_flash, offset, read_cnt); + retval = flash_driver_read(p, buffer_flash, offset, length); if (retval != ERROR_OK) { LOG_ERROR("Flash read error"); free(buffer_flash); @@ -780,15 +841,15 @@ COMMAND_HANDLER(handle_flash_verify_bank_command) if (duration_measure(&bench) == ERROR_OK) command_print(CMD_CTX, "read %zd bytes from file %s and flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", - read_cnt, CMD_ARGV[1], p->bank_number, offset, - duration_elapsed(&bench), duration_kbps(&bench, read_cnt)); + length, CMD_ARGV[1], p->bank_number, offset, + duration_elapsed(&bench), duration_kbps(&bench, length)); - differ = memcmp(buffer_file, buffer_flash, read_cnt); + differ = memcmp(buffer_file, buffer_flash, length); command_print(CMD_CTX, "contents %s", differ ? "differ" : "match"); if (differ) { uint32_t t; int diffs = 0; - for (t = 0; t < read_cnt; t++) { + for (t = 0; t < length; t++) { if (buffer_flash[t] == buffer_file[t]) continue; command_print(CMD_CTX, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x", @@ -908,10 +969,9 @@ static const struct command_registration flash_exec_command_handlers[] = { .name = "write_bank", .handler = handle_flash_write_bank_command, .mode = COMMAND_EXEC, - .usage = "bank_id filename offset", - .help = "Write binary data from file to flash bank, " - "starting at specified byte offset from the " - "beginning of the bank.", + .usage = "bank_id filename [offset]", + .help = "Write binary data from file to flash bank. Allow optional " + "offset from beginning of the bank (defaults to zero).", }, { .name = "write_image", @@ -926,10 +986,9 @@ static const struct command_registration flash_exec_command_handlers[] = { .name = "read_bank", .handler = handle_flash_read_bank_command, .mode = COMMAND_EXEC, - .usage = "bank_id filename offset length", - .help = "Read binary data from flash bank to file, " - "starting at specified byte offset from the " - "beginning of the bank.", + .usage = "bank_id filename [offset [length]]", + .help = "Read binary data from flash bank to file. Allow optional " + "offset from beginning of the bank (defaults to zero).", }, { .name = "verify_bank", diff --git a/src/helper/log.c b/src/helper/log.c index d4e87f662..c8a3a6c55 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -50,11 +50,12 @@ static int64_t current_time; static int64_t start; -static const char * const log_strings[5] = { +static const char * const log_strings[6] = { "User : ", "Error: ", "Warn : ", /* want a space after each colon, all same width, colons aligned */ "Info : ", + "Debug: ", "Debug: " }; @@ -234,8 +235,8 @@ COMMAND_HANDLER(handle_debug_level_command) if (CMD_ARGC == 1) { int new_level; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level); - if ((new_level > LOG_LVL_DEBUG) || (new_level < LOG_LVL_SILENT)) { - LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG); + if ((new_level > LOG_LVL_DEBUG_IO) || (new_level < LOG_LVL_SILENT)) { + LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO); return ERROR_COMMAND_SYNTAX_ERROR; } debug_level = new_level; @@ -279,7 +280,8 @@ static struct command_registration log_command_handlers[] = { .mode = COMMAND_ANY, .help = "Sets the verbosity level of debugging output. " "0 shows errors only; 1 adds warnings; " - "2 (default) adds other info; 3 adds debugging.", + "2 (default) adds other info; 3 adds debugging; " + "4 adds extra verbose debugging.", .usage = "number", }, COMMAND_REGISTRATION_DONE @@ -303,7 +305,7 @@ void log_init(void) int retval = parse_int(debug_env, &value); if (ERROR_OK == retval && debug_level >= LOG_LVL_SILENT && - debug_level <= LOG_LVL_DEBUG) + debug_level <= LOG_LVL_DEBUG_IO) debug_level = value; } diff --git a/src/helper/log.h b/src/helper/log.h index 6b938165b..512bcc512 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -46,6 +46,7 @@ * LOG_LVL_WARNING - non-fatal errors, that may be resolved later * LOG_LVL_INFO - state information, etc. * LOG_LVL_DEBUG - debug statements, execution trace + * LOG_LVL_DEBUG_IO - verbose debug, low-level I/O trace */ enum log_levels { LOG_LVL_SILENT = -3, @@ -54,7 +55,8 @@ enum log_levels { LOG_LVL_ERROR = 0, LOG_LVL_WARNING = 1, LOG_LVL_INFO = 2, - LOG_LVL_DEBUG = 3 + LOG_LVL_DEBUG = 3, + LOG_LVL_DEBUG_IO = 4, }; void log_printf(enum log_levels level, const char *file, unsigned line, @@ -102,6 +104,14 @@ extern int debug_level; #define LOG_LEVEL_IS(FOO) ((debug_level) >= (FOO)) +#define LOG_DEBUG_IO(expr ...) \ + do { \ + if (debug_level >= LOG_LVL_DEBUG_IO) \ + log_printf_lf(LOG_LVL_DEBUG, \ + __FILE__, __LINE__, __func__, \ + expr); \ + } while (0) + #define LOG_DEBUG(expr ...) \ do { \ if (debug_level >= LOG_LVL_DEBUG) \ diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 86f796877..19c3b19c9 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -596,7 +596,7 @@ static int cmsis_dap_swd_run_queue(void) { uint8_t *buffer = cmsis_dap_handle->packet_buffer; - LOG_DEBUG("Executing %d queued transactions", pending_transfer_count); + LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count); if (queued_retval != ERROR_OK) { LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); @@ -616,7 +616,7 @@ static int cmsis_dap_swd_run_queue(void) uint8_t cmd = pending_transfers[i].cmd; uint32_t data = pending_transfers[i].data; - LOG_DEBUG("%s %s reg %x %"PRIx32, + LOG_DEBUG_IO("%s %s reg %x %"PRIx32, cmd & SWD_CMD_APnDP ? "AP" : "DP", cmd & SWD_CMD_RnW ? "read" : "write", (cmd & SWD_CMD_A32) >> 1, data); @@ -674,7 +674,7 @@ static int cmsis_dap_swd_run_queue(void) uint32_t tmp = data; idx += 4; - LOG_DEBUG("Read result: %"PRIx32, data); + LOG_DEBUG_IO("Read result: %"PRIx32, data); /* Imitate posted AP reads */ if ((pending_transfers[i].cmd & SWD_CMD_APnDP) || diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 8b78fe8d5..883cd24c8 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1109,12 +1109,12 @@ static void ftdi_swd_swdio_en(bool enable) */ static int ftdi_swd_run_queue(void) { - LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length); + LOG_DEBUG_IO("Executing %zu queued transactions", swd_cmd_queue_length); int retval; struct signal *led = find_signal_by_name("LED"); if (queued_retval != ERROR_OK) { - LOG_DEBUG("Skipping due to previous errors: %d", queued_retval); + LOG_DEBUG_IO("Skipping due to previous errors: %d", queued_retval); goto skip; } @@ -1135,7 +1135,7 @@ static int ftdi_swd_run_queue(void) for (size_t i = 0; i < swd_cmd_queue_length; i++) { int ack = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3); - LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + LOG_DEBUG_IO("%s %s %s reg %X = %08"PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", swd_cmd_queue[i].cmd & SWD_CMD_APnDP ? "AP" : "DP", swd_cmd_queue[i].cmd & SWD_CMD_RnW ? "read" : "write", diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c index f2f5564fd..c260b7f80 100644 --- a/src/rtos/rtos_ucos_iii_stackings.c +++ b/src/rtos/rtos_ucos_iii_stackings.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2016 by Square, Inc. * + * Copyright (C) 2017 by Square, Inc. * * Steven Stallion * * * * This program is free software; you can redistribute it and/or modify * @@ -20,34 +20,35 @@ #include "config.h" #endif -#include "rtos.h" -#include "rtos_standard_stackings.h" -#include "target/armv7m.h" +#include +#include +#include +#include -static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[ARMV7M_NUM_CORE_REGS] = { - { 0x20, 32 }, /* r0 */ - { 0x24, 32 }, /* r1 */ - { 0x28, 32 }, /* r2 */ - { 0x2c, 32 }, /* r3 */ - { 0x00, 32 }, /* r4 */ - { 0x04, 32 }, /* r5 */ - { 0x08, 32 }, /* r6 */ - { 0x0c, 32 }, /* r7 */ - { 0x10, 32 }, /* r8 */ - { 0x14, 32 }, /* r9 */ - { 0x18, 32 }, /* r10 */ - { 0x1c, 32 }, /* r11 */ - { 0x30, 32 }, /* r12 */ - { -2, 32 }, /* sp */ - { 0x34, 32 }, /* lr */ - { 0x38, 32 }, /* pc */ - { 0x3c, 32 }, /* xPSR */ +static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[] = { + { 0x20, 32 }, /* r0 */ + { 0x24, 32 }, /* r1 */ + { 0x28, 32 }, /* r2 */ + { 0x2c, 32 }, /* r3 */ + { 0x00, 32 }, /* r4 */ + { 0x04, 32 }, /* r5 */ + { 0x08, 32 }, /* r6 */ + { 0x0c, 32 }, /* r7 */ + { 0x10, 32 }, /* r8 */ + { 0x14, 32 }, /* r9 */ + { 0x18, 32 }, /* r10 */ + { 0x1c, 32 }, /* r11 */ + { 0x30, 32 }, /* r12 */ + { -2, 32 }, /* sp */ + { 0x34, 32 }, /* lr */ + { 0x38, 32 }, /* pc */ + { 0x3c, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = { - 0x40, /* stack_registers_size */ - -1, /* stack_growth_direction */ - ARMV7M_NUM_CORE_REGS, /* num_output_registers */ - rtos_generic_stack_align8, /* stack_alignment */ - rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */ + 0x40, /* stack_registers_size */ + -1, /* stack_growth_direction */ + ARRAY_SIZE(rtos_uCOS_III_Cortex_M_stack_offsets), /* num_output_registers */ + rtos_generic_stack_align8, /* stack_alignment */ + rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */ }; diff --git a/src/rtos/rtos_ucos_iii_stackings.h b/src/rtos/rtos_ucos_iii_stackings.h index c462cd745..f4703da37 100644 --- a/src/rtos/rtos_ucos_iii_stackings.h +++ b/src/rtos/rtos_ucos_iii_stackings.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2016 by Square, Inc. * + * Copyright (C) 2017 by Square, Inc. * * Steven Stallion * * * * This program is free software; you can redistribute it and/or modify * @@ -23,7 +23,7 @@ #include "config.h" #endif -#include "rtos.h" +#include extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking; diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 75cfe52bd..0a0fb3e9e 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2016 by Square, Inc. * + * Copyright (C) 2017 by Square, Inc. * * Steven Stallion * * * * This program is free software; you can redistribute it and/or modify * @@ -20,14 +20,14 @@ #include "config.h" #endif +#include #include -#include -#include "target/target.h" -#include "target/target_type.h" -#include "rtos.h" -#include "helper/log.h" -#include "helper/types.h" -#include "rtos/rtos_ucos_iii_stackings.h" +#include +#include +#include +#include + +#include "rtos_ucos_iii_stackings.h" #ifndef UCOS_III_MAX_STRLEN #define UCOS_III_MAX_STRLEN 64 @@ -55,18 +55,18 @@ struct uCOS_III_params { static const struct uCOS_III_params uCOS_III_params_list[] = { { - "cortex_m", /* target_name */ - sizeof(uint32_t), /* pointer_width */ - 0, /* thread_stack_offset */ - 0, /* thread_name_offset */ - 0, /* thread_state_offset */ - 0, /* thread_priority_offset */ - 0, /* thread_prev_offset */ - 0, /* thread_next_offset */ - false, /* thread_offsets_updated */ - 1, /* threadid_start */ + "cortex_m", /* target_name */ + sizeof(uint32_t), /* pointer_width */ + 0, /* thread_stack_offset */ + 0, /* thread_name_offset */ + 0, /* thread_state_offset */ + 0, /* thread_priority_offset */ + 0, /* thread_prev_offset */ + 0, /* thread_next_offset */ + false, /* thread_offsets_updated */ + 1, /* threadid_start */ &rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */ - 0, /* num_threads */ + 0, /* num_threads */ }, }; @@ -159,10 +159,10 @@ static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t symbol_address_t thread_list_address = 0; retval = target_read_memory(rtos->target, - rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address, - params->pointer_width, - 1, - (void *)&thread_list_address); + rtos->symbols[uCOS_III_VAL_OSTaskDbgListPtr].address, + params->pointer_width, + 1, + (void *)&thread_list_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread list address"); return retval; @@ -173,10 +173,10 @@ static int uCOS_III_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address = thread_list_address; retval = target_read_memory(rtos->target, - thread_list_address + params->thread_next_offset, - params->pointer_width, - 1, - (void *)&thread_list_address); + thread_list_address + params->thread_next_offset, + params->pointer_width, + 1, + (void *)&thread_list_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read next thread address"); return retval; @@ -227,10 +227,10 @@ static int uCOS_III_update_thread_offsets(struct rtos *rtos) const struct thread_offset_map *thread_offset_map = &thread_offset_maps[i]; int retval = target_read_memory(rtos->target, - rtos->symbols[thread_offset_map->symbol_value].address, - params->pointer_width, - 1, - (void *)thread_offset_map->thread_offset); + rtos->symbols[thread_offset_map->symbol_value].address, + params->pointer_width, + 1, + (void *)thread_offset_map->thread_offset); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread offset"); return retval; @@ -244,7 +244,7 @@ static int uCOS_III_update_thread_offsets(struct rtos *rtos) static int uCOS_III_detect_rtos(struct target *target) { return target->rtos->symbols != NULL && - target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0; + target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0; } static int uCOS_III_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv) @@ -263,8 +263,7 @@ static int uCOS_III_create(struct target *target) for (size_t i = 0; i < ARRAY_SIZE(uCOS_III_params_list); i++) if (strcmp(uCOS_III_params_list[i].target_name, target->type->name) == 0) { - params = malloc(sizeof(*params) + - UCOS_III_MAX_THREADS * sizeof(*params->threads)); + params = malloc(sizeof(*params) + (UCOS_III_MAX_THREADS * sizeof(*params->threads))); if (params == NULL) { LOG_ERROR("uCOS-III: out of memory"); return ERROR_FAIL; @@ -294,13 +293,18 @@ static int uCOS_III_update_threads(struct rtos *rtos) uint8_t rtos_running; retval = target_read_u8(rtos->target, - rtos->symbols[uCOS_III_VAL_OSRunning].address, - &rtos_running); + rtos->symbols[uCOS_III_VAL_OSRunning].address, + &rtos_running); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read RTOS running"); return retval; } + if (rtos_running != 1 && rtos_running != 0) { + LOG_ERROR("uCOS-III: invalid RTOS running value"); + return ERROR_FAIL; + } + if (!rtos_running) { rtos->thread_details = calloc(1, sizeof(struct thread_detail)); if (rtos->thread_details == NULL) { @@ -327,10 +331,10 @@ static int uCOS_III_update_threads(struct rtos *rtos) symbol_address_t current_thread_address = 0; retval = target_read_memory(rtos->target, - rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address, - params->pointer_width, - 1, - (void *)¤t_thread_address); + rtos->symbols[uCOS_III_VAL_OSTCBCurPtr].address, + params->pointer_width, + 1, + (void *)¤t_thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read current thread address"); return retval; @@ -338,8 +342,8 @@ static int uCOS_III_update_threads(struct rtos *rtos) /* read number of tasks */ retval = target_read_u16(rtos->target, - rtos->symbols[uCOS_III_VAL_OSTaskQty].address, - (void *)&rtos->thread_count); + rtos->symbols[uCOS_III_VAL_OSTaskQty].address, + (void *)&rtos->thread_count); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread count"); return retval; @@ -368,9 +372,7 @@ static int uCOS_III_update_threads(struct rtos *rtos) char thread_str_buffer[UCOS_III_MAX_STRLEN + 1]; /* find or create new threadid */ - retval = uCOS_III_find_or_create_thread(rtos, - thread_address, - &thread_detail->threadid); + retval = uCOS_III_find_or_create_thread(rtos, thread_address, &thread_detail->threadid); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to find or create thread"); return retval; @@ -385,19 +387,19 @@ static int uCOS_III_update_threads(struct rtos *rtos) symbol_address_t thread_name_address = 0; retval = target_read_memory(rtos->target, - thread_address + params->thread_name_offset, - params->pointer_width, - 1, - (void *)&thread_name_address); + thread_address + params->thread_name_offset, + params->pointer_width, + 1, + (void *)&thread_name_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to name address"); return retval; } retval = target_read_buffer(rtos->target, - thread_name_address, - sizeof(thread_str_buffer), - (void *)thread_str_buffer); + thread_name_address, + sizeof(thread_str_buffer), + (void *)thread_str_buffer); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread name"); return retval; @@ -411,16 +413,16 @@ static int uCOS_III_update_threads(struct rtos *rtos) uint8_t thread_priority; retval = target_read_u8(rtos->target, - thread_address + params->thread_state_offset, - &thread_state); + thread_address + params->thread_state_offset, + &thread_state); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread state"); return retval; } retval = target_read_u8(rtos->target, - thread_address + params->thread_priority_offset, - &thread_priority); + thread_address + params->thread_priority_offset, + &thread_priority); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read thread priority"); return retval; @@ -434,15 +436,15 @@ static int uCOS_III_update_threads(struct rtos *rtos) thread_state_str = "Unknown"; snprintf(thread_str_buffer, sizeof(thread_str_buffer), "State: %s, Priority: %d", - thread_state_str, thread_priority); + thread_state_str, thread_priority); thread_detail->extra_info_str = strdup(thread_str_buffer); /* read previous thread address */ retval = target_read_memory(rtos->target, - thread_address + params->thread_prev_offset, - params->pointer_width, - 1, - (void *)&thread_address); + thread_address + params->thread_prev_offset, + params->pointer_width, + 1, + (void *)&thread_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read previous thread address"); return retval; @@ -470,19 +472,19 @@ static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, symbol_address_t stack_address = 0; retval = target_read_memory(rtos->target, - thread_address + params->thread_stack_offset, - params->pointer_width, - 1, - (void *)&stack_address); + thread_address + params->thread_stack_offset, + params->pointer_width, + 1, + (void *)&stack_address); if (retval != ERROR_OK) { LOG_ERROR("uCOS-III: failed to read stack address"); return retval; } return rtos_generic_stack_read(rtos->target, - params->stacking_info, - stack_address, - hex_reg_list); + params->stacking_info, + stack_address, + hex_reg_list); } static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) diff --git a/src/target/target.c b/src/target/target.c index eb45faf4e..adedd4709 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3037,16 +3037,16 @@ static void handle_md_output(struct command_context *cmd_ctx, const char *value_fmt; switch (size) { case 8: - value_fmt = "%16.16llx "; + value_fmt = "%16.16"PRIx64" "; break; case 4: - value_fmt = "%8.8x "; + value_fmt = "%8.8"PRIx64" "; break; case 2: - value_fmt = "%4.4x "; + value_fmt = "%4.4"PRIx64" "; break; case 1: - value_fmt = "%2.2x "; + value_fmt = "%2.2"PRIx64" "; break; default: /* "can't happen", caller checked */ diff --git a/tcl/target/ke02.cfg b/tcl/target/ke02.cfg deleted file mode 100644 index 8311920ad..000000000 --- a/tcl/target/ke02.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# -# Freescale Kinetis KE02 devices -# - -set CHIPNAME ke02 -source [find target/kex.cfg] diff --git a/tcl/target/ke04.cfg b/tcl/target/ke04.cfg deleted file mode 100644 index f63d77c5e..000000000 --- a/tcl/target/ke04.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# -# Freescale Kinetis KE04 devices -# - -set CHIPNAME ke04 -source [find target/kex.cfg] diff --git a/tcl/target/ke06.cfg b/tcl/target/ke06.cfg deleted file mode 100644 index 3465b8b33..000000000 --- a/tcl/target/ke06.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# -# Freescale Kinetis KE06 devices -# - -set CHIPNAME ke06 -source [find target/kex.cfg] diff --git a/tcl/target/kex.cfg b/tcl/target/ke0x.cfg similarity index 90% rename from tcl/target/kex.cfg rename to tcl/target/ke0x.cfg index dca8a35ab..7927e0ae0 100644 --- a/tcl/target/kex.cfg +++ b/tcl/target/ke0x.cfg @@ -1,5 +1,5 @@ # -# Freescale Kinetis KE series devices +# Freescale Kinetis KE0x series devices # source [find target/swj-dp.tcl] @@ -21,11 +21,7 @@ if { [info exists WORKAREASIZE] } { if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { - if { [using_jtag] } { - set _CPUTAPID 0x4ba00477 - } { - set _CPUTAPID 0x2ba01477 - } + set _CPUTAPID 0x0bc11477 } swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID diff --git a/tcl/target/ke1xf.cfg b/tcl/target/ke1xf.cfg new file mode 100644 index 000000000..b1200cec2 --- /dev/null +++ b/tcl/target/ke1xf.cfg @@ -0,0 +1,7 @@ +# +# NXP (Freescale) Kinetis KE1xF devices +# + +set CHIPNAME ke + +source [find target/kx.cfg] diff --git a/tcl/target/ke1xz.cfg b/tcl/target/ke1xz.cfg new file mode 100644 index 000000000..6a3f509ed --- /dev/null +++ b/tcl/target/ke1xz.cfg @@ -0,0 +1,7 @@ +# +# NXP (Freescale) Kinetis KE1xZ devices +# + +set CHIPNAME ke + +source [find target/klx.cfg] diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index 0df6612f7..7dd0404f9 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -1,5 +1,6 @@ # -# Freescale Kinetis KL series devices +# NXP (former Freescale) Kinetis KL series devices +# Also used for Cortex-M0+ equipped members of KVx and KE1xZ series # source [find target/swj-dp.tcl] @@ -31,11 +32,13 @@ target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash +set _FLASHNAME $_CHIPNAME.pflash flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME +kinetis create_banks # Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual -# specifies up to 1MHz for VLPR mode. +# specifies up to 1MHz for VLPR mode and up to 24MHz for run mode; +# Table 17 of Sub-Family Data Sheet rev4 lists 25MHz as the maximum frequency. adapter_khz 1000 reset_config srst_nogate @@ -51,10 +54,9 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } -# Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual -# specifies up to 24MHz for run mode; Table 17 of Sub-Family Data -# Sheet rev4 lists 25MHz as the maximum frequency. -# Uncoment only if VLPR mode is not used -#$_TARGETNAME configure -event reset-init { -# adapter_khz 24000 -#} +# Disable watchdog not to disturb OpenOCD algorithms running on MCU +# (e.g. armv7m_checksum_memory() in verify_image) +# Flash driver also disables watchdog before FTFA flash programming. +$_TARGETNAME configure -event reset-init { + kinetis disable_wdog +} diff --git a/tcl/target/kx.cfg b/tcl/target/kx.cfg index b39ee3dd1..7b0351706 100644 --- a/tcl/target/kx.cfg +++ b/tcl/target/kx.cfg @@ -1,5 +1,6 @@ # -# Freescale Kinetis Kx series devices +# NXP (former Freescale) Kinetis Kx series devices +# Also used for Cortex-M4 equipped members of KVx and KE1xF series # source [find target/swj-dp.tcl] @@ -35,8 +36,9 @@ target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -set _FLASHNAME $_CHIPNAME.flash +set _FLASHNAME $_CHIPNAME.pflash flash bank $_FLASHNAME kinetis 0 0 0 0 $_TARGETNAME +kinetis create_banks adapter_khz 1000 @@ -52,3 +54,11 @@ if {![using_hla]} { # perform a soft reset cortex_m reset_config sysresetreq } + +# Disable watchdog not to disturb OpenOCD algorithms running on MCU +# (e.g. armv7m_checksum_memory() in verify_image) +# Flash driver also disables watchdog before FTFA flash programming. +$_TARGETNAME configure -event reset-init { + kinetis disable_wdog +} + diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index b11de3287..70a861625 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -10,7 +10,8 @@ set _TARGETNAME $_CHIPNAME.cpu jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \ -expected-id 0x23727093 \ -expected-id 0x13722093 \ - -expected-id 0x03727093 + -expected-id 0x03727093 \ + -expected-id 0x03736093 jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477