Merge branch 'master' into update
Change-Id: I2cd34ed5bb1903736ae8ce109acebaf13bf49805
This commit is contained in:
@@ -56,6 +56,7 @@ NOR_DRIVERS = \
|
||||
%D%/str9xpec.c \
|
||||
%D%/tms470.c \
|
||||
%D%/virtual.c \
|
||||
%D%/xcf.c \
|
||||
%D%/xmc1xxx.c \
|
||||
%D%/xmc4xxx.c
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ extern struct flash_driver str9x_flash;
|
||||
extern struct flash_driver str9xpec_flash;
|
||||
extern struct flash_driver tms470_flash;
|
||||
extern struct flash_driver virtual_flash;
|
||||
extern struct flash_driver xcf_flash;
|
||||
extern struct flash_driver xmc1xxx_flash;
|
||||
extern struct flash_driver xmc4xxx_flash;
|
||||
|
||||
@@ -124,6 +125,7 @@ static struct flash_driver *flash_drivers[] = {
|
||||
&str9xpec_flash,
|
||||
&tms470_flash,
|
||||
&virtual_flash,
|
||||
&xcf_flash,
|
||||
&xmc1xxx_flash,
|
||||
&xmc4xxx_flash,
|
||||
NULL,
|
||||
|
||||
+47
-24
@@ -32,14 +32,13 @@ struct jtagspi_flash_bank {
|
||||
const struct flash_device *dev;
|
||||
int probed;
|
||||
uint32_t ir;
|
||||
uint32_t dr_len;
|
||||
};
|
||||
|
||||
FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
|
||||
{
|
||||
struct jtagspi_flash_bank *info;
|
||||
|
||||
if (CMD_ARGC < 8)
|
||||
if (CMD_ARGC < 7)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
info = malloc(sizeof(struct jtagspi_flash_bank));
|
||||
@@ -52,7 +51,6 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
|
||||
info->tap = NULL;
|
||||
info->probed = 0;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->dr_len);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -63,9 +61,6 @@ static void jtagspi_set_ir(struct flash_bank *bank)
|
||||
struct scan_field field;
|
||||
uint8_t buf[4];
|
||||
|
||||
if (buf_get_u32(info->tap->cur_instr, 0, info->tap->ir_length) == info->ir)
|
||||
return;
|
||||
|
||||
LOG_DEBUG("loading jtagspi ir");
|
||||
buf_set_u32(buf, 0, info->tap->ir_length, info->ir);
|
||||
field.num_bits = info->tap->ir_length;
|
||||
@@ -84,28 +79,53 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
|
||||
uint32_t *addr, uint8_t *data, int len)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
struct scan_field fields[3];
|
||||
uint8_t cmd_buf[4];
|
||||
struct scan_field fields[6];
|
||||
uint8_t marker = 1;
|
||||
uint8_t xfer_bits_buf[4];
|
||||
uint8_t addr_buf[3];
|
||||
uint8_t *data_buf;
|
||||
uint32_t xfer_bits;
|
||||
int is_read, lenb, n;
|
||||
|
||||
/* LOG_DEBUG("cmd=0x%02x len=%i", cmd, len); */
|
||||
|
||||
n = 0;
|
||||
fields[n].num_bits = 8;
|
||||
cmd_buf[0] = cmd;
|
||||
if (addr) {
|
||||
h_u24_to_be(cmd_buf + 1, *addr);
|
||||
fields[n].num_bits += 24;
|
||||
}
|
||||
flip_u8(cmd_buf, cmd_buf, 4);
|
||||
fields[n].out_value = cmd_buf;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
is_read = (len < 0);
|
||||
if (is_read)
|
||||
len = -len;
|
||||
|
||||
n = 0;
|
||||
|
||||
fields[n].num_bits = 1;
|
||||
fields[n].out_value = ▮
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
xfer_bits = 8 + len - 1;
|
||||
/* cmd + read/write - 1 due to the counter implementation */
|
||||
if (addr)
|
||||
xfer_bits += 24;
|
||||
h_u32_to_be(xfer_bits_buf, xfer_bits);
|
||||
flip_u8(xfer_bits_buf, xfer_bits_buf, 4);
|
||||
fields[n].num_bits = 32;
|
||||
fields[n].out_value = xfer_bits_buf;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
cmd = flip_u32(cmd, 8);
|
||||
fields[n].num_bits = 8;
|
||||
fields[n].out_value = &cmd;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
if (addr) {
|
||||
h_u24_to_be(addr_buf, *addr);
|
||||
flip_u8(addr_buf, addr_buf, 3);
|
||||
fields[n].num_bits = 24;
|
||||
fields[n].out_value = addr_buf;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
}
|
||||
|
||||
lenb = DIV_ROUND_UP(len, 8);
|
||||
data_buf = malloc(lenb);
|
||||
if (lenb > 0) {
|
||||
@@ -114,10 +134,11 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (is_read) {
|
||||
fields[n].num_bits = info->dr_len;
|
||||
fields[n].num_bits = jtag_tap_count_enabled();
|
||||
fields[n].out_value = NULL;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
fields[n].out_value = NULL;
|
||||
fields[n].in_value = data_buf;
|
||||
} else {
|
||||
@@ -130,6 +151,7 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
|
||||
}
|
||||
|
||||
jtagspi_set_ir(bank);
|
||||
/* passing from an IR scan to SHIFT-DR clears BYPASS registers */
|
||||
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
|
||||
@@ -202,9 +224,10 @@ static int jtagspi_probe(struct flash_bank *bank)
|
||||
static void jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
|
||||
{
|
||||
uint8_t buf;
|
||||
jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8);
|
||||
*status = buf;
|
||||
/* LOG_DEBUG("status=0x%08" PRIx32, *status); */
|
||||
if (jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8) == ERROR_OK) {
|
||||
*status = buf;
|
||||
/* LOG_DEBUG("status=0x%08" PRIx32, *status); */
|
||||
}
|
||||
}
|
||||
|
||||
static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
|
||||
|
||||
+58
-8
@@ -287,6 +287,7 @@ struct kinetis_chip {
|
||||
|
||||
FS_NO_CMD_BLOCKSTAT = 0x40,
|
||||
FS_WIDTH_256BIT = 0x80,
|
||||
FS_ECC = 0x100,
|
||||
} flash_support;
|
||||
|
||||
enum {
|
||||
@@ -388,6 +389,7 @@ static const struct kinetis_type kinetis_types_old[] = {
|
||||
|
||||
static bool allow_fcf_writes;
|
||||
static uint8_t fcf_fopt = 0xff;
|
||||
static bool fcf_fopt_configured;
|
||||
static bool create_banks;
|
||||
|
||||
|
||||
@@ -1881,9 +1883,13 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
{
|
||||
int result;
|
||||
bool set_fcf = false;
|
||||
bool fcf_in_data_valid = false;
|
||||
int sect = 0;
|
||||
struct kinetis_flash_bank *k_bank = bank->driver_priv;
|
||||
struct kinetis_chip *k_chip = k_bank->k_chip;
|
||||
uint8_t fcf_buffer[FCF_SIZE];
|
||||
uint8_t fcf_current[FCF_SIZE];
|
||||
uint8_t fcf_in_data[FCF_SIZE];
|
||||
|
||||
result = kinetis_check_run_mode(k_chip);
|
||||
if (result != ERROR_OK)
|
||||
@@ -1904,11 +1910,41 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
}
|
||||
|
||||
if (set_fcf) {
|
||||
uint8_t fcf_buffer[FCF_SIZE];
|
||||
uint8_t fcf_current[FCF_SIZE];
|
||||
|
||||
kinetis_fill_fcf(bank, fcf_buffer);
|
||||
|
||||
fcf_in_data_valid = offset <= FCF_ADDRESS
|
||||
&& offset + count >= FCF_ADDRESS + FCF_SIZE;
|
||||
if (fcf_in_data_valid) {
|
||||
memcpy(fcf_in_data, buffer + FCF_ADDRESS - offset, FCF_SIZE);
|
||||
if (memcmp(fcf_in_data + FCF_FPROT, fcf_buffer, 4)) {
|
||||
fcf_in_data_valid = false;
|
||||
LOG_INFO("Flash protection requested in programmed file differs from current setting.");
|
||||
}
|
||||
if (fcf_in_data[FCF_FDPROT] != fcf_buffer[FCF_FDPROT]) {
|
||||
fcf_in_data_valid = false;
|
||||
LOG_INFO("Data flash protection requested in programmed file differs from current setting.");
|
||||
}
|
||||
if ((fcf_in_data[FCF_FSEC] & 3) != 2) {
|
||||
fcf_in_data_valid = false;
|
||||
LOG_INFO("Device security requested in programmed file!");
|
||||
} else if (k_chip->flash_support & FS_ECC
|
||||
&& fcf_in_data[FCF_FSEC] != fcf_buffer[FCF_FSEC]) {
|
||||
fcf_in_data_valid = false;
|
||||
LOG_INFO("Strange unsecure mode 0x%02" PRIx8
|
||||
"requested in programmed file!",
|
||||
fcf_in_data[FCF_FSEC]);
|
||||
}
|
||||
if ((k_chip->flash_support & FS_ECC || fcf_fopt_configured)
|
||||
&& fcf_in_data[FCF_FOPT] != fcf_fopt) {
|
||||
fcf_in_data_valid = false;
|
||||
LOG_INFO("FOPT requested in programmed file differs from current setting.");
|
||||
}
|
||||
if (!fcf_in_data_valid)
|
||||
LOG_INFO("Expect verify errors at FCF (0x408-0x40f).");
|
||||
}
|
||||
}
|
||||
|
||||
if (set_fcf && !fcf_in_data_valid) {
|
||||
if (offset < FCF_ADDRESS) {
|
||||
/* write part preceding FCF */
|
||||
result = kinetis_write_inner(bank, buffer, offset, FCF_ADDRESS - offset);
|
||||
@@ -1937,9 +1973,10 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
}
|
||||
return result;
|
||||
|
||||
} else
|
||||
} else {
|
||||
/* no FCF fiddling, normal write */
|
||||
return kinetis_write_inner(bank, buffer, offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2146,10 +2183,21 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
|
||||
k_chip->nvm_sector_size = 4<<10;
|
||||
k_chip->max_flash_prog_size = 1<<10;
|
||||
num_blocks = 4;
|
||||
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR;
|
||||
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC;
|
||||
cpu_mhz = 180;
|
||||
break;
|
||||
|
||||
case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX7:
|
||||
/* K27FN2M0 */
|
||||
case KINETIS_SDID_FAMILYID_K2X | KINETIS_SDID_SUBFAMID_KX8:
|
||||
/* K28FN2M0 */
|
||||
k_chip->pflash_sector_size = 4<<10;
|
||||
k_chip->max_flash_prog_size = 1<<10;
|
||||
num_blocks = 4;
|
||||
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC;
|
||||
cpu_mhz = 150;
|
||||
break;
|
||||
|
||||
case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX0:
|
||||
case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX1:
|
||||
case KINETIS_SDID_FAMILYID_K8X | KINETIS_SDID_SUBFAMID_KX2:
|
||||
@@ -2300,7 +2348,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip)
|
||||
k_chip->max_flash_prog_size = 1<<10;
|
||||
num_blocks = 1;
|
||||
maxaddr_shift = 14;
|
||||
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT;
|
||||
k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT | FS_ECC;
|
||||
k_chip->pflash_base = 0x10000000;
|
||||
k_chip->progr_accel_ram = 0x18000000;
|
||||
cpu_mhz = 240;
|
||||
@@ -2959,10 +3007,12 @@ COMMAND_HANDLER(kinetis_fopt_handler)
|
||||
if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
if (CMD_ARGC == 1)
|
||||
if (CMD_ARGC == 1) {
|
||||
fcf_fopt = (uint8_t)strtoul(CMD_ARGV[0], NULL, 0);
|
||||
else
|
||||
fcf_fopt_configured = true;
|
||||
} else {
|
||||
command_print(CMD_CTX, "FCF_FOPT 0x%02" PRIx8, fcf_fopt);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
@@ -168,6 +168,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
|
||||
|
||||
/* nRF51822 Devices (IC rev 3). */
|
||||
NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256),
|
||||
NRF5_DEVICE_DEF(0x00D1, "51822", "QFAA", "H2", 256),
|
||||
NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128),
|
||||
NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256),
|
||||
NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256),
|
||||
|
||||
@@ -652,6 +652,9 @@ static int stm32l4_probe(struct flash_bank *bank)
|
||||
/* get options to for DUAL BANK. */
|
||||
retval = target_read_u32(target, STM32_FLASH_OPTR, &options);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* only devices with < 1024 kiB may be set to single bank dual banks */
|
||||
if ((flash_size_in_kb == 1024) || !(options & OPT_DUALBANK))
|
||||
stm32l4_info->option_bytes.bank_b_start = 256;
|
||||
|
||||
@@ -0,0 +1,897 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2016 by Uladzimir Pylinski aka barthess *
|
||||
* barthess@yandex.ru *
|
||||
* *
|
||||
* 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 <string.h>
|
||||
|
||||
#include "imp.h"
|
||||
#include <jtag/jtag.h>
|
||||
#include <helper/time_support.h>
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* DEFINES
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#define SECTOR_ERASE_TIMEOUT_MS (35 * 1000)
|
||||
|
||||
#define XCF_PAGE_SIZE 32
|
||||
#define XCF_DATA_SECTOR_SIZE (1024 * 1024)
|
||||
|
||||
#define ID_XCF01S 0x05044093
|
||||
#define ID_XCF02S 0x05045093
|
||||
#define ID_XCF04S 0x05046093
|
||||
#define ID_XCF08P 0x05057093
|
||||
#define ID_XCF16P 0x05058093
|
||||
#define ID_XCF32P 0x05059093
|
||||
#define ID_MEANINGFUL_MASK 0x0FFFFFFF
|
||||
|
||||
const char *xcf_name_list[] = {
|
||||
"XCF08P",
|
||||
"XCF16P",
|
||||
"XCF32P",
|
||||
"unknown"
|
||||
};
|
||||
|
||||
struct xcf_priv {
|
||||
bool probed;
|
||||
};
|
||||
|
||||
struct xcf_status {
|
||||
bool isc_error; /* false == OK, true == error */
|
||||
bool prog_error; /* false == OK, true == error */
|
||||
bool prog_busy; /* false == idle, true == busy */
|
||||
bool isc_mode; /* false == normal mode, true == ISC mode */
|
||||
};
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* GLOBAL VARIABLES
|
||||
******************************************************************************
|
||||
*/
|
||||
static const uint8_t CMD_BYPASS[2] = {0xFF, 0xFF};
|
||||
|
||||
static const uint8_t CMD_ISC_ADDRESS_SHIFT[2] = {0xEB, 0x00};
|
||||
static const uint8_t CMD_ISC_DATA_SHIFT[2] = {0xED, 0x00};
|
||||
static const uint8_t CMD_ISC_DISABLE[2] = {0xF0, 0x00};
|
||||
static const uint8_t CMD_ISC_ENABLE[2] = {0xE8, 0x00};
|
||||
static const uint8_t CMD_ISC_ERASE[2] = {0xEC, 0x00};
|
||||
static const uint8_t CMD_ISC_PROGRAM[2] = {0xEA, 0x00};
|
||||
|
||||
static const uint8_t CMD_XSC_BLANK_CHECK[2] = {0x0D, 0x00};
|
||||
static const uint8_t CMD_XSC_CONFIG[2] = {0xEE, 0x00};
|
||||
static const uint8_t CMD_XSC_DATA_BTC[2] = {0xF2, 0x00};
|
||||
static const uint8_t CMD_XSC_DATA_CCB[2] = {0x0C, 0x00};
|
||||
static const uint8_t CMD_XSC_DATA_DONE[2] = {0x09, 0x00};
|
||||
static const uint8_t CMD_XSC_DATA_SUCR[2] = {0x0E, 0x00};
|
||||
static const uint8_t CMD_XSC_DATA_WRPT[2] = {0xF7, 0x00};
|
||||
static const uint8_t CMD_XSC_OP_STATUS[2] = {0xE3, 0x00};
|
||||
static const uint8_t CMD_XSC_READ[2] = {0xEF, 0x00};
|
||||
static const uint8_t CMD_XSC_UNLOCK[2] = {0x55, 0xAA};
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* LOCAL FUNCTIONS
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
static const char *product_name(const struct flash_bank *bank)
|
||||
{
|
||||
|
||||
switch (bank->target->tap->idcode & ID_MEANINGFUL_MASK) {
|
||||
case ID_XCF08P:
|
||||
return xcf_name_list[0];
|
||||
case ID_XCF16P:
|
||||
return xcf_name_list[1];
|
||||
case ID_XCF32P:
|
||||
return xcf_name_list[2];
|
||||
default:
|
||||
return xcf_name_list[3];
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_sector_table(struct flash_bank *bank)
|
||||
{
|
||||
/* Note: is_erased and is_protected fields must be set here to an unknown
|
||||
* state, they will be correctly filled from other API calls. */
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = -1;
|
||||
}
|
||||
for (i = 0; i < bank->num_sectors; i++) {
|
||||
bank->sectors[i].size = XCF_DATA_SECTOR_SIZE;
|
||||
bank->sectors[i].offset = i * XCF_DATA_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
bank->size = bank->num_sectors * XCF_DATA_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
static struct xcf_status read_status(struct flash_bank *bank)
|
||||
{
|
||||
struct xcf_status ret;
|
||||
uint8_t irdata[2];
|
||||
struct scan_field scan;
|
||||
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = CMD_BYPASS;
|
||||
scan.in_value = irdata;
|
||||
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
|
||||
ret.isc_error = ((irdata[0] >> 7) & 3) == 0b01;
|
||||
ret.prog_error = ((irdata[0] >> 5) & 3) == 0b01;
|
||||
ret.prog_busy = ((irdata[0] >> 4) & 1) == 0;
|
||||
ret.isc_mode = ((irdata[0] >> 3) & 1) == 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isc_enter(struct flash_bank *bank)
|
||||
{
|
||||
|
||||
struct xcf_status status = read_status(bank);
|
||||
|
||||
if (true == status.isc_mode)
|
||||
return ERROR_OK;
|
||||
else {
|
||||
struct scan_field scan;
|
||||
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = CMD_ISC_ENABLE;
|
||||
scan.in_value = NULL;
|
||||
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
|
||||
status = read_status(bank);
|
||||
if (false == status.isc_mode) {
|
||||
LOG_ERROR("*** XCF: FAILED to enter ISC mode");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static int isc_leave(struct flash_bank *bank)
|
||||
{
|
||||
|
||||
struct xcf_status status = read_status(bank);
|
||||
|
||||
if (false == status.isc_mode)
|
||||
return ERROR_OK;
|
||||
else {
|
||||
struct scan_field scan;
|
||||
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = CMD_ISC_DISABLE;
|
||||
scan.in_value = NULL;
|
||||
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
alive_sleep(1); /* device needs 50 uS to leave ISC mode */
|
||||
|
||||
status = read_status(bank);
|
||||
if (true == status.isc_mode) {
|
||||
LOG_ERROR("*** XCF: FAILED to leave ISC mode");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static int sector_state(uint8_t wrpt, int sector)
|
||||
{
|
||||
if (((wrpt >> sector) & 1) == 1)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t fill_select_block(int first, int last)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
for (int i = first; i <= last; i++)
|
||||
ret |= 1 << i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isc_read_register(struct flash_bank *bank, const uint8_t *cmd,
|
||||
uint8_t *data_buf, int num_bits)
|
||||
{
|
||||
struct scan_field scan;
|
||||
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.out_value = cmd;
|
||||
scan.in_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT);
|
||||
|
||||
scan.out_value = NULL;
|
||||
scan.in_value = data_buf;
|
||||
scan.num_bits = num_bits;
|
||||
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
|
||||
|
||||
return jtag_execute_queue();
|
||||
}
|
||||
|
||||
static int isc_wait_erase_program(struct flash_bank *bank, int64_t timeout_ms)
|
||||
{
|
||||
|
||||
uint8_t isc_default;
|
||||
int64_t t0 = timeval_ms();
|
||||
int64_t dt;
|
||||
|
||||
do {
|
||||
isc_read_register(bank, CMD_XSC_OP_STATUS, &isc_default, 8);
|
||||
if (((isc_default >> 2) & 1) == 1)
|
||||
return ERROR_OK;
|
||||
dt = timeval_ms() - t0;
|
||||
} while (dt <= timeout_ms);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function for procedures without program jtag command at the end
|
||||
*/
|
||||
static int isc_set_register(struct flash_bank *bank, const uint8_t *cmd,
|
||||
const uint8_t *data_buf, int num_bits, int64_t timeout_ms)
|
||||
{
|
||||
struct scan_field scan;
|
||||
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = cmd;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT);
|
||||
|
||||
scan.num_bits = num_bits;
|
||||
scan.out_value = data_buf;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
|
||||
|
||||
if (0 == timeout_ms)
|
||||
return jtag_execute_queue();
|
||||
else
|
||||
return isc_wait_erase_program(bank, timeout_ms);
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function for procedures required program jtag command at the end
|
||||
*/
|
||||
static int isc_program_register(struct flash_bank *bank, const uint8_t *cmd,
|
||||
const uint8_t *data_buf, int num_bits, int64_t timeout_ms)
|
||||
{
|
||||
struct scan_field scan;
|
||||
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = cmd;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_DRSHIFT);
|
||||
|
||||
scan.num_bits = num_bits;
|
||||
scan.out_value = data_buf;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IRSHIFT);
|
||||
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = CMD_ISC_PROGRAM;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
|
||||
|
||||
if (0 == timeout_ms)
|
||||
return jtag_execute_queue();
|
||||
else
|
||||
return isc_wait_erase_program(bank, timeout_ms);
|
||||
}
|
||||
|
||||
static int isc_clear_protect(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
uint8_t select_block[3] = {0x0, 0x0, 0x0};
|
||||
select_block[0] = fill_select_block(first, last);
|
||||
return isc_set_register(bank, CMD_XSC_UNLOCK, select_block, 24, 0);
|
||||
}
|
||||
|
||||
static int isc_set_protect(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
uint8_t wrpt[2] = {0xFF, 0xFF};
|
||||
for (int i = first; i <= last; i++)
|
||||
wrpt[0] &= ~(1 << i);
|
||||
|
||||
return isc_program_register(bank, CMD_XSC_DATA_WRPT, wrpt, 16, 0);
|
||||
}
|
||||
|
||||
static int isc_erase_sectors(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
uint8_t select_block[3] = {0, 0, 0};
|
||||
select_block[0] = fill_select_block(first, last);
|
||||
int64_t timeout = SECTOR_ERASE_TIMEOUT_MS * (last - first + 1);
|
||||
return isc_set_register(bank, CMD_ISC_ERASE, select_block, 24, timeout);
|
||||
}
|
||||
|
||||
static int isc_adr_shift(struct flash_bank *bank, int adr)
|
||||
{
|
||||
uint8_t adr_buf[3];
|
||||
h_u24_to_le(adr_buf, adr);
|
||||
return isc_set_register(bank, CMD_ISC_ADDRESS_SHIFT, adr_buf, 24, 0);
|
||||
}
|
||||
|
||||
static int isc_program_data_page(struct flash_bank *bank, const uint8_t *page_buf)
|
||||
{
|
||||
return isc_program_register(bank, CMD_ISC_DATA_SHIFT, page_buf, 8 * XCF_PAGE_SIZE, 100);
|
||||
}
|
||||
|
||||
static void isc_data_read_out(struct flash_bank *bank, uint8_t *buffer, uint32_t count)
|
||||
{
|
||||
|
||||
struct scan_field scan;
|
||||
|
||||
/* Do not change this code with isc_read_register() call because it needs
|
||||
* transition to IDLE state before data retrieving. */
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = CMD_XSC_READ;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
|
||||
|
||||
scan.num_bits = 8 * count;
|
||||
scan.out_value = NULL;
|
||||
scan.in_value = buffer;
|
||||
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
|
||||
|
||||
jtag_execute_queue();
|
||||
}
|
||||
|
||||
static int isc_set_data_done(struct flash_bank *bank, int sector)
|
||||
{
|
||||
uint8_t done = 0xFF;
|
||||
done &= ~(1 << sector);
|
||||
return isc_program_register(bank, CMD_XSC_DATA_DONE, &done, 8, 100);
|
||||
}
|
||||
|
||||
static void flip_u8(uint8_t *out, const uint8_t *in, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
out[i] = flip_u32(in[i], 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* Xilinx bin file contains simple fixed header for automatic bus width detection:
|
||||
* 16 bytes of 0xFF
|
||||
* 4 byte sync word 0xAA995566 or (bit reversed) 0x5599AA66 in MSC file
|
||||
*
|
||||
* Function presumes need of bit reversing if it can not exactly detects
|
||||
* the opposite.
|
||||
*/
|
||||
bool need_bit_reverse(const uint8_t *buffer)
|
||||
{
|
||||
const size_t L = 20;
|
||||
uint8_t reference[L];
|
||||
memset(reference, 0xFF, 16);
|
||||
reference[16] = 0x55;
|
||||
reference[17] = 0x99;
|
||||
reference[18] = 0xAA;
|
||||
reference[19] = 0x66;
|
||||
|
||||
if (0 == memcmp(reference, buffer, L))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The page address to be programmed is determined by loading the
|
||||
* internal ADDRESS Register using an ISC_ADDRESS_SHIFT instruction sequence.
|
||||
* The page address automatically increments to the next 256-bit
|
||||
* page address after each programming sequence until the last address
|
||||
* in the 8 Mb block is reached. To continue programming the next block,
|
||||
* the next 8 Mb block's starting address must be loaded into the
|
||||
* internal ADDRESS register.
|
||||
*/
|
||||
static int read_write_data(struct flash_bank *bank, const uint8_t *w_buffer,
|
||||
uint8_t *r_buffer, bool write_flag, uint32_t offset, uint32_t count)
|
||||
{
|
||||
int dbg_count = count;
|
||||
int dbg_written = 0;
|
||||
int ret = ERROR_OK;
|
||||
uint8_t *page_buf = malloc(XCF_PAGE_SIZE);
|
||||
bool revbit = true;
|
||||
isc_enter(bank);
|
||||
|
||||
if (offset % XCF_PAGE_SIZE != 0) {
|
||||
ret = ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
if ((offset + count) > (uint32_t)(bank->num_sectors * XCF_DATA_SECTOR_SIZE)) {
|
||||
ret = ERROR_FLASH_DST_OUT_OF_BANK;
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
if ((write_flag) && (0 == offset) && (count >= XCF_PAGE_SIZE))
|
||||
revbit = need_bit_reverse(w_buffer);
|
||||
|
||||
while (count > 0) {
|
||||
uint32_t sector_num = offset / XCF_DATA_SECTOR_SIZE;
|
||||
uint32_t sector_offset = offset - sector_num * XCF_DATA_SECTOR_SIZE;
|
||||
uint32_t sector_bytes = XCF_DATA_SECTOR_SIZE - sector_offset;
|
||||
if (count < sector_bytes)
|
||||
sector_bytes = count;
|
||||
isc_adr_shift(bank, offset);
|
||||
offset += sector_bytes;
|
||||
count -= sector_bytes;
|
||||
|
||||
if (write_flag) {
|
||||
while (sector_bytes > 0) {
|
||||
int len;
|
||||
|
||||
if (sector_bytes < XCF_PAGE_SIZE) {
|
||||
len = sector_bytes;
|
||||
memset(page_buf, 0xFF, XCF_PAGE_SIZE);
|
||||
} else
|
||||
len = XCF_PAGE_SIZE;
|
||||
|
||||
if (revbit)
|
||||
flip_u8(page_buf, w_buffer, len);
|
||||
else
|
||||
memcpy(page_buf, w_buffer, len);
|
||||
|
||||
w_buffer += len;
|
||||
sector_bytes -= len;
|
||||
ret = isc_program_data_page(bank, page_buf);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
else {
|
||||
LOG_DEBUG("written %d bytes from %d", dbg_written, dbg_count);
|
||||
dbg_written += len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isc_data_read_out(bank, r_buffer, sector_bytes);
|
||||
flip_u8(r_buffer, r_buffer, sector_bytes);
|
||||
r_buffer += sector_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set 'done' flags for all data sectors because driver supports
|
||||
* only single revision. */
|
||||
if (write_flag) {
|
||||
for (int i = 0; i < bank->num_sectors; i++) {
|
||||
ret = isc_set_data_done(bank, i);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
EXIT:
|
||||
free(page_buf);
|
||||
isc_leave(bank);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint16_t isc_read_ccb(struct flash_bank *bank)
|
||||
{
|
||||
uint8_t ccb[2];
|
||||
isc_read_register(bank, CMD_XSC_DATA_CCB, ccb, 16);
|
||||
return le_to_h_u16(ccb);
|
||||
}
|
||||
|
||||
static int gucr_num(const struct flash_bank *bank)
|
||||
{
|
||||
return bank->num_sectors;
|
||||
}
|
||||
|
||||
static int sucr_num(const struct flash_bank *bank)
|
||||
{
|
||||
return bank->num_sectors + 1;
|
||||
}
|
||||
|
||||
static int isc_program_ccb(struct flash_bank *bank, uint16_t ccb)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
h_u16_to_le(buf, ccb);
|
||||
return isc_program_register(bank, CMD_XSC_DATA_CCB, buf, 16, 100);
|
||||
}
|
||||
|
||||
static int isc_program_singe_revision_sucr(struct flash_bank *bank)
|
||||
{
|
||||
uint8_t sucr[2] = {0xFC, 0xFF};
|
||||
return isc_program_register(bank, CMD_XSC_DATA_SUCR, sucr, 16, 100);
|
||||
}
|
||||
|
||||
static int isc_program_single_revision_btc(struct flash_bank *bank)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
uint32_t btc = 0xFFFFFFFF;
|
||||
btc &= ~0b1111;
|
||||
btc |= ((bank->num_sectors - 1) << 2);
|
||||
btc &= ~(1 << 4);
|
||||
h_u32_to_le(buf, btc);
|
||||
return isc_program_register(bank, CMD_XSC_DATA_BTC, buf, 32, 100);
|
||||
}
|
||||
|
||||
static int fpga_configure(struct flash_bank *bank)
|
||||
{
|
||||
struct scan_field scan;
|
||||
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = CMD_XSC_CONFIG;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* EXPORTED FUNCTIONS
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
FLASH_BANK_COMMAND_HANDLER(xcf_flash_bank_command)
|
||||
{
|
||||
struct xcf_priv *priv;
|
||||
|
||||
priv = malloc(sizeof(struct xcf_priv));
|
||||
if (priv == NULL) {
|
||||
LOG_ERROR("no memory for flash bank info");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
bank->driver_priv = priv;
|
||||
priv->probed = false;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int xcf_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
const struct xcf_priv *priv = bank->driver_priv;
|
||||
|
||||
if (false == priv->probed) {
|
||||
snprintf(buf, buf_size, "\nXCF flash bank not probed yet\n");
|
||||
return ERROR_OK;
|
||||
}
|
||||
snprintf(buf, buf_size, "%s", product_name(bank));
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int xcf_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct xcf_priv *priv = bank->driver_priv;
|
||||
uint32_t id;
|
||||
|
||||
if (true == priv->probed)
|
||||
free(bank->sectors);
|
||||
priv->probed = false;
|
||||
|
||||
if (bank->target->tap == NULL) {
|
||||
LOG_ERROR("Target has no JTAG tap");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* check idcode and alloc memory for sector table */
|
||||
if (!bank->target->tap->hasidcode)
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
|
||||
/* guess number of blocks using chip ID */
|
||||
id = bank->target->tap->idcode;
|
||||
switch (id & ID_MEANINGFUL_MASK) {
|
||||
case ID_XCF08P:
|
||||
bank->num_sectors = 1;
|
||||
break;
|
||||
case ID_XCF16P:
|
||||
bank->num_sectors = 2;
|
||||
break;
|
||||
case ID_XCF32P:
|
||||
bank->num_sectors = 4;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Unknown flash device ID 0x%X", id);
|
||||
return ERROR_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector));
|
||||
if (NULL == bank->sectors) {
|
||||
LOG_ERROR("No memory for sector table");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
fill_sector_table(bank);
|
||||
|
||||
priv->probed = true;
|
||||
bank->driver_priv = priv;
|
||||
|
||||
LOG_INFO("product name: %s", product_name(bank));
|
||||
LOG_INFO("device id = 0x%X ", bank->target->tap->idcode);
|
||||
LOG_INFO("flash size = %d configuration bits",
|
||||
bank->num_sectors * XCF_DATA_SECTOR_SIZE * 8);
|
||||
LOG_INFO("number of sectors = %d", bank->num_sectors);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int xcf_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct xcf_priv *priv = bank->driver_priv;
|
||||
|
||||
if (true == priv->probed)
|
||||
return ERROR_OK;
|
||||
else
|
||||
return xcf_probe(bank);
|
||||
}
|
||||
|
||||
static int xcf_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
uint8_t wrpt[2];
|
||||
|
||||
isc_enter(bank);
|
||||
isc_read_register(bank, CMD_XSC_DATA_WRPT, wrpt, 16);
|
||||
isc_leave(bank);
|
||||
|
||||
for (int i = 0; i < bank->num_sectors; i++)
|
||||
bank->sectors[i].is_protected = sector_state(wrpt[0], i);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int xcf_erase_check(struct flash_bank *bank)
|
||||
{
|
||||
uint8_t blankreg;
|
||||
struct scan_field scan;
|
||||
|
||||
isc_enter(bank);
|
||||
|
||||
/* Do not change this code with isc_read_register() call because it needs
|
||||
* transition to IDLE state and pause before data retrieving. */
|
||||
scan.check_mask = NULL;
|
||||
scan.check_value = NULL;
|
||||
scan.num_bits = 16;
|
||||
scan.out_value = CMD_XSC_BLANK_CHECK;
|
||||
scan.in_value = NULL;
|
||||
jtag_add_ir_scan(bank->target->tap, &scan, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
alive_sleep(500); /* device needs at least 0.5s to self check */
|
||||
|
||||
scan.num_bits = 8;
|
||||
scan.in_value = &blankreg;
|
||||
jtag_add_dr_scan(bank->target->tap, 1, &scan, TAP_IDLE);
|
||||
jtag_execute_queue();
|
||||
|
||||
isc_leave(bank);
|
||||
|
||||
for (int i = 0; i < bank->num_sectors; i++)
|
||||
bank->sectors[i].is_erased = sector_state(blankreg, i);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int xcf_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
if ((first >= bank->num_sectors)
|
||||
|| (last >= bank->num_sectors)
|
||||
|| (last < first))
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
else {
|
||||
isc_enter(bank);
|
||||
isc_clear_protect(bank, first, last);
|
||||
int ret = isc_erase_sectors(bank, first, last);
|
||||
isc_leave(bank);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static int xcf_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
return read_write_data(bank, NULL, buffer, false, offset, count);
|
||||
}
|
||||
|
||||
static int xcf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
return read_write_data(bank, buffer, NULL, true, offset, count);
|
||||
}
|
||||
|
||||
static int xcf_protect(struct flash_bank *bank, int set, int first, int last)
|
||||
{
|
||||
int ret;
|
||||
|
||||
isc_enter(bank);
|
||||
if (set)
|
||||
ret = isc_set_protect(bank, first, last);
|
||||
else {
|
||||
/* write protection may be removed only with following erase */
|
||||
isc_clear_protect(bank, first, last);
|
||||
ret = isc_erase_sectors(bank, first, last);
|
||||
}
|
||||
isc_leave(bank);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(xcf_handle_ccb_command) {
|
||||
|
||||
if (!((CMD_ARGC == 1) || (CMD_ARGC == 5)))
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
uint16_t ccb = 0xFFFF;
|
||||
isc_enter(bank);
|
||||
uint16_t old_ccb = isc_read_ccb(bank);
|
||||
isc_leave(bank);
|
||||
|
||||
if (CMD_ARGC == 1) {
|
||||
LOG_INFO("current CCB = 0x%X", old_ccb);
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
/* skip over flash bank */
|
||||
CMD_ARGC--;
|
||||
CMD_ARGV++;
|
||||
while (CMD_ARGC) {
|
||||
if (strcmp("external", CMD_ARGV[0]) == 0)
|
||||
ccb |= (1 << 0);
|
||||
else if (strcmp("internal", CMD_ARGV[0]) == 0)
|
||||
ccb &= ~(1 << 0);
|
||||
else if (strcmp("serial", CMD_ARGV[0]) == 0)
|
||||
ccb |= (3 << 1);
|
||||
else if (strcmp("parallel", CMD_ARGV[0]) == 0)
|
||||
ccb &= ~(3 << 1);
|
||||
else if (strcmp("slave", CMD_ARGV[0]) == 0)
|
||||
ccb |= (1 << 3);
|
||||
else if (strcmp("master", CMD_ARGV[0]) == 0)
|
||||
ccb &= ~(1 << 3);
|
||||
else if (strcmp("40", CMD_ARGV[0]) == 0)
|
||||
ccb |= (3 << 4);
|
||||
else if (strcmp("20", CMD_ARGV[0]) == 0)
|
||||
ccb &= ~(1 << 5);
|
||||
else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
CMD_ARGC--;
|
||||
CMD_ARGV++;
|
||||
}
|
||||
|
||||
isc_enter(bank);
|
||||
int sector;
|
||||
|
||||
/* GUCR sector */
|
||||
sector = gucr_num(bank);
|
||||
isc_clear_protect(bank, sector, sector);
|
||||
int ret = isc_erase_sectors(bank, sector, sector);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
ret = isc_program_ccb(bank, ccb);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
ret = isc_program_single_revision_btc(bank);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
ret = isc_set_data_done(bank, sector);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
|
||||
/* SUCR sector */
|
||||
sector = sucr_num(bank);
|
||||
isc_clear_protect(bank, sector, sector);
|
||||
ret = isc_erase_sectors(bank, sector, sector);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
ret = isc_program_singe_revision_sucr(bank);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
ret = isc_set_data_done(bank, sector);
|
||||
if (ERROR_OK != ret)
|
||||
goto EXIT;
|
||||
|
||||
EXIT:
|
||||
isc_leave(bank);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(xcf_handle_configure_command) {
|
||||
|
||||
if (CMD_ARGC != 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
struct flash_bank *bank;
|
||||
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
return fpga_configure(bank);
|
||||
}
|
||||
|
||||
static const struct command_registration xcf_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "configure",
|
||||
.handler = xcf_handle_configure_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id",
|
||||
.help = "Initiate FPGA loading procedure."
|
||||
},
|
||||
{
|
||||
.name = "ccb",
|
||||
.handler = xcf_handle_ccb_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id [('external'|'internal') "
|
||||
"('serial'|'parallel') "
|
||||
"('slave'|'master') "
|
||||
"('40'|'20')]",
|
||||
.help = "Write CCB register with supplied options and (silently) BTC "
|
||||
"register with single revision options. Display current "
|
||||
"CCB value when only bank_id supplied. "
|
||||
"Following options available: "
|
||||
"1) external or internal clock source; "
|
||||
"2) serial or parallel bus mode; "
|
||||
"3) slave or master mode; "
|
||||
"4) clock frequency in MHz for internal clock in master mode;"
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration xcf_command_handlers[] = {
|
||||
{
|
||||
.name = "xcf",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "Xilinx platform flash command group",
|
||||
.usage = "",
|
||||
.chain = xcf_exec_command_handlers
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
struct flash_driver xcf_flash = {
|
||||
.name = "xcf",
|
||||
.usage = NULL,
|
||||
.commands = xcf_command_handlers,
|
||||
.flash_bank_command = xcf_flash_bank_command,
|
||||
.erase = xcf_erase,
|
||||
.protect = xcf_protect,
|
||||
.write = xcf_write,
|
||||
.read = xcf_read,
|
||||
.probe = xcf_probe,
|
||||
.auto_probe = xcf_auto_probe,
|
||||
.erase_check = xcf_erase_check,
|
||||
.protect_check = xcf_protect_check,
|
||||
.info = xcf_info
|
||||
};
|
||||
@@ -42,6 +42,7 @@ proc program {filename args} {
|
||||
|
||||
# start programming phase
|
||||
echo "** Programming Started **"
|
||||
set filename \{$filename\}
|
||||
if {[info exists address]} {
|
||||
set flash_args "$filename $address"
|
||||
} else {
|
||||
@@ -62,8 +63,10 @@ proc program {filename args} {
|
||||
|
||||
if {[info exists reset]} {
|
||||
# reset target if requested
|
||||
# also disable target polling, we are shutting down anyway
|
||||
poll off
|
||||
if {$exit == 1} {
|
||||
# also disable target polling, we are shutting down anyway
|
||||
poll off
|
||||
}
|
||||
echo "** Resetting Target **"
|
||||
reset run
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user