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
6 This commit uses the recently introduced SPI NAND framework to support
7 the Gigadevice GD5F serial NAND device.
9 The current support includes:
11 * Page read and page program operations (using on-die ECC)
12 * Page out-of-band read
15 * Device status retrieval
18 (based on http://lists.infradead.org/pipermail/linux-mtd/2014-December/056769.html)
20 Signed-off-by: Ezequiel Garcia <ezequiel.garcia@imgtec.com>
21 Signed-off-by: Ian Pozella <Ian.Pozella@imgtec.com>
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
29 --- a/drivers/mtd/spi-nand/Kconfig
30 +++ b/drivers/mtd/spi-nand/Kconfig
31 @@ -5,3 +5,13 @@ menuconfig MTD_SPI_NAND
33 This is the framework for the SPI NAND.
37 +config MTD_SPI_NAND_DEVICES
38 + tristate "Support for SPI NAND devices"
40 + depends on MTD_SPI_NAND
42 + Select this option if you require support for SPI NAND devices.
45 --- a/drivers/mtd/spi-nand/Makefile
46 +++ b/drivers/mtd/spi-nand/Makefile
48 obj-$(CONFIG_MTD_SPI_NAND) += spi-nand-base.o
49 +obj-$(CONFIG_MTD_SPI_NAND_DEVICES) += spi-nand-device.o
51 +++ b/drivers/mtd/spi-nand/spi-nand-device.c
54 + * Copyright (C) 2014 Imagination Technologies Ltd.
56 + * This program is free software; you can redistribute it and/or modify
57 + * it under the terms of the GNU General Public License as published by
58 + * the Free Software Foundation; version 2 of the License.
61 + * 1. We avoid using a stack-allocated buffer for SPI messages. Using
62 + * a kmalloced buffer is probably better, given we shouldn't assume
63 + * any particular usage by SPI core.
66 +#include <linux/device.h>
67 +#include <linux/err.h>
68 +#include <linux/errno.h>
69 +#include <linux/module.h>
70 +#include <linux/mtd/mtd.h>
71 +#include <linux/mtd/partitions.h>
72 +#include <linux/mtd/spi-nand.h>
73 +#include <linux/sizes.h>
74 +#include <linux/spi/spi.h>
76 +/* SPI NAND commands */
77 +#define SPI_NAND_WRITE_ENABLE 0x06
78 +#define SPI_NAND_WRITE_DISABLE 0x04
79 +#define SPI_NAND_GET_FEATURE 0x0f
80 +#define SPI_NAND_SET_FEATURE 0x1f
81 +#define SPI_NAND_PAGE_READ 0x13
82 +#define SPI_NAND_READ_CACHE 0x03
83 +#define SPI_NAND_FAST_READ_CACHE 0x0b
84 +#define SPI_NAND_READ_CACHE_X2 0x3b
85 +#define SPI_NAND_READ_CACHE_X4 0x6b
86 +#define SPI_NAND_READ_CACHE_DUAL_IO 0xbb
87 +#define SPI_NAND_READ_CACHE_QUAD_IO 0xeb
88 +#define SPI_NAND_READ_ID 0x9f
89 +#define SPI_NAND_PROGRAM_LOAD 0x02
90 +#define SPI_NAND_PROGRAM_LOAD4 0x32
91 +#define SPI_NAND_PROGRAM_EXEC 0x10
92 +#define SPI_NAND_PROGRAM_LOAD_RANDOM 0x84
93 +#define SPI_NAND_PROGRAM_LOAD_RANDOM4 0xc4
94 +#define SPI_NAND_BLOCK_ERASE 0xd8
95 +#define SPI_NAND_RESET 0xff
97 +#define SPI_NAND_GD5F_READID_LEN 2
99 +#define SPI_NAND_GD5F_ECC_MASK (BIT(0) | BIT(1) | BIT(2))
100 +#define SPI_NAND_GD5F_ECC_UNCORR (BIT(0) | BIT(1) | BIT(2))
101 +#define SPI_NAND_GD5F_ECC_SHIFT 4
103 +static int spi_nand_gd5f_ooblayout_256_ecc(struct mtd_info *mtd, int section,
104 + struct mtd_oob_region *oobregion)
109 + oobregion->offset = 128;
110 + oobregion->length = 128;
115 +static int spi_nand_gd5f_ooblayout_256_free(struct mtd_info *mtd, int section,
116 + struct mtd_oob_region *oobregion)
121 + oobregion->offset = 1;
122 + oobregion->length = 127;
127 +static const struct mtd_ooblayout_ops spi_nand_gd5f_oob_256_ops = {
128 + .ecc = spi_nand_gd5f_ooblayout_256_ecc,
129 + .free = spi_nand_gd5f_ooblayout_256_free,
132 +static struct nand_flash_dev spi_nand_flash_ids[] = {
134 + .name = "SPI NAND 512MiB 3,3V",
135 + .id = { NAND_MFR_GIGADEVICE, 0xb4 },
138 + .erasesize = SZ_256K,
141 + .ecc.strength_ds = 8,
142 + .ecc.step_ds = 512,
145 + .name = "SPI NAND 512MiB 1,8V",
146 + .id = { NAND_MFR_GIGADEVICE, 0xa4 },
149 + .erasesize = SZ_256K,
152 + .ecc.strength_ds = 8,
153 + .ecc.step_ds = 512,
157 +enum spi_nand_device_variant {
162 +struct spi_nand_device_cmd {
165 + * Command and address. I/O errors have been observed if a
166 + * separate spi_transfer is used for command and address,
167 + * so keep them together.
183 +struct spi_nand_device {
184 + struct spi_nand spi_nand;
185 + struct spi_device *spi;
187 + struct spi_nand_device_cmd cmd;
190 +static int spi_nand_send_command(struct spi_device *spi,
191 + struct spi_nand_device_cmd *cmd)
193 + struct spi_message message;
194 + struct spi_transfer x[2];
197 + dev_err(&spi->dev, "cannot send an empty command\n");
201 + if (cmd->n_tx && cmd->n_rx) {
202 + dev_err(&spi->dev, "cannot send and receive data at the same time\n");
206 + spi_message_init(&message);
207 + memset(x, 0, sizeof(x));
209 + /* Command and address */
210 + x[0].len = cmd->n_cmd;
211 + x[0].tx_buf = cmd->cmd;
212 + x[0].tx_nbits = cmd->tx_nbits;
213 + spi_message_add_tail(&x[0], &message);
215 + /* Data to be transmitted */
217 + x[1].len = cmd->n_tx;
218 + x[1].tx_buf = cmd->tx_buf;
219 + x[1].tx_nbits = cmd->tx_nbits;
220 + spi_message_add_tail(&x[1], &message);
223 + /* Data to be received */
225 + x[1].len = cmd->n_rx;
226 + x[1].rx_buf = cmd->rx_buf;
227 + x[1].rx_nbits = cmd->rx_nbits;
228 + spi_message_add_tail(&x[1], &message);
231 + return spi_sync(spi, &message);
234 +static int spi_nand_device_reset(struct spi_nand *snand)
236 + struct spi_nand_device *snand_dev = snand->priv;
237 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
239 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
241 + cmd->cmd[0] = SPI_NAND_RESET;
243 + dev_dbg(snand->dev, "%s\n", __func__);
245 + return spi_nand_send_command(snand_dev->spi, cmd);
248 +static int spi_nand_device_read_reg(struct spi_nand *snand, u8 opcode, u8 *buf)
250 + struct spi_nand_device *snand_dev = snand->priv;
251 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
253 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
255 + cmd->cmd[0] = SPI_NAND_GET_FEATURE;
256 + cmd->cmd[1] = opcode;
260 + dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode);
262 + return spi_nand_send_command(snand_dev->spi, cmd);
265 +static int spi_nand_device_write_reg(struct spi_nand *snand, u8 opcode, u8 *buf)
267 + struct spi_nand_device *snand_dev = snand->priv;
268 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
270 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
272 + cmd->cmd[0] = SPI_NAND_SET_FEATURE;
273 + cmd->cmd[1] = opcode;
277 + dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode);
279 + return spi_nand_send_command(snand_dev->spi, cmd);
282 +static int spi_nand_device_write_enable(struct spi_nand *snand)
284 + struct spi_nand_device *snand_dev = snand->priv;
285 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
287 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
289 + cmd->cmd[0] = SPI_NAND_WRITE_ENABLE;
291 + dev_dbg(snand->dev, "%s\n", __func__);
293 + return spi_nand_send_command(snand_dev->spi, cmd);
296 +static int spi_nand_device_write_disable(struct spi_nand *snand)
298 + struct spi_nand_device *snand_dev = snand->priv;
299 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
301 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
303 + cmd->cmd[0] = SPI_NAND_WRITE_DISABLE;
305 + dev_dbg(snand->dev, "%s\n", __func__);
307 + return spi_nand_send_command(snand_dev->spi, cmd);
310 +static int spi_nand_device_write_page(struct spi_nand *snand,
311 + unsigned int page_addr)
313 + struct spi_nand_device *snand_dev = snand->priv;
314 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
316 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
318 + cmd->cmd[0] = SPI_NAND_PROGRAM_EXEC;
319 + cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16);
320 + cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8);
321 + cmd->cmd[3] = (u8)(page_addr & 0xff);
323 + dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr);
325 + return spi_nand_send_command(snand_dev->spi, cmd);
328 +static int spi_nand_device_store_cache(struct spi_nand *snand,
329 + unsigned int page_offset, size_t length,
332 + struct spi_nand_device *snand_dev = snand->priv;
333 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
334 + struct spi_device *spi = snand_dev->spi;
336 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
338 + cmd->cmd[0] = spi->mode & SPI_TX_QUAD ? SPI_NAND_PROGRAM_LOAD4 :
339 + SPI_NAND_PROGRAM_LOAD;
340 + cmd->cmd[1] = (u8)((page_offset & 0xff00) >> 8);
341 + cmd->cmd[2] = (u8)(page_offset & 0xff);
342 + cmd->n_tx = length;
343 + cmd->tx_buf = write_buf;
344 + cmd->tx_nbits = spi->mode & SPI_TX_QUAD ? 4 : 1;
346 + dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset);
348 + return spi_nand_send_command(snand_dev->spi, cmd);
351 +static int spi_nand_device_load_page(struct spi_nand *snand,
352 + unsigned int page_addr)
354 + struct spi_nand_device *snand_dev = snand->priv;
355 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
357 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
359 + cmd->cmd[0] = SPI_NAND_PAGE_READ;
360 + cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16);
361 + cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8);
362 + cmd->cmd[3] = (u8)(page_addr & 0xff);
364 + dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr);
366 + return spi_nand_send_command(snand_dev->spi, cmd);
369 +static int spi_nand_device_read_cache(struct spi_nand *snand,
370 + unsigned int page_offset, size_t length,
373 + struct spi_nand_device *snand_dev = snand->priv;
374 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
375 + struct spi_device *spi = snand_dev->spi;
377 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
378 + if ((spi->mode & SPI_RX_DUAL) || (spi->mode & SPI_RX_QUAD))
382 + cmd->cmd[0] = (spi->mode & SPI_RX_QUAD) ? SPI_NAND_READ_CACHE_X4 :
383 + ((spi->mode & SPI_RX_DUAL) ? SPI_NAND_READ_CACHE_X2 :
384 + SPI_NAND_READ_CACHE);
385 + cmd->cmd[1] = 0; /* dummy byte */
386 + cmd->cmd[2] = (u8)((page_offset & 0xff00) >> 8);
387 + cmd->cmd[3] = (u8)(page_offset & 0xff);
388 + cmd->cmd[4] = 0; /* dummy byte */
389 + cmd->n_rx = length;
390 + cmd->rx_buf = read_buf;
391 + cmd->rx_nbits = (spi->mode & SPI_RX_QUAD) ? 4 :
392 + ((spi->mode & SPI_RX_DUAL) ? 2 : 1);
394 + dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset);
396 + return spi_nand_send_command(snand_dev->spi, cmd);
399 +static int spi_nand_device_block_erase(struct spi_nand *snand,
400 + unsigned int page_addr)
402 + struct spi_nand_device *snand_dev = snand->priv;
403 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
405 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
407 + cmd->cmd[0] = SPI_NAND_BLOCK_ERASE;
408 + cmd->cmd[1] = (u8)((page_addr & 0xff0000) >> 16);
409 + cmd->cmd[2] = (u8)((page_addr & 0xff00) >> 8);
410 + cmd->cmd[3] = (u8)(page_addr & 0xff);
412 + dev_dbg(snand->dev, "%s: block 0x%x\n", __func__, page_addr);
414 + return spi_nand_send_command(snand_dev->spi, cmd);
417 +static int spi_nand_gd5f_read_id(struct spi_nand *snand, u8 *buf)
419 + struct spi_nand_device *snand_dev = snand->priv;
420 + struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
422 + memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
424 + cmd->cmd[0] = SPI_NAND_READ_ID;
425 + cmd->n_rx = SPI_NAND_GD5F_READID_LEN;
428 + dev_dbg(snand->dev, "%s\n", __func__);
430 + return spi_nand_send_command(snand_dev->spi, cmd);
433 +static void spi_nand_gd5f_ecc_status(unsigned int status,
434 + unsigned int *corrected,
435 + unsigned int *ecc_error)
437 + unsigned int ecc_status = (status >> SPI_NAND_GD5F_ECC_SHIFT) &
438 + SPI_NAND_GD5F_ECC_MASK;
440 + *ecc_error = (ecc_status == SPI_NAND_GD5F_ECC_UNCORR) ? 1 : 0;
441 + if (*ecc_error == 0)
442 + *corrected = (ecc_status > 1) ? (2 + ecc_status) : 0;
445 +static int spi_nand_device_probe(struct spi_device *spi)
447 + enum spi_nand_device_variant variant;
448 + struct spi_nand_device *priv;
449 + struct spi_nand *snand;
452 + priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
456 + snand = &priv->spi_nand;
458 + snand->read_cache = spi_nand_device_read_cache;
459 + snand->load_page = spi_nand_device_load_page;
460 + snand->store_cache = spi_nand_device_store_cache;
461 + snand->write_page = spi_nand_device_write_page;
462 + snand->write_reg = spi_nand_device_write_reg;
463 + snand->read_reg = spi_nand_device_read_reg;
464 + snand->block_erase = spi_nand_device_block_erase;
465 + snand->reset = spi_nand_device_reset;
466 + snand->write_enable = spi_nand_device_write_enable;
467 + snand->write_disable = spi_nand_device_write_disable;
468 + snand->dev = &spi->dev;
469 + snand->priv = priv;
471 + /* This'll mean we won't need to specify any specific compatible string
472 + * for a given device, and instead just support spi-nand.
474 + variant = spi_get_device_id(spi)->driver_data;
476 + case SPI_NAND_GD5F:
477 + snand->read_id = spi_nand_gd5f_read_id;
478 + snand->get_ecc_status = spi_nand_gd5f_ecc_status;
479 + snand->ooblayout = &spi_nand_gd5f_oob_256_ops;
482 + dev_err(snand->dev, "unknown device\n");
486 + spi_set_drvdata(spi, snand);
489 + ret = spi_nand_register(snand, spi_nand_flash_ids);
495 +static int spi_nand_device_remove(struct spi_device *spi)
497 + struct spi_nand *snand = spi_get_drvdata(spi);
499 + spi_nand_unregister(snand);
504 +const struct spi_device_id spi_nand_id_table[] = {
505 + { "spi-nand", SPI_NAND_GENERIC },
506 + { "gd5f", SPI_NAND_GD5F },
509 +MODULE_DEVICE_TABLE(spi, spi_nand_id_table);
511 +static struct spi_driver spi_nand_device_driver = {
513 + .name = "spi_nand_device",
514 + .owner = THIS_MODULE,
516 + .id_table = spi_nand_id_table,
517 + .probe = spi_nand_device_probe,
518 + .remove = spi_nand_device_remove,
520 +module_spi_driver(spi_nand_device_driver);
522 +MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@imgtec.com>");
523 +MODULE_DESCRIPTION("SPI NAND device support");
524 +MODULE_LICENSE("GPL v2");