diff --git a/configure.ac b/configure.ac index 274be15c3..7b20d48ea 100644 --- a/configure.ac +++ b/configure.ac @@ -670,7 +670,11 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBGPIOD], [libgpiod], [use_libgpiod=yes], [use_libgpiod=no]) +PKG_CHECK_MODULES([LIBGPIOD], [libgpiod < 2.0], [ + use_libgpiod=yes + PKG_CHECK_EXISTS([libgpiod >= 1.5], + [AC_DEFINE([HAVE_LIBGPIOD1_FLAGS_BIAS], [1], [define if libgpiod v1 has line request flags bias])]) +], [use_libgpiod=no]) PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) diff --git a/doc/manual/jtag/drivers/remote_bitbang.txt b/doc/manual/jtag/drivers/remote_bitbang.txt index 94d603816..8316cb0dd 100644 --- a/doc/manual/jtag/drivers/remote_bitbang.txt +++ b/doc/manual/jtag/drivers/remote_bitbang.txt @@ -77,7 +77,12 @@ The read responses are encoded in ASCII as either digit 0 or 1. If the use_remote_sleep option is set to 'yes', two additional requests may be sent: - D - Sleep for 1 millisecond - d - Sleep for 1 microsecond + Z - Sleep for 1 millisecond + z - Sleep for 1 microsecond + +NOTE: Previously these were specified as 'D' and 'd', which conflicts with the +"SWD write 0 0" command defined above. Adapters that implement Dd for remote +sleep must be updated to work with Zz. + */ diff --git a/doc/openocd.texi b/doc/openocd.texi index 832ec7737..47879cc54 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6805,6 +6805,24 @@ Note that in order for this command to take effect, the target needs to be reset supported.} @end deffn +@deffn {Flash Driver} {eneispif} +All versions of the KB1200 microcontrollers from ENE include internal +flash. The eneispif flash driver supports the KB1200 family of devices. The driver +automatically recognizes the specific version's flash parameters and +autoconfigures itself. The flash bank starts at address 0x60000000. An optional additional +parameter sets the address of eneispif controller, with the default address is 0x50101000. + +@example + +flash bank $_FLASHNAME eneispif 0x60000000 0 0 0 $_TARGETNAME \ + 0x50101000 + +# Address defaults to 0x50101000 +flash bank $_FLASHNAME eneispif 0x60000000 0 0 0 $_TARGETNAME + +@end example +@end deffn + @deffn {Flash Driver} {esirisc} Members of the eSi-RISC family may optionally include internal flash programmed via the eSi-TSMC Flash interface. Additional parameters are required to diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 534a7a804..afa11e7d4 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -28,6 +28,7 @@ NOR_DRIVERS = \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ + %D%/eneispif.c \ %D%/esirisc_flash.c \ %D%/faux.c \ %D%/fespi.c \ diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index a63b72c8f..7d6f8c5cc 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -256,6 +256,7 @@ extern const struct flash_driver cfi_flash; extern const struct flash_driver dsp5680xx_flash; extern const struct flash_driver efm32_flash; extern const struct flash_driver em357_flash; +extern const struct flash_driver eneispif_flash; extern const struct flash_driver esirisc_flash; extern const struct flash_driver faux_flash; extern const struct flash_driver fespi_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3157bd329..34359889a 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -33,6 +33,7 @@ static const struct flash_driver * const flash_drivers[] = { &dsp5680xx_flash, &efm32_flash, &em357_flash, + &eneispif_flash, &esirisc_flash, &faux_flash, &fm3_flash, diff --git a/src/flash/nor/eneispif.c b/src/flash/nor/eneispif.c new file mode 100644 index 000000000..6572b8c25 --- /dev/null +++ b/src/flash/nor/eneispif.c @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (c) 2024 ENE Technology Inc. + * steven@ene.com.tw +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#define ISPICFG 0x0000 +#define ISPISTS 0x0004 +#define ISPIADDR 0x0008 +#define ISPICMD 0x000C +#define ISPIDAT 0x0100 + +#define ISPISTS_BUSY BIT(0) +#define STATUS1_QE BIT(1) + +#define CFG_READ 0x372 +#define CFG_WRITE 0x371 + +#define ISPI_CTRL_BASE 0x50101000 + +/* name read qread page erase chip device_id page erase flash + * _cmd _cmd _prog _cmd* _erase size size* size + * _cmd _cmd + */ +struct flash_device ene_flash_device = + FLASH_ID("ISPI flash", 0x03, 0x00, 0x02, 0x20, 0x60, 0x00132085, 0x100, 0x1000, 0x80000); + +struct eneispif_flash_bank { + bool probed; + target_addr_t ctrl_base; + uint32_t dev_id; + const struct flash_device *dev; +}; + +FLASH_BANK_COMMAND_HANDLER(eneispif_flash_bank_command) +{ + struct eneispif_flash_bank *eneispif_info; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + eneispif_info = malloc(sizeof(struct eneispif_flash_bank)); + if (!eneispif_info) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = eneispif_info; + eneispif_info->probed = false; + eneispif_info->ctrl_base = ISPI_CTRL_BASE; + if (CMD_ARGC >= 7) { + COMMAND_PARSE_ADDRESS(CMD_ARGV[6], eneispif_info->ctrl_base); + LOG_INFO("ASSUMING ISPI device at ctrl_base = " TARGET_ADDR_FMT, + eneispif_info->ctrl_base); + } + + return ERROR_OK; +} + +static int eneispif_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_t address) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + int result = target_read_u32(target, eneispif_info->ctrl_base + address, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error at " TARGET_ADDR_FMT, __func__, + eneispif_info->ctrl_base + address); + return result; + } + LOG_DEBUG("Read address " TARGET_ADDR_FMT " = 0x%" PRIx32, + eneispif_info->ctrl_base + address, *value); + return ERROR_OK; +} + +static int eneispif_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + LOG_DEBUG("Write address " TARGET_ADDR_FMT " = 0x%" PRIx32, + eneispif_info->ctrl_base + address, value); + int result = target_write_u32(target, eneispif_info->ctrl_base + address, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error writing 0x%" PRIx32 " to " TARGET_ADDR_FMT, __func__, + value, eneispif_info->ctrl_base + address); + return result; + } + return ERROR_OK; +} + +static int eneispif_wait(struct flash_bank *bank) +{ + int64_t start = timeval_ms(); + + while (1) { + uint32_t status; + + if (eneispif_read_reg(bank, &status, ISPISTS) != ERROR_OK) + return ERROR_FAIL; + + if (!(status & ISPISTS_BUSY)) + break; + + int64_t now = timeval_ms(); + if (now - start > 1000) { + LOG_ERROR("Busy more than 1000ms."); + return ERROR_TARGET_TIMEOUT; + } + } + + return ERROR_OK; +} + +static int eneispi_erase_sector(struct flash_bank *bank, int sector) +{ + int retval = ERROR_OK; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + uint32_t offset; + uint32_t conf; + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + offset = bank->sectors[sector].offset; + retval = eneispif_write_reg(bank, ISPIADDR, offset); /* Address */ + if (retval != ERROR_OK) + goto done; + + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); /* Cmmmand enable */ + eneispif_write_reg(bank, ISPICMD, SPIFLASH_WRITE_ENABLE); /* Write enable */ + retval = eneispif_write_reg(bank, ISPICMD, eneispif_info->dev->erase_cmd); /* Erase page */ + if (retval != ERROR_OK) + goto done; + + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto done; + +done: + eneispif_write_reg(bank, ISPICFG, conf); /* restore */ + return retval; +} + +static int eneispif_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + int retval = ERROR_OK; + + LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (last < first || last >= bank->num_sectors) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + if (!(eneispif_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + for (unsigned int sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FAIL; + } + } + + if (eneispif_info->dev->erase_cmd == 0x00) + return ERROR_FLASH_OPER_UNSUPPORTED; + + for (unsigned int sector = first; sector <= last; sector++) { + retval = eneispi_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + } + + return retval; +} + +static int eneispif_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 eneispif_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, + uint32_t count) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + uint32_t page_size; + uint32_t conf; + int retval = ERROR_OK; + + LOG_DEBUG("bank->size=0x%x offset=0x%08" PRIx32 " count=0x%08" PRIx32, bank->size, offset, + count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > eneispif_info->dev->size_in_bytes) { + LOG_WARNING("Write past end of flash. Extra data discarded."); + count = eneispif_info->dev->size_in_bytes - offset; + } + + /* Check sector protection */ + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && + ((offset + count - 1) >= bank->sectors[sector].offset) && + bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FAIL; + } + } + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); // Cmmmand enable + + /* If no valid page_size, use reasonable default. */ + page_size = + eneispif_info->dev->pagesize ? eneispif_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; + uint32_t page_offset = offset % page_size; + + while (count > 0) { + uint32_t cur_count; + + /* clip block at page boundary */ + if (page_offset + count > page_size) + cur_count = page_size - page_offset; + else + cur_count = count; + + eneispif_write_reg(bank, ISPICMD, SPIFLASH_WRITE_ENABLE); /* Write enable */ + target_write_buffer(target, eneispif_info->ctrl_base + ISPIDAT, cur_count, buffer); + eneispif_write_reg(bank, ISPIADDR, offset); + retval = eneispif_write_reg(bank, ISPICMD, + (cur_count << 16) | eneispif_info->dev->pprog_cmd); + if (retval != ERROR_OK) + goto err; + + page_offset = 0; + buffer += cur_count; + offset += cur_count; + count -= cur_count; + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto err; + } + +err: + eneispif_write_reg(bank, ISPICFG, conf); /* restore */ + return retval; +} + +/* Return ID of flash device */ +/* On exit, SW mode is kept */ +static int eneispif_read_flash_id(struct flash_bank *bank, uint32_t *id) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + struct target *target = bank->target; + int retval; + uint32_t conf, value; + uint8_t buffer[4]; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("ISPCFG = (0x%08" PRIx32 ")", conf); + + /* read ID from Receive Register */ + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); /* Cmmmand enable */ + retval = eneispif_write_reg(bank, ISPICMD, (3 << 16) | SPIFLASH_READ_ID); + if (retval != ERROR_OK) + goto done; + + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto done; + + retval = target_read_buffer(target, eneispif_info->ctrl_base + ISPIDAT, 3, buffer); + if (retval != ERROR_OK) + goto done; + value = (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]; + LOG_DEBUG("ISPDAT = (0x%08" PRIx32 ")", value); + + *id = value; +done: + eneispif_write_reg(bank, ISPICFG, conf); // restore + return retval; +} + +static int eneispif_probe(struct flash_bank *bank) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + struct flash_sector *sectors; + uint32_t id; + int retval; + uint32_t sectorsize; + + if (eneispif_info->probed) + free(bank->sectors); + + eneispif_info->probed = false; + + LOG_INFO("Assuming ISPI flash at address " TARGET_ADDR_FMT + " with controller at " TARGET_ADDR_FMT, + bank->base, eneispif_info->ctrl_base); + + eneispif_write_reg(bank, ISPICFG, CFG_READ); /* RAM map enable */ + + retval = eneispif_read_flash_id(bank, &id); + if (retval != ERROR_OK) + return retval; + + eneispif_info->dev_id = id; + eneispif_info->dev = &ene_flash_device; + + LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", eneispif_info->dev->name, + eneispif_info->dev_id); + + /* Set correct size value */ + bank->size = eneispif_info->dev->size_in_bytes; + + if (bank->size <= (1UL << 16)) + LOG_WARNING("device needs 2-byte addresses - not implemented"); + + /* if no sectors, treat whole bank as single sector */ + sectorsize = eneispif_info->dev->sectorsize ? eneispif_info->dev->sectorsize + : eneispif_info->dev->size_in_bytes; + + /* create and fill sectors array */ + bank->num_sectors = eneispif_info->dev->size_in_bytes / 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 * sectorsize; + sectors[sector].size = sectorsize; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + eneispif_info->probed = true; + return ERROR_OK; +} + +static int eneispif_auto_probe(struct flash_bank *bank) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + if (eneispif_info->probed) + return ERROR_OK; + return eneispif_probe(bank); +} + +static int eneispif_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +static int get_eneispif_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + if (!(eneispif_info->probed)) { + command_print(cmd, "ENE ISPI flash bank not probed yet."); + return ERROR_OK; + } + + command_print(cmd, + "ENE ISPI flash information:\n" + " Device \'%s\' (ID 0x%08" PRIx32 ")", + eneispif_info->dev->name, eneispif_info->dev_id); + + return ERROR_OK; +} + +const struct flash_driver eneispif_flash = { + .name = "eneispif", + .usage = "flash bank 'eneispif' 0 0 ", + .flash_bank_command = eneispif_flash_bank_command, + .erase = eneispif_erase, + .protect = eneispif_protect, + .write = eneispif_write, + .read = default_flash_read, + .probe = eneispif_probe, + .auto_probe = eneispif_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = eneispif_protect_check, + .info = get_eneispif_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 942883788..2f3d64454 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -157,7 +157,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) int retval; if (!swdio_input) { - if (!last_stored || (swdio != last_swdio)) { + if (!last_stored || swdio != last_swdio) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], swdio); if (retval < 0) LOG_WARNING("Fail set swdio"); @@ -165,7 +165,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) } /* write swclk last */ - if (!last_stored || (swclk != last_swclk)) { + if (!last_stored || swclk != last_swclk) { retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWCLK], swclk); if (retval < 0) LOG_WARNING("Fail set swclk"); @@ -320,12 +320,12 @@ static int helper_get_line(enum adapter_gpio_config_index idx) switch (adapter_gpio_config[idx].pull) { case ADAPTER_GPIO_PULL_NONE: -#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; #endif break; case ADAPTER_GPIO_PULL_UP: -#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP; #else LOG_WARNING("linuxgpiod: ignoring request for pull-up on %s: not supported by gpiod v%s", @@ -333,7 +333,7 @@ static int helper_get_line(enum adapter_gpio_config_index idx) #endif break; case ADAPTER_GPIO_PULL_DOWN: -#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN; #else LOG_WARNING("linuxgpiod: ignoring request for pull-down on %s: not supported by gpiod v%s", diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index c97b6b6ab..53d2151fd 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -230,13 +230,13 @@ static int remote_bitbang_sleep(unsigned int microseconds) unsigned int us = microseconds % 1000; for (unsigned int i = 0; i < ms; i++) { - tmp = remote_bitbang_queue('D', NO_FLUSH); + tmp = remote_bitbang_queue('Z', NO_FLUSH); if (tmp != ERROR_OK) return tmp; } for (unsigned int i = 0; i < us; i++) { - tmp = remote_bitbang_queue('d', NO_FLUSH); + tmp = remote_bitbang_queue('z', NO_FLUSH); if (tmp != ERROR_OK) return tmp; } diff --git a/src/target/mips32.c b/src/target/mips32.c index 6bbf71bd8..81faab72d 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -2109,7 +2109,7 @@ static int mips32_dsp_find_register_by_name(const char *reg_name) */ static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) { - uint32_t value; + uint32_t value = 0; for (int i = 0; i < MIPS32NUMDSPREGS; i++) { int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, i); if (retval != ERROR_OK) { @@ -2134,7 +2134,7 @@ static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_e */ static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) { - uint32_t value; + uint32_t value = 0; int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); if (index == MIPS32NUMDSPREGS) { command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index f5b4478ff..5a88b6e9d 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -47,7 +47,7 @@ ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" pld create zynq_pl.pld virtex2 -chain-position zynq_pl.bs -no_jstart -virtex2 set_user_codes $zynq_pl.pld 0x02 0x03 0x22 0x23 +virtex2 set_user_codes zynq_pl.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b