Subject: Re: Au1200 and NAND Flash - K9F1G08U0A -

From: Frank Neuber <[email-masked]>
Date: Thu, 12 Feb 2009 08:55:37 +0100

Hi Bora,
I have the same problem here.
Did you find a solution for this nand large page device.
I tried to copy nand_command_lp from nand_base.c and added the -CE stuff
including disabling interrupts during read.
The result is that I found just one bad block during scan :-). Also
erasing nand seems to be possible (usinf eraseall /dev/mtdX).
But if I write and read back the data (using dd) I get io errors :-(

I found your posting on this list wihout an answer so I hope you was
able to manage the nand stuff.

Kind Regards,
 Frank   

Am Samstag, den 19.05.2007, 22:13 +0300 schrieb [email-masked]:
> Hi,
> 
> We want to use NAND flash on Alchemy Au1200 and have a custom board along with 
> Db1200; so tried it both on our custom board and Db1200 without success.
> (Because Db1200 has a slot we opened it and replaced the original with our 
> part)
> 
> Kernel -> 2.6.20.1. Error messages:
> 
> NAND device: Manufacturer ID: 0xec, Chip ID: 0xf1 (Samsung NAND 128MiB 3,3V 
> 8-bit)
> Scanning device for bad blocks
> Bad eraseblock 0 at 0x00000000
> Bad eraseblock 1 at 0x00020000
> ...
> Bad eraseblock 1022 at 0x07fc0000
> Bad eraseblock 1023 at 0x07fe0000
> Creating 2 MTD partitions on "NAND 128MiB 3,3V 8-bit":
> 
> It marks all the eraseblocks as BAD. As far as I understand 
> "au1xxx_nand_command" seems doesnt work correctly. Has someone succeded to 
> work with these large block parts in the Au1200/Au1550?
> 
> Thanks...
> 
> --
> Bora SAHIN

---

From: Manuel Lauss <[email-masked]>
Date: Thu, 12 Feb 2009 09:17:07 +0100

> able to manage the nand stuff.

Here's the NAND portion of a DB1200 board support rewrite I did a while
ago.  It uses gen_nand instead of the au1550nd.c driver (which seems to
only work on the Db1550 and small page devices).  It shouls also work on
any Au1550 since the Au1200 has identical NAND hardware.

---------- 8< --------------------------- 8< ---------------------

#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>

[...]

static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
				 unsigned int ctrl)
{
	struct nand_chip *this = mtd->priv;
	unsigned long ioaddr = (unsigned long)this->IO_ADDR_W;

	ioaddr &= 0xffffff00;

	if (ctrl & NAND_CLE) {
		ioaddr += MEM_STNAND_CMD;
	} else if (ctrl & NAND_ALE) {
		ioaddr += MEM_STNAND_ADDR;
	} else {
		/* assume we want to r/w real data  by default */
		ioaddr += MEM_STNAND_DATA;
	}
	this->IO_ADDR_R = this->IO_ADDR_W = (void __iomem *)ioaddr;
	if (cmd != NAND_CMD_NONE) {
		au_writeb(cmd, ioaddr);
		au_sync();
	}
}

static int au1200_nand_device_ready(struct mtd_info *mtd)
{
	return au_readl(MEM_STSTAT) & 1;
}

static const char *db1200_part_probes[] = { "cmdlinepart", NULL };

static struct mtd_partition db1200_nand_parts[] = {
	{
		.name	= "NAND FS 0",
		.offset	= 0,
		.size	= 8 * 1024 * 1024,
	},
	{
		.name	= "NAND FS 1",
		.offset	= MTDPART_OFS_APPEND,
		.size	= MTDPART_SIZ_FULL
	},
};

struct platform_nand_data db1200_nand_platdata = {
	.chip = {
		.nr_chips	= 1,
		.chip_offset	= 0,
		.nr_partitions	= ARRAY_SIZE(db1200_nand_parts),
		.partitions	= db1200_nand_parts,
		.chip_delay	= 20,
		.part_probe_types = db1200_part_probes,
	},
	.ctrl = {
		.hwcontrol	= 0,
		.dev_ready	= au1200_nand_device_ready,
		.select_chip	= 0,
		.cmd_ctrl	= au1200_nand_cmd_ctrl,
	},
};

static struct resource db1200_nand_res[] = {
	[0] = {
		.start	= 0x20000000,
		.end	= 0x200000ff,
		.flags	= IORESOURCE_MEM,
	},
};

static struct platform_device nand_dev = {
	.name		= "gen_nand",
	.num_resources	= ARRAY_SIZE(db1200_nand_res),
	.resource	= db1200_nand_res,
	.id		= -1,
	.dev		= {
		.platform_data = &db1200_nand_platdata,
	}
};

[...]

static struct platform_device *db1200_devs[] __initdata = {
  [...]
	&nand_dev,
  [...]
};

-------------------- 8< ------------------------ 8< -------------------

Best regards,
	Manuel Lauss

---

From: Frank Neuber <[email-masked]>
Date: Thu, 12 Feb 2009 09:40:43 +0100

Thank you for this very quick answer ...

> ago.  It uses gen_nand instead of the au1550nd.c driver (which seems to
I saw this gen_nand (plat_nand.c) never before (because it is not
configurable in the Makefile)

> any Au1550 since the Au1200 has identical NAND hardware.
Do I understand right, this is not a handmade patch aginst
plat_nand.c ? 

I try to mix this code now with the plat_nand.c, rigth?

Kind regards,
 Frank

---

From: Manuel Lauss <[email-masked]>
Date: Thu, 12 Feb 2009 09:53:12 +0100

> I try to mix this code now with the plat_nand.c, rigth?

No no no no: this belongs in your board code (board_setup.c or whatever you
call it).  It's nothing more than registration of a platform_device plus
required information/callbacks for the gen_nand driver.

	Manuel Lauss

---

From: Frank Neuber <[email-masked]>
Date: Thu, 12 Feb 2009 14:24:50 +0100

Hi Manuel,
thank you for the code. It is working perfect :-)
I added this in arch/mips/au1000/common/platform.c.
1,94 MByte/s read performance.
I think it is a good idea to remove the au1550nd.c.

Thank's again,
 Frank