public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* Tips and Tricks for S3C2410 NAND controller?
@ 2003-08-08  9:30 "David Müller (ELSOFT AG)"
  2003-08-08  9:47 ` David Woodhouse
  2003-08-09  0:59 ` SeonKon Choi
  0 siblings, 2 replies; 3+ messages in thread
From: "David Müller (ELSOFT AG)" @ 2003-08-08  9:30 UTC (permalink / raw)
  To: linux-mtd

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

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Tips and Tricks for S3C2410 NAND controller?
  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
  1 sibling, 0 replies; 3+ messages in thread
From: David Woodhouse @ 2003-08-08  9:47 UTC (permalink / raw)
  To: "David Müller (ELSOFT AG)"; +Cc: linux-mtd

On Fri, 2003-08-08 at 10:30, "David Müller (ELSOFT AG)" wrote:
> 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. 

-- 
dwmw2

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Tips and Tricks for S3C2410 NAND controller?
  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
  1 sibling, 0 replies; 3+ messages in thread
From: SeonKon Choi @ 2003-08-09  0:59 UTC (permalink / raw)
  To: MTD

[-- 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 */

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2003-08-09  1:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox