aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mpc83xx/patches-3.14/203-mtd-add-rbppc_nand-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mpc83xx/patches-3.14/203-mtd-add-rbppc_nand-driver.patch')
-rw-r--r--target/linux/mpc83xx/patches-3.14/203-mtd-add-rbppc_nand-driver.patch280
1 files changed, 280 insertions, 0 deletions
diff --git a/target/linux/mpc83xx/patches-3.14/203-mtd-add-rbppc_nand-driver.patch b/target/linux/mpc83xx/patches-3.14/203-mtd-add-rbppc_nand-driver.patch
new file mode 100644
index 0000000000..d005637576
--- /dev/null
+++ b/target/linux/mpc83xx/patches-3.14/203-mtd-add-rbppc_nand-driver.patch
@@ -0,0 +1,280 @@
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -405,6 +405,13 @@ config MTD_NAND_PLATFORM
+ devices. You will need to provide platform-specific functions
+ via platform_data.
+
++config MTD_NAND_RB_PPC
++ tristate "MikroTik RB333/600 NAND support"
++ depends on RB_PPC
++ help
++ This option enables support for the NAND device on MikroTik
++ RouterBOARD 333/600 series boards.
++
+ config MTD_NAND_ORION
+ tristate "NAND Flash support for Marvell Orion SoC"
+ depends on PLAT_ORION
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -31,6 +31,7 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx27
+ obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
+ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
++obj-$(CONFIG_MTD_NAND_RB_PPC) += rbppc_nand.o
+ obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
+ obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
+ obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
+--- /dev/null
++++ b/drivers/mtd/nand/rbppc_nand.c
+@@ -0,0 +1,251 @@
++/*
++ * Copyright (C) 2008-2009 Noah Fontes <nfontes@transtruct.org>
++ * Copyright (C) 2009 Michael Guntsche <mike@it-loops.com>
++ * Copyright (C) Mikrotik 2007
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of_platform.h>
++#include <linux/of_device.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/of_address.h>
++#include <asm/io.h>
++
++#define DRV_NAME "rbppc_nand"
++#define DRV_VERSION "0.0.2"
++
++static struct mtd_info rmtd;
++static struct nand_chip rnand;
++
++struct rbppc_nand_info {
++ void *gpi;
++ void *gpo;
++ void *localbus;
++
++ unsigned gpio_rdy;
++ unsigned gpio_nce;
++ unsigned gpio_cle;
++ unsigned gpio_ale;
++ unsigned gpio_ctrls;
++};
++
++/* We must use the OOB layout from yaffs 1 if we want this to be recognized
++ * properly. Borrowed from the OpenWRT patches for the RB532.
++ *
++ * See <https://dev.openwrt.org/browser/trunk/target/linux/rb532/
++ * patches-2.6.28/025-rb532_nand_fixup.patch> for more details.
++ */
++static struct nand_ecclayout rbppc_nand_oob_16 = {
++ .eccbytes = 6,
++ .eccpos = { 8, 9, 10, 13, 14, 15 },
++ .oobavail = 9,
++ .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
++};
++
++static struct mtd_partition rbppc_nand_partition_info[] = {
++ {
++ name: "kernel",
++ offset: 0,
++ size: 4 * 1024 * 1024,
++ },
++ {
++ name: "rootfs",
++ offset: MTDPART_OFS_NXTBLK,
++ size: MTDPART_SIZ_FULL,
++ },
++};
++
++static int rbppc_nand_dev_ready(struct mtd_info *mtd) {
++ struct nand_chip *chip = mtd->priv;
++ struct rbppc_nand_info *priv = chip->priv;
++
++ return in_be32(priv->gpi) & priv->gpio_rdy;
++}
++
++static void rbppc_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) {
++ struct nand_chip *chip = mtd->priv;
++ struct rbppc_nand_info *priv = chip->priv;
++
++ if (ctrl & NAND_CTRL_CHANGE) {
++ unsigned val = in_be32(priv->gpo);
++ if (!(val & priv->gpio_nce)) {
++ /* make sure Local Bus has done NAND operations */
++ readb(priv->localbus);
++ }
++
++ if (ctrl & NAND_CLE) {
++ val |= priv->gpio_cle;
++ } else {
++ val &= ~priv->gpio_cle;
++ }
++ if (ctrl & NAND_ALE) {
++ val |= priv->gpio_ale;
++ } else {
++ val &= ~priv->gpio_ale;
++ }
++ if (!(ctrl & NAND_NCE)) {
++ val |= priv->gpio_nce;
++ } else {
++ val &= ~priv->gpio_nce;
++ }
++ out_be32(priv->gpo, val);
++
++ /* make sure GPIO output has changed */
++ val ^= in_be32(priv->gpo);
++ if (val & priv->gpio_ctrls) {
++ printk(KERN_ERR "rbppc_nand_hwcontrol: NAND GPO change failed 0x%08x\n", val);
++ }
++ }
++
++ if (cmd != NAND_CMD_NONE) writeb(cmd, chip->IO_ADDR_W);
++}
++
++static void rbppc_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++ struct nand_chip *chip = mtd->priv;
++ memcpy(buf, chip->IO_ADDR_R, len);
++}
++
++static unsigned init_ok = 0;
++
++static int rbppc_nand_probe(struct platform_device *pdev)
++{
++ struct device_node *gpio;
++ struct device_node *nnand;
++ struct resource res;
++ struct rbppc_nand_info *info;
++ void *baddr;
++ const unsigned *rdy, *nce, *cle, *ale;
++
++ printk(KERN_INFO "rbppc_nand_probe: MikroTik RouterBOARD 333/600 series NAND driver, version " DRV_VERSION "\n");
++
++ info = kmalloc(sizeof(*info), GFP_KERNEL);
++
++ rdy = of_get_property(pdev->dev.of_node, "rdy", NULL);
++ nce = of_get_property(pdev->dev.of_node, "nce", NULL);
++ cle = of_get_property(pdev->dev.of_node, "cle", NULL);
++ ale = of_get_property(pdev->dev.of_node, "ale", NULL);
++
++ if (!rdy || !nce || !cle || !ale) {
++ printk(KERN_ERR "rbppc_nand_probe: GPIO properties are missing\n");
++ goto err;
++ }
++ if (rdy[0] != nce[0] || rdy[0] != cle[0] || rdy[0] != ale[0]) {
++ printk(KERN_ERR "rbppc_nand_probe: Different GPIOs are not supported\n");
++ goto err;
++ }
++
++ gpio = of_find_node_by_phandle(rdy[0]);
++ if (!gpio) {
++ printk(KERN_ERR "rbppc_nand_probe: No GPIO<%x> node found\n", *rdy);
++ goto err;
++ }
++ if (of_address_to_resource(gpio, 0, &res)) {
++ printk(KERN_ERR "rbppc_nand_probe: No reg property in GPIO found\n");
++ goto err;
++ }
++ info->gpo = ioremap_nocache(res.start, res.end - res.start + 1);
++
++ if (!of_address_to_resource(gpio, 1, &res)) {
++ info->gpi = ioremap_nocache(res.start, res.end - res.start + 1);
++ } else {
++ info->gpi = info->gpo;
++ }
++ of_node_put(gpio);
++
++ info->gpio_rdy = 1 << (31 - rdy[1]);
++ info->gpio_nce = 1 << (31 - nce[1]);
++ info->gpio_cle = 1 << (31 - cle[1]);
++ info->gpio_ale = 1 << (31 - ale[1]);
++ info->gpio_ctrls = info->gpio_nce | info->gpio_cle | info->gpio_ale;
++
++ nnand = of_find_node_by_name(NULL, "nnand");
++ if (!nnand) {
++ printk("rbppc_nand_probe: No nNAND found\n");
++ goto err;
++ }
++ if (of_address_to_resource(nnand, 0, &res)) {
++ printk("rbppc_nand_probe: No reg property in nNAND found\n");
++ goto err;
++ }
++ of_node_put(nnand);
++ info->localbus = ioremap_nocache(res.start, res.end - res.start + 1);
++
++ if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
++ printk("rbppc_nand_probe: No reg property found\n");
++ goto err;
++ }
++ baddr = ioremap_nocache(res.start, res.end - res.start + 1);
++
++ memset(&rnand, 0, sizeof(rnand));
++ rnand.cmd_ctrl = rbppc_nand_cmd_ctrl;
++ rnand.dev_ready = rbppc_nand_dev_ready;
++ rnand.read_buf = rbppc_nand_read_buf;
++ rnand.IO_ADDR_W = baddr;
++ rnand.IO_ADDR_R = baddr;
++ rnand.priv = info;
++
++ memset(&rmtd, 0, sizeof(rmtd));
++ rnand.ecc.mode = NAND_ECC_SOFT;
++ rnand.ecc.layout = &rbppc_nand_oob_16;
++ rnand.chip_delay = 25;
++ rmtd.priv = &rnand;
++ rmtd.owner = THIS_MODULE;
++
++ if (nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)) {
++ printk(KERN_ERR "rbppc_nand_probe: RouterBOARD NAND device not found\n");
++ return -ENXIO;
++ }
++
++ mtd_device_parse_register(&rmtd, NULL, 0, rbppc_nand_partition_info, 2);
++ init_ok = 1;
++ return 0;
++
++err:
++ kfree(info);
++ return -1;
++}
++
++static struct of_device_id rbppc_nand_ids[] = {
++ { .name = "nand", },
++ { },
++};
++
++static struct platform_driver rbppc_nand_driver = {
++ .probe = rbppc_nand_probe,
++ .driver = {
++ .name = "rbppc-nand",
++ .owner = THIS_MODULE,
++ .of_match_table = rbppc_nand_ids,
++ },
++};
++
++static int __init rbppc_nand_init(void)
++{
++ return platform_driver_register(&rbppc_nand_driver);
++}
++
++static void __exit rbppc_nand_exit(void)
++{
++ platform_driver_unregister(&rbppc_nand_driver);
++}
++
++MODULE_AUTHOR("Mikrotikls SIA");
++MODULE_AUTHOR("Noah Fontes");
++MODULE_AUTHOR("Michael Guntsche");
++MODULE_DESCRIPTION("MikroTik RouterBOARD 333/600 series NAND driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(rbppc_nand_init);
++module_exit(rbppc_nand_exit);