diff options
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.patch | 280 |
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); |