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

📄 pxa3xx_nand.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	uint32_t ndcr;	ndcr = nand_readl(info, NDCR);	nand_writel(info, NDCR, ndcr & ~int_mask);}static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask){	uint32_t ndcr;	ndcr = nand_readl(info, NDCR);	nand_writel(info, NDCR, ndcr | int_mask);}/* NOTE: it is a must to set ND_RUN firstly, then write command buffer * otherwise, it does not work */static int write_cmd(struct pxa3xx_nand_info *info){	uint32_t ndcr;	/* clear status bits and run */	nand_writel(info, NDSR, NDSR_MASK);	ndcr = info->reg_ndcr;	ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;	ndcr |= info->use_dma ? NDCR_DMA_EN : 0;	ndcr |= NDCR_ND_RUN;	nand_writel(info, NDCR, ndcr);	if (wait_for_event(info, NDSR_WRCMDREQ)) {		printk(KERN_ERR "timed out writing command\n");		return -ETIMEDOUT;	}	nand_writel(info, NDCB0, info->ndcb0);	nand_writel(info, NDCB0, info->ndcb1);	nand_writel(info, NDCB0, info->ndcb2);	return 0;}static int handle_data_pio(struct pxa3xx_nand_info *info){	int ret, timeout = CHIP_DELAY_TIMEOUT;	switch (info->state) {	case STATE_PIO_WRITING:		__raw_writesl(info->mmio_base + NDDB, info->data_buff,				info->data_size << 2);		enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);		ret = wait_for_completion_timeout(&info->cmd_complete, timeout);		if (!ret) {			printk(KERN_ERR "program command time out\n");			return -1;		}		break;	case STATE_PIO_READING:		__raw_readsl(info->mmio_base + NDDB, info->data_buff,				info->data_size << 2);		break;	default:		printk(KERN_ERR "%s: invalid state %d\n", __func__,				info->state);		return -EINVAL;	}	info->state = STATE_READY;	return 0;}static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out){	struct pxa_dma_desc *desc = info->data_desc;	int dma_len = ALIGN(info->data_size, 32);	desc->ddadr = DDADR_STOP;	desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len;	if (dir_out) {		desc->dsadr = info->data_buff_phys;		desc->dtadr = NDDB_DMA_ADDR;		desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG;	} else {		desc->dtadr = info->data_buff_phys;		desc->dsadr = NDDB_DMA_ADDR;		desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC;	}	DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch;	DDADR(info->data_dma_ch) = info->data_desc_addr;	DCSR(info->data_dma_ch) |= DCSR_RUN;}static void pxa3xx_nand_data_dma_irq(int channel, void *data){	struct pxa3xx_nand_info *info = data;	uint32_t dcsr;	dcsr = DCSR(channel);	DCSR(channel) = dcsr;	if (dcsr & DCSR_BUSERR) {		info->retcode = ERR_DMABUSERR;		complete(&info->cmd_complete);	}	if (info->state == STATE_DMA_WRITING) {		info->state = STATE_DMA_DONE;		enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);	} else {		info->state = STATE_READY;		complete(&info->cmd_complete);	}}static irqreturn_t pxa3xx_nand_irq(int irq, void *devid){	struct pxa3xx_nand_info *info = devid;	unsigned int status;	status = nand_readl(info, NDSR);	if (status & (NDSR_RDDREQ | NDSR_DBERR)) {		if (status & NDSR_DBERR)			info->retcode = ERR_DBERR;		disable_int(info, NDSR_RDDREQ | NDSR_DBERR);		if (info->use_dma) {			info->state = STATE_DMA_READING;			start_data_dma(info, 0);		} else {			info->state = STATE_PIO_READING;			complete(&info->cmd_complete);		}	} else if (status & NDSR_WRDREQ) {		disable_int(info, NDSR_WRDREQ);		if (info->use_dma) {			info->state = STATE_DMA_WRITING;			start_data_dma(info, 1);		} else {			info->state = STATE_PIO_WRITING;			complete(&info->cmd_complete);		}	} else if (status & (NDSR_CS0_BBD | NDSR_CS0_CMDD)) {		if (status & NDSR_CS0_BBD)			info->retcode = ERR_BBERR;		disable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);		info->state = STATE_READY;		complete(&info->cmd_complete);	}	nand_writel(info, NDSR, status);	return IRQ_HANDLED;}static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event){	uint32_t ndcr;	int ret, timeout = CHIP_DELAY_TIMEOUT;	if (write_cmd(info)) {		info->retcode = ERR_SENDCMD;		goto fail_stop;	}	info->state = STATE_CMD_HANDLE;	enable_int(info, event);	ret = wait_for_completion_timeout(&info->cmd_complete, timeout);	if (!ret) {		printk(KERN_ERR "command execution timed out\n");		info->retcode = ERR_SENDCMD;		goto fail_stop;	}	if (info->use_dma == 0 && info->data_size > 0)		if (handle_data_pio(info))			goto fail_stop;	return 0;fail_stop:	ndcr = nand_readl(info, NDCR);	nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);	udelay(10);	return -ETIMEDOUT;}static int pxa3xx_nand_dev_ready(struct mtd_info *mtd){	struct pxa3xx_nand_info *info = mtd->priv;	return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0;}static inline int is_buf_blank(uint8_t *buf, size_t len){	for (; len > 0; len--)		if (*buf++ != 0xff)			return 0;	return 1;}static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,				int column, int page_addr){	struct pxa3xx_nand_info *info = mtd->priv;	const struct pxa3xx_nand_flash *flash_info = info->flash_info;	const struct pxa3xx_nand_cmdset *cmdset = flash_info->cmdset;	int ret;	info->use_dma = (use_dma) ? 1 : 0;	info->use_ecc = 0;	info->data_size = 0;	info->state = STATE_READY;	init_completion(&info->cmd_complete);	switch (command) {	case NAND_CMD_READOOB:		/* disable HW ECC to get all the OOB data */		info->buf_count = mtd->writesize + mtd->oobsize;		info->buf_start = mtd->writesize + column;		if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))			break;		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);		/* We only are OOB, so if the data has error, does not matter */		if (info->retcode == ERR_DBERR)			info->retcode = ERR_NONE;		break;	case NAND_CMD_READ0:		info->use_ecc = 1;		info->retcode = ERR_NONE;		info->buf_start = column;		info->buf_count = mtd->writesize + mtd->oobsize;		memset(info->data_buff, 0xFF, info->buf_count);		if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr))			break;		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR);		if (info->retcode == ERR_DBERR) {			/* for blank page (all 0xff), HW will calculate its ECC as			 * 0, which is different from the ECC information within			 * OOB, ignore such double bit errors			 */			if (is_buf_blank(info->data_buff, mtd->writesize))				info->retcode = ERR_NONE;		}		break;	case NAND_CMD_SEQIN:		info->buf_start = column;		info->buf_count = mtd->writesize + mtd->oobsize;		memset(info->data_buff, 0xff, info->buf_count);		/* save column/page_addr for next CMD_PAGEPROG */		info->seqin_column = column;		info->seqin_page_addr = page_addr;		break;	case NAND_CMD_PAGEPROG:		info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;		if (prepare_read_prog_cmd(info, cmdset->program,				info->seqin_column, info->seqin_page_addr))			break;		pxa3xx_nand_do_cmd(info, NDSR_WRDREQ);		break;	case NAND_CMD_ERASE1:		if (prepare_erase_cmd(info, cmdset->erase, page_addr))			break;		pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD);		break;	case NAND_CMD_ERASE2:		break;	case NAND_CMD_READID:	case NAND_CMD_STATUS:		info->use_dma = 0;	/* force PIO read */		info->buf_start = 0;		info->buf_count = (command == NAND_CMD_READID) ?				info->read_id_bytes : 1;		if (prepare_other_cmd(info, (command == NAND_CMD_READID) ?				cmdset->read_id : cmdset->read_status))			break;		pxa3xx_nand_do_cmd(info, NDSR_RDDREQ);		break;	case NAND_CMD_RESET:		if (prepare_other_cmd(info, cmdset->reset))			break;		ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD);		if (ret == 0) {			int timeout = 2;			uint32_t ndcr;			while (timeout--) {				if (nand_readl(info, NDSR) & NDSR_RDY)					break;				msleep(10);			}			ndcr = nand_readl(info, NDCR);			nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN);		}		break;	default:		printk(KERN_ERR "non-supported command.\n");		break;	}	if (info->retcode == ERR_DBERR) {		printk(KERN_ERR "double bit error @ page %08x\n", page_addr);		info->retcode = ERR_NONE;	}}static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd){	struct pxa3xx_nand_info *info = mtd->priv;	char retval = 0xFF;	if (info->buf_start < info->buf_count)		/* Has just send a new command? */		retval = info->data_buff[info->buf_start++];	return retval;}static u16 pxa3xx_nand_read_word(struct mtd_info *mtd){	struct pxa3xx_nand_info *info = mtd->priv;	u16 retval = 0xFFFF;	if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) {		retval = *((u16 *)(info->data_buff+info->buf_start));		info->buf_start += 2;	}	return retval;}static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len){	struct pxa3xx_nand_info *info = mtd->priv;	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);	memcpy(buf, info->data_buff + info->buf_start, real_len);	info->buf_start += real_len;}static void pxa3xx_nand_write_buf(struct mtd_info *mtd,		const uint8_t *buf, int len){	struct pxa3xx_nand_info *info = mtd->priv;	int real_len = min_t(size_t, len, info->buf_count - info->buf_start);	memcpy(info->data_buff + info->buf_start, buf, real_len);	info->buf_start += real_len;}static int pxa3xx_nand_verify_buf(struct mtd_info *mtd,		const uint8_t *buf, int len){	return 0;}static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip){	return;}static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this){	struct pxa3xx_nand_info *info = mtd->priv;	/* pxa3xx_nand_send_command has waited for command complete */	if (this->state == FL_WRITING || this->state == FL_ERASING) {		if (info->retcode == ERR_NONE)			return 0;		else {			/*			 * any error make it return 0x01 which will tell			 * the caller the erase and write fail			 */			return 0x01;		}	}	return 0;}static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode){	return;}static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd,		const uint8_t *dat, uint8_t *ecc_code){	return 0;}static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd,		uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc){	struct pxa3xx_nand_info *info = mtd->priv;	/*	 * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we

⌨️ 快捷键说明

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