brcm2708: arm8stub is no longer needed
[oweals/openwrt.git] / target / linux / pistachio / patches-4.14 / 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 --- a/drivers/mtd/spi-nand/Kconfig
30 +++ b/drivers/mtd/spi-nand/Kconfig
31 @@ -5,3 +5,13 @@ menuconfig MTD_SPI_NAND
32         help
33           This is the framework for the SPI NAND.
34  
35 +if MTD_SPI_NAND
36 +
37 +config MTD_SPI_NAND_DEVICES
38 +       tristate "Support for SPI NAND devices"
39 +       default y
40 +       depends on MTD_SPI_NAND
41 +       help
42 +         Select this option if you require support for SPI NAND devices.
43 +
44 +endif # MTD_SPI_NAND
45 --- a/drivers/mtd/spi-nand/Makefile
46 +++ b/drivers/mtd/spi-nand/Makefile
47 @@ -1 +1,2 @@
48  obj-$(CONFIG_MTD_SPI_NAND)             += spi-nand-base.o
49 +obj-$(CONFIG_MTD_SPI_NAND_DEVICES)     += spi-nand-device.o
50 --- /dev/null
51 +++ b/drivers/mtd/spi-nand/spi-nand-device.c
52 @@ -0,0 +1,472 @@
53 +/*
54 + * Copyright (C) 2014 Imagination Technologies Ltd.
55 + *
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.
59 + *
60 + * Notes:
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.
64 + */
65 +
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>
75 +
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
96 +
97 +#define SPI_NAND_GD5F_READID_LEN       2
98 +
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
102 +
103 +static int spi_nand_gd5f_ooblayout_256_ecc(struct mtd_info *mtd, int section,
104 +                                       struct mtd_oob_region *oobregion)
105 +{
106 +       if (section)
107 +               return -ERANGE;
108 +
109 +       oobregion->offset = 128;
110 +       oobregion->length = 128;
111 +
112 +       return 0;
113 +}
114 +
115 +static int spi_nand_gd5f_ooblayout_256_free(struct mtd_info *mtd, int section,
116 +                                       struct mtd_oob_region *oobregion)
117 +{
118 +       if (section)
119 +               return -ERANGE;
120 +
121 +       oobregion->offset = 1;
122 +       oobregion->length = 127;
123 +
124 +       return 0;
125 +}
126 +
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,
130 +};
131 +
132 +static struct nand_flash_dev spi_nand_flash_ids[] = {
133 +       {
134 +               .name = "SPI NAND 512MiB 3,3V",
135 +               .id = { NAND_MFR_GIGADEVICE, 0xb4 },
136 +               .chipsize = 512,
137 +               .pagesize = SZ_4K,
138 +               .erasesize = SZ_256K,
139 +               .id_len = 2,
140 +               .oobsize = 256,
141 +               .ecc.strength_ds = 8,
142 +               .ecc.step_ds = 512,
143 +       },
144 +       {
145 +               .name = "SPI NAND 512MiB 1,8V",
146 +               .id = { NAND_MFR_GIGADEVICE, 0xa4 },
147 +               .chipsize = 512,
148 +               .pagesize = SZ_4K,
149 +               .erasesize = SZ_256K,
150 +               .id_len = 2,
151 +               .oobsize = 256,
152 +               .ecc.strength_ds = 8,
153 +               .ecc.step_ds = 512,
154 +       },
155 +};
156 +
157 +enum spi_nand_device_variant {
158 +       SPI_NAND_GENERIC,
159 +       SPI_NAND_GD5F,
160 +};
161 +
162 +struct spi_nand_device_cmd {
163 +
164 +       /*
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.
168 +        */
169 +       u32 n_cmd;
170 +       u8 cmd[5];
171 +
172 +       /* Tx data */
173 +       u32 n_tx;
174 +       u8 *tx_buf;
175 +
176 +       /* Rx data */
177 +       u32 n_rx;
178 +       u8 *rx_buf;
179 +       u8 rx_nbits;
180 +       u8 tx_nbits;
181 +};
182 +
183 +struct spi_nand_device {
184 +       struct spi_nand spi_nand;
185 +       struct spi_device *spi;
186 +
187 +       struct spi_nand_device_cmd cmd;
188 +};
189 +
190 +static int spi_nand_send_command(struct spi_device *spi,
191 +                                struct spi_nand_device_cmd *cmd)
192 +{
193 +       struct spi_message message;
194 +       struct spi_transfer x[2];
195 +
196 +       if (!cmd->n_cmd) {
197 +               dev_err(&spi->dev, "cannot send an empty command\n");
198 +               return -EINVAL;
199 +       }
200 +
201 +       if (cmd->n_tx && cmd->n_rx) {
202 +               dev_err(&spi->dev, "cannot send and receive data at the same time\n");
203 +               return -EINVAL;
204 +       }
205 +
206 +       spi_message_init(&message);
207 +       memset(x, 0, sizeof(x));
208 +
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);
214 +
215 +       /* Data to be transmitted */
216 +       if (cmd->n_tx) {
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);
221 +       }
222 +
223 +       /* Data to be received */
224 +       if (cmd->n_rx) {
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);
229 +       }
230 +
231 +       return spi_sync(spi, &message);
232 +}
233 +
234 +static int spi_nand_device_reset(struct spi_nand *snand)
235 +{
236 +       struct spi_nand_device *snand_dev = snand->priv;
237 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
238 +
239 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
240 +       cmd->n_cmd = 1;
241 +       cmd->cmd[0] = SPI_NAND_RESET;
242 +
243 +       dev_dbg(snand->dev, "%s\n", __func__);
244 +
245 +       return spi_nand_send_command(snand_dev->spi, cmd);
246 +}
247 +
248 +static int spi_nand_device_read_reg(struct spi_nand *snand, u8 opcode, u8 *buf)
249 +{
250 +       struct spi_nand_device *snand_dev = snand->priv;
251 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
252 +
253 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
254 +       cmd->n_cmd = 2;
255 +       cmd->cmd[0] = SPI_NAND_GET_FEATURE;
256 +       cmd->cmd[1] = opcode;
257 +       cmd->n_rx = 1;
258 +       cmd->rx_buf = buf;
259 +
260 +       dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode);
261 +
262 +       return spi_nand_send_command(snand_dev->spi, cmd);
263 +}
264 +
265 +static int spi_nand_device_write_reg(struct spi_nand *snand, u8 opcode, u8 *buf)
266 +{
267 +       struct spi_nand_device *snand_dev = snand->priv;
268 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
269 +
270 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
271 +       cmd->n_cmd = 2;
272 +       cmd->cmd[0] = SPI_NAND_SET_FEATURE;
273 +       cmd->cmd[1] = opcode;
274 +       cmd->n_tx = 1;
275 +       cmd->tx_buf = buf;
276 +
277 +       dev_dbg(snand->dev, "%s: reg 0%x\n", __func__, opcode);
278 +
279 +       return spi_nand_send_command(snand_dev->spi, cmd);
280 +}
281 +
282 +static int spi_nand_device_write_enable(struct spi_nand *snand)
283 +{
284 +       struct spi_nand_device *snand_dev = snand->priv;
285 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
286 +
287 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
288 +       cmd->n_cmd = 1;
289 +       cmd->cmd[0] = SPI_NAND_WRITE_ENABLE;
290 +
291 +       dev_dbg(snand->dev, "%s\n", __func__);
292 +
293 +       return spi_nand_send_command(snand_dev->spi, cmd);
294 +}
295 +
296 +static int spi_nand_device_write_disable(struct spi_nand *snand)
297 +{
298 +       struct spi_nand_device *snand_dev = snand->priv;
299 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
300 +
301 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
302 +       cmd->n_cmd = 1;
303 +       cmd->cmd[0] = SPI_NAND_WRITE_DISABLE;
304 +
305 +       dev_dbg(snand->dev, "%s\n", __func__);
306 +
307 +       return spi_nand_send_command(snand_dev->spi, cmd);
308 +}
309 +
310 +static int spi_nand_device_write_page(struct spi_nand *snand,
311 +                                     unsigned int page_addr)
312 +{
313 +       struct spi_nand_device *snand_dev = snand->priv;
314 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
315 +
316 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
317 +       cmd->n_cmd = 4;
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);
322 +
323 +       dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr);
324 +
325 +       return spi_nand_send_command(snand_dev->spi, cmd);
326 +}
327 +
328 +static int spi_nand_device_store_cache(struct spi_nand *snand,
329 +                                      unsigned int page_offset, size_t length,
330 +                                      u8 *write_buf)
331 +{
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;
335 +
336 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
337 +       cmd->n_cmd = 3;
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;
345 +
346 +       dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset);
347 +
348 +       return spi_nand_send_command(snand_dev->spi, cmd);
349 +}
350 +
351 +static int spi_nand_device_load_page(struct spi_nand *snand,
352 +                                    unsigned int page_addr)
353 +{
354 +       struct spi_nand_device *snand_dev = snand->priv;
355 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
356 +
357 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
358 +       cmd->n_cmd = 4;
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);
363 +
364 +       dev_dbg(snand->dev, "%s: page 0x%x\n", __func__, page_addr);
365 +
366 +       return spi_nand_send_command(snand_dev->spi, cmd);
367 +}
368 +
369 +static int spi_nand_device_read_cache(struct spi_nand *snand,
370 +                                     unsigned int page_offset, size_t length,
371 +                                     u8 *read_buf)
372 +{
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;
376 +
377 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
378 +       if ((spi->mode & SPI_RX_DUAL) || (spi->mode & SPI_RX_QUAD))
379 +               cmd->n_cmd = 5;
380 +       else
381 +               cmd->n_cmd = 4;
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);
393 +
394 +       dev_dbg(snand->dev, "%s: offset 0x%x\n", __func__, page_offset);
395 +
396 +       return spi_nand_send_command(snand_dev->spi, cmd);
397 +}
398 +
399 +static int spi_nand_device_block_erase(struct spi_nand *snand,
400 +                                      unsigned int page_addr)
401 +{
402 +       struct spi_nand_device *snand_dev = snand->priv;
403 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
404 +
405 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
406 +       cmd->n_cmd = 4;
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);
411 +
412 +       dev_dbg(snand->dev, "%s: block 0x%x\n", __func__, page_addr);
413 +
414 +       return spi_nand_send_command(snand_dev->spi, cmd);
415 +}
416 +
417 +static int spi_nand_gd5f_read_id(struct spi_nand *snand, u8 *buf)
418 +{
419 +       struct spi_nand_device *snand_dev = snand->priv;
420 +       struct spi_nand_device_cmd *cmd = &snand_dev->cmd;
421 +
422 +       memset(cmd, 0, sizeof(struct spi_nand_device_cmd));
423 +       cmd->n_cmd = 1;
424 +       cmd->cmd[0] = SPI_NAND_READ_ID;
425 +       cmd->n_rx = SPI_NAND_GD5F_READID_LEN;
426 +       cmd->rx_buf = buf;
427 +
428 +       dev_dbg(snand->dev, "%s\n", __func__);
429 +
430 +       return spi_nand_send_command(snand_dev->spi, cmd);
431 +}
432 +
433 +static void spi_nand_gd5f_ecc_status(unsigned int status,
434 +                                    unsigned int *corrected,
435 +                                    unsigned int *ecc_error)
436 +{
437 +       unsigned int ecc_status = (status >> SPI_NAND_GD5F_ECC_SHIFT) &
438 +                                            SPI_NAND_GD5F_ECC_MASK;
439 +
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;
443 +}
444 +
445 +static int spi_nand_device_probe(struct spi_device *spi)
446 +{
447 +       enum spi_nand_device_variant variant;
448 +       struct spi_nand_device *priv;
449 +       struct spi_nand *snand;
450 +       int ret;
451 +
452 +       priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
453 +       if (!priv)
454 +               return -ENOMEM;
455 +
456 +       snand = &priv->spi_nand;
457 +
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;
470 +
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.
473 +        */
474 +       variant = spi_get_device_id(spi)->driver_data;
475 +       switch (variant) {
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;
480 +               break;
481 +       default:
482 +               dev_err(snand->dev, "unknown device\n");
483 +               return -ENODEV;
484 +       }
485 +
486 +       spi_set_drvdata(spi, snand);
487 +       priv->spi = spi;
488 +
489 +       ret = spi_nand_register(snand, spi_nand_flash_ids);
490 +       if (ret)
491 +               return ret;
492 +       return 0;
493 +}
494 +
495 +static int spi_nand_device_remove(struct spi_device *spi)
496 +{
497 +       struct spi_nand *snand = spi_get_drvdata(spi);
498 +
499 +       spi_nand_unregister(snand);
500 +
501 +       return 0;
502 +}
503 +
504 +const struct spi_device_id spi_nand_id_table[] = {
505 +       { "spi-nand", SPI_NAND_GENERIC },
506 +       { "gd5f", SPI_NAND_GD5F },
507 +       { },
508 +};
509 +MODULE_DEVICE_TABLE(spi, spi_nand_id_table);
510 +
511 +static struct spi_driver spi_nand_device_driver = {
512 +       .driver = {
513 +               .name   = "spi_nand_device",
514 +               .owner  = THIS_MODULE,
515 +       },
516 +       .id_table = spi_nand_id_table,
517 +       .probe  = spi_nand_device_probe,
518 +       .remove = spi_nand_device_remove,
519 +};
520 +module_spi_driver(spi_nand_device_driver);
521 +
522 +MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@imgtec.com>");
523 +MODULE_DESCRIPTION("SPI NAND device support");
524 +MODULE_LICENSE("GPL v2");