This is an automated email from Gerrit. "Alan-19950616 <wangyan...@nucleisys.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8096
-- gerrit commit ea3bdaa39203b6d4cc3ea19f9b893ba347d1f25f Author: wangyanwen <wangyan...@nucleisys.com> Date: Fri Jan 19 11:00:20 2024 +0800 src/flash/nor:add custom flash Add custom flash driver to open up the flash programming algorithm. Change-Id: I4e291ea1b0cd328d223a93ddd8f2c5eb094269b4 Signed-off-by: wangyanwen <wangyan...@nucleisys.com> diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 534a7a804e..f11058b0a8 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -25,6 +25,7 @@ NOR_DRIVERS = \ %D%/cc3220sf.c \ %D%/cc26xx.c \ %D%/cfi.c \ + %D%/custom.c \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ diff --git a/src/flash/nor/custom.c b/src/flash/nor/custom.c new file mode 100644 index 0000000000..dfc0d217b2 --- /dev/null +++ b/src/flash/nor/custom.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2010 by Antonio Borneo <borneo.anto...@gmail.com> * + * Modified by Yanwen Wang <wangyan...@nucleisys.com> based on fespi.c * + * * + * 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/>. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include "imp.h" +#include "spi.h" +#include <jtag/jtag.h> +#include <helper/time_support.h> +#include <target/algorithm.h> +#include "target/riscv/riscv.h" +#include <helper/configuration.h> + +#define ERASE_CMD (1) +#define WRITE_CMD (2) +#define READ_CMD (3) +#define PROBE_CMD (4) + +struct flash_bank_msg { + bool probed; + const struct flash_device *dev; + target_addr_t ctrl_base; + char *loader_path; + uint8_t cs; + uint8_t *buffer; + uint32_t param_0; + uint32_t param_1; + bool simulation; + uint32_t sectorsize; +}; + +static int custom_run_algorithm(struct flash_bank *bank) +{ + struct flash_bank_msg *bank_msg = bank->driver_priv; + struct target *target = bank->target; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int xlen = riscv_xlen(target); + struct working_area *algorithm_wa = NULL; + struct working_area *data_wa = NULL; + uint8_t *bin = (uint8_t *)malloc(target->working_area_size); + size_t bin_size; + + FILE *fd = fopen((char *)bank_msg->loader_path, "rb"); + if (!fd) + fd = fopen(find_file(strrchr((char *)bank_msg->loader_path, '/')), "rb"); + if (fd) { + fseek(fd, 0, SEEK_END); + bin_size = ftell(fd); + rewind(fd); + if (target->working_area_size < bin_size) { + LOG_ERROR("working_area_size less than loader_bin_size"); + goto err; + } + if (fread(bin, bin_size, 1, fd) != 1) { + LOG_ERROR("read loader error"); + goto err; + } + fclose(fd); + } else { + LOG_ERROR("Failed to open loader:%s ", bank_msg->loader_path); + goto err; + } + + unsigned int data_wa_size = 0; + if (target_alloc_working_area(target, bin_size, &algorithm_wa) == ERROR_OK) { + retval = target_write_buffer(target, algorithm_wa->address, bin_size, bin); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d", + algorithm_wa->address, retval); + target_free_working_area(target, algorithm_wa); + algorithm_wa = NULL; + } else { + data_wa_size = MIN(target->working_area_size - algorithm_wa->size, bank_msg->param_0); + while (1) { + if (target_alloc_working_area_try(target, data_wa_size, &data_wa) == ERROR_OK) + break; + data_wa_size = data_wa_size * 3 / 4; + } + } + } else { + LOG_WARNING("Couldn't allocate %zd-byte working area.", bin_size); + algorithm_wa = NULL; + } + + if (algorithm_wa) { + uint32_t count = 0; + uint32_t offset = 0; + uint32_t first_addr = 0; + uint32_t end_addr = 0; + uint32_t cur_count = 0; + int algorithm_result = 0; + struct reg_param reg_params[5]; + init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); + init_reg_param(®_params[2], "a2", xlen, PARAM_OUT); + init_reg_param(®_params[3], "a3", xlen, PARAM_OUT); + init_reg_param(®_params[4], "a4", xlen, PARAM_OUT); + switch (bank_msg->cs) { + case ERASE_CMD: + first_addr = bank_msg->param_0; + end_addr = bank_msg->param_1; + buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs); + buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base); + buf_set_u64(reg_params[2].value, 0, xlen, first_addr); + buf_set_u64(reg_params[3].value, 0, xlen, end_addr); + buf_set_u64(reg_params[4].value, 0, xlen, 0); + if (bank_msg->simulation) { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, 0x7FFFFFFF, NULL); + } else { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, (end_addr - first_addr) * 2, NULL); + } + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d", + algorithm_wa->address, retval); + goto err; + } + algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen); + if (algorithm_result != 0) { + LOG_ERROR("Algorithm returned error %d", algorithm_result); + LOG_ERROR("erase command error"); + retval = ERROR_FAIL; + goto err; + } + break; + case WRITE_CMD: + count = bank_msg->param_0; + offset = bank_msg->param_1; + cur_count = 0; + while (count > 0) { + cur_count = MIN(count, data_wa_size); + buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs); + buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base); + buf_set_u64(reg_params[2].value, 0, xlen, data_wa->address); + buf_set_u64(reg_params[3].value, 0, xlen, offset); + buf_set_u64(reg_params[4].value, 0, xlen, cur_count); + retval = target_write_buffer(target, data_wa->address, cur_count, bank_msg->buffer); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed to write %d bytes to " TARGET_ADDR_FMT ": %d", + cur_count, data_wa->address, retval); + goto err; + } + if (bank_msg->simulation) { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, 0x7FFFFFFF, NULL); + } else { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, cur_count * 2, NULL); + } + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d", + algorithm_wa->address, retval); + goto err; + } + algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen); + if (algorithm_result != 0) { + LOG_ERROR("Algorithm returned error %d", algorithm_result); + LOG_ERROR("write command error"); + retval = ERROR_FAIL; + goto err; + } + bank_msg->buffer += cur_count; + offset += cur_count; + count -= cur_count; + } + break; + case READ_CMD: + count = bank_msg->param_0; + offset = bank_msg->param_1; + cur_count = 0; + while (count > 0) { + cur_count = MIN(count, data_wa_size); + buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs); + buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base); + buf_set_u64(reg_params[2].value, 0, xlen, data_wa->address); + buf_set_u64(reg_params[3].value, 0, xlen, offset); + buf_set_u64(reg_params[4].value, 0, xlen, cur_count); + if (bank_msg->simulation) { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, 0x7FFFFFFF, NULL); + } else { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, cur_count * 2, NULL); + } + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d", + algorithm_wa->address, retval); + goto err; + } + algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen); + if (algorithm_result != 0) { + LOG_ERROR("Algorithm returned error %d", algorithm_result); + LOG_ERROR("read command error"); + retval = ERROR_FAIL; + goto err; + } + retval = target_read_buffer(target, data_wa->address, cur_count, bank_msg->buffer); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed to read %d bytes from " TARGET_ADDR_FMT ": %d", + cur_count, data_wa->address, retval); + goto err; + } + bank_msg->buffer += cur_count; + offset += cur_count; + count -= cur_count; + } + break; + case PROBE_CMD: + buf_set_u64(reg_params[0].value, 0, xlen, bank_msg->cs); + buf_set_u64(reg_params[1].value, 0, xlen, bank_msg->ctrl_base); + buf_set_u64(reg_params[2].value, 0, xlen, 0); + buf_set_u64(reg_params[3].value, 0, xlen, 0); + buf_set_u64(reg_params[4].value, 0, xlen, 0); + if (bank_msg->simulation) { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, 0x7FFFFFFF, NULL); + } else { + retval = target_run_algorithm(target, 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm_wa->address, 0, 10000, NULL); + } + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at " TARGET_ADDR_FMT ": %d", + algorithm_wa->address, retval); + goto err; + } + algorithm_result = buf_get_u64(reg_params[0].value, 0, xlen); + retval = algorithm_result; + break; + default: + break; + } + target_free_working_area(target, data_wa); + target_free_working_area(target, algorithm_wa); + } + +err: + if (bin) + free(bin); + if (algorithm_wa) { + target_free_working_area(target, data_wa); + target_free_working_area(target, algorithm_wa); + } + return retval; +} + +FLASH_BANK_COMMAND_HANDLER(custom_flash_bank_command) +{ + struct flash_bank_msg *bank_msg; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 8) { + LOG_ERROR("Parameter error:"); + LOG_ERROR("flash bank $FLASHNAME custom 0x20000000 0 0 0 $TARGETNAME 0x10014000 ~/work/riscv.bin [simulation] [sectorsize=]"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bank_msg = malloc(sizeof(struct flash_bank_msg)); + if (!bank_msg) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = bank_msg; + bank_msg->probed = false; + bank_msg->ctrl_base = 0; + bank_msg->loader_path = NULL; + bank_msg->cs = 0; + bank_msg->buffer = NULL; + bank_msg->param_0 = 0; + bank_msg->param_1 = 0; + + COMMAND_PARSE_ADDRESS(CMD_ARGV[6], bank_msg->ctrl_base); + LOG_DEBUG("ASSUMING CUSTOM device at ctrl_base = " TARGET_ADDR_FMT, + bank_msg->ctrl_base); + bank_msg->loader_path = malloc(strlen(CMD_ARGV[7])); + strcpy((char *)bank_msg->loader_path, CMD_ARGV[7]); + for (char *p = bank_msg->loader_path; *p; p++) { + if (*p == '\\') + *p = '/'; + } + bank_msg->simulation = false; + bank_msg->sectorsize = 0; + for (unsigned int i = 8; i < CMD_ARGC; i++) { + if (strcmp(CMD_ARGV[i], "simulation") == 0) { + bank_msg->simulation = true; + LOG_DEBUG("Custom Simulation Mode"); + } + if (strncmp(CMD_ARGV[i], "sectorsize=", strlen("sectorsize=")) == 0) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i] + strlen("sectorsize="), bank_msg->sectorsize); + LOG_DEBUG("Custom flash sectorsize is %x", bank_msg->sectorsize); + } + } + + return ERROR_OK; +} + +static int custom_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct flash_bank_msg *bank_msg = bank->driver_priv; + + bank_msg->cs = ERASE_CMD; + bank_msg->buffer = NULL; + bank_msg->param_0 = bank->sectors[first].offset; + bank_msg->param_1 = bank->sectors[last].offset + bank_msg->sectorsize; + + return custom_run_algorithm(bank); +} + +static int custom_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct flash_bank_msg *bank_msg = bank->driver_priv; + + bank_msg->cs = WRITE_CMD; + bank_msg->buffer = (uint8_t *)buffer; + bank_msg->param_0 = count; + bank_msg->param_1 = offset; + + return custom_run_algorithm(bank); +} + +static int custom_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct flash_bank_msg *bank_msg = bank->driver_priv; + + bank_msg->cs = READ_CMD; + bank_msg->buffer = buffer; + bank_msg->param_0 = count; + bank_msg->param_1 = offset; + + return custom_run_algorithm(bank); +} + +static int custom_probe(struct flash_bank *bank) +{ + struct flash_bank_msg *bank_msg = bank->driver_priv; + + uint32_t id = 0x12345678; + struct flash_sector *sectors; + + if (bank_msg->probed) + free(bank->sectors); + bank_msg->probed = false; + + bank_msg->dev = NULL; + for (const struct flash_device *p = flash_devices; p->name ; p++) { + if (p->device_id == id) { + bank_msg->dev = p; + break; + } + } + /* Set correct size value */ + bank->size = bank_msg->dev->size_in_bytes; + /* if no sectors, treat whole bank as single sector */ + if (bank_msg->sectorsize == 0) { + bank_msg->sectorsize = bank_msg->dev->sectorsize ? + bank_msg->dev->sectorsize : bank_msg->dev->size_in_bytes; + } + /* create and fill sectors array */ + bank->num_sectors = bank_msg->dev->size_in_bytes / bank_msg->sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * bank_msg->sectorsize; + sectors[sector].size = bank_msg->sectorsize; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + bank->sectors = sectors; + + bank_msg->cs = PROBE_CMD; + bank_msg->buffer = NULL; + bank_msg->param_0 = 0; + bank_msg->param_1 = 0; + + id = custom_run_algorithm(bank); + + LOG_INFO("Found custom flash device (ID 0x%08" PRIx32 ")", id); + bank_msg->probed = true; + return ERROR_OK; +} + +static int custom_info(struct flash_bank *bank, struct command_invocation *command) +{ + struct flash_bank_msg *bank_msg = bank->driver_priv; + + if (!(bank_msg->probed)) + return ERROR_OK; + + return ERROR_OK; +} + +static int custom_auto_probe(struct flash_bank *bank) +{ + struct flash_bank_msg *bank_msg = bank->driver_priv; + if (bank_msg->probed) + return ERROR_OK; + return custom_probe(bank); +} + +static int custom_protect(struct flash_bank *bank, int set, + unsigned int first, unsigned int last) +{ + for (unsigned int sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + return ERROR_OK; +} + +static int custom_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +const struct flash_driver custom_flash = { + .name = "custom", + .flash_bank_command = custom_flash_bank_command, + .erase = custom_erase, + .protect = custom_protect, + .write = custom_write, + .read = custom_read, + .probe = custom_probe, + .auto_probe = custom_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = custom_protect_check, + .info = custom_info, + .free_driver_priv = default_flash_free_driver_priv +}; diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index bf654f9f6b..17e232a106 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -184,6 +184,7 @@ const struct flash_device flash_devices[] = { FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000), FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000), FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001560ba, 0x100, 0x10000, 0x200000), + FLASH_ID("custom flash", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00000000, 0x00, 0x10000, 0x10000000), /* FRAM, no erase commands, no write page or sectors */ --