Nandflash的驱动加载

分析at91sam9260ek的代码示范。

(1)板级初始化。

Board-sam9260ek.c中的初始化调用:

static void __init ek_board_init(void)
{
。。。代码略
/* NAND */
	ek_add_device_nand();
。。。代码略
}

ek_add_device_nand()的代码:

/*
 * NAND flash
 */
static struct mtd_partition __initdata ek_nand_partition[] = {   //flash中的分区信息
	{
		.name	= "Partition 1",
		.offset	= 0,
		.size	= SZ_256K,
	},
	{
		.name	= "Partition 2",
		.offset	= MTDPART_OFS_NXTBLK,
		.size	= MTDPART_SIZ_FULL,
	},
};

//得到Nandflash分区
static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
{
	*num_partitions = ARRAY_SIZE(ek_nand_partition);
	return ek_nand_partition;
}

//Nandflash使用的私有数据类型atmel_nand_data
static struct atmel_nand_data __initdata ek_nand_data = {
	.ale		= 21,
	.cle		= 22,
//	.det_pin	= ... not connected
	.rdy_pin	= AT91_PIN_PC13,
	.enable_pin	= AT91_PIN_PC14,
	.partition_info	= nand_partitions,  //得到Nandflash分区
#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
	.bus_width_16	= 1,    //总线宽度
#else
	.bus_width_16	= 0,
#endif
};

//SMC配置
static struct sam9_smc_config __initdata ek_nand_smc_config = {
	.ncs_read_setup		= 0,
	.nrd_setup		= 1,
	.ncs_write_setup	= 0,
	.nwe_setup		= 1,

	.ncs_read_pulse		= 3,
	.nrd_pulse		= 3,
	.ncs_write_pulse	= 3,
	.nwe_pulse		= 3,

	.read_cycle		= 5,
	.write_cycle		= 5,

	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
	.tdf_cycles		= 2,
};

static void __init ek_add_device_nand(void)
{
	/* setup bus-width (8 or 16) */
	if (ek_nand_data.bus_width_16)
		ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
	else
		ek_nand_smc_config.mode |= AT91_SMC_DBW_8;

	/* configure chip-select 3 (NAND) */
	sam9_smc_configure(3, &ek_nand_smc_config);

	at91_add_device_nand(&ek_nand_data); //跳到At91sam9260_devices.c中执行
}

At91sam9260_devices.c中的代码:

static struct atmel_nand_data nand_data;

#define NAND_BASE	AT91_CHIPSELECT_3

static struct resource nand_resources[] = {
	[0] = {
		.start	= NAND_BASE,
		.end	= NAND_BASE + SZ_256M - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91_BASE_SYS + AT91_ECC,
		.end	= AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,
		.flags	= IORESOURCE_MEM,
	}
};

static struct platform_device at91sam9260_nand_device = {
	.name		= "atmel_nand",
	.id		= -1,
	.dev		= {
				.platform_data	= &nand_data,
	},
	.resource	= nand_resources,
	.num_resources	= ARRAY_SIZE(nand_resources),
};

void __init at91_add_device_nand(struct atmel_nand_data *data)
{
	unsigned long csa;

	if (!data)
		return;

	csa = at91_sys_read(AT91_MATRIX_EBICSA);
	at91_sys_write(AT91_MATRIX_EBICSA,
                csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);

	/* enable pin */
	if (data->enable_pin)
		at91_set_gpio_output(data->enable_pin, 1); 
	/* ready/busy pin */
	if (data->rdy_pin)
		at91_set_gpio_input(data->rdy_pin, 1);  

	/* card detect pin */
	if (data->det_pin)
		at91_set_gpio_input(data->det_pin, 1);

	nand_data = *data;
	platform_device_register(&at91sam9260_nand_device);
}

(2)驱动初始化

//驱动私有数据结构
struct atmel_nand_host {
	struct nand_chip	nand_chip;  //Nandflash与mtd的接口
	struct mtd_info		mtd;  //主分区的mtd_info,创建分区使用
	void __iomem		*io_base;    //虚拟地址
	struct atmel_nand_data	*board;  //板级私有数据
	struct device		*dev;        
	void __iomem		*ecc;    //ecc的虚拟地址
};

static int __init atmel_nand_probe(struct platform_device *pdev)
{
	struct atmel_nand_host *host;
	struct mtd_info *mtd;
	struct nand_chip *nand_chip;
	struct resource *regs;
	struct resource *mem;
   . . .
   //为驱动私有数据分配空间并清0
   host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
  . . . 
	mtd = &host->mtd;
	nand_chip = &host->nand_chip;
	host->board = pdev->dev.platform_data;  //板级私有数据
	host->dev = &pdev->dev;    //dev

	nand_chip->priv = host;		/* link the private data structures */
	mtd->priv = nand_chip;     //链接nand_chip到mtd
	mtd->owner = THIS_MODULE;

	/* Set address of NAND IO lines */
	nand_chip->IO_ADDR_R = host->io_base;   //读地址
	nand_chip->IO_ADDR_W = host->io_base;     //写地址
	nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;   
//上面这个是写命令或写地址接口

	if (host->board->rdy_pin)
		nand_chip->dev_ready = atmel_nand_device_ready;

//ECC的初始化代码,略

//从数据手册获取命令延迟时间
nand_chip->chip_delay = 20;		/* 20us command delay time */

if (host->board->bus_width_16) {	/* 16-bit bus width */
		nand_chip->options |= NAND_BUSWIDTH_16;
		nand_chip->read_buf = atmel_read_buf16;
		nand_chip->write_buf = atmel_write_buf16;
	} else {
		nand_chip->read_buf = atmel_read_buf;
		nand_chip->write_buf = atmel_write_buf;
	}

	platform_set_drvdata(pdev, host);  //设置数据到pdev
	atmel_nand_enable(host);

. . .
	/* first scan to find the device and get the page size */
	if (nand_scan_ident(mtd, 1)) {
		res = -ENXIO;
		goto err_scan_ident;
	}

    //根据扫描得到的flash页大小初始化ECC硬件,代码略

	/* second phase scan */
	if (nand_scan_tail(mtd)) {
		res = -ENXIO;
		goto err_scan_tail;
	}


#ifdef CONFIG_MTD_PARTITIONS
#ifdef CONFIG_MTD_CMDLINE_PARTS
	mtd->name = "atmel_nand";
	num_partitions = parse_mtd_partitions(mtd, part_probes, //提取flash中的分区信息

					      &partitions, 0);
#endif
    //如果提取flash中的分区信息不存在,则读取板级初始化设定的分区信息
	if (num_partitions <= 0 && host->board->partition_info)
		partitions = host->board->partition_info(mtd->size,
							 &num_partitions);

	res = add_mtd_partitions(mtd, partitions, num_partitions);
#else
	res = add_mtd_device(mtd); //只有一个主分区的情况,不支持分区表
#endif

	if (!res)
		return res;
  . . .略
}


 

nand_chip->cmd_ctrl是写命令或写地址接口,它可以是下面三个值:

#define NAND_CTRL_CLE		(NAND_NCE | NAND_CLE)
#define NAND_CTRL_ALE		(NAND_NCE | NAND_ALE)
#define NAND_CTRL_CHANGE	     0x80


 

(3) ECC的配置

ECC的状态:

/*
 * Constants for ECC_MODES
 */
typedef enum {
	NAND_ECC_NONE,
	NAND_ECC_SOFT,
	NAND_ECC_HW,
	NAND_ECC_HW_SYNDROME,
} nand_ecc_modes_t;

如果是软件ECC:

nand_chip->ecc.mode = NAND_ECC_SOFT;
			nand_chip->ecc.mode = NAND_ECC_SOFT;
			nand_chip->ecc.calculate = NULL;
			nand_chip->ecc.correct = NULL;
			nand_chip->ecc.hwctl = NULL;
			nand_chip->ecc.read_page = NULL;
			nand_chip->ecc.postpad = 0;
			nand_chip->ecc.prepad = 0;
			nand_chip->ecc.bytes = 0;


 

如果是硬件ECC:

		nand_chip->ecc.mode = NAND_ECC_HW;
		nand_chip->ecc.calculate = atmel_nand_calculate;  //计算ECC
		nand_chip->ecc.correct = atmel_nand_correct;      //读完一页数据后判断ECC是否正确
		nand_chip->ecc.hwctl = atmel_nand_hwctl;        //硬件控制函数,大部分CPU不用支持
		nand_chip->ecc.read_page = atmel_nand_read_page; //有硬件ECC的情况下读一个页数据的接口
		nand_chip->ecc.bytes = 4;


nand_chip->ecc.layout是一个结构:


struct nand_oobfree {
	__u32 offset;
	__u32 length;
};

#define MTD_MAX_OOBFREE_ENTRIES	8
/*
 * ECC layout control structure. Exported to userspace for
 * diagnosis and to allow creation of raw images
 */
struct nand_ecclayout {
	__u32 eccbytes;   //ECC的大小(字节)
	__u32 eccpos[64];  //ECC所在的字节位置
	__u32 oobavail;   
	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];  //OOB可用的数据空间
};

例子:
/* oob layout for large page size
 * bad block info is on bytes 0 and 1
 * the bytes have to be consecutives to avoid
 * several NAND_CMD_RNDOUT during read
 */
static struct nand_ecclayout atmel_oobinfo_large = {
	.eccbytes	= 4,
	.eccpos		= {60, 61, 62, 63},
	.oobfree	= {
		{2, 58}
	},
};

/* oob layout for small page size
 * bad block info is on bytes 4 and 5
 * the bytes have to be consecutives to avoid
 * several NAND_CMD_RNDOUT during read
 */
static struct nand_ecclayout atmel_oobinfo_small = {
	.eccbytes	= 4,
	.eccpos		= {0, 1, 2, 3},
	.oobfree	= {
		{6, 10}
	},
};

 

总结:
NAND Flash的加载过程中,定义了一个结构atmel_nand_host,它的成员包含了nand_chip和mtd_info结构。nand_chip->priv指向atmel_nand_host结构,mtd_info->priv指向nand_chip结构。Nand_base.c中的nand_scan_ident函数完成NAND Flash探测的大部分工作。




 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: FPGA(现场可编程门阵列)是一种集成电路技术,可以在设计后进行灵活的重编程。NAND flash则是一种非易失性存储器,用于数据存储和传输。要实现FPGA驱动NAND flash,需要以下步骤: 首先,需要确定FPGA与NAND flash之间的通信接口。常用的接口包括SPI(串行外围接口)和I2C(串行总线接口)。通过这些接口,FPGA可以与NAND flash进行数据传输和控制命令交互。 其次,需要在FPGA中实现相应的逻辑电路来控制NAND flash。这些逻辑电路包括NAND flash的读取、写入和擦除操作,以及数据的缓存和错误纠正等功能。可以使用硬件描述语言(如VHDL或Verilog)来编写这些逻辑电路的代码,并在FPGA上进行编译和实现。 然后,需要将编写好的逻辑电路代码加载到FPGA中。这可以通过将代码通过特定的设计工具进行编译和综合,生成可以在FPGA上直接加载的二进制文件。将生成的二进制文件通过JTAG(联机测试与编程接口)或其他方式加载到FPGA中。 最后,在FPGA中配置好逻辑电路后,可以通过FPGA与NAND flash之间的通信接口进行控制和数据交互。FPGA可以发送读取、写入和擦除等命令给NAND flash,从而实现对其进行驱动。同时,也可以通过FPGA将数据NAND flash读取出来,或者将数据写入到NAND flash中。 总结来说,FPGA驱动NAND flash需要确定通信接口、实现逻辑电路、加载代码到FPGA,并通过通信接口进行控制和数据交互。这样就能实现对NAND flash的有效驱动和利用。 ### 回答2: FPGA驱动NAND Flash是指在FPGA芯片中通过编程控制来对NAND Flash进行操作和传输数据。FPGA作为一种可编程逻辑器件,通过其灵活的可编程性和并行处理能力,可以实现对NAND Flash的各种功能操作。 首先,FPGA需要连接到NAND Flash,通常通过片选信号、数据总线和控制总线进行连接。FPGA通过配置其IO管脚,将数据和控制信号发送到NAND Flash,实现对它的读取和写入。同时,FPGA还需要设置正确的时序和信号处理方式,确保数据的可靠传输。 其次,FPGA需要通过编程来实现对NAND Flash驱动。FPGA的硬件描述语言(HDL)编程可以用于控制存储器操作的时序和数据流程,包括片选和使能信号的生成,以及数据的读写操作。通过HDL编程,FPGA可以控制读取和写入的地址、数据、传输方式等参数,实现对NAND Flash的全面控制。 此外,FPGA还可以通过添加硬件逻辑和电路设计,对NAND Flash进行更高级的操作和处理。例如,可以通过FPGA的逻辑单元实现位翻转校验(BVC)和纠错码(ECC)等功能,提高数据传输和存储的可靠性。也可以通过并行处理的方式,实现多个NAND Flash的并行读取和写入,加快存储器访问速度。 总之,FPGA驱动NAND Flash是通过FPGA芯片的编程控制来实现对NAND Flash的读写和操作。通过正确配置连接和编程,FPGA可以实现对NAND Flash的高度可定制化的驱动,满足各种应用场景的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值