Tips and Tricks for S3C2410 NAND controller?
Hello
I have written a hardware driver for the NAND controller built in Samsung's S3C2410 SoC. I followed the instruction on
http://linux-mtd.infradead.org/tech/nand.html to implement it but it doesn't seem to work correctly.
Does anybody have some tricks or ideas what needs to be specially observed when using this controller?
TIA
Dave
Quoted 6 lines · David Müller (ELSOFT AG)
Hello
I have written a hardware driver for the NAND controller built in Samsung's S3C2410 SoC. I followed the instruction on
http://linux-mtd.infradead.org/tech/nand.html to implement it but it doesn't seem to work correctly.
Show code and describe symptoms. I've changed the interface to the core NAND code recently -- the docs will be slightly out of date.
Signature · 1 line
dwmw2
Quoted 15 lines
Hello
I have written a hardware driver for the NAND controller built in Samsung's S3C2410 SoC. I followed the instruction on
http://linux-mtd.infradead.org/tech/nand.html to implement it but it doesn't seem to work correctly.Does anybody have some tricks or ideas what needs to be specially observed when using this controller?
TIA
Quoted 7 lines
Dave
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
Hi,
attached file is my implementation against with MTD CVS Jul.06.2003.
(
ignore the BONFS dependency in source code. it's a read-only
block-device layer that support the bad-block-management on NAND flash for general filesystem such as cramfs, ...
)
my boss says,
"do not any technical-support about these. just open the source."
Bushi
/*
* NAND controller on SAMSUNG S3C2410
*
* [email protected]
*
* 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/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <asm/arch/hardware.h>
#include <asm/sizes.h>
static struct mtd_info *s3c2410_nand_mtd = NULL;
/*
* if you use the BON,
* the partition table for MTD blkdev will be generated by "bon_check_mtd()". */
#ifdef CONFIG_MTD_NAND_BONFS
static int mtd_num = 0;
static struct mtd_partition *partition_info = NULL;
extern struct nand_oobinfo bonfs_oob;
extern int bon_check_mtd(struct mtd_info *mtd, struct mtd_partition **mtd_table); #endif /* CONFIG_MTD_NAND_BONFS */
static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
{
if (chip == 0)
NFCONF &= ~NFCONF_nFCE_HIGH;
else
NFCONF |= NFCONF_nFCE_HIGH;
}static int s3c2410_nand_device_ready(struct mtd_info *mtd)
{
return (NFSTAT & NFSTAT_RnB) ? 1:0;
}static void s3c2410_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) {
register struct nand_chip *this = mtd->priv;
/*
* 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);
}
/* Latch in address */
}
/*
* 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_RESET:
if (this->dev_ready)
break;
NFCMD = NAND_CMD_STATUS;
while ( !(NFDATA & 0x40));
return;
/* 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));
}/*
* Main initialization routine
*/
int __init s3c2410_nand_init (void)
{
struct nand_chip *this;
u_int16_t nfconf;
int err = 0;
/* Allocate memory for MTD device structure and private data */
s3c2410_nand_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
GFP_KERNEL);
if (!s3c2410_nand_mtd) {
printk ("Unable to allocate NAND MTD device structure.\n");
err = -ENOMEM;
goto out;
}
/* Get pointer to private data */
this = (struct nand_chip *) (&s3c2410_nand_mtd[1]);
/* Initialize structures */
memset((char *) s3c2410_nand_mtd, 0, sizeof(struct mtd_info));
memset((char *) this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
s3c2410_nand_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 = io_p2v(0x4e00000c);
this->IO_ADDR_W = io_p2v(0x4e00000c);
this->select_chip = s3c2410_nand_select_chip;
this->dev_ready = s3c2410_nand_device_ready;
this->cmdfunc = s3c2410_nand_cmdfunc;
this->eccmode = NAND_ECC_SOFT;
/* 20 us command delay time */
this->chip_delay = 20;
/* Scan to find existance of the device */
if (nand_scan (s3c2410_nand_mtd, 1)) {
err = -ENXIO;
goto out_mtd;
}
/* Allocate memory for internal data buffer */
this->data_buf = kmalloc (sizeof(u_char) * (s3c2410_nand_mtd->oobblock + s3c2410_nand_mtd->oobsize), GFP_KERNEL);
if (!this->data_buf) {
printk ("Unable to allocate NAND data buffer\n");
err = -ENOMEM;
goto out_mtd;
}#ifdef CONFIG_MTD_NAND_BONFS s3c2410_nand_mtd->oobinfo = bonfs_oob; mtd_num = bon_check_mtd(s3c2410_nand_mtd, &partition_info); if (mtd_num > 1) add_mtd_partitions(s3c2410_nand_mtd, partition_info, mtd_num); else add_mtd_device(s3c2410_nand_mtd); #else add_mtd_device(s3c2410_nand_mtd);
#endif
goto out;
out_cac:
kfree (this->data_buf); out_mtd: kfree (s3c2410_nand_mtd); out: return err; }
module_init(s3c2410_nand_init);
/*
* Clean up routine
*/
#ifdef MODULE
static void __exit s3c2410_nand_cleanup (void)
{
struct nand_chip *this = (struct nand_chip *) &s3c2410_nand_mtd[1];
/* Unregister partitions */
del_mtd_partitions(s3c2410_nand_mtd);
/* Unregister the device */
del_mtd_device (s3c2410_nand_mtd);
/* Free internal data buffers */
kfree (this->data_buf);
/* Free the MTD device structure */
kfree (s3c2410_nand_mtd);
}module_exit(s3c2410_nand_cleanup);
#endif
MODULE_LICENSE("GPL");
/*
* NAND Flash Controller (Page 6-1 ~ 6-8)
*
* Register
NFCONF NAND Flash Configuration [word, R/W, 0x00000000] NFCMD NAND Flash Command Set [word, R/W, 0x00000000] NFADDR NAND Flash Address Set [word, R/W, 0x00000000] NFDATA NAND Flash Data [word, R/W, 0x00000000] NFSTAT NAND Flash Status [word, R, 0x00000000] NFECC NAND Flash ECC [3 bytes, R, 0x00000000]
*
*/
#if 0
#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)
#endif /* 0 */