⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pxa3xx_nand.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * drivers/mtd/nand/pxa3xx_nand.c * * Copyright © 2005 Intel Corporation * Copyright © 2006 Marvell International Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/delay.h>#include <linux/clk.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <linux/io.h>#include <linux/irq.h>#include <asm/dma.h>#include <mach/pxa-regs.h>#include <mach/pxa3xx_nand.h>#define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)/* registers and bit definitions */#define NDCR		(0x00) /* Control register */#define NDTR0CS0	(0x04) /* Timing Parameter 0 for CS0 */#define NDTR1CS0	(0x0C) /* Timing Parameter 1 for CS0 */#define NDSR		(0x14) /* Status Register */#define NDPCR		(0x18) /* Page Count Register */#define NDBDR0		(0x1C) /* Bad Block Register 0 */#define NDBDR1		(0x20) /* Bad Block Register 1 */#define NDDB		(0x40) /* Data Buffer */#define NDCB0		(0x48) /* Command Buffer0 */#define NDCB1		(0x4C) /* Command Buffer1 */#define NDCB2		(0x50) /* Command Buffer2 */#define NDCR_SPARE_EN		(0x1 << 31)#define NDCR_ECC_EN		(0x1 << 30)#define NDCR_DMA_EN		(0x1 << 29)#define NDCR_ND_RUN		(0x1 << 28)#define NDCR_DWIDTH_C		(0x1 << 27)#define NDCR_DWIDTH_M		(0x1 << 26)#define NDCR_PAGE_SZ		(0x1 << 24)#define NDCR_NCSX		(0x1 << 23)#define NDCR_ND_MODE		(0x3 << 21)#define NDCR_NAND_MODE   	(0x0)#define NDCR_CLR_PG_CNT		(0x1 << 20)#define NDCR_CLR_ECC		(0x1 << 19)#define NDCR_RD_ID_CNT_MASK	(0x7 << 16)#define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)#define NDCR_RA_START		(0x1 << 15)#define NDCR_PG_PER_BLK		(0x1 << 14)#define NDCR_ND_ARB_EN		(0x1 << 12)#define NDSR_MASK		(0xfff)#define NDSR_RDY		(0x1 << 11)#define NDSR_CS0_PAGED		(0x1 << 10)#define NDSR_CS1_PAGED		(0x1 << 9)#define NDSR_CS0_CMDD		(0x1 << 8)#define NDSR_CS1_CMDD		(0x1 << 7)#define NDSR_CS0_BBD		(0x1 << 6)#define NDSR_CS1_BBD		(0x1 << 5)#define NDSR_DBERR		(0x1 << 4)#define NDSR_SBERR		(0x1 << 3)#define NDSR_WRDREQ		(0x1 << 2)#define NDSR_RDDREQ		(0x1 << 1)#define NDSR_WRCMDREQ		(0x1)#define NDCB0_AUTO_RS		(0x1 << 25)#define NDCB0_CSEL		(0x1 << 24)#define NDCB0_CMD_TYPE_MASK	(0x7 << 21)#define NDCB0_CMD_TYPE(x)	(((x) << 21) & NDCB0_CMD_TYPE_MASK)#define NDCB0_NC		(0x1 << 20)#define NDCB0_DBC		(0x1 << 19)#define NDCB0_ADDR_CYC_MASK	(0x7 << 16)#define NDCB0_ADDR_CYC(x)	(((x) << 16) & NDCB0_ADDR_CYC_MASK)#define NDCB0_CMD2_MASK		(0xff << 8)#define NDCB0_CMD1_MASK		(0xff)#define NDCB0_ADDR_CYC_SHIFT	(16)/* dma-able I/O address for the NAND data and commands */#define NDCB0_DMA_ADDR		(0x43100048)#define NDDB_DMA_ADDR		(0x43100040)/* macros for registers read/write */#define nand_writel(info, off, val)	\	__raw_writel((val), (info)->mmio_base + (off))#define nand_readl(info, off)		\	__raw_readl((info)->mmio_base + (off))/* error code and state */enum {	ERR_NONE	= 0,	ERR_DMABUSERR	= -1,	ERR_SENDCMD	= -2,	ERR_DBERR	= -3,	ERR_BBERR	= -4,};enum {	STATE_READY	= 0,	STATE_CMD_HANDLE,	STATE_DMA_READING,	STATE_DMA_WRITING,	STATE_DMA_DONE,	STATE_PIO_READING,	STATE_PIO_WRITING,};struct pxa3xx_nand_info {	struct nand_chip	nand_chip;	struct platform_device	 *pdev;	const struct pxa3xx_nand_flash *flash_info;	struct clk		*clk;	void __iomem		*mmio_base;	unsigned int 		buf_start;	unsigned int		buf_count;	/* DMA information */	int			drcmr_dat;	int			drcmr_cmd;	unsigned char		*data_buff;	dma_addr_t 		data_buff_phys;	size_t			data_buff_size;	int 			data_dma_ch;	struct pxa_dma_desc	*data_desc;	dma_addr_t 		data_desc_addr;	uint32_t		reg_ndcr;	/* saved column/page_addr during CMD_SEQIN */	int			seqin_column;	int			seqin_page_addr;	/* relate to the command */	unsigned int		state;	int			use_ecc;	/* use HW ECC ? */	int			use_dma;	/* use DMA ? */	size_t			data_size;	/* data size in FIFO */	int 			retcode;	struct completion 	cmd_complete;	/* generated NDCBx register values */	uint32_t		ndcb0;	uint32_t		ndcb1;	uint32_t		ndcb2;	/* calculated from pxa3xx_nand_flash data */	size_t		oob_size;	size_t		read_id_bytes;	unsigned int	col_addr_cycles;	unsigned int	row_addr_cycles;};static int use_dma = 1;module_param(use_dma, bool, 0444);MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");#ifdef CONFIG_MTD_NAND_PXA3xx_BUILTINstatic struct pxa3xx_nand_cmdset smallpage_cmdset = {	.read1		= 0x0000,	.read2		= 0x0050,	.program	= 0x1080,	.read_status	= 0x0070,	.read_id	= 0x0090,	.erase		= 0xD060,	.reset		= 0x00FF,	.lock		= 0x002A,	.unlock		= 0x2423,	.lock_status	= 0x007A,};static struct pxa3xx_nand_cmdset largepage_cmdset = {	.read1		= 0x3000,	.read2		= 0x0050,	.program	= 0x1080,	.read_status	= 0x0070,	.read_id	= 0x0090,	.erase		= 0xD060,	.reset		= 0x00FF,	.lock		= 0x002A,	.unlock		= 0x2423,	.lock_status	= 0x007A,};static struct pxa3xx_nand_timing samsung512MbX16_timing = {	.tCH	= 10,	.tCS	= 0,	.tWH	= 20,	.tWP	= 40,	.tRH	= 30,	.tRP	= 40,	.tR	= 11123,	.tWHR	= 110,	.tAR	= 10,};static struct pxa3xx_nand_flash samsung512MbX16 = {	.timing		= &samsung512MbX16_timing,	.cmdset		= &smallpage_cmdset,	.page_per_block	= 32,	.page_size	= 512,	.flash_width	= 16,	.dfc_width	= 16,	.num_blocks	= 4096,	.chip_id	= 0x46ec,};static struct pxa3xx_nand_timing micron_timing = {	.tCH	= 10,	.tCS	= 25,	.tWH	= 15,	.tWP	= 25,	.tRH	= 15,	.tRP	= 25,	.tR	= 25000,	.tWHR	= 60,	.tAR	= 10,};static struct pxa3xx_nand_flash micron1GbX8 = {	.timing		= &micron_timing,	.cmdset		= &largepage_cmdset,	.page_per_block	= 64,	.page_size	= 2048,	.flash_width	= 8,	.dfc_width	= 8,	.num_blocks	= 1024,	.chip_id	= 0xa12c,};static struct pxa3xx_nand_flash micron1GbX16 = {	.timing		= &micron_timing,	.cmdset		= &largepage_cmdset,	.page_per_block	= 64,	.page_size	= 2048,	.flash_width	= 16,	.dfc_width	= 16,	.num_blocks	= 1024,	.chip_id	= 0xb12c,};static struct pxa3xx_nand_timing stm2GbX16_timing = {	.tCH = 10,	.tCS = 35,	.tWH = 15,	.tWP = 25,	.tRH = 15,	.tRP = 25,	.tR = 25000,	.tWHR = 60,	.tAR = 10,};static struct pxa3xx_nand_flash stm2GbX16 = {	.timing = &stm2GbX16_timing,	.cmdset	= &largepage_cmdset,	.page_per_block = 64,	.page_size = 2048,	.flash_width = 16,	.dfc_width = 16,	.num_blocks = 2048,	.chip_id = 0xba20,};static struct pxa3xx_nand_flash *builtin_flash_types[] = {	&samsung512MbX16,	&micron1GbX8,	&micron1GbX16,	&stm2GbX16,};#endif /* CONFIG_MTD_NAND_PXA3xx_BUILTIN */#define NDTR0_tCH(c)	(min((c), 7) << 19)#define NDTR0_tCS(c)	(min((c), 7) << 16)#define NDTR0_tWH(c)	(min((c), 7) << 11)#define NDTR0_tWP(c)	(min((c), 7) << 8)#define NDTR0_tRH(c)	(min((c), 7) << 3)#define NDTR0_tRP(c)	(min((c), 7) << 0)#define NDTR1_tR(c)	(min((c), 65535) << 16)#define NDTR1_tWHR(c)	(min((c), 15) << 4)#define NDTR1_tAR(c)	(min((c), 15) << 0)/* convert nano-seconds to nand flash controller clock cycles */#define ns2cycle(ns, clk)	(int)(((ns) * (clk / 1000000) / 1000) + 1)static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,				   const struct pxa3xx_nand_timing *t){	unsigned long nand_clk = clk_get_rate(info->clk);	uint32_t ndtr0, ndtr1;	ndtr0 = NDTR0_tCH(ns2cycle(t->tCH, nand_clk)) |		NDTR0_tCS(ns2cycle(t->tCS, nand_clk)) |		NDTR0_tWH(ns2cycle(t->tWH, nand_clk)) |		NDTR0_tWP(ns2cycle(t->tWP, nand_clk)) |		NDTR0_tRH(ns2cycle(t->tRH, nand_clk)) |		NDTR0_tRP(ns2cycle(t->tRP, nand_clk));	ndtr1 = NDTR1_tR(ns2cycle(t->tR, nand_clk)) |		NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |		NDTR1_tAR(ns2cycle(t->tAR, nand_clk));	nand_writel(info, NDTR0CS0, ndtr0);	nand_writel(info, NDTR1CS0, ndtr1);}#define WAIT_EVENT_TIMEOUT	10static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event){	int timeout = WAIT_EVENT_TIMEOUT;	uint32_t ndsr;	while (timeout--) {		ndsr = nand_readl(info, NDSR) & NDSR_MASK;		if (ndsr & event) {			nand_writel(info, NDSR, ndsr);			return 0;		}		udelay(10);	}	return -ETIMEDOUT;}static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,			uint16_t cmd, int column, int page_addr){	const struct pxa3xx_nand_flash *f = info->flash_info;	const struct pxa3xx_nand_cmdset *cmdset = f->cmdset;	/* calculate data size */	switch (f->page_size) {	case 2048:		info->data_size = (info->use_ecc) ? 2088 : 2112;		break;	case 512:		info->data_size = (info->use_ecc) ? 520 : 528;		break;	default:		return -EINVAL;	}	/* generate values for NDCBx registers */	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);	info->ndcb1 = 0;	info->ndcb2 = 0;	info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles);	if (info->col_addr_cycles == 2) {		/* large block, 2 cycles for column address		 * row address starts from 3rd cycle		 */		info->ndcb1 |= (page_addr << 16) | (column & 0xffff);		if (info->row_addr_cycles == 3)			info->ndcb2 = (page_addr >> 16) & 0xff;	} else		/* small block, 1 cycles for column address		 * row address starts from 2nd cycle		 */		info->ndcb1 = (page_addr << 8) | (column & 0xff);	if (cmd == cmdset->program)		info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;	return 0;}static int prepare_erase_cmd(struct pxa3xx_nand_info *info,			uint16_t cmd, int page_addr){	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);	info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);	info->ndcb1 = page_addr;	info->ndcb2 = 0;	return 0;}static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd){	const struct pxa3xx_nand_cmdset *cmdset = info->flash_info->cmdset;	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);	info->ndcb1 = 0;	info->ndcb2 = 0;	if (cmd == cmdset->read_id) {		info->ndcb0 |= NDCB0_CMD_TYPE(3);		info->data_size = 8;	} else if (cmd == cmdset->read_status) {		info->ndcb0 |= NDCB0_CMD_TYPE(4);		info->data_size = 8;	} else if (cmd == cmdset->reset || cmd == cmdset->lock ||		   cmd == cmdset->unlock) {		info->ndcb0 |= NDCB0_CMD_TYPE(5);	} else		return -EINVAL;	return 0;}static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -