All of lore.kernel.org
 help / color / mirror / Atom feed
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 */

      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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.