This is an automated email from Gerrit. Lars Poeschel (poeschell+open...@mailbox.org) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/5505
-- gerrit commit 3d17eaeff24865f7a0e764a35fe0daa845e6e556 Author: Lars Poeschel <poeschell+open...@mailbox.org> Date: Mon Nov 11 15:36:43 2019 +0100 avrf.c: Add a driver for the eeprom on avrs This adds a driver to use the eeprom on avrs with openocds flash interface. The eeprom can be read and written. BEWARE: Erasing only works in conjunction with the flash. So if you erase the flash, the eeprom is also erased an vice versa. This is a hardware limitation. Change-Id: I72f24f07c73c196bd415829fdcb26bc99cf27059 Signed-off-by: Lars Pöschel <poeschell+open...@mailbox.org> diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 3f8e322..b7f9153 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -246,6 +246,98 @@ static int avr_jtagprg_readflashpage(struct avr_common *avr, return ERROR_OK; } +static int avr_jtagprg_writeeeprompage(struct avr_common *avr, + const uint8_t *page_buf, + uint32_t buf_size, + uint32_t addr, + uint32_t page_size) +{ + uint32_t i, poll_value; + + avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2311, AVR_JTAG_REG_ProgrammingCommand_Len); + + /* load addr high byte */ + avr_jtag_senddat(avr->jtag_info.tap, + NULL, + 0x0700 | ((addr >> 8) & 0xFF), + AVR_JTAG_REG_ProgrammingCommand_Len); + + for (i = 0; i < page_size; i++) { + /* load addr low byte */ + avr_jtag_senddat(avr->jtag_info.tap, + NULL, + 0x0300 | (addr & 0xFF), + AVR_JTAG_REG_ProgrammingCommand_Len); + + if (i < buf_size) + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x1300 | page_buf[i], AVR_JTAG_REG_ProgrammingCommand_Len); + else + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x1300 | 0xFF, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x7700, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); + } + + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3100, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len); + + do { + poll_value = 0; + avr_jtag_senddat(avr->jtag_info.tap, + &poll_value, + 0x3300, + AVR_JTAG_REG_ProgrammingCommand_Len); + if (ERROR_OK != mcu_execute_queue()) + return ERROR_FAIL; + LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); + } while (!(poll_value & 0x0200)); + + return ERROR_OK; +} + +static int avr_jtagprg_readeeprompage(struct avr_common *avr, + uint32_t *page_buf, + uint32_t buf_size, + uint32_t addr, + uint32_t page_size) +{ + uint32_t i; + + avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2303, AVR_JTAG_REG_ProgrammingCommand_Len); + + for(i = 0; i < page_size; i++) { + /* load addr high byte */ + avr_jtag_senddat(avr->jtag_info.tap, + NULL, + 0x0700 | (((addr + i) >> 8) & 0xFF), + AVR_JTAG_REG_ProgrammingCommand_Len); + + /* load addr low byte */ + avr_jtag_senddat(avr->jtag_info.tap, + NULL, + 0x0300 | ((addr + i) & 0xFF), + AVR_JTAG_REG_ProgrammingCommand_Len); + + /* load addr low byte again for some reason */ + avr_jtag_senddat(avr->jtag_info.tap, + NULL, + 0x3300 | ((addr + i) & 0xFF), + AVR_JTAG_REG_ProgrammingCommand_Len); + + avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3200, AVR_JTAG_REG_ProgrammingCommand_Len); + avr_jtag_senddat(avr->jtag_info.tap, &page_buf[i], 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len); + } + + if (ERROR_OK != mcu_execute_queue()) + return ERROR_FAIL; + + return ERROR_OK; +} + FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command) { struct avrf_flash_bank *avrf_info; @@ -586,3 +678,230 @@ const struct flash_driver avr_flash = { .info = avrf_info, .free_driver_priv = default_flash_free_driver_priv, }; + +/* + * EEPROM + */ +struct avr_eeprom_flash_bank { + int ppage_size; + int probed; + const struct avrf_type *avr_info; +}; + +static int avr_eeprom_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct avr_common *avr = target->arch_info; + uint32_t cur_size, cur_buffer_size, page_size; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + page_size = bank->sectors[0].size; + if ((offset % page_size) != 0) { + LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", + offset, + page_size); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + LOG_DEBUG("offset is 0x%08" PRIx32 "", offset); + LOG_DEBUG("count is %" PRId32 "", count); + + if (ERROR_OK != avr_jtagprg_enterprogmode(avr)) + return ERROR_FAIL; + + cur_size = 0; + while (count > 0) { + if (count > page_size) + cur_buffer_size = page_size; + else + cur_buffer_size = count; + avr_jtagprg_writeeeprompage(avr, + buffer + cur_size, + cur_buffer_size, + offset + cur_size, + page_size); + count -= cur_buffer_size; + cur_size += cur_buffer_size; + + keep_alive(); + } + + return avr_jtagprg_leaveprogmode(avr); +} + +static int avr_eeprom_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct avr_common *avr = target->arch_info; + uint32_t cur_size, cur_buffer_size, page_size; + uint32_t *tmp_buf; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + page_size = bank->sectors[0].size; + if ((offset % page_size) != 0) { + LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", + offset, + page_size); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + LOG_DEBUG("offset is 0x%08" PRIx32 "", offset); + LOG_DEBUG("count is %" PRId32 "", count); + + if (ERROR_OK != avr_jtagprg_enterprogmode(avr)) + return ERROR_FAIL; + + tmp_buf = calloc(page_size, sizeof(uint32_t)); + if (tmp_buf == NULL) + return ERROR_FAIL; + + cur_size = 0; + while (count > 0) { + if (count > page_size) + cur_buffer_size = page_size; + else + cur_buffer_size = count; + + avr_jtagprg_readeeprompage(avr, + tmp_buf, + cur_buffer_size, + offset + cur_size, + page_size); + for(uint32_t i = 0; i < page_size; i++) + buffer[cur_size + i] = tmp_buf[i]; + + count -= cur_buffer_size; + cur_size += cur_buffer_size; + + keep_alive(); + } + + free(tmp_buf); + + return avr_jtagprg_leaveprogmode(avr); +} + +static int avr_eeprom_probe(struct flash_bank *bank) +{ + uint8_t ver; + int error = ERROR_OK; + struct avr_eeprom_flash_bank *avr_eeprom_bank = bank->driver_priv; + const struct avrf_type *avr_info = avrf_get_avr_info(bank, &error, &ver); + int i; + + if (avr_info != NULL) { + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + /* chip found */ + bank->base = 0x00000000; + bank->size = (avr_info->eeprom_page_size * avr_info->eeprom_page_num); + bank->num_sectors = avr_info->eeprom_page_num; + bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->eeprom_page_num); + + for (i = 0; i < avr_info->eeprom_page_num; i++) { + bank->sectors[i].offset = i * avr_info->eeprom_page_size; + bank->sectors[i].size = avr_info->eeprom_page_size; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = -1; + } + + avr_eeprom_bank->probed = 1; + avr_eeprom_bank->avr_info = avr_info; + return ERROR_OK; + } else { + if (error == ERROR_FLASH_OPERATION_FAILED) { + /* chip not supported */ + LOG_ERROR("device id is not supported for avr"); + avr_eeprom_bank->probed = 1; + return ERROR_FAIL; + } + } + + return error; +} + +static int avr_eeprom_auto_probe(struct flash_bank *bank) +{ + struct avr_eeprom_flash_bank *avr_eeprom_bank = bank->driver_priv; + + if (avr_eeprom_bank->probed) + return ERROR_OK; + + return avr_eeprom_probe(bank); +} + +static int avr_eeprom_info(struct flash_bank *bank, char *buf, int buf_size) +{ + uint8_t ver; + int error = ERROR_OK; + struct avr_eeprom_flash_bank *avr_eeprom_bank = bank->driver_priv; + const struct avrf_type *avr_info = avrf_get_avr_info(bank, &error, &ver); + + if (avr_info != NULL) { + /* chip found */ + snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, + ver); + avr_eeprom_bank->avr_info = avr_info; + } else + if (error == ERROR_FLASH_OPERATION_FAILED) + snprintf(buf, buf_size, "Cannot identify target as a avr\n"); + + return error; +} + +FLASH_BANK_COMMAND_HANDLER(avr_eeprom_flash_bank_command) +{ + struct avr_eeprom_flash_bank *avr_eeprom_bank; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + avr_eeprom_bank = malloc(sizeof(struct avr_eeprom_flash_bank)); + if (!avr_eeprom_bank) + return ERROR_FLASH_OPERATION_FAILED; + + avr_eeprom_bank->probed = 0; + bank->driver_priv = avr_eeprom_bank; + + return ERROR_OK; +} + +static const struct command_registration avr_eeprom_exec_command_handlers[] = { + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration avr_eeprom_command_handlers[] = { + { + .name = "avr_eeprom", + .mode = COMMAND_ANY, + .help = "AVR EEPROM command group", + .usage = "", + .chain = avr_eeprom_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +const struct flash_driver avr_eeprom = { + .name = "avr_eeprom", + .commands = avr_eeprom_command_handlers, + .flash_bank_command = avr_eeprom_flash_bank_command, + .info = avr_eeprom_info, + .probe = avr_eeprom_probe, + .auto_probe = avr_eeprom_auto_probe, + .read = avr_eeprom_read, + .erase = avrf_erase, + .erase_check = default_flash_blank_check, + .write = avr_eeprom_write, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index d52e072..e79e9bf 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -32,6 +32,7 @@ extern const struct flash_driver ath79_flash; extern const struct flash_driver atsame5_flash; extern const struct flash_driver atsamv_flash; extern const struct flash_driver avr_flash; +extern const struct flash_driver avr_eeprom; extern const struct flash_driver bluenrgx_flash; extern const struct flash_driver cc3220sf_flash; extern const struct flash_driver cc26xx_flash; @@ -104,6 +105,7 @@ static const struct flash_driver * const flash_drivers[] = { &atsame5_flash, &atsamv_flash, &avr_flash, + &avr_eeprom, &bluenrgx_flash, &cc3220sf_flash, &cc26xx_flash, -- _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel