[PATCH 1/2] P4080/eLBC: Make Freescale elbc interrupt common to elbc devices

tiejun.chen tiejun.chen at windriver.com
Mon Oct 18 19:55:49 EST 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 Linuxppc-dev mailing list