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
6 Signed-off-by: Luke Wren <wren6991@gmail.com>
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
22 +++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
24 +* BCM2835 SMI NAND flash
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.
30 +- compatible: "brcm,bcm2835-smi-nand"
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!)
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
45 + compatible = "brcm,bcm2835-smi-nand";
57 + reg = <0x20000 0x1000000>;
63 + reg = <0x1020000 0x80000000>;
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
78 +++ b/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
80 +// Description: Overlay to enable NAND flash through
81 +// the secondary memory interface
88 + compatible = "brcm,bcm2708";
93 + pinctrl-names = "default";
94 + pinctrl-0 = <&smi_pins>;
102 + #address-cells = <1>;
106 + compatible = "brcm,bcm2835-smi-nand";
107 + smi_handle = <&smi>;
108 + #address-cells = <1>;
119 + label = "firmware";
121 + reg = <0x20000 0x1000000>;
126 + // 2G (will need to use 64 bit for >=4G)
127 + reg = <0x1020000 0x80000000>;
136 + smi_pins: smi_pins {
137 + brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
140 + brcm,function = <5 5 5 5 5 5 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>;
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
154 CONFIG_CMA_SIZE_MBYTES=5
160 CONFIG_ZRAM_LZ4_COMPRESS=y
161 CONFIG_BLK_DEV_LOOP=y
162 @@ -1140,6 +1144,9 @@ CONFIG_CONFIGFS_FS=y
167 +CONFIG_JFFS2_SUMMARY=y
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
177 CONFIG_CMA_SIZE_MBYTES=5
183 CONFIG_ZRAM_LZ4_COMPRESS=y
184 CONFIG_BLK_DEV_LOOP=y
185 @@ -1133,6 +1137,9 @@ CONFIG_CONFIGFS_FS=y
190 +CONFIG_JFFS2_SUMMARY=y
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
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
206 + Uses the BCM2835's SMI peripheral as a NAND controller.
208 config MTD_NAND_DENALI
209 tristate "Support Denali NAND controller"
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
222 +++ b/drivers/mtd/nand/bcm2835_smi_nand.c
225 + * NAND flash driver for Broadcom Secondary Memory Interface
227 + * Written by Luke Wren <luke@raspberrypi.org>
228 + * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
230 + * Redistribution and use in source and binary forms, with or without
231 + * modification, are permitted provided that the following conditions
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.
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.
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.
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>
268 +#include <linux/broadcom/bcm2835_smi.h>
270 +#define DEVICE_NAME "bcm2835-smi-nand"
271 +#define DRIVER_NAME "smi-nand-bcm2835"
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;
280 +/****************************************************************************
282 +* NAND functionality implementation
284 +****************************************************************************/
286 +#define SMI_NAND_CLE_PIN 0x01
287 +#define SMI_NAND_ALE_PIN 0x02
289 +static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
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;
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);
305 + bcm2835_smi_set_address(inst, addr);
307 + if (cmd != NAND_CMD_NONE)
308 + bcm2835_smi_write_buf(inst, &cmd32, 1);
311 +static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
314 + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
315 + struct bcm2835_smi_instance *inst = host->smi_inst;
317 + bcm2835_smi_read_buf(inst, &byte, 1);
321 +static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
324 + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
325 + struct bcm2835_smi_instance *inst = host->smi_inst;
327 + bcm2835_smi_write_buf(inst, &byte, 1);
330 +static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
331 + const uint8_t *buf, int len)
333 + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
334 + struct bcm2835_smi_instance *inst = host->smi_inst;
336 + bcm2835_smi_write_buf(inst, buf, len);
339 +static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
340 + uint8_t *buf, int len)
342 + struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
343 + struct bcm2835_smi_instance *inst = host->smi_inst;
345 + bcm2835_smi_read_buf(inst, buf, len);
348 +/****************************************************************************
350 +* Probe and remove functions
352 +***************************************************************************/
354 +static int bcm2835_smi_nand_probe(struct platform_device *pdev)
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;
367 + dev_err(dev, "No device tree node supplied!");
371 + smi_node = of_parse_phandle(node, "smi_handle", 0);
373 + /* Request use of SMI peripheral: */
374 + smi_inst = bcm2835_smi_get(smi_node);
377 + dev_err(dev, "Could not register with SMI.");
378 + return -EPROBE_DEFER;
381 + /* Set SMI timing and bus width */
383 + smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
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;
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;
396 + bcm2835_smi_set_regs_from_settings(smi_inst);
398 + host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
404 + host->smi_inst = smi_inst;
406 + platform_set_drvdata(pdev, host);
408 + /* Link the structures together */
410 + this = &host->nand_chip;
413 + mtd->owner = THIS_MODULE;
414 + mtd->dev.parent = dev;
415 + mtd->name = DRIVER_NAME;
416 + ppdata.of_node = node;
418 + /* 20 us command delay time... */
419 + this->chip_delay = 20;
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;
428 + this->ecc.mode = NAND_ECC_SOFT;
430 + /* Should never be accessed directly: */
432 + this->IO_ADDR_R = (void *)0xdeadbeef;
433 + this->IO_ADDR_W = (void *)0xdeadbeef;
435 + /* First scan to find the device and get the page size */
437 + if (nand_scan_ident(mtd, 1, NULL))
440 + /* Second phase scan */
442 + if (nand_scan_tail(mtd))
445 + ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
453 +static int bcm2835_smi_nand_remove(struct platform_device *pdev)
455 + struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
457 + nand_release(&host->mtd);
462 +/****************************************************************************
464 +* Register the driver with device tree
466 +***************************************************************************/
468 +static const struct of_device_id bcm2835_smi_nand_of_match[] = {
469 + {.compatible = "brcm,bcm2835-smi-nand",},
473 +MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
475 +static struct platform_driver bcm2835_smi_nand_driver = {
476 + .probe = bcm2835_smi_nand_probe,
477 + .remove = bcm2835_smi_nand_remove,
479 + .name = DRIVER_NAME,
480 + .owner = THIS_MODULE,
481 + .of_match_table = bcm2835_smi_nand_of_match,
485 +module_platform_driver(bcm2835_smi_nand_driver);
487 +MODULE_ALIAS("platform:smi-nand-bcm2835");
488 +MODULE_LICENSE("GPL");
490 + ("Driver for NAND chips using Broadcom Secondary Memory Interface");
491 +MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");