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

AM335x通过GPMC接口与FPGA通讯问题求教

板子是参考Beaglebone设计的,处理器为AM3352,CS0接NAND,型号为MT29F2G08,大小256MB;CS2接FPGA,通过GPMC与FPG使用异步通讯方式通讯,驱动主要参考网上资料http://blog.chinaunix.net/uid-24159092-id-3355612.html。

fpga驱动部分代码如下:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#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 1024*64 

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 //1 //20141013:GPMC_CS2#define GPMC_CS0 0x60#define GPMC_CS_SIZE 0x30

#define STNOR_GPMC_CONFIG1 0x00001010
#define STNOR_GPMC_CONFIG2 0x0002020f 
#define STNOR_GPMC_CONFIG3 0x0002020f
#define STNOR_GPMC_CONFIG4 0x000f000f
#define STNOR_GPMC_CONFIG5 0x00031f1f 
#define STNOR_GPMC_CONFIG6 0x04000fc2
#define STNOR_GPMC_CONFIG7 0x00000f41

static const u32 gpmc_nor[7] = {
STNOR_GPMC_CONFIG1,
STNOR_GPMC_CONFIG2,
STNOR_GPMC_CONFIG3,
STNOR_GPMC_CONFIG4,
STNOR_GPMC_CONFIG5,
STNOR_GPMC_CONFIG6,
STNOR_GPMC_CONFIG7
}

static ssize_t fpga_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{ ssize_t status = 0;
unsigned long p = *offp;
int i, nRdCnt;
unsigned short ushVal;

if(count > USER_BUFF_SIZE )
{
count = USER_BUFF_SIZE;
}
printk("fpga_read 1\n");
if (down_interruptible(&fpga_dev.sem))
return -ERESTARTSYS;

printk("fpga_read 2\n");

if ( (count%2) > 0 )
{
nRdCnt = count/2 + 1;
}
else
{
nRdCnt = count/2;
}
if (!fpga_dev.user_buff) {
printk("fpga_read: user_buff null\n");
return -EFAULT;
}
if ( !fpga_base )
{
printk("fpga_read: fpga_base null\n");
return -EFAULT;
}

for( i = 0; i < nRdCnt; i++)
{
ushVal = readw(fpga_base + i*2);
memcpy(fpga_dev.user_buff+i*2, &ushVal, 2);
}
printk("fpga_read 3\n");
if (copy_to_user(buff, fpga_dev.user_buff , count)) {
status = -EFAULT;
goto fpga_read_done;
}
fpga_read_done:
up(&fpga_dev.sem);
printk("fpga_read:status =%d\n", status);
return status;
}

static int __init fpga_init_cdev(void){ int error; u32 val; u32 base, size;

printk(KERN_ALERT"dan_fpga_init_cdev()\n"); 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 = 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);

/*Disable Chip Select*/
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, gpmc_nor[6]&(~GPMC_CONFIG7_CSVALID) );

if (!gpmc_cs_mem_enabled(GPMC_CS))
{ gpmc_cs_get_memconf(GPMC_CS, &base, &size);
printk("base= 0x%x, size=0x%x\n", base, size);
if (gpmc_cs_insert_mem(GPMC_CS, base, size) < 0)
{
BUG();
}
}
mdelay(20);
/* Delay for settling */
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]); /*Enable the config*/
//gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, gpmc_nor[6]);

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_4K, (unsigned long *)&mem_base) < 0)
{ printk(KERN_ERR "Failed request for GPMC mem for usrp_e\n"); return -1; }
printk("Got CS2, address = 0x%lx\n", mem_base); val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7); printk("GPMC_CS_CONFIG7 value 0x%x\n", val);

if ( !request_mem_region(mem_base, SZ_4K, "mem_fpga") ) { printk(KERN_ERR "Request_mem_region failed.\n"); gpmc_cs_free(GPMC_CS); return -1; } //获取对应数据指针
fpga_base = ioremap(mem_base, SZ_4K); if ( !fpga_base ) {
gpmc_cs_free(GPMC_CS); printk("fpga_base: Failed to ioremap memory\n");
return -1;
}
printk("fpga_base = 0x%p\n", fpga_base);

return 0;}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

现在的情况是Linux起来时关于GPMC部分的输出信息如下:

[ 0.170252] gpmc_probe
[ 0.170469] gpmc->phys_base=0x50000000, gpmc->memsize=0x2000, gpmc->io_base=0xd083c000
[ 0.170492] omap-gpmc omap-gpmc: GPMC revision 6.0
[ 0.170501] gpmc_mem_init
[ 0.170508] gpmc->mem_root.start=0x100000, gpmc->mem_root.end=0x3fffffff
[ 0.170521] gpmc_cs_get_memconf:cs=0
[ 0.170531] base= 0x8000000, size=0x10000000
[ 0.170540] gpmc_cs_insert_mem:cs=0
[ 0.170554] Registering NAND on CS0

而加载fpga.ko模块时输出相应的信息如下:

root@am335x:~# insmod /nfs/fpga.ko
[ 161.115858] fpga_init()
[ 161.118430] dan_fpga_init_cdev()
[ 161.126132] Getting Chip Select
[ 161.129674] GPMC revision 6.0
[ 161.133401] gpmc_cs_get_memconf:cs=2
[ 161.137137] base= 0x1000000, size=0x1000000
[ 161.141938] gpmc_cs_insert_mem:cs=2
[ 161.166079] GPMC_CS_CONFIG7 value 0xf01
[ 161.170134] gpmc_cs_request:cs=2
[ 161.182387] Got CS2, address = 0x1000000
[ 161.186477] GPMC_CS_CONFIG7 value 0xf41
[ 161.190846] fpga_base = 0xd09e8000

读GPMC几个CS对应的CONFIG7寄存器值如下:

root@am335x:~# devmem2 0x50000078 (CS0.CONFIG7)
/dev/mem opened.
Memory mapped at address 0x402c8000.
Read at address 0x50000078 (0x402c8078): 0x00000F48

root@am335x:~# devmem2 0x500000d8 (CS2.CONFIG7)
/dev/mem opened.
Memory mapped at address 0x40044000.
Read at address 0x500000D8 (0x400440d8): 0x00000F41

在devmem2读寄存器数据时超级终端有时会出现一些关于UBI的错误,比如

root@am335x:~# devmem2 [ 704.462440] UBI error: ubi_io_write: error -5 while writing 2048 bytes to PEB 952:73728, written 0 bytes
[ 704.472921] UBI warning: ubi_eba_write_leb: failed to write data to PEB 952
[ 704.480566] UBI: recover PEB 952, move data to PEB 1214
[ 704.489908] UBI error: ubi_io_read: error -74 (ECC error) while reading 512 bytes from PEB 952:2048, read 512 bytes
[ 704.501195] UBI: run torture test for PEB 1214
[ 704.505850] UBI warning: ubi_ro_mode: switch to read-only mode
[ 704.512295] UBI error: do_sync_erase: cannot erase PEB 1214, error -5
[ 704.519141] UBIFS error (pid 710): ubifs_leb_write: writing 2048 bytes to LEB 299:69632 failed, error -5
[ 704.529353] UBI error: erase_worker: failed to erase PEB 1214, error -5
[ 704.536495] UBI: mark PEB 1214 as bad
[ 704.540519] UBIFS warning (pid 710): ubifs_ro_mode: switched to read-only mode, error -5
[ 704.549059] UBI error: ubi_io_mark_bad: read-only mode
[ 704.554693] Backtrace:[ 704.557156] UBI error: do_work: work failed with error code -30
[ 704.563735][ 704.565335] [<c0017c2c>] (dump_backtrace+0x0/0x110) from [<c037f600>] (dump_stack+0x18/0x1c)
0[ 704.574709] UBI error: ubi_thread: ubi_bgt0d: work failed with error code -30
[ 704.582482] r6:0000012b r5:fffffffb r4:60008400 r3:00000002
[ 704.588667] [<c037f5e8>] (dump_stack+0x0/0x1c) from [<c0190044>] (ubifs_ro_mode+0x74/0x78)
[ 704.597640] [<c018ffd0>] (ubifs_ro_mode+0x0/0x78) from [<c0190258>] (ubifs_leb_write+0x9c/0xa4)
[ 704.607057] r4:cfb9e000 r3:00000002
[ 704.611031] [<c01901bc>] (ubifs_leb_write+0x0/0xa4) from [<c0190a3c>] (ubifs_wbuf_sync_nolock+0x90/0x178)
[ 704.621351] r8:00000001 r7:00000728 r6:00000800 r5:cfb9e000 r4:cf05e2a0
[ 704.628625] [<c01909ac>] (ubifs_wbuf_sync_nolock+0x0/0x178) from [<c0190cb4>] (ubifs_bg_wbufs_sync+0xd0/0x170)
[ 704.639436] r7:000000a0 r6:cf05e2a0 r5:00000001 r4:cfb9e000
[ 704.645662] [<c0190be4>] (ubifs_bg_wbufs_sync+0x0/0x170) from [<c0199558>] (ubifs_bg_thread+0x94/0x1a4)
[ 704.655901] [<c01994c4>] (ubifs_bg_thread+0x0/0x1a4) from [<c0059ea4>] (kthread+0x90/0x94)
[ 704.664734] r7:00000013 r6:c01994c4 r5:cfb9e000 r4:cf81dd60
[ 704.671015] [<c0059e14>] (kthread+0x0/0x94) from [<c0041e28>] (do_exit+0x0/0x728)
[ 704.678959] r6:c0041e28 r5:c0059e14 r4:cf81dd60
[ 704.684021] UBIFS error (pid 710): ubifs_bg_wbufs_sync: cannot sync write-buffer, error -5

还有就是执行fpga模块读数据双口RAM测试时,会卡在readw(fpga_base+i)语句上,超级终端无法再操作,只能掉电复位板子了。

也看过斑上关于AM335x GPMC地址区域划分问题,根据理解我现在的区域划分相当于是这样的:

NAND: base =0x8000000, size=0x10000000

FPGA: base=0x1000000,size=0x1000000

NAND和FPGA之间不存在地址区域重叠的问题呀,请问是什么原因呀?

Frank Zhang2:

补充:软件版本为linux-3.2.0-04.06.00.08

在看gpmc驱动时,看到在关于地址划分计算时有这么一段代码:

static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)

{

         u32 l;

         u32 mask;

 

         l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);

         *base = (l & 0x3f) << GPMC_CHUNK_SHIFT;

         mask = (l >> 8) & 0x0f;

         *size = (1 << GPMC_SECTION_SHIFT) – (mask << GPMC_CHUNK_SHIFT);

         if (cpu_is_am33xx()) {

                   *base = 0x8000000;

                   *size = 0x10000000;

         }

}

按照理解GPMC的每个CS都是根据CONFIG7的配置信息获得对应的地址空间范围,但是这里为什么专门针对am33xx系列做了一个特别的处理,而这个地址正好又是NAND的base和size,而这与CS0的CONFIG7数据值又存在相互矛盾的地方(0x00000F48,相当于base=0x80000000, size=0x1000000),请问这是怎么回事呢?

Frank Zhang2:

补充:软件版本为linux-3.2.0-04.06.00.08

在看gpmc驱动时,看到在关于地址划分计算时有这么一段代码:

static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)

{

         u32 l;

         u32 mask;

 

         l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);

         *base = (l & 0x3f) << GPMC_CHUNK_SHIFT;

         mask = (l >> 8) & 0x0f;

         *size = (1 << GPMC_SECTION_SHIFT) – (mask << GPMC_CHUNK_SHIFT);

         if (cpu_is_am33xx()) {

                   *base = 0x8000000;

                   *size = 0x10000000;

         }

}

按照理解GPMC的每个CS都是根据CONFIG7的配置信息获得对应的地址空间范围,但是这里为什么专门针对am33xx系列做了一个特别的处理,而这个地址正好又是NAND的base和size,而这与CS0的CONFIG7数据值又存在相互矛盾的地方(0x00000F48,相当于base=0x80000000, size=0x1000000),请问这是怎么回事呢?

Frank Zhang2:

补充:软件版本为linux-3.2.0-04.06.00.08

在看gpmc驱动时,看到在关于地址划分计算时有这么一段代码:

static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)

{

u32 l;

u32 mask;

l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);

*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;

mask = (l >> 8) & 0x0f;

*size = (1 << GPMC_SECTION_SHIFT) – (mask << GPMC_CHUNK_SHIFT);

if (cpu_is_am33xx()) {

*base = 0x8000000;

*size = 0x10000000;

}

}

按照理解GPMC的每个CS都是根据CONFIG7的配置信息获得对应的地址空间范围,但是这里为什么专门针对am33xx系列做了一个特别的处理,而这个地址正好又是NAND的base和size,而这与CS0的CONFIG7数据值又存在相互矛盾的地方(0x00000F48,相当于base=0x80000000, size=0x1000000),请问这是怎么回事呢?

Frank Zhang2:

补充:软件版本为linux-3.2.0-04.06.00.08

在看gpmc驱动时,看到在关于地址划分计算时有这么一段代码:

static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)

{

u32 l;

u32 mask;

l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);

*base = (l & 0x3f) << GPMC_CHUNK_SHIFT;

mask = (l >> 8) & 0x0f;

*size = (1 << GPMC_SECTION_SHIFT) – (mask << GPMC_CHUNK_SHIFT);

if (cpu_is_am33xx()) {

*base = 0x8000000;

*size = 0x10000000;

}

}

按照理解GPMC的每个CS都是根据CONFIG7的配置信息获得对应的地址空间范围,但是这里为什么专门针对am33xx系列做了一个特别的处理,而这个地址正好又是NAND的base和size,而这与CS0的CONFIG7数据值又存在相互矛盾的地方(0x00000F48,相当于base=0x80000000, size=0x1000000),请问这是怎么回事呢?

user4131006:

am335x上:

0x8000000 是在EMIF0区 

nand flash应该是接在 GPMC吧?

Frank Zhang2:

回复 user4131006:

EMIF0 SDRAM区间是:0x8000 0000 – 0xBFFF FFFF呀;

NAND是接在GPMC,跟FPGA复用部分管脚的呀;

NAND的地址是0x800 0000,是在GMPC地址范围内的呀;本身如果不接FPGA,NAND上的文件系统读写也是正常的;

我的疑问按照gpmc_cs_get_memconf(函数去理解的话:

NAND的实际基地址为0x800 0000, 大小为256MB;但是NAND对应CS0的CONFIG7计算出来就变成基地址0x800 0000,大小为16MB;怎么会这样呢?

user4131006:

回复 Frank Zhang2:

抱歉,有句话看的不仔细,把0x800_0000看成0x8000_0000了

继续正题:

我觉得gpmc_cs_get_memconf()函数写的不严谨吧,(或者am33xx内部设计有玄机?)应该以GPMC_CONFIG7_n的mask addr字段为准吧

Steven Liu1:

回复 Frank Zhang2:

我不是太明白你前面描述的问题点是什么,先针对你这个回复中提到的问题:

NAND 实际大小是256MB;但是对应的CS0的config7配置,你看到了基址配置是正确的,但是空间大小配的只有16MB,所以认为这里是有冲突的是吧?

请参考回复如下:

首先,GPMC对于接入的设备可以分成两类:

一类是属于nor flash这样的类型,可以通过地址线直接寻址,比如你接入的FPGA等设备都是属于这个种类,这个里面对相应的片选进行config7配置的时候,需要你分配基址,还需要注意空间大小的分布,因为地址线寻址的时候,就是按照你划分的空间大小来访问数据的;

另外一类是属于nand flash这样的,需要通过stream mode的方式来进行通信,换言之,这种stream mode的通信方式和那种地址线直接寻址是不一样的,你不再是通过地址线进行数据访问,而是通过相关的command来进行数据访问。所以你通过config7规划的这个地址空间,和真正的NAND flash的地址空间没有关系。最小为16MB,所以避免浪费,就给16MB咯。

换个角度去想,你使用的NAND flash不管是256M、还是8G,他都是通过接口命令进行数据读取的,哪里有地址线一说呢。

如果还有疑问或其他问题,请再post出来。

Frank Zhang2:

回复 Steven Liu1:

谢谢Steven。

昨天参考你写的GPMC与FPGA测试文档,在CCS中调试,发现是硬件上设计存在问题引起的;CS2对应CONFIG配置也存在问题,现在问题已经解决,感谢大家的关注和解答。

还有之前对NAND设备的理解也有问题,无意中跟NOR设备等同了,所以纠结于GPMC的地址分配了。

xiong shaoyi:

回复 Frank Zhang2:

你好Frank Zhang2 

对于你这个问题,我也很迷惑,我使用的是gpmc外扩dm9000, 地址线接了cs2,然后在dm9000.c中的dm9000_probe添加了如下代码

unsigned long mem_base=gpmc_init(DM9000_CS);//获取基地址

/***********************************************///add by shaoyi QQ:402097953/***********************************************/static unsigned long gpmc_init( int GPMC_CS ){ unsigned int val; unsigned int base, size; unsigned long mem_base;

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);

/*Disable Chip Select*/ gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, gpmc_dm9000[6]&(~GPMC_CONFIG7_CSVALID) );

if (!gpmc_cs_mem_enabled(GPMC_CS)) { gpmc_cs_get_memconf(GPMC_CS, &base, &size); printk("base= 0x%x, size=0x%x\n", base, size); if (gpmc_cs_insert_mem(GPMC_CS, base, size) < 0) BUG(); }

mdelay(20); /* Delay for settling */ gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG1, gpmc_dm9000[0]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG2, gpmc_dm9000[1]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG3, gpmc_dm9000[2]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG4, gpmc_dm9000[3]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG5, gpmc_dm9000[4]); gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG6, gpmc_dm9000[5]); /*Enable the config*/ gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG7, gpmc_dm9000[6]);

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_4K, (unsigned long *)&mem_base) < 0) { printk("Failed request for GPMC mem for usrp_e\n"); return -1; } printk("Got CS%d, mem_base = 0x%lx\n",GPMC_CS, mem_base); val = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7); printk("GPMC_CS_CONFIG7 value 0x%x\n", val);

/* if ( !request_mem_region(mem_base, SZ_4K, "mem_fpga") ) { printk(KERN_ERR "Request_mem_region failed.\n"); gpmc_cs_free(GPMC_CS); return -1; } */ return mem_base;}

结果在dm9000_probe申请基地址的时候出错,

Unable to handle kernel paging request at virtual address 01000000

还有个迷惑就是

gpmc_cs_get_memconf(GPMC_CS, &base, &size);

gpmc_cs_request(GPMC_CS, SZ_4K, (unsigned long *)&mem_base) 

GPMC_CS_CONFIG7配置基地址

这三种基地址分别什么意思呢?难道不应该一样?

我的QQ402097953

赞(0)
未经允许不得转载:TI中文支持网 » AM335x通过GPMC接口与FPGA通讯问题求教
分享到: 更多 (0)