static struct pinmux_config fpga_pin_mux[] = {
{"gpmc_ad0.gpmc_ad0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad1.gpmc_ad1", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad2.gpmc_ad2", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad3.gpmc_ad3", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad4.gpmc_ad4", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad5.gpmc_ad5", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad6.gpmc_ad6", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad7.gpmc_ad7", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad8.gpmc_ad8", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad9.gpmc_ad9", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad10.gpmc_ad10", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad11.gpmc_ad11", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad12.gpmc_ad12", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad13.gpmc_ad13", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad14.gpmc_ad14", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad15.gpmc_ad15", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_wait0.gpmc_wait0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_wpn.gpmc_wpn", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_csn1.gpmc_clk", OMAP_MUX_MODE1 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_oen_ren.gpmc_oen_ren", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{"gpmc_advn_ale.gpmc_advn_ale", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{"gpmc_wen.gpmc_wen", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{"gpmc_ben0_cle.gpmc_ben0_cle", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{"gpmc_csn2.gpmc_csn2", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{NULL, 0},
};
初始化引脚函数evm_fpga_init,并将其添加到evm_dev_cfg初始化列表。
static void evm_fpga_init(int evm_id, int profile)
{
setup_pin_mux(fpga_pin_mux);
}
并在
static struct evm_dev_cfg m3352_dev_cfg[] = {
{
…
{evm_fpga_init, DEV_ON_BASEBOARD, PROFILE_NONE }, //0521
…
{NULL, 0, 0},
};
FPGA驱动代码如下:
struct fpga_dev{
dev_t devt;
struct cdev cdev;
struct semaphore sem;
struct class *class;
char *user_buff;
};
static struct fpga_dev fpga_dev;
unsigned long mem_base;
static void __iomem *fpga_base;
static void __iomem *gpmc_base;
/* 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 2
#define GPMC_CS0 0x60
#define GPMC_CS_SIZE 0x30
#define STNOR_GPMC_CONFIG1 0x28001200
#define STNOR_GPMC_CONFIG2 0x00070900
#define STNOR_GPMC_CONFIG3 0x00000000
#define STNOR_GPMC_CONFIG4 0x06010701
#define STNOR_GPMC_CONFIG5 0x0009070C
#define STNOR_GPMC_CONFIG6 0x08000000
static const u32 gpmc_nor[7] ={
STNOR_GPMC_CONFIG1,
STNOR_GPMC_CONFIG2,
STNOR_GPMC_CONFIG3,
STNOR_GPMC_CONFIG4,
STNOR_GPMC_CONFIG5,
STNOR_GPMC_CONFIG6,
0
};
static ssize_t fpga_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos)
{
ssize_t status;
size_t len = USER_BUFF_SIZE – 1;
int i,tmp;
printk("[Drv]fpga_write start\n");
if (count == 0)
return 0;
if (down_interruptible(&fpga_dev.sem))
return -ERESTARTSYS;
if (len > count)
len = count;
memset(fpga_dev.user_buff, 0, USER_BUFF_SIZE);
if (copy_from_user(fpga_dev.user_buff, buff, len)) {
status = -EFAULT;
goto fpga_write_done;
}
/* do something with the user data */
printk("[Drv]fpga_write:0x%x\n", fpga_base);
for (i = 0; i < len; i=i+2) {
tmp = (fpga_dev.user_buff[i]) | (fpga_dev.user_buff[i+1] << 8); writew(tmp, fpga_base+i);
}
for (i = 0; i < len; i++)
{
printk("0x%x ",fpga_dev.user_buff); }
printk("\n");
fpga_write_done:
up(&fpga_dev.sem);
return status;
}
static ssize_t fpga_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
ssize_t status;
size_t len;
//int i,tmp;
/* Generic user progs like cat will continue calling until we return zero. So if *offp != 0, we know this is at least the
second call.
*/
printk("[Drv]fpga_read start\n");
if (*offp > 0)
return 0;
printk("[Drv]before read down sem\n");
if (down_interruptible(&fpga_dev.sem)) return -ERESTARTSYS;
printk("[Drv]after read down sem\n");
memset(fpga_dev.user_buff,0,USER_BUFF_SIZE);
printk("[Drv]before read:0x%x\n", fpga_base);
strcpy(fpga_dev.user_buff, "fpga driver data goes here\n");
fpga_dev.user_buff[0]= readb(fpga_base);
fpga_dev.user_buff[1]= readb(fpga_base + 1);
printk("[Drv]after read:0x%x\n", fpga_base);
len = strlen(fpga_dev.user_buff);
printk("[Drv]read len:%d\n", len);
if (len > count)
len = count;
if (copy_to_user(buff, fpga_dev.user_buff, len)) {
printk("[Drv]copy_to_user fail\n");
status = -EFAULT;
goto fpga_read_done;
}
printk("[Drv]copy_to_user succ\n");
fpga_read_done:
up(&fpga_dev.sem);
return status;
}
static int fpga_open(struct inode *inode, struct file *filp)
{
int status = 0;
printk("[Drv]fpga_open start\n");
if (down_interruptible(&fpga_dev.sem)) return -ERESTARTSYS;
if (!fpga_dev.user_buff)
{
fpga_dev.user_buff = kmalloc(USER_BUFF_SIZE, GFP_KERNEL);
if (!fpga_dev.user_buff)
{
printk(KERN_ALERT "fpga_open: user_buff alloc failed\n");
status = -ENOMEM;
}
}
up(&fpga_dev.sem);
return status;
}
static const struct file_operations fpga_fops ={
.owner = THIS_MODULE,
.open = fpga_open,
.read = fpga_read,
.write = fpga_write,
};
static int __init fpga_init_cdev(void)
{
int error;
u32 val;
fpga_dev.devt = MKDEV(0, 0);
error = alloc_chrdev_region(&fpga_dev.devt, 0, 1, "fpga");
if (error)
{
printk(KERN_ALERT "alloc_chrdev_region() failed: %d\n", error);
return error;
}
// 初始化cdev
cdev_init(&fpga_dev.cdev, &fpga_fops);
fpga_dev.cdev.owner = THIS_MODULE;
// 注册设备
error = cdev_add(&fpga_dev.cdev, fpga_dev.devt, 1);
if (error)
{
printk(KERN_ALERT "cdev_add() failed: %d\n", error);
unregister_chrdev_region(fpga_dev.devt, 1);
return error;
}
printk("Getting Chip Select\n");
val = gpmc_read_reg(GPMC_REVISION);
printk("GPMC revision %d.%d\n", (val >> 4) & 0x0f, val & 0x0f);
//val = gpmc_read_reg(GPMC_REVISION);
//gpmc_write_reg(GPMC_CONFIG, (val & 0xFFFFFFFD));
//0614 add
gpmc_write_reg(GPMC_IRQENABLE, 0);
gpmc_write_reg(GPMC_TIMEOUT_CONTROL, 0);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG1, gpmc_nor[0]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG2, gpmc_nor[1]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG3, gpmc_nor[2]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG4, gpmc_nor[3]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG5, gpmc_nor[4]);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG6, gpmc_nor[5]);
val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7);
printk("GPMC_CS_CONFIG7 value 0x%x\n", val);
// 申请GPMC内存
if (gpmc_cs_request(GPMC_CS, SZ_16M, (unsigned long *)&mem_base) < 0) {
printk(KERN_ERR "Failed request for GPMC mem for usrp_e\n");
return -1;
}
printk("Got CS2, address = %lx\n", mem_base);
if (!request_mem_region(mem_base, SZ_16M, "mem_fpga")) {
printk(KERN_ERR "Request_mem_region failed.\n");
gpmc_cs_free(GPMC_CS);
return -1;
}
fpga_base = ioremap(mem_base, SZ_16M);
printk("Got CS2, fpga_base = %lx\n", fpga_base);
val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7);
val |= GPMC_CONFIG7_CSVALID;
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, val);
printk("GPMC_CONFIG %08x\n", gpmc_read_reg(GPMC_CONFIG));
printk("GPMC_STATUS %08x\n", gpmc_read_reg(GPMC_STATUS));
printk("GPMC_SYSCONFIG %08x\n", gpmc_read_reg(GPMC_SYSCONFIG));
printk("GPMC_IRQENABLE %08x\n", gpmc_read_reg(GPMC_IRQENABLE));
printk("GPMC_TIMEOUT_CONTROL %08x\n", gpmc_read_reg(GPMC_TIMEOUT_CONTROL));
printk("GPMC_CS_CONFIG1 %08x\n", gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG1));
printk("GPMC_CS_CONFIG2 %08x\n", gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG2));
printk("GPMC_CS_CONFIG3 %08x\n", gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG3));
printk("GPMC_CS_CONFIG4 %08x\n", gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG4));
printk("GPMC_CS_CONFIG5 %08x\n", gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG5));
printk("GPMC_CS_CONFIG6 %08x\n", gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG6));
printk("GPMC_CS_CONFIG7 %08x\n", gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7));
return 0;
}
static int __init fpga_init_class(void)
{
struct device *device;
fpga_dev.class = class_create(THIS_MODULE, "fpga");
if (IS_ERR(fpga_dev.class))
{
printk(KERN_ALERT "class_create(fpga) failed\n");
return PTR_ERR(fpga_dev.class);
}
device = device_create(fpga_dev.class, NULL, fpga_dev.devt, NULL, "fpga");
if (IS_ERR(device))
{
class_destroy(fpga_dev.class);
return PTR_ERR(device);
}
return 0;
}
static int __init fpga_init(void)
{
printk(KERN_INFO "fpga_init()\n");
memset(&fpga_dev, 0, sizeof(struct fpga_dev));
sema_init(&fpga_dev.sem, 1);
if (fpga_init_cdev())
goto init_fail_1;
if (fpga_init_class())
goto init_fail_2;
return 0;
init_fail_2:
cdev_del(&fpga_dev.cdev);
unregister_chrdev_region(fpga_dev.devt, 1);
init_fail_1:
return -1;
}
module_init(fpga_init);
static void __exit fpga_exit(void)
{
printk(KERN_INFO "fpga_exit()\n");
device_destroy(fpga_dev.class, fpga_dev.devt);
class_destroy(fpga_dev.class);
cdev_del(&fpga_dev.cdev);
unregister_chrdev_region(fpga_dev.devt, 1);
release_mem_region(mem_base, SZ_16M);
gpmc_cs_free(GPMC_CS);
iounmap(fpga_base);
if (fpga_dev.user_buff)
kfree(fpga_dev.user_buff);
}
module_exit(fpga_exit);
MODULE_AUTHOR("chenzhufly");
MODULE_DESCRIPTION("fpga driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION("0.1");
内核启动后,成功添加FPGA设备节点“/dev/fpga”,各寄存器数值下,
Got CS2, address = 1000000
Got CS2, fpga_base = e1000000
GPMC_CONFIG 00000012
GPMC_STATUS 00000101
GPMC_SYSCONFIG 00000009
GPMC_IRQENABLE 00000000
GPMC_TIMEOUT_CONTROL 00000000
GPMC_CS_CONFIG1 28001200
GPMC_CS_CONFIG2 00070900
GPMC_CS_CONFIG3 00000000
GPMC_CS_CONFIG4 06010701
GPMC_CS_CONFIG5 0009070c
GPMC_CS_CONFIG6 08000000
GPMC_CS_CONFIG7 00000f41
问题:
调用打开FPGA设备节点并执行读操作时,fpga_read函数正确执行,但是在gpmc_ad1端无法抓取信号
user5363068:
更正,内核启动后,GPMC_CS_CONFIG1寄存器数值为28001200
Shine:
回复 user5363068:
请问设备树里做修改了吗?
user5363068:
回复 Shine:
linux设备版本是3.2.0, 没有采用设备树