brcm2708: switch to linux 4.4 and update patches
[openwrt.git] / target / linux / brcm2708 / patches-4.1 / 0190-Add-SMI-NAND-driver.patch
1 From 157d840faf0595aadf6b3c483cbed19bbeb462ea Mon Sep 17 00:00:00 2001
2 From: Luke Wren <wren6991@gmail.com>
3 Date: Sat, 5 Sep 2015 01:16:10 +0100
4 Subject: [PATCH 190/222] Add SMI NAND driver
5
6 Signed-off-by: Luke Wren <wren6991@gmail.com>
7 ---
8  .../bindings/mtd/brcm,bcm2835-smi-nand.txt         |  42 ++++
9  arch/arm/boot/dts/overlays/Makefile                |   1 +
10  arch/arm/boot/dts/overlays/smi-nand-overlay.dts    |  69 ++++++
11  arch/arm/configs/bcm2709_defconfig                 |   7 +
12  arch/arm/configs/bcmrpi_defconfig                  |   7 +
13  drivers/mtd/nand/Kconfig                           |   7 +
14  drivers/mtd/nand/Makefile                          |   1 +
15  drivers/mtd/nand/bcm2835_smi_nand.c                | 268 +++++++++++++++++++++
16  8 files changed, 402 insertions(+)
17  create mode 100644 Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
18  create mode 100644 arch/arm/boot/dts/overlays/smi-nand-overlay.dts
19  create mode 100644 drivers/mtd/nand/bcm2835_smi_nand.c
20
21 --- /dev/null
22 +++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
23 @@ -0,0 +1,42 @@
24 +* BCM2835 SMI NAND flash
25 +
26 +This driver is a shim between the BCM2835 SMI driver (SMI is a peripheral for
27 +talking to parallel register interfaces) and Linux's MTD layer.
28 +
29 +Required properties:
30 +- compatible: "brcm,bcm2835-smi-nand"
31 +- status: "okay"
32 +
33 +Optional properties:
34 +- partition@n, where n is an integer from a consecutive sequence starting at 0
35 +       - Difficult to store partition table on NAND device - normally put it
36 +       in the source code, kernel bootparams, or device tree (the best way!)
37 +       - Sub-properties:
38 +               - label: the partition name, as shown by mtdinfo /dev/mtd*
39 +               - reg: the size and offset of this partition.
40 +               - (optional) read-only: an empty property flagging as read only
41 +
42 +Example:
43 +
44 +nand: flash@0 {
45 +       compatible = "brcm,bcm2835-smi-nand";
46 +       status = "okay";
47 +
48 +       partition@0 {
49 +               label = "stage2";
50 +               // 128k
51 +               reg = <0 0x20000>;
52 +               read-only;
53 +       };
54 +       partition@1 {
55 +               label = "firmware";
56 +               // 16M
57 +               reg = <0x20000 0x1000000>;
58 +               read-only;
59 +       };
60 +       partition@2 {
61 +               label = "root";
62 +               // 2G
63 +               reg = <0x1020000 0x80000000>;
64 +       };
65 +};
66 \ No newline at end of file
67 --- a/arch/arm/boot/dts/overlays/Makefile
68 +++ b/arch/arm/boot/dts/overlays/Makefile
69 @@ -15,6 +15,7 @@ endif
70  dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
71  dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
72  dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
73 +dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
74  dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
75  dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
76  dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
77 --- /dev/null
78 +++ b/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
79 @@ -0,0 +1,69 @@
80 +// Description: Overlay to enable NAND flash through
81 +// the secondary memory interface
82 +// Author:     Luke Wren
83 +
84 +/dts-v1/;
85 +/plugin/;
86 +
87 +/{
88 +       compatible = "brcm,bcm2708";
89 +
90 +       fragment@0 {
91 +               target = <&smi>;
92 +               __overlay__ {
93 +                       pinctrl-names = "default";
94 +                       pinctrl-0 = <&smi_pins>;
95 +                       status = "okay";
96 +               };
97 +       };
98 +
99 +       fragment@1 {
100 +               target = <&soc>;
101 +               __overlay__ {
102 +                       #address-cells = <1>;
103 +                       #size-cells = <1>;
104 +
105 +                       nand: flash@0 {
106 +                               compatible = "brcm,bcm2835-smi-nand";
107 +                               smi_handle = <&smi>;
108 +                               #address-cells = <1>;
109 +                               #size-cells = <1>;
110 +                               status = "okay";
111 +
112 +                               partition@0 {
113 +                                       label = "stage2";
114 +                                       // 128k
115 +                                       reg = <0 0x20000>;
116 +                                       read-only;
117 +                               };
118 +                               partition@1 {
119 +                                       label = "firmware";
120 +                                       // 16M
121 +                                       reg = <0x20000 0x1000000>;
122 +                                       read-only;
123 +                               };
124 +                               partition@2 {
125 +                                       label = "root";
126 +                                       // 2G (will need to use 64 bit for >=4G)
127 +                                       reg = <0x1020000 0x80000000>;
128 +                               };
129 +                       };
130 +               };
131 +       };
132 +
133 +       fragment@2 {
134 +               target = <&gpio>;
135 +               __overlay__ {
136 +                       smi_pins: smi_pins {
137 +                               brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
138 +                                       12 13 14 15>;
139 +                               /* Alt 1: SMI */
140 +                               brcm,function = <5 5 5 5 5 5 5 5 5 5 5
141 +                                       5 5 5 5 5>;
142 +                               /* /CS, /WE and /OE are pulled high, as they are
143 +                                  generally active low signals */
144 +                               brcm,pull = <2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
145 +                       };
146 +               };
147 +       };
148 +};
149 --- a/arch/arm/configs/bcm2709_defconfig
150 +++ b/arch/arm/configs/bcm2709_defconfig
151 @@ -392,6 +392,10 @@ CONFIG_DEVTMPFS=y
152  CONFIG_DEVTMPFS_MOUNT=y
153  CONFIG_DMA_CMA=y
154  CONFIG_CMA_SIZE_MBYTES=5
155 +CONFIG_MTD=m
156 +CONFIG_MTD_BLOCK=m
157 +CONFIG_MTD_NAND=m
158 +CONFIG_MTD_UBI=m
159  CONFIG_ZRAM=m
160  CONFIG_ZRAM_LZ4_COMPRESS=y
161  CONFIG_BLK_DEV_LOOP=y
162 @@ -1140,6 +1144,9 @@ CONFIG_CONFIGFS_FS=y
163  CONFIG_ECRYPT_FS=m
164  CONFIG_HFS_FS=m
165  CONFIG_HFSPLUS_FS=m
166 +CONFIG_JFFS2_FS=m
167 +CONFIG_JFFS2_SUMMARY=y
168 +CONFIG_UBIFS_FS=m
169  CONFIG_SQUASHFS=m
170  CONFIG_SQUASHFS_XATTR=y
171  CONFIG_SQUASHFS_LZO=y
172 --- a/arch/arm/configs/bcmrpi_defconfig
173 +++ b/arch/arm/configs/bcmrpi_defconfig
174 @@ -385,6 +385,10 @@ CONFIG_DEVTMPFS=y
175  CONFIG_DEVTMPFS_MOUNT=y
176  CONFIG_DMA_CMA=y
177  CONFIG_CMA_SIZE_MBYTES=5
178 +CONFIG_MTD=m
179 +CONFIG_MTD_BLOCK=m
180 +CONFIG_MTD_NAND=m
181 +CONFIG_MTD_UBI=m
182  CONFIG_ZRAM=m
183  CONFIG_ZRAM_LZ4_COMPRESS=y
184  CONFIG_BLK_DEV_LOOP=y
185 @@ -1133,6 +1137,9 @@ CONFIG_CONFIGFS_FS=y
186  CONFIG_ECRYPT_FS=m
187  CONFIG_HFS_FS=m
188  CONFIG_HFSPLUS_FS=m
189 +CONFIG_JFFS2_FS=m
190 +CONFIG_JFFS2_SUMMARY=y
191 +CONFIG_UBIFS_FS=m
192  CONFIG_SQUASHFS=m
193  CONFIG_SQUASHFS_XATTR=y
194  CONFIG_SQUASHFS_LZO=y
195 --- a/drivers/mtd/nand/Kconfig
196 +++ b/drivers/mtd/nand/Kconfig
197 @@ -41,6 +41,13 @@ config MTD_SM_COMMON
198         tristate
199         default n
200  
201 +config MTD_NAND_BCM2835_SMI
202 +        tristate "Use Broadcom's Secondary Memory Interface as a NAND controller (BCM283x)"
203 +        depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI && MTD_NAND
204 +        default m
205 +        help
206 +         Uses the BCM2835's SMI peripheral as a NAND controller.
207 +
208  config MTD_NAND_DENALI
209          tristate "Support Denali NAND controller"
210          depends on HAS_DMA
211 --- a/drivers/mtd/nand/Makefile
212 +++ b/drivers/mtd/nand/Makefile
213 @@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_DENALI)         += denali
214  obj-$(CONFIG_MTD_NAND_DENALI_PCI)      += denali_pci.o
215  obj-$(CONFIG_MTD_NAND_DENALI_DT)       += denali_dt.o
216  obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
217 +obj-$(CONFIG_MTD_NAND_BCM2835_SMI)     += bcm2835_smi_nand.o
218  obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
219  obj-$(CONFIG_MTD_NAND_S3C2410)         += s3c2410.o
220  obj-$(CONFIG_MTD_NAND_DAVINCI)         += davinci_nand.o
221 --- /dev/null
222 +++ b/drivers/mtd/nand/bcm2835_smi_nand.c
223 @@ -0,0 +1,268 @@
224 +/**
225 + * NAND flash driver for Broadcom Secondary Memory Interface
226 + *
227 + * Written by Luke Wren <luke@raspberrypi.org>
228 + * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
229 + *
230 + * Redistribution and use in source and binary forms, with or without
231 + * modification, are permitted provided that the following conditions
232 + * are met:
233 + * 1. Redistributions of source code must retain the above copyright
234 + *    notice, this list of conditions, and the following disclaimer,
235 + *    without modification.
236 + * 2. Redistributions in binary form must reproduce the above copyright
237 + *    notice, this list of conditions and the following disclaimer in the
238 + *    documentation and/or other materials provided with the distribution.
239 + * 3. The names of the above-listed copyright holders may not be used
240 + *    to endorse or promote products derived from this software without
241 + *    specific prior written permission.
242 + *
243 + * ALTERNATIVELY, this software may be distributed under the terms of the
244 + * GNU General Public License ("GPL") version 2, as published by the Free
245 + * Software Foundation.
246 + *
247 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
248 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
249 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
250 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
251 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
252 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
253 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
254 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
255 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
256 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
257 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258 + */
259 +
260 +#include <linux/kernel.h>
261 +#include <linux/module.h>
262 +#include <linux/of.h>
263 +#include <linux/platform_device.h>
264 +#include <linux/slab.h>
265 +#include <linux/mtd/nand.h>
266 +#include <linux/mtd/partitions.h>
267 +
268 +#include <linux/broadcom/bcm2835_smi.h>
269 +
270 +#define DEVICE_NAME "bcm2835-smi-nand"
271 +#define DRIVER_NAME "smi-nand-bcm2835"
272 +
273 +struct bcm2835_smi_nand_host {
274 +       struct bcm2835_smi_instance *smi_inst;
275 +       struct nand_chip nand_chip;
276 +       struct mtd_info mtd;
277 +       struct device *dev;
278 +};
279 +
280 +/****************************************************************************
281 +*
282 +*   NAND functionality implementation
283 +*
284 +****************************************************************************/
285 +
286 +#define SMI_NAND_CLE_PIN 0x01
287 +#define SMI_NAND_ALE_PIN 0x02
288 +
289 +static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
290 +                                            unsigned int ctrl)
291 +{
292 +       uint32_t cmd32 = cmd;
293 +       uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
294 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
295 +       struct bcm2835_smi_instance *inst = host->smi_inst;
296 +
297 +       if (ctrl & NAND_CLE)
298 +               addr |= SMI_NAND_CLE_PIN;
299 +       if (ctrl & NAND_ALE)
300 +               addr |= SMI_NAND_ALE_PIN;
301 +       /* Lower ALL the CS pins! */
302 +       if (ctrl & NAND_NCE)
303 +               addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
304 +
305 +       bcm2835_smi_set_address(inst, addr);
306 +
307 +       if (cmd != NAND_CMD_NONE)
308 +               bcm2835_smi_write_buf(inst, &cmd32, 1);
309 +}
310 +
311 +static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
312 +{
313 +       uint8_t byte;
314 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
315 +       struct bcm2835_smi_instance *inst = host->smi_inst;
316 +
317 +       bcm2835_smi_read_buf(inst, &byte, 1);
318 +       return byte;
319 +}
320 +
321 +static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
322 +                                              uint8_t byte)
323 +{
324 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
325 +       struct bcm2835_smi_instance *inst = host->smi_inst;
326 +
327 +       bcm2835_smi_write_buf(inst, &byte, 1);
328 +}
329 +
330 +static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
331 +                                             const uint8_t *buf, int len)
332 +{
333 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
334 +       struct bcm2835_smi_instance *inst = host->smi_inst;
335 +
336 +       bcm2835_smi_write_buf(inst, buf, len);
337 +}
338 +
339 +static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
340 +                                            uint8_t *buf, int len)
341 +{
342 +       struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
343 +       struct bcm2835_smi_instance *inst = host->smi_inst;
344 +
345 +       bcm2835_smi_read_buf(inst, buf, len);
346 +}
347 +
348 +/****************************************************************************
349 +*
350 +*   Probe and remove functions
351 +*
352 +***************************************************************************/
353 +
354 +static int bcm2835_smi_nand_probe(struct platform_device *pdev)
355 +{
356 +       struct bcm2835_smi_nand_host *host;
357 +       struct nand_chip *this;
358 +       struct mtd_info *mtd;
359 +       struct device *dev = &pdev->dev;
360 +       struct device_node *node = dev->of_node, *smi_node;
361 +       struct mtd_part_parser_data ppdata;
362 +       struct smi_settings *smi_settings;
363 +       struct bcm2835_smi_instance *smi_inst;
364 +       int ret = -ENXIO;
365 +
366 +       if (!node) {
367 +               dev_err(dev, "No device tree node supplied!");
368 +               return -EINVAL;
369 +       }
370 +
371 +       smi_node = of_parse_phandle(node, "smi_handle", 0);
372 +
373 +       /* Request use of SMI peripheral: */
374 +       smi_inst = bcm2835_smi_get(smi_node);
375 +
376 +       if (!smi_inst) {
377 +               dev_err(dev, "Could not register with SMI.");
378 +               return -EPROBE_DEFER;
379 +       }
380 +
381 +       /* Set SMI timing and bus width */
382 +
383 +       smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
384 +
385 +       smi_settings->data_width = SMI_WIDTH_8BIT;
386 +       smi_settings->read_setup_time = 2;
387 +       smi_settings->read_hold_time = 1;
388 +       smi_settings->read_pace_time = 1;
389 +       smi_settings->read_strobe_time = 3;
390 +
391 +       smi_settings->write_setup_time = 2;
392 +       smi_settings->write_hold_time = 1;
393 +       smi_settings->write_pace_time = 1;
394 +       smi_settings->write_strobe_time = 3;
395 +
396 +       bcm2835_smi_set_regs_from_settings(smi_inst);
397 +
398 +       host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
399 +               GFP_KERNEL);
400 +       if (!host)
401 +               return -ENOMEM;
402 +
403 +       host->dev = dev;
404 +       host->smi_inst = smi_inst;
405 +
406 +       platform_set_drvdata(pdev, host);
407 +
408 +       /* Link the structures together */
409 +
410 +       this = &host->nand_chip;
411 +       mtd = &host->mtd;
412 +       mtd->priv = this;
413 +       mtd->owner = THIS_MODULE;
414 +       mtd->dev.parent = dev;
415 +       mtd->name = DRIVER_NAME;
416 +       ppdata.of_node = node;
417 +
418 +       /* 20 us command delay time... */
419 +       this->chip_delay = 20;
420 +
421 +       this->priv = host;
422 +       this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
423 +       this->read_byte = bcm2835_smi_nand_read_byte;
424 +       this->write_byte = bcm2835_smi_nand_write_byte;
425 +       this->write_buf = bcm2835_smi_nand_write_buf;
426 +       this->read_buf = bcm2835_smi_nand_read_buf;
427 +
428 +       this->ecc.mode = NAND_ECC_SOFT;
429 +
430 +       /* Should never be accessed directly: */
431 +
432 +       this->IO_ADDR_R = (void *)0xdeadbeef;
433 +       this->IO_ADDR_W = (void *)0xdeadbeef;
434 +
435 +       /* First scan to find the device and get the page size */
436 +
437 +       if (nand_scan_ident(mtd, 1, NULL))
438 +               return -ENXIO;
439 +
440 +       /* Second phase scan */
441 +
442 +       if (nand_scan_tail(mtd))
443 +               return -ENXIO;
444 +
445 +       ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
446 +       if (!ret)
447 +               return 0;
448 +
449 +       nand_release(mtd);
450 +       return -EINVAL;
451 +}
452 +
453 +static int bcm2835_smi_nand_remove(struct platform_device *pdev)
454 +{
455 +       struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
456 +
457 +       nand_release(&host->mtd);
458 +
459 +       return 0;
460 +}
461 +
462 +/****************************************************************************
463 +*
464 +*   Register the driver with device tree
465 +*
466 +***************************************************************************/
467 +
468 +static const struct of_device_id bcm2835_smi_nand_of_match[] = {
469 +       {.compatible = "brcm,bcm2835-smi-nand",},
470 +       { /* sentinel */ }
471 +};
472 +
473 +MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
474 +
475 +static struct platform_driver bcm2835_smi_nand_driver = {
476 +       .probe = bcm2835_smi_nand_probe,
477 +       .remove = bcm2835_smi_nand_remove,
478 +       .driver = {
479 +               .name = DRIVER_NAME,
480 +               .owner = THIS_MODULE,
481 +               .of_match_table = bcm2835_smi_nand_of_match,
482 +       },
483 +};
484 +
485 +module_platform_driver(bcm2835_smi_nand_driver);
486 +
487 +MODULE_ALIAS("platform:smi-nand-bcm2835");
488 +MODULE_LICENSE("GPL");
489 +MODULE_DESCRIPTION
490 +       ("Driver for NAND chips using Broadcom Secondary Memory Interface");
491 +MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");