TI中文支持网
TI专业的中文技术问题搜集分享网站

AM3352的GPMC总线下挂FPGA设备,执行FPGA读操作时,gpmc_ad0.gpmc_ad0和片选无信号输出

试验用gpmc总线片选2外接FPGA,采用地址、数据复用,同步访问的模式。总线位宽使用16位方式:
引脚定义如下:

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, 没有采用设备树

赞(0)
未经允许不得转载:TI中文支持网 » AM3352的GPMC总线下挂FPGA设备,执行FPGA读操作时,gpmc_ad0.gpmc_ad0和片选无信号输出
分享到: 更多 (0)