am3358——GPMC——参考网上驱动

作者:chenzhufly QQ:36886052 ( 转载请注明出处)

转自: http://bbs.eeworld.com.cn/thread-333652-1-1.html


1. 参考资料

  • AM335x ARM® Cortex™-A8 Microprocessors Technical Reference Manual
  • BeagleBone_revA3_SCH.pdf
  • BeagleBone_revA3_SRM.pdf
  • BeagleBone_revA3_BOM.xls


2. 测试的硬件环境: Beaglebone + EE_FPGA



3. 硬件连接图:用的是GPMC to 16-Bit Nonmultiplexed Memory

 

4. 设计思路

  • 初始化GPMC相关引脚
  • 完成GPMC驱动设计
  • 完成GPMC应用设计

5. 初始化相关代码,主要修改并编译

/linux-3.1.0-psp04.06.00.03.sdk/arch/arm/mach-omap2/board-am335xevm.c

配置相关引脚

  1. /* Pin mux for fpga module */
    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},

    {"lcd_data0.gpmc_a0", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data1.gpmc_a1", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data2.gpmc_a2", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data3.gpmc_a3", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data4.gpmc_a4", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data5.gpmc_a5", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data6.gpmc_a6", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data7.gpmc_a7", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_vsync.gpmc_a8", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_hsync.gpmc_a9", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_pclk.gpmc_a10", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_ac_bias_en.gpmc_a11", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data8.gpmc_a12", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data9.gpmc_a13", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data10.gpmc_a14", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"lcd_data11.gpmc_a15", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT 
    | AM33XX_PULL_DISA}, 
    {"gpmc_advn_ale.gpmc_advn_ale", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
    {"gpmc_oen_ren.gpmc_oen_ren", 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_csn1.gpmc_csn1", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
    {"gpmc_clk.gpmc_clk", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
    {NULL, 0},
    };
复制代码


  1. static void evm_fpga_init(int evm_id, int profile)
    {
    setup_pin_mux(fpga_pin_mux);
    }
复制代码


  1. /* Beaglebone Rev A3 and after */
    static struct evm_dev_cfg beaglebone_dev_cfg[] = {
    {mii1_init, DEV_ON_BASEBOARD, PROFILE_NONE},
    {usb0_init, DEV_ON_BASEBOARD, PROFILE_NONE},
    {usb1_init, DEV_ON_BASEBOARD, PROFILE_NONE},
    {mmc0_init, DEV_ON_BASEBOARD, PROFILE_NONE},
    {evm_fpga_init, DEV_ON_BASEBOARD, PROFILE_NONE},
    {NULL, 0, 0},
复制代码


6. GPMC驱动设计


  1. /*
    Char device driver fpga.
    Do a global replace of 'fpga' with your driver name.
    */

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <asm/uaccess.h>
    #include <linux/string.h>
    #include <linux/kernel.h>
    #include <linux/device.h>
    #include <linux/slab.h>

    #include <plat/gpmc.h>
    #include "plat/gpio.h"
    #include "plat/dma.h"

    #include "asm/uaccess.h"
    #include "asm/io.h"
    #include "asm/atomic.h"


    #define USER_BUFF_SIZE 128


    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 1
    #define GPMC_CS0 0x60
    #define GPMC_CS_SIZE 0x30
    #define STNOR_GPMC_CONFIG1 0x28601000
    #define STNOR_GPMC_CONFIG2 0x00011001
    #define STNOR_GPMC_CONFIG3 0x00020201
    #define STNOR_GPMC_CONFIG4 0x08031003
    #define STNOR_GPMC_CONFIG5 0x000f1111
    #define STNOR_GPMC_CONFIG6 0x0f030080
    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;

    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("fpga_write \n");
    for (i = 0; i < len; i=i+2) {
    tmp = fpga_dev.user_buff
     | 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.
    */
    if (*offp > 0)
    return 0;

    if (down_interruptible(&fpga_dev.sem)) 
    return -ERESTARTSYS;

    strcpy(fpga_dev.user_buff, "fpga driver data goes here\n");

    len = strlen(fpga_dev.user_buff);

    if (len > count)
    len = count;

    if (copy_to_user(buff, fpga_dev.user_buff, len)) {
    status = -EFAULT;
    goto fpga_read_done;
    }

    fpga_read_done:

    up(&fpga_dev.sem);

    return status;
    }

    static int fpga_open(struct inode *inode, struct file *filp)
    {
    int status = 0;

    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_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 = 0xf64;
    // gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, val);
    //gpmc_base = ioremap(GPMC_BASE_ADDR, SZ_4K);
    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_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);

    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 CS0, 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 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_2K);
    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");
复制代码


7. GPMC应用程序设计,目前只实现了beaglebone向FPGA写的流程

  1. #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <errno.h>

    #define FPGA_DEV "/dev/fpga"
    #define PAGE_SIZE 10


    int main(void)
    {
    int fd,i,res;
    unsigned char buf[PAGE_SIZE];

    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<sizeof(buf);i++)
    {
    buf = i;
    }

    write(fd,&buf,PAGE_SIZE);

    close(fd);
    return 0;

    }
复制代码


8. FPGA相关设计

ARM和FPGA的管脚分配如下图所示
 

FPGA简要代码如下所示:
  1. module interface_test
    (
    input clk,
    input ebgcs, 
    input eboe, 
    input ebwe, 
    input [11:0]ebaddr,

    input [15:0]ebdata,

    output led,
    output led1

    );


    wire [15:0] ram_q;
    wire ram_wren;
    wire ram_rden;

    assign ram_wren = ((ebgcs == 1'b0) && (ebwe == 1'b0)) ? 1'b1 : 1'b0;
    assign ram_rden = ((ebgcs == 1'b0) && (eboe == 1'b0)) ? 1'b1 : 1'b0;

    TestRam testram_inst (
    .clock ( clk),
    .data ( ebdata[15:0] ),
    .rdaddress ( ebaddr[11:1] ),
    .rden ( ram_rden ),
    .wraddress ( ebaddr[11:1] ),
    .wren ( ram_wren ),
    .q ( ram_q[15:0] )
    );

    wire ARM_READ_REG_EN;
    assign ARM_READ_REG_EN = ((ebgcs == 1'b0) && (eboe == 1'b0) && (ebaddr[11:1] == 11'b111_1111_1111)) ? 1'b1 : 1'b0;
    assign led1 = ARM_READ_REG_EN ? 1'b1 :
    ram_rden ? ram_q[0] : 1'bz;

    endmodule
复制代码


FPGA管脚分配如下所示:
  1. set_location_assignment PIN_89 -to ebaddr[0]
    set_location_assignment PIN_90 -to ebaddr[1]
    set_location_assignment PIN_87 -to ebaddr[2]
    set_location_assignment PIN_88 -to ebaddr[3]
    set_location_assignment PIN_84 -to ebaddr[4]
    set_location_assignment PIN_86 -to ebaddr[5]
    set_location_assignment PIN_81 -to ebaddr[6]
    set_location_assignment PIN_82 -to ebaddr[7]
    set_location_assignment PIN_63 -to ebaddr[8]
    set_location_assignment PIN_67 -to ebaddr[9]
    set_location_assignment PIN_64 -to ebaddr[10]
    set_location_assignment PIN_68 -to ebaddr[11]


    set_location_assignment PIN_60 -to ebdata[0]
    set_location_assignment PIN_59 -to ebdata[1]
    set_location_assignment PIN_28 -to ebdata[2]
    set_location_assignment PIN_30 -to ebdata[3]
    set_location_assignment PIN_58 -to ebdata[4]
    set_location_assignment PIN_57 -to ebdata[5]
    set_location_assignment PIN_24 -to ebdata[6]
    set_location_assignment PIN_27 -to ebdata[7]
    set_location_assignment PIN_47 -to ebdata[8]
    set_location_assignment PIN_40 -to ebdata[9]
    set_location_assignment PIN_41 -to ebdata[10]
    set_location_assignment PIN_45 -to ebdata[11]
    set_location_assignment PIN_39 -to ebdata[12]
    set_location_assignment PIN_37 -to ebdata[13]
    set_location_assignment PIN_44 -to ebdata[14]
    set_location_assignment PIN_43 -to ebdata[15]

    set_location_assignment PIN_61 -to ebgcs
    set_location_assignment PIN_33 -to eboe
    set_location_assignment PIN_35 -to ebwe


    set_location_assignment PIN_23 -to clk
    set_location_assignment PIN_31 -to led
    set_location_assignment PIN_34 -to led1
复制代码


9. 测试结果
BeagleBone向EE_FPGA写0,1,2,3,4,5,6,7,8,9;通过signaltap抓的结果。
 

备注: 实际项目中只使用了其初始化,应用程序只操作内存就好。GPMC其实很简单,就是只要向相应的GPMC_CS所申请的内存中丢数据,GPMC相应的片选会自动拉低。


  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值