📄 s3c2410_nand.c
字号:
/* * MTD NAND device driver for S3C2410 Development Board * based on smc.c * * 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 <linux/slab.h>#include <linux/init.h>#include <linux/module.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/partitions.h>#include <asm/io.h>#include <asm/sizes.h>#ifdef CONFIG_PM#include <linux/pm.h>#endif#ifdef CONFIG_PMstruct pm_dev *smc_pm_dev;#endif#define bNAND_CTL(Nb) __REG(0x4e000000 + (Nb))#define NFCONF bNAND_CTL(0x00)#define NFCMD bNAND_CTL(0x04)#define NFADDR bNAND_CTL(0x08)#define NFDATA bNAND_CTL(0x0c)#define NFSTAT bNAND_CTL(0x10)#define NFECC bNAND_CTL(0x14)#define fNFCONF_TWRPH1 Fld(3,0)#define NFCONF_TWRPH1 FMsk(fNFCONF_TWRPH1)#define NFCONF_TWRPH1_0 FInsrt(0x0, fNFCONF_TWRPH1) /* 0 */#define fNFCONF_TWRPH0 Fld(3,4)#define NFCONF_TWRPH0 FMsk(fNFCONF_TWRPH0)#define NFCONF_TWRPH0_3 FInsrt(0x3, fNFCONF_TWRPH0) /* 3 */#define fNFCONF_TACLS Fld(3,8)#define NFCONF_TACLS FMsk(fNFCONF_TACLS)#define NFCONF_TACLS_0 FInsrt(0x0, fNFCONF_TACLS) /* 0 */#define fNFCONF_nFCE Fld(1,11)#define NFCONF_nFCE FMsk(fNFCONF_nFCE)#define NFCONF_nFCE_LOW FInsrt(0x0, fNFCONF_nFCE) /* active */#define NFCONF_nFCE_HIGH FInsrt(0x1, fNFCONF_nFCE) /* inactive */#define fNFCONF_ECC Fld(1,12)#define NFCONF_ECC FMsk(fNFCONF_ECC)#define NFCONF_ECC_NINIT FInsrt(0x0, fNFCONF_ECC) /* not initialize */#define NFCONF_ECC_INIT FInsrt(0x1, fNFCONF_ECC) /* initialize */#define fNFCONF_ADDRSTEP Fld(1,13) /* Addressing Step */#define NFCONF_ADDRSTEP FMsk(fNFCONF_ADDRSTEP)#define fNFCONF_PAGESIZE Fld(1,14)#define NFCONF_PAGESIZE FMsk(fNFCONF_PAGESIZE)#define NFCONF_PAGESIZE_256 FInsrt(0x0, fNFCONF_PAGESIZE) /* 256 bytes */#define NFCONF_PAGESIZE_512 FInsrt(0x1, fNFCONF_PAGESIZE) /* 512 bytes */#define fNFCONF_FCTRL Fld(1,15) /* Flash controller enable/disable */#define NFCONF_FCTRL FMsk(fNFCONF_FCTRL)#define NFCONF_FCTRL_DIS FInsrt(0x0, fNFCONF_FCTRL) /* Disable */#define NFCONF_FCTRL_EN FInsrt(0x1, fNFCONF_FCTRL) /* Enable */#define NFSTAT_RnB (1 << 0)#define NFSTAT_nFWE (1 << 8)#define NFSTAT_nFRE (1 << 9)#define NFSTAT_ALE (1 << 10)#define NFSTAT_CLE (1 << 11)#define NFSTAT_AUTOBOOT (1 << 15)/* * MTD structure for S3C2410 Development Board */static struct mtd_info *s3c2410_mtd = NULL;#ifdef CONFIG_MTD_PARTITIONSstatic struct mtd_partition partition_info[] = { { name: "boot", offset: 0, size: SZ_128K + SZ_64K }, { name: "kernel", offset: SZ_128K + SZ_64K, size: SZ_2M - SZ_128K - SZ_64K}, { name: "rootfs", offset: SZ_2M, size: 62 * SZ_1M },/* { name: "ext-fs1", offset: SZ_32M, size: SZ_16M }, { name: "ext-fs2", offset: SZ_32M + SZ_16M, size: SZ_16M }*/};#endifstatic void smc_hwcontrol(struct mtd_info *mtd, int cmd) { struct nand_chip *my_nand = mtd->priv; switch (cmd) { case NAND_CTL_SETNCE: NFCONF &= ~NFCONF_nFCE_HIGH; break; case NAND_CTL_CLRNCE: NFCONF |= NFCONF_nFCE_HIGH; break; case NAND_CTL_SETCLE: my_nand->IO_ADDR_W = &NFCMD; break; case NAND_CTL_CLRCLE: my_nand->IO_ADDR_W = &NFDATA; break; case NAND_CTL_SETALE: my_nand->IO_ADDR_W = &NFADDR; break; case NAND_CTL_CLRALE: my_nand->IO_ADDR_W = &NFDATA; break; }}static void smc_command (struct mtd_info *mtd, unsigned command, int column, int page_addr){ register struct nand_chip *my_nand = mtd->priv; /* * Write out the command to the device. */ if (command != NAND_CMD_SEQIN) NFCMD = command; else { if (mtd->oobblock == 256 && column >= 256) { column -= 256; NFCMD = NAND_CMD_RESET; NFCMD = NAND_CMD_READOOB; NFCMD = NAND_CMD_SEQIN; } else if (mtd->oobblock == 512 && column >= 256) { if (column < 512) { column -= 256; NFCMD = NAND_CMD_READ1; NFCMD = NAND_CMD_SEQIN; } else { column -= 512; NFCMD = NAND_CMD_READOOB; NFCMD = NAND_CMD_SEQIN; } } else { NFCMD = NAND_CMD_READ0; NFCMD = NAND_CMD_SEQIN; } } /* Serially input address */ if (column != -1) NFADDR = column; 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); } } /* wait until command is processed */ while (!my_nand->dev_ready(mtd)) ;}static u_char read_data(struct mtd_info *mtd) { return (u_char) NFDATA;}static void write_data(struct mtd_info *mtd, u_char val) { NFDATA = (u_char) val;}static int device_ready(struct mtd_info *mtd) { return (NFSTAT & NFSTAT_RnB);}#ifdef CONFIG_PMstatic unsigned long nfcon;static ints3c2410_smc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){ struct nand_chip *this = (struct nand_chip *)pm_dev->data; switch (req) { case PM_SUSPEND: nfcon = NFCONF; break; case PM_RESUME: NFCONF = nfcon; /* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */ this->hwcontrol(s3c2410_mtd, NAND_CTL_SETNCE); this->cmdfunc(s3c2410_mtd, NAND_CMD_RESET, -1, -1); while(!this->dev_ready(s3c2410_mtd)); this->hwcontrol(s3c2410_mtd, NAND_CTL_CLRNCE); break; } return 0;}#endif/* * Main initialization routine */int __init smc_s3c2410_init (void){ struct nand_chip *this; u_int16_t nfconf; int err = 0; /* Allocate memory for MTD device structure and private data */ s3c2410_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); if (!s3c2410_mtd) { printk ("Unable to allocate S3C2410 NAND MTD device structure.\n"); return -ENOMEM; } /* Get pointer to private data */ this = (struct nand_chip *) (&s3c2410_mtd[1]); /* Initialize structures */ memset((char *) s3c2410_mtd, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); /* Link the private data with the MTD structure */ s3c2410_mtd->priv = this; /* set NAND Flash controller */ { nfconf = NFCONF; /* NAND Flash controller enable */ nfconf |= NFCONF_FCTRL_EN; /* Set flash memory timing */ nfconf &= ~NFCONF_TWRPH1; /* 0x0 */ nfconf |= NFCONF_TWRPH0_3; /* 0x3 */ nfconf &= ~NFCONF_TACLS; /* 0x0 */ NFCONF = nfconf; } /* Set address of NAND IO lines */ this->IO_ADDR_R = &NFDATA; this->IO_ADDR_W = &NFDATA; this->hwcontrol = smc_hwcontrol; this->dev_ready = device_ready; this->cmdfunc = smc_command; this->chip_delay = 20; this->eccmode = NAND_ECC_NONE;//NAND_ECC_SOFT;// this->write_cmd = write_cmd;// this->write_addr = write_addr;// this->read_byte = read_data;// this->write_byte = write_data; /* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */ this->hwcontrol(s3c2410_mtd, NAND_CTL_SETNCE); this->cmdfunc(s3c2410_mtd, NAND_CMD_RESET, -1, -1); while(!this->dev_ready(s3c2410_mtd)); this->hwcontrol(s3c2410_mtd, NAND_CTL_CLRNCE); /* Scan to find existance of the device */ if (nand_scan (s3c2410_mtd, 1)) { err = -ENXIO; goto out_mtd; } /* Allocate memory for internal data buffer */ this->data_buf = kmalloc(sizeof(u_char) * (s3c2410_mtd->oobblock + s3c2410_mtd->oobsize), GFP_KERNEL); if (!this->data_buf) { printk ("Unable to allocate NAND data buffer for S3C2410.\n"); err = -ENOMEM; goto out_mtd; }#ifdef CONFIG_MTD_PARTITIONS switch(s3c2410_mtd->size) { case SZ_16M: err = add_mtd_partitions(s3c2410_mtd, partition_info, ARRAY_SIZE (partition_info)-2 ); break; case SZ_32M: err = add_mtd_partitions(s3c2410_mtd, partition_info, ARRAY_SIZE (partition_info)-1); break; case SZ_64M: err = add_mtd_partitions(s3c2410_mtd, partition_info, ARRAY_SIZE (partition_info)); break; default: printk ("Unsupported SmartMedia device\n"); err = -ENXIO; goto out_cac; }#else add_mtd_device(s3c2410_mtd);#endif#ifdef CONFIG_PM smc_pm_dev = pm_register(PM_DEBUG_DEV, PM_SYS_MISC, s3c2410_smc_pm_callback); if (smc_pm_dev) smc_pm_dev->data = &s3c2410_mtd[1];#endif goto out;out_cac: kfree (this->data_buf);out_mtd: kfree (s3c2410_mtd);out: return err;}module_init(smc_s3c2410_init);/* * Clean up routine */#ifdef MODULEstatic void __exit smc_s3c2410_cleanup (void){ struct nand_chip *this = (struct nand_chip *) &s3c2410_mtd[1];#if defined(CONFIG_MTD_SMC_S3C2410_SMDK_PARTITION) del_mtd_partitions(s3c2410_mtd);#else del_mtd_device(s3c2410_mtd);#endif kfree (this->data_buf); kfree (s3c2410_mtd);}module_exit(smc_s3c2410_cleanup);#endifMODULE_LICENSE("GPL");MODULE_AUTHOR("Yong-iL Joh <tolkien@mizi.com>");MODULE_DESCRIPTION("SMC Card on S3C2410 board");/* | $Id: smc_s3c2410.c,v 1.1.2.2 2002/05/30 08:14:44 cgjeong Exp $ | | Local Variables: | mode: c | mode: font-lock | version-control: t | delete-old-versions: t | c-basic-offset: 2 | tab-width: 8 | End: | | -*- End-Of-File -*- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -