Other Parts Discussed in Thread: AM3352, SYSCONFIG
板子是参考Beaglebone设计的,处理器为AM3352,CS0接NAND,型号为MT29F2G08,大小256MB;CS2接FPGA,通过GPMC与FPG使用异步通讯方式通讯,驱动主要参考网上资料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之间不存在地址区域重叠的问题呀,请问是什么原因呀?