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

📄 mp2520f.c

📁 SMDK2440 boot code, base on vivi
💻 C
字号:
/* * NAND controller on MagicEye MP2520F * * Based on vivi/drivers/mtd/nand/mp2520f.c by bushi * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. */#include <config.h>#include <machine.h>#include <types.h>#include <mtd/mtd.h>#include <mtd/nand.h>#include <time.h>#include <vmalloc.h>#include <vstring.h>#include <errno.h>#define MP2520F_NAND_DEBUG 0#define USE_CPU_FCE 1#define USE_CPU_RnB 1#if MP2520F_NAND_DEBUG#define DPRINTK(x...) printk(x)#else#define DPRINTK(x...) (void)(0)#endif#define GPIO_nFCE0	GPIO_I0#define GPIO_nFCE1	GPIO_I1#define GPIO_nFCE2	GPIO_I2#define GPIO_nFCE3	GPIO_I3#define GPIO_RnB	GPIO_J2extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);static struct mtd_info *mp2520f_nand_mtd = NULL;#if USE_CPU_FCE == 0static const int chipnr_to_gpiobit[16] = {	0xe,0xd,0xb,0x7,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf};#endifstatic void mp2520f_nand_select_chip(struct mtd_info *mtd, int chip){#if USE_CPU_FCE	unsigned short memnandctrl = MEMNANDCTRL & 0xfffc;	DPRINTK("%s(): chip = %d\n", __FUNCTION__, chip);	if (chip >= 0 && chip < 4) {		memnandctrl |= chip;	} else {		memnandctrl |= 1; // FIXME !!	}	MEMNANDCTRL = memnandctrl;	DPRINTK("MEMNANDCTRL = 0x%04x\n", MEMNANDCTRL);#else# if 0	switch (chip) {		case 0:			write_gpio_bit(GPIO_nFCE0, 0);			write_gpio_bit(GPIO_nFCE1, 1);			write_gpio_bit(GPIO_nFCE2, 1);			write_gpio_bit(GPIO_nFCE3, 1);			break;		case 1:			write_gpio_bit(GPIO_nFCE0, 1);			write_gpio_bit(GPIO_nFCE1, 0);			write_gpio_bit(GPIO_nFCE2, 1);			write_gpio_bit(GPIO_nFCE3, 1);			break;		case 2:			write_gpio_bit(GPIO_nFCE0, 1);			write_gpio_bit(GPIO_nFCE1, 1);			write_gpio_bit(GPIO_nFCE2, 0);			write_gpio_bit(GPIO_nFCE3, 1);			break;		case 3:			write_gpio_bit(GPIO_nFCE0, 1);			write_gpio_bit(GPIO_nFCE1, 1);			write_gpio_bit(GPIO_nFCE2, 1);			write_gpio_bit(GPIO_nFCE3, 0);			break;		default:			write_gpio_bit(GPIO_nFCE0, 1);			write_gpio_bit(GPIO_nFCE1, 1);			write_gpio_bit(GPIO_nFCE2, 1);			write_gpio_bit(GPIO_nFCE3, 1);			break;	}# else	/*	 * Note:	 *  assume that we can read the GPIOIOUT	 */	unsigned int _fce = chipnr_to_gpiobit[chip & 0xf];	unsigned int gpioiout = GPIOIOUT & 0xfff0;	GPIOIOUT = (gpioiout | _fce);# endif#endif /* USE_CPU_FCE */}static int mp2520f_nand_device_ready(struct mtd_info *mtd){#if USE_CPU_RnB	DPRINTK("%s():\n", __FUNCTION__);	if ((MEMNANDCTRL & NAND_READY_DETECT) == NAND_READY_DETECT) {		while ( MEMNANDCTRL & NAND_READY_DETECT) {			MEMNANDCTRL |=  NAND_READY_DETECT;		}		return 1;	}	return 0;#else	udelay(1); /* T.T */	return read_gpio_bit(GPIO_RnB) ? 1 : 0;#endif}/* small and normal page size */static void mp2520f_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr){	register struct nand_chip *this = mtd->priv;	DPRINTK("%s(): options = 0x%0x\n", __FUNCTION__, this->options);	MEMNANDCTRL |=  NAND_READY_DETECT;	/* Adjust columns for 16 bit buswidth */	if (this->options & NAND_BUSWIDTH_16)		column >>= 1;	/*	 * Write out the command to the device.	 */	if (command == NAND_CMD_SEQIN) {		int readcmd;		if (column >= mtd->oobblock) {			/* OOB area */			column -= mtd->oobblock;			readcmd = NAND_CMD_READOOB;		} else if (column < 256) {			/* First 256 bytes --> READ0 */			readcmd = NAND_CMD_READ0;		} else {			column -= 256;			readcmd = NAND_CMD_READ1;		}		NFCMD = readcmd;	}	NFCMD = (command & 0xFF);	if (column != -1 || page_addr != -1) {		/* Serially input address */		if (column != -1)			NFADDR = (column & 0xFF);		if (page_addr != -1) {			NFADDR = (unsigned char)(page_addr & 0xff);			NFADDR = (unsigned char)((page_addr >> 8) & 0xff);			/* One more address cycle for higher density devices */			if (mtd->size & 0x0c000000) 				NFADDR = (unsigned char)((page_addr >> 16) & 0x0f);		}	}		/* 	 * program and erase have their own busy handlers 	 * status and sequential in needs no delay	 */	switch (command) {				case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_STATUS:		return;	case NAND_CMD_READID: /* T.T *///			udelay (this->chip_delay);		return;	case NAND_CMD_RESET:		if (this->dev_ready)				break;		NFCMD = NAND_CMD_STATUS;		while ( !(NFDATA & 0x40));		return;	/* This applies to read commands */		default:		if (!this->dev_ready) {			udelay (this->chip_delay);			return;		}		}		/* wait until command is processed */	while (!this->dev_ready(mtd));}/*  * large page size  *   (not used, but ...) */static void mp2520f_nand_cmdfunc_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr){	register struct nand_chip *this = mtd->priv;	/* Emulate NAND_CMD_READOOB */	if (command == NAND_CMD_READOOB) {		column += mtd->oobblock;		command = NAND_CMD_READ0;	}	/* Adjust columns for 16 bit buswidth */	if (this->options & NAND_BUSWIDTH_16)		column >>= 1;	NFCMD = command;	if (column != -1 || page_addr != -1) {		/* Serially input address */		if (column != -1) {			NFADDR = (column & 0xff);			NFADDR = (column >> 8);		}			if (page_addr != -1) {			NFADDR = (unsigned char) ((page_addr & 0xff));			NFADDR = (unsigned char) ((page_addr >> 8) & 0xff);			/* One more address cycle for devices > 128MiB */			if (this->chipsize > (128 << 20))				NFADDR = (unsigned char) ((page_addr >> 16) & 0xff);		}	}		/* 	 * program and erase have their own busy handlers 	 * status and sequential in needs no delay	*/	switch (command) {				case NAND_CMD_CACHEDPROG:	case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_STATUS:		return;	case NAND_CMD_READID: /* T.T *///			udelay (this->chip_delay);		return;	case NAND_CMD_RESET:		if (this->dev_ready)				break;		udelay(this->chip_delay);		NFCMD = NAND_CMD_STATUS;		while ( !(NFDATA & 0x40));		return;	case NAND_CMD_READ0:		NFCMD = NAND_CMD_READSTART;			/* This applies to read commands */		default:		/* 		 * If we don't have access to the busy pin, we apply the given		 * command delay		*/		if (!this->dev_ready) {			udelay (this->chip_delay);			return;		}		}		/* wait until command is processed */	while (!this->dev_ready(mtd));}#ifdef CONFIG_MTD_NAND_MP2520F_HWECCstatic void mp2520f_enable_hwecc(struct mtd_info *mtd, int mode){	/* do nothing */}/* * for 8bit NAND , emulate HW3_256 */static void mp2520f_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){	*(ecc_code+1) = MEMNANDECC0 & 0xff;	*(ecc_code+0) = MEMNANDECC1 & 0xff;	*(ecc_code+2) = (MEMNANDECC2 & 0xff) | 0x01;}/* * for 16bit NAND , emulate HW6_512 */static void mp2520f_calculate_ecc_16(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){	/* 	 * FIXME - not tested 	 */	*(ecc_code+1) = MEMNANDECC0 & 0xff;	*(ecc_code+0) = MEMNANDECC1 & 0xff;	*(ecc_code+2) = (MEMNANDECC2 & 0xff) | 0x01;	*(ecc_code+4) = (MEMNANDECC0 >> 8) & 0xff;	*(ecc_code+3) = (MEMNANDECC1 >> 8) & 0xff;	*(ecc_code+4) = ((MEMNANDECC2 >> 8) & 0xff) | 0x01;}# ifdef CONFIG_MTD_NAND_MP2520F_HWECC_DEBUGstatic int mp2520f_correct_data_debug(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc){	int ret = -1;	u_char dbg_ecc[3];	/* for 8-bit NAND */	nand_calculate_ecc(mtd, dat, &dbg_ecc[0]);	/*	 * read_ecc[] : read from device OOB	 * calc_ecc[] : h/w ECC	 * dgb_ecc[]  : s/w ECC	 */	if ((dbg_ecc[0] != calc_ecc[0]) || (dbg_ecc[1] != calc_ecc[1])			|| (dbg_ecc[2] != calc_ecc[2])			|| (ret = nand_correct_data(mtd, dat, read_ecc, calc_ecc))) {		printk("%s():\n\tread: 0x%02x 0x%02x 0x%02x\n"				"\t S/W: 0x%02x 0x%02x 0x%02x\n"				"\t H/W: 0x%02x 0x%02x 0x%02x\n",				__FUNCTION__,				read_ecc[0], read_ecc[1], read_ecc[2],				calc_ecc[0], calc_ecc[1], calc_ecc[2],				dbg_ecc[0], dbg_ecc[1], dbg_ecc[2]);		panic("%s(): do not use MP2520F_HWECC\n", __FUNCTION__);		return ret;	}	return 0;}# endif /* CONFIG_MTD_NAND_MP2520F_HWECC_DEBUG */#endif /* CONFIG_MTD_NAND_MP2520F_HWECC *//* Internal buffers. Page buffer and oob buffer for one block */static u_char data_buf[2048 + 64]; /* maximum */static u_char oob_buf[64 * 32];    /* FIXME */int mp2520f_nand_init (void){	struct nand_chip *this;	int err = 0;#if USE_CPU_FCE == 0	set_gpio_ctrl(GPIO_nFCE0, GPIOMD_OUT, GPIOPU_NOSET);	set_gpio_ctrl(GPIO_nFCE1, GPIOMD_OUT, GPIOPU_NOSET);	set_gpio_ctrl(GPIO_nFCE2, GPIOMD_OUT, GPIOPU_NOSET);	set_gpio_ctrl(GPIO_nFCE3, GPIOMD_OUT, GPIOPU_NOSET);	/* deselect all chips */	write_gpio_bit(GPIO_nFCE0, 1);	write_gpio_bit(GPIO_nFCE1, 1);	write_gpio_bit(GPIO_nFCE2, 1);	write_gpio_bit(GPIO_nFCE3, 1);#endif /* USE_CPU_FCE */#if USE_CPU_RnB == 0	set_gpio_ctrl(GPIO_RnB, GPIOMD_IN, GPIOPU_NOSET);#endif	/* Allocate memory for MTD device structure and private data */	mp2520f_nand_mtd = vmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip));	if (!mp2520f_nand_mtd) {		printk ("Unable to allocate NAND MTD device structure.\n");		err = -ENOMEM;		goto out;	}	/* Get pointer to private data */	this = (struct nand_chip *) (&mp2520f_nand_mtd[1]);	/* Initialize structures */	memset((char *) mp2520f_nand_mtd, 0, sizeof(struct mtd_info));	memset((char *) this, 0, sizeof(struct nand_chip));	/* Link the private data with the MTD structure */	mp2520f_nand_mtd->priv = this;	/* Set address of NAND IO lines */#ifdef CONFIG_MMSP2_SHADOW_ENABLE	this->IO_ADDR_R = 0x9c000000;	this->IO_ADDR_W = 0x9c000000;#else	this->IO_ADDR_R = 0x1c000000;	this->IO_ADDR_W = 0x1c000000;#endif /* CONFIG_MMSP2_SHADOW_ENABLE */	this->select_chip = mp2520f_nand_select_chip;	this->dev_ready = mp2520f_nand_device_ready;	this->cmdfunc = mp2520f_nand_cmdfunc;#ifdef CONFIG_MTD_NAND_MP2520F_HWECC	this->calculate_ecc = mp2520f_calculate_ecc; // mp2520f_calculate_ecc_16	this->enable_hwecc = mp2520f_enable_hwecc;	this->eccmode = NAND_ECC_HW3_256; // NAND_ECC_HW6_512# ifdef CONFIG_MTD_NAND_MP2520F_HWECC_DEBUG	this->correct_data = mp2520f_correct_data_debug;	printk(__FILE__": Using NAND H/W ECC, debug mode\n");# else	this->correct_data = nand_correct_data;	printk(__FILE__": Using NAND H/W ECC\n");# endif /* CONFIG_MP2520F_HWECC_DEBUG */#else	this->eccmode = NAND_ECC_SOFT;	printk(__FILE__": Using NAND S/W ECC\n");#endif /* CONFIG_MP2520F_HWECC */	/* Set internal data buffer */	this->data_buf = data_buf;	this->oob_buf = oob_buf;	/* 20 us command delay time */	this->chip_delay = 20;			/* Scan to find existance of the device */	if (nand_scan (mp2520f_nand_mtd, 1)) {		err = -ENXIO;		goto out_mtd;	}	mp2520f_nand_mtd->eccsize = this->eccsize;	add_mtd_device(mp2520f_nand_mtd);	goto out;out_mtd:	free (mp2520f_nand_mtd);out:	return err;}

⌨️ 快捷键说明

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