/** filename: program.c
* description: demo of program FPGA application
* date: 2015-10-13
* compiler: ARCH=arm CROSS_COMPILE=arm-fsl-linux-gnueabi- make
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <asm/ioctl.h>
#include <mtd/mtd-user.h>
#include <errno.h>
#include <ctype.h> /* isprint */
/* gpio index */
#define FPGA_GPIO_NCONFIG 0
#define FPGA_GPIO_ROMPATH_SEL 1
#define FPGA_GPIO_CONF_DONE 2
#define FPGA_GPIO_NSTATUS 3
/* dev/fpga ioctl cmd */
#define FPGA_IOC_SET_GPIO _IO('F',0)
#define FPGA_IOC_RST_GPIO _IO('F',1)
#define FPGA_IOC_GET_GPIO _IO('F',2)
#define BUFFER_SIZE 1048576
#define DEBUG_SIZE 2048
/* buffer */
char buffer[BUFFER_SIZE];
char read_buffer[DEBUG_SIZE];
/* fpga device */
struct fpga {
int fd;
int nconfig;
int rompath_sel;
int conf_done;
int nstaus;
};
/* global variable */
struct fpga fpga_dev;
/** flash erase
*/
int region_erase(int Fd, int start, int count, int unlock, int regcount)
{
int i, j;
region_info_t * reginfo;
reginfo = calloc(regcount, sizeof(region_info_t));
for(i = 0; i < regcount; i++)
{
reginfo[i].regionindex = i;
if(ioctl(Fd,MEMGETREGIONINFO,&(reginfo[i])) != 0)
return 8;
else
printf("Region %d is at %d of %d sector and with sector "
"size %x\n", i, reginfo[i].offset, reginfo[i].numblocks,
reginfo[i].erasesize);
}
// We have all the information about the chip we need.
for(i = 0; i < regcount; i++)
{ //Loop through the regions
region_info_t * r = &(reginfo[i]);
if((start >= reginfo[i].offset) &&
(start < (r->offset + r->numblocks*r->erasesize)))
break;
}
if(i >= regcount)
{
printf("Starting offset %x not within chip.\n", start);
return 8;
}
//We are now positioned within region i of the chip, so start erasing
//count sectors from there.
for(j = 0; (j < count)&&(i < regcount); j++)
{
erase_info_t erase;
region_info_t * r = &(reginfo[i]);
erase.start = start;
erase.length = r->erasesize;
if(unlock != 0)
{ //Unlock the sector first.
if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
{
perror("\nMTD Unlock failure");
close(Fd);
return 8;
}
}
printf("\rPerforming Flash Erase of length 0x%llx at offset 0x%llx",
erase.length, erase.start);
fflush(stdout);
if(ioctl(Fd, MEMERASE, &erase) != 0)
{
perror("\nMTD Erase failure");
close(Fd);
return 8;
}
start += erase.length;
if(start >= (r->offset + r->numblocks*r->erasesize))
{ //We finished region i so move to region i+1
printf("\nMoving to region %d\n", i+1);
i++;
}
}
printf(" done\n");
return 0;
}
int non_region_erase(int Fd, int start, int count, int unlock)
{
mtd_info_t meminfo;
if (ioctl(Fd,MEMGETINFO,&meminfo) == 0)
{
erase_info_t erase;
erase.start = start;
erase.length = meminfo.erasesize;
for (; count > 0; count--) {
printf("\rPerforming Flash Erase of length %u at offset 0x%x",
erase.length, erase.start);
fflush(stdout);
if(unlock != 0)
{
//Unlock the sector first.
printf("\rPerforming Flash unlock at offset 0x%x",erase.start);
if(ioctl(Fd, MEMUNLOCK, &erase) != 0)
{
perror("\nMTD Unlock failure");
close(Fd);
return 8;
}
}
if (ioctl(Fd,MEMERASE,&erase) != 0)
{
perror("\nMTD Erase failure");
close(Fd);
return 8;
}
erase.start += meminfo.erasesize;
}
printf(" done\n");
}
return 0;
}
/** fpga print info
*/
int print_fpga(void)
{
char str[128];
sprintf(str,"nconfig:%d\n", fpga_dev.nconfig);
printf(str);
sprintf(str,"rompath sel:%d\n", fpga_dev.rompath_sel);
printf(str);
sprintf(str,"conf_done:%d\n", fpga_dev.conf_done);
printf(str);
sprintf(str,"nstatus:%d\n", fpga_dev.nstaus);
printf(str);
return 0;
}
/** after write flash, poll up nconfig single, and wait at least 2us
*/
int fpga_nconfig()
{
char str[128];
int ret, param;
/* pull down rompath sel */
ret = ioctl(fpga_dev.fd, FPGA_IOC_RST_GPIO, FPGA_GPIO_ROMPATH_SEL);
if(ret < 0) {
sprintf(str,"Unable to rst nconfig single, errno=%d\n",errno);
printf(str);
return -1;
}
sleep(20);
/* pull down nconfig */
ret = ioctl(fpga_dev.fd, FPGA_IOC_RST_GPIO, FPGA_GPIO_NCONFIG);
if(ret < 0) {
sprintf(str,"Unable to rst nconfig single, errno=%d\n",errno);
printf(str);
return -1;
}
/* sleep 2us */
sleep(2);
/* query nconfig*/
param = FPGA_GPIO_NCONFIG;
ret = ioctl(fpga_dev.fd, FPGA_IOC_GET_GPIO, ¶m);
if(ret < 0) {
sprintf(str,"Unable to get single, errno=%d\n",errno);
printf(str);
return -1;
}
fpga_dev.nconfig = param;
printf("================query nconfig:%d\n", fpga_dev.nconfig);
/* pull up nconfig */
ret = ioctl(fpga_dev.fd, FPGA_IOC_SET_GPIO, FPGA_GPIO_NCONFIG);
if(ret < 0) {
sprintf(str,"Unable to set nconfig single, errno=%d\n",errno);
printf(str);
return -1;
}
return 0;
}
/** check status
*/
int fpga_check()
{
char str[128];
int ret, param;
param = FPGA_GPIO_NCONFIG;
ret = ioctl(fpga_dev.fd, FPGA_IOC_GET_GPIO, ¶m);
if(ret < 0) {
sprintf(str,"Unable to get single, errno=%d\n",errno);
printf(str);
return -1;
}
fpga_dev.nconfig = param;
param = FPGA_GPIO_ROMPATH_SEL;
ret = ioctl(fpga_dev.fd, FPGA_IOC_GET_GPIO, ¶m);
if(ret < 0) {
sprintf(str,"Unable to get rompath sel single, errno=%d\n",errno);
printf(str);
return -1;
}
fpga_dev.rompath_sel = param;
/* get conf done */
param = FPGA_GPIO_CONF_DONE;
ret = ioctl(fpga_dev.fd, FPGA_IOC_GET_GPIO, ¶m);
if(ret < 0) {
sprintf(str,"Unable to get conf_done single, errno=%d\n",errno);
printf(str);
return -1;
}
fpga_dev.conf_done = param;
/* get nstaus */
param = FPGA_GPIO_NSTATUS;
ret = ioctl(fpga_dev.fd, FPGA_IOC_GET_GPIO, ¶m);
if(ret < 0) {
sprintf(str,"Unable to get nstatus single, errno=%d\n",errno);
printf(str);
return -1;
}
fpga_dev.nstaus = param;
print_fpga();
return 0;
}
/** open fpga device
*
*/
static int open_device(void)
{
char str[128];
int ret;
fpga_dev.fd = open("/dev/fpga", O_RDWR);
if (fpga_dev.fd < 0) {
sprintf(str, "Unable to open file /dev/fpga, errno=%d\n", errno);
printf(str);
return -1;
}
printf("successful open device /dev/fpga. file handle:%d\n", fpga_dev.fd);
return 0;
}
static int close_device(void)
{
close(fpga_dev.fd);
return 0;
}
/** get file size
*/
unsigned long get_file_size(const char *path)
{
unsigned long filesize = -1;
struct stat statbuff;
if(stat(path, &statbuff) < 0) {
return filesize;
}else{
filesize = statbuff.st_size;
}
return filesize;
}
/* read */
int flash_erase(const char* device)
{
int fd;
int bytes_read;
struct mtd_info_user info;
int regcount;
int start;
int count;
int unlock;
int ret;
/*1. open dst mtd device file */
if ((fd = open(device, O_RDWR)) < 0)
{
fprintf(stderr,"Open %s Error:%s\n", device, strerror(errno));
return -1;
}
else
{
if(ioctl(fd,MEMGETINFO,&info) == 0)
{
/*
printf("info.size=%d\n info.erasesize=%d\ninfo.writesize=%d\n
info.oobsize=%d\n",
info.size,info.erasesize,info.writesize,info.oobsize);
*/
}
}
/* flash erase */
start = 0;
count = info.size/info.erasesize;
unlock = 0;
printf("Erase Total %d Units\n", count);
if (ioctl(fd,MEMGETREGIONCOUNT,®count) == 0)
{
printf("regcount=%d\n",regcount);
if(regcount == 0)
{
ret = non_region_erase(fd, start, count, unlock);
}
else
{
ret = region_erase(fd, start, count, unlock, regcount);
}
}
printf("erased flash!\n");
sleep(3);
/* */
close(fd);
return 0;
}
/** write the FPGA config file to Altera ECPS flash device
*/
int program(const char *filename, const char* device)
{
int ret;
int from_fd,to_fd;
int bytes_read,bytes_write;
int file_count, left_bytes;
unsigned long file_size, total_bytes;
char *ptr;
/* check */
if(!filename || !*filename || !device || !*device) {
fprintf(stderr,"Invalidate parameter, application exit\n");
return -1;
}
file_size = get_file_size(filename);
file_count = file_size / BUFFER_SIZE;
left_bytes = file_size % BUFFER_SIZE;
printf("file name:%s, file size:%d bytes, file count:%d, left bytes:%d\n",
filename, file_size, file_count, left_bytes);
/*1. open source file */
if((from_fd=open(filename,O_RDONLY))==-1) /*open file readonly, if error return -1, otherwise return file desc */
{
fprintf(stderr,"Open %s Error:%s\n", filename,strerror(errno));
return -2;
}
/*2. open dst mtd device file */
if ((to_fd = open(device, O_RDWR)) < 0)
{
fprintf(stderr,"Open %s Error:%s\n", device, strerror(errno));
close(from_fd);
return -1;
}
/*3. this is classical copy file code */
int cnt = 0;
total_bytes = 0;
while(bytes_read = read(from_fd, buffer, BUFFER_SIZE))
{
/* debug code */
if(cnt == 0)
{
//memset(buffer, 'A', BUFFER_SIZE);
}
if((bytes_read == -1)&&(errno != EINTR))
break;
else if(bytes_read > 0)
{
ptr = buffer;
while(bytes_write = write(to_fd, ptr, bytes_read))
{
if((bytes_write == -1)&&(errno != EINTR))
{
printf("flash write error.....\n\n\n ");
break;
}
else if(bytes_write == bytes_read)
{
total_bytes += bytes_write;
break;
}
else if(bytes_write > 0)
{
ptr += bytes_write;
bytes_read -= bytes_write;
total_bytes += bytes_write;
}
}// end while
printf("\rWrite %ld bytes\n ", total_bytes);
if(bytes_write == -1)
break;
}
cnt++;
}// end for
printf("\n\n\n");
sleep(5);
// clean:
close(from_fd);
close(to_fd);
return 0;
}
/* read */
int flash_read(const char* device, int size)
{
int fd;
int bytes_read;
/*1. open dst mtd device file */
if ((fd = open(device, O_RDWR)) < 0)
{
fprintf(stderr,"Open %s Error:%s\n", device, strerror(errno));
return -1;
}
/*2. read */
bytes_read = read(fd, read_buffer, size);
printf("read %d bytes from device %s\n", bytes_read, device);
int i;
for(i = 0; i < bytes_read; i++)
{
if(isprint(read_buffer[i]))
printf("%c", read_buffer[i]);
else
printf(".");
if((i + 1) % 16 == 0)
printf("\n");
}
printf("\n\n");
/* */
close(fd);
return 0;
}
/** main routine
*/
int main(int argc, char *argv[])
{
if(3 > argc)
{
printf("Usage: ./program filename device\n");
return -1;
}
fpga_dev.conf_done = -99;
fpga_dev.nstaus = -99;
/* open device */
open_device();
/* check */
fpga_check();
/* erase flash */
flash_erase(argv[2]);
/* program FPGA */
if(program(argv[1], argv[2]) == 0)
{
printf("success program flash!\n");
sleep(3);
flash_read(argv[2], DEBUG_SIZE);
sleep(10);
/* trigger */
fpga_nconfig();
/* check singele */
int i;
for(i = 0; i < 5; i ++)
{
fpga_check();
if( fpga_dev.conf_done == 1 || fpga_dev.nstaus == 1)
{
printf("success query fpga state.");
break;
}
sleep(1);
}
if(i > 5)
printf("can't query fpga state");
}else {
printf("program flash failed!\n");
}
/* close fpga device */
close_device();
return 1;
}
/* [] */