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

📄 mxc_nd.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. *//* * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */#include <linux/delay.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/module.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/interrupt.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/clk.h>#include <linux/err.h>#include <linux/mtd/partitions.h>#include <asm/mach/flash.h>#include <asm/io.h>#include "mxc_nd.h"/*! * Number of static partitions on NAND Flash. */#define NUM_PARTITIONS    (sizeof(partition_info)/sizeof(struct mtd_partition))/*! * The version of this driver */#define DVR_VER "2.0"struct mxc_mtd_s {	struct mtd_info mtd;	struct nand_chip nand;	struct mtd_partition *parts;	struct device *dev;};static struct mxc_mtd_s *mxc_nand_data = NULL;/*! * Define delays in microsec for NAND device operations */#define TROP_US_DELAY   2000/*! * \def BITPOS(x) * Macros to get byte and bit positions of ECC *//*! * Macros to get byte and bit positions of ECC */#define COLPOS(x)  ((x) >> 3)#define BITPOS(x) ((x)& 0xf)/*! * \def SPARE_SINGLEBIT_ERROR * Define single bit Error positions in Main & Spare area *//*! Define single bit Error positions in Main & Spare area */#define MAIN_SINGLEBIT_ERROR 0x4#define SPARE_SINGLEBIT_ERROR 0x1struct nand_info {	bool bSpareOnly;	bool bStatusRequest;	u16 colAddr;};static struct nand_info g_nandfc_info;#ifdef CONFIG_MTD_NAND_MXC_SWECCstatic int hardware_ecc = 0;#elsestatic int hardware_ecc = 1;#endif#ifndef CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2static int Ecc_disabled;#endifstatic int is2k_Pagesize = 0;static struct clk *nfc_clk;/* * OOB placement block for use with hardware ecc generation */static struct nand_ecclayout nand_hw_eccoob_8 = {        .eccbytes = 20,        .eccpos   = {                     6, 7, 8, 9, 10,                     22,23,24,25,26,                     38,39,40,41,42,                     54,55,56,57,58},        .oobfree  = {                     {.offset = 0,                      .length = 5},                     {.offset = 11,                      .length = 10},                     {.offset = 27,                      .length = 10},                     {.offset = 43,                      .length = 10},                     {.offset = 59,                      .length = 5}                    }};static struct nand_ecclayout nand_hw_eccoob_16 = {	.eccbytes = 5,	.eccpos = {6, 7, 8, 9, 10},	.oobfree = {{0, 6}, {12, 4}}};/*! * @defgroup NAND_MTD NAND Flash MTD Driver for MXC processors *//*! * @file mxc_nd.c * * @brief This file contains the hardware specific layer for NAND Flash on * MXC processor * * @ingroup NAND_MTD */#ifdef CONFIG_MTD_PARTITIONSstatic const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL };#endifstatic wait_queue_head_t irq_waitq;static irqreturn_t mxc_nfc_irq(int irq, void *dev_id){	NFC_CONFIG1 |= NFC_INT_MSK;	/* Disable interrupt */	wake_up(&irq_waitq);	return IRQ_RETVAL(1);}/*! * This function polls the NANDFC to wait for the basic operation to complete by * checking the INT bit of config2 register. * * @param       maxRetries     number of retry attempts (separated by 1 us) * @param       param           parameter for debug * @param       useirq         True if IRQ should be used rather than polling */static void wait_op_done(int maxRetries, u16 param, bool useirq){	if (useirq) {		if ((NFC_CONFIG2 & NFC_INT) == 0) {			NFC_CONFIG1 &= ~NFC_INT_MSK;	/* Enable interrupt */			wait_event(irq_waitq, NFC_CONFIG2 & NFC_INT);			NFC_CONFIG2 &= ~NFC_INT;		}	} else {		while (maxRetries-- > 0) {			if (NFC_CONFIG2 & NFC_INT) {				NFC_CONFIG2 &= ~NFC_INT;				break;			}			udelay(1);		}		if (maxRetries <= 0)			DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n",			      __FUNCTION__, param);	}}/*! * This function issues the specified command to the NAND device and * waits for completion. * * @param       cmd     command for NAND Flash * @param       useirq  True if IRQ should be used rather than polling */static void send_cmd(u16 cmd, bool useirq){	DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(0x%x, %d)\n", cmd, useirq);	NFC_FLASH_CMD = (u16) cmd;	NFC_CONFIG2 = NFC_CMD;	/* Wait for operation to complete */	wait_op_done(TROP_US_DELAY, cmd, useirq);}/*! * This function sends an address (or partial address) to the * NAND device.  The address is used to select the source/destination for * a NAND command. * * @param       addr    address to be written to NFC. * @param       islast  True if this is the last address cycle for command */static void send_addr(u16 addr, bool islast){	DEBUG(MTD_DEBUG_LEVEL3, "send_addr(0x%x %d)\n", addr, islast);	NFC_FLASH_ADDR = addr;	NFC_CONFIG2 = NFC_ADDR;	/* Wait for operation to complete */	wait_op_done(TROP_US_DELAY, addr, islast);}/*! * This function requests the NANDFC to initate the transfer * of data currently in the NANDFC RAM buffer to the NAND device. * * @param	buf_id	      Specify Internal RAM Buffer number (0-3)	 * @param       bSpareOnly    set true if only the spare area is transferred */static void send_prog_page(u8 buf_id, bool bSpareOnly){	DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", bSpareOnly);	/* NANDFC buffer 0 is used for page read/write */	NFC_BUF_ADDR = buf_id;	/* Configure spare or page+spare access */	if (!is2k_Pagesize) {		if (bSpareOnly) {			NFC_CONFIG1 |= NFC_SP_EN;		} else {			NFC_CONFIG1 &= ~(NFC_SP_EN);		}	}	NFC_CONFIG2 = NFC_INPUT;	/* Wait for operation to complete */	wait_op_done(TROP_US_DELAY, bSpareOnly, true);}/*! * This function will correct the single bit ECC error * * @param  buf_id	Specify Internal RAM Buffer number (0-3)	 * @param  eccpos 	Ecc byte and bit position * @param  bSpareOnly  	set to true if only spare area needs correction */static void mxc_nd_correct_error(u8 buf_id, u16 eccpos, bool bSpareOnly){	u16 col;	u8 pos;	volatile u16 *buf;	/* Get col & bit position of error	   these macros works for both 8 & 16 bits */	col = COLPOS(eccpos);	/* Get half-word position */	pos = BITPOS(eccpos);	/* Get bit position */	DEBUG(MTD_DEBUG_LEVEL3,	      "mxc_nd_correct_error (col=%d pos=%d)\n", col, pos);	/* Set the pointer for main / spare area */	if (!bSpareOnly) {		buf = MAIN_AREA0 + (col >> 1) + (512 * buf_id);	} else {		buf = SPARE_AREA0 + (col >> 1) + (16 * buf_id);	}	/* Fix the data */	*buf ^= (1 << pos);}/*! * This function will maintains state of single bit Error * in Main & spare  area * * @param buf_id	Specify Internal RAM Buffer number (0-3)	 * @param spare  	set to true if only spare area needs correction */static void mxc_nd_correct_ecc(u8 buf_id, bool spare){#ifdef CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2	static int lastErrMain = 0, lastErrSpare = 0;	/* To maintain single bit							   error in previous page */#endif	u16 value, ecc_status;	/* Read the ECC result */	ecc_status = NFC_ECC_STATUS_RESULT;	DEBUG(MTD_DEBUG_LEVEL3,	      "mxc_nd_correct_ecc (Ecc status=%x)\n", ecc_status);#ifdef CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2	/* Check for Error in Mainarea */	if ((ecc_status & 0xC) == MAIN_SINGLEBIT_ERROR) {		/* Check for error in previous page */		if (lastErrMain && !spare) {			value = NFC_RSLTMAIN_AREA;			/* Correct single bit error in Mainarea			   NFC will not correct the error in			   current page */			mxc_nd_correct_error(buf_id, value, false);		} else {			/* Set if single bit error in current page */			lastErrMain = 1;		}	} else {		/* Reset if no single bit error in current page */		lastErrMain = 0;	}	/* Check for Error in Sparearea */	if ((ecc_status & 0x3) == SPARE_SINGLEBIT_ERROR) {		/* Check for error in previous page */		if (lastErrSpare) {			value = NFC_RSLTSPARE_AREA;			/* Correct single bit error in Mainarea			   NFC will not correct the error in			   current page */			mxc_nd_correct_error(buf_id, value, true);		} else {			/* Set if single bit error in current page */			lastErrSpare = 1;		}	} else {		/* Reset if no single bit error in current page */		lastErrSpare = 0;	}#else	if (((ecc_status & 0xC) == MAIN_SINGLEBIT_ERROR)	    || ((ecc_status & 0x3) == SPARE_SINGLEBIT_ERROR)) {		if (Ecc_disabled) {			if ((ecc_status & 0xC) == MAIN_SINGLEBIT_ERROR) {				value = NFC_RSLTMAIN_AREA;				/* Correct single bit error in Mainarea				   NFC will not correct the error in				   current page */				mxc_nd_correct_error(buf_id, value, false);			}			if ((ecc_status & 0x3) == SPARE_SINGLEBIT_ERROR) {				value = NFC_RSLTSPARE_AREA;				/* Correct single bit error in Mainarea				   NFC will not correct the error in				   current page */				mxc_nd_correct_error(buf_id, value, true);			}		} else {			/* Disable ECC  */			NFC_CONFIG1 &= ~(NFC_ECC_EN);			Ecc_disabled = 1;		}	} else if (ecc_status == 0) {		if (Ecc_disabled) {			/* Enable ECC */			NFC_CONFIG1 |= NFC_ECC_EN;			Ecc_disabled = 0;		}	} else {		/* 2-bit Error  Do nothing */	}#endif				/* CONFIG_MTD_NAND_MXC_ECC_CORRECTION_OPTION2 */}/*! * This function requests the NANDFC to initated the transfer * of data from the NAND device into in the NANDFC ram buffer. * * @param  	buf_id		Specify Internal RAM Buffer number (0-3)	 * @param       bSpareOnly    	set true if only the spare area is transferred */static void send_read_page(u8 buf_id, bool bSpareOnly){	DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", bSpareOnly);	/* NANDFC buffer 0 is used for page read/write */	NFC_BUF_ADDR = buf_id;	/* Configure spare or page+spare access */	if (!is2k_Pagesize) {		if (bSpareOnly) {			NFC_CONFIG1 |= NFC_SP_EN;		} else {			NFC_CONFIG1 &= ~(NFC_SP_EN);		}	}	NFC_CONFIG2 = NFC_OUTPUT;	/* Wait for operation to complete */	wait_op_done(TROP_US_DELAY, bSpareOnly, true);	/* If there are single bit errors in	   two consecutive page reads then	   the error is not  corrected by the	   NFC for the second page.	   Correct single bit error in driver */	mxc_nd_correct_ecc(buf_id, bSpareOnly);}/*! * This function requests the NANDFC to perform a read of the * NAND device ID. */static void send_read_id(void){	struct nand_chip *this = &mxc_nand_data->nand;	/* NANDFC buffer 0 is used for device ID output */	NFC_BUF_ADDR = 0x0;	/* Read ID into main buffer */	NFC_CONFIG1 &= (~(NFC_SP_EN));	NFC_CONFIG2 = NFC_ID;	/* Wait for operation to complete */	wait_op_done(TROP_US_DELAY, 0, true);	if (this->options & NAND_BUSWIDTH_16) {		volatile u16 *mainBuf = MAIN_AREA0;		/*		 * Pack the every-other-byte result for 16-bit ID reads		 * into every-byte as the generic code expects and various		 * chips implement.		 */		mainBuf[0] = (mainBuf[0] & 0xff) | ((mainBuf[1] & 0xff) << 8);		mainBuf[1] = (mainBuf[2] & 0xff) | ((mainBuf[3] & 0xff) << 8);		mainBuf[2] = (mainBuf[4] & 0xff) | ((mainBuf[5] & 0xff) << 8);	}}/*! * This function requests the NANDFC to perform a read of the * NAND device status and returns the current status. * * @return  device status

⌨️ 快捷键说明

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