Files
kernel-tenderloin-3.0/drivers/misc/a6/high_level_funcs.c
2012-02-26 16:42:59 -06:00

528 lines
14 KiB
C

/****************************************************************************/
/* Includes */
/****************************************************************************/
#include "a6_host_adapter.h" // Maps function calls to host porting-layer implementations
#include "jtag_funcs.h" // Spy-by-wire JTAG functions
#include "low_level_funcs.h" // low level user functions
#define LOCAL_TRACE 0
/****************************************************************************/
/* Global types */
/****************************************************************************/
/****************************************************************************/
/* Main section of Replicator program: User can modify/insert code as needed*/
/****************************************************************************/
/*
Note: All High Level JTAG Functions are applied here.
*/
// definition for current implementation mappings used by the sbw code...
uint16_t (*SetSBWTCK)(void) = NULL;
uint16_t (*ClrSBWTCK)(void) = NULL;
uint16_t (*SetSBWTDIO)(void) = NULL;
uint16_t (*ClrSBWTDIO)(void) = NULL;
uint16_t (*SetInSBWTDIO)(void) = NULL;
uint16_t (*SetOutSBWTDIO)(void) = NULL;
uint16_t (*GetSBWTDIO)(void) = NULL;
uint16_t (*SetSBWAKEUP)(void) = NULL;
uint16_t (*ClrSBWAKEUP)(void) = NULL;
void (*delay)(uint32_t delay_us) = NULL;
//
typedef enum {
SBW_OK = 0,
SBW_TOK,
SBW_EOL,
SBW_EOS,
SBW_SOS,
SBW_EOI,
SBW_STATE_ERROR
} SBW_STATE_CODE;
#define SIZEOF_NEWLINE (1)
static int hexval(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0;
}
SBW_STATE_CODE sbw_get_token(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
//assert(read_p && read_len_p && write_len_p);
// end-of-line
if (0x0d == *read_p && 0x0a == *(read_p+1)) {
*read_len_p = 2;
*write_len_p = 0;
ret = SBW_EOL;
//printk("<EOL>\n");
}
// end-of-image
else if (('q' == *read_p) || ('Q' == *read_p)) {
*read_len_p = 1;
*write_len_p = 0;
ret = SBW_EOI;
//printk("<EOI>\n");
}
else {
uint32_t val = 0;
// section start
if ('@' == read_p[0]) {
ret = SBW_SOS;
val = hexval(read_p[1 + 0]) << 12;
val |= hexval(read_p[1 +1]) << 8;
val |= hexval(read_p[1 +2]) << 4;
val |= hexval(read_p[1 +3]);
*read_len_p = 1+4+2; //'@' + XXXX + CRLF
*write_len_p = 2; // two bytes written
//printk("<SOS>\n");
}
// data
else {
ret = SBW_TOK;
val = hexval(read_p[0]) << 4;
val |= hexval(read_p[1]);
// handle variation: the last 2-byte value on a line may not include trailing space
*read_len_p = 2+1; //XX + ' '
//*read_len_p = 2 + (' ' == read_p[2]) ? 1 : 0; //XX + ' '
*write_len_p = 1; // one byte written
}
// no target? skip the actual write...
if (write_p) {
//*((uint32_t*)write_p) = val;
write_p[0] = val & 0x000000ff;
write_p[1] = (val >> 8) & 0x000000ff;
write_p[2] = (val >> 16) & 0x000000ff;
write_p[3] = (val >> 24) & 0x000000ff;
}
//printk("%02x ", val);
}
return ret;
}
SBW_STATE_CODE sbw_parse_line(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
uint32_t total_read_len = 0, total_write_len = 0, val = 0, r_len = 0, w_len = 0;
do {
ret = sbw_get_token(read_p, (uint8_t*)&val, &r_len, &w_len);
// end-of-line; break out of loop
if (SBW_EOL == ret) {
total_read_len += r_len;
*read_len_p = total_read_len;
total_write_len += w_len;
*write_len_p = total_write_len;
}
// regular token; keep looping
else if (SBW_TOK == ret) {
*((uint8_t*)write_p) = (uint8_t)val;
total_read_len += r_len;
read_p += r_len;
total_write_len += w_len;
write_p += w_len;
}
// map start-of-section/end-of-image to end-of-section
else if ((SBW_SOS == ret) || (SBW_EOI == ret)) {
*read_len_p = *write_len_p = 0;
ret = SBW_EOS;
}
// state mismatch
else {
printk("SBW_ERROR[sbw_parse_line]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
}
} while (SBW_TOK == ret);
return ret;
}
SBW_STATE_CODE sbw_parse_section(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
uint32_t total_read_len = 0, total_write_len = 0, r_len = 0, w_len = 0;
do {
ret = sbw_parse_line(read_p, write_p, &r_len, &w_len);
// end-of-section; break out of loop
if (SBW_EOS == ret){
total_read_len += r_len;
*read_len_p = total_read_len;
total_write_len += w_len;
*write_len_p = total_write_len;
}
// end-of-line; keep looping
else if (SBW_EOL == ret) {
total_read_len += r_len;
read_p += r_len;
total_write_len += w_len;
write_p += w_len;
}
// state mismatch
else {
printk("SBW_ERROR[sbw_parse_section]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
}
} while (SBW_EOL == ret);
return ret;
}
typedef struct {
uint32_t sec_addr[75];
uint32_t sec_len[75];
uint32_t num_sections;
} sec_info_struct;
sec_info_struct sec_info;
int32_t sec_index = 0;
SBW_STATE_CODE sbw_parse_image(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
uint32_t total_read_len = 0, total_write_len = 0, r_len = 0, w_len = 0, val = 0;
memset(&sec_info, 0, sizeof(sec_info));
do {
ret = sbw_get_token(read_p, (uint8_t*)&val, &r_len, &w_len);
if (SBW_SOS != ret) {
if (!sec_info.num_sections) {
printk("SBW_ERROR[sbw_parse_image]: does not start with section; value: %d\n", ret);
return SBW_STATE_ERROR;
}
if (SBW_EOI == ret) {
*read_len_p = total_read_len;
*write_len_p = total_write_len;
ret = SBW_OK;
break;
}
else {
printk("SBW_ERROR[sbw_parse_image]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
break;
}
}
//printk("[Status]: SOS detected; address: %x, r_len: %d, w_len: %d\n", val, r_len, w_len);
total_read_len += r_len;
read_p += r_len;
sec_info.sec_addr[sec_info.num_sections] = val;
ret = sbw_parse_section(read_p, write_p, &r_len, &w_len);
// end-of-section; keep looping
if (SBW_EOS == ret) {
total_read_len += r_len;
read_p += r_len;
if (w_len & 1) {
write_p[w_len] = 0xff;
w_len++;
}
total_write_len += w_len;
write_p += w_len;
// sec_len converted to A6 words (16-bit)
sec_info.sec_len[sec_info.num_sections] = w_len/2;
sec_info.num_sections++;
}
// state mismatch
else {
printk("SBW_ERROR[sbw_parse_image:1]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
}
} while (SBW_EOS == ret);
if (SBW_OK == ret) {
int idx = 0;
printk("Parsing complete. Read size: %d, Write size: %d. Num sections: %d\n",
*read_len_p, *write_len_p, sec_info.num_sections);
while (idx < (int)sec_info.num_sections) {
printk("Section idx: %d; Addr: 0x%04x; Length: %d\n",
idx, sec_info.sec_addr[idx], sec_info.sec_len[idx]);
idx++;
}
/*
printk("\nDumping converted data:\n");
for (idx = 0; idx < (int)*write_len_p; idx++) {
if (!(idx % 16)) {
printk("\n");
}
printk("%02x ", (write_p-*write_len_p)[idx]);
}
*/
}
return ret;
}
int program_device_sbw(struct a6_sbw_interface* sbw_ops, uint32_t read_address)
{
uint32_t read_len = 0, write_len = 0;
SBW_STATE_CODE parse_ret;
int retry = 0, ret_val = 0;
uint16_t addr;
if (read_address & 1) {
printk("program_fw: Please enter an even read address.\n");
return -1;
}
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
parse_ret = sbw_parse_image((uint8_t*)read_address, (uint8_t*)read_address/*write_p*/, &read_len, &write_len);
if (SBW_OK != parse_ret) {
printk("Error in parsing A6 fw file...\n");
return -1;
}
/* TEMP: Workaround for occasional verification failure. Not root-Caused yet but,
empirically, a retry always works. Revisit.*/
retry_0:
InitTarget();
// Start of SBW access to the Target
if (GetDevice() != STATUS_OK) // Set DeviceId
{
printk("Error in GetDevice()\n"); // stop here if invalid JTAG ID or
// time-out. (error: red LED is ON)
ret_val = -1;
goto err0;
}
// Program the boot code
if (!WriteAllSections((const unsigned short*)read_address, (const unsigned long *)&sec_info.sec_addr[0],
(const unsigned long *)&sec_info.sec_len[0], sec_info.num_sections))
{
printk("Error in WriteAllSections(all)\n");
ret_val = -1;
goto err0;
}
if (!VerifyAllSections((const unsigned short*)read_address, (const unsigned long *)&sec_info.sec_addr[0],
(const unsigned long *)&sec_info.sec_len[0], sec_info.num_sections))
{
printk("Error in VerifyAllSections(all)\n");
printk("Retrying...\n\n");
if (retry++ < 15) {
addr = ReadMem_430Xv2(F_WORD, V_RESET);
ReleaseDevice(addr, ERROR); // set PC to V_RESET contents
ReleaseTarget();
goto retry_0;
}
else {
printk("Failure to write and verify fw file after %d retries\n", retry);
ret_val = -1;
}
}
err0:
addr = ReadMem_430Xv2(F_WORD, V_RESET);
if (ReleaseDevice(addr, PROGRAM) < 0) { // set PC to V_RESET contents
printk(KERN_ERR "Checksum validation failed post-flashing.\n");
if (retry < 15) {
printk(KERN_ERR "Retrying...\n\n");
retry++;
ReleaseTarget();
goto retry_0;
}
else {
printk(KERN_ERR "Failure to program fw after %d retries.\n", retry);
ret_val = -1;
}
}
// if fail to set JTAG mode
if (ret_val == -1 && retry == 0 ) {
retry++;
ret_val = 0;
goto retry_0;
}
ReleaseTarget();
return ret_val;
}
int verify_device_sbw(struct a6_sbw_interface* sbw_ops, uint32_t read_address)
{
uint32_t read_len = 0, write_len = 0;
SBW_STATE_CODE parse_ret;
int ret_val = 0;
uint16_t addr;
if (read_address & 1) {
printk("program_fw: Please enter an even read address.\n");
return -1;
}
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
parse_ret = sbw_parse_image( (uint8_t*)read_address,
(uint8_t*)read_address/*write_p*/,
&read_len, &write_len);
if (SBW_OK != parse_ret) {
printk("Error in parsing A6 fw file...\n");
return -1;
}
InitTarget();
// Start of SBW access to the Target
if (GetDevice() != STATUS_OK) // Set DeviceId
{
printk("Error in GetDevice()\n"); // stop here if invalid JTAG ID or
// time-out. (error: red LED is ON)
ret_val = -1;
goto err0;
}
if (!VerifyAllSections((const unsigned short*)read_address,
(const unsigned long *)&sec_info.sec_addr[0],
(const unsigned long *)&sec_info.sec_len[0], sec_info.num_sections)) {
printk("Error in VerifyAllSections(all)\n");
ret_val = -1;
}
err0:
addr = ReadMem_430Xv2(F_WORD, V_RESET);
ReleaseDevice(addr, VERIFY); // set PC to V_RESET contents
ReleaseTarget();
return ret_val;
}
int ttf_extract_fw_sbw(struct a6_sbw_interface* sbw_ops)
{
int ret_val = 0;
uint16_t addr;
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
InitTarget();
// Start of SBW access to the Target
if (GetDevice() != STATUS_OK) // Set DeviceId
{
printk("Error in GetDevice()\n"); // stop here if invalid JTAG ID or
// time-out. (error: red LED is ON)
ret_val = -1;
goto err0;
}
if (!TTFExtractAllSections()) {
printk("Error in TTFExtractAllSections\n");
ret_val = -1;
}
err0:
addr = ReadMem_430Xv2(F_WORD, V_RESET);
ReleaseDevice(addr, VERIFY); // set PC to V_RESET contents
ReleaseTarget();
return ret_val;
}
int ttf_image_read(char *buf, size_t count, loff_t *ppos)
{
return TTFImageRead(buf, count, ppos);
}
int ttf_extract_cache_clear(void)
{
TTFExtractCacheClear();
return 0;
}
int get_checksum_data_sbw(struct a6_sbw_interface* sbw_ops, unsigned short* cksum1,
unsigned short* cksum2, unsigned short* cksum_cycles,
unsigned short* cksum_errors)
{
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
return GetChecksumData(cksum1, cksum2, cksum_cycles, cksum_errors);
}