jtagdev, pif, mehfet: refactor device_class ops to be unified under jtagdev instead of using separate implementations
This commit is contained in:
parent
0a8ebf4a66
commit
ddfffa06fb
|
@ -35,10 +35,14 @@
|
|||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jtaglib.h"
|
||||
#include "output.h"
|
||||
#include "jtaglib_defs.h"
|
||||
|
||||
#include "output.h"
|
||||
#include "ctrlc.h"
|
||||
#include "device.h"
|
||||
|
||||
/* Reset target JTAG interface and perform fuse-HW check */
|
||||
static void jtag_default_reset_tap(struct jtdev *p)
|
||||
{
|
||||
|
@ -525,7 +529,7 @@ int jtag_is_fuse_blown (struct jtdev *p)
|
|||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int jtag_refresh_bps(const char *module, device_t dev, struct jtdev *p)
|
||||
int jtag_refresh_bps(device_t dev, struct jtdev *p)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
|
@ -536,9 +540,8 @@ int jtag_refresh_bps(const char *module, device_t dev, struct jtdev *p)
|
|||
for (i = 0; i < dev->max_breakpoints; i++) {
|
||||
bp = &dev->breakpoints[i];
|
||||
|
||||
printc_dbg("%s: refresh breakpoint %d: type=%d "
|
||||
"addr=%04x flags=%04x\n", module,
|
||||
i, bp->type, bp->addr, bp->flags);
|
||||
printc_dbg("jtaglib: refresh breakpoint %d: type=%d "
|
||||
"addr=%04x flags=%04x\n", i, bp->type, bp->addr, bp->flags);
|
||||
|
||||
if ( (bp->flags & DEVICE_BP_DIRTY) &&
|
||||
(bp->type == DEVICE_BPTYPE_BREAK) ) {
|
||||
|
@ -549,8 +552,7 @@ int jtag_refresh_bps(const char *module, device_t dev, struct jtdev *p)
|
|||
}
|
||||
|
||||
if ( jtag_set_breakpoint (p, i, addr) == 0) {
|
||||
printc_err("%s: failed to refresh "
|
||||
"breakpoint #%d\n", module, i);
|
||||
printc_err("jtaglib: failed to refresh breakpoint #%d\n", i);
|
||||
ret = -1;
|
||||
} else {
|
||||
bp->flags &= ~DEVICE_BP_DIRTY;
|
||||
|
@ -561,3 +563,184 @@ int jtag_refresh_bps(const char *module, device_t dev, struct jtdev *p)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
static int write_ram_word(struct jtdev *p, address_t addr, uint16_t value)
|
||||
{
|
||||
jtag_write_mem(p, 16, addr, value);
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
static int write_flash_block(struct jtdev *p, address_t addr,
|
||||
address_t len, const uint8_t *data)
|
||||
{
|
||||
uint16_t* word = malloc( len / 2 * sizeof(*word) );
|
||||
if (!word) {
|
||||
pr_error("jtaglib: failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < len/2; i++) {
|
||||
word[i] = data[2*i] + (((uint16_t)data[2*i+1]) << 8);
|
||||
}
|
||||
jtag_write_flash(p, addr, len/2, word);
|
||||
|
||||
free(word);
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int read_words(device_t dev_base, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, uint8_t *data) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
|
||||
for (unsigned int index = 0; index < len; index += 2) {
|
||||
unsigned int word = jtag_read_mem(p, 16, addr+index);
|
||||
data[index ] = word & 0x00ff;
|
||||
data[index+1] = (word >> 8) & 0x00ff;
|
||||
}
|
||||
|
||||
return p->failed ? -1 : len;
|
||||
}
|
||||
static int write_words(device_t dev_base, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, const uint8_t *data) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
int r;
|
||||
|
||||
if (m->type != CHIPINFO_MEMTYPE_FLASH) {
|
||||
len = 2;
|
||||
r = write_ram_word(p, addr, r16le(data));
|
||||
} else {
|
||||
r = write_flash_block(p, addr, len, data);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
printc_err("jtaglib: write_words at address 0x%x failed\n", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;}
|
||||
|
||||
int jtag_dev_readmem(device_t dev_base, address_t addr, uint8_t *mem, address_t len) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
p->failed = 0;
|
||||
return readmem(dev_base, addr, mem, len, read_words);
|
||||
}
|
||||
int jtag_dev_writemem(device_t dev_base, address_t addr, const uint8_t *mem, address_t len) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
p->failed = 0;
|
||||
return writemem(dev_base, addr, mem, len, write_words, read_words);
|
||||
}
|
||||
int jtag_dev_erase(device_t dev_base, device_erase_type_t type, address_t addr) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
|
||||
p->failed = 0;
|
||||
|
||||
switch (type) {
|
||||
case DEVICE_ERASE_MAIN:
|
||||
jtag_erase_flash(p, JTAG_ERASE_MAIN, addr);
|
||||
break;
|
||||
case DEVICE_ERASE_ALL:
|
||||
jtag_erase_flash(p, JTAG_ERASE_MASS, addr);
|
||||
break;
|
||||
case DEVICE_ERASE_SEGMENT:
|
||||
jtag_erase_flash(p, JTAG_ERASE_SGMT, addr);
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
int jtag_dev_getregs(device_t dev_base, address_t *regs) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
|
||||
p->failed = 0;
|
||||
|
||||
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||
regs[i] = jtag_read_reg(p, i);
|
||||
}
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
int jtag_dev_setregs(device_t dev_base, const address_t *regs) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
|
||||
p->failed = 0;
|
||||
|
||||
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||
jtag_write_reg(p, i, regs[i]);
|
||||
}
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
int jtag_dev_ctl(device_t dev_base, device_ctl_t type) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
|
||||
p->failed = 0;
|
||||
|
||||
switch (type) {
|
||||
case DEVICE_CTL_RESET:
|
||||
/* perform soft reset */
|
||||
jtag_execute_puc(p);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_RUN:
|
||||
/* transfer changed breakpoints to device */
|
||||
if (jtag_refresh_bps(&p->base, p) < 0)
|
||||
return -1;
|
||||
|
||||
/* start program execution at current PC */
|
||||
jtag_release_device(p, 0xffff);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_HALT:
|
||||
/* take device under JTAG control */
|
||||
jtag_get_device(p);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_STEP:
|
||||
/* execute next instruction at current PC */
|
||||
jtag_single_step(p);
|
||||
break;
|
||||
|
||||
default:
|
||||
printc_err("mehfet: unsupported operation %d\n", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
device_status_t jtag_dev_poll(device_t dev_base) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
|
||||
if (delay_ms(100) < 0 || ctrlc_check())
|
||||
return DEVICE_STATUS_INTR;
|
||||
|
||||
int r = jtag_cpu_state(p);
|
||||
|
||||
if (r == 1) return DEVICE_STATUS_HALTED;
|
||||
|
||||
return DEVICE_STATUS_RUNNING;
|
||||
}
|
||||
int jtag_dev_getconfigfuses(device_t dev_base) {
|
||||
struct jtdev *p = (struct jtdev*)dev_base;
|
||||
|
||||
return jtag_get_config_fuses(p);
|
||||
}
|
||||
|
||||
int jtag_dev_init(struct jtdev *p) {
|
||||
unsigned int jtagid = jtag_init(p);
|
||||
if (p->failed) return -1;
|
||||
|
||||
printc("JTAG ID: 0x%02x\n", jtagid);
|
||||
// TODO: validate JTAG ID in a better way!
|
||||
if (jtagid != 0x89 && jtagid != 0x91) {
|
||||
printc_err("mehfet: unexpected JTAG ID: 0x%02x\n", jtagid);
|
||||
jtag_release_device(p, 0xfffe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,11 +40,6 @@
|
|||
#include "jtdev.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Flash erasing modes */
|
||||
#define JTAG_ERASE_MASS 0xA506
|
||||
#define JTAG_ERASE_MAIN 0xA504
|
||||
#define JTAG_ERASE_SGMT 0xA502
|
||||
|
||||
/* Colleciton of functions that need different implementation for different
|
||||
* CPU types (that is, 16-bit vs CPUX vs Xv2) */
|
||||
struct jtaglib_funcs {
|
||||
|
@ -167,6 +162,16 @@ uint32_t jtag_default_dr_shift_20(struct jtdev *p, uint32_t dr);
|
|||
void jtag_default_tms_sequence(struct jtdev *p, int bits, unsigned int value);
|
||||
void jtag_default_init_dap(struct jtdev *p);
|
||||
|
||||
int jtag_refresh_bps(const char *driver, device_t dev, struct jtdev *p);
|
||||
int jtag_refresh_bps(device_t dev, struct jtdev *p);
|
||||
|
||||
int jtag_dev_readmem(device_t dev_base, address_t addr, uint8_t *mem, address_t len);
|
||||
int jtag_dev_writemem(device_t dev_base, address_t addr, const uint8_t *mem, address_t len);
|
||||
int jtag_dev_getregs(device_t dev_base, address_t *regs);
|
||||
int jtag_dev_setregs(device_t dev_base, const address_t *regs);
|
||||
int jtag_dev_ctl(device_t dev_base, device_ctl_t type);
|
||||
device_status_t jtag_dev_poll(device_t dev_base);
|
||||
int jtag_dev_erase(device_t dev_base, device_erase_type_t, address_t addr);
|
||||
int jtag_dev_getconfigfuses(device_t dev_base);
|
||||
int jtag_dev_init(struct jtdev *p);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
#include "jtaglib.h"
|
||||
#include "eem_defs.h"
|
||||
|
||||
/* Flash erasing modes */
|
||||
#define JTAG_ERASE_MASS 0xA506
|
||||
#define JTAG_ERASE_MAIN 0xA504
|
||||
#define JTAG_ERASE_SGMT 0xA502
|
||||
|
||||
/* JTAG identification value for all existing Flash-based MSP430 devices
|
||||
*/
|
||||
#define JTAG_ID_CPU16 0x89
|
||||
|
|
301
drivers/mehfet.c
301
drivers/mehfet.c
|
@ -223,257 +223,6 @@ static const struct jtdev_func jtdev_func_mehfet = {
|
|||
};
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
// TODO: these five are kinda copied from pif.c, should be deduplicated
|
||||
|
||||
static int read_words(device_t dev_base, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, uint8_t *data)
|
||||
{
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: read_words: addr=0x%04x, len=0x%x\n", addr, len);
|
||||
#endif
|
||||
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
struct jtdev *p = &dev->jtag;
|
||||
|
||||
for (unsigned int index = 0; index < len; index += 2) {
|
||||
unsigned int word = jtag_read_mem(p, 16, addr+index);
|
||||
data[index ] = word & 0x00ff;
|
||||
data[index+1] = (word >> 8) & 0x00ff;
|
||||
}
|
||||
|
||||
return p->failed ? -1 : len;
|
||||
}
|
||||
|
||||
static int write_ram_word(struct jtdev *p, address_t addr, uint16_t value)
|
||||
{
|
||||
jtag_write_mem(p, 16, addr, value);
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int write_flash_block(struct jtdev *p, address_t addr,
|
||||
address_t len, const uint8_t *data)
|
||||
{
|
||||
uint16_t* word = malloc( len / 2 * sizeof(*word) );
|
||||
if (!word) {
|
||||
pr_error("mehfet: failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < len/2; i++) {
|
||||
word[i]=data[2*i] + (((uint16_t)data[2*i+1]) << 8);
|
||||
}
|
||||
jtag_write_flash(p, addr, len/2, word);
|
||||
|
||||
free(word);
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Write a word-aligned block to any kind of memory.
|
||||
* returns the number of bytes written or -1 on failure
|
||||
*/
|
||||
static int write_words(device_t dev_base, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, const uint8_t *data)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
struct jtdev *p = &dev->jtag;
|
||||
int r;
|
||||
|
||||
if (m->type != CHIPINFO_MEMTYPE_FLASH) {
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: write_words: addr=0x%04x, len=0x%x data=0x%04x\n",
|
||||
addr, len, r16le(data));
|
||||
if (len != 2) {
|
||||
printc_dbg("mehfet: WARN: write_words: len != 2! but 0x%04x\n", len);
|
||||
__builtin_trap();
|
||||
}
|
||||
#endif
|
||||
len = 2;
|
||||
r = write_ram_word(p, addr, r16le(data));
|
||||
} else {
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: write_flash_block: addr=0x%04x, len=0x%x\n", addr, len);
|
||||
#endif
|
||||
r = write_flash_block(p, addr, len, data);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
printc_err("mehfet: write_words at address 0x%x failed\n", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static int mehfet_readmem(device_t dev_base, address_t addr,
|
||||
uint8_t *mem, address_t len)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
dev->jtag.failed = 0;
|
||||
return readmem(dev_base, addr, mem, len, read_words);
|
||||
}
|
||||
|
||||
static int mehfet_writemem(device_t dev_base, address_t addr,
|
||||
const uint8_t *mem, address_t len)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
dev->jtag.failed = 0;
|
||||
return writemem(dev_base, addr, mem, len, write_words, read_words);
|
||||
}
|
||||
|
||||
static int mehfet_setregs(device_t dev_base, const address_t *regs)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: set regs\n");
|
||||
#endif
|
||||
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: [%d] = 0x%04x\n", i, regs[i]);
|
||||
#endif
|
||||
jtag_write_reg(&dev->jtag, i, regs[i]);
|
||||
}
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int mehfet_getregs(device_t dev_base, address_t *regs)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: get regs\n");
|
||||
#endif
|
||||
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||
regs[i] = jtag_read_reg(&dev->jtag, i);
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: [%d] = 0x%04x\n", i, regs[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int mehfet_ctl(device_t dev_base, device_ctl_t type)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
switch (type) {
|
||||
case DEVICE_CTL_RESET:
|
||||
/* perform soft reset */
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: soft reset (PUC)\n");
|
||||
#endif
|
||||
jtag_execute_puc(&dev->jtag);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_RUN:
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: set breakpoints\n");
|
||||
#endif
|
||||
/* transfer changed breakpoints to device */
|
||||
if (jtag_refresh_bps("mehfet", &dev->jtag.base, &dev->jtag) < 0) return -1;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: run @ current PC\n");
|
||||
#endif
|
||||
/* start program execution at current PC */
|
||||
jtag_release_device(&dev->jtag, 0xffff);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_HALT:
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: halt\n");
|
||||
#endif
|
||||
/* take device under JTAG control */
|
||||
jtag_get_device(&dev->jtag);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_STEP:
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: single-step\n");
|
||||
#endif
|
||||
/* execute next instruction at current PC */
|
||||
jtag_single_step(&dev->jtag);
|
||||
break;
|
||||
|
||||
default:
|
||||
printc_err("mehfet: unsupported operation %d\n", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static device_status_t mehfet_poll(device_t dev_base)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
if (delay_ms(100) < 0 || ctrlc_check())
|
||||
return DEVICE_STATUS_INTR;
|
||||
|
||||
int r = jtag_cpu_state(&dev->jtag);
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: cpu state: %d\n", r);
|
||||
#endif
|
||||
|
||||
if (r == 1) return DEVICE_STATUS_HALTED;
|
||||
|
||||
return DEVICE_STATUS_RUNNING;
|
||||
}
|
||||
|
||||
static int mehfet_erase(device_t dev_base, device_erase_type_t type,
|
||||
address_t addr)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
switch (type) {
|
||||
case DEVICE_ERASE_MAIN:
|
||||
jtag_erase_flash(&dev->jtag, JTAG_ERASE_MAIN, addr);
|
||||
break;
|
||||
case DEVICE_ERASE_ALL:
|
||||
jtag_erase_flash(&dev->jtag, JTAG_ERASE_MASS, addr);
|
||||
break;
|
||||
case DEVICE_ERASE_SEGMENT:
|
||||
jtag_erase_flash(&dev->jtag, JTAG_ERASE_SGMT, addr);
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: erase flash %d at %04x: %s\n", type, addr, dev->jtag.failed ? "failed" : "succeeded");
|
||||
#endif
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int mehfet_getconfigfuses(device_t dev_base)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
int r = jtag_get_config_fuses(&dev->jtag);
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: get_config_fuses: %d\n", r);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static int check_dev_ok(struct mehfet_device* dev, const struct device_args* args,
|
||||
|
@ -529,32 +278,6 @@ static int check_dev_ok(struct mehfet_device* dev, const struct device_args* arg
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int init_device(struct mehfet_device* dev) {
|
||||
printc_dbg("Starting JTAG\n");
|
||||
|
||||
unsigned int jtagid = jtag_init(&dev->jtag);
|
||||
if (dev->jtag.failed) return -1;
|
||||
|
||||
printc("JTAG ID: 0x%02x\n", jtagid);
|
||||
if (jtagid != 0x89 && jtagid != 0x91) {
|
||||
printc_err("mehfet: unexpected JTAG ID: 0x%02x\n", jtagid);
|
||||
jtag_release_device(&dev->jtag, 0xfffe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// JTAG fuse check has been performed, so we can now switch to a
|
||||
// higher-speed physical transport suitable for ~350 kHz TCLK strobes used
|
||||
// in (and required for) flash programming
|
||||
int r = mehfet_cmd_set_clkspeed(dev->trans, true);
|
||||
if (r < 0) {
|
||||
jtag_release_device(&dev->jtag, 0xfffe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void mehfet_destroy(device_t dev_base) {
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
|
@ -619,7 +342,13 @@ static device_t mehfet_open(const struct device_args* args) {
|
|||
goto FAIL;
|
||||
}
|
||||
|
||||
r = init_device(dev);
|
||||
r = jtag_dev_init(&dev->jtag);
|
||||
if (r < 0) goto FAIL;
|
||||
|
||||
// JTAG fuse check has been performed, so we can now switch to a
|
||||
// higher-speed physical transport suitable for ~350 kHz TCLK strobes used
|
||||
// in (and required for) flash programming
|
||||
r = mehfet_cmd_set_clkspeed(dev->trans, true);
|
||||
if (r < 0) goto FAIL;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
|
@ -638,13 +367,13 @@ const struct device_class device_mehfet = {
|
|||
.help = "MehFET USB JTAG/SBW device",
|
||||
.open = mehfet_open,
|
||||
.destroy = mehfet_destroy,
|
||||
.readmem = mehfet_readmem,
|
||||
.writemem = mehfet_writemem,
|
||||
.getregs = mehfet_getregs,
|
||||
.setregs = mehfet_setregs,
|
||||
.ctl = mehfet_ctl,
|
||||
.poll = mehfet_poll,
|
||||
.erase = mehfet_erase,
|
||||
.getconfigfuses = mehfet_getconfigfuses
|
||||
.readmem = jtag_dev_readmem,
|
||||
.writemem = jtag_dev_writemem,
|
||||
.getregs = jtag_dev_getregs,
|
||||
.setregs = jtag_dev_setregs,
|
||||
.ctl = jtag_dev_ctl,
|
||||
.poll = jtag_dev_poll,
|
||||
.erase = jtag_dev_erase,
|
||||
.getconfigfuses = jtag_dev_getconfigfuses
|
||||
};
|
||||
|
||||
|
|
299
drivers/pif.c
299
drivers/pif.c
|
@ -38,252 +38,7 @@ struct pif_device {
|
|||
struct jtdev jtag;
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
/* pif MSP430 JTAG operations */
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Read a word-aligned block from any kind of memory
|
||||
* returns the number of bytes read or -1 on failure
|
||||
*/
|
||||
static int read_words(device_t dev, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, uint8_t *data)
|
||||
{
|
||||
struct pif_device *pif = (struct pif_device *)dev;
|
||||
struct jtdev *p = &pif->jtag;
|
||||
unsigned int index;
|
||||
unsigned int word;
|
||||
|
||||
for ( index = 0; index < len; index += 2 ) {
|
||||
word = jtag_read_mem( p, 16, addr+index );
|
||||
data[index] = word & 0x00ff;
|
||||
data[index+1] = (word >> 8) & 0x00ff;
|
||||
}
|
||||
|
||||
return p->failed ? -1 : len;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Write a word to RAM */
|
||||
static int write_ram_word( struct jtdev *p, address_t addr,
|
||||
uint16_t value )
|
||||
{
|
||||
jtag_write_mem( p, 16, addr, value );
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Write a word-aligned flash block. */
|
||||
/* The starting address must be within the flash memory range. */
|
||||
|
||||
static int write_flash_block( struct jtdev *p, address_t addr,
|
||||
address_t len,
|
||||
const uint8_t *data)
|
||||
{
|
||||
unsigned int i;
|
||||
uint16_t *word;
|
||||
|
||||
word = malloc( len / 2 * sizeof(*word) );
|
||||
if (!word) {
|
||||
pr_error("pif: failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i = 0; i < len/2; i++) {
|
||||
word[i]=data[2*i] + (((uint16_t)data[2*i+1]) << 8);
|
||||
}
|
||||
jtag_write_flash( p, addr, len/2, word );
|
||||
|
||||
free(word);
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Write a word-aligned block to any kind of memory.
|
||||
* returns the number of bytes written or -1 on failure
|
||||
*/
|
||||
static int write_words(device_t dev, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, const uint8_t *data)
|
||||
{
|
||||
struct pif_device *pif = (struct pif_device *)dev;
|
||||
struct jtdev *p = &pif->jtag;
|
||||
int r;
|
||||
|
||||
if (m->type != CHIPINFO_MEMTYPE_FLASH) {
|
||||
len = 2;
|
||||
r = write_ram_word(p, addr, r16le(data));
|
||||
} else {
|
||||
r = write_flash_block(p, addr, len, data);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
printc_err("pif: write_words at address 0x%x failed\n", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int init_device(struct jtdev *p)
|
||||
{
|
||||
unsigned int jtag_id;
|
||||
|
||||
printc_dbg("Starting JTAG\n");
|
||||
jtag_id = jtag_init(p);
|
||||
printc("JTAG ID: 0x%02x\n", jtag_id);
|
||||
if (jtag_id != 0x89 && jtag_id != 0x91) {
|
||||
printc_err("pif: unexpected JTAG ID: 0x%02x\n", jtag_id);
|
||||
jtag_release_device(p, 0xfffe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*===== MSPDebug Device interface ============================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_readmem( device_t dev_base,
|
||||
address_t addr,
|
||||
uint8_t* mem,
|
||||
address_t len )
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
dev->jtag.failed = 0;
|
||||
return readmem(dev_base, addr, mem, len, read_words);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_writemem( device_t dev_base,
|
||||
address_t addr,
|
||||
const uint8_t* mem,
|
||||
address_t len )
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
dev->jtag.failed = 0;
|
||||
return writemem(dev_base, addr, mem, len, write_words, read_words);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_getregs(device_t dev_base, address_t *regs)
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
int i;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
for (i = 0; i < DEVICE_NUM_REGS; i++)
|
||||
regs[i] = jtag_read_reg(&dev->jtag, i);
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_setregs( device_t dev_base, const address_t* regs )
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
int i;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
for (i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||
jtag_write_reg( &dev->jtag, i, regs[i] );
|
||||
}
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_ctl(device_t dev_base, device_ctl_t type)
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
switch (type) {
|
||||
case DEVICE_CTL_RESET:
|
||||
/* perform soft reset */
|
||||
jtag_execute_puc(&dev->jtag);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_RUN:
|
||||
/* transfer changed breakpoints to device */
|
||||
if (jtag_refresh_bps("pif", &dev->jtag.base, &dev->jtag) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* start program execution at current PC */
|
||||
jtag_release_device(&dev->jtag, 0xffff);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_HALT:
|
||||
/* take device under JTAG control */
|
||||
jtag_get_device(&dev->jtag);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_STEP:
|
||||
/* execute next instruction at current PC */
|
||||
jtag_single_step(&dev->jtag);
|
||||
break;
|
||||
|
||||
default:
|
||||
printc_err("pif: unsupported operation\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static device_status_t pif_poll(device_t dev_base)
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
|
||||
if (delay_ms(100) < 0 || ctrlc_check())
|
||||
return DEVICE_STATUS_INTR;
|
||||
|
||||
if (jtag_cpu_state(&dev->jtag) == 1) {
|
||||
return DEVICE_STATUS_HALTED;
|
||||
}
|
||||
|
||||
return DEVICE_STATUS_RUNNING;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_erase( device_t dev_base,
|
||||
device_erase_type_t type,
|
||||
address_t addr )
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
switch(type) {
|
||||
case DEVICE_ERASE_MAIN:
|
||||
jtag_erase_flash ( &dev->jtag, JTAG_ERASE_MAIN, addr );
|
||||
break;
|
||||
case DEVICE_ERASE_ALL:
|
||||
jtag_erase_flash ( &dev->jtag, JTAG_ERASE_MASS, addr );
|
||||
break;
|
||||
case DEVICE_ERASE_SEGMENT:
|
||||
jtag_erase_flash ( &dev->jtag, JTAG_ERASE_SGMT, addr );
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_getconfigfuses(device_t dev_base)
|
||||
{
|
||||
struct pif_device *dev = (struct pif_device *)dev_base;
|
||||
|
||||
return jtag_get_config_fuses(&dev->jtag);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static device_t pif_open(const struct device_args *args)
|
||||
{
|
||||
|
@ -317,7 +72,7 @@ static device_t pif_open(const struct device_args *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (init_device(&dev->jtag) < 0) {
|
||||
if (jtag_dev_init(&dev->jtag) < 0) {
|
||||
printc_err("pif: initialization failed\n");
|
||||
free(dev);
|
||||
return NULL;
|
||||
|
@ -360,7 +115,7 @@ static device_t gpio_open(const struct device_args *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (init_device(&dev->jtag) < 0) {
|
||||
if (jtag_dev_init(&dev->jtag) < 0) {
|
||||
printc_err("gpio: initialization failed\n");
|
||||
free(dev);
|
||||
return NULL;
|
||||
|
@ -404,7 +159,7 @@ static device_t bp_open(const struct device_args *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (init_device(&dev->jtag) < 0) {
|
||||
if (jtag_dev_init(&dev->jtag) < 0) {
|
||||
printc_err("bp: initialization failed\n");
|
||||
free(dev);
|
||||
return NULL;
|
||||
|
@ -431,14 +186,14 @@ const struct device_class device_pif = {
|
|||
.help = "Parallel Port JTAG",
|
||||
.open = pif_open,
|
||||
.destroy = pif_destroy,
|
||||
.readmem = pif_readmem,
|
||||
.writemem = pif_writemem,
|
||||
.getregs = pif_getregs,
|
||||
.setregs = pif_setregs,
|
||||
.ctl = pif_ctl,
|
||||
.poll = pif_poll,
|
||||
.erase = pif_erase,
|
||||
.getconfigfuses = pif_getconfigfuses
|
||||
.readmem = jtag_dev_readmem,
|
||||
.writemem = jtag_dev_writemem,
|
||||
.getregs = jtag_dev_getregs,
|
||||
.setregs = jtag_dev_setregs,
|
||||
.ctl = jtag_dev_ctl,
|
||||
.poll = jtag_dev_poll,
|
||||
.erase = jtag_dev_erase,
|
||||
.getconfigfuses = jtag_dev_getconfigfuses
|
||||
};
|
||||
|
||||
const struct device_class device_gpio = {
|
||||
|
@ -446,14 +201,14 @@ const struct device_class device_gpio = {
|
|||
.help = "/sys/class/gpio direct connect",
|
||||
.open = gpio_open,
|
||||
.destroy = pif_destroy,
|
||||
.readmem = pif_readmem,
|
||||
.writemem = pif_writemem,
|
||||
.getregs = pif_getregs,
|
||||
.setregs = pif_setregs,
|
||||
.ctl = pif_ctl,
|
||||
.poll = pif_poll,
|
||||
.erase = pif_erase,
|
||||
.getconfigfuses = pif_getconfigfuses
|
||||
.readmem = jtag_dev_readmem,
|
||||
.writemem = jtag_dev_writemem,
|
||||
.getregs = jtag_dev_getregs,
|
||||
.setregs = jtag_dev_setregs,
|
||||
.ctl = jtag_dev_ctl,
|
||||
.poll = jtag_dev_poll,
|
||||
.erase = jtag_dev_erase,
|
||||
.getconfigfuses = jtag_dev_getconfigfuses
|
||||
};
|
||||
|
||||
const struct device_class device_bp = {
|
||||
|
@ -461,12 +216,12 @@ const struct device_class device_bp = {
|
|||
.help = "Bus Pirate JTAG, MISO-TDO, MOSI-TDI, CS-TMS, AUX-RESET, CLK-TCK",
|
||||
.open = bp_open,
|
||||
.destroy = pif_destroy,
|
||||
.readmem = pif_readmem,
|
||||
.writemem = pif_writemem,
|
||||
.getregs = pif_getregs,
|
||||
.setregs = pif_setregs,
|
||||
.ctl = pif_ctl,
|
||||
.poll = pif_poll,
|
||||
.erase = pif_erase,
|
||||
.getconfigfuses = pif_getconfigfuses
|
||||
.readmem = jtag_dev_readmem,
|
||||
.writemem = jtag_dev_writemem,
|
||||
.getregs = jtag_dev_getregs,
|
||||
.setregs = jtag_dev_setregs,
|
||||
.ctl = jtag_dev_ctl,
|
||||
.poll = jtag_dev_poll,
|
||||
.erase = jtag_dev_erase,
|
||||
.getconfigfuses = jtag_dev_getconfigfuses
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue