aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.1/0190-Add-SMI-NAND-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.1/0190-Add-SMI-NAND-driver.patch')
-rw-r--r--target/linux/brcm2708/patches-4.1/0190-Add-SMI-NAND-driver.patch491
1 files changed, 491 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.1/0190-Add-SMI-NAND-driver.patch b/target/linux/brcm2708/patches-4.1/0190-Add-SMI-NAND-driver.patch
new file mode 100644
index 0000000..c6b40aa
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.1/0190-Add-SMI-NAND-driver.patch
@@ -0,0 +1,491 @@
+From 3103b6c1b1a881e55421b7463fb76ad7bdf3974a Mon Sep 17 00:00:00 2001
+From: Luke Wren <wren6991@gmail.com>
+Date: Sat, 5 Sep 2015 01:16:10 +0100
+Subject: [PATCH 190/203] Add SMI NAND driver
+
+Signed-off-by: Luke Wren <wren6991@gmail.com>
+---
+ .../bindings/mtd/brcm,bcm2835-smi-nand.txt | 42 ++++
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/smi-nand-overlay.dts | 69 ++++++
+ arch/arm/configs/bcm2709_defconfig | 7 +
+ arch/arm/configs/bcmrpi_defconfig | 7 +
+ drivers/mtd/nand/Kconfig | 7 +
+ drivers/mtd/nand/Makefile | 1 +
+ drivers/mtd/nand/bcm2835_smi_nand.c | 268 +++++++++++++++++++++
+ 8 files changed, 402 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
+ create mode 100644 arch/arm/boot/dts/overlays/smi-nand-overlay.dts
+ create mode 100644 drivers/mtd/nand/bcm2835_smi_nand.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
+@@ -0,0 +1,42 @@
++* BCM2835 SMI NAND flash
++
++This driver is a shim between the BCM2835 SMI driver (SMI is a peripheral for
++talking to parallel register interfaces) and Linux's MTD layer.
++
++Required properties:
++- compatible: "brcm,bcm2835-smi-nand"
++- status: "okay"
++
++Optional properties:
++- partition@n, where n is an integer from a consecutive sequence starting at 0
++ - Difficult to store partition table on NAND device - normally put it
++ in the source code, kernel bootparams, or device tree (the best way!)
++ - Sub-properties:
++ - label: the partition name, as shown by mtdinfo /dev/mtd*
++ - reg: the size and offset of this partition.
++ - (optional) read-only: an empty property flagging as read only
++
++Example:
++
++nand: flash@0 {
++ compatible = "brcm,bcm2835-smi-nand";
++ status = "okay";
++
++ partition@0 {
++ label = "stage2";
++ // 128k
++ reg = <0 0x20000>;
++ read-only;
++ };
++ partition@1 {
++ label = "firmware";
++ // 16M
++ reg = <0x20000 0x1000000>;
++ read-only;
++ };
++ partition@2 {
++ label = "root";
++ // 2G
++ reg = <0x1020000 0x80000000>;
++ };
++};
+\ No newline at end of file
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,7 @@ endif
+ dtb-$(RPI_DT_OVERLAYS) += ads7846-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += smi-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += smi-dev-overlay.dtb
++dtb-$(RPI_DT_OVERLAYS) += smi-nand-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
+ dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/smi-nand-overlay.dts
+@@ -0,0 +1,69 @@
++// Description: Overlay to enable NAND flash through
++// the secondary memory interface
++// Author: Luke Wren
++
++/dts-v1/;
++/plugin/;
++
++/{
++ compatible = "brcm,bcm2708";
++
++ fragment@0 {
++ target = <&smi>;
++ __overlay__ {
++ pinctrl-names = "default";
++ pinctrl-0 = <&smi_pins>;
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&soc>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ nand: flash@0 {
++ compatible = "brcm,bcm2835-smi-nand";
++ smi_handle = <&smi>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ status = "okay";
++
++ partition@0 {
++ label = "stage2";
++ // 128k
++ reg = <0 0x20000>;
++ read-only;
++ };
++ partition@1 {
++ label = "firmware";
++ // 16M
++ reg = <0x20000 0x1000000>;
++ read-only;
++ };
++ partition@2 {
++ label = "root";
++ // 2G (will need to use 64 bit for >=4G)
++ reg = <0x1020000 0x80000000>;
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&gpio>;
++ __overlay__ {
++ smi_pins: smi_pins {
++ brcm,pins = <0 1 2 3 4 5 6 7 8 9 10 11
++ 12 13 14 15>;
++ /* Alt 1: SMI */
++ brcm,function = <5 5 5 5 5 5 5 5 5 5 5
++ 5 5 5 5 5>;
++ /* /CS, /WE and /OE are pulled high, as they are
++ generally active low signals */
++ brcm,pull = <2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0>;
++ };
++ };
++ };
++};
+--- a/arch/arm/configs/bcm2709_defconfig
++++ b/arch/arm/configs/bcm2709_defconfig
+@@ -392,6 +392,10 @@ CONFIG_DEVTMPFS=y
+ CONFIG_DEVTMPFS_MOUNT=y
+ CONFIG_DMA_CMA=y
+ CONFIG_CMA_SIZE_MBYTES=5
++CONFIG_MTD=m
++CONFIG_MTD_BLOCK=m
++CONFIG_MTD_NAND=m
++CONFIG_MTD_UBI=m
+ CONFIG_ZRAM=m
+ CONFIG_ZRAM_LZ4_COMPRESS=y
+ CONFIG_BLK_DEV_LOOP=y
+@@ -1140,6 +1144,9 @@ CONFIG_CONFIGFS_FS=y
+ CONFIG_ECRYPT_FS=m
+ CONFIG_HFS_FS=m
+ CONFIG_HFSPLUS_FS=m
++CONFIG_JFFS2_FS=m
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_UBIFS_FS=m
+ CONFIG_SQUASHFS=m
+ CONFIG_SQUASHFS_XATTR=y
+ CONFIG_SQUASHFS_LZO=y
+--- a/arch/arm/configs/bcmrpi_defconfig
++++ b/arch/arm/configs/bcmrpi_defconfig
+@@ -385,6 +385,10 @@ CONFIG_DEVTMPFS=y
+ CONFIG_DEVTMPFS_MOUNT=y
+ CONFIG_DMA_CMA=y
+ CONFIG_CMA_SIZE_MBYTES=5
++CONFIG_MTD=m
++CONFIG_MTD_BLOCK=m
++CONFIG_MTD_NAND=m
++CONFIG_MTD_UBI=m
+ CONFIG_ZRAM=m
+ CONFIG_ZRAM_LZ4_COMPRESS=y
+ CONFIG_BLK_DEV_LOOP=y
+@@ -1133,6 +1137,9 @@ CONFIG_CONFIGFS_FS=y
+ CONFIG_ECRYPT_FS=m
+ CONFIG_HFS_FS=m
+ CONFIG_HFSPLUS_FS=m
++CONFIG_JFFS2_FS=m
++CONFIG_JFFS2_SUMMARY=y
++CONFIG_UBIFS_FS=m
+ CONFIG_SQUASHFS=m
+ CONFIG_SQUASHFS_XATTR=y
+ CONFIG_SQUASHFS_LZO=y
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -41,6 +41,13 @@ config MTD_SM_COMMON
+ tristate
+ default n
+
++config MTD_NAND_BCM2835_SMI
++ tristate "Use Broadcom's Secondary Memory Interface as a NAND controller (BCM283x)"
++ depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI && MTD_NAND
++ default m
++ help
++ Uses the BCM2835's SMI peripheral as a NAND controller.
++
+ config MTD_NAND_DENALI
+ tristate "Support Denali NAND controller"
+ depends on HAS_DMA
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_DENALI) += denali
+ obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
+ obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
+ obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
++obj-$(CONFIG_MTD_NAND_BCM2835_SMI) += bcm2835_smi_nand.o
+ obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
+ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
+ obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
+--- /dev/null
++++ b/drivers/mtd/nand/bcm2835_smi_nand.c
+@@ -0,0 +1,268 @@
++/**
++ * NAND flash driver for Broadcom Secondary Memory Interface
++ *
++ * Written by Luke Wren <luke@raspberrypi.org>
++ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions, and the following disclaimer,
++ * without modification.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ * 3. The names of the above-listed copyright holders may not be used
++ * to endorse or promote products derived from this software without
++ * specific prior written permission.
++ *
++ * ALTERNATIVELY, this software may be distributed under the terms of the
++ * GNU General Public License ("GPL") version 2, as published by the Free
++ * Software Foundation.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
++ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++
++#include <linux/broadcom/bcm2835_smi.h>
++
++#define DEVICE_NAME "bcm2835-smi-nand"
++#define DRIVER_NAME "smi-nand-bcm2835"
++
++struct bcm2835_smi_nand_host {
++ struct bcm2835_smi_instance *smi_inst;
++ struct nand_chip nand_chip;
++ struct mtd_info mtd;
++ struct device *dev;
++};
++
++/****************************************************************************
++*
++* NAND functionality implementation
++*
++****************************************************************************/
++
++#define SMI_NAND_CLE_PIN 0x01
++#define SMI_NAND_ALE_PIN 0x02
++
++static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++ unsigned int ctrl)
++{
++ uint32_t cmd32 = cmd;
++ uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ if (ctrl & NAND_CLE)
++ addr |= SMI_NAND_CLE_PIN;
++ if (ctrl & NAND_ALE)
++ addr |= SMI_NAND_ALE_PIN;
++ /* Lower ALL the CS pins! */
++ if (ctrl & NAND_NCE)
++ addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
++
++ bcm2835_smi_set_address(inst, addr);
++
++ if (cmd != NAND_CMD_NONE)
++ bcm2835_smi_write_buf(inst, &cmd32, 1);
++}
++
++static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
++{
++ uint8_t byte;
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_read_buf(inst, &byte, 1);
++ return byte;
++}
++
++static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
++ uint8_t byte)
++{
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_write_buf(inst, &byte, 1);
++}
++
++static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
++ const uint8_t *buf, int len)
++{
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_write_buf(inst, buf, len);
++}
++
++static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
++ uint8_t *buf, int len)
++{
++ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
++ struct bcm2835_smi_instance *inst = host->smi_inst;
++
++ bcm2835_smi_read_buf(inst, buf, len);
++}
++
++/****************************************************************************
++*
++* Probe and remove functions
++*
++***************************************************************************/
++
++static int bcm2835_smi_nand_probe(struct platform_device *pdev)
++{
++ struct bcm2835_smi_nand_host *host;
++ struct nand_chip *this;
++ struct mtd_info *mtd;
++ struct device *dev = &pdev->dev;
++ struct device_node *node = dev->of_node, *smi_node;
++ struct mtd_part_parser_data ppdata;
++ struct smi_settings *smi_settings;
++ struct bcm2835_smi_instance *smi_inst;
++ int ret = -ENXIO;
++
++ if (!node) {
++ dev_err(dev, "No device tree node supplied!");
++ return -EINVAL;
++ }
++
++ smi_node = of_parse_phandle(node, "smi_handle", 0);
++
++ /* Request use of SMI peripheral: */
++ smi_inst = bcm2835_smi_get(smi_node);
++
++ if (!smi_inst) {
++ dev_err(dev, "Could not register with SMI.");
++ return -EPROBE_DEFER;
++ }
++
++ /* Set SMI timing and bus width */
++
++ smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
++
++ smi_settings->data_width = SMI_WIDTH_8BIT;
++ smi_settings->read_setup_time = 2;
++ smi_settings->read_hold_time = 1;
++ smi_settings->read_pace_time = 1;
++ smi_settings->read_strobe_time = 3;
++
++ smi_settings->write_setup_time = 2;
++ smi_settings->write_hold_time = 1;
++ smi_settings->write_pace_time = 1;
++ smi_settings->write_strobe_time = 3;
++
++ bcm2835_smi_set_regs_from_settings(smi_inst);
++
++ host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
++ GFP_KERNEL);
++ if (!host)
++ return -ENOMEM;
++
++ host->dev = dev;
++ host->smi_inst = smi_inst;
++
++ platform_set_drvdata(pdev, host);
++
++ /* Link the structures together */
++
++ this = &host->nand_chip;
++ mtd = &host->mtd;
++ mtd->priv = this;
++ mtd->owner = THIS_MODULE;
++ mtd->dev.parent = dev;
++ mtd->name = DRIVER_NAME;
++ ppdata.of_node = node;
++
++ /* 20 us command delay time... */
++ this->chip_delay = 20;
++
++ this->priv = host;
++ this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
++ this->read_byte = bcm2835_smi_nand_read_byte;
++ this->write_byte = bcm2835_smi_nand_write_byte;
++ this->write_buf = bcm2835_smi_nand_write_buf;
++ this->read_buf = bcm2835_smi_nand_read_buf;
++
++ this->ecc.mode = NAND_ECC_SOFT;
++
++ /* Should never be accessed directly: */
++
++ this->IO_ADDR_R = (void *)0xdeadbeef;
++ this->IO_ADDR_W = (void *)0xdeadbeef;
++
++ /* First scan to find the device and get the page size */
++
++ if (nand_scan_ident(mtd, 1, NULL))
++ return -ENXIO;
++
++ /* Second phase scan */
++
++ if (nand_scan_tail(mtd))
++ return -ENXIO;
++
++ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
++ if (!ret)
++ return 0;
++
++ nand_release(mtd);
++ return -EINVAL;
++}
++
++static int bcm2835_smi_nand_remove(struct platform_device *pdev)
++{
++ struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
++
++ nand_release(&host->mtd);
++
++ return 0;
++}
++
++/****************************************************************************
++*
++* Register the driver with device tree
++*
++***************************************************************************/
++
++static const struct of_device_id bcm2835_smi_nand_of_match[] = {
++ {.compatible = "brcm,bcm2835-smi-nand",},
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
++
++static struct platform_driver bcm2835_smi_nand_driver = {
++ .probe = bcm2835_smi_nand_probe,
++ .remove = bcm2835_smi_nand_remove,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = bcm2835_smi_nand_of_match,
++ },
++};
++
++module_platform_driver(bcm2835_smi_nand_driver);
++
++MODULE_ALIAS("platform:smi-nand-bcm2835");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION
++ ("Driver for NAND chips using Broadcom Secondary Memory Interface");
++MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");