From: Xiangfu Liu xian...@openmobilefree.net
Date: Fri, 19 Aug 2011 14:35:29 +0800
Jz4740 NAND flash controller can support:
* MLC NAND as well as SLC NAND
* all 8-bit/16-bit NAND flash devices
* HAMMING and RS hardware ECC
* automatic boot up from NAND flash devices
nand_ecclayout is set up for 2GiB NAND chip mounted in Qi LB60.
We'll bring up boot-from-NAND support in nand_spl/ in the future.
Signed-off-by: Xiangfu Liu xian...@openmobilefree.net
Acked-by: Daniel z...@ingenic.cn
Signed-off-by: Shinya Kuribayashi skuri...@pobox.com
---
Changes since v6:
* Remove NAND-boot stuff. Those bits will be submitted as a nand-spl
support once this Jz4740 base support is merged.
* All previous comments from Scott are fixed.
* Bunch of coding style issues fixed.
drivers/mtd/nand/Makefile |1 +
drivers/mtd/nand/jz4740_nand.c | 261
2 files changed, 262 insertions(+), 0 deletions(-)
create mode 100644 drivers/mtd/nand/jz4740_nand.c
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index b6a7886..c257128 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -44,6 +44,7 @@ COBJS-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o
COBJS-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
+COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
COBJS-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
new file mode 100644
index 000..db50da3
--- /dev/null
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -0,0 +1,261 @@
+/*
+ * Platform independend driver for JZ4740.
+ *
+ * Copyright (c) 2007 Ingenic Semiconductor Inc.
+ * Author: jl...@ingenic.cn
+ *
+ * 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.
+ */
+#include common.h
+
+#include nand.h
+#include asm/io.h
+#include asm/jz4740.h
+
+#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB800)
+#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000)
+#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x1)
+
+#define BIT(x) (1 (x))
+#define JZ_NAND_ECC_CTRL_ENCODING BIT(3)
+#define JZ_NAND_ECC_CTRL_RSBIT(2)
+#define JZ_NAND_ECC_CTRL_RESET BIT(1)
+#define JZ_NAND_ECC_CTRL_ENABLEBIT(0)
+
+#define EMC_SMCR1_OPT_NAND 0x094c4400
+/* Optimize the timing of nand */
+
+static struct jz4740_emc * emc = (struct jz4740_emc *)JZ4740_EMC_BASE;
+
+static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
+ .eccbytes = 72,
+ .eccpos = {
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83 },
+ .oobfree = {
+ {.offset = 2,
+.length = 10 },
+ {.offset = 84,
+.length = 44 } }
+};
+
+static int is_reading;
+
+static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *this = mtd-priv;
+ uint32_t reg;
+
+ if (ctrl NAND_CTRL_CHANGE) {
+ if (ctrl NAND_ALE)
+ this-IO_ADDR_W = JZ_NAND_ADDR_ADDR;
+ else if (ctrl NAND_CLE)
+ this-IO_ADDR_W = JZ_NAND_CMD_ADDR;
+ else
+ this-IO_ADDR_W = JZ_NAND_DATA_ADDR;
+
+ reg = readl(emc-nfcsr);
+ if (ctrl NAND_NCE)
+ reg |= EMC_NFCSR_NFCE1;
+ else
+ reg = ~EMC_NFCSR_NFCE1;
+ writel(reg, emc-nfcsr);
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, this-IO_ADDR_W);
+}
+
+static int jz_nand_device_ready(struct mtd_info *mtd)
+{
+ return (readl(GPIO_PXPIN(2)) 0x4000) ? 1 : 0;
+}
+
+void board_nand_select_device(struct nand_chip *nand, int chip)
+{
+ /*
+* Don't use chip to address the NAND device,
+* generate the cs from the address where it is encoded.
+*/
+}
+
+static int jz_nand_rs_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
+ u_char* ecc_code)
+{
+ uint32_t status;
+ int i;
+
+ if (is_reading)
+ return 0;
+
+ do {
+ status = readl(emc-nfints);
+ } while (!(status EMC_NFINTS_ENCF));
+
+ /* disable ecc */
+