kernel: update 4.1 to 4.1.5
[openwrt/svn-archive/archive.git] / target / linux / sunxi / patches-4.1 / 117-mtd-nand-add-hynix-init.patch
1 From 5c5e3963a1b58be1669da5da93f51dc339cd73d7 Mon Sep 17 00:00:00 2001
2 From: Boris BREZILLON <b.brezillon.dev@gmail.com>
3 Date: Mon, 24 Feb 2014 16:30:22 +0100
4 Subject: [PATCH] mtd: nand: Add hynix specific initializer
5
6 Add an hynix initiliazer to manage read retries on h27uxgt8t2a chip.
7
8 Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
9 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
10 ---
11 drivers/mtd/nand/Makefile | 2 +-
12 drivers/mtd/nand/nand_hynix.c | 159 ++++++++++++++++++++++++++++++++++++++++++
13 drivers/mtd/nand/nand_ids.c | 3 +-
14 include/linux/mtd/nand.h | 2 +
15 4 files changed, 164 insertions(+), 2 deletions(-)
16 create mode 100644 drivers/mtd/nand/nand_hynix.c
17
18 --- a/drivers/mtd/nand/Makefile
19 +++ b/drivers/mtd/nand/Makefile
20 @@ -5,7 +5,7 @@
21 obj-$(CONFIG_MTD_NAND) += nand.o
22 obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
23 obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
24 -obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
25 +obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o nand_hynix.o
26 obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
27
28 obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
29 --- /dev/null
30 +++ b/drivers/mtd/nand/nand_hynix.c
31 @@ -0,0 +1,159 @@
32 +/*
33 + * Copyright (C) 2014 Boris BREZILLON <b.brezillon.dev@gmail.com>
34 + *
35 + * This program is free software; you can redistribute it and/or modify
36 + * it under the terms of the GNU General Public License as published by
37 + * the Free Software Foundation; either version 2 of the License, or
38 + * (at your option) any later version.
39 + *
40 + * This program is distributed in the hope that it will be useful,
41 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 + * GNU General Public License for more details.
44 + */
45 +
46 +#include <linux/module.h>
47 +#include <linux/mtd/nand.h>
48 +#include <linux/slab.h>
49 +
50 +static u8 h27ucg8t2a_read_retry_regs[] = {
51 + 0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
52 +};
53 +
54 +struct hynix_read_retry {
55 + u8 *regs;
56 + u8 values[64];
57 +};
58 +
59 +struct hynix_nand {
60 + struct hynix_read_retry read_retry;
61 +};
62 +
63 +int nand_setup_read_retry_hynix(struct mtd_info *mtd, int retry_mode)
64 +{
65 + struct nand_chip *chip = mtd->priv;
66 + struct hynix_nand *hynix = chip->manuf_priv;
67 + int offset = retry_mode * 8;
68 + int status;
69 + int i;
70 +
71 + chip->cmdfunc(mtd, 0x36, -1, -1);
72 + for (i = 0; i < 8; i++) {
73 + int column = hynix->read_retry.regs[i];
74 + column |= column << 8;
75 + chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
76 + chip->write_byte(mtd, hynix->read_retry.values[offset + i]);
77 + }
78 + chip->cmdfunc(mtd, 0x16, -1, -1);
79 +
80 + status = chip->waitfunc(mtd, chip);
81 + if (status & NAND_STATUS_FAIL)
82 + return -EIO;
83 +
84 + return 0;
85 +}
86 +
87 +static void h27ucg8t2a_cleanup(struct mtd_info *mtd)
88 +{
89 + struct nand_chip *chip = mtd->priv;
90 + kfree(chip->manuf_priv);
91 +}
92 +
93 +static int h27ucg8t2a_init(struct mtd_info *mtd, const uint8_t *id)
94 +{
95 + struct nand_chip *chip = mtd->priv;
96 + struct hynix_nand *hynix;
97 + u8 * buf = NULL;
98 + int i, j;
99 + int ret;
100 +
101 + buf = kzalloc(1024, GFP_KERNEL);
102 + if (!buf)
103 + return -ENOMEM;
104 +
105 + chip->select_chip(mtd, 0);
106 + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
107 + chip->cmdfunc(mtd, 0x36, 0xff, -1);
108 + chip->write_byte(mtd, 0x40);
109 + chip->cmdfunc(mtd, NAND_CMD_NONE, 0xcc, -1);
110 + chip->write_byte(mtd, 0x4d);
111 + chip->cmdfunc(mtd, 0x16, -1, -1);
112 + chip->cmdfunc(mtd, 0x17, -1, -1);
113 + chip->cmdfunc(mtd, 0x04, -1, -1);
114 + chip->cmdfunc(mtd, 0x19, -1, -1);
115 + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, 0x200);
116 +
117 + chip->read_buf(mtd, buf, 2);
118 + if (buf[0] != 0x8 || buf[1] != 0x8) {
119 + ret = -EINVAL;
120 + goto leave;
121 + }
122 + chip->read_buf(mtd, buf, 1024);
123 +
124 + ret = 0;
125 + for (j = 0; j < 8; j++) {
126 + for (i = 0; i < 64; i++) {
127 + u8 *tmp = buf + (128 * j);
128 + if ((tmp[i] | tmp[i + 64]) != 0xff) {
129 + ret = -EINVAL;
130 + goto leave;
131 + }
132 + }
133 + }
134 +
135 + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
136 + chip->cmdfunc(mtd, 0x38, -1, -1);
137 + chip->select_chip(mtd, -1);
138 +
139 + if (!ret) {
140 + hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
141 + if (!hynix) {
142 + ret = -ENOMEM;
143 + goto leave;
144 + }
145 +
146 + hynix->read_retry.regs = h27ucg8t2a_read_retry_regs;
147 + memcpy(hynix->read_retry.values, buf, 64);
148 + chip->manuf_priv = hynix;
149 + chip->setup_read_retry = nand_setup_read_retry_hynix;
150 + chip->read_retries = 8;
151 + chip->manuf_cleanup = h27ucg8t2a_cleanup;
152 + }
153 +
154 +leave:
155 + kfree(buf);
156 +
157 + return ret;
158 +}
159 +
160 +struct hynix_nand_initializer {
161 + u8 id[6];
162 + int (*init)(struct mtd_info *mtd, const uint8_t *id);
163 +};
164 +
165 +struct hynix_nand_initializer initializers[] = {
166 + {
167 + .id = {NAND_MFR_HYNIX, 0xde, 0x94, 0xda, 0x74, 0xc4},
168 + .init = h27ucg8t2a_init,
169 + },
170 +};
171 +
172 +int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id)
173 +{
174 + int i;
175 +
176 + for (i = 0; i < ARRAY_SIZE(initializers); i++) {
177 + struct hynix_nand_initializer *initializer = &initializers[i];
178 + if (memcmp(id, initializer->id, sizeof(initializer->id)))
179 + continue;
180 +
181 + return initializer->init(mtd, id);
182 + }
183 +
184 + return 0;
185 +}
186 +EXPORT_SYMBOL(hynix_nand_init);
187 +
188 +MODULE_LICENSE("GPL");
189 +MODULE_AUTHOR("Boris BREZILLON <b.brezillon.dev@gmail.com>");
190 +MODULE_DESCRIPTION("Hynix NAND specific code");
191 --- a/drivers/mtd/nand/nand_ids.c
192 +++ b/drivers/mtd/nand/nand_ids.c
193 @@ -163,6 +163,7 @@ struct nand_flash_dev nand_flash_ids[] =
194 {NULL}
195 };
196
197 +
198 /* Manufacturer IDs */
199 struct nand_manufacturers nand_manuf_ids[] = {
200 {NAND_MFR_TOSHIBA, "Toshiba"},
201 @@ -171,7 +172,7 @@ struct nand_manufacturers nand_manuf_ids
202 {NAND_MFR_NATIONAL, "National"},
203 {NAND_MFR_RENESAS, "Renesas"},
204 {NAND_MFR_STMICRO, "ST Micro"},
205 - {NAND_MFR_HYNIX, "Hynix"},
206 + {NAND_MFR_HYNIX, "Hynix", hynix_nand_init},
207 {NAND_MFR_MICRON, "Micron"},
208 {NAND_MFR_AMD, "AMD/Spansion"},
209 {NAND_MFR_MACRONIX, "Macronix"},
210 --- a/include/linux/mtd/nand.h
211 +++ b/include/linux/mtd/nand.h
212 @@ -959,6 +959,8 @@ struct nand_manufacturers {
213 extern struct nand_flash_dev nand_flash_ids[];
214 extern struct nand_manufacturers nand_manuf_ids[];
215
216 +int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id);
217 +
218 extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
219 extern int nand_default_bbt(struct mtd_info *mtd);
220 extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);