aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/sunxi/patches-4.1/117-mtd-nand-add-hynix-init.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/sunxi/patches-4.1/117-mtd-nand-add-hynix-init.patch')
-rw-r--r--target/linux/sunxi/patches-4.1/117-mtd-nand-add-hynix-init.patch229
1 files changed, 229 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-4.1/117-mtd-nand-add-hynix-init.patch b/target/linux/sunxi/patches-4.1/117-mtd-nand-add-hynix-init.patch
new file mode 100644
index 0000000000..4430a50822
--- /dev/null
+++ b/target/linux/sunxi/patches-4.1/117-mtd-nand-add-hynix-init.patch
@@ -0,0 +1,229 @@
+From 5c5e3963a1b58be1669da5da93f51dc339cd73d7 Mon Sep 17 00:00:00 2001
+From: Boris BREZILLON <b.brezillon.dev@gmail.com>
+Date: Mon, 24 Feb 2014 16:30:22 +0100
+Subject: [PATCH] mtd: nand: Add hynix specific initializer
+
+Add an hynix initiliazer to manage read retries on h27uxgt8t2a chip.
+
+Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/mtd/nand/Makefile | 2 +-
+ drivers/mtd/nand/nand_hynix.c | 159 ++++++++++++++++++++++++++++++++++++++++++
+ drivers/mtd/nand/nand_ids.c | 3 +-
+ include/linux/mtd/nand.h | 2 +
+ 4 files changed, 164 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mtd/nand/nand_hynix.c
+
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index fcbe032..07b7c8c 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -5,7 +5,7 @@
+ obj-$(CONFIG_MTD_NAND) += nand.o
+ obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
+ obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
+-obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
++obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o nand_hynix.o
+ obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
+
+ obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
+diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c
+new file mode 100644
+index 0000000..0d051bf5
+--- /dev/null
++++ b/drivers/mtd/nand/nand_hynix.c
+@@ -0,0 +1,159 @@
++/*
++ * Copyright (C) 2014 Boris BREZILLON <b.brezillon.dev@gmail.com>
++ *
++ * 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/module.h>
++#include <linux/mtd/nand.h>
++#include <linux/slab.h>
++
++static u8 h27ucg8t2a_read_retry_regs[] = {
++ 0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
++};
++
++struct hynix_read_retry {
++ u8 *regs;
++ u8 values[64];
++};
++
++struct hynix_nand {
++ struct hynix_read_retry read_retry;
++};
++
++int nand_setup_read_retry_hynix(struct mtd_info *mtd, int retry_mode)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct hynix_nand *hynix = chip->manuf_priv;
++ int offset = retry_mode * 8;
++ int status;
++ int i;
++
++ chip->cmdfunc(mtd, 0x36, -1, -1);
++ for (i = 0; i < 8; i++) {
++ int column = hynix->read_retry.regs[i];
++ column |= column << 8;
++ chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
++ chip->write_byte(mtd, hynix->read_retry.values[offset + i]);
++ }
++ chip->cmdfunc(mtd, 0x16, -1, -1);
++
++ status = chip->waitfunc(mtd, chip);
++ if (status & NAND_STATUS_FAIL)
++ return -EIO;
++
++ return 0;
++}
++
++static void h27ucg8t2a_cleanup(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd->priv;
++ kfree(chip->manuf_priv);
++}
++
++static int h27ucg8t2a_init(struct mtd_info *mtd, const uint8_t *id)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct hynix_nand *hynix;
++ u8 * buf = NULL;
++ int i, j;
++ int ret;
++
++ buf = kzalloc(1024, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ chip->select_chip(mtd, 0);
++ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++ chip->cmdfunc(mtd, 0x36, 0xff, -1);
++ chip->write_byte(mtd, 0x40);
++ chip->cmdfunc(mtd, NAND_CMD_NONE, 0xcc, -1);
++ chip->write_byte(mtd, 0x4d);
++ chip->cmdfunc(mtd, 0x16, -1, -1);
++ chip->cmdfunc(mtd, 0x17, -1, -1);
++ chip->cmdfunc(mtd, 0x04, -1, -1);
++ chip->cmdfunc(mtd, 0x19, -1, -1);
++ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, 0x200);
++
++ chip->read_buf(mtd, buf, 2);
++ if (buf[0] != 0x8 || buf[1] != 0x8) {
++ ret = -EINVAL;
++ goto leave;
++ }
++ chip->read_buf(mtd, buf, 1024);
++
++ ret = 0;
++ for (j = 0; j < 8; j++) {
++ for (i = 0; i < 64; i++) {
++ u8 *tmp = buf + (128 * j);
++ if ((tmp[i] | tmp[i + 64]) != 0xff) {
++ ret = -EINVAL;
++ goto leave;
++ }
++ }
++ }
++
++ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++ chip->cmdfunc(mtd, 0x38, -1, -1);
++ chip->select_chip(mtd, -1);
++
++ if (!ret) {
++ hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
++ if (!hynix) {
++ ret = -ENOMEM;
++ goto leave;
++ }
++
++ hynix->read_retry.regs = h27ucg8t2a_read_retry_regs;
++ memcpy(hynix->read_retry.values, buf, 64);
++ chip->manuf_priv = hynix;
++ chip->setup_read_retry = nand_setup_read_retry_hynix;
++ chip->read_retries = 8;
++ chip->manuf_cleanup = h27ucg8t2a_cleanup;
++ }
++
++leave:
++ kfree(buf);
++
++ return ret;
++}
++
++struct hynix_nand_initializer {
++ u8 id[6];
++ int (*init)(struct mtd_info *mtd, const uint8_t *id);
++};
++
++struct hynix_nand_initializer initializers[] = {
++ {
++ .id = {NAND_MFR_HYNIX, 0xde, 0x94, 0xda, 0x74, 0xc4},
++ .init = h27ucg8t2a_init,
++ },
++};
++
++int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(initializers); i++) {
++ struct hynix_nand_initializer *initializer = &initializers[i];
++ if (memcmp(id, initializer->id, sizeof(initializer->id)))
++ continue;
++
++ return initializer->init(mtd, id);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(hynix_nand_init);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Boris BREZILLON <b.brezillon.dev@gmail.com>");
++MODULE_DESCRIPTION("Hynix NAND specific code");
+diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
+index dd620c1..b786718 100644
+--- a/drivers/mtd/nand/nand_ids.c
++++ b/drivers/mtd/nand/nand_ids.c
+@@ -163,6 +163,7 @@ struct nand_flash_dev nand_flash_ids[] = {
+ {NULL}
+ };
+
++
+ /* Manufacturer IDs */
+ struct nand_manufacturers nand_manuf_ids[] = {
+ {NAND_MFR_TOSHIBA, "Toshiba"},
+@@ -171,7 +172,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
+ {NAND_MFR_NATIONAL, "National"},
+ {NAND_MFR_RENESAS, "Renesas"},
+ {NAND_MFR_STMICRO, "ST Micro"},
+- {NAND_MFR_HYNIX, "Hynix"},
++ {NAND_MFR_HYNIX, "Hynix", hynix_nand_init},
+ {NAND_MFR_MICRON, "Micron"},
+ {NAND_MFR_AMD, "AMD/Spansion"},
+ {NAND_MFR_MACRONIX, "Macronix"},
+diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
+index 5844d6f..328aab2 100644
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -959,6 +959,8 @@ struct nand_manufacturers {
+ extern struct nand_flash_dev nand_flash_ids[];
+ extern struct nand_manufacturers nand_manuf_ids[];
+
++int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id);
++
+ extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
+ extern int nand_default_bbt(struct mtd_info *mtd);
+ extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);