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

📄 mx2_nand.c

📁 nandflash k9g808u0a在pxa270的驱动,由于pxa270没有nandflash接口
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************	drivers/mtd/nand/mx2_nand.c	driver for i.MX21 on-chip NAND Flash controller.	tested with NAND Flash devices that come with MX21ADS board:	SAMSUNG K9F1208Q0A (8bit i/o)	SAMSUNG K9F5616Q0C (16Bit i/o)	Copyright (c) 2004 MontaVista Software, Inc. <source@mvista.com>	Based on mx2 nand support code from Motorola's MX21 BSP:	Copyright (C) 2003 Motorola Inc. Ltd	This program is free software; you can redistribute it and/or	modify it under the terms of the GNU General Public License	as published by the Free Software Foundation; either version 2	of the License, or (at your option) any later version.	This program is distributed in the hope that it will be useful,	but WITHOUT ANY WARRANTY; without even the implied warranty of	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the	GNU General Public License for more details.	You should have received a copy of the GNU General Public License	along with this program; if not, write to the Free Software	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.	********************************************************************************/#include <linux/slab.h>#include <linux/init.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <asm/arch/gpio.h>#include <asm/arch/pll.h>#include <asm/arch/hardware.h>static void mx2nand_setup_clock(void);#if 1 /*CEE LDM*/static char mx2nand_ldm_inited;#include <linux/device.h>extern void mx21_ldm_bus_register(struct device *device,                          struct device_driver *driver);extern void mx21_ldm_bus_unregister(struct device *device,                          struct device_driver *driver);static int mx2nand_freq_scale(struct bus_op_point * op, u32 level){	mx2nand_setup_clock();	return 0;}static struct device_driver __driver_ldm = {	.name = "mx2_nand",	.scale = mx2nand_freq_scale,};static struct device __device_ldm = {	.name = "NAND FLASH",	.bus_id = "mx2_nand",	.driver = &__driver_ldm,	.power_state = DPM_POWER_ON,};#endif#define NAND_FLASH_CONFIG2_INT 0x8000#define NAND_FLASH_CONFIG2_FCMD 0x1#define NAND_FLASH_CONFIG2_FADD 0x2#define NAND_FLASH_CONFIG2_FDI  0x4#define NAND_FLASH_CONFIG2_PAGE_OUT  0x8#define NAND_FLASH_CONFIG2_ID_OUT  0x10#define NAND_FLASH_CONFIG2_STATUS_OUT  0x20/*critical section*/#define MX2NAND_DECLARE_CS_FLAGS(name) u32 name#ifdef  CONFIG_MX2_16_BIT_NAND#define MX2NAND_ENTER_CS(x) do { \	save_flags(x); \	cli(); \	SYS_FMCR |= (1 << 4); \} while (0)#define MX2NAND_EXIT_CS(x) do { \	SYS_FMCR &= ~(1 << 4); \	restore_flags(x); \} while (0)#else#define MX2NAND_ENTER_CS(x) do { \	save_flags(x); \	cli(); \} while (0)#define MX2NAND_EXIT_CS(x) do { \	restore_flags(x); \} while (0)#endif#ifdef CONFIG_MTD_CMDLINE_PARTSconst char *mx2nand_probes[] = { "cmdlinepart", NULL };#endifstatic struct mtd_info *mx2nand_mtd = NULL;static u8 mx2nand_region_init;static u8 mx2nand_gpio_init;static void __init mx2nand_cleanup(void);#define NAND_TIMEOUT HZ*5struct mx2nand_priv {	u_char mode;	u_char cmd;	u32 offset;	u32 max_offset;};static uint8_t mx2nand_bi_pattern[] = { 0 };	/*bad block indicator pattern - I saw only 0's */#ifdef  CONFIG_MX2_16_BIT_NANDstatic struct nand_oobinfo mx2nand_oob = {	.useecc = MTD_NANDECC_AUTOPLACE,	.eccbytes = 0,		/* 0 instead of 3 to prevent writing attempts to ECC area */	.eccpos = {6, 7, 8},	/*no practical value - SW ECC write is disabled, handled by HW */	.oobfree = {{0, 6}, {12, 4}},	/*accessible bytes in the spare area */};static struct nand_bbt_descr mx2nand_bbt_descr = {	.options = 0,	.offs = 11,	.len = 1,	.pattern = mx2nand_bi_pattern,};#elsestatic struct nand_oobinfo mx2nand_oob = {	.useecc = MTD_NANDECC_AUTOPLACE,	.eccbytes = 0,		/* 0 instead of 3 to prevent writing attempts to ECC area */	.eccpos = {6, 7, 8},	/*no practical value - SW ECC write is disabled, handled by HW */	.oobfree = {{0, 5}, {11, 5}},	/*accessible bytes in the spare area */};static struct nand_bbt_descr mx2nand_bbt_descr = {	.options = 0,	.offs = 5,	.len = 1,	.pattern = mx2nand_bi_pattern,};#endifstatic intmx2nand_scan_bbt(struct mtd_info *mtd){	nand_scan_bbt(mtd, &mx2nand_bbt_descr);	return 0;}static intmx2nand_correct_data(struct mtd_info *mtd, u_char * dat,		     u_char * read_ecc, u_char * calc_ecc){/*ecc is handled entirely by the MX2 NFC*//*report ECC Uncorrectable error*/	if (NFC_ECC_STAT_RES & 0xA)		return -1;	else		return 0;}static voidmx2nand_enable_hwecc(struct mtd_info *mtd, int mode){/*ecc is handled entirely by the MX2 NFC*/}static intmx2nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,		      u_char * ecc_code){/*ecc is handled entirely by the MX2 NFC*/	return 0;}static voidmx2nand_wait(void){	unsigned long timeout;	timeout = jiffies + NAND_TIMEOUT;	while (!(NFC_NF_CONFIG2 & NAND_FLASH_CONFIG2_INT)) {		if (time_after(jiffies, timeout)) {			printk(KERN_ERR			       "MX2_NAND: timeout waiting for Nand command complete\n");			return;		}	}}static voidmx2nand_request_data(int cmd){	MX2NAND_DECLARE_CS_FLAGS(flags);	MX2NAND_ENTER_CS(flags);	switch (cmd) {	case NAND_CMD_READID:		NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_ID_OUT;		break;	case NAND_CMD_STATUS:		NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_STATUS_OUT;		break;	default:		NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_PAGE_OUT;	}	mx2nand_wait();	MX2NAND_EXIT_CS(flags);}static u_charmx2nand_read_byte(struct mtd_info *mtd){	struct nand_chip *chip_priv = mtd->priv;	struct mx2nand_priv *mx2_priv = chip_priv->priv;	char b;	u16 buf;	u32 offset = mx2_priv->offset;	int cmd = mx2_priv->cmd;	if (offset == 0) {		mx2nand_request_data(cmd);	}	if ((offset >= 512) || (cmd == NAND_CMD_READOOB))		buf = *((u16 *) NFC_SAB_BASE(3) + (offset >> 1));	else		buf = *((u16 *) NFC_MAB_BASE(3) + (offset >> 1));	b = ((u8 *) & buf)[offset & 0x1];#ifdef CONFIG_MX2_16_BIT_NAND	if (cmd == NAND_CMD_READID)		offset++;	/*skip 1 byte */#endif	offset++;	if (offset >= mx2_priv->max_offset)		offset = 0;	mx2_priv->offset = offset;	return b;}static u16mx2nand_read_word(struct mtd_info *mtd){	u8 buf[2];	buf[0] = mx2nand_read_byte(mtd);	buf[1] = mx2nand_read_byte(mtd);	return *(u16 *) buf;}static voidmx2nand_send_command(struct mtd_info *mtd, u8 cmd){	struct nand_chip *chip_priv = mtd->priv;	struct mx2nand_priv *mx2_priv = chip_priv->priv;	MX2NAND_DECLARE_CS_FLAGS(flags);	mx2_priv->cmd = cmd;	/*remember command for further				   internal handling */	if (cmd == NAND_CMD_PAGEPROG) {		MX2NAND_ENTER_CS(flags);		NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_FDI;		mx2nand_wait();		MX2NAND_EXIT_CS(flags);	}	/*send command */	NFC_NAND_FLASH_CMD = cmd;	MX2NAND_ENTER_CS(flags);	NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_FCMD;	if (cmd != NAND_CMD_RESET)		mx2nand_wait();	MX2NAND_EXIT_CS(flags);	/*extra command processing for read/write-prepare commands */	switch (cmd) {	case NAND_CMD_READ0:		NFC_NF_CONFIG1 = 0x8 | 0x2;	/*enable ECC, Spare + Main Area */		mx2_priv->offset = 0;		mx2_priv->max_offset = 528;		break;	case NAND_CMD_READOOB:		NFC_NF_CONFIG1 = 0xC | 0x2;	/*enable ECC, Spare Area Only */		mx2_priv->offset = 0;		mx2_priv->max_offset = 16;		break;	case NAND_CMD_READID:		NFC_NF_CONFIG1 = 0x8 | 0x2;	/*enable ECC, Spare + Main Area */		mx2_priv->offset = 0;#ifdef CONFIG_MX2_16_BIT_NAND		mx2_priv->max_offset = 12;#else		mx2_priv->max_offset = 6;#endif		break;	case NAND_CMD_STATUS:		NFC_NF_CONFIG1 = 0x8 | 0x2;	/*enable ECC, Spare + Main Area */		mx2_priv->offset = 0;		mx2_priv->max_offset = 1;		break;	}}static voidmx2nand_send_address(u8 addr){	MX2NAND_DECLARE_CS_FLAGS(flags);	NFC_NAND_FLASH_ADDR = addr;	MX2NAND_ENTER_CS(flags);	NFC_NF_CONFIG2 = NAND_FLASH_CONFIG2_FADD;	mx2nand_wait();	MX2NAND_EXIT_CS(flags);}static voidmx2nand_write_byte(struct mtd_info *mtd, u_char byte){	struct nand_chip *chip_priv = mtd->priv;	struct mx2nand_priv *mx2_priv = chip_priv->priv;	u32 offset;	u16 buf;	int cmd;	switch (mx2_priv->mode) {	case NAND_CTL_SETCLE:		mx2nand_send_command(mtd, byte);		break;	case NAND_CTL_SETALE:		mx2nand_send_address(byte);		break;	default:		offset = mx2_priv->offset;		cmd = mx2_priv->cmd;		if ((offset >= 512) || (cmd == NAND_CMD_READOOB))			buf = *((u16 *) NFC_SAB_BASE(3) + (offset >> 1));		else			buf = *((u16 *) NFC_MAB_BASE(3) + (offset >> 1));		((u8 *) & buf)[offset & 0x1] = byte;		if ((offset >= 512) || (cmd == NAND_CMD_READOOB))			*((u16 *) NFC_SAB_BASE(3) + (offset >> 1)) = buf;		else			*((u16 *) NFC_MAB_BASE(3) + (offset >> 1)) = buf;		offset++;		if (offset >= mx2_priv->max_offset)			offset = 0;		mx2_priv->offset = offset;

⌨️ 快捷键说明

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