linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V4 0/2] Nand and OneNand for ARM Nomadik
@ 2009-07-22 22:25 Alessandro Rubini
  2009-07-22 22:25 ` [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board) Alessandro Rubini
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-22 22:25 UTC (permalink / raw)
  To: linux-mtd; +Cc: STEricsson_nomadik_linux, linux, andrea.gallo

These two patches are the ones I last posted on Jun 22nd 2009 (thus
with all comments accepted), rebased to current master.

At this time, the arch/arm/mach-nomadik files have been accepted in
Russell's tree ("nomadik branch", I'm told), but I can't find a public
repository for that tree.

So these are from the tip of my rebased tree, and I think only
Rusell can apply them cleanly. So I Cc: him while posting to linux-mtd.

Thanks for your patience
/alessandro

Alessandro Rubini (2):
  Nand driver for Nomadik 8815 SoC (on NHK8815 board)
  OneNand support for Nomadik 8815 SoC (on NHK8815 board)

 arch/arm/mach-nomadik/board-nhk8815.c     |  155 ++++++++++++++
 arch/arm/mach-nomadik/include/mach/fsmc.h |   29 +++
 arch/arm/mach-nomadik/include/mach/nand.h |   16 ++
 drivers/mtd/nand/Kconfig                  |    6 +
 drivers/mtd/nand/Makefile                 |    1 +
 drivers/mtd/nand/nomadik_nand.c           |  329 +++++++++++++++++++++++++++++
 6 files changed, 536 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-nomadik/include/mach/fsmc.h
 create mode 100644 arch/arm/mach-nomadik/include/mach/nand.h
 create mode 100644 drivers/mtd/nand/nomadik_nand.c

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

* [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-22 22:25 [PATCH V4 0/2] Nand and OneNand for ARM Nomadik Alessandro Rubini
@ 2009-07-22 22:25 ` Alessandro Rubini
  2009-07-22 22:25   ` Alessandro Rubini
  2009-07-22 22:26 ` [PATCH V4 2/2] OneNand support " Alessandro Rubini
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-22 22:25 UTC (permalink / raw)
  To: linux-mtd; +Cc: STEricsson_nomadik_linux, linux, andrea.gallo


Signed-off-by: Alessandro Rubini <rubini@unipv.it>
Acked-by: Andrea Gallo <andrea.gallo@stericsson.com>
---
 arch/arm/mach-nomadik/board-nhk8815.c     |   92 ++++++++
 arch/arm/mach-nomadik/include/mach/fsmc.h |   29 +++
 arch/arm/mach-nomadik/include/mach/nand.h |   16 ++
 drivers/mtd/nand/Kconfig                  |    6 +
 drivers/mtd/nand/Makefile                 |    1 +
 drivers/mtd/nand/nomadik_nand.c           |  329 +++++++++++++++++++++++++++++
 6 files changed, 473 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-nomadik/include/mach/fsmc.h
 create mode 100644 arch/arm/mach-nomadik/include/mach/nand.h
 create mode 100644 drivers/mtd/nand/nomadik_nand.c

diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 79bdea9..3fde972 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -16,12 +16,103 @@
 #include <linux/amba/bus.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/sizes.h>
+#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <mach/setup.h>
+#include <mach/nand.h>
+#include <mach/fsmc.h>
 #include "clock.h"
 
+/* These adresses span 16MB, so use three individual pages */
+static struct resource nhk8815_nand_resources[] = {
+	{
+		.name = "nand_addr",
+		.start = NAND_IO_ADDR,
+		.end = NAND_IO_ADDR + 0xfff,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.name = "nand_cmd",
+		.start = NAND_IO_CMD,
+		.end = NAND_IO_CMD + 0xfff,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.name = "nand_data",
+		.start = NAND_IO_DATA,
+		.end = NAND_IO_DATA + 0xfff,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static int nhk8815_nand_init(void)
+{
+	/* FSMC setup for nand chip select (8-bit nand in 8815NHK) */
+	writel(0x0000000E, FSMC_PCR(0));
+	writel(0x000D0A00, FSMC_PMEM(0));
+	writel(0x00100A00, FSMC_PATT(0));
+
+	/* enable access to the chip select area */
+	writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0));
+
+	return 0;
+}
+
+/*
+ * These partitions are the same as those used in the 2.6.20 release
+ * shipped by the vendor; the first two partitions are mandated
+ * by the boot ROM, and the bootloader area is somehow oversized...
+ */
+static struct mtd_partition nhk8815_partitions[] = {
+	{
+		.name	= "X-Loader(NAND)",
+		.offset = 0,
+		.size	= SZ_256K,
+	}, {
+		.name	= "MemInit(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_256K,
+	}, {
+		.name	= "BootLoader(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_2M,
+	}, {
+		.name	= "Kernel zImage(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 3 * SZ_1M,
+	}, {
+		.name	= "Root Filesystem(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 22 * SZ_1M,
+	}, {
+		.name	= "User Filesystem(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= MTDPART_SIZ_FULL,
+	}
+};
+
+static struct nomadik_nand_platform_data nhk8815_nand_data = {
+	.parts		= nhk8815_partitions,
+	.nparts		= ARRAY_SIZE(nhk8815_partitions),
+	.options	= NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING \
+			| NAND_NO_READRDY | NAND_NO_AUTOINCR,
+	.init		= nhk8815_nand_init,
+};
+
+static struct platform_device nhk8815_nand_device = {
+	.name		= "nomadik_nand",
+	.dev		= {
+				.platform_data = &nhk8815_nand_data,
+	},
+	.resource	= nhk8815_nand_resources,
+	.num_resources	= ARRAY_SIZE(nhk8815_nand_resources),
+};
+
+
 #define __MEM_4K_RESOURCE(x) \
 	.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
 
@@ -81,6 +172,7 @@ static int __init nhk8815_eth_init(void)
 device_initcall(nhk8815_eth_init);
 
 static struct platform_device *nhk8815_platform_devices[] __initdata = {
+	&nhk8815_nand_device,
 	&nhk8815_eth_device,
 	/* will add more devices */
 };
diff --git a/arch/arm/mach-nomadik/include/mach/fsmc.h b/arch/arm/mach-nomadik/include/mach/fsmc.h
new file mode 100644
index 0000000..8c2c051
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/fsmc.h
@@ -0,0 +1,29 @@
+
+/* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */
+
+#ifndef __ASM_ARCH_FSMC_H
+#define __ASM_ARCH_FSMC_H
+
+#include <mach/hardware.h>
+/*
+ * Register list
+ */
+
+/* bus control reg. and bus timing reg. for CS0..CS3 */
+#define FSMC_BCR(x)     (NOMADIK_FSMC_VA + (x << 3))
+#define FSMC_BTR(x)     (NOMADIK_FSMC_VA + (x << 3) + 0x04)
+
+/* PC-card and NAND:
+ * PCR = control register
+ * PMEM = memory timing
+ * PATT = attribute timing
+ * PIO = I/O timing
+ * PECCR = ECC result
+ */
+#define FSMC_PCR(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x00)
+#define FSMC_PMEM(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x08)
+#define FSMC_PATT(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x0c)
+#define FSMC_PIO(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x10)
+#define FSMC_PECCR(x)   (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x14)
+
+#endif /* __ASM_ARCH_FSMC_H */
diff --git a/arch/arm/mach-nomadik/include/mach/nand.h b/arch/arm/mach-nomadik/include/mach/nand.h
new file mode 100644
index 0000000..c3c8254
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/nand.h
@@ -0,0 +1,16 @@
+#ifndef __ASM_ARCH_NAND_H
+#define __ASM_ARCH_NAND_H
+
+struct nomadik_nand_platform_data {
+	struct mtd_partition *parts;
+	int nparts;
+	int options;
+	int (*init) (void);
+	int (*exit) (void);
+};
+
+#define NAND_IO_DATA	0x40000000
+#define NAND_IO_CMD	0x40800000
+#define NAND_IO_ADDR	0x41000000
+
+#endif				/* __ASM_ARCH_NAND_H */
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index ce96c09..b9fa465 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,12 @@ config MTD_NAND_MXC
 	  This enables the driver for the NAND flash controller on the
 	  MXC processors.
 
+config MTD_NAND_NOMADIK
+	tristate "ST Nomadik 8815 NAND support"
+	depends on ARCH_NOMADIK
+	help
+	  Driver for the NAND flash controller on the Nomadik, with ECC.
+
 config MTD_NAND_SH_FLCTL
 	tristate "Support for NAND on Renesas SuperH FLCTL"
 	depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index f3a786b..0fe9a0c 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -40,5 +40,6 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
 obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
 obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
+obj-$(CONFIG_MTD_NAND_NOMADIK)		+= nomadik_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c
new file mode 100644
index 0000000..bbd1925
--- /dev/null
+++ b/drivers/mtd/nand/nomadik_nand.c
@@ -0,0 +1,329 @@
+/*
+ *  drivers/mtd/nand/nomadik_nand.c
+ *
+ *  Overview:
+ *  	Driver for on-board NAND flash on Nomadik Platforms
+ *
+ * Copyright (C) 2007 STMicroelectronics Pvt. Ltd.
+ * Author: Sachin Verma <sachin.verma@st.com>
+ *
+ * Copyright (C) 2009 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+#include <mach/nand.h>
+#include <mach/fsmc.h>
+
+#include <mtd/mtd-abi.h>
+
+struct nomadik_nand_host {
+	struct mtd_info		mtd;
+	struct nand_chip	nand;
+	void __iomem *data_va;
+	void __iomem *cmd_va;
+	void __iomem *addr_va;
+	struct nand_bbt_descr *bbt_desc;
+};
+
+static inline int parity(int b) /* uses low 8 bits: returns 0 or all-1 */
+{
+	b = b ^ (b >> 4);
+	b = b ^ (b >> 2);
+	return (b ^ (b >> 1)) & 1
+		? ~0 : 0;
+}
+
+/*
+ * This is the ECC routine used in hardware, according to the manual.
+ * HW claims to make the calculation but not the correction. However,
+ * I haven't managed to get the desired data out of it; so do it in sw.
+ * There is problably some errata involved, but currently miss the info.
+ */
+static int nomadik_ecc512_calc(struct mtd_info *mtd, const u_char *data,
+			u_char *ecc)
+{
+	int gpar = 0;
+	int i, val, par;
+	int pbits = 0;		/* P8, P16, ... P2048 */
+	int pprime = 0;		/* P8', P16', ... P2048' */
+	int lowbits;		/* P1, P2, P4 and primes */
+
+	for (i = 0; i < 512; i++) {
+		par = parity((val = data[i]));
+		gpar ^= val;
+		pbits ^= (i & par);
+	}
+	/*
+	 * Ok, now gpar is global parity (xor of all bytes)
+	 * pbits are all the parity bits (non-prime ones)
+	 */
+	par = parity(gpar);
+	pprime = pbits ^ par;
+	/* Put low bits in the right position for ecc[2] (bits 7..2) */
+	lowbits = 0
+		| (parity(gpar & 0xf0) & 0x80)	/* P4  */
+		| (parity(gpar & 0x0f) & 0x40)	/* P4' */
+		| (parity(gpar & 0xcc) & 0x20)	/* P2  */
+		| (parity(gpar & 0x33) & 0x10)	/* P2' */
+		| (parity(gpar & 0xaa) & 0x08)	/* P1  */
+		| (parity(gpar & 0x55) & 0x04);	/* P1' */
+
+	ecc[2] = ~(lowbits | ((pbits & 0x100) >> 7) | ((pprime & 0x100) >> 8));
+	/* now intermix bits for ecc[1] (P1024..P128') and ecc[0] (P64..P8') */
+	ecc[1] = ~(    (pbits & 0x80) >> 0  | ((pprime & 0x80) >> 1)
+		    | ((pbits & 0x40) >> 1) | ((pprime & 0x40) >> 2)
+		    | ((pbits & 0x20) >> 2) | ((pprime & 0x20) >> 3)
+		    | ((pbits & 0x10) >> 3) | ((pprime & 0x10) >> 4));
+
+	ecc[0] = ~(    (pbits & 0x8) << 4  | ((pprime & 0x8) << 3)
+		    | ((pbits & 0x4) << 3) | ((pprime & 0x4) << 2)
+		    | ((pbits & 0x2) << 2) | ((pprime & 0x2) << 1)
+		    | ((pbits & 0x1) << 1) | ((pprime & 0x1) << 0));
+	return 0;
+}
+
+static int nomadik_ecc512_correct(struct mtd_info *mtd, uint8_t *dat,
+				uint8_t *r_ecc, uint8_t *c_ecc)
+{
+	struct nand_chip *chip = mtd->priv;
+	uint32_t r, c, d, diff; /*read, calculated, xor of them */
+
+	if (!memcmp(r_ecc, c_ecc, chip->ecc.bytes))
+		return 0;
+
+	/* Reorder the bytes into ascending-order 24 bits -- see manual */
+	r = r_ecc[2] << 22 | r_ecc[1] << 14 | r_ecc[0] << 6 | r_ecc[2] >> 2;
+	c = c_ecc[2] << 22 | c_ecc[1] << 14 | c_ecc[0] << 6 | c_ecc[2] >> 2;
+	diff = (r ^ c) & ((1 << 24) - 1); /* use 24 bits only */
+
+	/* If 12 bits are different, one per pair, it's correctable */
+	if (((diff | (diff>>1)) & 0x555555) == 0x555555) {
+		int bit = ((diff & 2) >> 1)
+			| ((diff & 0x8) >> 2) | ((diff & 0x20) >> 3);
+		int byte;
+
+		d = diff >> 6; /* remove bit-order info */
+		byte =  ((d & 2) >> 1)
+			| ((d & 0x8) >> 2) | ((d & 0x20) >> 3)
+			| ((d & 0x80) >> 4) | ((d & 0x200) >> 5)
+			| ((d & 0x800) >> 6) | ((d & 0x2000) >> 7)
+			| ((d & 0x8000) >> 8) | ((d & 0x20000) >> 9);
+		/* correct the single bit */
+		dat[byte] ^= 1 << bit;
+		return 0;
+	}
+	/* If 1 bit only differs, it's one bit error in ECC, ignore */
+	if ((diff ^ (1 << (ffs(diff) - 1))) == 0)
+		return 0;
+	/* Otherwise, uncorrectable */
+	return -1;
+}
+
+static struct nand_ecclayout nomadik_ecc_layout = {
+	.eccbytes = 3 * 4,
+	.eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
+		0x02, 0x03, 0x04,
+		0x12, 0x13, 0x14,
+		0x22, 0x23, 0x24,
+		0x32, 0x33, 0x34},
+	/* let's keep bytes 5,6,7 for us, just in case we change ECC algo */
+	.oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} },
+};
+
+static void nomadik_ecc_control(struct mtd_info *mtd, int mode)
+{
+	/* No need to enable hw ecc, it's on by default */
+}
+
+static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct nomadik_nand_host *host = nand->priv;
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd, host->cmd_va);
+	else
+		writeb(cmd, host->addr_va);
+}
+
+static int nomadik_nand_probe(struct platform_device *pdev)
+{
+	struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
+	struct nomadik_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	struct resource *res;
+	int ret = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL);
+	if (!host) {
+		dev_err(&pdev->dev, "Failed to allocate device structure.\n");
+		return -ENOMEM;
+	}
+
+	/* Call the client's init function, if any */
+	if (pdata->init && (ret = pdata->init()) < 0) {
+		dev_err(&pdev->dev, "Init function failed\n");
+		goto err;
+	}
+
+	/* ioremap three regions */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
+	if (!res) {ret = -EIO; goto err_unmap; }
+	host->addr_va = ioremap(res->start, res->end - res->start + 1);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
+	if (!res) {ret = -EIO; goto err_unmap; }
+	host->data_va = ioremap(res->start, res->end - res->start + 1);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
+	if (!res) {ret = -EIO; goto err_unmap; }
+	host->cmd_va = ioremap(res->start, res->end - res->start + 1);
+
+	if (!host->addr_va || !host->data_va || !host->cmd_va) {
+		ret = -ENOMEM;
+		goto err_unmap;
+	}
+
+	/* Link all private pointers */
+	mtd = &host->mtd;
+	nand = &host->nand;
+	mtd->priv = nand;
+	nand->priv = host;
+
+	host->mtd.owner = THIS_MODULE;
+	nand->IO_ADDR_R = host->data_va;
+	nand->IO_ADDR_W = host->data_va;
+	nand->cmd_ctrl = nomadik_cmd_ctrl;
+
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.layout = &nomadik_ecc_layout;
+	nand->ecc.calculate = nomadik_ecc512_calc;
+	nand->ecc.correct = nomadik_ecc512_correct;
+	nand->ecc.hwctl = nomadik_ecc_control;
+	nand->ecc.size = 512;
+	nand->ecc.bytes = 3;
+
+	nand->options = pdata->options;
+
+	/*
+	 * Scan to find existance of the device
+	 */
+	if (nand_scan(&host->mtd, 1)) {
+		ret = -ENXIO;
+		goto err_unmap;
+	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	add_mtd_partitions(&host->mtd, pdata->parts, pdata->nparts);
+#else
+	pr_info("Registering %s as whole device\n", mtd->name);
+	add_mtd_device(mtd);
+#endif
+
+	platform_set_drvdata(pdev, host);
+	return 0;
+
+ err_unmap:
+	if (host->cmd_va) iounmap(host->cmd_va);
+	if (host->data_va) iounmap(host->data_va);
+	if (host->addr_va) iounmap(host->addr_va);
+ err:
+	kfree(host);
+	return ret;
+}
+
+/*
+ * Clean up routine
+ */
+static int nomadik_nand_remove(struct platform_device *pdev)
+{
+	struct nomadik_nand_host *host = platform_get_drvdata(pdev);
+	struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
+
+	if (pdata->exit)
+		pdata->exit();
+
+	if (host) {
+		iounmap(host->cmd_va);
+		iounmap(host->data_va);
+		iounmap(host->addr_va);
+		kfree(host);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int nomadik_nand_suspend(struct platform_device *pdev,
+				pm_message_t state)
+{
+	struct nomadik_nand_host *host = platform_get_drvdata(pdev);
+	int ret = 0;
+	if (host)
+		ret = host->mtd.suspend(&host->mtd);
+	return ret;
+}
+
+static int nomadik_nand_resume(struct platform_device *pdev)
+{
+	struct nomadik_nand_host *host = platform_get_drvdata(pdev);
+	if (host)
+		host->mtd.resume(&host->mtd);
+	return 0;
+}
+
+#else
+#define nomadik_nand_suspend NULL
+#define nomadik_nand_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver nomadik_nand_driver = {
+	.probe = nomadik_nand_probe,
+	.remove = nomadik_nand_remove,
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "nomadik_nand",
+		   },
+	.suspend = nomadik_nand_suspend,
+	.resume = nomadik_nand_resume,
+};
+
+static int __init nand_nomadik_init(void)
+{
+	pr_info("Nomadik NAND driver\n");
+	return platform_driver_register(&nomadik_nand_driver);
+}
+
+static void __exit nand_nomadik_exit(void)
+{
+	platform_driver_unregister(&nomadik_nand_driver);
+}
+
+module_init(nand_nomadik_init);
+module_exit(nand_nomadik_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)");
+MODULE_DESCRIPTION("NAND driver for Nomadik Platform");
-- 
1.6.0.2

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

* [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-22 22:25 ` [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board) Alessandro Rubini
@ 2009-07-22 22:25   ` Alessandro Rubini
  0 siblings, 0 replies; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-22 22:25 UTC (permalink / raw)
  To: linux-mtd


Signed-off-by: Alessandro Rubini <rubini@unipv.it>
Acked-by: Andrea Gallo <andrea.gallo@stericsson.com>
---
 arch/arm/mach-nomadik/board-nhk8815.c     |   92 ++++++++
 arch/arm/mach-nomadik/include/mach/fsmc.h |   29 +++
 arch/arm/mach-nomadik/include/mach/nand.h |   16 ++
 drivers/mtd/nand/Kconfig                  |    6 +
 drivers/mtd/nand/Makefile                 |    1 +
 drivers/mtd/nand/nomadik_nand.c           |  329 +++++++++++++++++++++++++++++
 6 files changed, 473 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-nomadik/include/mach/fsmc.h
 create mode 100644 arch/arm/mach-nomadik/include/mach/nand.h
 create mode 100644 drivers/mtd/nand/nomadik_nand.c

diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 79bdea9..3fde972 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -16,12 +16,103 @@
 #include <linux/amba/bus.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/sizes.h>
+#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <mach/setup.h>
+#include <mach/nand.h>
+#include <mach/fsmc.h>
 #include "clock.h"
 
+/* These adresses span 16MB, so use three individual pages */
+static struct resource nhk8815_nand_resources[] = {
+	{
+		.name = "nand_addr",
+		.start = NAND_IO_ADDR,
+		.end = NAND_IO_ADDR + 0xfff,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.name = "nand_cmd",
+		.start = NAND_IO_CMD,
+		.end = NAND_IO_CMD + 0xfff,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.name = "nand_data",
+		.start = NAND_IO_DATA,
+		.end = NAND_IO_DATA + 0xfff,
+		.flags = IORESOURCE_MEM,
+	}
+};
+
+static int nhk8815_nand_init(void)
+{
+	/* FSMC setup for nand chip select (8-bit nand in 8815NHK) */
+	writel(0x0000000E, FSMC_PCR(0));
+	writel(0x000D0A00, FSMC_PMEM(0));
+	writel(0x00100A00, FSMC_PATT(0));
+
+	/* enable access to the chip select area */
+	writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0));
+
+	return 0;
+}
+
+/*
+ * These partitions are the same as those used in the 2.6.20 release
+ * shipped by the vendor; the first two partitions are mandated
+ * by the boot ROM, and the bootloader area is somehow oversized...
+ */
+static struct mtd_partition nhk8815_partitions[] = {
+	{
+		.name	= "X-Loader(NAND)",
+		.offset = 0,
+		.size	= SZ_256K,
+	}, {
+		.name	= "MemInit(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_256K,
+	}, {
+		.name	= "BootLoader(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_2M,
+	}, {
+		.name	= "Kernel zImage(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 3 * SZ_1M,
+	}, {
+		.name	= "Root Filesystem(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 22 * SZ_1M,
+	}, {
+		.name	= "User Filesystem(NAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= MTDPART_SIZ_FULL,
+	}
+};
+
+static struct nomadik_nand_platform_data nhk8815_nand_data = {
+	.parts		= nhk8815_partitions,
+	.nparts		= ARRAY_SIZE(nhk8815_partitions),
+	.options	= NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING \
+			| NAND_NO_READRDY | NAND_NO_AUTOINCR,
+	.init		= nhk8815_nand_init,
+};
+
+static struct platform_device nhk8815_nand_device = {
+	.name		= "nomadik_nand",
+	.dev		= {
+				.platform_data = &nhk8815_nand_data,
+	},
+	.resource	= nhk8815_nand_resources,
+	.num_resources	= ARRAY_SIZE(nhk8815_nand_resources),
+};
+
+
 #define __MEM_4K_RESOURCE(x) \
 	.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
 
@@ -81,6 +172,7 @@ static int __init nhk8815_eth_init(void)
 device_initcall(nhk8815_eth_init);
 
 static struct platform_device *nhk8815_platform_devices[] __initdata = {
+	&nhk8815_nand_device,
 	&nhk8815_eth_device,
 	/* will add more devices */
 };
diff --git a/arch/arm/mach-nomadik/include/mach/fsmc.h b/arch/arm/mach-nomadik/include/mach/fsmc.h
new file mode 100644
index 0000000..8c2c051
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/fsmc.h
@@ -0,0 +1,29 @@
+
+/* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */
+
+#ifndef __ASM_ARCH_FSMC_H
+#define __ASM_ARCH_FSMC_H
+
+#include <mach/hardware.h>
+/*
+ * Register list
+ */
+
+/* bus control reg. and bus timing reg. for CS0..CS3 */
+#define FSMC_BCR(x)     (NOMADIK_FSMC_VA + (x << 3))
+#define FSMC_BTR(x)     (NOMADIK_FSMC_VA + (x << 3) + 0x04)
+
+/* PC-card and NAND:
+ * PCR = control register
+ * PMEM = memory timing
+ * PATT = attribute timing
+ * PIO = I/O timing
+ * PECCR = ECC result
+ */
+#define FSMC_PCR(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x00)
+#define FSMC_PMEM(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x08)
+#define FSMC_PATT(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x0c)
+#define FSMC_PIO(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x10)
+#define FSMC_PECCR(x)   (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x14)
+
+#endif /* __ASM_ARCH_FSMC_H */
diff --git a/arch/arm/mach-nomadik/include/mach/nand.h b/arch/arm/mach-nomadik/include/mach/nand.h
new file mode 100644
index 0000000..c3c8254
--- /dev/null
+++ b/arch/arm/mach-nomadik/include/mach/nand.h
@@ -0,0 +1,16 @@
+#ifndef __ASM_ARCH_NAND_H
+#define __ASM_ARCH_NAND_H
+
+struct nomadik_nand_platform_data {
+	struct mtd_partition *parts;
+	int nparts;
+	int options;
+	int (*init) (void);
+	int (*exit) (void);
+};
+
+#define NAND_IO_DATA	0x40000000
+#define NAND_IO_CMD	0x40800000
+#define NAND_IO_ADDR	0x41000000
+
+#endif				/* __ASM_ARCH_NAND_H */
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index ce96c09..b9fa465 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,12 @@ config MTD_NAND_MXC
 	  This enables the driver for the NAND flash controller on the
 	  MXC processors.
 
+config MTD_NAND_NOMADIK
+	tristate "ST Nomadik 8815 NAND support"
+	depends on ARCH_NOMADIK
+	help
+	  Driver for the NAND flash controller on the Nomadik, with ECC.
+
 config MTD_NAND_SH_FLCTL
 	tristate "Support for NAND on Renesas SuperH FLCTL"
 	depends on MTD_NAND && SUPERH && CPU_SUBTYPE_SH7723
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index f3a786b..0fe9a0c 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -40,5 +40,6 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
 obj-$(CONFIG_MTD_NAND_SOCRATES)		+= socrates_nand.o
 obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
+obj-$(CONFIG_MTD_NAND_NOMADIK)		+= nomadik_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c
new file mode 100644
index 0000000..bbd1925
--- /dev/null
+++ b/drivers/mtd/nand/nomadik_nand.c
@@ -0,0 +1,329 @@
+/*
+ *  drivers/mtd/nand/nomadik_nand.c
+ *
+ *  Overview:
+ *  	Driver for on-board NAND flash on Nomadik Platforms
+ *
+ * Copyright (C) 2007 STMicroelectronics Pvt. Ltd.
+ * Author: Sachin Verma <sachin.verma@st.com>
+ *
+ * Copyright (C) 2009 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+#include <mach/nand.h>
+#include <mach/fsmc.h>
+
+#include <mtd/mtd-abi.h>
+
+struct nomadik_nand_host {
+	struct mtd_info		mtd;
+	struct nand_chip	nand;
+	void __iomem *data_va;
+	void __iomem *cmd_va;
+	void __iomem *addr_va;
+	struct nand_bbt_descr *bbt_desc;
+};
+
+static inline int parity(int b) /* uses low 8 bits: returns 0 or all-1 */
+{
+	b = b ^ (b >> 4);
+	b = b ^ (b >> 2);
+	return (b ^ (b >> 1)) & 1
+		? ~0 : 0;
+}
+
+/*
+ * This is the ECC routine used in hardware, according to the manual.
+ * HW claims to make the calculation but not the correction. However,
+ * I haven't managed to get the desired data out of it; so do it in sw.
+ * There is problably some errata involved, but currently miss the info.
+ */
+static int nomadik_ecc512_calc(struct mtd_info *mtd, const u_char *data,
+			u_char *ecc)
+{
+	int gpar = 0;
+	int i, val, par;
+	int pbits = 0;		/* P8, P16, ... P2048 */
+	int pprime = 0;		/* P8', P16', ... P2048' */
+	int lowbits;		/* P1, P2, P4 and primes */
+
+	for (i = 0; i < 512; i++) {
+		par = parity((val = data[i]));
+		gpar ^= val;
+		pbits ^= (i & par);
+	}
+	/*
+	 * Ok, now gpar is global parity (xor of all bytes)
+	 * pbits are all the parity bits (non-prime ones)
+	 */
+	par = parity(gpar);
+	pprime = pbits ^ par;
+	/* Put low bits in the right position for ecc[2] (bits 7..2) */
+	lowbits = 0
+		| (parity(gpar & 0xf0) & 0x80)	/* P4  */
+		| (parity(gpar & 0x0f) & 0x40)	/* P4' */
+		| (parity(gpar & 0xcc) & 0x20)	/* P2  */
+		| (parity(gpar & 0x33) & 0x10)	/* P2' */
+		| (parity(gpar & 0xaa) & 0x08)	/* P1  */
+		| (parity(gpar & 0x55) & 0x04);	/* P1' */
+
+	ecc[2] = ~(lowbits | ((pbits & 0x100) >> 7) | ((pprime & 0x100) >> 8));
+	/* now intermix bits for ecc[1] (P1024..P128') and ecc[0] (P64..P8') */
+	ecc[1] = ~(    (pbits & 0x80) >> 0  | ((pprime & 0x80) >> 1)
+		    | ((pbits & 0x40) >> 1) | ((pprime & 0x40) >> 2)
+		    | ((pbits & 0x20) >> 2) | ((pprime & 0x20) >> 3)
+		    | ((pbits & 0x10) >> 3) | ((pprime & 0x10) >> 4));
+
+	ecc[0] = ~(    (pbits & 0x8) << 4  | ((pprime & 0x8) << 3)
+		    | ((pbits & 0x4) << 3) | ((pprime & 0x4) << 2)
+		    | ((pbits & 0x2) << 2) | ((pprime & 0x2) << 1)
+		    | ((pbits & 0x1) << 1) | ((pprime & 0x1) << 0));
+	return 0;
+}
+
+static int nomadik_ecc512_correct(struct mtd_info *mtd, uint8_t *dat,
+				uint8_t *r_ecc, uint8_t *c_ecc)
+{
+	struct nand_chip *chip = mtd->priv;
+	uint32_t r, c, d, diff; /*read, calculated, xor of them */
+
+	if (!memcmp(r_ecc, c_ecc, chip->ecc.bytes))
+		return 0;
+
+	/* Reorder the bytes into ascending-order 24 bits -- see manual */
+	r = r_ecc[2] << 22 | r_ecc[1] << 14 | r_ecc[0] << 6 | r_ecc[2] >> 2;
+	c = c_ecc[2] << 22 | c_ecc[1] << 14 | c_ecc[0] << 6 | c_ecc[2] >> 2;
+	diff = (r ^ c) & ((1 << 24) - 1); /* use 24 bits only */
+
+	/* If 12 bits are different, one per pair, it's correctable */
+	if (((diff | (diff>>1)) & 0x555555) == 0x555555) {
+		int bit = ((diff & 2) >> 1)
+			| ((diff & 0x8) >> 2) | ((diff & 0x20) >> 3);
+		int byte;
+
+		d = diff >> 6; /* remove bit-order info */
+		byte =  ((d & 2) >> 1)
+			| ((d & 0x8) >> 2) | ((d & 0x20) >> 3)
+			| ((d & 0x80) >> 4) | ((d & 0x200) >> 5)
+			| ((d & 0x800) >> 6) | ((d & 0x2000) >> 7)
+			| ((d & 0x8000) >> 8) | ((d & 0x20000) >> 9);
+		/* correct the single bit */
+		dat[byte] ^= 1 << bit;
+		return 0;
+	}
+	/* If 1 bit only differs, it's one bit error in ECC, ignore */
+	if ((diff ^ (1 << (ffs(diff) - 1))) == 0)
+		return 0;
+	/* Otherwise, uncorrectable */
+	return -1;
+}
+
+static struct nand_ecclayout nomadik_ecc_layout = {
+	.eccbytes = 3 * 4,
+	.eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
+		0x02, 0x03, 0x04,
+		0x12, 0x13, 0x14,
+		0x22, 0x23, 0x24,
+		0x32, 0x33, 0x34},
+	/* let's keep bytes 5,6,7 for us, just in case we change ECC algo */
+	.oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} },
+};
+
+static void nomadik_ecc_control(struct mtd_info *mtd, int mode)
+{
+	/* No need to enable hw ecc, it's on by default */
+}
+
+static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct nomadik_nand_host *host = nand->priv;
+
+	if (cmd == NAND_CMD_NONE)
+		return;
+
+	if (ctrl & NAND_CLE)
+		writeb(cmd, host->cmd_va);
+	else
+		writeb(cmd, host->addr_va);
+}
+
+static int nomadik_nand_probe(struct platform_device *pdev)
+{
+	struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
+	struct nomadik_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand;
+	struct resource *res;
+	int ret = 0;
+
+	/* Allocate memory for the device structure (and zero it) */
+	host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL);
+	if (!host) {
+		dev_err(&pdev->dev, "Failed to allocate device structure.\n");
+		return -ENOMEM;
+	}
+
+	/* Call the client's init function, if any */
+	if (pdata->init && (ret = pdata->init()) < 0) {
+		dev_err(&pdev->dev, "Init function failed\n");
+		goto err;
+	}
+
+	/* ioremap three regions */
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
+	if (!res) {ret = -EIO; goto err_unmap; }
+	host->addr_va = ioremap(res->start, res->end - res->start + 1);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
+	if (!res) {ret = -EIO; goto err_unmap; }
+	host->data_va = ioremap(res->start, res->end - res->start + 1);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
+	if (!res) {ret = -EIO; goto err_unmap; }
+	host->cmd_va = ioremap(res->start, res->end - res->start + 1);
+
+	if (!host->addr_va || !host->data_va || !host->cmd_va) {
+		ret = -ENOMEM;
+		goto err_unmap;
+	}
+
+	/* Link all private pointers */
+	mtd = &host->mtd;
+	nand = &host->nand;
+	mtd->priv = nand;
+	nand->priv = host;
+
+	host->mtd.owner = THIS_MODULE;
+	nand->IO_ADDR_R = host->data_va;
+	nand->IO_ADDR_W = host->data_va;
+	nand->cmd_ctrl = nomadik_cmd_ctrl;
+
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.layout = &nomadik_ecc_layout;
+	nand->ecc.calculate = nomadik_ecc512_calc;
+	nand->ecc.correct = nomadik_ecc512_correct;
+	nand->ecc.hwctl = nomadik_ecc_control;
+	nand->ecc.size = 512;
+	nand->ecc.bytes = 3;
+
+	nand->options = pdata->options;
+
+	/*
+	 * Scan to find existance of the device
+	 */
+	if (nand_scan(&host->mtd, 1)) {
+		ret = -ENXIO;
+		goto err_unmap;
+	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	add_mtd_partitions(&host->mtd, pdata->parts, pdata->nparts);
+#else
+	pr_info("Registering %s as whole device\n", mtd->name);
+	add_mtd_device(mtd);
+#endif
+
+	platform_set_drvdata(pdev, host);
+	return 0;
+
+ err_unmap:
+	if (host->cmd_va) iounmap(host->cmd_va);
+	if (host->data_va) iounmap(host->data_va);
+	if (host->addr_va) iounmap(host->addr_va);
+ err:
+	kfree(host);
+	return ret;
+}
+
+/*
+ * Clean up routine
+ */
+static int nomadik_nand_remove(struct platform_device *pdev)
+{
+	struct nomadik_nand_host *host = platform_get_drvdata(pdev);
+	struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
+
+	if (pdata->exit)
+		pdata->exit();
+
+	if (host) {
+		iounmap(host->cmd_va);
+		iounmap(host->data_va);
+		iounmap(host->addr_va);
+		kfree(host);
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int nomadik_nand_suspend(struct platform_device *pdev,
+				pm_message_t state)
+{
+	struct nomadik_nand_host *host = platform_get_drvdata(pdev);
+	int ret = 0;
+	if (host)
+		ret = host->mtd.suspend(&host->mtd);
+	return ret;
+}
+
+static int nomadik_nand_resume(struct platform_device *pdev)
+{
+	struct nomadik_nand_host *host = platform_get_drvdata(pdev);
+	if (host)
+		host->mtd.resume(&host->mtd);
+	return 0;
+}
+
+#else
+#define nomadik_nand_suspend NULL
+#define nomadik_nand_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver nomadik_nand_driver = {
+	.probe = nomadik_nand_probe,
+	.remove = nomadik_nand_remove,
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "nomadik_nand",
+		   },
+	.suspend = nomadik_nand_suspend,
+	.resume = nomadik_nand_resume,
+};
+
+static int __init nand_nomadik_init(void)
+{
+	pr_info("Nomadik NAND driver\n");
+	return platform_driver_register(&nomadik_nand_driver);
+}
+
+static void __exit nand_nomadik_exit(void)
+{
+	platform_driver_unregister(&nomadik_nand_driver);
+}
+
+module_init(nand_nomadik_init);
+module_exit(nand_nomadik_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ST Microelectronics (sachin.verma at st.com)");
+MODULE_DESCRIPTION("NAND driver for Nomadik Platform");
-- 
1.6.0.2

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

* [PATCH V4 2/2] OneNand support for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-22 22:25 [PATCH V4 0/2] Nand and OneNand for ARM Nomadik Alessandro Rubini
  2009-07-22 22:25 ` [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board) Alessandro Rubini
@ 2009-07-22 22:26 ` Alessandro Rubini
  2009-07-22 22:26   ` Alessandro Rubini
       [not found] ` <cae21cf16cad72ef35ce7e8cc3effe25b497924e.1248300341.git.rubini@unipv.it>
  2009-07-23  9:20 ` [PATCH V4 0/2] Nand and OneNand for ARM Nomadik Russell King - ARM Linux
  3 siblings, 1 reply; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-22 22:26 UTC (permalink / raw)
  To: linux-mtd; +Cc: STEricsson_nomadik_linux, linux, andrea.gallo


Signed-off-by: Alessandro Rubini <rubini@unipv.it>
Acked-by: Andrea Gallo <andrea.gallo@stericsson.com>
---
 arch/arm/mach-nomadik/board-nhk8815.c |   63 +++++++++++++++++++++++++++++++++
 1 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 3fde972..0ad6bba 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -24,6 +24,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
 #include <mach/setup.h>
 #include <mach/nand.h>
 #include <mach/fsmc.h>
@@ -112,6 +113,66 @@ static struct platform_device nhk8815_nand_device = {
 	.num_resources	= ARRAY_SIZE(nhk8815_nand_resources),
 };
 
+/* These are the partitions for the OneNand device, different from above */
+static struct mtd_partition nhk8815_onenand_partitions[] = {
+	{
+		.name	= "X-Loader(OneNAND)",
+		.offset = 0,
+		.size	= SZ_256K,
+	}, {
+		.name	= "MemInit(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_256K,
+	}, {
+		.name	= "BootLoader(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_2M-SZ_256K,
+	}, {
+		.name	= "SysImage(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 4 * SZ_1M,
+	}, {
+		.name	= "Root Filesystem(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 22 * SZ_1M,
+	}, {
+		.name	= "User Filesystem(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= MTDPART_SIZ_FULL,
+	}
+};
+
+static struct flash_platform_data nhk8815_onenand_data = {
+	.parts		= nhk8815_onenand_partitions,
+	.nr_parts	= ARRAY_SIZE(nhk8815_onenand_partitions),
+};
+
+static struct resource nhk8815_onenand_resource[] = {
+	{
+		.start		= 0x30000000,
+		.end		= 0x30000000 + SZ_128K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device nhk8815_onenand_device = {
+	.name		= "onenand",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &nhk8815_onenand_data,
+	},
+	.resource	= nhk8815_onenand_resource,
+	.num_resources	= ARRAY_SIZE(nhk8815_onenand_resource),
+};
+
+static void __init nhk8815_onenand_init(void)
+{
+#ifdef CONFIG_ONENAND
+       /* Set up SMCS0 for OneNand */
+       writel(0x000030db, FSMC_BCR0);
+       writel(0x02100551, FSMC_BTR0);
+#endif
+}
 
 #define __MEM_4K_RESOURCE(x) \
 	.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
@@ -173,6 +234,7 @@ device_initcall(nhk8815_eth_init);
 
 static struct platform_device *nhk8815_platform_devices[] __initdata = {
 	&nhk8815_nand_device,
+	&nhk8815_onenand_device,
 	&nhk8815_eth_device,
 	/* will add more devices */
 };
@@ -182,6 +244,7 @@ static void __init nhk8815_platform_init(void)
 	int i;
 
 	cpu8815_platform_init();
+	nhk8815_onenand_init();
 	platform_add_devices(nhk8815_platform_devices,
 			     ARRAY_SIZE(nhk8815_platform_devices));
 
-- 
1.6.0.2

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

* [PATCH V4 2/2] OneNand support for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-22 22:26 ` [PATCH V4 2/2] OneNand support " Alessandro Rubini
@ 2009-07-22 22:26   ` Alessandro Rubini
  0 siblings, 0 replies; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-22 22:26 UTC (permalink / raw)
  To: linux-mtd


Signed-off-by: Alessandro Rubini <rubini@unipv.it>
Acked-by: Andrea Gallo <andrea.gallo@stericsson.com>
---
 arch/arm/mach-nomadik/board-nhk8815.c |   63 +++++++++++++++++++++++++++++++++
 1 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index 3fde972..0ad6bba 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -24,6 +24,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
 #include <mach/setup.h>
 #include <mach/nand.h>
 #include <mach/fsmc.h>
@@ -112,6 +113,66 @@ static struct platform_device nhk8815_nand_device = {
 	.num_resources	= ARRAY_SIZE(nhk8815_nand_resources),
 };
 
+/* These are the partitions for the OneNand device, different from above */
+static struct mtd_partition nhk8815_onenand_partitions[] = {
+	{
+		.name	= "X-Loader(OneNAND)",
+		.offset = 0,
+		.size	= SZ_256K,
+	}, {
+		.name	= "MemInit(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_256K,
+	}, {
+		.name	= "BootLoader(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= SZ_2M-SZ_256K,
+	}, {
+		.name	= "SysImage(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 4 * SZ_1M,
+	}, {
+		.name	= "Root Filesystem(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= 22 * SZ_1M,
+	}, {
+		.name	= "User Filesystem(OneNAND)",
+		.offset	= MTDPART_OFS_APPEND,
+		.size	= MTDPART_SIZ_FULL,
+	}
+};
+
+static struct flash_platform_data nhk8815_onenand_data = {
+	.parts		= nhk8815_onenand_partitions,
+	.nr_parts	= ARRAY_SIZE(nhk8815_onenand_partitions),
+};
+
+static struct resource nhk8815_onenand_resource[] = {
+	{
+		.start		= 0x30000000,
+		.end		= 0x30000000 + SZ_128K - 1,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device nhk8815_onenand_device = {
+	.name		= "onenand",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &nhk8815_onenand_data,
+	},
+	.resource	= nhk8815_onenand_resource,
+	.num_resources	= ARRAY_SIZE(nhk8815_onenand_resource),
+};
+
+static void __init nhk8815_onenand_init(void)
+{
+#ifdef CONFIG_ONENAND
+       /* Set up SMCS0 for OneNand */
+       writel(0x000030db, FSMC_BCR0);
+       writel(0x02100551, FSMC_BTR0);
+#endif
+}
 
 #define __MEM_4K_RESOURCE(x) \
 	.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
@@ -173,6 +234,7 @@ device_initcall(nhk8815_eth_init);
 
 static struct platform_device *nhk8815_platform_devices[] __initdata = {
 	&nhk8815_nand_device,
+	&nhk8815_onenand_device,
 	&nhk8815_eth_device,
 	/* will add more devices */
 };
@@ -182,6 +244,7 @@ static void __init nhk8815_platform_init(void)
 	int i;
 
 	cpu8815_platform_init();
+	nhk8815_onenand_init();
 	platform_add_devices(nhk8815_platform_devices,
 			     ARRAY_SIZE(nhk8815_platform_devices));
 
-- 
1.6.0.2

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

* Re: [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board)
       [not found] ` <cae21cf16cad72ef35ce7e8cc3effe25b497924e.1248300341.git.rubini@unipv.it>
@ 2009-07-23  4:30   ` vimal singh
  2009-07-23  6:59     ` Alessandro Rubini
  0 siblings, 1 reply; 11+ messages in thread
From: vimal singh @ 2009-07-23  4:30 UTC (permalink / raw)
  To: Alessandro Rubini, linux-mtd, andrea.gallo,
	STEricsson_nomadik_linux, linux

On Thu, Jul 23, 2009 at 3:55 AM, Alessandro Rubini<rubini-list@gnudd.com> wrote:
>
> Signed-off-by: Alessandro Rubini <rubini@unipv.it>
> Acked-by: Andrea Gallo <andrea.gallo@stericsson.com>
> ---
>  arch/arm/mach-nomadik/board-nhk8815.c     |   92 ++++++++
>  arch/arm/mach-nomadik/include/mach/fsmc.h |   29 +++
>  arch/arm/mach-nomadik/include/mach/nand.h |   16 ++
>  drivers/mtd/nand/Kconfig                  |    6 +
>  drivers/mtd/nand/Makefile                 |    1 +
>  drivers/mtd/nand/nomadik_nand.c           |  329 +++++++++++++++++++++++++++++
>  6 files changed, 473 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-nomadik/include/mach/fsmc.h
>  create mode 100644 arch/arm/mach-nomadik/include/mach/nand.h
>  create mode 100644 drivers/mtd/nand/nomadik_nand.c

--snip--

> diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c
> new file mode 100644
> index 0000000..bbd1925
> --- /dev/null
> +++ b/drivers/mtd/nand/nomadik_nand.c
> @@ -0,0 +1,329 @@
> +/*
> + *  drivers/mtd/nand/nomadik_nand.c
> + *
> + *  Overview:
> + *     Driver for on-board NAND flash on Nomadik Platforms
> + *
> + * Copyright (C) 2007 STMicroelectronics Pvt. Ltd.
> + * Author: Sachin Verma <sachin.verma@st.com>
> + *
> + * Copyright (C) 2009 Alessandro Rubini
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/platform_device.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/io.h>

I think one black line will be good here.

> +#include <mach/nand.h>
> +#include <mach/fsmc.h>
> +
> +#include <mtd/mtd-abi.h>
> +
> +struct nomadik_nand_host {
> +       struct mtd_info         mtd;
> +       struct nand_chip        nand;
> +       void __iomem *data_va;
> +       void __iomem *cmd_va;
> +       void __iomem *addr_va;
> +       struct nand_bbt_descr *bbt_desc;
> +};
> +
> +static inline int parity(int b) /* uses low 8 bits: returns 0 or all-1 */
> +{
> +       b = b ^ (b >> 4);
> +       b = b ^ (b >> 2);
> +       return (b ^ (b >> 1)) & 1
> +               ? ~0 : 0;
> +}
> +
> +/*
> + * This is the ECC routine used in hardware, according to the manual.
> + * HW claims to make the calculation but not the correction. However,
> + * I haven't managed to get the desired data out of it; so do it in sw.
> + * There is problably some errata involved, but currently miss the info.
> + */

'nand_calculate_ecc' and 'nand_correct_data' (nand_ecc.c) do it in SW.
This need not to be re-do.

> +static int nomadik_ecc512_calc(struct mtd_info *mtd, const u_char *data,
> +                       u_char *ecc)
> +{
> +       int gpar = 0;
> +       int i, val, par;
> +       int pbits = 0;          /* P8, P16, ... P2048 */
> +       int pprime = 0;         /* P8', P16', ... P2048' */
> +       int lowbits;            /* P1, P2, P4 and primes */
> +
> +       for (i = 0; i < 512; i++) {
> +               par = parity((val = data[i]));
> +               gpar ^= val;
> +               pbits ^= (i & par);
> +       }
> +       /*
> +        * Ok, now gpar is global parity (xor of all bytes)
> +        * pbits are all the parity bits (non-prime ones)
> +        */
> +       par = parity(gpar);
> +       pprime = pbits ^ par;
> +       /* Put low bits in the right position for ecc[2] (bits 7..2) */
> +       lowbits = 0
> +               | (parity(gpar & 0xf0) & 0x80)  /* P4  */
> +               | (parity(gpar & 0x0f) & 0x40)  /* P4' */
> +               | (parity(gpar & 0xcc) & 0x20)  /* P2  */
> +               | (parity(gpar & 0x33) & 0x10)  /* P2' */
> +               | (parity(gpar & 0xaa) & 0x08)  /* P1  */
> +               | (parity(gpar & 0x55) & 0x04); /* P1' */
> +
> +       ecc[2] = ~(lowbits | ((pbits & 0x100) >> 7) | ((pprime & 0x100) >> 8));
> +       /* now intermix bits for ecc[1] (P1024..P128') and ecc[0] (P64..P8') */
> +       ecc[1] = ~(    (pbits & 0x80) >> 0  | ((pprime & 0x80) >> 1)
> +                   | ((pbits & 0x40) >> 1) | ((pprime & 0x40) >> 2)
> +                   | ((pbits & 0x20) >> 2) | ((pprime & 0x20) >> 3)
> +                   | ((pbits & 0x10) >> 3) | ((pprime & 0x10) >> 4));
> +
> +       ecc[0] = ~(    (pbits & 0x8) << 4  | ((pprime & 0x8) << 3)
> +                   | ((pbits & 0x4) << 3) | ((pprime & 0x4) << 2)
> +                   | ((pbits & 0x2) << 2) | ((pprime & 0x2) << 1)
> +                   | ((pbits & 0x1) << 1) | ((pprime & 0x1) << 0));
> +       return 0;
> +}
> +
> +static int nomadik_ecc512_correct(struct mtd_info *mtd, uint8_t *dat,
> +                               uint8_t *r_ecc, uint8_t *c_ecc)
> +{
> +       struct nand_chip *chip = mtd->priv;
> +       uint32_t r, c, d, diff; /*read, calculated, xor of them */
> +
> +       if (!memcmp(r_ecc, c_ecc, chip->ecc.bytes))
> +               return 0;
> +
> +       /* Reorder the bytes into ascending-order 24 bits -- see manual */
> +       r = r_ecc[2] << 22 | r_ecc[1] << 14 | r_ecc[0] << 6 | r_ecc[2] >> 2;
> +       c = c_ecc[2] << 22 | c_ecc[1] << 14 | c_ecc[0] << 6 | c_ecc[2] >> 2;
> +       diff = (r ^ c) & ((1 << 24) - 1); /* use 24 bits only */
> +
> +       /* If 12 bits are different, one per pair, it's correctable */
> +       if (((diff | (diff>>1)) & 0x555555) == 0x555555) {
> +               int bit = ((diff & 2) >> 1)
> +                       | ((diff & 0x8) >> 2) | ((diff & 0x20) >> 3);
> +               int byte;
> +
> +               d = diff >> 6; /* remove bit-order info */
> +               byte =  ((d & 2) >> 1)
> +                       | ((d & 0x8) >> 2) | ((d & 0x20) >> 3)
> +                       | ((d & 0x80) >> 4) | ((d & 0x200) >> 5)
> +                       | ((d & 0x800) >> 6) | ((d & 0x2000) >> 7)
> +                       | ((d & 0x8000) >> 8) | ((d & 0x20000) >> 9);
> +               /* correct the single bit */
> +               dat[byte] ^= 1 << bit;
> +               return 0;
> +       }
> +       /* If 1 bit only differs, it's one bit error in ECC, ignore */
> +       if ((diff ^ (1 << (ffs(diff) - 1))) == 0)
> +               return 0;
> +       /* Otherwise, uncorrectable */
> +       return -1;
> +}
> +
> +static struct nand_ecclayout nomadik_ecc_layout = {
> +       .eccbytes = 3 * 4,
> +       .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
> +               0x02, 0x03, 0x04,
> +               0x12, 0x13, 0x14,
> +               0x22, 0x23, 0x24,
> +               0x32, 0x33, 0x34},
> +       /* let's keep bytes 5,6,7 for us, just in case we change ECC algo */
> +       .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} },
> +};
> +
> +static void nomadik_ecc_control(struct mtd_info *mtd, int mode)
> +{
> +       /* No need to enable hw ecc, it's on by default */
> +}
> +
> +static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
> +{
> +       struct nand_chip *nand = mtd->priv;
> +       struct nomadik_nand_host *host = nand->priv;
> +
> +       if (cmd == NAND_CMD_NONE)
> +               return;
> +
> +       if (ctrl & NAND_CLE)
> +               writeb(cmd, host->cmd_va);
> +       else
> +               writeb(cmd, host->addr_va);
> +}
> +
> +static int nomadik_nand_probe(struct platform_device *pdev)
> +{
> +       struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
> +       struct nomadik_nand_host *host;
> +       struct mtd_info *mtd;
> +       struct nand_chip *nand;
> +       struct resource *res;
> +       int ret = 0;
> +
> +       /* Allocate memory for the device structure (and zero it) */
> +       host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL);
> +       if (!host) {
> +               dev_err(&pdev->dev, "Failed to allocate device structure.\n");
> +               return -ENOMEM;
> +       }
> +
> +       /* Call the client's init function, if any */
> +       if (pdata->init && (ret = pdata->init()) < 0) {
> +               dev_err(&pdev->dev, "Init function failed\n");
> +               goto err;
> +       }
> +
> +       /* ioremap three regions */
> +       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
> +       if (!res) {ret = -EIO; goto err_unmap; }

We should not write multiple statements in single line needlessly.

> +       host->addr_va = ioremap(res->start, res->end - res->start + 1);
> +
> +       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
> +       if (!res) {ret = -EIO; goto err_unmap; }

ditto

> +       host->data_va = ioremap(res->start, res->end - res->start + 1);
> +
> +       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
> +       if (!res) {ret = -EIO; goto err_unmap; }

ditto...

> +       host->cmd_va = ioremap(res->start, res->end - res->start + 1);
> +
> +       if (!host->addr_va || !host->data_va || !host->cmd_va) {
> +               ret = -ENOMEM;
> +               goto err_unmap;
> +       }
> +
> +       /* Link all private pointers */
> +       mtd = &host->mtd;
> +       nand = &host->nand;
> +       mtd->priv = nand;
> +       nand->priv = host;
> +
> +       host->mtd.owner = THIS_MODULE;
> +       nand->IO_ADDR_R = host->data_va;
> +       nand->IO_ADDR_W = host->data_va;
> +       nand->cmd_ctrl = nomadik_cmd_ctrl;
> +
> +       nand->ecc.mode = NAND_ECC_HW;
> +       nand->ecc.layout = &nomadik_ecc_layout;
> +       nand->ecc.calculate = nomadik_ecc512_calc;
> +       nand->ecc.correct = nomadik_ecc512_correct;
> +       nand->ecc.hwctl = nomadik_ecc_control;
> +       nand->ecc.size = 512;
> +       nand->ecc.bytes = 3;
> +
> +       nand->options = pdata->options;
> +
> +       /*
> +        * Scan to find existance of the device
> +        */
> +       if (nand_scan(&host->mtd, 1)) {
> +               ret = -ENXIO;
> +               goto err_unmap;
> +       }
> +
> +#ifdef CONFIG_MTD_PARTITIONS
> +       add_mtd_partitions(&host->mtd, pdata->parts, pdata->nparts);
> +#else
> +       pr_info("Registering %s as whole device\n", mtd->name);
> +       add_mtd_device(mtd);
> +#endif
> +
> +       platform_set_drvdata(pdev, host);
> +       return 0;
> +
> + err_unmap:
> +       if (host->cmd_va) iounmap(host->cmd_va);
> +       if (host->data_va) iounmap(host->data_va);
> +       if (host->addr_va) iounmap(host->addr_va);
> + err:
> +       kfree(host);
> +       return ret;
> +}
> +
> +/*
> + * Clean up routine
> + */
> +static int nomadik_nand_remove(struct platform_device *pdev)
> +{
> +       struct nomadik_nand_host *host = platform_get_drvdata(pdev);
> +       struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
> +
> +       if (pdata->exit)
> +               pdata->exit();
> +
> +       if (host) {
> +               iounmap(host->cmd_va);
> +               iounmap(host->data_va);
> +               iounmap(host->addr_va);
> +               kfree(host);
> +       }
> +       return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int nomadik_nand_suspend(struct platform_device *pdev,
> +                               pm_message_t state)
> +{
> +       struct nomadik_nand_host *host = platform_get_drvdata(pdev);
> +       int ret = 0;
> +       if (host)
> +               ret = host->mtd.suspend(&host->mtd);
> +       return ret;
> +}
> +
> +static int nomadik_nand_resume(struct platform_device *pdev)
> +{
> +       struct nomadik_nand_host *host = platform_get_drvdata(pdev);
> +       if (host)
> +               host->mtd.resume(&host->mtd);
> +       return 0;
> +}
> +
> +#else
> +#define nomadik_nand_suspend NULL
> +#define nomadik_nand_resume NULL
> +#endif /* CONFIG_PM */
> +
> +static struct platform_driver nomadik_nand_driver = {
> +       .probe = nomadik_nand_probe,
> +       .remove = nomadik_nand_remove,
> +       .driver = {
> +                  .owner = THIS_MODULE,
> +                  .name = "nomadik_nand",
> +                  },
> +       .suspend = nomadik_nand_suspend,
> +       .resume = nomadik_nand_resume,
> +};
> +
> +static int __init nand_nomadik_init(void)
> +{
> +       pr_info("Nomadik NAND driver\n");
> +       return platform_driver_register(&nomadik_nand_driver);
> +}
> +
> +static void __exit nand_nomadik_exit(void)
> +{
> +       platform_driver_unregister(&nomadik_nand_driver);
> +}
> +
> +module_init(nand_nomadik_init);
> +module_exit(nand_nomadik_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)");
> +MODULE_DESCRIPTION("NAND driver for Nomadik Platform");
> --
> 1.6.0.2
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>



-- 
---
Regards,
\/ | |\/| /-\ |_

____      __o
------   -\<,
-----  ( )/ ( )

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

* Re: [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-23  4:30   ` [PATCH V4 1/2] Nand driver " vimal singh
@ 2009-07-23  6:59     ` Alessandro Rubini
  2009-07-23  9:07       ` Alessandro Rubini
  0 siblings, 1 reply; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-23  6:59 UTC (permalink / raw)
  To: vimal.newwork; +Cc: STEricsson_nomadik_linux, linux, linux-mtd, andrea.gallo

> 'nand_calculate_ecc' and 'nand_correct_data' (nand_ecc.c) do it in SW.
> This need not to be re-do.

When I initially tried soft ecc it didn't work, so I thought ours was
a different algorithm. Most likely I was wrong, I'll recheck ASAP.

> We should not write multiple statements in single line needlessly.

I didn't want to waste a whole screenfull for a burst of similar
error checks. (I still don't want, but I'll obey to the request).

/alessandro

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

* Re: [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-23  6:59     ` Alessandro Rubini
@ 2009-07-23  9:07       ` Alessandro Rubini
  2009-07-23  9:49         ` vimal singh
  0 siblings, 1 reply; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-23  9:07 UTC (permalink / raw)
  To: rubini-list
  Cc: STEricsson_nomadik_linux, linux, vimal.newwork, linux-mtd,
	andrea.gallo

>> 'nand_calculate_ecc' and 'nand_correct_data' (nand_ecc.c) do it in SW.
>> This need not to be re-do.
> 
> When I initially tried soft ecc it didn't work, so I thought ours was
> a different algorithm. Most likely I was wrong, I'll recheck ASAP.

It's slightly different. This is what I get (old is nand_calculate_ecc(), new is mine).

   old: 65 56 55
   new: 56 65 55

   old: 33 fc 0c
   new: fc 33 0c

   old: c0 c0 3c
   new: c0 c0 3c

   old: c3 3f cf
   new: 3f c3 cf

   old: c0 0f 30
   new: 0f c0 30

   old: 03 f3 3f
   new: f3 03 3f

So, the standard procedure is not compatible with data already in
flash (written with the older u-boot and kernel provided by the vendor
with the kit).

The code in nomadik_ecc512_calc() is derived from vendor data sheet,
looking at vendor code I got; since both routines gives the same results,
mine _should_ be compatible with hw ecc, for the day I'll be
able to make it work. However vendor code never used hw ecc, either,
so I'm not sure this routine is really compatible with it.

Actually, I got a hint about why hw ecc isn't working for me, but
can't try it these days.

In view of this, can my code stay? 

/alessandro

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

* Re: [PATCH V4 0/2] Nand and OneNand for ARM Nomadik
  2009-07-22 22:25 [PATCH V4 0/2] Nand and OneNand for ARM Nomadik Alessandro Rubini
                   ` (2 preceding siblings ...)
       [not found] ` <cae21cf16cad72ef35ce7e8cc3effe25b497924e.1248300341.git.rubini@unipv.it>
@ 2009-07-23  9:20 ` Russell King - ARM Linux
  3 siblings, 0 replies; 11+ messages in thread
From: Russell King - ARM Linux @ 2009-07-23  9:20 UTC (permalink / raw)
  To: Alessandro Rubini; +Cc: STEricsson_nomadik_linux, linux-mtd, andrea.gallo

On Thu, Jul 23, 2009 at 12:25:47AM +0200, Alessandro Rubini wrote:
> At this time, the arch/arm/mach-nomadik files have been accepted in
> Russell's tree ("nomadik branch", I'm told), but I can't find a public
> repository for that tree.

You're not looking hard enough - it is in my tree and it is public, and
has been visible for at least the last four days.  See my devel branch.

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

* Re: [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-23  9:07       ` Alessandro Rubini
@ 2009-07-23  9:49         ` vimal singh
  2009-07-23  9:57           ` Alessandro Rubini
  0 siblings, 1 reply; 11+ messages in thread
From: vimal singh @ 2009-07-23  9:49 UTC (permalink / raw)
  To: Alessandro Rubini, vimal.newwork, STEricsson_nomadik_linux, linux,
	linux-mtd, andrea.gallo

On Thu, Jul 23, 2009 at 2:37 PM, Alessandro Rubini<rubini-list@gnudd.com> wrote:
>>> 'nand_calculate_ecc' and 'nand_correct_data' (nand_ecc.c) do it in SW.
>>> This need not to be re-do.
>>
>> When I initially tried soft ecc it didn't work, so I thought ours was
>> a different algorithm. Most likely I was wrong, I'll recheck ASAP.
>
> It's slightly different. This is what I get (old is nand_calculate_ecc(), new is mine).
>
>   old: 65 56 55
>   new: 56 65 55
>
>   old: 33 fc 0c
>   new: fc 33 0c
>
>   old: c0 c0 3c
>   new: c0 c0 3c
>
>   old: c3 3f cf
>   new: 3f c3 cf
>
>   old: c0 0f 30
>   new: 0f c0 30
>
>   old: 03 f3 3f
>   new: f3 03 3f
>
> So, the standard procedure is not compatible with data already in
> flash (written with the older u-boot and kernel provided by the vendor
> with the kit).

No, Its just byte order. Try enabling 'CONFIG_MTD_NAND_ECC_SMC' in your configs.
It should work fine.

-vimal

>
> The code in nomadik_ecc512_calc() is derived from vendor data sheet,
> looking at vendor code I got; since both routines gives the same results,
> mine _should_ be compatible with hw ecc, for the day I'll be
> able to make it work. However vendor code never used hw ecc, either,
> so I'm not sure this routine is really compatible with it.
>
> Actually, I got a hint about why hw ecc isn't working for me, but
> can't try it these days.
>
> In view of this, can my code stay?
>
> /alessandro
>



-- 
---
Regards,
\/ | |\/| /-\ |_

____      __o
------   -\<,
-----  ( )/ ( )

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

* Re: [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board)
  2009-07-23  9:49         ` vimal singh
@ 2009-07-23  9:57           ` Alessandro Rubini
  0 siblings, 0 replies; 11+ messages in thread
From: Alessandro Rubini @ 2009-07-23  9:57 UTC (permalink / raw)
  To: vimal.newwork; +Cc: STEricsson_nomadik_linux, linux-mtd, linux, andrea.gallo

>> So, the standard procedure is not compatible with data already in
>> flash (written with the older u-boot and kernel provided by the vendor
>> with the kit).
> 
> No, Its just byte order. Try enabling 'CONFIG_MTD_NAND_ECC_SMC' in your configs.
> It should work fine.

Yes, it does. Didn't notice it, thanks. I'll resubmit tomorrow.

/alessandro

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

end of thread, other threads:[~2009-07-23  9:57 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-22 22:25 [PATCH V4 0/2] Nand and OneNand for ARM Nomadik Alessandro Rubini
2009-07-22 22:25 ` [PATCH V4 1/2] Nand driver for Nomadik 8815 SoC (on NHK8815 board) Alessandro Rubini
2009-07-22 22:25   ` Alessandro Rubini
2009-07-22 22:26 ` [PATCH V4 2/2] OneNand support " Alessandro Rubini
2009-07-22 22:26   ` Alessandro Rubini
     [not found] ` <cae21cf16cad72ef35ce7e8cc3effe25b497924e.1248300341.git.rubini@unipv.it>
2009-07-23  4:30   ` [PATCH V4 1/2] Nand driver " vimal singh
2009-07-23  6:59     ` Alessandro Rubini
2009-07-23  9:07       ` Alessandro Rubini
2009-07-23  9:49         ` vimal singh
2009-07-23  9:57           ` Alessandro Rubini
2009-07-23  9:20 ` [PATCH V4 0/2] Nand and OneNand for ARM Nomadik Russell King - ARM Linux

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).