// SPDX-License-Identifier: GPL-2.0-or-later /*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on a file written by: * * Kevin McGuire * * Marcel Wijlaars * * Michael Ashton * ***************************************************************************/ /** * @file dsp5680xx_flash.c * @author Rodrigo L. Rosa * @date Thu Jun 9 18:21:58 2011 * * @brief This file implements the basic functions to run flashing commands * from the TCL interface. * It allows the user to flash the Freescale 5680xx DSP. * * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #include static int dsp5680xx_build_sector_list(struct flash_bank *bank) { bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = i * HFM_SECTOR_SIZE; bank->sectors[i].size = HFM_SECTOR_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } LOG_USER("%s not tested yet.", __func__); return ERROR_OK; } /* flash bank dsp5680xx 0 0 0 0 */ FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command) { bank->base = HFM_FLASH_BASE_ADDR; bank->size = HFM_SIZE_BYTES; /* top 4k not accessible */ bank->num_sectors = HFM_SECTOR_COUNT; dsp5680xx_build_sector_list(bank); return ERROR_OK; } /** * A memory mapped register (PROT) holds information regarding sector protection. * Protection refers to undesired core access. * The value in this register is loaded from flash upon reset. * * @param bank * * @return */ static int dsp5680xx_flash_protect_check(struct flash_bank *bank) { int retval = ERROR_OK; uint16_t protected = 0; retval = dsp5680xx_f_protect_check(bank->target, &protected); if (retval != ERROR_OK) { for (int i = 0; i < HFM_SECTOR_COUNT; i++) bank->sectors[i].is_protected = -1; return ERROR_OK; } for (int i = 0; i < HFM_SECTOR_COUNT / 2; i++) { if (protected & 1) { bank->sectors[2 * i].is_protected = 1; bank->sectors[2 * i + 1].is_protected = 1; } else { bank->sectors[2 * i].is_protected = 0; bank->sectors[2 * i + 1].is_protected = 0; } protected = (protected >> 1); } return retval; } /** * Protection functionality is not implemented. * The current implementation applies/removes security on the chip. * The chip is effectively secured/unsecured after the first reset * following the execution of this function. * * @param bank * @param set Apply or remove security on the chip. * @param first This parameter is ignored. * @param last This parameter is ignored. * * @return */ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { /** * This applies security to flash module after next reset, it does * not actually apply protection (protection refers to undesired access from the core) */ int retval; if (set) retval = dsp5680xx_f_lock(bank->target); else retval = dsp5680xx_f_unlock(bank->target); return retval; } /** * The dsp5680xx use word addressing. The "/2" that appear in the following code * are a workaround for the fact that OpenOCD uses byte addressing. * * @param bank * @param buffer Data to write to flash. * @param offset * @param count In bytes (2 bytes per address). * * @return */ static int dsp5680xx_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { if ((offset + count / 2) > bank->size) { LOG_ERROR("%s: Flash bank cannot fit data.", __func__); return ERROR_FAIL; } if (offset % 2) { /** * Writing to odd addresses not supported. * This chip uses word addressing, Openocd only supports byte addressing. * The workaround results in disabling writing to odd byte addresses */ LOG_ERROR("%s: Writing to odd addresses not supported for this target", __func__); return ERROR_FAIL; } return dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0); } static int dsp5680xx_probe(struct flash_bank *bank) { LOG_DEBUG("%s not implemented", __func__); return ERROR_OK; } /** * The flash module (FM) on the dsp5680xx supports both individual sector * and mass erase of the flash memory. * If this function is called with @a first == @a last == 0 or if @a first is the * first sector (#0) and @a last is the last sector then the mass erase command * is executed (much faster than erasing each sector individually). * * @param bank * @param first * @param last * * @return */ static int dsp5680xx_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { return dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last); } /** * The flash module (FM) on the dsp5680xx support a blank check function. * This function executes the FM's blank check functionality on each and every sector. * * @param bank * * @return */ static int dsp5680xx_flash_erase_check(struct flash_bank *bank) { int retval = ERROR_OK; uint8_t erased = 0; uint32_t i; for (i = 0; i < HFM_SECTOR_COUNT; i++) { retval = dsp5680xx_f_erase_check(bank->target, &erased, i); if (retval != ERROR_OK) { bank->sectors[i].is_erased = -1; } else { if (erased) bank->sectors[i].is_erased = 1; else bank->sectors[i].is_erased = 0; } } return retval; } const struct flash_driver dsp5680xx_flash = { .name = "dsp5680xx_flash", .flash_bank_command = dsp5680xx_flash_bank_command, .erase = dsp5680xx_flash_erase, .protect = dsp5680xx_flash_protect, .write = dsp5680xx_flash_write, /* .read = default_flash_read, */ .probe = dsp5680xx_probe, .auto_probe = dsp5680xx_probe, .erase_check = dsp5680xx_flash_erase_check, .protect_check = dsp5680xx_flash_protect_check, };