This is an automated email from Gerrit. "Mathieu Pilato <pilato...@gmail.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6878
-- gerrit commit 809d4e8bc2203f463437cfea1d4a4538aabb844a Author: Pilatomic <pilato...@gmail.com> Date: Wed Mar 16 19:10:16 2022 +0100 topic : Artery MCUs initial support Adds initial support for Artery MCUs ( https://www.arterytek.com/cn/product/AT32F415.jsp ) Nothing fancy yet, but support enough to flash and debug a program to an AT32F415 MCU using a ST-LINK programmer. Code heavily inspired from the stm32f2x.c file. Clean checkpatch.sh output Signed-off-by: Pilatomic <pilato...@gmail.com> Change-Id: Ifbf5368ab635852d1773a2df3288503fe0d05af0 diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index a5ef422104..0914fc4ed7 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -10,6 +10,7 @@ NOR_DRIVERS = \ %D%/aduc702x.c \ %D%/aducm360.c \ %D%/ambiqmicro.c \ + %D%/artery.c \ %D%/at91sam4.c \ %D%/at91sam4l.c \ %D%/at91samd.c \ diff --git a/src/flash/nor/artery.c b/src/flash/nor/artery.c new file mode 100644 index 0000000000..3dce8c441b --- /dev/null +++ b/src/flash/nor/artery.c @@ -0,0 +1,672 @@ +/*************************************************************************** +* * +* 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, see <http://www.gnu.org/licenses/>. * +***************************************************************************/ + +/* Only tested on AT32F415 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <target/algorithm.h> +#include <target/cortex_m.h> + +#define MCU_DEVICE_ID_ADDR 0xE0042000 +#define FLASH_SIZE_ADDR 0x1FFFF7E0 +#define DEVICE_UID_ADDR 0x1FFFF7E8 +#define MASK_VERSION_ADDR 0x1FFFF7F1 +#define FLASH_BASE_ADDR 0x08000000 + +#define EFC_CTRL_REG 0x40022010 +#define EFC_PRGM_BIT (1<<0) +#define EFC_PGERS_BIT (1<<1) +#define EFC_RSTR_BIT (1<<6) +#define EFC_LOCK_BIT (1<<7) +#define EFC_FCKEY_REG 0x40022004 +#define EFC_KEY1 0x45670123 +#define EFC_KEY2 0xCDEF89AB +#define EFC_RDPRTEN 0x00A5 +#define EFC_STS_REG 0x4002200C +#define EFC_BSY_BIT (1<<0) +#define EFC_PRGMFLR_BIT (1<<2) +#define EFC_WRPRTFLR_BIT (1<<4) +#define EFC_PRCDN_BIT (1<<5) +#define EFC_ADDR_REG 0x40022014 + +#define FLASH_ERASE_TIMEOUT 100 /* 10ms actually required */ +#define FLASH_WRITE_TIMEOUT 10 /* 42us actually required */ + +struct artery_flash_bank { + bool probed; +}; + +struct artery_chip_info { + uint32_t chip_id; + uint32_t flash_size_kB; + uint32_t sector_size; + char *chip_name; +}; + +static const struct artery_chip_info known_artery_chips[] = { +{ 0xF0050340 , 1024 , 2048 , "AR8F403CGT6-A" }, +{ 0xF0050340 , 1024 , 2048 , "AR8F403CGT6" }, +{ 0x70050242 , 256 , 2048 , "AT32F403ACCT7" }, +{ 0x70050243 , 256 , 2048 , "AT32F403ACCU7" }, +{ 0x700502CF , 512 , 2048 , "AT32F403ACET7" }, +{ 0x700502D0 , 512 , 2048 , "AT32F403ACEU7" }, +{ 0x70050346 , 1024 , 2048 , "AT32F403ACGT7" }, +{ 0x70050347 , 1024 , 2048 , "AT32F403ACGU7" }, +{ 0x70050241 , 256 , 2048 , "AT32F403ARCT7" }, +{ 0x700502CE , 512 , 2048 , "AT32F403ARET7" }, +{ 0x70050345 , 1024 , 2048 , "AT32F403ARGT7" }, +{ 0x70050240 , 256 , 2048 , "AT32F403AVCT7" }, +{ 0x700502CD , 512 , 2048 , "AT32F403AVET7" }, +{ 0x70050344 , 1024 , 2048 , "AT32F403AVGT7" }, +{ 0xF0050355 , 1024 , 2048 , "AT32F403AVGW" }, +{ 0x700301CF , 128 , 1024 , "AT32F403CBT6" }, +{ 0x70050243 , 256 , 2048 , "AT32F403CCT6" }, +{ 0x7005024E , 256 , 2048 , "AT32F403CCU6" }, +{ 0x700502CB , 512 , 2048 , "AT32F403CET6" }, +{ 0x700502CD , 512 , 2048 , "AT32F403CEU6" }, +{ 0x70050347 , 1024 , 2048 , "AT32F403CGT6" }, +{ 0x7005034C , 1024 , 2048 , "AT32F403CGU6" }, +{ 0x70050242 , 256 , 2048 , "AT32F403RCT6" }, +{ 0x700502CA , 512 , 2048 , "AT32F403RET6" }, +{ 0x70050346 , 1024 , 2048 , "AT32F403RGT6" }, +{ 0x70050241 , 256 , 2048 , "AT32F403VCT6" }, +{ 0x700502C9 , 512 , 2048 , "AT32F403VET6" }, +{ 0x70050345 , 1024 , 2048 , "AT32F403VGT6" }, +{ 0x70050240 , 256 , 2048 , "AT32F403ZCT6" }, +{ 0x700502C8 , 512 , 2048 , "AT32F403ZET6" }, +{ 0x70050344 , 1024 , 2048 , "AT32F403ZGT6" }, +{ 0x70050254 , 256 , 2048 , "AT32F407AVCT7" }, +{ 0x70050353 , 1024 , 2048 , "AT32F407AVGT7" }, +{ 0x7005024A , 256 , 2048 , "AT32F407RCT7" }, +{ 0x700502D2 , 512 , 2048 , "AT32F407RET7" }, +{ 0x7005034C , 1024 , 2048 , "AT32F407RGT7" }, +{ 0x70050249 , 256 , 2048 , "AT32F407VCT7" }, +{ 0x700502D1 , 512 , 2048 , "AT32F407VET7" }, +{ 0x7005034B , 1024 , 2048 , "AT32F407VGT7" }, +{ 0x70030106 , 64 , 1024 , "AT32F413C8T7" }, +{ 0x700301C3 , 128 , 1024 , "AT32F413CBT7" }, +{ 0x700301CA , 128 , 1024 , "AT32F413CBU7" }, +{ 0x70030242 , 256 , 2048 , "AT32F413CCT7" }, +{ 0x70030247 , 256 , 2048 , "AT32F413CCU7" }, +{ 0x700301C5 , 128 , 1024 , "AT32F413KBU7-4" }, +{ 0x70030244 , 256 , 2048 , "AT32F413KCU7-4" }, +{ 0x700301C1 , 128 , 1024 , "AT32F413RBT7" }, +{ 0x70030240 , 256 , 2048 , "AT32F413RCT7" }, +{ 0x700301CB , 128 , 1024 , "AT32F413TBU7" }, +{ 0x70030109 , 64 , 1024 , "AT32F415C8T7" }, +{ 0x700301C5 , 128 , 1024 , "AT32F415CBT7" }, +{ 0x700301CD , 128 , 1024 , "AT32F415CBU7" }, +{ 0x70030241 , 256 , 2048 , "AT32F415CCT7" }, +{ 0x7003024C , 256 , 2048 , "AT32F415CCU7" }, +{ 0x7003010A , 64 , 1024 , "AT32F415K8U7-4" }, +{ 0x700301C6 , 128 , 1024 , "AT32F415KBU7-4" }, +{ 0x70030242 , 256 , 2048 , "AT32F415KCU7-4" }, +{ 0x7003010B , 64 , 1024 , "AT32F415R8T7-7" }, +{ 0x70030108 , 64 , 1024 , "AT32F415R8T7" }, +{ 0x700301C7 , 128 , 1024 , "AT32F415RBT7-7" }, +{ 0x700301C4 , 128 , 1024 , "AT32F415RBT7" }, +{ 0x700301CF , 128 , 1024 , "AT32F415RBW" }, +{ 0x70030243 , 256 , 2048 , "AT32F415RCT7-7" }, +{ 0x70030240 , 256 , 2048 , "AT32F415RCT7" }, +{ 0x7003024E , 256 , 2048 , "AT32F415RCW" }, +{ 0x5001000C , 16 , 1024 , "AT32F421C4T7" }, +{ 0x50020086 , 32 , 1024 , "AT32F421C6T7" }, +{ 0x50020100 , 64 , 1024 , "AT32F421C8T7" }, +{ 0xD0020100 , 64 , 1024 , "AT32F421C8W-YY" }, +{ 0x50020117 , 64 , 1024 , "AT32F421C8W" }, +{ 0x50010011 , 16 , 1024 , "AT32F421F4P7" }, +{ 0x50010010 , 16 , 1024 , "AT32F421F4U7" }, +{ 0x5002008B , 32 , 1024 , "AT32F421F6P7" }, +{ 0x5002008A , 32 , 1024 , "AT32F421F6U7" }, +{ 0x50020105 , 64 , 1024 , "AT32F421F8P7" }, +{ 0x50020104 , 64 , 1024 , "AT32F421F8U7" }, +{ 0x50010014 , 16 , 1024 , "AT32F421G4U7" }, +{ 0x50020093 , 32 , 1024 , "AT32F421G6U7" }, +{ 0x50020112 , 64 , 1024 , "AT32F421G8U7" }, +{ 0x5001000D , 16 , 1024 , "AT32F421K4T7" }, +{ 0x5001000F , 16 , 1024 , "AT32F421K4U7-4" }, +{ 0x5001000E , 16 , 1024 , "AT32F421K4U7" }, +{ 0x50020087 , 32 , 1024 , "AT32F421K6T7" }, +{ 0x50020089 , 32 , 1024 , "AT32F421K6U7-4" }, +{ 0x50020088 , 32 , 1024 , "AT32F421K6U7" }, +{ 0x50020101 , 64 , 1024 , "AT32F421K8T7" }, +{ 0x50020103 , 64 , 1024 , "AT32F421K8U7-4" }, +{ 0x50020102 , 64 , 1024 , "AT32F421K8U7" }, +{ 0x50010016 , 16 , 1024 , "AT32F421PF4P7" }, +{ 0x50020115 , 64 , 1024 , "AT32F421PF8P7" }, +{ 0x7003210B , 64 , 1024 , "AT32F423C8T7" }, +{ 0x7003210E , 64 , 1024 , "AT32F423C8U7" }, +{ 0x700A21CA , 128 , 1024 , "AT32F423CBT7" }, +{ 0x700A21CD , 128 , 1024 , "AT32F423CBU7" }, +{ 0x700A3249 , 256 , 2048 , "AT32F423CCT7" }, +{ 0x700A324C , 256 , 2048 , "AT32F423CCU7" }, +{ 0x70032115 , 64 , 1024 , "AT32F423K8U7-4" }, +{ 0x700A21D4 , 128 , 1024 , "AT32F423KBU7-4" }, +{ 0x700A3253 , 256 , 2048 , "AT32F423KCU7-4" }, +{ 0x70032108 , 64 , 1024 , "AT32F423R8T7-7" }, +{ 0x70032105 , 64 , 1024 , "AT32F423R8T7" }, +{ 0x700A21C7 , 128 , 1024 , "AT32F423RBT7-7" }, +{ 0x700A21C4 , 128 , 1024 , "AT32F423RBT7" }, +{ 0x700A3246 , 256 , 2048 , "AT32F423RCT7-7" }, +{ 0x700A3243 , 256 , 2048 , "AT32F423RCT7" }, +{ 0x70032112 , 64 , 1024 , "AT32F423T8U7" }, +{ 0x700A21D1 , 128 , 1024 , "AT32F423TBU7" }, +{ 0x700A3250 , 256 , 2048 , "AT32F423TCU7" }, +{ 0x70032102 , 64 , 1024 , "AT32F423V8T7" }, +{ 0x700A21C1 , 128 , 1024 , "AT32F423VBT7" }, +{ 0x700A3240 , 256 , 2048 , "AT32F423VCT7" }, +{ 0x50092087 , 32 , 1024 , "AT32F425C6T7" }, +{ 0x5009208A , 32 , 1024 , "AT32F425C6U7" }, +{ 0x50092106 , 64 , 1024 , "AT32F425C8T7" }, +{ 0x50092109 , 64 , 1024 , "AT32F425C8U7" }, +{ 0x50092093 , 32 , 1024 , "AT32F425F6P7" }, +{ 0x50092112 , 64 , 1024 , "AT32F425F8P7" }, +{ 0x50092096 , 32 , 1024 , "AT32F425G6U7" }, +{ 0x50092115 , 64 , 1024 , "AT32F425G8U7" }, +{ 0x5009208D , 32 , 1024 , "AT32F425K6T7" }, +{ 0x50092090 , 32 , 1024 , "AT32F425K6U7-4" }, +{ 0x5009210C , 64 , 1024 , "AT32F425K8T7" }, +{ 0x5009210F , 64 , 1024 , "AT32F425K8U7-4" }, +{ 0x50092084 , 32 , 1024 , "AT32F425R6T7-7" }, +{ 0x50092081 , 32 , 1024 , "AT32F425R6T7" }, +{ 0x50092103 , 64 , 1024 , "AT32F425R8T7-7" }, +{ 0x50092100 , 64 , 1024 , "AT32F425R8T7" }, +{ 0x7008449A , 192 , 4096 , "AT32F435CCT7-W" }, +{ 0x7008324B , 256 , 2048 , "AT32F435CCT7" }, +{ 0x7008449D , 192 , 4096 , "AT32F435CCU7-W" }, +{ 0x7008324E , 256 , 2048 , "AT32F435CCU7" }, +{ 0x700844D9 , 960 , 4096 , "AT32F435CGT7-W" }, +{ 0x7008334A , 1024 , 2048 , "AT32F435CGT7" }, +{ 0x700844DC , 960 , 4096 , "AT32F435CGU7-W" }, +{ 0x7008334D , 1024 , 2048 , "AT32F435CGU7" }, +{ 0x70084558 , 4032 , 4096 , "AT32F435CMT7-E" }, +{ 0x70084549 , 4032 , 4096 , "AT32F435CMT7" }, +{ 0x7008455B , 4032 , 4096 , "AT32F435CMU7-E" }, +{ 0x7008454C , 4032 , 4096 , "AT32F435CMU7" }, +{ 0x70083248 , 256 , 2048 , "AT32F435RCT7" }, +{ 0x70083347 , 1024 , 2048 , "AT32F435RGT7" }, +{ 0x70084546 , 4032 , 4096 , "AT32F435RMT7" }, +{ 0x70083245 , 256 , 2048 , "AT32F435VCT7" }, +{ 0x70083344 , 1024 , 2048 , "AT32F435VGT7" }, +{ 0x70084543 , 4032 , 4096 , "AT32F435VMT7" }, +{ 0x70083242 , 256 , 2048 , "AT32F435ZCT7" }, +{ 0x70083341 , 1024 , 2048 , "AT32F435ZGT7" }, +{ 0x70084540 , 4032 , 4096 , "AT32F435ZMT7" }, +{ 0x70083257 , 256 , 2048 , "AT32F437RCT7" }, +{ 0x70083356 , 1024 , 2048 , "AT32F437RGT7" }, +{ 0x70084555 , 4032 , 4096 , "AT32F437RMT7" }, +{ 0x70083254 , 256 , 2048 , "AT32F437VCT7" }, +{ 0x70083353 , 1024 , 2048 , "AT32F437VGT7" }, +{ 0x70084552 , 4032 , 4096 , "AT32F437VMT7" }, +{ 0x70083251 , 256 , 2048 , "AT32F437ZCT7" }, +{ 0x70083350 , 1024 , 2048 , "AT32F437ZGT7" }, +{ 0x7008454F , 4032 , 4096 , "AT32F437ZMT7" }, +{ 0x70030109 , 64 , 1024 , "AT32FEBKC8T7" }, +{ 0x10012006 , 16 , 1024 , "AT32L021C4T7" }, +{ 0x1001208D , 32 , 1024 , "AT32L021C6T7" }, +{ 0x10012114 , 64 , 1024 , "AT32L021C8T7" }, +{ 0x10012001 , 16 , 1024 , "AT32L021F4P7" }, +{ 0x10012002 , 16 , 1024 , "AT32L021F4U7" }, +{ 0x10012088 , 32 , 1024 , "AT32L021F6P7" }, +{ 0x10012089 , 32 , 1024 , "AT32L021F6U7" }, +{ 0x1001210F , 64 , 1024 , "AT32L021F8P7" }, +{ 0x10012110 , 64 , 1024 , "AT32L021F8U7" }, +{ 0x10012000 , 16 , 1024 , "AT32L021G4U7" }, +{ 0x10012087 , 32 , 1024 , "AT32L021G6U7" }, +{ 0x1001210E , 64 , 1024 , "AT32L021G8U7" }, +{ 0x10012005 , 16 , 1024 , "AT32L021K4T7" }, +{ 0x10012003 , 16 , 1024 , "AT32L021K4U7-4" }, +{ 0x10012004 , 16 , 1024 , "AT32L021K4U7" }, +{ 0x1001208C , 32 , 1024 , "AT32L021K6T7" }, +{ 0x1001208A , 32 , 1024 , "AT32L021K6U7-4" }, +{ 0x1001208B , 32 , 1024 , "AT32L021K6U7" }, +{ 0x10012113 , 64 , 1024 , "AT32L021K8T7" }, +{ 0x10012111 , 64 , 1024 , "AT32L021K8U7-4" }, +{ 0x10012112 , 64 , 1024 , "AT32L021K8U7" }, +{ 0x70030250 , 256 , 2048 , "AT32WB415CCU7-7" }, +{ 0xF00301C2 , 128 , 1024 , "KC9060" }, +{ 0 , 0 , 0 , NULL } +}; + +static int artery_find_chip_from_id(uint32_t id, const struct artery_chip_info **chip_info) +{ + const struct artery_chip_info *curr_chip = known_artery_chips; + while (curr_chip->chip_id != 0 || curr_chip->chip_name != NULL) { + if (curr_chip->chip_id == id) { + if (chip_info) + *chip_info = curr_chip; + return ERROR_OK; + } + curr_chip += 1; + } + return ERROR_FAIL; +} + +static int artery_guess_sector_size_from_flash_size(int flash_size_kb) +{ + /* According to device DB, devices with 4096 byte sectors do not have a power of 2 kB of FLASH */ + if ((flash_size_kb & (flash_size_kb - 1)) != 0) + return 4096; + + /* According to AT32F415 code examples, FLASH <= 128kB means 1024 bytes setor size */ + if (flash_size_kb <= 128) + return 1024; + + /* Other devices have 2048 bytes per sectors */ + return 2048; +} + +static int artery_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct artery_flash_bank *artery_bank_info = bank->driver_priv; + uint32_t device_id, sector_size; + uint16_t read_flash_size_in_kb; + unsigned int num_sectors; + unsigned int flash_size; + const struct artery_chip_info *chip_info = 0; + int retval; + + artery_bank_info->probed = false; + + free(bank->sectors); + bank->num_sectors = 0; + bank->sectors = NULL; + + free(bank->prot_blocks); + bank->num_prot_blocks = 0; + bank->prot_blocks = NULL; + + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + /* Read device ID */ + retval = target_read_u32(target, MCU_DEVICE_ID_ADDR, &device_id); + if (retval != ERROR_OK) { + LOG_WARNING("Cannot read device ID."); + return retval; + } + + /* get flash size from target. */ + retval = target_read_u16(target, FLASH_SIZE_ADDR, &read_flash_size_in_kb); + if (retval != ERROR_OK || read_flash_size_in_kb == 0xffff || read_flash_size_in_kb == 0) { + LOG_WARNING("Cannot read flash size."); + return ERROR_FAIL; + } + + /* look up chip id in known chip db */ + retval = artery_find_chip_from_id(device_id, &chip_info); + if (retval == ERROR_OK) { + /* known flash size matches read flash size. Trust known sector size */ + if (read_flash_size_in_kb == chip_info->flash_size_kB) { + sector_size = chip_info->sector_size; + LOG_INFO("Chip: %s, %" PRIi32 "kB FLASH, %" PRIi32 " bytes sectors", + chip_info->chip_name, read_flash_size_in_kb, sector_size); + } + + /* Known flash size does not match read flash size. Guess sector size */ + else { + sector_size = artery_guess_sector_size_from_flash_size(read_flash_size_in_kb); + LOG_INFO("Chip: %s, %" PRIi32 "kB FLASH expected, but %" PRIi32 \ + "kB detected. Guessing %" PRIi32 " bytes sectors", + chip_info->chip_name, chip_info->flash_size_kB, + read_flash_size_in_kb, sector_size); + } + } + + /* Unknown chip. Guess sector size */ + else { + sector_size = artery_guess_sector_size_from_flash_size(read_flash_size_in_kb); + LOG_INFO("Unknown chip id: %" PRIi32 ", %" PRIi32 \ + "kB FLASH detected. Guessing %" PRIi32 " bytes sectors", + device_id, read_flash_size_in_kb, sector_size); + } + + flash_size = read_flash_size_in_kb; + flash_size <<= 10; + + num_sectors = flash_size / sector_size; + if ((num_sectors * sector_size) != flash_size) { + LOG_ERROR("Total FLASH size does not match sector size times sectors count !"); + return ERROR_FAIL; + } + + bank->base = FLASH_BASE_ADDR; + bank->num_sectors = num_sectors; + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); + bank->size = flash_size; + for (unsigned int i = 0; i < num_sectors; i++) { + bank->sectors[i].offset = i * sector_size; + bank->sectors[i].size = sector_size; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = -1; + /* Currently we simply ignore sector protection. TODO : implement protection read / write */ + } + LOG_DEBUG("allocated %u sectors", num_sectors); + + artery_bank_info->probed = true; + return ERROR_OK; +} + +/* flash bank stm32x <base> <size> 0 0 <target#> +*/ +FLASH_BANK_COMMAND_HANDLER(artery_flash_bank_command) +{ + struct artery_flash_bank *artery_bank_info; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + artery_bank_info = malloc(sizeof(struct artery_flash_bank)); + bank->driver_priv = artery_bank_info; + + artery_bank_info->probed = false; + + return ERROR_OK; +} + +static const struct command_registration artery_exec_command_handlers[] = { + COMMAND_REGISTRATION_DONE +}; + +static int artery_auto_probe(struct flash_bank *bank) +{ + struct artery_flash_bank *artery_bank_info = bank->driver_priv; + if (artery_bank_info->probed) + return ERROR_OK; + return artery_probe(bank); +} + +static int artery_print_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct target *target = bank->target; + uint32_t device_id; + uint16_t flash_size_in_kb; + uint8_t mask_version; + int retval; + const struct artery_chip_info *chip_info = 0; + + /* Read device ID */ + retval = target_read_u32(target, MCU_DEVICE_ID_ADDR, &device_id); + if (retval != ERROR_OK) { + LOG_WARNING("Cannot read device ID."); + return retval; + } + + /* Read revision */ + retval = target_read_u8(target, MASK_VERSION_ADDR, &mask_version); + if (retval != ERROR_OK) { + LOG_WARNING("Cannot read mask version."); + return retval; + } + mask_version = ((mask_version >> 4) & 0x07) + 'A'; + + /* Read Flash size */ + retval = target_read_u16(target, FLASH_SIZE_ADDR, &flash_size_in_kb); + if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { + LOG_WARNING("Cannot read flash size."); + return retval; + } + + /* look up chip id in known chip db */ + retval = artery_find_chip_from_id(device_id, &chip_info); + if (retval == ERROR_OK) + command_print_sameline(cmd, "Chip: %s Rev. %c, %" PRIi32 "kB FLASH", + chip_info->chip_name, mask_version, flash_size_in_kb); + else + command_print_sameline(cmd, "Unknown chip, Id: 0x%08" PRIx32 \ + ", Rev: %c, %" PRIi32 "kB FLASH", + device_id, mask_version, flash_size_in_kb); + + return ERROR_OK; +} + +static int artery_wait_status_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + uint32_t status; + int retval = ERROR_OK; + + /* wait for busy to clear */ + for (;;) { + retval = target_read_u32(target, EFC_STS_REG, &status); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("status: 0x%" PRIx32, status); + if ((status & EFC_BSY_BIT) == 0) + break; + if (timeout-- <= 0) { + LOG_ERROR("timed out waiting for flash"); + return ERROR_FAIL; + } + alive_sleep(1); + } + + if (status & EFC_WRPRTFLR_BIT) { + LOG_ERROR("Device protected"); + retval = ERROR_FAIL; + } + + /* Clear but report errors */ + if (status & EFC_WRPRTFLR_BIT) { + LOG_ERROR("Attempt to write an address that has not been erased before"); + retval = ERROR_FAIL; + } + return retval; +} + + +static int artery_unlock_flash_write(struct target *target) +{ + uint32_t ctrl; + + int retval = target_read_u32(target, EFC_CTRL_REG, &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & EFC_LOCK_BIT) == 0) + return ERROR_OK; + + /* unlock flash registers */ + retval = target_write_u32(target, EFC_FCKEY_REG, EFC_KEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, EFC_FCKEY_REG, EFC_KEY2); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, EFC_CTRL_REG, &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & EFC_LOCK_BIT) { + LOG_ERROR("flash not unlocked FLASH_CTRL: 0x%" PRIx32, ctrl); + return ERROR_TARGET_FAILURE; + } + + return ERROR_OK; +} + +static int artery_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct target *target = bank->target; + + assert((first <= last) && (last < bank->num_sectors)); + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval; + retval = artery_unlock_flash_write(target); + if (retval != ERROR_OK) + return retval; + + /* Wait for flash not busy */ + retval = artery_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = first; i <= last; i++) { + /* Clear status register beforehand */ + target_write_u32(target, EFC_STS_REG, EFC_PRCDN_BIT | EFC_WRPRTFLR_BIT | EFC_PRGMFLR_BIT); + + /* Set the PGERS bit in the FLASH_CTRLx register */ + retval = target_write_u32(target, EFC_CTRL_REG, EFC_PGERS_BIT); + if (retval != ERROR_OK) + return retval; + + /* Select the page to be erased with the FLASH_ADDRx register */ + target_addr_t eraseAddress = bank->base + bank->sectors[i].offset; + retval = target_write_u32(target, EFC_ADDR_REG, eraseAddress); + if (retval != ERROR_OK) + return retval; + + /* Set the RSTR bit in the FLASH_CTRLx register */ + retval = target_write_u32(target, EFC_CTRL_REG, EFC_PGERS_BIT | EFC_RSTR_BIT); + if (retval != ERROR_OK) + return retval; + + /* Wait for flash not busy */ + retval = artery_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + } + + /* Re-lock flash */ + retval = target_write_u32(target, EFC_CTRL_REG, EFC_LOCK_BIT); + return retval; +} + +static int artery_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + target_addr_t write_address = bank->base + offset; + uint32_t bytes_written = 0; + int retval; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = artery_unlock_flash_write(target); + if (retval != ERROR_OK) + return retval; + + /* Write byte by byte until we align to a word */ + while ((bytes_written < count) && (write_address & 0x03)) { + /* Set the PRGM bit = 1 in FLASH_CTRL */ + retval = target_write_u32(target, EFC_CTRL_REG, EFC_PRGM_BIT); + if (retval != ERROR_OK) + return retval; + + /* Write byte to flash */ + retval = target_write_u8(target, write_address, buffer[bytes_written]); + if (retval != ERROR_OK) + return retval; + + retval = artery_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + bytes_written += 1; + write_address += 1; + } + + /* First write word by word, as it provides the highest write speed */ + while (bytes_written < (count - 3)) { + /* Set the PRGM bit = 1 in FLASH_CTRL */ + retval = target_write_u32(target, EFC_CTRL_REG, EFC_PRGM_BIT); + if (retval != ERROR_OK) + return retval; + + /* Write word to flash */ + retval = target_write_memory(target, write_address, 4, 1, buffer + bytes_written); + if (retval != ERROR_OK) + return retval; + + retval = artery_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + bytes_written += 4; + write_address += 4; + } + + /* Write potential last bytes */ + while (bytes_written < count) { + /* Set the PRGM bit = 1 in FLASH_CTRL */ + retval = target_write_u32(target, EFC_CTRL_REG, EFC_PRGM_BIT); + if (retval != ERROR_OK) + return retval; + + /* Write byte to flash */ + retval = target_write_u8(target, write_address, buffer[bytes_written]); + if (retval != ERROR_OK) + return retval; + + retval = artery_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + bytes_written += 1; + write_address += 1; + } + + /* Re-lock flash */ + retval = target_write_u32(target, EFC_CTRL_REG, EFC_LOCK_BIT); + return retval; +} + +static const struct command_registration artery_command_handlers[] = { +{ + .name = "artery", + .mode = COMMAND_ANY, + .help = "artery flash command group", + .usage = "", + .chain = artery_exec_command_handlers, +}, +COMMAND_REGISTRATION_DONE +}; + + +const struct flash_driver artery_flash = { + .name = "artery", + .commands = artery_command_handlers, + .flash_bank_command = artery_flash_bank_command, + .erase = artery_erase, + .protect = NULL, + .write = artery_write, + .read = default_flash_read, + .probe = artery_probe, + .auto_probe = artery_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = NULL, + .info = artery_print_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3e35c0954d..bf78b076c1 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -89,6 +89,7 @@ extern const struct flash_driver w600_flash; extern const struct flash_driver xcf_flash; extern const struct flash_driver xmc1xxx_flash; extern const struct flash_driver xmc4xxx_flash; +extern const struct flash_driver artery_flash; /** * The list of built-in flash drivers. @@ -98,6 +99,7 @@ static const struct flash_driver * const flash_drivers[] = { &aduc702x_flash, &aducm360_flash, &ambiqmicro_flash, + &artery_flash, &at91sam3_flash, &at91sam4_flash, &at91sam4l_flash, --