This is an automated email from Gerrit. dmitry pervushin (dpervus...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/2720
-- gerrit commit 927e89ea818b7e97113a98e2363a049fb9692705 Author: dmitry pervushin <dpervus...@gmail.com> Date: Thu Apr 16 17:35:46 2015 +0200 flash/nor: added sfctl (Toshiba) flash controller This controller is used on Toshiba TX03 and probably other Cortex-M3 based chips Change-Id: I546bdf35373145cc59fe72be3c9fb63fb93b018b Signed-off-by: dmitry pervushin <dpervus...@gmail.com> diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 878fc26..54a8a87 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -46,7 +46,8 @@ NOR_DRIVERS = \ nrf51.c \ mrvlqspi.c \ psoc4.c \ - sim3x.c + sim3x.c \ + sfctl.c noinst_HEADERS = \ core.h \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index fead797..9af72fe 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -59,6 +59,7 @@ extern struct flash_driver nrf51_flash; extern struct flash_driver mrvlqspi_flash; extern struct flash_driver psoc4_flash; extern struct flash_driver sim3x_flash; +extern struct flash_driver sfctl_flash; /** * The list of built-in flash drivers. @@ -102,6 +103,7 @@ static struct flash_driver *flash_drivers[] = { &mrvlqspi_flash, &psoc4_flash, &sim3x_flash, + &sfctl_flash, NULL, }; diff --git a/src/flash/nor/sfctl.c b/src/flash/nor/sfctl.c new file mode 100644 index 0000000..1395a6f --- /dev/null +++ b/src/flash/nor/sfctl.c @@ -0,0 +1,430 @@ +/*************************************************************************** + * Copyright (C) 2015 dmitry pervushin <dpervus...@gmail.com> * + * * + * 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. * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/binarybuffer.h> +#include <target/algorithm.h> +#include "spi.h" +#include "imp.h" + +#define SFCTL_TIMEOUT 0x100 +#define SFCTL_R_CTL0 0x400 +#define SFCTL_R_CTL1 0x404 +#define SFCTL_R_INTE 0x408 +#define SFCTL_R_STS 0x40C +#define SFCTL_R_BUF0 0x500 +#define SFCTL_R_BUF1 0x600 + +static int sfctl_probe(struct flash_bank *bank); +static int sfctl_autoprobe(struct flash_bank *bank); +static int sfctl_get_info(struct flash_bank *bank, char *buf, int buf_size); +static int sfctl_read(struct flash_bank *bank, + uint8_t *buffer, + uint32_t offset, + uint32_t count); +static int sfctl_write(struct flash_bank *bank, + const uint8_t *buffer, + uint32_t offset, + uint32_t count); +static int sfctl_erase(struct flash_bank *bank, int first, int last); +static int sfctl_protect_check(struct flash_bank *); +FLASH_BANK_COMMAND_HANDLER(sfctl_flash_bank_command); + +struct flash_driver sfctl_flash = { + .name = "sfctl", + .flash_bank_command = sfctl_flash_bank_command, + .erase = sfctl_erase, + .protect = NULL, + .write = sfctl_write, + .read = sfctl_read, + .probe = sfctl_probe, + .auto_probe = sfctl_autoprobe, + .erase_check = default_flash_blank_check, + .protect_check = sfctl_protect_check, + .info = sfctl_get_info, +}; + +struct sfctl_flash_bank { + struct target *target; + bool probed; + const struct flash_device *dev; + uint32_t base; +}; + +static int _sfctl_go_with_bufs(struct sfctl_flash_bank *sfb, int primary, int secondary); +static int _sfctl_wait(struct sfctl_flash_bank *sfb); +static int _sfctl_command(struct sfctl_flash_bank *sfb, uint8_t command, uint32_t addr); +static int _sfctl_readid(struct sfctl_flash_bank *sfb, uint32_t *id); +static int _sfctl_wrenable(struct sfctl_flash_bank *sfb); + +static int sfctl_entry_check(struct flash_bank *bank, int first_probe) +{ + struct sfctl_flash_bank *sfb = bank->driver_priv; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (first_probe) + return ERROR_OK; + + if (!sfb->probed) + return ERROR_FAIL; + return ERROR_OK; +} + +static int sfctl_autoprobe(struct flash_bank *bank) +{ + int rc; + + rc = sfctl_entry_check(bank, false); + if (rc != ERROR_OK) + return sfctl_probe(bank); + return rc; +} + +static int sfctl_probe(struct flash_bank *bank) +{ + struct sfctl_flash_bank *sfb = bank->driver_priv; + uint32_t id = 0xFFFFFFFF; + struct flash_sector *sectors; + int rc; + + rc = sfctl_entry_check(bank, true); + if (rc != ERROR_OK) + return rc; + + _sfctl_readid(sfb, &id); + + for (sfb->dev = flash_devices; sfb->dev->name; sfb->dev++) { + if (sfb->dev->device_id == id) + break; + } + if (!sfb->dev->name) + return ERROR_FAIL; + + bank->size = sfb->dev->size_in_bytes; + bank->num_sectors = bank->size / sfb->dev->sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + rc = target_write_u32(sfb->target, sfb->base + 0x08, + (0 << 0) | /* SPI mode 0 */ + (1 << 4) | /* fetch on 1st neg edge */ + (1 << 6) | /* SF WIP */ + (0x1F << 8)); /* SFCSn deassertion time */ + if (rc != ERROR_OK) + return rc; + + for (int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = + sector * sfb->dev->sectorsize; + sectors[sector].size = sfb->dev->sectorsize; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + + sfb->probed = true; + + return ERROR_OK; +} + +static int sfctl_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct sfctl_flash_bank *sfb = bank->driver_priv; + int rc; + + rc = sfctl_entry_check(bank, false); + if (rc != ERROR_OK) + return rc; + if (sfb && sfb->dev) + snprintf(buf, buf_size, "FSCTL flash info\n\tdevice '%s'\n\tid 0x%08x\n", + sfb->dev->name, sfb->dev->device_id); + return ERROR_OK; +} + +FLASH_BANK_COMMAND_HANDLER(sfctl_flash_bank_command) +{ + struct sfctl_flash_bank *sfb; + + sfb = malloc(sizeof(*sfb)); + if (!sfb) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = sfb; + sfb->probed = false; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], sfb->base); + bank->base = 0x10000000; + sfb->dev = NULL; + sfb->target = bank->target; + + return ERROR_OK; +} + +static int _sfctl_wait(struct sfctl_flash_bank *sfb) +{ + int rc; + uint32_t sts; + uint32_t c; + + for (c = 0;; c++) { + rc = target_read_u32(sfb->target, sfb->base + SFCTL_R_STS, &sts); + if (rc != ERROR_OK) + return rc; + if ((sts & (1 << 1)) == 0) + break; + if (c > SFCTL_TIMEOUT) + return ERROR_TARGET_TIMEOUT; + alive_sleep(1); + } + return ERROR_OK; +} + +static int _sfctl_go_with_bufs(struct sfctl_flash_bank *sfb, int primary, int secondary) +{ + int rc; + uint32_t v; + + rc = target_read_u32(sfb->target, sfb->base + SFCTL_R_CTL1, &v); + if (rc != ERROR_OK) + return rc; + + /* secondary size and enable */ + v &= ~(0xFF << 24); + v &= ~(1 << 5); + /* primary size and enable */ + v &= ~(0x7 << 16); + v &= ~(1 << 4); + + if (primary > 0) { + v |= (1 << 4); + v |= ((primary - 1) << 16); + } + + if (secondary > 0) { + v |= (1 << 5); + v |= ((secondary - 1) << 24); + } + + v |= 1; + + rc = target_write_u32(sfb->target, sfb->base + SFCTL_R_CTL1, v); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_wait(sfb); + if (rc != ERROR_OK) + return rc; + return rc; +} + +static int _sfctl_readid(struct sfctl_flash_bank *sfb, uint32_t *id) +{ + int rc = ERROR_OK; + uint8_t v[4]; + + rc = _sfctl_wait(sfb); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_command(sfb, SPIFLASH_READ_ID, 0); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_go_with_bufs(sfb, 5, 0); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_wait(sfb); + if (rc != ERROR_OK) + return rc; + rc = target_read_u32(sfb->target, sfb->base + SFCTL_R_BUF0, (uint32_t *)v); + if (rc != ERROR_OK) + return rc; + *id = be_to_h_u32(v); + return rc; +} + +static int _sfctl_wrenable(struct sfctl_flash_bank *sfb) +{ + int rc; + + rc = _sfctl_wait(sfb); + if (rc == ERROR_OK) + rc = _sfctl_command(sfb, SPIFLASH_WRITE_ENABLE, 0); + if (rc == ERROR_OK) + rc = _sfctl_go_with_bufs(sfb, 1, 0); + return _sfctl_wait(sfb); +} + +static int sfctl_protect_check(struct flash_bank *bank) +{ + return ERROR_OK; +} + +static int sfctl_write(struct flash_bank *bank, + const uint8_t *buffer, + uint32_t offset, + uint32_t count) +{ + struct sfctl_flash_bank *sfb = bank->driver_priv; + int rc; + int i, cnt; + + rc = sfctl_entry_check(bank, false); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_wait(sfb); + if (rc != ERROR_OK) + return rc; + while (count > 0) { + + cnt = count; + if (cnt > 256) + cnt = 256; + + rc = _sfctl_wrenable(sfb); + if (rc != ERROR_OK) + return rc; + + for (i = 0; rc == ERROR_OK && i < cnt; i++) { + rc = target_write_u8(sfb->target, sfb->base + SFCTL_R_BUF1 + i, buffer[i]); + if (rc != ERROR_OK) + return rc; + } + + rc = _sfctl_command(sfb, SPIFLASH_PAGE_PROGRAM, offset); + if (rc != ERROR_OK) + return rc; + + rc = _sfctl_go_with_bufs(sfb, 4, 256); + if (rc != ERROR_OK) + return rc; + + rc = _sfctl_wait(sfb); + if (rc != ERROR_OK) + return rc; + + buffer = buffer + cnt; + count = count - cnt; + offset = offset + cnt; + } + return rc; +} + + +static int sfctl_read(struct flash_bank *bank, + uint8_t *buffer, + uint32_t offset, + uint32_t count) +{ + struct sfctl_flash_bank *sfb = bank->driver_priv; + int rc; + int i, cnt; + + rc = sfctl_entry_check(bank, false); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_wait(sfb); + if (rc != ERROR_OK) + return rc; + + memset(buffer, 0xEE, count); + while (count > 0) { + + cnt = count; + if (cnt > 256) + cnt = 256; + + for (i = 0; rc == ERROR_OK && i < cnt; i++) + rc = target_write_u8(sfb->target, sfb->base + SFCTL_R_BUF1 + i, 0xAA); + if (rc == ERROR_OK) + rc = _sfctl_command(sfb, SPIFLASH_FAST_READ, offset); + if (rc == ERROR_OK) + rc = _sfctl_go_with_bufs(sfb, 5, 256); + for (i = 0; rc == ERROR_OK && i < cnt; i++) + rc = target_read_u8(sfb->target, sfb->base + SFCTL_R_BUF1 + i, buffer + i); + if (rc != ERROR_OK) + break; + + buffer = buffer + cnt; + count = count - cnt; + offset = offset + cnt; + } + return rc; +} + +static int _sfctl_erase_chip(struct sfctl_flash_bank *sfb) +{ + int rc; + + rc = _sfctl_wrenable(sfb); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_command(sfb, 0xC7, 0); + if (rc != ERROR_OK) + return rc; + rc = _sfctl_go_with_bufs(sfb, 1, 0); + return rc; +} + +static int sfctl_erase(struct flash_bank *bank, int first, int last) +{ + struct sfctl_flash_bank *sfb = bank->driver_priv; + int rc = ERROR_OK; + int sector; + + rc = sfctl_entry_check(bank, false); + if (rc != ERROR_OK) + return rc; + if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + for (sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %d protected", sector); + return ERROR_FAIL; + } + } + + rc = _sfctl_wait(sfb); + + if (first == 0 && last == bank->num_sectors - 1) { + LOG_INFO("%s: erasing whole chip", __func__); + return _sfctl_erase_chip(sfb); + } + + for (sector = first; rc == ERROR_OK && sector <= last; sector++) { + rc = _sfctl_wrenable(sfb); + if (rc == ERROR_OK) + rc = _sfctl_command(sfb, sfb->dev->erase_cmd, + sector * sfb->dev->sectorsize); + if (rc == ERROR_OK) + rc = _sfctl_go_with_bufs(sfb, 4, 0); + } + return rc; +} + +static int _sfctl_command(struct sfctl_flash_bank *sfb, uint8_t command, uint32_t addr) +{ + return target_write_u32(sfb->target, sfb->base + SFCTL_R_BUF0, + command | (addr << 8)); +} -- ------------------------------------------------------------------------------ BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT Develop your own process in accordance with the BPMN 2 standard Learn Process modeling best practices with Bonita BPM through live exercises http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_ source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel