[PATCH 1/2] P4080/eLBC: Make Freescale elbc interrupt common to elbc devices
tiejun.chen
tiejun.chen at windriver.com
Mon Oct 18 04:55:49 EDT 2010
Roy Zang wrote:
> Move Freescale elbc interrupt from nand dirver to elbc driver.
> Then all elbc devices can use the interrupt instead of ONLY nand.
>
> For former nand driver, it had the two functions:
>
> 1. detecting nand flash partitions;
> 2. registering elbc interrupt.
>
> Now, second function is removed to fsl_lbc.c.
>
> Signed-off-by: Lan Chunhe-B25806 <b25806 at freescale.com>
> Signed-off-by: Roy Zang <tie-fei.zang at freescale.com>
> Reviewed-by: Anton Vorontsov <cbouatmailru at gmail.com>
> Cc: Wood Scott-B07421 <B07421 at freescale.com>
> ---
>
> These two patches are based on the following commits:
> 1. http://lists.infradead.org/pipermail/linux-mtd/2010-September/032112.html
> 2. http://lists.infradead.org/pipermail/linux-mtd/2010-September/032110.html
> 3. http://lists.infradead.org/pipermail/linux-mtd/2010-September/032111.html
> According to Anton's comment, I merge 1 & 2 together and start a new thread.
> Comparing the provided link:
> 1. Merge 1 & 2 together.
> 2. Some code style updates
> 3. Add counter protect for elbc driver remove
> 4. Rebase to 2.6.36-rc7
>
> Other histories from the links:
> V2: Comparing with v1, according to the feedback, add some decorations.
>
> V3: Comparing with v2:
> 1. according to the feedback, add some decorations.
> 2. change of_platform_driver to platform_driver
> 3. rebase to 2.6.36-rc4
>
> V4: Comparing with v3
> 1. minor fix from type unsigned int to u32
> 2. fix platform_driver issue.
> 3. add mutex for nand probe
>
> arch/powerpc/Kconfig | 7 +-
> arch/powerpc/include/asm/fsl_lbc.h | 33 +++-
> arch/powerpc/sysdev/fsl_lbc.c | 229 ++++++++++++++---
> drivers/mtd/nand/Kconfig | 1 +
> drivers/mtd/nand/fsl_elbc_nand.c | 482 +++++++++++++++---------------------
> 5 files changed, 425 insertions(+), 327 deletions(-)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 631e5a0..44df1ba 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -687,9 +687,12 @@ config 4xx_SOC
> bool
>
> config FSL_LBC
> - bool
> + bool "Freescale Local Bus support"
> + depends on FSL_SOC
> help
> - Freescale Localbus support
> + Enables reporting of errors from the Freescale local bus
> + controller. Also contains some common code used by
> + drivers for specific local bus peripherals.
>
> config FSL_GTM
> bool
> diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
> index 1b5a210..0c40c05 100644
> --- a/arch/powerpc/include/asm/fsl_lbc.h
> +++ b/arch/powerpc/include/asm/fsl_lbc.h
> @@ -1,9 +1,10 @@
> /* Freescale Local Bus Controller
> *
> - * Copyright (c) 2006-2007 Freescale Semiconductor
> + * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
> *
> * Authors: Nick Spence <nick.spence at freescale.com>,
> * Scott Wood <scottwood at freescale.com>
> + * Jack Lan <jack.lan at freescale.com>
> *
> * 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
> @@ -26,6 +27,8 @@
> #include <linux/compiler.h>
> #include <linux/types.h>
> #include <linux/io.h>
> +#include <linux/device.h>
> +#include <linux/spinlock.h>
>
> struct fsl_lbc_bank {
> __be32 br; /**< Base Register */
> @@ -125,13 +128,23 @@ struct fsl_lbc_regs {
> #define LTESR_ATMW 0x00800000
> #define LTESR_ATMR 0x00400000
> #define LTESR_CS 0x00080000
> +#define LTESR_UPM 0x00000002
> #define LTESR_CC 0x00000001
> #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
> +#define LTESR_MASK (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \
> + | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \
> + | LTESR_CC)
> +#define LTESR_CLEAR 0xFFFFFFFF
> +#define LTECCR_CLEAR 0xFFFFFFFF
> +#define LTESR_STATUS LTESR_MASK
> +#define LTEIR_ENABLE LTESR_MASK
> +#define LTEDR_ENABLE 0x00000000
> __be32 ltedr; /**< Transfer Error Disable Register */
> __be32 lteir; /**< Transfer Error Interrupt Register */
> __be32 lteatr; /**< Transfer Error Attributes Register */
> __be32 ltear; /**< Transfer Error Address Register */
> - u8 res6[0xC];
> + __be32 lteccr; /**< Transfer Error ECC Register */
> + u8 res6[0x8];
> __be32 lbcr; /**< Configuration Register */
> #define LBCR_LDIS 0x80000000
> #define LBCR_LDIS_SHIFT 31
> @@ -265,7 +278,23 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
> cpu_relax();
> }
>
> +/* overview of the fsl lbc controller */
> +
> +struct fsl_lbc_ctrl {
> + /* device info */
> + struct device *dev;
> + struct fsl_lbc_regs __iomem *regs;
> + int irq;
> + wait_queue_head_t irq_wait;
> + spinlock_t lock;
> + void *nand;
> +
> + /* status read from LTESR by irq handler */
> + unsigned int irq_status;
> +};
> +
> extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
> u32 mar);
> +extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
>
> #endif /* __ASM_FSL_LBC_H */
> diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
> index dceb8d1..4bb0336 100644
> --- a/arch/powerpc/sysdev/fsl_lbc.c
> +++ b/arch/powerpc/sysdev/fsl_lbc.c
> @@ -2,8 +2,11 @@
> * Freescale LBC and UPM routines.
> *
> * Copyright (c) 2007-2008 MontaVista Software, Inc.
> + * Copyright (c) 2010 Freescale Semiconductor
> *
> * Author: Anton Vorontsov <avorontsov at ru.mvista.com>
> + * Author: Jack Lan <Jack.Lan at freescale.com>
> + * Author: Roy Zang <tie-fei.zang at freescale.com>
> *
> * 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
> @@ -19,39 +22,16 @@
> #include <linux/types.h>
> #include <linux/io.h>
> #include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/mod_devicetable.h>
> #include <asm/prom.h>
> #include <asm/fsl_lbc.h>
>
> static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
> -static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
> -
> -static char __initdata *compat_lbc[] = {
> - "fsl,pq2-localbus",
> - "fsl,pq2pro-localbus",
> - "fsl,pq3-localbus",
> - "fsl,elbc",
> -};
> -
> -static int __init fsl_lbc_init(void)
> -{
> - struct device_node *lbus;
> - int i;
> -
> - for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
> - lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
> - if (lbus)
> - goto found;
> - }
> - return -ENODEV;
> -
> -found:
> - fsl_lbc_regs = of_iomap(lbus, 0);
> - of_node_put(lbus);
> - if (!fsl_lbc_regs)
> - return -ENOMEM;
> - return 0;
> -}
> -arch_initcall(fsl_lbc_init);
> +struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
> +EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
>
> /**
> * fsl_lbc_find - find Localbus bank
> @@ -65,13 +45,15 @@ arch_initcall(fsl_lbc_init);
> int fsl_lbc_find(phys_addr_t addr_base)
> {
> int i;
> + struct fsl_lbc_regs __iomem *lbc;
>
> - if (!fsl_lbc_regs)
> + if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
> return -ENODEV;
>
> - for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
> - __be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
> - __be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
> + lbc = fsl_lbc_ctrl_dev->regs;
> + for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
> + __be32 br = in_be32(&lbc->bank[i].br);
> + __be32 or = in_be32(&lbc->bank[i].or);
>
> if (br & BR_V && (br & or & BR_BA) == addr_base)
> return i;
> @@ -94,22 +76,27 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
> {
> int bank;
> __be32 br;
> + struct fsl_lbc_regs __iomem *lbc;
>
> bank = fsl_lbc_find(addr_base);
> if (bank < 0)
> return bank;
>
> - br = in_be32(&fsl_lbc_regs->bank[bank].br);
> + if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
> + return -ENODEV;
> +
> + lbc = fsl_lbc_ctrl_dev->regs;
> + br = in_be32(&lbc->bank[bank].br);
>
> switch (br & BR_MSEL) {
> case BR_MS_UPMA:
> - upm->mxmr = &fsl_lbc_regs->mamr;
> + upm->mxmr = &lbc->mamr;
> break;
> case BR_MS_UPMB:
> - upm->mxmr = &fsl_lbc_regs->mbmr;
> + upm->mxmr = &lbc->mbmr;
> break;
> case BR_MS_UPMC:
> - upm->mxmr = &fsl_lbc_regs->mcmr;
> + upm->mxmr = &lbc->mcmr;
> break;
> default:
> return -EINVAL;
> @@ -148,9 +135,12 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
> int ret = 0;
> unsigned long flags;
>
> + if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
> + return -ENODEV;
> +
> spin_lock_irqsave(&fsl_lbc_lock, flags);
>
> - out_be32(&fsl_lbc_regs->mar, mar);
> + out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
>
> switch (upm->width) {
> case 8:
> @@ -172,3 +162,166 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
> return ret;
> }
> EXPORT_SYMBOL(fsl_upm_run_pattern);
> +
> +static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
> +{
> + struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> +
> + /* clear event registers */
> + setbits32(&lbc->ltesr, LTESR_CLEAR);
> + out_be32(&lbc->lteatr, 0);
> + out_be32(&lbc->ltear, 0);
> + out_be32(&lbc->lteccr, LTECCR_CLEAR);
> + out_be32(&lbc->ltedr, LTEDR_ENABLE);
> +
> + /* Enable interrupts for any detected events */
> + out_be32(&lbc->lteir, LTEIR_ENABLE);
> +
> + return 0;
> +}
> +
> +/*
> + * NOTE: This interrupt is used to report localbus events of various kinds,
> + * such as transaction errors on the chipselects.
> + */
> +
> +static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
> +{
> + struct fsl_lbc_ctrl *ctrl = data;
> + struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> + u32 status;
> +
> + status = in_be32(&lbc->ltesr);
> + if (!status)
> + return IRQ_NONE;
> +
> + out_be32(&lbc->ltesr, LTESR_CLEAR);
> + out_be32(&lbc->lteatr, 0);
> + out_be32(&lbc->ltear, 0);
> + ctrl->irq_status = status;
> +
> + if (status & LTESR_BM)
> + dev_err(ctrl->dev, "Local bus monitor time-out: "
> + "LTESR 0x%08X\n", status);
> + if (status & LTESR_WP)
> + dev_err(ctrl->dev, "Write protect error: "
> + "LTESR 0x%08X\n", status);
> + if (status & LTESR_ATMW)
> + dev_err(ctrl->dev, "Atomic write error: "
> + "LTESR 0x%08X\n", status);
> + if (status & LTESR_ATMR)
> + dev_err(ctrl->dev, "Atomic read error: "
> + "LTESR 0x%08X\n", status);
> + if (status & LTESR_CS)
> + dev_err(ctrl->dev, "Chip select error: "
> + "LTESR 0x%08X\n", status);
> + if (status & LTESR_UPM)
> + ;
> + if (status & LTESR_FCT) {
> + dev_err(ctrl->dev, "FCM command time-out: "
> + "LTESR 0x%08X\n", status);
> + smp_wmb();
> + wake_up(&ctrl->irq_wait);
> + }
> + if (status & LTESR_PAR) {
> + dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
> + "LTESR 0x%08X\n", status);
> + smp_wmb();
> + wake_up(&ctrl->irq_wait);
> + }
> + if (status & LTESR_CC) {
> + smp_wmb();
> + wake_up(&ctrl->irq_wait);
> + }
> + if (status & ~LTESR_MASK)
> + dev_err(ctrl->dev, "Unknown error: "
> + "LTESR 0x%08X\n", status);
> + return IRQ_HANDLED;
> +}
> +
> +/*
> + * fsl_lbc_ctrl_probe
> + *
> + * called by device layer when it finds a device matching
> + * one our driver can handled. This code allocates all of
> + * the resources needed for the controller only. The
> + * resources for the NAND banks themselves are allocated
> + * in the chip probe function.
> +*/
> +
> +static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
> +{
> + int ret;
> +
> + if (!dev->dev.of_node) {
> + dev_err(&dev->dev, "Device OF-Node is NULL");
> + return -EFAULT;
> + }
> +
> + fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
> + if (!fsl_lbc_ctrl_dev)
> + return -ENOMEM;
> +
> + dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
> +
> + spin_lock_init(&fsl_lbc_ctrl_dev->lock);
> + init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
> +
> + fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
> + if (!fsl_lbc_ctrl_dev->regs) {
> + dev_err(&dev->dev, "failed to get memory region\n");
> + ret = -ENODEV;
> + goto err;
Looks you always iounmap(fsl_lbc_ctrl_dev->regs) on position 'err' but here
of_iomap() is already failed you should skip iounmap() fsl_lbc_ctrl_dev->regs
again. So you should improve that as the following on 'err', or layout 'err' in
gain.
------
if(fsl_lbc_ctrl_dev->regs)
iounmap(fsl_lbc_ctrl_dev->regs);
Tiejun
> + }
> +
> + fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
> + if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
> + dev_err(&dev->dev, "failed to get irq resource\n");
> + ret = -ENODEV;
> + goto err;
> + }
> +
> + fsl_lbc_ctrl_dev->dev = &dev->dev;
> +
> + ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
> + if (ret < 0)
> + goto err;
> +
> + ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
> + "fsl-lbc", fsl_lbc_ctrl_dev);
> + if (ret != 0) {
> + dev_err(&dev->dev, "failed to install irq (%d)\n",
> + fsl_lbc_ctrl_dev->irq);
> + ret = fsl_lbc_ctrl_dev->irq;
> + goto err;
> + }
> +
> + return 0;
> +
> +err:
> + iounmap(fsl_lbc_ctrl_dev->regs);
> + kfree(fsl_lbc_ctrl_dev);
> + return ret;
> +}
> +
> +static const struct of_device_id fsl_lbc_match[] = {
> + { .compatible = "fsl,elbc", },
> + { .compatible = "fsl,pq3-localbus", },
> + { .compatible = "fsl,pq2-localbus", },
> + { .compatible = "fsl,pq2pro-localbus", },
> + {},
> +};
> +
> +static struct platform_driver fsl_lbc_ctrl_driver = {
> + .driver = {
> + .name = "fsl-lbc",
> + .of_match_table = fsl_lbc_match,
> + },
> + .probe = fsl_lbc_ctrl_probe,
> +};
> +
> +static int __init fsl_lbc_init(void)
> +{
> + return platform_driver_register(&fsl_lbc_ctrl_driver);
> +}
> +module_init(fsl_lbc_init);
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 8b4b67c..4132c46 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -458,6 +458,7 @@ config MTD_NAND_ORION
> config MTD_NAND_FSL_ELBC
> tristate "NAND support for Freescale eLBC controllers"
> depends on PPC_OF
> + select FSL_LBC
> help
> Various Freescale chips, including the 8313, include a NAND Flash
> Controller Module with built-in hardware ECC capabilities.
> diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
> index 80de0bf..400f01f 100644
> --- a/drivers/mtd/nand/fsl_elbc_nand.c
> +++ b/drivers/mtd/nand/fsl_elbc_nand.c
> @@ -1,9 +1,11 @@
> /* Freescale Enhanced Local Bus Controller NAND driver
> *
> - * Copyright (c) 2006-2007 Freescale Semiconductor
> + * Copyright (c) 2006-2007, 2010 Freescale Semiconductor
> *
> * Authors: Nick Spence <nick.spence at freescale.com>,
> * Scott Wood <scottwood at freescale.com>
> + * Jack Lan <jack.lan at freescale.com>
> + * Roy Zang <tie-fei.zang at freescale.com>
> *
> * 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
> @@ -27,6 +29,7 @@
> #include <linux/string.h>
> #include <linux/ioport.h>
> #include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> #include <linux/slab.h>
> #include <linux/interrupt.h>
>
> @@ -42,14 +45,12 @@
> #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */
> #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */
>
> -struct fsl_elbc_ctrl;
> -
> /* mtd information per set */
>
> struct fsl_elbc_mtd {
> struct mtd_info mtd;
> struct nand_chip chip;
> - struct fsl_elbc_ctrl *ctrl;
> + struct fsl_lbc_ctrl *ctrl;
>
> struct device *dev;
> int bank; /* Chip select bank number */
> @@ -58,18 +59,12 @@ struct fsl_elbc_mtd {
> unsigned int fmr; /* FCM Flash Mode Register value */
> };
>
> -/* overview of the fsl elbc controller */
> +/* Freescale eLBC FCM controller infomation */
>
> -struct fsl_elbc_ctrl {
> +struct fsl_elbc_fcm_ctrl {
> struct nand_hw_control controller;
> struct fsl_elbc_mtd *chips[MAX_BANKS];
>
> - /* device info */
> - struct device *dev;
> - struct fsl_lbc_regs __iomem *regs;
> - int irq;
> - wait_queue_head_t irq_wait;
> - unsigned int irq_status; /* status read from LTESR by irq handler */
> u8 __iomem *addr; /* Address of assigned FCM buffer */
> unsigned int page; /* Last page written to / read from */
> unsigned int read_bytes; /* Number of bytes read during command */
> @@ -79,6 +74,7 @@ struct fsl_elbc_ctrl {
> unsigned int mdr; /* UPM/FCM Data Register value */
> unsigned int use_mdr; /* Non zero if the MDR is to be set */
> unsigned int oob; /* Non zero if operating on OOB data */
> + unsigned int counter; /* counter for the initializations */
> char *oob_poi; /* Place to write ECC after read back */
> };
>
> @@ -164,11 +160,12 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
> int buf_num;
>
> - ctrl->page = page_addr;
> + elbc_fcm_ctrl->page = page_addr;
>
> out_be32(&lbc->fbar,
> page_addr >> (chip->phys_erase_shift - chip->page_shift));
> @@ -185,16 +182,18 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
> buf_num = page_addr & 7;
> }
>
> - ctrl->addr = priv->vbase + buf_num * 1024;
> - ctrl->index = column;
> + elbc_fcm_ctrl->addr = priv->vbase + buf_num * 1024;
> + elbc_fcm_ctrl->index = column;
>
> /* for OOB data point to the second half of the buffer */
> if (oob)
> - ctrl->index += priv->page_size ? 2048 : 512;
> + elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
>
> - dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), "
> + dev_vdbg(priv->dev, "set_addr: bank=%d, "
> + "elbc_fcm_ctrl->addr=0x%p (0x%p), "
> "index %x, pes %d ps %d\n",
> - buf_num, ctrl->addr, priv->vbase, ctrl->index,
> + buf_num, elbc_fcm_ctrl->addr, priv->vbase,
> + elbc_fcm_ctrl->index,
> chip->phys_erase_shift, chip->page_shift);
> }
>
> @@ -205,18 +204,19 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
> struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
>
> /* Setup the FMR[OP] to execute without write protection */
> out_be32(&lbc->fmr, priv->fmr | 3);
> - if (ctrl->use_mdr)
> - out_be32(&lbc->mdr, ctrl->mdr);
> + if (elbc_fcm_ctrl->use_mdr)
> + out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
>
> - dev_vdbg(ctrl->dev,
> + dev_vdbg(priv->dev,
> "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
> in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
> - dev_vdbg(ctrl->dev,
> + dev_vdbg(priv->dev,
> "fsl_elbc_run_command: fbar=%08x fpar=%08x "
> "fbcr=%08x bank=%d\n",
> in_be32(&lbc->fbar), in_be32(&lbc->fpar),
> @@ -229,19 +229,18 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
> /* wait for FCM complete flag or timeout */
> wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
> FCM_TIMEOUT_MSECS * HZ/1000);
> - ctrl->status = ctrl->irq_status;
> -
> + elbc_fcm_ctrl->status = ctrl->irq_status;
> /* store mdr value in case it was needed */
> - if (ctrl->use_mdr)
> - ctrl->mdr = in_be32(&lbc->mdr);
> + if (elbc_fcm_ctrl->use_mdr)
> + elbc_fcm_ctrl->mdr = in_be32(&lbc->mdr);
>
> - ctrl->use_mdr = 0;
> + elbc_fcm_ctrl->use_mdr = 0;
>
> - if (ctrl->status != LTESR_CC) {
> - dev_info(ctrl->dev,
> + if (elbc_fcm_ctrl->status != LTESR_CC) {
> + dev_info(priv->dev,
> "command failed: fir %x fcr %x status %x mdr %x\n",
> in_be32(&lbc->fir), in_be32(&lbc->fcr),
> - ctrl->status, ctrl->mdr);
> + elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
> return -EIO;
> }
>
> @@ -251,7 +250,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
> static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
> {
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
>
> if (priv->page_size) {
> @@ -284,15 +283,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
> struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
>
> - ctrl->use_mdr = 0;
> + elbc_fcm_ctrl->use_mdr = 0;
>
> /* clear the read buffer */
> - ctrl->read_bytes = 0;
> + elbc_fcm_ctrl->read_bytes = 0;
> if (command != NAND_CMD_PAGEPROG)
> - ctrl->index = 0;
> + elbc_fcm_ctrl->index = 0;
>
> switch (command) {
> /* READ0 and READ1 read the entire buffer to use hardware ECC. */
> @@ -301,7 +301,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
>
> /* fall-through */
> case NAND_CMD_READ0:
> - dev_dbg(ctrl->dev,
> + dev_dbg(priv->dev,
> "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
> " 0x%x, column: 0x%x.\n", page_addr, column);
>
> @@ -309,8 +309,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
> set_addr(mtd, 0, page_addr, 0);
>
> - ctrl->read_bytes = mtd->writesize + mtd->oobsize;
> - ctrl->index += column;
> + elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
> + elbc_fcm_ctrl->index += column;
>
> fsl_elbc_do_read(chip, 0);
> fsl_elbc_run_command(mtd);
> @@ -318,14 +318,14 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
>
> /* READOOB reads only the OOB because no ECC is performed. */
> case NAND_CMD_READOOB:
> - dev_vdbg(ctrl->dev,
> + dev_vdbg(priv->dev,
> "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
> " 0x%x, column: 0x%x.\n", page_addr, column);
>
> out_be32(&lbc->fbcr, mtd->oobsize - column);
> set_addr(mtd, column, page_addr, 1);
>
> - ctrl->read_bytes = mtd->writesize + mtd->oobsize;
> + elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
>
> fsl_elbc_do_read(chip, 1);
> fsl_elbc_run_command(mtd);
> @@ -333,7 +333,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
>
> /* READID must read all 5 possible bytes while CEB is active */
> case NAND_CMD_READID:
> - dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
> + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
>
> out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
> (FIR_OP_UA << FIR_OP1_SHIFT) |
> @@ -341,9 +341,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
> /* 5 bytes for manuf, device and exts */
> out_be32(&lbc->fbcr, 5);
> - ctrl->read_bytes = 5;
> - ctrl->use_mdr = 1;
> - ctrl->mdr = 0;
> + elbc_fcm_ctrl->read_bytes = 5;
> + elbc_fcm_ctrl->use_mdr = 1;
> + elbc_fcm_ctrl->mdr = 0;
>
> set_addr(mtd, 0, 0, 0);
> fsl_elbc_run_command(mtd);
> @@ -351,7 +351,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
>
> /* ERASE1 stores the block and page address */
> case NAND_CMD_ERASE1:
> - dev_vdbg(ctrl->dev,
> + dev_vdbg(priv->dev,
> "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
> "page_addr: 0x%x.\n", page_addr);
> set_addr(mtd, 0, page_addr, 0);
> @@ -359,7 +359,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
>
> /* ERASE2 uses the block and page address from ERASE1 */
> case NAND_CMD_ERASE2:
> - dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
> + dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
>
> out_be32(&lbc->fir,
> (FIR_OP_CM0 << FIR_OP0_SHIFT) |
> @@ -374,8 +374,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
>
> out_be32(&lbc->fbcr, 0);
> - ctrl->read_bytes = 0;
> - ctrl->use_mdr = 1;
> + elbc_fcm_ctrl->read_bytes = 0;
> + elbc_fcm_ctrl->use_mdr = 1;
>
> fsl_elbc_run_command(mtd);
> return;
> @@ -383,14 +383,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> /* SEQIN sets up the addr buffer and all registers except the length */
> case NAND_CMD_SEQIN: {
> __be32 fcr;
> - dev_vdbg(ctrl->dev,
> - "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
> + dev_vdbg(priv->dev,
> + "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
> "page_addr: 0x%x, column: 0x%x.\n",
> page_addr, column);
>
> - ctrl->column = column;
> - ctrl->oob = 0;
> - ctrl->use_mdr = 1;
> + elbc_fcm_ctrl->use_mdr = 1;
>
> fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
> (NAND_CMD_SEQIN << FCR_CMD2_SHIFT) |
> @@ -420,7 +418,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> /* OOB area --> READOOB */
> column -= mtd->writesize;
> fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
> - ctrl->oob = 1;
> + elbc_fcm_ctrl->oob = 1;
> } else {
> WARN_ON(column != 0);
> /* First 256 bytes --> READ0 */
> @@ -429,24 +427,24 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> }
>
> out_be32(&lbc->fcr, fcr);
> - set_addr(mtd, column, page_addr, ctrl->oob);
> + set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
> return;
> }
>
> /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
> case NAND_CMD_PAGEPROG: {
> int full_page;
> - dev_vdbg(ctrl->dev,
> + dev_vdbg(priv->dev,
> "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
> - "writing %d bytes.\n", ctrl->index);
> + "writing %d bytes.\n", elbc_fcm_ctrl->index);
>
> /* if the write did not start at 0 or is not a full page
> * then set the exact length, otherwise use a full page
> * write so the HW generates the ECC.
> */
> - if (ctrl->oob || ctrl->column != 0 ||
> - ctrl->index != mtd->writesize + mtd->oobsize) {
> - out_be32(&lbc->fbcr, ctrl->index);
> + if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
> + elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) {
> + out_be32(&lbc->fbcr, elbc_fcm_ctrl->index);
> full_page = 0;
> } else {
> out_be32(&lbc->fbcr, 0);
> @@ -458,21 +456,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> /* Read back the page in order to fill in the ECC for the
> * caller. Is this really needed?
> */
> - if (full_page && ctrl->oob_poi) {
> + if (full_page && elbc_fcm_ctrl->oob_poi) {
> out_be32(&lbc->fbcr, 3);
> set_addr(mtd, 6, page_addr, 1);
>
> - ctrl->read_bytes = mtd->writesize + 9;
> + elbc_fcm_ctrl->read_bytes = mtd->writesize + 9;
>
> fsl_elbc_do_read(chip, 1);
> fsl_elbc_run_command(mtd);
>
> - memcpy_fromio(ctrl->oob_poi + 6,
> - &ctrl->addr[ctrl->index], 3);
> - ctrl->index += 3;
> + memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6,
> + &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3);
> + elbc_fcm_ctrl->index += 3;
> }
>
> - ctrl->oob_poi = NULL;
> + elbc_fcm_ctrl->oob_poi = NULL;
> return;
> }
>
> @@ -485,26 +483,26 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
> out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
> out_be32(&lbc->fbcr, 1);
> set_addr(mtd, 0, 0, 0);
> - ctrl->read_bytes = 1;
> + elbc_fcm_ctrl->read_bytes = 1;
>
> fsl_elbc_run_command(mtd);
>
> /* The chip always seems to report that it is
> * write-protected, even when it is not.
> */
> - setbits8(ctrl->addr, NAND_STATUS_WP);
> + setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
> return;
>
> /* RESET without waiting for the ready line */
> case NAND_CMD_RESET:
> - dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
> + dev_dbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n");
> out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT);
> out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT);
> fsl_elbc_run_command(mtd);
> return;
>
> default:
> - dev_err(ctrl->dev,
> + dev_err(priv->dev,
> "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
> command);
> }
> @@ -524,24 +522,24 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
> unsigned int bufsize = mtd->writesize + mtd->oobsize;
>
> if (len <= 0) {
> - dev_err(ctrl->dev, "write_buf of %d bytes", len);
> - ctrl->status = 0;
> + dev_err(priv->dev, "write_buf of %d bytes", len);
> + elbc_fcm_ctrl->status = 0;
> return;
> }
>
> - if ((unsigned int)len > bufsize - ctrl->index) {
> - dev_err(ctrl->dev,
> + if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
> + dev_err(priv->dev,
> "write_buf beyond end of buffer "
> "(%d requested, %u available)\n",
> - len, bufsize - ctrl->index);
> - len = bufsize - ctrl->index;
> + len, bufsize - elbc_fcm_ctrl->index);
> + len = bufsize - elbc_fcm_ctrl->index;
> }
>
> - memcpy_toio(&ctrl->addr[ctrl->index], buf, len);
> + memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
> /*
> * This is workaround for the weird elbc hangs during nand write,
> * Scott Wood says: "...perhaps difference in how long it takes a
> @@ -549,9 +547,9 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
> * is causing problems, and sync isn't helping for some reason."
> * Reading back the last byte helps though.
> */
> - in_8(&ctrl->addr[ctrl->index] + len - 1);
> + in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index] + len - 1);
>
> - ctrl->index += len;
> + elbc_fcm_ctrl->index += len;
> }
>
> /*
> @@ -562,13 +560,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>
> /* If there are still bytes in the FCM, then use the next byte. */
> - if (ctrl->index < ctrl->read_bytes)
> - return in_8(&ctrl->addr[ctrl->index++]);
> + if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
> + return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
>
> - dev_err(ctrl->dev, "read_byte beyond end of buffer\n");
> + dev_err(priv->dev, "read_byte beyond end of buffer\n");
> return ERR_BYTE;
> }
>
> @@ -579,18 +577,19 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
> int avail;
>
> if (len < 0)
> return;
>
> - avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index);
> - memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail);
> - ctrl->index += avail;
> + avail = min((unsigned int)len,
> + elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
> + memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
> + elbc_fcm_ctrl->index += avail;
>
> if (len > avail)
> - dev_err(ctrl->dev,
> + dev_err(priv->dev,
> "read_buf beyond end of buffer "
> "(%d requested, %d available)\n",
> len, avail);
> @@ -603,30 +602,32 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
> int i;
>
> if (len < 0) {
> - dev_err(ctrl->dev, "write_buf of %d bytes", len);
> + dev_err(priv->dev, "write_buf of %d bytes", len);
> return -EINVAL;
> }
>
> - if ((unsigned int)len > ctrl->read_bytes - ctrl->index) {
> - dev_err(ctrl->dev,
> - "verify_buf beyond end of buffer "
> - "(%d requested, %u available)\n",
> - len, ctrl->read_bytes - ctrl->index);
> + if ((unsigned int)len >
> + elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index) {
> + dev_err(priv->dev,
> + "verify_buf beyond end of buffer "
> + "(%d requested, %u available)\n",
> + len, elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
>
> - ctrl->index = ctrl->read_bytes;
> + elbc_fcm_ctrl->index = elbc_fcm_ctrl->read_bytes;
> return -EINVAL;
> }
>
> for (i = 0; i < len; i++)
> - if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i])
> + if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i])
> + != buf[i])
> break;
>
> - ctrl->index += len;
> - return i == len && ctrl->status == LTESR_CC ? 0 : -EIO;
> + elbc_fcm_ctrl->index += len;
> + return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO;
> }
>
> /* This function is called after Program and Erase Operations to
> @@ -635,22 +636,22 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
> static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip)
> {
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>
> - if (ctrl->status != LTESR_CC)
> + if (elbc_fcm_ctrl->status != LTESR_CC)
> return NAND_STATUS_FAIL;
>
> /* The chip always seems to report that it is
> * write-protected, even when it is not.
> */
> - return (ctrl->mdr & 0xff) | NAND_STATUS_WP;
> + return (elbc_fcm_ctrl->mdr & 0xff) | NAND_STATUS_WP;
> }
>
> static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
> {
> struct nand_chip *chip = mtd->priv;
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> unsigned int al;
>
> @@ -665,41 +666,41 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
> priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */
> (al << FMR_AL_SHIFT);
>
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
> chip->numchips);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
> chip->chipsize);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
> chip->pagemask);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
> chip->chip_delay);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
> chip->badblockpos);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
> chip->chip_shift);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
> chip->page_shift);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
> chip->phys_erase_shift);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
> chip->ecclayout);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
> chip->ecc.mode);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
> chip->ecc.steps);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
> chip->ecc.bytes);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
> chip->ecc.total);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
> chip->ecc.layout);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
> + dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
> + dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
> mtd->erasesize);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
> mtd->writesize);
> - dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
> + dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
> mtd->oobsize);
>
> /* adjust Option Register and ECC to match Flash page size */
> @@ -719,7 +720,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
> chip->badblock_pattern = &largepage_memorybased;
> }
> } else {
> - dev_err(ctrl->dev,
> + dev_err(priv->dev,
> "fsl_elbc_init: page size %d is not supported\n",
> mtd->writesize);
> return -1;
> @@ -750,18 +751,19 @@ static void fsl_elbc_write_page(struct mtd_info *mtd,
> const uint8_t *buf)
> {
> struct fsl_elbc_mtd *priv = chip->priv;
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
>
> fsl_elbc_write_buf(mtd, buf, mtd->writesize);
> fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
>
> - ctrl->oob_poi = chip->oob_poi;
> + elbc_fcm_ctrl->oob_poi = chip->oob_poi;
> }
>
> static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
> {
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> + struct fsl_lbc_ctrl *ctrl = priv->ctrl;
> struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
> struct nand_chip *chip = &priv->chip;
>
> dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank);
> @@ -790,7 +792,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
> chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR |
> NAND_USE_FLASH_BBT;
>
> - chip->controller = &ctrl->controller;
> + chip->controller = &elbc_fcm_ctrl->controller;
> chip->priv = priv;
>
> chip->ecc.read_page = fsl_elbc_read_page;
> @@ -815,8 +817,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
>
> static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
> {
> - struct fsl_elbc_ctrl *ctrl = priv->ctrl;
> -
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
> nand_release(&priv->mtd);
>
> kfree(priv->mtd.name);
> @@ -824,18 +825,21 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
> if (priv->vbase)
> iounmap(priv->vbase);
>
> - ctrl->chips[priv->bank] = NULL;
> + elbc_fcm_ctrl->chips[priv->bank] = NULL;
> kfree(priv);
> -
> + kfree(elbc_fcm_ctrl);
> return 0;
> }
>
> -static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
> - struct device_node *node)
> +static DEFINE_MUTEX(fsl_elbc_nand_mutex);
> +
> +static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
> {
> - struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> + struct fsl_lbc_regs __iomem *lbc;
> struct fsl_elbc_mtd *priv;
> struct resource res;
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl;
> +
> #ifdef CONFIG_MTD_PARTITIONS
> static const char *part_probe_types[]
> = { "cmdlinepart", "RedBoot", NULL };
> @@ -843,11 +847,18 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
> #endif
> int ret;
> int bank;
> + struct device *dev;
> + struct device_node *node = pdev->dev.of_node;
> +
> + if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
> + return -ENODEV;
> + lbc = fsl_lbc_ctrl_dev->regs;
> + dev = fsl_lbc_ctrl_dev->dev;
>
> /* get, allocate and map the memory resource */
> ret = of_address_to_resource(node, 0, &res);
> if (ret) {
> - dev_err(ctrl->dev, "failed to get resource\n");
> + dev_err(dev, "failed to get resource\n");
> return ret;
> }
>
> @@ -861,7 +872,7 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
> break;
>
> if (bank >= MAX_BANKS) {
> - dev_err(ctrl->dev, "address did not match any chip selects\n");
> + dev_err(dev, "address did not match any chip selects\n");
> return -ENODEV;
> }
>
> @@ -869,14 +880,33 @@ static int __devinit fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl,
> if (!priv)
> return -ENOMEM;
>
> - ctrl->chips[bank] = priv;
> + mutex_lock(&fsl_elbc_nand_mutex);
> + if (!fsl_lbc_ctrl_dev->nand) {
> + elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
> + if (!elbc_fcm_ctrl) {
> + dev_err(dev, "failed to allocate memory\n");
> + mutex_unlock(&fsl_elbc_nand_mutex);
> + ret = -ENOMEM;
> + goto err;
> + }
> + elbc_fcm_ctrl->counter++;
> +
> + spin_lock_init(&elbc_fcm_ctrl->controller.lock);
> + init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
> + fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
> + } else {
> + elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
> + }
> + mutex_unlock(&fsl_elbc_nand_mutex);
> +
> + elbc_fcm_ctrl->chips[bank] = priv;
> priv->bank = bank;
> - priv->ctrl = ctrl;
> - priv->dev = ctrl->dev;
> + priv->ctrl = fsl_lbc_ctrl_dev;
> + priv->dev = dev;
>
> priv->vbase = ioremap(res.start, resource_size(&res));
> if (!priv->vbase) {
> - dev_err(ctrl->dev, "failed to map chip region\n");
> + dev_err(dev, "failed to map chip region\n");
> ret = -ENOMEM;
> goto err;
> }
> @@ -933,171 +963,53 @@ err:
> return ret;
> }
>
> -static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl)
> +static int fsl_elbc_nand_remove(struct platform_device *pdev)
> {
> - struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> -
> - /*
> - * NAND transactions can tie up the bus for a long time, so set the
> - * bus timeout to max by clearing LBCR[BMT] (highest base counter
> - * value) and setting LBCR[BMTPS] to the highest prescaler value.
> - */
> - clrsetbits_be32(&lbc->lbcr, LBCR_BMT, 15);
> -
> - /* clear event registers */
> - setbits32(&lbc->ltesr, LTESR_NAND_MASK);
> - out_be32(&lbc->lteatr, 0);
> -
> - /* Enable interrupts for any detected events */
> - out_be32(&lbc->lteir, LTESR_NAND_MASK);
> -
> - ctrl->read_bytes = 0;
> - ctrl->index = 0;
> - ctrl->addr = NULL;
> -
> - return 0;
> -}
> -
> -static int fsl_elbc_ctrl_remove(struct platform_device *ofdev)
> -{
> - struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
> int i;
> -
> + struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
> for (i = 0; i < MAX_BANKS; i++)
> - if (ctrl->chips[i])
> - fsl_elbc_chip_remove(ctrl->chips[i]);
> -
> - if (ctrl->irq)
> - free_irq(ctrl->irq, ctrl);
> -
> - if (ctrl->regs)
> - iounmap(ctrl->regs);
> -
> - dev_set_drvdata(&ofdev->dev, NULL);
> - kfree(ctrl);
> - return 0;
> -}
> -
> -/* NOTE: This interrupt is also used to report other localbus events,
> - * such as transaction errors on other chipselects. If we want to
> - * capture those, we'll need to move the IRQ code into a shared
> - * LBC driver.
> - */
> -
> -static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data)
> -{
> - struct fsl_elbc_ctrl *ctrl = data;
> - struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
> - __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK;
> -
> - if (status) {
> - out_be32(&lbc->ltesr, status);
> - out_be32(&lbc->lteatr, 0);
> -
> - ctrl->irq_status = status;
> - smp_wmb();
> - wake_up(&ctrl->irq_wait);
> -
> - return IRQ_HANDLED;
> + if (elbc_fcm_ctrl->chips[i])
> + fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]);
> +
> + mutex_lock(&fsl_elbc_nand_mutex);
> + elbc_fcm_ctrl->counter--;
> + if (!elbc_fcm_ctrl->counter) {
> + fsl_lbc_ctrl_dev->nand = NULL;
> + kfree(elbc_fcm_ctrl);
> }
> -
> - return IRQ_NONE;
> -}
> -
> -/* fsl_elbc_ctrl_probe
> - *
> - * called by device layer when it finds a device matching
> - * one our driver can handled. This code allocates all of
> - * the resources needed for the controller only. The
> - * resources for the NAND banks themselves are allocated
> - * in the chip probe function.
> -*/
> -
> -static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev,
> - const struct of_device_id *match)
> -{
> - struct device_node *child;
> - struct fsl_elbc_ctrl *ctrl;
> - int ret;
> -
> - ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
> - if (!ctrl)
> - return -ENOMEM;
> -
> - dev_set_drvdata(&ofdev->dev, ctrl);
> -
> - spin_lock_init(&ctrl->controller.lock);
> - init_waitqueue_head(&ctrl->controller.wq);
> - init_waitqueue_head(&ctrl->irq_wait);
> -
> - ctrl->regs = of_iomap(ofdev->dev.of_node, 0);
> - if (!ctrl->regs) {
> - dev_err(&ofdev->dev, "failed to get memory region\n");
> - ret = -ENODEV;
> - goto err;
> - }
> -
> - ctrl->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
> - if (ctrl->irq == NO_IRQ) {
> - dev_err(&ofdev->dev, "failed to get irq resource\n");
> - ret = -ENODEV;
> - goto err;
> - }
> -
> - ctrl->dev = &ofdev->dev;
> -
> - ret = fsl_elbc_ctrl_init(ctrl);
> - if (ret < 0)
> - goto err;
> -
> - ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl);
> - if (ret != 0) {
> - dev_err(&ofdev->dev, "failed to install irq (%d)\n",
> - ctrl->irq);
> - ret = ctrl->irq;
> - goto err;
> - }
> -
> - for_each_child_of_node(ofdev->dev.of_node, child)
> - if (of_device_is_compatible(child, "fsl,elbc-fcm-nand"))
> - fsl_elbc_chip_probe(ctrl, child);
> + mutex_unlock(&fsl_elbc_nand_mutex);
>
> return 0;
>
> -err:
> - fsl_elbc_ctrl_remove(ofdev);
> - return ret;
> }
>
> -static const struct of_device_id fsl_elbc_match[] = {
> - {
> - .compatible = "fsl,elbc",
> - },
> +static const struct of_device_id fsl_elbc_nand_match[] = {
> + { .compatible = "fsl,elbc-fcm-nand", },
> {}
> };
>
> -static struct of_platform_driver fsl_elbc_ctrl_driver = {
> +static struct platform_driver fsl_elbc_nand_driver = {
> .driver = {
> - .name = "fsl-elbc",
> + .name = "fsl,elbc-fcm-nand",
> .owner = THIS_MODULE,
> - .of_match_table = fsl_elbc_match,
> + .of_match_table = fsl_elbc_nand_match,
> },
> - .probe = fsl_elbc_ctrl_probe,
> - .remove = fsl_elbc_ctrl_remove,
> + .probe = fsl_elbc_nand_probe,
> + .remove = fsl_elbc_nand_remove,
> };
>
> -static int __init fsl_elbc_init(void)
> +static int __init fsl_elbc_nand_init(void)
> {
> - return of_register_platform_driver(&fsl_elbc_ctrl_driver);
> + return platform_driver_register(&fsl_elbc_nand_driver);
> }
>
> -static void __exit fsl_elbc_exit(void)
> +static void __exit fsl_elbc_nand_exit(void)
> {
> - of_unregister_platform_driver(&fsl_elbc_ctrl_driver);
> + platform_driver_unregister(&fsl_elbc_nand_driver);
> }
>
> -module_init(fsl_elbc_init);
> -module_exit(fsl_elbc_exit);
> +module_init(fsl_elbc_nand_init);
> +module_exit(fsl_elbc_nand_exit);
>
> MODULE_LICENSE("GPL");
> MODULE_AUTHOR("Freescale");
More information about the linux-mtd
mailing list