This is an automated email from Gerrit. Konstantin Kraskovsky (kraskovs...@otsl.jp) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/4650
-- gerrit commit 9747703c80fc4c0104d85281ea6c4f52a10dc548 Author: Konstantin Kraskovskiy <kraskovs...@otsl.jp> Date: Tue Aug 14 18:35:49 2018 +0900 flash/nor: add support for Renesas EC-1 device Adds support for Renesas EC-1 (r9a06g043) microcontroller Change-Id: Id715350283e52c2048208be8ee57c749c734fe13 Signed-off-by: Konstantin Kraskovskiy <kraskovs...@otsl.jp> diff --git a/contrib/loaders/flash/ec-1/ec1_loader.c b/contrib/loaders/flash/ec-1/ec1_loader.c new file mode 100644 index 0000000..520c9d6 --- /dev/null +++ b/contrib/loaders/flash/ec-1/ec1_loader.c @@ -0,0 +1,162 @@ +/*************************************************************************** + * + * Copyright (C) 2018 by Konstantin Kraskovskiy <kraskov...@otsl.jp> * + * * + * 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/>. * + ***************************************************************************/ + +/* + To compile: arm-none-eabi-gcc -march=armv7-r -marm -c ./ec1_loader.c + To strip: arm-none-eabi-objcopy -O binary ec1_loader.o ec1.bin + To hex: xxd -c4 -i ./ec1.h + */ + +#define BASE 0xA0005000 +#define SMCR (BASE + 0x20) +#define SMCMR (BASE + 0x24) +#define SMADR (BASE + 0x28) +#define SMENR (BASE + 0x30) +#define SMRDR0 (BASE + 0x38) +#define SMWDR0 (BASE + 0x40) +#define CMNSR (BASE + 0x48) + +#define CDE (1 << 14) +#define SPIE (1) +#define SPIWE (2) +#define SPIRE (4) +#define SSLKP (1 << 8) +#define TEND (1) +#define ADE_24 (7 << 8) +#define BUSY (1) +#define SPIDE_BYTE (8) +#define SPIDE_HALF (12) +#define SPIDE_WORD (15) + +#define SPIFLASH_PAGE_PROGRAM (2 << 16) +#define SPIFLASH_READ_STATUS (5 << 16) +#define SPIFLASH_WRITE_ENABLE (6 << 16) + +#define PAGE_MASK (0xFF) + + +__attribute__((noreturn, naked, pcs("aapcs"), aligned(4))) +unsigned ec1_write( + unsigned r0_count, + unsigned r1_dummy, + unsigned r2_offset, + unsigned r3_p_buffer) +{ + register unsigned v_smenr = CDE | ADE_24; + + /* write enable */ + *(unsigned *)SMENR = CDE; + *(unsigned *)SMCMR = SPIFLASH_WRITE_ENABLE; + *(unsigned *)SMCR = SPIE; + while (!(*((volatile unsigned *)CMNSR) & TEND)); + + /* writing */ + *(unsigned *)SMCMR = SPIFLASH_PAGE_PROGRAM; + *(unsigned *)SMADR = r2_offset; + + while (r0_count) { + switch (PAGE_MASK - (r2_offset & PAGE_MASK)) { + case 0: + *(unsigned *)SMENR = v_smenr | SPIDE_BYTE; + *(unsigned char *)SMWDR0 = *(unsigned char *)r3_p_buffer; + *(unsigned *)SMCR = SPIWE | SPIE; + r0_count--; + r3_p_buffer++; + r2_offset++; + break; + case 1: + case 2: + switch (r0_count) { + case 1: + *(unsigned *)SMENR = v_smenr | SPIDE_BYTE; + *(unsigned char *)SMWDR0 = *(unsigned char *)r3_p_buffer; + *(unsigned *)SMCR = SPIWE | SPIE; + r0_count--; + r3_p_buffer++; + r2_offset++; + break; + default: + *(unsigned *)SMENR = v_smenr | SPIDE_HALF; + *(unsigned short *)SMWDR0 = *(unsigned short *)r3_p_buffer; + if (r0_count == 2) + *(unsigned *)SMCR = SPIWE | SPIE; + else + *(unsigned *)SMCR = SSLKP | SPIWE | SPIE; + r0_count -= 2; + r3_p_buffer += 2; + r2_offset +=2; + } + break; + default: + switch (r0_count) { + case 1: + *(unsigned *)SMENR = v_smenr | SPIDE_BYTE; + *(unsigned char *)SMWDR0 = *(unsigned char *)r3_p_buffer; + *(unsigned *)SMCR = SPIWE | SPIE; + r0_count--; + r3_p_buffer++; + r2_offset++; + break; + case 2: + case 3: + *(unsigned *)SMENR = v_smenr | SPIDE_HALF; + *(unsigned short *)SMWDR0 = *(unsigned short *)r3_p_buffer; + if (r0_count == 2) + *(unsigned *)SMCR = SPIWE | SPIE; + else + *(unsigned *)SMCR = SSLKP | SPIWE | SPIE; + r0_count -= 2; + r3_p_buffer += 2; + r2_offset +=2; + break; + default: + *(unsigned *)SMENR = v_smenr | SPIDE_WORD; + *(unsigned *)SMWDR0 = *(unsigned *)r3_p_buffer; + if (r0_count == 4) + *(unsigned *)SMCR = SPIWE | SPIE; + else + *(unsigned *)SMCR = SSLKP | SPIWE | SPIE; + r0_count -= 4; + r3_p_buffer += 4; + r2_offset +=4; + } + } + + while (!(*((volatile unsigned *)CMNSR) & TEND)); + v_smenr = 0; + if (!(r2_offset & PAGE_MASK)) + break; + } + + /* wait for page commit */ + *(unsigned *)SMENR = CDE | SPIDE_BYTE; + *(unsigned *)SMCMR = SPIFLASH_READ_STATUS; + *(unsigned *)SMCR = SSLKP | SPIRE | SPIE; + while (!(*((volatile unsigned *)CMNSR) & TEND)); + + *(unsigned *)SMENR = SPIDE_BYTE; + while (*((volatile unsigned char *)SMRDR0) & BUSY) { + *(volatile unsigned *)SMCR = SSLKP | SPIRE | SPIE; + while (!(*((volatile unsigned *)CMNSR) & TEND)); + } + + *(volatile unsigned *)SMCR = SPIRE | SPIE; + while (!(*((volatile unsigned *)CMNSR) & TEND)); + + __asm__ __volatile__ ("bkpt"); /* return */ +} diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 13e589c..5addbba 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -23,6 +23,7 @@ NOR_DRIVERS = \ %D%/cc26xx.c \ %D%/cfi.c \ %D%/dsp5680xx_flash.c \ + %D%/ec1.c \ %D%/efm32.c \ %D%/em357.c \ %D%/faux.c \ diff --git a/src/flash/nor/ec1.c b/src/flash/nor/ec1.c new file mode 100644 index 0000000..5cdc65c --- /dev/null +++ b/src/flash/nor/ec1.c @@ -0,0 +1,1036 @@ +/*************************************************************************** + * + * Copyright (C) 2018 by Konstantin Kraskovskiy <kraskov...@otsl.jp> * + * * + * 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/>. * + ***************************************************************************/ + +/* + * This is serial flash controller (aka SPIBSC) driver for Renesas EC-1. + * + * Its design is derived from mrvlqspi driver + * Copyright (C) 2014 by Mahavir Jain <mj...@marvell.com> + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "spi.h" +#include <helper/binarybuffer.h> +#include <target/algorithm.h> +#include <target/arm.h> + +#define BLOCK_ERASE_TIMEOUT (50) +#define CHIP_ERASE_TIMEOUT (5000) + +#define RCF (1 << 9) + +#define MODE_SPI (1) +#define MODE_MAP (0) +#define TEND (1) +#define SPIE (1) +#define SPIRE (4) +#define SPIWE (2) +#define SPIDE (0xF) +#define ADE_24 (0x7 << 8) +#define OCDE (1 << 12) +#define CDE (1 << 14) +#define SSLN (1 << 24) + +#define CMNCR 0x0 /* SPIBSC_BASE + 0x0 */ +#define SSLDR 0x4 +#define SPBCR 0x8 +#define DRCR 0xC + +#define SMCR 0x20 +#define SMCMR 0x24 +#define SMADR 0x28 +#define SMENR 0x30 +#define SMRDR0 0x38 +#define SMWDR0 0x40 +#define CMNSR 0x48 + +struct platform_flash_bank { + int probed; + uint32_t reg_base; + uint32_t bank_num; + const struct flash_device *dev; +}; + +static inline uint32_t spibsc_get_reg(struct flash_bank *bank, uint32_t reg) +{ + struct platform_flash_bank *platform_info = bank->driver_priv; + return reg + platform_info->reg_base; +} + +static inline int spibsc_set_addr(struct flash_bank *bank, uint32_t addr) +{ + int retval; + uint32_t regval; + struct target *target = bank->target; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMADR), addr); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, + spibsc_get_reg(bank, SMENR), ®val); + if (retval != ERROR_OK) + return retval; + + regval |= ADE_24; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMENR), regval); + + return retval; +} + +static inline int spibsc_set_cmd(struct flash_bank *bank, uint32_t cmd) +{ + int retval; + uint32_t regval; + struct target *target = bank->target; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMCMR), (cmd << 16)); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, + spibsc_get_reg(bank, SMENR), ®val); + if (retval != ERROR_OK) + return retval; + + regval |= CDE; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMENR), regval); + + return retval; +} + +static inline int spibsc_mode_init(struct flash_bank *bank, bool mode) +{ + int retval; + uint32_t regval; + struct target *target = bank->target; + + retval = target_read_u32(target, + spibsc_get_reg(bank, CMNSR), ®val); + if (retval != ERROR_OK) + return retval; + + if (!(regval & TEND)) + return ERROR_FLASH_BUSY; + + + if (mode == MODE_SPI) { + regval = 0; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMCR), regval); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMENR), regval); + if (retval != ERROR_OK) + return retval; + + } + + return ERROR_OK; +} + +static int spibsc_start_transfer(struct flash_bank *bank) +{ + int retval; + uint32_t regval; + struct target *target = bank->target; + + retval = target_read_u32(target, + spibsc_get_reg(bank, CMNSR), ®val); + if (retval != ERROR_OK) + return retval; + + if (!(regval & TEND)) + return ERROR_FLASH_BUSY; + + retval = target_read_u32(target, + spibsc_get_reg(bank, SMCR), ®val); + if (retval != ERROR_OK) + return retval; + + regval |= SPIE; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMCR), regval); + if (retval != ERROR_OK) + return retval; + + do { + keep_alive(); + retval = target_read_u32(target, + spibsc_get_reg(bank, CMNSR), ®val); + if (retval != ERROR_OK) + return retval; + } while(!(regval & TEND)); + + return ERROR_OK; +} + +static int spibsc_cache_flush(struct flash_bank *bank) +{ + int retval; + uint32_t val; + struct target *target = bank->target; + + retval = target_read_u32(target, + spibsc_get_reg(bank, DRCR), &val); + if (retval != ERROR_OK) + return retval; + + val |= RCF; + + retval = target_write_u32(target, + spibsc_get_reg(bank, DRCR), val); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, + spibsc_get_reg(bank, DRCR), &val); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int spibsc_set_mode(struct flash_bank *bank, bool mode) +{ + int retval; + uint32_t regval; + struct target *target = bank->target; + + retval = target_read_u32(target, + spibsc_get_reg(bank, CMNCR), ®val); + if (retval != ERROR_OK) + return retval; + + if (!(regval & (1<<31))) { + + retval = target_read_u32(target, + spibsc_get_reg(bank, DRCR), ®val); + if (retval != ERROR_OK) + return retval; + + regval |= SSLN; + + retval = target_write_u32(target, + spibsc_get_reg(bank, DRCR), regval); + if (retval != ERROR_OK) + return retval; + + } + + do { + keep_alive(); + retval = target_read_u32(target, + spibsc_get_reg(bank, CMNSR), ®val); + if (retval != ERROR_OK) + return retval; + } while(regval != 1); + + /* Flush SPIBSC cache */ + retval = spibsc_cache_flush(bank); + if (retval != ERROR_OK) + return retval; + + /* set timing */ + retval = target_write_u32(target, + spibsc_get_reg(bank, SSLDR), 0x030303); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SPBCR), 0x3); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, + spibsc_get_reg(bank, CMNCR), ®val); + if (retval != ERROR_OK) + return retval; + + regval |= mode << 31; + + retval = target_write_u32(target, + spibsc_get_reg(bank, CMNCR), regval); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int spibsc_cmd_read(struct flash_bank *bank, void *data, uint32_t len) +{ + int retval; + uint32_t regval; + struct target *target = bank->target; + + if (len) { + retval = target_read_u32(target, + spibsc_get_reg(bank, SMCR), ®val); + if (retval != ERROR_OK) + return retval; + + regval |= SPIRE; + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMCR), regval); + if (retval != ERROR_OK) + return retval; + } + + retval = target_read_u32(target, + spibsc_get_reg(bank, SMENR), ®val); + if (retval != ERROR_OK) + return retval; + + regval |= (SPIDE & len); + + retval = target_write_u32(target, + spibsc_get_reg(bank, SMENR), regval); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_start_transfer(bank); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, + spibsc_get_reg(bank, SMRDR0), data); + + return retval; +} + + +static int platform_flash_status(struct flash_bank *bank, void *status, int polling_interval_ms) +{ + int retval = ERROR_OK; + + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_set_cmd(bank, SPIFLASH_READ_STATUS); + if (retval != ERROR_OK) + return retval; + + if (polling_interval_ms) { + + do { + + alive_sleep(polling_interval_ms); + + retval = spibsc_cmd_read(bank, status, 0x8); + if (retval != ERROR_OK) + return retval; + + } while ((*(uint32_t *)status) & SPIFLASH_BSY_BIT); + + } else { + + retval = spibsc_cmd_read(bank, status, 0x8); + if (retval != ERROR_OK) + return retval; + + } + + return retval; +} + +static int platform_write_enable(struct flash_bank *bank) +{ + int retval; + unsigned data; + + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_set_cmd(bank, SPIFLASH_WRITE_ENABLE); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_start_transfer(bank); + if (retval != ERROR_OK) + return retval; + + retval = platform_flash_status(bank, &data, 0); + if (retval != ERROR_OK) + return retval; + + if ((data & 0xFF) != 2) + return ERROR_FLASH_BUSY; + + return retval; +} + +static int platform_read_id(struct flash_bank *bank, uint32_t *id) +{ + uint8_t id_buf[4] = {0, 0, 0, 0}; + int retval; + + LOG_DEBUG("Getting ID"); + + retval = spibsc_set_mode(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Initialize SPIBSC */ + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Set SPI instruction */ + retval = spibsc_set_cmd(bank, SPIFLASH_READ_ID); + if (retval != ERROR_OK) + return retval; + + /* Read 32 bits from SPIBSC */ + retval = spibsc_cmd_read(bank, id_buf, 0xF); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("ID is 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8, + id_buf[0], id_buf[1], id_buf[2]); + + *id = id_buf[2] << 16 | id_buf[1] << 8 | id_buf[0]; + + /* Read status for fun */ + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_set_cmd(bank, SPIFLASH_READ_STATUS); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_cmd_read(bank, &id_buf[0], 0x8); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_set_cmd(bank, 0x35); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_cmd_read(bank, &id_buf[1], 0x8); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_set_cmd(bank, 0x15); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_cmd_read(bank, &id_buf[2], 0x8); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("Status regs are: 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8, + id_buf[0], id_buf[1], id_buf[2]); + + return ERROR_OK; +} + +static int platform_block_erase(struct flash_bank *bank, uint32_t offset) +{ + int retval; + unsigned data; + struct platform_flash_bank *platform_info = bank->driver_priv; + + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Set read offset address */ + retval = spibsc_set_addr(bank, offset); + if (retval != ERROR_OK) + return retval; + + /* Set instruction */ + retval = spibsc_set_cmd(bank, platform_info->dev->erase_cmd); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_start_transfer(bank); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("0x%08" PRIx32 "KiB block erasing. Wait...", + (unsigned)platform_info->dev->sectorsize); + + retval = platform_flash_status(bank, &data, BLOCK_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + if (data & (SPIFLASH_BSY_BIT | SPIFLASH_WE_BIT)) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +static int platform_bulk_erase(struct flash_bank *bank) +{ + int retval; + unsigned data; + struct platform_flash_bank *platform_info = bank->driver_priv; + + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Set instruction */ + retval = spibsc_set_cmd(bank, platform_info->dev->chip_erase_cmd); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_start_transfer(bank); + if (retval != ERROR_OK) + return retval; + + LOG_INFO("Chip erasing. Wait..."); + + retval = platform_flash_status(bank, &data, CHIP_ERASE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + if (data & (SPIFLASH_BSY_BIT | SPIFLASH_WE_BIT)) + return ERROR_FLASH_OPERATION_FAILED; + + return ERROR_OK; +} + +static int platform_flash_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + struct platform_flash_bank *platform_info = bank->driver_priv; + int retval = ERROR_OK; + int sector; + + LOG_DEBUG("erase from sector %d to sector %d", first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + if (!(platform_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + for (sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + retval = spibsc_set_mode(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Initialize SPIBSC */ + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + retval = platform_write_enable(bank); + if (retval != ERROR_OK) + return retval; + + /* If we're erasing the entire chip and the flash supports + * it, use a bulk erase instead of going sector-by-sector. */ + if (first == 0 && last == (bank->num_sectors - 1) + && platform_info->dev->chip_erase_cmd != + platform_info->dev->erase_cmd) { + LOG_DEBUG("Chip supports the bulk erase command."\ + " Will use bulk erase instead of sector-by-sector erase."); + retval = platform_bulk_erase(bank); + if (retval == ERROR_OK) { + return retval; + } else + LOG_WARNING("Bulk flash erase failed." + " Falling back to sector-by-sector erase."); + } + + for (sector = first; sector <= last; sector++) { + retval = platform_block_erase(bank, + sector * platform_info->dev->sectorsize); + if (retval != ERROR_OK) + return retval; + } + + return retval; +} + +static int platform_flash_write(struct flash_bank *bank, + const uint8_t *buffer, + uint32_t offset, + uint32_t count) +{ + struct target *target = bank->target; + struct platform_flash_bank *platform_info = bank->driver_priv; + int retval = ERROR_OK; + uint32_t i; + + LOG_INFO("Begin at offset=0x%08" PRIx32 " count=0x%08" PRIx32, + offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(platform_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (offset + count > platform_info->dev->size_in_bytes) { + LOG_WARNING("Writes past end of flash. Extra data discarded."); + count = platform_info->dev->size_in_bytes - offset; + } + + retval = spibsc_set_mode(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Initialize SPIBSC */ + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Check sector protection */ + for (i = 0; i < (unsigned)bank->num_sectors; i++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < + (bank->sectors[i].offset + bank->sectors[i].size)) + && ((offset + count - 1) >= bank->sectors[i].offset) + && bank->sectors[i].is_protected) { + LOG_ERROR("Flash sector %d protected", i); + return ERROR_FAIL; + } + } + + struct working_area *p_page, *p_code; + struct reg_param reg_params[4]; + struct arm_algorithm arm_info; + + /* see contrib/loaders/flash/ec-1/ec1_loader.c for src */ + static const uint8_t code[] = { + 0x05, 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x01, 0xc9, 0xa0, + 0xe3, 0x30, 0xc0, 0x81, 0xe5, 0x06, 0xc8, 0xa0, 0xe3, 0x24, 0xc0, + 0x81, 0xe5, 0x01, 0xc0, 0xa0, 0xe3, 0x20, 0xc0, 0x81, 0xe5, 0x05, + 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x48, 0x10, 0x91, 0xe5, + 0x01, 0x00, 0x11, 0xe3, 0xfa, 0xff, 0xff, 0x0a, 0x05, 0x1a, 0xa0, + 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x02, 0xc8, 0xa0, 0xe3, 0x24, 0xc0, + 0x81, 0xe5, 0x28, 0x20, 0x81, 0xe5, 0x47, 0xcc, 0xa0, 0xe3, 0x74, + 0x00, 0x00, 0xea, 0x02, 0x10, 0xe0, 0xe1, 0xff, 0x10, 0x11, 0xe2, + 0x02, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x51, 0xe3, 0x2d, 0x00, 0x00, + 0x8a, 0x0a, 0x00, 0x00, 0xea, 0x08, 0xc0, 0x8c, 0xe3, 0x05, 0x1a, + 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x30, 0xc0, 0x81, 0xe5, 0x01, + 0xc0, 0xd3, 0xe4, 0x40, 0xc0, 0xc1, 0xe5, 0x03, 0xc0, 0xa0, 0xe3, + 0x20, 0xc0, 0x81, 0xe5, 0x01, 0x00, 0x40, 0xe2, 0x01, 0x20, 0x82, + 0xe2, 0x5b, 0x00, 0x00, 0xea, 0x01, 0x00, 0x50, 0xe3, 0x0a, 0x00, + 0x00, 0x1a, 0x08, 0xc0, 0x8c, 0xe3, 0x05, 0x1a, 0xa0, 0xe3, 0x00, + 0x10, 0x4a, 0xe3, 0x30, 0xc0, 0x81, 0xe5, 0x01, 0xc0, 0xd3, 0xe4, + 0x40, 0xc0, 0xc1, 0xe5, 0x03, 0xc0, 0xa0, 0xe3, 0x20, 0xc0, 0x81, + 0xe5, 0x01, 0x00, 0x40, 0xe2, 0x01, 0x20, 0x82, 0xe2, 0x4e, 0x00, + 0x00, 0xea, 0x0c, 0xc0, 0x8c, 0xe3, 0x05, 0x1a, 0xa0, 0xe3, 0x00, + 0x10, 0x4a, 0xe3, 0x30, 0xc0, 0x81, 0xe5, 0xb0, 0xc0, 0xd3, 0xe1, + 0xb0, 0xc4, 0xc1, 0xe1, 0x02, 0x00, 0x50, 0xe3, 0x04, 0x00, 0x00, + 0x1a, 0x05, 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x03, 0xc0, + 0xa0, 0xe3, 0x20, 0xc0, 0x81, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x05, + 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x03, 0xc1, 0x00, 0xe3, + 0x20, 0xc0, 0x81, 0xe5, 0x02, 0x00, 0x40, 0xe2, 0x02, 0x30, 0x83, + 0xe2, 0x02, 0x20, 0x82, 0xe2, 0x39, 0x00, 0x00, 0xea, 0x01, 0x00, + 0x50, 0xe3, 0x03, 0x00, 0x00, 0x0a, 0x22, 0x00, 0x00, 0x3a, 0x03, + 0x00, 0x50, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x1f, 0x00, 0x00, 0xea, + 0x08, 0xc0, 0x8c, 0xe3, 0x05, 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, + 0xe3, 0x30, 0xc0, 0x81, 0xe5, 0x01, 0xc0, 0xd3, 0xe4, 0x40, 0xc0, + 0xc1, 0xe5, 0x03, 0xc0, 0xa0, 0xe3, 0x20, 0xc0, 0x81, 0xe5, 0x01, + 0x00, 0x40, 0xe2, 0x01, 0x20, 0x82, 0xe2, 0x28, 0x00, 0x00, 0xea, + 0x0c, 0xc0, 0x8c, 0xe3, 0x05, 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, + 0xe3, 0x30, 0xc0, 0x81, 0xe5, 0xb0, 0xc0, 0xd3, 0xe1, 0xb0, 0xc4, + 0xc1, 0xe1, 0x02, 0x00, 0x50, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x05, + 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x03, 0xc0, 0xa0, 0xe3, + 0x20, 0xc0, 0x81, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x05, 0x1a, 0xa0, + 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x03, 0xc1, 0x00, 0xe3, 0x20, 0xc0, + 0x81, 0xe5, 0x02, 0x00, 0x40, 0xe2, 0x02, 0x30, 0x83, 0xe2, 0x02, + 0x20, 0x82, 0xe2, 0x13, 0x00, 0x00, 0xea, 0x0f, 0xc0, 0x8c, 0xe3, + 0x05, 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x30, 0xc0, 0x81, + 0xe5, 0x00, 0xc0, 0x93, 0xe5, 0x40, 0xc0, 0x81, 0xe5, 0x04, 0x00, + 0x50, 0xe3, 0x04, 0x00, 0x00, 0x1a, 0x05, 0x1a, 0xa0, 0xe3, 0x00, + 0x10, 0x4a, 0xe3, 0x03, 0xc0, 0xa0, 0xe3, 0x20, 0xc0, 0x81, 0xe5, + 0x03, 0x00, 0x00, 0xea, 0x05, 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, + 0xe3, 0x03, 0xc1, 0x00, 0xe3, 0x20, 0xc0, 0x81, 0xe5, 0x04, 0x00, + 0x40, 0xe2, 0x04, 0x30, 0x83, 0xe2, 0x04, 0x20, 0x82, 0xe2, 0x05, + 0x1a, 0xa0, 0xe3, 0x00, 0x10, 0x4a, 0xe3, 0x48, 0x10, 0x91, 0xe5, + 0x01, 0x00, 0x11, 0xe3, 0xfa, 0xff, 0xff, 0x0a, 0x00, 0xc0, 0xa0, + 0xe3, 0xff, 0x00, 0x12, 0xe3, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x50, 0xe3, 0x88, 0xff, 0xff, 0x1a, 0x05, 0x3a, 0xa0, 0xe3, 0x00, + 0x30, 0x4a, 0xe3, 0x08, 0x20, 0x04, 0xe3, 0x30, 0x20, 0x83, 0xe5, + 0x05, 0x28, 0xa0, 0xe3, 0x24, 0x20, 0x83, 0xe5, 0x05, 0x21, 0x00, + 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x05, 0x3a, 0xa0, 0xe3, 0x00, 0x30, + 0x4a, 0xe3, 0x48, 0x30, 0x93, 0xe5, 0x01, 0x00, 0x13, 0xe3, 0xfa, + 0xff, 0xff, 0x0a, 0x05, 0x3a, 0xa0, 0xe3, 0x00, 0x30, 0x4a, 0xe3, + 0x08, 0x20, 0xa0, 0xe3, 0x30, 0x20, 0x83, 0xe5, 0x08, 0x00, 0x00, + 0xea, 0x05, 0x3a, 0xa0, 0xe3, 0x00, 0x30, 0x4a, 0xe3, 0x05, 0x21, + 0x00, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x05, 0x3a, 0xa0, 0xe3, 0x00, + 0x30, 0x4a, 0xe3, 0x48, 0x30, 0x93, 0xe5, 0x01, 0x00, 0x13, 0xe3, + 0xfa, 0xff, 0xff, 0x0a, 0x05, 0x3a, 0xa0, 0xe3, 0x00, 0x30, 0x4a, + 0xe3, 0x38, 0x30, 0xd3, 0xe5, 0x01, 0x00, 0x13, 0xe3, 0xf1, 0xff, + 0xff, 0x1a, 0x05, 0x3a, 0xa0, 0xe3, 0x00, 0x30, 0x4a, 0xe3, 0x05, + 0x20, 0xa0, 0xe3, 0x20, 0x20, 0x83, 0xe5, 0x05, 0x3a, 0xa0, 0xe3, + 0x00, 0x30, 0x4a, 0xe3, 0x48, 0x30, 0x93, 0xe5, 0x01, 0x00, 0x13, + 0xe3, 0xfa, 0xff, 0xff, 0x0a, 0x70, 0x00, 0x20, 0xe1 +}; + + /* Check the target's RAM availability */ + i = target_get_working_area_avail(target); + + if (i < (sizeof(code) + platform_info->dev->pagesize + 8)) { + LOG_ERROR("Insufficient memory. Please allocate at least"\ + " %zdB of working area.", + (sizeof(code) + platform_info->dev->pagesize)); + + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + i = sizeof(code) + 8 - (sizeof(code) & 3); + + /* Allocate target's RAM for the code */ + if (target_alloc_working_area(target, i, + &p_code) != ERROR_OK) { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Populate the code at the target */ + retval = target_write_buffer(target, p_code->address, + sizeof(code), code); + if (retval != ERROR_OK) { + target_free_working_area(target, p_code); + return retval; + } + + /* allocate the page buffer */ + if (target_alloc_working_area(target, platform_info->dev->pagesize, + &p_page) != ERROR_OK) { + target_free_working_area(target, p_code); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + arm_info.common_magic = ARM_COMMON_MAGIC; + arm_info.core_mode = ARM_MODE_SVC; + arm_info.core_state = ARM_STATE_ARM; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count and result */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* dummy */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* offset */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer start */ + + buf_set_u32(reg_params[3].value, 0, 32, p_page->address); + + while (count) { + + unsigned rest = platform_info->dev->pagesize - (offset & (platform_info->dev->pagesize - 1)); + + LOG_INFO("...at offset=0x%08" PRIx32 " 0x%08" PRIx32 " bytes to write", offset, count); + + if (count <= rest) + rest = count; + + buf_set_u32(reg_params[0].value, 0, 32, rest); + buf_set_u32(reg_params[2].value, 0, 32, offset); + + /* Populate the data at the target */ + retval = target_write_buffer(target, p_page->address, + rest, buffer); + if (retval != ERROR_OK) + break; + + count -= rest; + offset += rest; + buffer += rest; + + /* program page */ + retval = target_run_algorithm(target, + 0, NULL, + 4, reg_params, + p_code->address, 0, + 10000, &arm_info); + if (retval != ERROR_OK) + break; + + } + + if (retval != ERROR_OK) + LOG_ERROR("Error executing flash write algorithm"); + + target_free_working_area(target, p_page); + target_free_working_area(target, p_code); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + + return retval; +} + +int platform_flash_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct platform_flash_bank *platform_info = bank->driver_priv; + int retval; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(platform_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (!count) + return ERROR_FAIL; + + retval = spibsc_set_mode(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Initialize SPIBSC */ + retval = spibsc_mode_init(bank, MODE_SPI); + if (retval != ERROR_OK) + return retval; + + /* Set SPI instruction */ + retval = spibsc_set_cmd(bank, SPIFLASH_READ); + if (retval != ERROR_OK) + return retval; + + /* Set read offset address */ + retval = spibsc_set_addr(bank, offset++); + if (retval != ERROR_OK) + return retval; + + /* Read an octet from SPIBSC */ + retval = spibsc_cmd_read(bank, buffer++, 0x8); + if (retval != ERROR_OK) + return retval; + count--; + + /* can be faster, but do you really need this? */ + while (count--) { + retval = spibsc_set_addr(bank, offset++); + if (retval != ERROR_OK) + return retval; + + retval = spibsc_start_transfer(bank); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u8(target, + spibsc_get_reg(bank, SMRDR0), buffer++); + if (retval != ERROR_OK) + return retval; + + } + + return ERROR_OK; +} + +static int platform_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct platform_flash_bank *platform_info = bank->driver_priv; + uint32_t id = 0; + int retval; + struct flash_sector *sectors; + + /* If we've already probed, we should be fine to skip this time. */ + if (platform_info->probed) + return ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Probe: target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + platform_info->probed = 0; + platform_info->bank_num = bank->bank_number; + + /* Read flash JEDEC ID */ + retval = platform_read_id(bank, &id); + if (retval != ERROR_OK) + return retval; + + platform_info->dev = NULL; + for (const struct flash_device *p = flash_devices; p->name ; p++) + if (p->device_id == id) { + platform_info->dev = p; + break; + } + + if (!platform_info->dev) { + LOG_ERROR("Unknown flash device ID 0x%08" PRIx32, id); + return ERROR_FAIL; + } + + LOG_INFO("Found flash device \'%s\' ID 0x%08" PRIx32, + platform_info->dev->name, platform_info->dev->device_id); + + /* Set correct size value */ + bank->size = platform_info->dev->size_in_bytes; + + /* create and fill sectors array */ + bank->num_sectors = platform_info->dev->size_in_bytes / + platform_info->dev->sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (sectors == NULL) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + for (int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = + sector * platform_info->dev->sectorsize; + sectors[sector].size = platform_info->dev->sectorsize; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + platform_info->probed = 1; + + return ERROR_OK; +} + +static int platform_auto_probe(struct flash_bank *bank) +{ + int retval; + uint32_t regval; + struct target *target = bank->target; + struct platform_flash_bank *platform_info = bank->driver_priv; + + if (platform_info->probed) + return ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Autoprobe: target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = target_read_u32(target, + spibsc_get_reg(bank, CMNSR), ®val); + if (retval != ERROR_OK) + return retval; + + if (retval & ~TEND) { + LOG_ERROR("Not a SPIBSC or ROM is busy"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +static int platform_flash_erase_check(struct flash_bank *bank) +{ + /* Not implemented yet */ + return ERROR_OK; +} + +static int platform_protect_check(struct flash_bank *bank) +{ + /* Not implemented yet */ + return ERROR_OK; +} + +int platform_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct platform_flash_bank *platform_info = bank->driver_priv; + + if (!(platform_info->probed)) { + snprintf(buf, buf_size, + "\nSPI flash bank not probed yet\n"); + return ERROR_OK; + } + + snprintf(buf, buf_size, "\nSPI flash information:\n" + " Device \'%s\' ID 0x%08" PRIx32 "\n", + platform_info->dev->name, platform_info->dev->device_id); + + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(platform_flash_bank_command) +{ + struct platform_flash_bank *platform_info; + + if (CMD_ARGC < 7) + return ERROR_COMMAND_SYNTAX_ERROR; + + platform_info = malloc(sizeof(struct platform_flash_bank)); + if (platform_info == NULL) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + /* Get SPIBSC controller base address */ + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], platform_info->reg_base); + bank->driver_priv = platform_info; + platform_info->probed = 0; + + return ERROR_OK; +} + +struct flash_driver ec1_flash = { + .name = "spibsc", + .flash_bank_command = platform_flash_bank_command, + .erase = platform_flash_erase, + .protect = NULL, + .write = platform_flash_write, + .read = platform_flash_read, + .probe = platform_probe, + .auto_probe = platform_auto_probe, + .erase_check = platform_flash_erase_check, + .protect_check = platform_protect_check, + .info = platform_get_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 273e850..458e289 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -74,6 +74,7 @@ const struct flash_device flash_devices[] = { FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), + FLASH_ID("win w25q32jv", 0xd8, 0xc7, 0x001670ef, 0x100, 0x10000, 0x400000), FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), diff --git a/tcl/target/renesas_ec1.cfg b/tcl/target/renesas_ec1.cfg new file mode 100644 index 0000000..ad385fd --- /dev/null +++ b/tcl/target/renesas_ec1.cfg @@ -0,0 +1,119 @@ +# +# Renesas EC-1 w/ ARM Cortex-R4F @ 150 MHz +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME r9a06g043 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +if { [info exists CPU_JTAG_TAPID] } { + set _CPU_JTAG_TAPID $CPU_JTAG_TAPID +} else { + set _CPU_JTAG_TAPID 0x4ba00477 +} + + +source [find target/swj-dp.tcl] + +if { [using_jtag] } { + set _CPU_TAPID $_CPU_JTAG_TAPID +} else { + set _CPU_TAPID $_CPU_SWD_TAPID +} + +swj_newdap $_CHIPNAME tap -irlen 4 -expected-id $_CPU_TAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_r4 -dap $_CHIPNAME.dap -endian $_ENDIAN + +# 512 KiB ATCM @0x0 +# 32 KiB BTCM @0x800000 +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x8000 +} + +if { [info exists WORKAREAPHYS] } { + set _WORKAREAPHYS $WORKAREAPHYS +} else { + set _WORKAREAPHYS 0x800000 +} + +$_TARGETNAME configure \ +-work-area-phys $_WORKAREAPHYS \ +-work-area-size $_WORKAREASIZE \ +-work-area-backup 0 \ +-event gdb-attach { + cortex_r4 dbginit + halt +} + +$_TARGETNAME configure -event reset-init { + ec1_init + cortex_r4 dbginit +} + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME spibsc 0x30000000 0x400000 0 0 $_TARGETNAME 0xA0005000 + +source [find mem_helper.tcl] + +proc ec1_init {} { + halt + + ;# disable caches, MPU & branch predictor + set tR [arm mrc 15 0 1 0 0] + arm mcr 15 0 1 0 0 [expr $tR & 0xFFFFE7FA] + + ;# invalidate caches + arm mcr 15 0 7 5 0 0 + arm mcr 15 0 15 5 0 0 + + ;# Configure TCM + ;# Enable ECC + set tR [arm mrc 15 0 1 0 1] + arm mcr 15 0 1 0 1 [expr $tR | 0x06000000] + + ;# Configure clocks + ;# unlock + mww 0xA00B0B00 0x0000A501 + mdw 0xA00B0B00 0x1 + + ;# Enables LOCO clock + mww 0xA00B0040 0x0 + + ;# Enables PLL1 operation + mww 0xA00B0038 0x1 + + sleep 1 + ;# Selects the PLL1 + mww 0xA00B0024 0x1 + + ;# lock + mww 0xA00B0B00 0x0000A500 + mdw 0xA00B0B00 0x1 + + ;# unlock + mww 0xA00B0B00 0x0000A508 + mdw 0xA00B0B00 0x1 + + ;# access 0-wait + mww 0xA00B0800 0x2 + + ;# lock + mww 0xA00B0B00 0x0000A500 + mdw 0xA00B0B00 0x1 + +} + +reset_config trst_and_srst -- ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel