pistachio: add 4.9 kernel support
[openwrt/openwrt.git] / target / linux / pistachio / patches-4.9 / 414-mtd-spi-nand-Support-Gigadevice-GD5F.patch
1 From 7723e59d483a883578115a73eb87eb7fff0ff724 Mon Sep 17 00:00:00 2001
2 From: Ezequiel Garcia <ezequiel.garcia@imgtec.com>
3 Date: Tue, 28 Feb 2017 10:37:24 +0000
4 Subject: mtd: spi-nand: Support Gigadevice GD5F
5
6 This commit uses the recently introduced SPI NAND framework to support
7 the Gigadevice GD5F serial NAND device.
8
9 The current support includes:
10
11 * Page read and page program operations (using on-die ECC)
12 * Page out-of-band read
13 * Erase
14 * Reset
15 * Device status retrieval
16 * Device ID retrieval
17
18 (based on http://lists.infradead.org/pipermail/linux-mtd/2014-December/056769.html)
19
20 Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com>
21 Signed-off-by: Ian Pozella <Ian.Pozella@imgtec.com>
22 ---
23 drivers/mtd/spi-nand/Kconfig | 10 +
24 drivers/mtd/spi-nand/Makefile | 1 +
25 drivers/mtd/spi-nand/spi-nand-device.c | 472 +++++++++++++++++++++++++++++++++
26 3 files changed, 483 insertions(+)
27 create mode 100644 drivers/mtd/spi-nand/spi-nand-device.c
28
29 diff --git a/drivers/mtd/spi-nand/Kconfig b/drivers/mtd/spi-nand/Kconfig
30 index 17b31e1..ab6bb6c 100644
31 --- a/drivers/mtd/spi-nand/Kconfig
32 +++ b/drivers/mtd/spi-nand/Kconfig
33 @@ -5,3 +5,13 @@ menuconfig MTD_SPI_NAND
34 help
35 This is the framework for the SPI NAND.
36
37 +if MTD_SPI_NAND
38 +
39 +config MTD_SPI_NAND_DEVICES
40 + tristate "Support for SPI NAND devices"
41 + default y
42 + depends on MTD_SPI_NAND
43 + help
44 + Select this option if you require support for SPI NAND devices.
45 +
46 +endif # MTD_SPI_NAND
47 diff --git a/drivers/mtd/spi-nand/Makefile b/drivers/mtd/spi-nand/Makefile
48 index d454c52..6e460d1 100644
49 --- a/drivers/mtd/spi-nand/Makefile
50 +++ b/drivers/mtd/spi-nand/Makefile
51 @@ -1 +1,2 @@
52 obj-$(CONFIG_MTD_SPI_NAND) += spi-nand-base.o
53 +obj-$(CONFIG_MTD_SPI_NAND_DEVICES) += spi-nand-device.o
54 diff --git a/drivers/mtd/spi-nand/spi-nand-device.c b/drivers/mtd/spi-nand/spi-nand-device.c
55 new file mode 100644
56 index 0000000..95db20b
57 --- /dev/null
58 +++ b/drivers/mtd/spi-nand/spi-nand-device.c
59 @@ -0,0 +1,472 @@
60 +/*
61 + * Copyright (C) 2014 Imagination Technologies Ltd.
62 + *
63 + * This program is free software; you can redistribute it and/or modify
64 + * it under the terms of the GNU General Public License as published by
65 + * the Free Software Foundation; version 2 of the License.
66 + *
67 + * Notes:
68 + * 1. We avoid using a stack-allocated buffer for SPI messages. Using
69 + * a kmalloced buffer is probably better, given we shouldn't assume
70 + * any particular usage by SPI core.
71 + */
72 +
73 +#include <linux/device.h>
74 +#include <linux/err.h>
75 +#include <linux/errno.h>
76 +#include <linux/module.h>
77 +#include <linux/mtd/mtd.h>
78 +#include <linux/mtd/partitions.h>
79 +#include <linux/mtd/spi-nand.h>
80 +#include <linux/sizes.h>
81 +#include <linux/spi/spi.h>
82 +
83 +/* SPI NAND commands */
84 +#define SPI_NAND_WRITE_ENABLE 0x06
85 +#define SPI_NAND_WRITE_DISABLE 0x04
86 +#define SPI_NAND_GET_FEATURE 0x0f
87 +#define SPI_NAND_SET_FEATURE 0x1f
88 +#define SPI_NAND_PAGE_READ 0x13
89 +#define SPI_NAND_READ_CACHE 0x03
90 +#define SPI_NAND_FAST_READ_CACHE 0x0b
91 +#define SPI_NAND_READ_CACHE_X2 0x3b
92 +#define SPI_NAND_READ_CACHE_X4 0x6b
93 +#define SPI_NAND_READ_CACHE_DUAL_IO 0xbb
94 +#define SPI_NAND_READ_CACHE_QUAD_IO 0xeb
95 +#define SPI_NAND_READ_ID 0x9f
96 +#define SPI_NAND_PROGRAM_LOAD 0x02
97 +#define SPI_NAND_PROGRAM_LOAD4 0x32
98 +#define SPI_NAND_PROGRAM_EXEC 0x10
99 +#define SPI_NAND_PROGRAM_LOAD_RANDOM 0x84
100 +#define SPI_NAND_PROGRAM_LOAD_RANDOM4 0xc4
101 +#define SPI_NAND_BLOCK_ERASE 0xd8
102 +#define SPI_NAND_RESET 0xff
103 +
104 +#define SPI_NAND_GD5F_READID_LEN 2
105 +
106 +#define SPI_NAND_GD5F_ECC_MASK (BIT(0) | BIT(1) | BIT(2))
107 +#define SPI_NAND_GD5F_ECC_UNCORR (BIT(0) | BIT(1) | BIT(2))
108 +#define SPI_NAND_GD5F_ECC_SHIFT 4
109 +
110 +static int spi_nand_gd5f_ooblayout_256_ecc(struct mtd_info *mtd, int section,
111 + struct mtd_oob_region *oobregion)
112 +{
113 + if (section)
114 + return -ERANGE;
115 +
116 + oobregion->offset = 128;
117 + oobregion->length = 128;
118 +
119 + return 0;
120 +}
121 +
122 +static int spi_nand_gd5f_ooblayout_256_free(struct mtd_info *mtd, int section,
123 + struct mtd_oob_region *oobregion)
124 +{
125 + if (section)
126 + return -ERANGE;
127 +
128 + oobregion->offset = 1;
129 + oobregion->length = 127;
130 +
131 + return 0;
132 +}
133 +
134 +static const struct mtd_ooblayout_ops spi_nand_gd5f_oob_256_ops = {
135 + .ecc = spi_nand_gd5f_ooblayout_256_ecc,
136 + .free = spi_nand_gd5f_ooblayout_256_free,
137 +};
138 +
139 +static struct nand_flash_dev spi_nand_flash_ids[] = {
140 + {
141 + .name = "SPI NAND 512MiB 3,3V",
142 + .id = { NAND_MFR_GIGADEVICE, 0xb4 },
143 + .chipsize = 512,
144 + .pagesize = SZ_4K,
145 + .erasesize = SZ_256K,
146 + .id_len = 2,
147 + .oobsize = 256,
148 + .ecc.strength_ds = 8,
149 + .ecc.step_ds = 512,
150 + },
151 + {
152 + .name = "SPI NAND 512MiB 1,8V",
153 + .id = { NAND_MFR_GIGADEVICE, 0xa4 },
154 + .chipsize = 512,
155 + .pagesize = SZ_4K,
156 + .erasesize = SZ_256K,
157 + .id_len = 2,
158 + .oobsize = 256,
159 + .ecc.strength_ds = 8,
160 + .ecc.step_ds = 512,
161 + },
162 +};
163 +
164 +enum spi_nand_device_variant {
165 + SPI_NAND_GENERIC,
166 + SPI_NAND_GD5F,
167 +};
168 +
169 +struct spi_nand_device_cmd {
170 +
171 + /*
172 + * Command and address. I/O errors have been observed if a
173 + * separate spi_transfer is used for command and address,
174 + * so keep them together.
175 + */
176 + u32 n_cmd;
177 + u8 cmd[5];
178 +
179 + /* Tx data */
180 + u32 n_tx;
181 + u8 *tx_buf;
182 +
183 + /* Rx data */
184 + u32 n_rx;
185 + u8 *rx_buf;
186 + u8 rx_nbits;
187 + u8 tx_nbits;
188 +};
189 +
190 +struct spi_nand_device {
191 + struct spi_nand spi_nand;
192 + struct spi_device *spi;
193 +
194 + struct spi_nand_device_cmd cmd;
195 +};
196 +
197 +static int spi_nand_send_command(struct spi_device *spi,
198 + struct spi_nand_device_cmd *cmd)
199 +{
200 + struct spi_message message;
201 + struct spi_transfer x[2];
202 +
203 + if (!cmd->n_cmd) {
204 + dev_err(&spi->dev, "cannot send an empty command\n");
205 + return -EINVAL;
206 + }
207 +
208 + if (cmd->n_tx && cmd->n_rx) {
209 + dev_err(&spi->dev, "cannot send and receive data at the same time\n");
210 + return -EINVAL;
211 + }
212 +
213 + spi_message_init(&message);
214 + memset(x, 0, sizeof(x));
215 +
216 + /* Command and address */
217 + x[0].len = cmd->n_cmd;
218 + x[0].tx_buf = cmd->cmd;
219 + x[0].tx_nbits = cmd->tx_nbits;
220 + spi_message_add_tail(&x[0], &message);
221 +
222 + /* Data to be transmitted */
223 + if (cmd->n_tx) {
224 + x[1].len = cmd->n_tx;
225 + x[1].tx_buf = cmd->tx_buf;
226 + x[1].tx_nbits = cmd->tx_nbits;
227 + spi_message_add_tail(&x[1], &message);
228 + }
229 +
230 + /* Data to be received */
231 + if (cmd->n_rx) {
232 + x[1].len = cmd->n_rx;
233 + x[1].rx_buf = cmd->rx_buf;
234 + x[1].rx_nbits = cmd->rx_nbits;
235 + spi_message_add_tail(&x[1], &message);
236 + }
237 +
238 + return spi_sync(spi, &message);
239 +}
240 +
241 +static int spi_nand_device_reset(struct spi_nand *snand)
242 +{
243 + struct spi_nand_device *snand_dev = snand->priv;
244 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
245 +
246 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
247 + cmd->n_cmd = 1;
248 + cmd->cmd[0] = SPI_NAND_RESET;
249 +
250 + dev_dbg(snand->dev, "%s\n", __func__);
251 +
252 + return spi_nand_send_command(snand_dev->spi, cmd);
253 +}
254 +
255 +static int spi_nand_device_read_reg(struct spi_nand *snand, u8 opcode, u8 *buf)
256 +{
257 + struct spi_nand_device *snand_dev = snand->priv;
258 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
259 +
260 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
261 + cmd->n_cmd = 2;
262 + cmd->cmd[0] = SPI_NAND_GET_FEATURE;
263 + cmd->cmd[1] = opcode;
264 + cmd->n_rx = 1;
265 + cmd->rx_buf = buf;
266 +
267 + dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode);
268 +
269 + return spi_nand_send_command(snand_dev->spi, cmd);
270 +}
271 +
272 +static int spi_nand_device_write_reg(struct spi_nand *snand, u8 opcode, u8 *buf)
273 +{
274 + struct spi_nand_device *snand_dev = snand->priv;
275 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
276 +
277 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
278 + cmd->n_cmd = 2;
279 + cmd->cmd[0] = SPI_NAND_SET_FEATURE;
280 + cmd->cmd[1] = opcode;
281 + cmd->n_tx = 1;
282 + cmd->tx_buf = buf;
283 +
284 + dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode);
285 +
286 + return spi_nand_send_command(snand_dev->spi, cmd);
287 +}
288 +
289 +static int spi_nand_device_write_enable(struct spi_nand *snand)
290 +{
291 + struct spi_nand_device *snand_dev = snand->priv;
292 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
293 +
294 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
295 + cmd->n_cmd = 1;
296 + cmd->cmd[0] = SPI_NAND_WRITE_ENABLE;
297 +
298 + dev_dbg(snand->dev, "%s\n", __func__);
299 +
300 + return spi_nand_send_command(snand_dev->spi, cmd);
301 +}
302 +
303 +static int spi_nand_device_write_disable(struct spi_nand *snand)
304 +{
305 + struct spi_nand_device *snand_dev = snand->priv;
306 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
307 +
308 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
309 + cmd->n_cmd = 1;
310 + cmd->cmd[0] = SPI_NAND_WRITE_DISABLE;
311 +
312 + dev_dbg(snand->dev, "%s\n", __func__);
313 +
314 + return spi_nand_send_command(snand_dev->spi, cmd);
315 +}
316 +
317 +static int spi_nand_device_write_page(struct spi_nand *snand,
318 + unsigned int page_addr)
319 +{
320 + struct spi_nand_device *snand_dev = snand->priv;
321 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
322 +
323 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
324 + cmd->n_cmd = 4;
325 + cmd->cmd[0] = SPI_NAND_PROGRAM_EXEC;
326 + cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16);
327 + cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8);
328 + cmd->cmd[3] = (u8)(page_addr & 0xff);
329 +
330 + dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr);
331 +
332 + return spi_nand_send_command(snand_dev->spi, cmd);
333 +}
334 +
335 +static int spi_nand_device_store_cache(struct spi_nand *snand,
336 + unsigned int page_offset, size_t length,
337 + u8 *write_buf)
338 +{
339 + struct spi_nand_device *snand_dev = snand->priv;
340 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
341 + struct spi_device *spi = snand_dev->spi;
342 +
343 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
344 + cmd->n_cmd = 3;
345 + cmd->cmd[0] = spi->mode & SPI_TX_QUAD ? SPI_NAND_PROGRAM_LOAD4 :
346 + SPI_NAND_PROGRAM_LOAD;
347 + cmd->cmd[1] = (u8)((page_offset & 0xff00) >> 8);
348 + cmd->cmd[2] = (u8)(page_offset & 0xff);
349 + cmd->n_tx = length;
350 + cmd->tx_buf = write_buf;
351 + cmd->tx_nbits = spi->mode & SPI_TX_QUAD ? 4 : 1;
352 +
353 + dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset);
354 +
355 + return spi_nand_send_command(snand_dev->spi, cmd);
356 +}
357 +
358 +static int spi_nand_device_load_page(struct spi_nand *snand,
359 + unsigned int page_addr)
360 +{
361 + struct spi_nand_device *snand_dev = snand->priv;
362 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
363 +
364 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
365 + cmd->n_cmd = 4;
366 + cmd->cmd[0] = SPI_NAND_PAGE_READ;
367 + cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16);
368 + cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8);
369 + cmd->cmd[3] = (u8)(page_addr & 0xff);
370 +
371 + dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr);
372 +
373 + return spi_nand_send_command(snand_dev->spi, cmd);
374 +}
375 +
376 +static int spi_nand_device_read_cache(struct spi_nand *snand,
377 + unsigned int page_offset, size_t length,
378 + u8 *read_buf)
379 +{
380 + struct spi_nand_device *snand_dev = snand->priv;
381 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
382 + struct spi_device *spi = snand_dev->spi;
383 +
384 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
385 + if ((spi->mode & SPI_RX_DUAL) || (spi->mode & SPI_RX_QUAD))
386 + cmd->n_cmd = 5;
387 + else
388 + cmd->n_cmd = 4;
389 + cmd->cmd[0] = (spi->mode & SPI_RX_QUAD) ? SPI_NAND_READ_CACHE_X4 :
390 + ((spi->mode & SPI_RX_DUAL) ? SPI_NAND_READ_CACHE_X2 :
391 + SPI_NAND_READ_CACHE);
392 + cmd->cmd[1] = 0; /* dummy byte */
393 + cmd->cmd[2] = (u8)((page_offset & 0xff00) >> 8);
394 + cmd->cmd[3] = (u8)(page_offset & 0xff);
395 + cmd->cmd[4] = 0; /* dummy byte */
396 + cmd->n_rx = length;
397 + cmd->rx_buf = read_buf;
398 + cmd->rx_nbits = (spi->mode & SPI_RX_QUAD) ? 4 :
399 + ((spi->mode & SPI_RX_DUAL) ? 2 : 1);
400 +
401 + dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset);
402 +
403 + return spi_nand_send_command(snand_dev->spi, cmd);
404 +}
405 +
406 +static int spi_nand_device_block_erase(struct spi_nand *snand,
407 + unsigned int page_addr)
408 +{
409 + struct spi_nand_device *snand_dev = snand->priv;
410 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
411 +
412 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
413 + cmd->n_cmd = 4;
414 + cmd->cmd[0] = SPI_NAND_BLOCK_ERASE;
415 + cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16);
416 + cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8);
417 + cmd->cmd[3] = (u8)(page_addr & 0xff);
418 +
419 + dev_dbg(snand->dev, "%s: block 0x%x\n", __func__, page_addr);
420 +
421 + return spi_nand_send_command(snand_dev->spi, cmd);
422 +}
423 +
424 +static int spi_nand_gd5f_read_id(struct spi_nand *snand, u8 *buf)
425 +{
426 + struct spi_nand_device *snand_dev = snand->priv;
427 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
428 +
429 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
430 + cmd->n_cmd = 1;
431 + cmd->cmd[0] = SPI_NAND_READ_ID;
432 + cmd->n_rx = SPI_NAND_GD5F_READID_LEN;
433 + cmd->rx_buf = buf;
434 +
435 + dev_dbg(snand->dev, "%s\n", __func__);
436 +
437 + return spi_nand_send_command(snand_dev->spi, cmd);
438 +}
439 +
440 +static void spi_nand_gd5f_ecc_status(unsigned int status,
441 + unsigned int *corrected,
442 + unsigned int *ecc_error)
443 +{
444 + unsigned int ecc_status = (status >> SPI_NAND_GD5F_ECC_SHIFT) &
445 + SPI_NAND_GD5F_ECC_MASK;
446 +
447 + *ecc_error = (ecc_status == SPI_NAND_GD5F_ECC_UNCORR) ? 1 : 0;
448 + if (*ecc_error == 0)
449 + *corrected = (ecc_status > 1) ? (2 + ecc_status) : 0;
450 +}
451 +
452 +static int spi_nand_device_probe(struct spi_device *spi)
453 +{
454 + enum spi_nand_device_variant variant;
455 + struct spi_nand_device *priv;
456 + struct spi_nand *snand;
457 + int ret;
458 +
459 + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
460 + if (!priv)
461 + return -ENOMEM;
462 +
463 + snand = &priv->spi_nand;
464 +
465 + snand->read_cache = spi_nand_device_read_cache;
466 + snand->load_page = spi_nand_device_load_page;
467 + snand->store_cache = spi_nand_device_store_cache;
468 + snand->write_page = spi_nand_device_write_page;
469 + snand->write_reg = spi_nand_device_write_reg;
470 + snand->read_reg = spi_nand_device_read_reg;
471 + snand->block_erase = spi_nand_device_block_erase;
472 + snand->reset = spi_nand_device_reset;
473 + snand->write_enable = spi_nand_device_write_enable;
474 + snand->write_disable = spi_nand_device_write_disable;
475 + snand->dev = &spi->dev;
476 + snand->priv = priv;
477 +
478 + /* This'll mean we won't need to specify any specific compatible string
479 + * for a given device, and instead just support spi-nand.
480 + */
481 + variant = spi_get_device_id(spi)->driver_data;
482 + switch (variant) {
483 + case SPI_NAND_GD5F:
484 + snand->read_id = spi_nand_gd5f_read_id;
485 + snand->get_ecc_status = spi_nand_gd5f_ecc_status;
486 + snand->ooblayout = &spi_nand_gd5f_oob_256_ops;
487 + break;
488 + default:
489 + dev_err(snand->dev, "unknown device\n");
490 + return -ENODEV;
491 + }
492 +
493 + spi_set_drvdata(spi, snand);
494 + priv->spi = spi;
495 +
496 + ret = spi_nand_register(snand, spi_nand_flash_ids);
497 + if (ret)
498 + return ret;
499 + return 0;
500 +}
501 +
502 +static int spi_nand_device_remove(struct spi_device *spi)
503 +{
504 + struct spi_nand *snand = spi_get_drvdata(spi);
505 +
506 + spi_nand_unregister(snand);
507 +
508 + return 0;
509 +}
510 +
511 +const struct spi_device_id spi_nand_id_table[] = {
512 + { "spi-nand", SPI_NAND_GENERIC },
513 + { "gd5f", SPI_NAND_GD5F },
514 + { },
515 +};
516 +MODULE_DEVICE_TABLE(spi, spi_nand_id_table);
517 +
518 +static struct spi_driver spi_nand_device_driver = {
519 + .driver = {
520 + .name = "spi_nand_device",
521 + .owner = THIS_MODULE,
522 + },
523 + .id_table = spi_nand_id_table,
524 + .probe = spi_nand_device_probe,
525 + .remove = spi_nand_device_remove,
526 +};
527 +module_spi_driver(spi_nand_device_driver);
528 +
529 +MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@imgtec.com>");
530 +MODULE_DESCRIPTION("SPI NAND device support");
531 +MODULE_LICENSE("GPL v2");
532 --
533 2.7.4
534