Commit 4ab75a36 authored by Steven Stallion's avatar Steven Stallion Committed by Matthias Welwarsky
Browse files

esirisc: support eSi-RISC targets



eSi-RISC is a highly configurable microprocessor architecture for
embedded systems provided by EnSilica. This patch adds support for
32-bit targets and also includes an internal flash driver and
uC/OS-III RTOS support. This is a non-traditional target and required
a number of additional changes to support non-linear register numbers
and the 'p' packet in RTOS support for proper integration into
EnSilica's GDB port.

Change-Id: I59d5c40b3bb2ace1b1a01b2538bfab211adf113f
Signed-off-by: default avatarSteven Stallion <stallion@squareup.com>
Reviewed-on: http://openocd.zylin.com/4660


Tested-by: jenkins
Reviewed-by: default avatarMatthias Welwarsky <matthias@welwarsky.de>
parent e72b2601
......@@ -117,17 +117,18 @@ Debug targets
-------------
ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M, LS102x-SAP,
Feroceon/Dragonite, DSP563xx, DSP5680xx, FA526, MIPS EJTAG, NDS32,
XScale, Intel Quark.
Feroceon/Dragonite, DSP563xx, DSP5680xx, EnSilica eSi-RISC, FA526, MIPS
EJTAG, NDS32, XScale, Intel Quark.
Flash drivers
-------------
ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis,
LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI,
Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x, Stellaris, STM32,
STMSMI, STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx,
i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400, XMC1xxx, XMC4xxx.
ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC,
FM3, FM4, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI,
Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x,
Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of
AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood,
S3C24xx, S3C6400, XMC1xxx, XMC4xxx.
==================
......
......@@ -4275,6 +4275,8 @@ compact Thumb2 instruction set.
@item @code{dragonite} -- resembles arm966e
@item @code{dsp563xx} -- implements Freescale's 24-bit DSP.
(Support for this is still incomplete.)
@item @code{esirisc} -- this is an EnSilica eSi-RISC core.
The current implementation supports eSi-32xx cores.
@item @code{fa526} -- resembles arm920 (w/o Thumb)
@item @code{feroceon} -- resembles arm926
@item @code{mips_m4k} -- a MIPS core
......@@ -5647,6 +5649,27 @@ Note that in order for this command to take effect, the target needs to be reset
supported.}
@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
configure the driver: @option{cfg_address} is the base address of the
configuration register interface, @option{clock_hz} is the expected clock
frequency, and @option{wait_states} is the number of configured read wait states.
@example
flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 $_TARGETNAME cfg_address clock_hz wait_states
@end example
@deffn Command {esirisc_flash mass_erase} (bank_id)
Erases all pages in data memory for the bank identified by @option{bank_id}.
@end deffn
@deffn Command {esirisc_flash ref_erase} (bank_id)
Erases the reference cell for the bank identified by @option{bank_id}. This is
an uncommon operation.
@end deffn
@end deffn
@deffn {Flash Driver} fm3
All members of the FM3 microcontroller family from Fujitsu
include internal flash and use ARM Cortex-M3 cores.
......@@ -8933,6 +8956,29 @@ Selects whether interrupts will be processed when single stepping. The default c
@option{on}.
@end deffn
@section EnSilica eSi-RISC Architecture
eSi-RISC is a highly configurable microprocessor architecture for embedded systems
provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.)
@subsection esirisc specific commands
@deffn Command {esirisc cache_arch} (@option{harvard}|@option{von_neumann})
Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE}
option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed.
@end deffn
@deffn Command {esirisc flush_caches}
Flush instruction and data caches. This command requires that the target is halted
when the command is issued and configured with an instruction or data cache.
@end deffn
@deffn Command {esirisc hwdc} (@option{all}|@option{none}|mask ...)
Configure hardware debug control. The HWDC register controls which exceptions return
control back to the debugger. Possible masks are @option{all}, @option{none},
@option{reset}, @option{interrupt}, @option{syscall}, @option{error}, and @option{debug}.
By default, @option{reset}, @option{error}, and @option{debug} are enabled.
@end deffn
@section Intel Architecture
Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32
......
......@@ -25,6 +25,7 @@ NOR_DRIVERS = \
%D%/dsp5680xx_flash.c \
%D%/efm32.c \
%D%/em357.c \
%D%/esirisc_flash.c \
%D%/faux.c \
%D%/fm3.c \
%D%/fm4.c \
......
......@@ -38,6 +38,7 @@ extern struct flash_driver cfi_flash;
extern struct flash_driver dsp5680xx_flash;
extern struct flash_driver efm32_flash;
extern struct flash_driver em357_flash;
extern struct flash_driver esirisc_flash;
extern struct flash_driver faux_flash;
extern struct flash_driver fm3_flash;
extern struct flash_driver fm4_flash;
......@@ -103,6 +104,7 @@ static struct flash_driver *flash_drivers[] = {
&dsp5680xx_flash,
&efm32_flash,
&em357_flash,
&esirisc_flash,
&faux_flash,
&fm3_flash,
&fm4_flash,
......
/***************************************************************************
* Copyright (C) 2018 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> *
* James Zhao <hjz@squareup.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. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <flash/common.h>
#include <flash/nor/imp.h>
#include <helper/command.h>
#include <helper/log.h>
#include <helper/time_support.h>
#include <helper/types.h>
#include <target/esirisc.h>
#include <target/target.h>
/* eSi-TSMC Flash Registers */
#define CONTROL 0x00 /* Control Register */
#define TIMING0 0x04 /* Timing Register 0 */
#define TIMING1 0x08 /* Timing Register 1 */
#define TIMING2 0x0c /* Timing Register 2 */
#define UNLOCK1 0x18 /* Unlock 1 */
#define UNLOCK2 0x1c /* Unlock 2 */
#define ADDRESS 0x20 /* Erase/Program Address */
#define PB_DATA 0x24 /* Program Buffer Data */
#define PB_INDEX 0x28 /* Program Buffer Index */
#define STATUS 0x2c /* Status Register */
#define REDUN_0 0x30 /* Redundant Address 0 */
#define REDUN_1 0x34 /* Redundant Address 1 */
/* Control Fields */
#define CONTROL_SLM (1<<0) /* Sleep Mode */
#define CONTROL_WP (1<<1) /* Register Write Protect */
#define CONTROL_E (1<<3) /* Erase */
#define CONTROL_EP (1<<4) /* Erase Page */
#define CONTROL_P (1<<5) /* Program Flash */
#define CONTROL_ERC (1<<6) /* Erase Reference Cell */
#define CONTROL_R (1<<7) /* Recall Trim Code */
#define CONTROL_AP (1<<8) /* Auto-Program */
/* Timing Fields */
#define TIMING0_R(x) (((x) << 0) & 0x3f) /* Read Wait States */
#define TIMING0_F(x) (((x) << 16) & 0xffff0000) /* Tnvh Clock Cycles */
#define TIMING1_E(x) (((x) << 0) & 0xffffff) /* Tme/Terase/Tre Clock Cycles */
#define TIMING2_P(x) (((x) << 0) & 0xffff) /* Tprog Clock Cycles */
#define TIMING2_H(x) (((x) << 16) & 0xff0000) /* Clock Cycles in 100ns */
#define TIMING2_T(x) (((x) << 24) & 0xf000000) /* Clock Cycles in 10ns */
/* Status Fields */
#define STATUS_BUSY (1<<0) /* Busy (Erase/Program) */
#define STATUS_WER (1<<1) /* Write Protect Error */
#define STATUS_DR (1<<2) /* Disable Redundancy */
#define STATUS_DIS (1<<3) /* Discharged */
#define STATUS_BO (1<<4) /* Brown Out */
/* Redundant Address Fields */
#define REDUN_R (1<<0) /* Used */
#define REDUN_P(x) (((x) << 12) & 0x7f000) /* Redundant Page Address */
/*
* The eSi-TSMC Flash manual provides two sets of timings based on the
* underlying flash process. By default, 90nm is assumed.
*/
#if 0 /* 55nm */
#define TNVH 5000 /* 5us */
#define TME 80000000 /* 80ms */
#define TERASE 160000000 /* 160ms */
#define TRE 100000000 /* 100ms */
#define TPROG 8000 /* 8us */
#else /* 90nm */
#define TNVH 5000 /* 5us */
#define TME 20000000 /* 20ms */
#define TERASE 40000000 /* 40ms */
#define TRE 40000000 /* 40ms */
#define TPROG 40000 /* 40us */
#endif
#define CONTROL_TIMEOUT 5000 /* 5s */
#define PAGE_SIZE 4096
#define PB_MAX 32
#define NUM_NS_PER_S 1000000000ULL
struct esirisc_flash_bank {
bool probed;
uint32_t cfg;
uint32_t clock;
uint32_t wait_states;
};
FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
{
struct esirisc_flash_bank *esirisc_info;
if (CMD_ARGC < 9)
return ERROR_COMMAND_SYNTAX_ERROR;
esirisc_info = calloc(1, sizeof(struct esirisc_flash_bank));
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], esirisc_info->cfg);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], esirisc_info->clock);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], esirisc_info->wait_states);
bank->driver_priv = esirisc_info;
return ERROR_OK;
}
/*
* Register writes are ignored if the control.WP flag is set; the
* following sequence is required to modify this flag even when
* protection is disabled.
*/
static int esirisc_flash_unlock(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0x7123);
target_write_u32(target, esirisc_info->cfg + UNLOCK2, 0x812a);
target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0xbee1);
return ERROR_OK;
}
static int esirisc_flash_disable_protect(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t control;
target_read_u32(target, esirisc_info->cfg + CONTROL, &control);
if (!(control & CONTROL_WP))
return ERROR_OK;
esirisc_flash_unlock(bank);
control &= ~CONTROL_WP;
target_write_u32(target, esirisc_info->cfg + CONTROL, control);
return ERROR_OK;
}
static int esirisc_flash_enable_protect(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t control;
target_read_u32(target, esirisc_info->cfg + CONTROL, &control);
if (control & CONTROL_WP)
return ERROR_OK;
esirisc_flash_unlock(bank);
control |= CONTROL_WP;
target_write_u32(target, esirisc_info->cfg + CONTROL, control);
return ERROR_OK;
}
static int esirisc_flash_check_status(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t status;
target_read_u32(target, esirisc_info->cfg + STATUS, &status);
if (status & STATUS_WER) {
LOG_ERROR("%s: bad status: 0x%" PRIx32, bank->name, status);
return ERROR_FLASH_OPERATION_FAILED;
}
return ERROR_OK;
}
static int esirisc_flash_clear_status(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
target_write_u32(target, esirisc_info->cfg + STATUS, STATUS_WER);
return ERROR_OK;
}
static int esirisc_flash_wait(struct flash_bank *bank, int ms)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t status;
int64_t t;
t = timeval_ms();
for (;;) {
target_read_u32(target, esirisc_info->cfg + STATUS, &status);
if (!(status & STATUS_BUSY))
return ERROR_OK;
if ((timeval_ms() - t) > ms)
return ERROR_TARGET_TIMEOUT;
keep_alive();
}
}
static int esirisc_flash_control(struct flash_bank *bank, uint32_t control)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
esirisc_flash_clear_status(bank);
target_write_u32(target, esirisc_info->cfg + CONTROL, control);
int retval = esirisc_flash_wait(bank, CONTROL_TIMEOUT);
if (retval != ERROR_OK) {
LOG_ERROR("%s: control timed out: 0x%" PRIx32, bank->name, control);
return retval;
}
return esirisc_flash_check_status(bank);
}
static int esirisc_flash_recall(struct flash_bank *bank)
{
return esirisc_flash_control(bank, CONTROL_R);
}
static int esirisc_flash_erase(struct flash_bank *bank, int first, int last)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
int retval = ERROR_OK;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank);
for (int page = first; page < last; ++page) {
uint32_t address = page * PAGE_SIZE;
target_write_u32(target, esirisc_info->cfg + ADDRESS, address);
retval = esirisc_flash_control(bank, CONTROL_EP);
if (retval != ERROR_OK) {
LOG_ERROR("%s: failed to erase address: 0x%" PRIx32, bank->name, address);
break;
}
}
esirisc_flash_enable_protect(bank);
return retval;
}
static int esirisc_flash_mass_erase(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank);
target_write_u32(target, esirisc_info->cfg + ADDRESS, 0);
retval = esirisc_flash_control(bank, CONTROL_E);
if (retval != ERROR_OK)
LOG_ERROR("%s: failed to mass erase", bank->name);
esirisc_flash_enable_protect(bank);
return retval;
}
/*
* Per TSMC, the reference cell should be erased once per sample. This
* is typically done during wafer sort, however we include support for
* those that may need to calibrate flash at a later time.
*/
static int esirisc_flash_ref_erase(struct flash_bank *bank)
{
struct target *target = bank->target;
int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank);
retval = esirisc_flash_control(bank, CONTROL_ERC);
if (retval != ERROR_OK)
LOG_ERROR("%s: failed to erase reference cell", bank->name);
esirisc_flash_enable_protect(bank);
return retval;
}
static int esirisc_flash_protect(struct flash_bank *bank, int set, int first, int last)
{
struct target *target = bank->target;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
if (set)
esirisc_flash_enable_protect(bank);
else
esirisc_flash_disable_protect(bank);
return ERROR_OK;
}
static int esirisc_flash_fill_pb(struct flash_bank *bank,
const uint8_t *buffer, uint32_t count)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
struct esirisc_common *esirisc = target_to_esirisc(target);
/*
* The pb_index register is auto-incremented when pb_data is written
* and should be cleared before each operation.
*/
target_write_u32(target, esirisc_info->cfg + PB_INDEX, 0);
/*
* The width of the pb_data register depends on the underlying
* target; writing one byte at a time incurs a significant
* performance penalty and should be avoided.
*/
while (count > 0) {
uint32_t max_bytes = DIV_ROUND_UP(esirisc->num_bits, 8);
uint32_t num_bytes = MIN(count, max_bytes);
target_write_buffer(target, esirisc_info->cfg + PB_DATA, num_bytes, buffer);
buffer += num_bytes;
count -= num_bytes;
}
return ERROR_OK;
}
static int esirisc_flash_write(struct flash_bank *bank,
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
int retval = ERROR_OK;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank);
/*
* The address register is auto-incremented based on the contents of
* the pb_index register after each operation completes. It can be
* set once provided pb_index is cleared before each operation.
*/
target_write_u32(target, esirisc_info->cfg + ADDRESS, offset);
/*
* Care must be taken when filling the program buffer; a maximum of
* 32 bytes may be written at a time and may not cross a 32-byte
* boundary based on the current offset.
*/
while (count > 0) {
uint32_t max_bytes = PB_MAX - (offset & 0x1f);
uint32_t num_bytes = MIN(count, max_bytes);
esirisc_flash_fill_pb(bank, buffer, num_bytes);
retval = esirisc_flash_control(bank, CONTROL_P);
if (retval != ERROR_OK) {
LOG_ERROR("%s: failed to program address: 0x%" PRIx32, bank->name, offset);
break;
}
buffer += num_bytes;
offset += num_bytes;
count -= num_bytes;
}
esirisc_flash_enable_protect(bank);
return retval;
}
static uint32_t esirisc_flash_num_cycles(struct flash_bank *bank, uint64_t ns)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
/* apply scaling factor to avoid truncation */
uint64_t hz = (uint64_t)esirisc_info->clock * 1000;
uint64_t num_cycles = ((hz / NUM_NS_PER_S) * ns) / 1000;
if (hz % NUM_NS_PER_S > 0)
num_cycles++;
return num_cycles;
}
static int esirisc_flash_init(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t value;
int retval;
esirisc_flash_disable_protect(bank);
/* initialize timing registers */
value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH)) |
TIMING0_R(esirisc_info->wait_states);
LOG_DEBUG("TIMING0: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING0, value);
value = TIMING1_E(esirisc_flash_num_cycles(bank, TERASE));
LOG_DEBUG("TIMING1: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING1, value);
value = TIMING2_T(esirisc_flash_num_cycles(bank, 10)) |
TIMING2_H(esirisc_flash_num_cycles(bank, 100)) |
TIMING2_P(esirisc_flash_num_cycles(bank, TPROG));
LOG_DEBUG("TIMING2: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING2, value);
/* recall trim code */
retval = esirisc_flash_recall(bank);
if (retval != ERROR_OK)
LOG_ERROR("%s: failed to recall trim code", bank->name);
esirisc_flash_enable_protect(bank);
return retval;
}
static int esirisc_flash_probe(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
bank->num_sectors = bank->size / PAGE_SIZE;
bank->sectors = alloc_block_array(0, PAGE_SIZE, bank->num_sectors);
/*
* Register write protection is enforced using a single protection
* block for the entire bank. This is as good as it gets.
*/
bank->num_prot_blocks = 1;
bank->prot_blocks = alloc_block_array(0, bank->size, bank->num_prot_blocks);
retval = esirisc_flash_init(bank);
if (retval != ERROR_OK) {
LOG_ERROR("%s: failed to initialize bank", bank->name);
return retval;
}
esirisc_info->probed = true;
return ERROR_OK;
}
static int esirisc_flash_auto_probe(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;