/*gpmc_fpga driver*/
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <plat/gpmc.h>
/* GPMC register offsets */
#define GPMC_REVISION 0x00
#define GPMC_SYSCONFIG 0x10
#define GPMC_SYSSTATUS 0x14
#define GPMC_IRQSTATUS 0x18
#define GPMC_IRQENABLE 0x1c
#define GPMC_TIMEOUT_CONTROL 0x40
#define GPMC_ERR_ADDRESS 0x44
#define GPMC_ERR_TYPE 0x48
#define GPMC_CONFIG 0x50
#define GPMC_STATUS 0x54
#define GPMC_PREFETCH_CONFIG1 0x1e0
#define GPMC_PREFETCH_CONFIG2 0x1e4
#define GPMC_PREFETCH_CONTROL 0x1ec
#define GPMC_PREFETCH_STATUS 0x1f0
#define GPMC_ECC_CONFIG 0x1f4
#define GPMC_ECC_CONTROL 0x1f8
#define GPMC_ECC_SIZE_CONFIG 0x1fc
#define GPMC_ECC1_RESULT 0x200
#define GPMC_ECC_BCH_RESULT_0 0x240
#define GPMC_BASE_ADDR 0x50000000
#define GPMC_CS 1
#define GPMC_CS0 0x60
#define GPMC_CS_SIZE 0x30
#if 1
#define STNAND_GPMC_CONFIG1 0x00000800
#define STNAND_GPMC_CONFIG2 0x00141400 //20-16:CSWROFFTIME,12-8:CSRDOFFTIME,3-0:CSONTIME
#define STNAND_GPMC_CONFIG3 0x00141400
#define STNAND_GPMC_CONFIG4 0x0F010F01 //28-24:WEOFFTIME,19-16:WEONTIME,12-8:OEOFFTIME,3-0:OEONTIME
#define STNAND_GPMC_CONFIG5 0x010C1414 //20-16:RDACCESSTIME means Delay between start cycle time and first data valid 12-8:WRCYCLETIME,4-0:RDCYCLETIME
#define STNAND_GPMC_CONFIG6 0x1F0F0A80 //28-24:WRACCESSTIME
#define STNAND_GPMC_CONFIG7 0x00000F1F //28-24:WRACCESSTIME
#else
1
#define STNAND_GPMC_CONFIG1 (0x00000000 | (0x3<<23) | (0x3<<18) |(0x3<<16))
#define STNAND_GPMC_CONFIG2 0x00011001 //20-16:CSWROFFTIME,12-8:CSRDOFFTIME,3-0:CSONTIME
#define STNAND_GPMC_CONFIG3 0x00020201
//#define STNAND_GPMC_CONFIG4 0x08031003
#define STNAND_GPMC_CONFIG4 0x08031003 //28-24:WEOFFTIME,19-16:WEONTIME,12-8:OEOFFTIME,3-0:OEONTIME
//#define STNAND_GPMC_CONFIG5 0x000f1111 //20-16:RDACCESSTIME means Delay between start cycle time and first data valid
//12-8:WRCYCLETIME,4-0:RDCYCLETIME
#define STNAND_GPMC_CONFIG5 0x00101f1f
#define STNAND_GPMC_CONFIG6 0x0f030080 //28-24:WRACCESSTIME
#endif
static const u32 gpmc_nand[8] = {
STNAND_GPMC_CONFIG1,
STNAND_GPMC_CONFIG2,
STNAND_GPMC_CONFIG3,
STNAND_GPMC_CONFIG4,
STNAND_GPMC_CONFIG5,
STNAND_GPMC_CONFIG6,
STNAND_GPMC_CONFIG7,
0
};
#define CONTROL_BASE 0x44e10000
unsigned long GPMC_config1;
unsigned long GPMC_config7;
unsigned long bank_addr_start;
static void __iomem *gpmc_base;
static void __iomem *fpga_base;
static void __iomem *control_base;
unsigned long mem_base;
//---------
struct semaphore sem;
unsigned int read_way=1;
#define USER_BUFF_SIZE 128
//------------------------
static void register_configuration(void)
{
control_base = ioremap(CONTROL_BASE,0x89C);
iowrite32(0x30,(control_base+0x800)); //configure ad0
iowrite32(0x30,(control_base+0x804)); //configure ad1
iowrite32(0x30,(control_base+0x808)); //configure ad2
iowrite32(0x30,(control_base+0x80C)); //configure ad3
iowrite32(0x30,(control_base+0x810)); //configure ad4
iowrite32(0x30,(control_base+0x814)); //configure ad5
iowrite32(0x30,(control_base+0x818)); //configure ad6
iowrite32(0x30,(control_base+0x81C)); //configure ad7
iowrite32(0x08,(control_base+0x870)); //configure wait0
iowrite32(0x08,(control_base+0x874)); //configure wpn
iowrite32(0x08,(control_base+0x880)); //configure csn1
iowrite32(0x08,(control_base+0x890)); //configure advn ale
iowrite32(0x08,(control_base+0x894)); //configure oen ren
iowrite32(0x08,(control_base+0x898)); //configure we
iowrite32(0x08,(control_base+0x89C)); //configure ben0 cle
}
static void gpmc_write_cs_reg(int cs, int idx, u32 val)
{
void __iomem *reg_addr;
reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
//__raw_writel(val, reg_addr);
iowrite32(val,reg_addr);
}
u32 gpmc_read_cs_reg(int cs, int idx)
{
void __iomem *reg_addr;
reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
//return __raw_readl(reg_addr);
return ioread32(reg_addr);
}
static void show_gpmc_reg(int cs)
{
u32 val;
int i=0;
for(i=0; i<7; i++)
{
val = gpmc_read_cs_reg(cs, GPMC_CS_CONFIG1 + i*4);
printk(KERN_INFO"gpmc cs%d GPMC_CS_CONFIG%d reg: 0x%08x\n",cs, i+1, val);
}
/*gpmc_cs_get_memconf(cs);
printk(KERN_INFO"\n");*/
}
static void gpmc_write_reg(int idx, u32 val)
{
//writel(val, gpmc_base + idx);
iowrite32(val, gpmc_base + idx);
}
static u32 gpmc_read_reg(int idx)
{
//return readl(gpmc_base + idx);
return ioread32(gpmc_base + idx);
}
static int am335_setup(void)
{
u32 val;
register_configuration();
sema_init(&sem,1);
gpmc_base = ioremap(GPMC_BASE_ADDR,SZ_4K);
printk("Getting Chip Select\n");
val = gpmc_read_reg(GPMC_REVISION);
printk("GPMC revision %d.%d\n", (val >> 4) & 0x0f, val & 0x0f);
gpmc_write_reg(GPMC_IRQENABLE, 0);
gpmc_write_reg(GPMC_TIMEOUT_CONTROL, 0);
gpmc_write_cs_reg(GPMC_CS, GPMC_CS_CONFIG1, gpmc_nand[0]);
gpmc_write_cs_reg(GPMC_CS, GPMC_CS_CONFIG2, gpmc_nand[1]);
gpmc_write_cs_reg(GPMC_CS, GPMC_CS_CONFIG3, gpmc_nand[2]);
gpmc_write_cs_reg(GPMC_CS, GPMC_CS_CONFIG4, gpmc_nand[3]);
gpmc_write_cs_reg(GPMC_CS, GPMC_CS_CONFIG5, gpmc_nand[4]);
gpmc_write_cs_reg(GPMC_CS, GPMC_CS_CONFIG6, gpmc_nand[5]);
// gpmc_write_cs_reg(GPMC_CS, GPMC_CS_CONFIG7, gpmc_nand[6]);
show_gpmc_reg(GPMC_CS);
if (gpmc_cs_request(GPMC_CS, SZ_2K, (unsigned long *)&mem_base) < 0)
{
printk(KERN_ERR "Failed request for GPMC mem for usrp_e\n");
return -1;
}
printk("Got CS1, address = %lx\n", mem_base);
if (!request_mem_region(mem_base, SZ_2K, "mem_fpga"))
{
printk(KERN_ERR "Request_mem_region failed.\n");
gpmc_cs_free(GPMC_CS);
return -1;
}
fpga_base = ioremap(mem_base, SZ_2K);
return 1;
}
static void fpga_relash(void)
{
release_mem_region(mem_base,SZ_2K);
//iounmap((void*)GPMC_BASE_ADDR);
gpmc_cs_free(GPMC_CS);
iounmap(fpga_base);
}
//---------------------------------
static long fpga_wrrd(struct file *filp,unsigned int cmd,unsigned long arg)
{
if(down_interruptible(&sem))
return -ERESTARTSYS;
if(cmd==255)
{
read_way=255;
}
else
{
read_way=cmd;
}
up(&sem);
return 1;
}
//------------------------//
static ssize_t fpga_write(struct file *filp,const char __user *buff,size_t count,loff_t *f_pos)
{
ssize_t status;
unsigned int data_usr[2];
if(count==0)
return 0;
//printk("the buff[0] is %d,and the buff[1] is %d count is %d\n",buff[0],buff[1],count);
if(down_interruptible(&sem))
return -ERESTARTSYS;
//printk("write is in\n");
if(copy_from_user(data_usr,buff,count))
{
status=-EFAULT;
goto fpga_write_done;
}
printk("the data_usr[0] is %d,and the data_usr[1] is %d\n",data_usr[0],data_usr[1]);
//printk("fpga_write start\n");
iowrite8(data_usr[1],fpga_base+data_usr[0]);
fpga_write_done:
up(&sem);
//printk("write finished\n");
return status;
}
static ssize_t fpga_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
unsigned int data_from_fpga[256];
unsigned int data_from_bit[2];
unsigned int data_fpga;
unsigned int hex_data[127];
int i;
if(down_interruptible(&sem))
return -ERESTARTSYS;
if(read_way==255)
{
for(i=0;i<256;i++)
{
data_from_fpga[i]=ioread8(fpga_base+i);
}
for(i=0;i<127;i++)
{
hex_data[i]=data_from_fpga[i*2+1]<<8 | data_from_fpga[i*2+0];
}
if(copy_to_user(buff,hex_data,sizeof(hex_data)))
{
return 1;
goto fpga_read_done;
}
}
else if(read_way != 255)
{
for(i=0;i<2;i++)
{
data_from_bit[i]=ioread8(fpga_base+i+read_way*2);
}
data_fpga=data_from_bit[1]<<8 | data_from_bit[0];
if(copy_to_user(buff,&data_fpga,sizeof(data_fpga)))
{
return 1;
goto fpga_read_done;
}
}
fpga_read_done:
up(&sem);
return 1;
}
//--------------------------
static const struct file_operations dev_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = fpga_wrrd,
.write=fpga_write,
.read=fpga_read,
};
static struct miscdevice misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = "fpga",
.fops = &dev_fops,
};
/*\C9豸\C7\FD\B6\AFģ\BF\E9\BC\D3\D4غ\AF\CA\FD*/
static int __init dev_init(void)
{
int ret;
am335_setup();
ret = misc_register(&misc);
printk("am335x initialized minor=%d\n",misc.minor);
return ret;
}
/*ģ\BF\E9ж\D4غ\AF\CA\FD*/
static void __exit dev_exit(void)
{
fpga_relash();
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_AUTHOR("<tq_rd@embedsky.net>");
MODULE_DESCRIPTION("module Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
/* test app*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#define FPGA_DEV "/dev/fpga"
#define PAGE_SIZE 2
int main(void)
{
int fd,i,res;
//unsigned char buf[PAGE_SIZE];
unsigned int data_in[2];
printf("GPMC Test version 1.0-BeagleBone Build on %s %s\n\r",__DATE__,__TIME__);
fd=open(FPGA_DEV,O_RDWR);
if(fd<0)
{
printf("Can't Open %s !!!\n\r",FPGA_DEV);
return -1;
}
for(i=0;i<30;i++){
data_in[0]=i+4; // the address
data_in[1]=i+1; //the data
write(fd,data_in,sizeof(data_in));
}
/*
data_in[0]=2;
data_in[1]=199;
write(fd,data_in,sizeof(data_in));
data_in[0]=3;
data_in[1]=0;
write(fd,data_in,sizeof(data_in));*/
close(fd);
return 0;
}