From: SeonKon Choi <bushi@mizi.com>
To: MTD <linux-mtd@lists.infradead.org>
Subject: Re: Tips and Tricks for S3C2410 NAND controller?
Date: Sat, 09 Aug 2003 09:59:44 +0900 [thread overview]
Message-ID: <3F344780.8020803@mizi.com> (raw)
In-Reply-To: 3F336DA8.4040706@elsoft.ch
[-- Attachment #1: Type: text/plain, Size: 871 bytes --]
> 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
>
>
>
> ______________________________________________________
> 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
[-- Attachment #2: nand_s3c2410.c --]
[-- Type: text/plain, Size: 7971 bytes --]
/*
* NAND controller on SAMSUNG S3C2410
*
* bushi@mizi.com
*
* 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 */
prev parent reply other threads:[~2003-08-09 1:00 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-08-08 9:30 Tips and Tricks for S3C2410 NAND controller? "David Müller (ELSOFT AG)"
2003-08-08 9:47 ` David Woodhouse
2003-08-09 0:59 ` SeonKon Choi [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3F344780.8020803@mizi.com \
--to=bushi@mizi.com \
--cc=linux-mtd@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox