Newer
Older
/* V3 Flasher - temporary version */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <libgen.h>
#include <inttypes.h>
#include "serial.h"
#include "applet.h"
#define BOARD_REV_V2 2
#define BOARD_REV_V3 3
#define ID_SAM9263 0x019607A2
#define ID_SAM9G45 0x819b05a2
#define SERIAL_TIMEOUT 10000000
#define MBOX_COMMAND 0x4
#define MBOX_STATUS 0x8
#define MBOX_COMTYPE 0xc
#define MBOX_TRACELEVEL 0x10
#define MBOX_EXTRAM_VDDMEM 0x14
#define MBOX_EXTRAM_RAMTYPE 0x18
#define MBOX_EXTRAM_BUSWIDTH 0x1c
#define MBOX_EXTRAM_DDRMODEL 0x20
#define MBOX_DATAFLASH_INDEX 0x14
#define MBOX_DATAFLASH_BUFFER_ADDR 0x10
#define MBOX_PROG_BUF_SIZE 0x
#define MBOX_MEM_BUF_ADDR 0xc
#define MBOX_MEM_BUF_SIZE 0x10
#define MBOX_MEM_BUF_OFFSET 0x14
#define MBOX_MEM_ERASE_TYPE 0xc
#define MBOX_MEM_ERASE_START 0x10
#define MBOX_MEM_ERASE_END 0x14
#define INTERNAL_SRAM_BUF 0x300000
#define SDRAM_START 0x70000000
#define DF_HWINFO_START 0x000000094800
#define DF_HWINFO_END 0x000000095040
#define PORT_SPEED 115200
#define MEMTYPE_DDR 0
#define MEMTYPE_DF 1
#define MEMTYPE_NAND 2
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
#endif
const char* memName[3] = { "DDR", "DataFlash", "NandFlash" };
typedef struct {
char *fname;
uint32_t offset;
} sndfile;
sndfile filearray[16];
//External variable from version.c
extern const char build_time[];
extern const char git_user[];
extern const char git_revision[];
Benoit Rat
committed
char *program_name;
int applet_silent_mode = 1;
unsigned int buffer_size = 0x3000;
unsigned int buffer_addr ;
int mem_write(int type, uint32_t offset, uint32_t buf_addr, uint32_t size);
int crc16(int value, int crcin)
{
int k = (((crcin >> 8) ^ value) & 255) << 8;
int crc = 0;
int bits = 8;
do
{
if (( crc ^ k ) & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
k <<= 1;
}
while (--bits);
return ((crcin << 8) ^ crc);
int write_xmodem(int index, char *p)
unsigned short crc=0;
int i;
data[0]=1;
data[1]=index;
data[2]=0xff-index;
memcpy(data+3,p,128);
for(i=3;i<131;i++){
crc=crc16(data[i],crc);
}
data[131] = (crc>>8)&0xff;
data[132] = (crc)&0xff;
printf("XMDump: ");
for(i=0;i<133;i++) printf("%02x ", data[i]);
printf("\n\n");
serial_write(data,133);
return serial_read_byte();
}
void die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n\n");
va_end(ap);
exit(-1);
}
void samba_write (uint32_t addr, uint32_t data, int size, int timeout)
{
uint32_t tstart;
serial_purge();
snprintf(tmpbuf, 1024, "%c%08x,%08x#", size==1?'O':(size==2?'H':'W'), addr, data);
serial_write(tmpbuf, strlen(tmpbuf));
tstart = sys_get_clock_usec();
if(serial_data_avail())
{
if(serial_read_byte() =='>') break;
}
if(sys_get_clock_usec() - tstart > timeout) die("tx timeout");
}
uint32_t samba_read (uint32_t addr, int size, int timeout)
{
char tmpbuf[1024],c=0;
int i,xpos=-1;
uint32_t rval;
uint32_t tstart;
serial_purge();
snprintf(tmpbuf, 1024, "%c%08x,#", size==1?'o':(size==2?'h':'w'), addr);
// printf("--> cmd: '%s'\n", tmpbuf);
serial_write(tmpbuf, strlen(tmpbuf));
tstart = sys_get_clock_usec();
if(serial_data_avail())
{
tmpbuf[i]=c=serial_read_byte();
// fprintf(stderr,"%c", c);
if(c=='x') xpos=i;
i++;
}
if(sys_get_clock_usec()-tstart>timeout) die("rx timeout");
if(xpos<0) die("invalid response from samba");
sscanf(tmpbuf, "%x", &rval);
// fprintf(stderr,"samba_read: %x\n", rval);
/**
* filename: name of the file in the host
* address: place to send to file on the device
* offset: internal offset, can be use with size
* size: can be 0
*/
static int samba_send_file(const char *filename, uint32_t address, uint32_t offset, uint32_t size, int quiet)
{
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
FILE *f;
unsigned char *buf;
int boffset = 0;
char tmp[4097];
// printf("SendFile: %s\n", filename);
f = fopen(filename, "rb");
if(!f) die("file open error: '%s'",filename);
if(!size)
{
fseek(f, 0, SEEK_END);
size = ftell(f);
offset = 0;
rewind(f);
} else
fseek(f, offset, SEEK_SET);
if(!quiet) printf("size 0x%x (%dKb)\n",size,size/1024);
buf = malloc(size+1);
if(!buf) die("malloc failed");
fread(buf, 1, size, f);
fclose(f);
// printf("Send: %s\n", filename);
while(size > 0)
{
int tosend = size > 1024 ? 1024 : size;
// printf("Sending %d bytes\n", tosend);
snprintf(tmp, 128, "S%08x,%x#", address, tosend);
serial_write(tmp, strlen(tmp));
memcpy(tmp, buf + boffset, tosend);
tmp[tosend]='\n';
serial_write(tmp, tosend+1);
size -= tosend;
boffset +=tosend;
address += tosend;
while(1)
{
if(serial_data_avail())
if(serial_read_byte() == '>')
break;
}
}
free(buf);
return boffset;
}
static void samba_load_applet(char *applet_name, uint32_t address)
{
char namebuf[1024];
printf("loading applet %s at 0x%08x\n", applet_name, address);
snprintf(namebuf, 1024, "%s/samba_applets/%s.bin", program_path, applet_name);
samba_send_file(namebuf, address, 0, 0, 1);
}
static void mbox_write(uint32_t base, uint32_t offset, uint32_t value)
{
samba_write(base+offset, value, 4, SERIAL_TIMEOUT);
void samba_run(uint32_t addr, int timeout)
{
char tmpbuf[1024],c;
uint32_t tstart,t1;
serial_purge();
snprintf(tmpbuf, 1024, "G%08x#", addr);
serial_write(tmpbuf, strlen(tmpbuf));
t1 = tstart = sys_get_clock_usec();
while((timeout && (sys_get_clock_usec()- tstart < timeout)) || !timeout)
{
if(serial_data_avail()) {
c = serial_read_byte();
if(c == '>') break;
if(!applet_silent_mode )fprintf(stderr,"%c", c);
t1 = sys_get_clock_usec();
}
else if(sys_get_clock_usec() - t1 > 10000)
// fprintf(stderr,"Phase1\n");
// serial_write_byte('\n');
serial_write_byte(0x0a);
serial_write_byte(0x0d);
serial_write_byte('T');
serial_write_byte('#');
serial_write_byte(0x0a);
serial_write_byte(0x0d);
usleep(10000);
while(serial_data_avail())
{
c=serial_read_byte();
if( c == '>')
return;
else if(!applet_silent_mode)
fprintf(stderr,"%c", c);
}
usleep(1000);
//TODO: Improve data available for DDR load
}
}
int samba_connect(int board_rev)
{
char handshake[] = {0x80, 0x80, 0x23};
serial_write(handshake,3);
sys_delay(100);
uint32_t id = samba_read(0xffffee40, 4, SERIAL_TIMEOUT);
printf("CPU ID: 0x%08x\n",id);
if(board_rev == BOARD_REV_V2 && id != ID_SAM9263) die ("Not a 9263 CPU");
if(board_rev == BOARD_REV_V3 && id != ID_SAM9G45) die ("Not a 9G45 CPU");
return 0;
Benoit Rat
committed
int ddr_init(int board_rev)
if(board_rev == BOARD_REV_V2)
samba_load_applet("isp-extram-at91sam9263", INTERNAL_SRAM_BUF);
else if(board_rev == BOARD_REV_V3)
samba_load_applet("isp-extram-at91sam9g45", INTERNAL_SRAM_BUF);
mbox_write(INTERNAL_SRAM_BUF, MBOX_COMMAND, APPLET_CMD_INIT);
mbox_write(INTERNAL_SRAM_BUF, MBOX_TRACELEVEL, 0);
mbox_write(INTERNAL_SRAM_BUF, MBOX_EXTRAM_RAMTYPE, 1);
mbox_write(INTERNAL_SRAM_BUF, MBOX_EXTRAM_VDDMEM, 0);
mbox_write(INTERNAL_SRAM_BUF, MBOX_EXTRAM_BUSWIDTH, 16);
mbox_write(INTERNAL_SRAM_BUF, MBOX_EXTRAM_DDRMODEL, 0);
samba_run(INTERNAL_SRAM_BUF, 100000000);
Benoit Rat
committed
if((samba_read(INTERNAL_SRAM_BUF + MBOX_COMMAND, 4, 10000000)) != ~APPLET_CMD_INIT) die("invalid response from applet init");
if((samba_read(INTERNAL_SRAM_BUF + MBOX_STATUS, 4, 10000000)) != APPLET_SUCCESS) die("invalid response from applet status");
int ddr_load(int nFile, const sndfile* pFileArray)
Benoit Rat
committed
{
int i;
uint32_t len=0;
fprintf(stderr,"Loading DDR...\n");
for(i=0;i<nFile; i++)
{
printf("\t @ 0x%08x : %s ; ",SDRAM_START+ pFileArray[i].offset, pFileArray[i].fname);
len += samba_send_file(pFileArray[i].fname, SDRAM_START+pFileArray[i].offset,0, 0, 0);
}
mem_write(MEMTYPE_DDR,0,SDRAM_START,len);
return 0;
Benoit Rat
committed
}
int memflash_init(int type, int board_rev)
fprintf(stderr,"Initializing %s...\n",memName[type]);
//Load the correct applet
if(board_rev == BOARD_REV_V2)
{
if(type==MEMTYPE_NAND) samba_load_applet("isp-nandflash-at91sam9263", INTERNAL_SRAM_BUF);
else if(type==MEMTYPE_DF) samba_load_applet("isp-dataflash-at91sam9263", INTERNAL_SRAM_BUF);
}
else if(board_rev == BOARD_REV_V3)
{
if(type==MEMTYPE_NAND) samba_load_applet("isp-nandflash-at91sam9g45", INTERNAL_SRAM_BUF);
else if(type==MEMTYPE_DF) samba_load_applet("isp-dataflash-at91sam9g45", INTERNAL_SRAM_BUF);
}
mbox_write(INTERNAL_SRAM_BUF, MBOX_COMMAND, APPLET_CMD_INIT);
mbox_write(INTERNAL_SRAM_BUF, MBOX_COMTYPE, 1);
mbox_write(INTERNAL_SRAM_BUF, MBOX_TRACELEVEL, 4);
mbox_write(INTERNAL_SRAM_BUF, MBOX_DATAFLASH_INDEX, 0);
samba_run(INTERNAL_SRAM_BUF, 0);
if(samba_read(INTERNAL_SRAM_BUF + MBOX_COMMAND, 4, 10000000) != ~APPLET_CMD_INIT) die("invalid response from applet");
if(samba_read(INTERNAL_SRAM_BUF + MBOX_STATUS, 4, 10000000) != APPLET_SUCCESS) die("Initialization failure (no chip deteted?)");
buffer_addr = samba_read(INTERNAL_SRAM_BUF + MBOX_DATAFLASH_BUFFER_ADDR, 4, 10000000);
fprintf(stderr,"Initializing %s > Done! \n\n",memName[type]);
return 0;
}
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
int mem_program(int type, int nFile, const sndfile* pFileArray)
{
int i;
uint32_t len=0;
if(type==MEMTYPE_DDR) return ddr_load(nFile,pFileArray);
else
{
fprintf(stderr,"Programming %s...\n",memName[type]);
for(i=0;i<nFile; i++)
{
printf("\t @ 0x%08x : %s ; ",SDRAM_START+ pFileArray[i].offset, pFileArray[i].fname);
len = samba_send_file(pFileArray[i].fname, SDRAM_START,0,0,0);
mem_write(type,pFileArray[i].offset, SDRAM_START, len);
}
fprintf(stderr,"Programming %s Done!!!\n",memName[type]);
return 0;
}
}
void mem_check(int type)
{
fprintf(stderr,"Checking %s...\n\n",memName[type]);
mbox_write(INTERNAL_SRAM_BUF, MBOX_COMMAND, APPLET_CMD_LIST_BAD_BLOCKS);
samba_run(INTERNAL_SRAM_BUF, 0);
if((samba_read(INTERNAL_SRAM_BUF + MBOX_COMMAND, 4, 10000000)) != ~APPLET_CMD_LIST_BAD_BLOCKS) die("invalid response from applet write");
if((samba_read(INTERNAL_SRAM_BUF + MBOX_STATUS, 4, 10000000)) != APPLET_SUCCESS) die("invalid response from applet status");
}
void mem_erase(int type, int scrub)
const char *action=(scrub)?"Scrubing":"Erasing";
fprintf(stderr,"%s %s...",action,memName[type]);
if(type==MEMTYPE_DF)
{
mbox_write(INTERNAL_SRAM_BUF, MBOX_COMMAND, APPLET_CMD_FULL_ERASE);
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_TYPE,0);
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_START,0);
if(scrub)
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_END,0);
else
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_END,DF_HWINFO_START);
samba_run(INTERNAL_SRAM_BUF, 0);
// fprint("\rDF: 2nd part...");
// mbox_write(INTERNAL_SRAM_BUF, MBOX_COMMAND, APPLET_CMD_FULL_ERASE);
// mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_TYPE,0);
// mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_START,DF_HWINFO_END);
// mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_END,0);
// samba_run(INTERNAL_SRAM_BUF, 0);
}
else
{
//Full NF Erase
mbox_write(INTERNAL_SRAM_BUF, MBOX_COMMAND, APPLET_CMD_FULL_ERASE);
if(scrub) mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_ERASE_TYPE,0x0000EA11);
samba_run(INTERNAL_SRAM_BUF, 0);
}
fprintf(stderr,"\r%s %s > DONE\n\n",action,memName[type]);
}
int mem_write(int type, uint32_t offset, uint32_t buf_addr, uint32_t size)
uint32_t timeout;
applet_silent_mode=1;
fprintf(stderr, "%s: Writing %d bytes at offset 0x%x buffer %x....", memName[type], size, offset, buf_addr);
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_BUF_ADDR, buf_addr);
fprintf(stderr,"A");
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_BUF_ADDR, buf_addr);
fprintf(stderr,"B");
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_BUF_SIZE, size);
fprintf(stderr,"C");
mbox_write(INTERNAL_SRAM_BUF, MBOX_MEM_BUF_OFFSET, offset);
fprintf(stderr,"D");
mbox_write(INTERNAL_SRAM_BUF, MBOX_COMMAND, APPLET_CMD_WRITE);
fprintf(stderr,"E");
if(type==MEMTYPE_DDR) timeout=10;
else timeout=0;
samba_run(INTERNAL_SRAM_BUF, timeout);
fprintf(stderr,"F");
if(type == MEMTYPE_DDR) // booting a barebox/kernel will fuck up USB, so we'll never get any response
return 0;
if(samba_read(INTERNAL_SRAM_BUF + MBOX_COMMAND, 4, 10000000) != ~APPLET_CMD_WRITE) die(" invalid response from applet");
if(samba_read(INTERNAL_SRAM_BUF + MBOX_STATUS, 4, 10000000) != APPLET_SUCCESS) die(" write failure");
printf(" OK\n");
uint32_t getOffset(const char *str)
uint32_t ret=0;
if (str == NULL || *str == '\0') return ret;
if(str[0]=='0' && (str[1]=='X' || str[1]=='x'))
{
str+=2;
sscanf(str, "%x", &ret);
}
else sscanf(str, "%d", &ret);
return ret;
Benoit Rat
committed
void show_help(const char* serial_port)
{
printf("WhiteRabbit MCH DataFlash programmer (c) T.W. 2010\n");
printf("Compiled by %s (%s)\ngit rev:%s\n\n",git_user,build_time,git_revision);
printf("Usage: %s [options] [<FILE1> <OFFSET1> <FILE2> <OFFSET2> <FILE3> <OFFSET3>]\n", program_name);
printf("if FILEx set it will write the FILEx at the given OFFSETx (by default 0x0), "
"otherwise you can use this binary to erase, check or scrub a memory\n");
Benoit Rat
committed
printf("Options:\n");
printf("\t-m \t Select the memory type: ddr, nf, df\n");
printf("\t-e \t\t erase the memory\n");
printf("\t-c \t\t check the memory (not available for df)\n");
printf("\t-s \t\t scrub the memory (WARNING: full erase)\n");
printf("\t-r \t\t addr run the image at address addr\n");
printf("\t-p SERIAL_PORT\t By default it is: -p %s\n",serial_port);
Benoit Rat
committed
printf("\t-h \t\t Show this little help\n");
printf("\n");
}
int main(int argc, char *argv[])
{
int board_rev = BOARD_REV_V3;
char *serial_port = "/dev/ttyACM0";
char * mode_str ="df";
char opt;
int erase=0, check=0, scrub=0;
int type=-1;
int nFile=0;
program_name = basename(strdup(argv[0]));
program_path = dirname(strdup(argv[0]));
if(argc==1)
{
show_help(serial_port);
return 1;
}
Benoit Rat
committed
//Parse options
while ((opt = getopt (argc, argv, "m:p:r:ecsh")) != -1)
switch (opt) {
case 'm':
mode_str = optarg;
break;
case 'p':
serial_port = optarg;
break;
case 'e':
erase = 1;
break;
case 'c':
check = 1;
break;
case 's':
scrub = 1;
break;
case 'r':
run = 1;
sscanf(optarg,"%i", &run_addr);
break;
case 'h':
case '?':
show_help(serial_port);
return 0;
default:
printf("find: illegal option %c\n", opt);
break;
Benoit Rat
committed
}
//Obtain the various filename & offset (3 MAX)
for(nFile=0; optind < argc; nFile++)
if (nFile >= ARRAY_SIZE(filearray)) {
fprintf(stderr, "%s: too may arguments\n",
argv[0]);
exit(1);
}
filearray[nFile].fname=argv[optind++];
filearray[nFile].offset=getOffset(argv[optind++]);
printf("n=%d, mode=%s, nFile=%d, serial=%s, (e=%d,c=%d,s=%d)\n", argc, mode_str, nFile, serial_port, erase,check,scrub);
if (serial_open(serial_port, PORT_SPEED) < 0) {
fprintf(stderr, "%s: %s: %s\n", argv[0], serial_port,
strerror(errno));
exit(1);
}
fprintf(stderr,"Initializing SAM-BA: ");
samba_connect(board_rev);
//Init the DDR for every action (used as buffer)
fprintf(stderr,"\nInitializing DDR...\n");
Benoit Rat
committed
ddr_init(board_rev);
fprintf(stderr,"Initializing DDR > Done\n\n");
//Obtain the memory type mode
if(strcmp(mode_str,"nand")==0 || strcmp(mode_str,"nf")==0) {
type=MEMTYPE_NAND;
} else if(strcmp(mode_str,"dataflash")==0 || strcmp(mode_str,"df")==0) {
type=MEMTYPE_DF;
} else if(strcmp(mode_str,"ddr")==0 || strcmp(mode_str,"ram")==0) {
type=MEMTYPE_DDR;
} else {
fprintf(stderr,"Bad memory type %s...\n\n",mode_str);
show_help(serial_port);
return 0;
Benoit Rat
committed
}
//Init the memory (except DDR which is already init)
if(type!=MEMTYPE_DDR)
memflash_init(type, board_rev);
//Run the action
if((erase || scrub) && type!=MEMTYPE_DDR)
mem_erase(type,scrub);
if(check)
mem_check(type);
if(nFile>0)
mem_program(type,nFile,(const sndfile*)&filearray);
if(run)
{
fprintf(stderr,"Executing payload @ %x\n", run_addr);
samba_run(run_addr, 0);
}
serial_close();
printf("Closing...\n");
return 0;