LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/2] mtd/nand: Fix IFC driver to support 2K NAND page
From: Prabhakar Kushwaha @ 2011-12-29  4:59 UTC (permalink / raw)
  To: linuxppc-dev, linux-mtd; +Cc: scottwood, Poonam Aggrwal, Prabhakar Kushwaha
In-Reply-To: <1325134779-3571-1-git-send-email-prabhakar@freescale.com>

1) OOB area should be updated irrespective of NAND page size. Earlier it was
updated only for 512byte NAND page.

2) During OOB update fbcr should be equal to OOB size.

Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
---
 git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git (branch next)

 Tested on P1010RDB

 drivers/mtd/nand/fsl_ifc_nand.c |   20 ++++++++------------
 1 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 2df7206..2c02168 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -439,20 +439,16 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 			out_be32(&ifc->ifc_nand.nand_fir1,
 				 (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
 
-			if (column >= mtd->writesize) {
-				/* OOB area --> READOOB */
-				column -= mtd->writesize;
-				nand_fcr0 |= NAND_CMD_READOOB <<
-						IFC_NAND_FCR0_CMD0_SHIFT;
-				ifc_nand_ctrl->oob = 1;
-			} else if (column < 256)
+			if (column < 256)
 				/* First 256 bytes --> READ0 */
 				nand_fcr0 |=
 				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
-			else
-				/* Second 256 bytes --> READ1 */
-				nand_fcr0 |=
-				NAND_CMD_READ1 << IFC_NAND_FCR0_CMD0_SHIFT;
+		}
+
+		if (column >= mtd->writesize) {
+			/* OOB area --> READOOB */
+			column -= mtd->writesize;
+			ifc_nand_ctrl->oob = 1;
 		}
 
 		out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
@@ -465,7 +461,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 		int full_page;
 		if (ifc_nand_ctrl->oob) {
 			out_be32(&ifc->ifc_nand.nand_fbcr,
-					ifc_nand_ctrl->index);
+				ifc_nand_ctrl->index - ifc_nand_ctrl->column);
 			full_page = 0;
 		} else {
 			out_be32(&ifc->ifc_nand.nand_fbcr, 0);
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 1/2] mtd/nand:Fix wrong address read in is_blank()
From: Prabhakar Kushwaha @ 2011-12-29  4:59 UTC (permalink / raw)
  To: linuxppc-dev, linux-mtd; +Cc: scottwood, Poonam Aggrwal, Prabhakar Kushwaha
In-Reply-To: <1325134779-3571-1-git-send-email-prabhakar@freescale.com>

IFC NAND Machine calculates ECC on 512byte sector. Same is taken care in
fsl_ifc_run_command() while ECC status verification. Here buffer number is
calculated assuming 512byte sector and same is passed to is_blank.
However in is_blank() buffer address is calculated using mdt->writesize which is
wrong. It should be calculated on basis of ecc sector size.

Also, in fsl_ifc_run_command() bufferpage is calculated on the basis of ecc sector
size instead of hard coded value.

Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
---
 git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git (branch next)

 Tested on P1010RDB

 drivers/mtd/nand/fsl_ifc_nand.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 8475b88..2df7206 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -191,7 +191,9 @@ static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
 {
 	struct nand_chip *chip = mtd->priv;
 	struct fsl_ifc_mtd *priv = chip->priv;
-	u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
+	int bufperpage = mtd->writesize / chip->ecc.size;
+	u8 __iomem *addr = priv->vbase + bufnum / bufperpage
+					* (mtd->writesize * 2);
 	u32 __iomem *mainarea = (u32 *)addr;
 	u8 __iomem *oob = addr + mtd->writesize;
 	int i;
@@ -273,7 +275,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
 		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
 
 	if (nctrl->eccread) {
-		int bufperpage = mtd->writesize / 512;
+		int bufperpage = mtd->writesize / chip->ecc.size;
 		int bufnum = (nctrl->page & priv->bufnum_mask) * bufperpage;
 		int bufnum_end = bufnum + bufperpage - 1;
 
-- 
1.7.5.4

^ permalink raw reply related

* mtd/NAND:Fix issues with freescale IFC to support NAND 2K
From: Prabhakar Kushwaha @ 2011-12-29  4:59 UTC (permalink / raw)
  To: linuxppc-dev, linux-mtd; +Cc: scottwood

This Patch series takes care issues with Freescale IFC driver for supporting 2K
page size NAND with ECC enabled.

[PATCH 1/2] mtd/nand:Fix wrong address read in is_blank()
  Fix driver issue when ECC enabled.

[PATCH 2/2] mtd/nand: Fix IFC driver to support 2K NAND page
  Fix driver during OOB updation

^ permalink raw reply

* Re: [PATCH 1/2][v2] Integrated Flash Controller support
From: dmitry pervushin @ 2011-12-28 13:30 UTC (permalink / raw)
  To: Prabhakar Kushwaha; +Cc: Scott Wood, Dipen Dudhat, linuxppc-dev, Liu Shuo
In-Reply-To: <1324987753-30318-1-git-send-email-prabhakar@freescale.com>

On Tue, 2011-12-27 at 17:39 +0530, Prabhakar Kushwaha wrote:
[...]
> +/*
> + * IFC Controller NAND Machine registers
> + */
> +struct fsl_ifc_nand {
> +	__be32 ncfgr;
> +	u32 res1[0x4];
> +	__be32 nand_fcr0;
> +	__be32 nand_fcr1;
> +	u32 res2[0x8];
> +	__be32 row0;
> +	u32 res3;
> +	__be32 col0;
> +	u32 res4;
> +	__be32 row1;
> +	u32 res5;
> +	__be32 col1;
> +	u32 res6;
> +	__be32 row2;
> +	u32 res7;
> +	__be32 col2;
> +	u32 res8;
> +	__be32 row3;
> +	u32 res9;
> +	__be32 col3;
> +	u32 res10[0x24];
> +	__be32 nand_fbcr;
> +	u32 res11;
> +	__be32 nand_fir0;
> +	__be32 nand_fir1;
> +	__be32 nand_fir2;
> +	u32 res12[0x10];
> +	__be32 nand_csel;
> +	u32 res13;
> +	__be32 nandseq_strt;
> +	u32 res14;
> +	__be32 nand_evter_stat;
> +	u32 res15;
> +	__be32 pgrdcmpl_evt_stat;
> +	u32 res16[0x2];
> +	__be32 nand_evter_en;
> +	u32 res17[0x2];
> +	__be32 nand_evter_intr_en;
> +	u32 res18[0x2];
> +	__be32 nand_erattr0;
> +	__be32 nand_erattr1;
> +	u32 res19[0x10];
> +	__be32 nand_fsr;
> +	u32 res20;
> +	__be32 nand_eccstat[4];
> +	u32 res21[0x20];
> +	__be32 nanndcr;
> +	u32 res22[0x2];
> +	__be32 nand_autoboot_trgr;
> +	u32 res23;
> +	__be32 nand_mdr;
> +	u32 res24[0x5C];
> +};
If you're using memory-mapped structure, shouldn't it be announced with
__attribute__(packed) ?
> +
> +/*
> + * IFC controller NOR Machine registers
> + */
> +struct fsl_ifc_nor {
> +	__be32 nor_evter_stat;
> +	u32 res1[0x2];
> +	__be32 nor_evter_en;
> +	u32 res2[0x2];
> +	__be32 nor_evter_intr_en;
> +	u32 res3[0x2];
> +	__be32 nor_erattr0;
> +	__be32 nor_erattr1;
> +	__be32 nor_erattr2;
> +	u32 res4[0x4];
> +	__be32 norcr;
> +	u32 res5[0xEF];
> +};
> +
> +/*
> + * IFC controller GPCM Machine registers
> + */
> +struct fsl_ifc_gpcm {
> +	__be32 gpcm_evter_stat;
> +	u32 res1[0x2];
> +	__be32 gpcm_evter_en;
> +	u32 res2[0x2];
> +	__be32 gpcm_evter_intr_en;
> +	u32 res3[0x2];
> +	__be32 gpcm_erattr0;
> +	__be32 gpcm_erattr1;
> +	__be32 gpcm_erattr2;
> +	__be32 gpcm_stat;
> +	u32 res4[0x1F3];
> +};
...here too...
> +
> +/*
> + * IFC Controller Registers
> + */
> +struct fsl_ifc_regs {
> +	__be32 ifc_rev;
> +	u32 res1[0x3];
> +	struct {
> +		__be32 cspr;
> +		u32 res2[0x2];
> +	} cspr_cs[FSL_IFC_BANK_COUNT];
> +	u32 res3[0x18];
> +	struct {
> +		__be32 amask;
> +		u32 res4[0x2];
> +	} amask_cs[FSL_IFC_BANK_COUNT];
> +	u32 res5[0x18];
> +	struct {
> +		__be32 csor;
> +		u32 res6[0x2];
> +	} csor_cs[FSL_IFC_BANK_COUNT];
> +	u32 res7[0x18];
> +	struct {
> +		__be32 ftim[4];
> +		u32 res8[0x8];
> +	} ftim_cs[FSL_IFC_BANK_COUNT];
> +	u32 res9[0x60];
> +	__be32 rb_stat;
> +	u32 res10[0x2];
> +	__be32 ifc_gcr;
> +	u32 res11[0x2];
> +	__be32 cm_evter_stat;
> +	u32 res12[0x2];
> +	__be32 cm_evter_en;
> +	u32 res13[0x2];
> +	__be32 cm_evter_intr_en;
> +	u32 res14[0x2];
> +	__be32 cm_erattr0;
> +	__be32 cm_erattr1;
> +	u32 res15[0x2];
> +	__be32 ifc_ccr;
> +	__be32 ifc_csr;
> +	u32 res16[0x2EB];
> +	struct fsl_ifc_nand ifc_nand;
> +	struct fsl_ifc_nor ifc_nor;
> +	struct fsl_ifc_gpcm ifc_gpcm;
> +};
...and here.
> +
> +extern unsigned int convert_ifc_address(phys_addr_t addr_base);
> +extern int fsl_ifc_find(phys_addr_t addr_base);
> +
> +/* overview of the fsl ifc controller */
> +
> +struct fsl_ifc_ctrl {
> +	/* device info */
> +	struct device			*dev;
> +	struct fsl_ifc_regs __iomem	*regs;
> +	int				irq;
> +	int				nand_irq;
> +	spinlock_t			lock;
> +	void				*nand;
> +
> +	u32 nand_stat;
> +	wait_queue_head_t nand_wait;
> +};
> +
> +extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
> +
> +
> +#endif /* __ASM_FSL_IFC_H */

^ permalink raw reply

* RE: [PATCH 00/14] DMA-mapping framework redesign preparation
From: Marek Szyprowski @ 2011-12-28 12:52 UTC (permalink / raw)
  To: 'James Bottomley'
  Cc: linux-mips, linux-ia64, linux-sh, linux-mm, sparclinux,
	linux-arch, 'Stephen Rothwell', 'Jonathan Corbet',
	x86, 'Arnd Bergmann', 'Matthew Wilcox',
	microblaze-uclinux, linaro-mm-sig, Andrzej Pietrasiewicz,
	'Thomas Gleixner', linux-arm-kernel, discuss,
	linux-kernel, 'Kyungmin Park', linux-alpha,
	'Andrew Morton', linuxppc-dev
In-Reply-To: <1325008393.14252.5.camel@dabdike>

Hello,

On Tuesday, December 27, 2011 6:53 PM James Bottomley wrote:

> On Tue, 2011-12-27 at 09:25 +0100, Marek Szyprowski wrote:
> [...]
> > > > Usually these drivers don't touch the buffer data at all, so the mapping
> > > > in kernel virtual address space is not needed. We can introduce
> > > > DMA_ATTRIB_NO_KERNEL_MAPPING attribute which lets kernel to skip/ignore
> > > > creation of kernel virtual mapping. This way we can save previous
> > > > vmalloc area and simply some mapping operation on a few architectures.
> > >
> > > I really think this wants to be a separate function.  dma_alloc_coherent
> > > is for allocating memory to be shared between the kernel and a driver;
> > > we already have dma_map_sg for mapping userspace I/O as an alternative
> > > interface.  This feels like it's something different again rather than
> > > an option to dma_alloc_coherent.
> >
> > That is just a starting point for the discussion.
> >
> > I thought about this API a bit and came to conclusion that there is no much
> > difference between a dma_alloc_coherent which creates a mapping in kernel
> > virtual space and the one that does not. It is just a hint from the driver
> > that it will not use that mapping at all. Of course this attribute makes sense
> > only together with adding a dma_mmap_attrs() call, because otherwise drivers
> > won't be able to get access to the buffer data.
> 
> This depends.  On Virtually indexed systems like PA-RISC, there are two
> ways of making a DMA range coherent.  One is to make the range uncached.
> This is incredibly slow and not what we do by default, but it can be
> used to make multiple mappings coherent.  The other is to load the
> virtual address up as a coherence index into the IOMMU.  This makes it a
> full peer in the coherence process, but means we can only designate a
> single virtual range to be coherent (not multiple mappings unless they
> happen to be congruent).  Perhaps it doesn't matter that much, since I
> don't see a use for this on PA, but if any other architecture works the
> same, you'd have to designate a single mapping as the coherent one and
> essentially promise not to use the other mapping if we followed our
> normal coherence protocols.
> 
> Obviously, the usual range we currently make coherent is the kernel
> mapping (that's actually the only virtual address we have by the time
> we're deep in the iommu code), so designating a different virtual
> address would need some surgery to the guts of the iommu code.

I see, in this case not much can be achieved by dropping the kernel
mapping for the allocated buffer. I'm also not sure how to mmap the buffer
into userspace meet the cpu requirements? Is it possible to use non-cached
mapping in userspace together with coherent mapping in kernel virtual
space?

However on some other architectures this attribute allows using HIGH_MEM
for the allocated coherent buffer. The other possibility is to allocate it
in chunks and map them contiguously into dma address space. With 
NO_KERNEL_MAPPING attribute we avoid consuming vmalloc range for the newly
allocated buffer for which we cannot use the linear mapping (because it is
scattered).

Of course this attribute will be implemented by the architectures where it
gives some benefits. All other can simply ignore it and return plain
coherent buffer with ordinary kernel virtual mapping. The driver will just
ignore it.

Best regards
-- 
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply

* Re: [PATCH] mmc:sdhci: restore the enabled dma when do reset all
From: Adrian Hunter @ 2011-12-28 11:42 UTC (permalink / raw)
  To: Shaohui Xie; +Cc: linuxppc-dev, linux-mmc
In-Reply-To: <1325065281-17785-1-git-send-email-Shaohui.Xie@freescale.com>

On 28/12/11 11:41, Shaohui Xie wrote:
> If dma is enabled, it'll be cleared when reset all is performed, this can
> be observed on some platforms, such as P2041 which has a version 2.3
> controller, but platform like P4080 which has a version 2.2 controller,
> does not suffer this, so we will check if the dma is enabled, we should
> restore it after reset all.
> 
> Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
> ---
> based on http://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git,
> branch 'for-linus'.
> 
>  drivers/mmc/host/sdhci.c |    7 +++++++
>  1 files changed, 7 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 19ed580..22033c3 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -29,6 +29,7 @@
>  #include <linux/mmc/host.h>
>  
>  #include "sdhci.h"
> +#include "sdhci-esdhc.h"
>  
>  #define DRIVER_NAME "sdhci"
>  
> @@ -176,6 +177,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
>  {
>  	unsigned long timeout;
>  	u32 uninitialized_var(ier);
> +	u32 uninitialized_var(dma);
>  
>  	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
>  		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
> @@ -189,6 +191,8 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
>  	if (host->ops->platform_reset_enter)
>  		host->ops->platform_reset_enter(host, mask);
>  
> +	dma = sdhci_readl(host, ESDHC_DMA_SYSCTL);


You must not access eSDHC-specific registers in generic SDHCI code


> +
>  	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
>  
>  	if (mask & SDHCI_RESET_ALL)
> @@ -214,6 +218,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
>  
>  	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
>  		sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
> +
> +	if ((dma & ESDHC_DMA_SNOOP) && (mask & SDHCI_RESET_ALL))
> +		sdhci_writel(host, dma, ESDHC_DMA_SYSCTL);
>  }
>  
>  static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);

^ permalink raw reply

* Re: linux-next: build failure after merge of the final tree (powerpc related)
From: Benjamin Herrenschmidt @ 2011-12-28 10:32 UTC (permalink / raw)
  To: Stephen Rothwell
  Cc: linux-kernel, linux-next, Paul Mackerras, Thomas Gleixner,
	linuxppc-dev
In-Reply-To: <20111228194949.ff20a609745e816c266f7d91@canb.auug.org.au>

On Wed, 2011-12-28 at 19:49 +1100, Stephen Rothwell wrote:
> Hi ,
> 
> After merging the final tree, today's linux-next build (powerpc
> allyesconfig) failed like this:
> 
> kernel/built-in.o: In function `irq_dispose_mapping':
> (.opd+0x159f0): multiple definition of `irq_dispose_mapping'
> arch/powerpc/kernel/built-in.o:(.opd+0x960): first defined here
> kernel/built-in.o: In function `irq_create_of_mapping':
> (.opd+0x15a20): multiple definition of `irq_create_of_mapping'
> arch/powerpc/kernel/built-in.o:(.opd+0x9a8): first defined here
> kernel/built-in.o: In function `.irq_create_of_mapping':
> (.text+0x147030): multiple definition of `.irq_create_of_mapping'
> arch/powerpc/kernel/built-in.o:(.text+0x9de0): first defined here
> kernel/built-in.o: In function `.irq_dispose_mapping':
> (.text+0x146f4c): multiple definition of `.irq_dispose_mapping'
> arch/powerpc/kernel/built-in.o:(.text+0x9684): first defined here
> 
> I am not sure what caused this. And have just left it broken.

Grant, is your irq remapper misbehaving ?

Cheers,
Ben.

^ permalink raw reply

* [PATCH] mmc:sdhci: restore the enabled dma when do reset all
From: Shaohui Xie @ 2011-12-28  9:41 UTC (permalink / raw)
  To: linux-mmc; +Cc: linuxppc-dev, Shaohui Xie

If dma is enabled, it'll be cleared when reset all is performed, this can
be observed on some platforms, such as P2041 which has a version 2.3
controller, but platform like P4080 which has a version 2.2 controller,
does not suffer this, so we will check if the dma is enabled, we should
restore it after reset all.

Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
---
based on http://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git,
branch 'for-linus'.

 drivers/mmc/host/sdhci.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 19ed580..22033c3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -29,6 +29,7 @@
 #include <linux/mmc/host.h>
 
 #include "sdhci.h"
+#include "sdhci-esdhc.h"
 
 #define DRIVER_NAME "sdhci"
 
@@ -176,6 +177,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	unsigned long timeout;
 	u32 uninitialized_var(ier);
+	u32 uninitialized_var(dma);
 
 	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
 		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
@@ -189,6 +191,8 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 	if (host->ops->platform_reset_enter)
 		host->ops->platform_reset_enter(host, mask);
 
+	dma = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+
 	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
 	if (mask & SDHCI_RESET_ALL)
@@ -214,6 +218,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 
 	if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
 		sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+
+	if ((dma & ESDHC_DMA_SNOOP) && (mask & SDHCI_RESET_ALL))
+		sdhci_writel(host, dma, ESDHC_DMA_SYSCTL);
 }
 
 static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
-- 
1.6.4

^ permalink raw reply related

* [PATCH] offb: Fix setting of the pseudo-palette for >8bpp
From: Benjamin Herrenschmidt @ 2011-12-28 10:10 UTC (permalink / raw)
  To: linux-fbdev; +Cc: linuxppc-dev

When using a >8bpp framebuffer, offb advertises truecolor, not directcolor,
and doesn't touch the color map even if it has a corresponding access method
for the real hardware.

Thus it needs to set the pseudo-palette with all 3 components of the color,
like other truecolor framebuffers, not with copies of the color index like
a directcolor framebuffer would do.

This went unnoticed for a long time because it's pretty hard to get offb
to kick in with anything but 8bpp (old BootX under MacOS will do that and
qemu does it).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

(resent to the right list)

BTW. Do we have a maintainer to pick up those offb patches I sent ? I'm
happy to carry them in -powerpc instead, it would actually make it easier
for me....

diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index cb163a5..24e1fc6 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -100,36 +100,32 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			  u_int transp, struct fb_info *info)
 {
 	struct offb_par *par = (struct offb_par *) info->par;
-	int i, depth;
-	u32 *pal = info->pseudo_palette;
-
-	depth = info->var.bits_per_pixel;
-	if (depth == 16)
-		depth = (info->var.green.length == 5) ? 15 : 16;
-
-	if (regno > 255 ||
-	    (depth == 16 && regno > 63) ||
-	    (depth == 15 && regno > 31))
-		return 1;
-
-	if (regno < 16) {
-		switch (depth) {
-		case 15:
-			pal[regno] = (regno << 10) | (regno << 5) | regno;
-			break;
-		case 16:
-			pal[regno] = (regno << 11) | (regno << 5) | regno;
-			break;
-		case 24:
-			pal[regno] = (regno << 16) | (regno << 8) | regno;
-			break;
-		case 32:
-			i = (regno << 8) | regno;
-			pal[regno] = (i << 16) | i;
-			break;
+
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 *pal = info->pseudo_palette;
+		u32 cr = red >> (16 - info->var.red.length);
+		u32 cg = green >> (16 - info->var.green.length);
+		u32 cb = blue >> (16 - info->var.blue.length);
+		u32 value;
+
+		if (regno >= 16)
+			return -EINVAL;
+
+		value = (cr << info->var.red.offset) |
+			(cg << info->var.green.offset) |
+			(cb << info->var.blue.offset);
+		if (info->var.transp.length > 0) {
+			u32 mask = (1 << info->var.transp.length) - 1;
+			mask <<= info->var.transp.offset;
+			value |= mask;
 		}
+		pal[regno] = value;
+		return 0;
 	}
 
+	if (regno > 255)
+		return -EINVAL;
+
 	red >>= 8;
 	green >>= 8;
 	blue >>= 8;

^ permalink raw reply related

* [PATCH] offb: Fix setting of the pseudo-palette for >8bpp
From: Benjamin Herrenschmidt @ 2011-12-28 10:08 UTC (permalink / raw)
  To: linux-fbdev-devel; +Cc: linuxppc-dev

When using a >8bpp framebuffer, offb advertises truecolor, not directcolor,
and doesn't touch the color map even if it has a corresponding access method
for the real hardware.

Thus it needs to set the pseudo-palette with all 3 components of the color,
like other truecolor framebuffers, not with copies of the color index like
a directcolor framebuffer would do.

This went unnoticed for a long time because it's pretty hard to get offb
to kick in with anything but 8bpp (old BootX under MacOS will do that and
qemu does it).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index cb163a5..24e1fc6 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -100,36 +100,32 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			  u_int transp, struct fb_info *info)
 {
 	struct offb_par *par = (struct offb_par *) info->par;
-	int i, depth;
-	u32 *pal = info->pseudo_palette;
-
-	depth = info->var.bits_per_pixel;
-	if (depth == 16)
-		depth = (info->var.green.length == 5) ? 15 : 16;
-
-	if (regno > 255 ||
-	    (depth == 16 && regno > 63) ||
-	    (depth == 15 && regno > 31))
-		return 1;
-
-	if (regno < 16) {
-		switch (depth) {
-		case 15:
-			pal[regno] = (regno << 10) | (regno << 5) | regno;
-			break;
-		case 16:
-			pal[regno] = (regno << 11) | (regno << 5) | regno;
-			break;
-		case 24:
-			pal[regno] = (regno << 16) | (regno << 8) | regno;
-			break;
-		case 32:
-			i = (regno << 8) | regno;
-			pal[regno] = (i << 16) | i;
-			break;
+
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 *pal = info->pseudo_palette;
+		u32 cr = red >> (16 - info->var.red.length);
+		u32 cg = green >> (16 - info->var.green.length);
+		u32 cb = blue >> (16 - info->var.blue.length);
+		u32 value;
+
+		if (regno >= 16)
+			return -EINVAL;
+
+		value = (cr << info->var.red.offset) |
+			(cg << info->var.green.offset) |
+			(cb << info->var.blue.offset);
+		if (info->var.transp.length > 0) {
+			u32 mask = (1 << info->var.transp.length) - 1;
+			mask <<= info->var.transp.offset;
+			value |= mask;
 		}
+		pal[regno] = value;
+		return 0;
 	}
 
+	if (regno > 255)
+		return -EINVAL;
+
 	red >>= 8;
 	green >>= 8;
 	blue >>= 8;

^ permalink raw reply related

* RE: Kernel not booting when supplying boot parameter mem
From: Arshad, Farrukh @ 2011-12-28  9:26 UTC (permalink / raw)
  To: tiejun.chen; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4EFAB4B9.1020205@windriver.com>

Pj4gUGxlYXNlIGNoZWNrIGlmIHRoZSBmb2xsb3dpbmcgY29tbWl0IGlzIGFscmVhZHkgaW4geW91
ciBrZXJuZWw6DQo+PiAtLS0tLS0NCj4+ICAgICBwb3dlcnBjOiBGaXggbWVtb3J5IGxpbWl0cyB3
aGVuIHN0YXJ0aW5nIGF0IGEgbm9uLXplcm8gYWRkcmVzcw0KDQo+PiAgICAgbWVtYmxvY2tfZW5m
b3JjZV9tZW1vcnlfbGltaXQoKSB0YWtlcyB0aGUgZGVzaXJlZCBtYXhpbXVtIHF1YW50aXR5IG9m
IG1lbW9yeQ0KPj4gICAgIHRvIGVuZCB1cCB3aXRoLCBub3QgYW4gYWRkcmVzcyBhYm92ZSB3aGlj
aCBtZW1vcnkgd2lsbCBub3QgYmUgdXNlZC4NCg0KVGhhbmtzIFRpZWp1biwgVGhpcyBmaXggd2Fz
IG5vdCB0aGVyZSBpbiB0aGUga2VybmVsIGFuZCB3aXRoIHRoaXMgZml4IG15IGJvdGgga2VybmVs
cyBhcmUgbG9hZGluZyB3aGVuIHByb3ZpZGluZyBtZW0gcGFyYW1ldGVyIGluIHRoZSBrZXJuZWwg
Ym9vdCBwYXJtYXMuDQoNClJlZ2FyZHMsDQpGYXJydWtoIEFyc2hhZA0KDQoNCi0tLS0tT3JpZ2lu
YWwgTWVzc2FnZS0tLS0tDQpGcm9tOiB0aWVqdW4uY2hlbiBbbWFpbHRvOnRpZWp1bi5jaGVuQHdp
bmRyaXZlci5jb21dIA0KU2VudDogV2VkbmVzZGF5LCBEZWNlbWJlciAyOCwgMjAxMSAxMToxOSBB
TQ0KVG86IEFyc2hhZCwgRmFycnVraA0KQ2M6IGxpbnV4cHBjLWRldkBsaXN0cy5vemxhYnMub3Jn
DQpTdWJqZWN0OiBSZTogS2VybmVsIG5vdCBib290aW5nIHdoZW4gc3VwcGx5aW5nIGJvb3QgcGFy
YW1ldGVyIG1lbQ0KDQpBcnNoYWQsIEZhcnJ1a2ggd3JvdGU6DQo+IEhpIFRpZWp1biwNCj4gDQo+
IFRoYW5rcyBmb3IgeW91ciByZXNwb25zZS4gWWVzLCBJIGFtIHJ1bm5pbmcgdHdvIGtlcm5lbHMg
b25lIG9uIGVhY2ggY29yZSBpbiBTQU1QIGNvbmZpZ3VyYXRpb24gb24gUDEwMjJSREsgYm9hcmQu
IEdpdmVuIGlzIG15IG1lbW9yeSBwYXJ0aXRpb25pbmcuIENvcmUgMCBpcyBsb2FkaW5nIGZpbmUg
YnV0IENvcmUgMSBpcyBub3QgbG9hZGluZy4gQ09ORklHX1JFTE9DQVRBQkxFIGlzIG5vdCBzZXQu
DQo+IA0KPiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCj4gQ29y
ZSAgICAgICAgICAgICAgICAgICAgICAJfCBCYXNlIEFkZHJlc3MgIAl8ICAgIFNpemUgICAgICAg
ICAgICAgICAgIAkJCXwgVWJvb3QgcGFyYW1ldGVycwkJCQkJfCBLZXJuZWwgQ29uZmlndXJhdGlv
bgkJCQkJCQkJCXwNCj4gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0K
PiBDb3JlIDAgKE1FTCBSVCBLZXJuZWwpIAl8IDB4MDAwMCwwMDAwICAgCQl8IDB4MTAwMCwwMDAw
IC0gMjU2IChNQikgICAJfGJvb3RtX2xvdyA9IDB4MDAwMCwwMDAwLCBib290bV9zaXplID0gMHgx
MDAwLDAwMDAJfCBDT05GSUdfUEhZU0lDQUxfU1RBUlQgPSAweDAwMDAsMDAwMCwgQ09ORklHX0tF
Uk5FTF9TVEFSVCA9IDB4QzAwMCwwMDAwCXwNCj4gQ29yZSAxIChMVElCIEtlcm5lbCkgICAgICAJ
fDB4MTAwMCwwMDAwICAgIAkJfCAweDA4MDAsMDAwMCAtIDEyOCAoTUIpICAgCXxib290bV9sb3cg
PSAweDEwMDAsMDAwMCwgYm9vdG1fc2l6ZSA9IDB4MDgwMCwwMDAwCXwgQ09ORklHX1BIWVNJQ0FM
X1NUQVJUID0gMHgxMDAwLDAwMDAsIENPTkZJR19LRVJORUxfU1RBUlQgPSAweEMwMDAsMDAwMAl8
DQo+IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KPiANCg0KUGxl
YXNlIGNoZWNrIGlmIHRoZSBmb2xsb3dpbmcgY29tbWl0IGlzIGFscmVhZHkgaW4geW91ciBrZXJu
ZWw6DQotLS0tLS0NCiAgICBwb3dlcnBjOiBGaXggbWVtb3J5IGxpbWl0cyB3aGVuIHN0YXJ0aW5n
IGF0IGEgbm9uLXplcm8gYWRkcmVzcw0KDQogICAgbWVtYmxvY2tfZW5mb3JjZV9tZW1vcnlfbGlt
aXQoKSB0YWtlcyB0aGUgZGVzaXJlZCBtYXhpbXVtIHF1YW50aXR5IG9mIG1lbW9yeQ0KICAgIHRv
IGVuZCB1cCB3aXRoLCBub3QgYW4gYWRkcmVzcyBhYm92ZSB3aGljaCBtZW1vcnkgd2lsbCBub3Qg
YmUgdXNlZC4NCg0KVGllanVuDQo=

^ permalink raw reply

* linux-next: build failure after merge of the final tree (powerpc related)
From: Stephen Rothwell @ 2011-12-28  8:49 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
  Cc: linux-next, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1028 bytes --]

Hi ,

After merging the final tree, today's linux-next build (powerpc
allyesconfig) failed like this:

kernel/built-in.o: In function `irq_dispose_mapping':
(.opd+0x159f0): multiple definition of `irq_dispose_mapping'
arch/powerpc/kernel/built-in.o:(.opd+0x960): first defined here
kernel/built-in.o: In function `irq_create_of_mapping':
(.opd+0x15a20): multiple definition of `irq_create_of_mapping'
arch/powerpc/kernel/built-in.o:(.opd+0x9a8): first defined here
kernel/built-in.o: In function `.irq_create_of_mapping':
(.text+0x147030): multiple definition of `.irq_create_of_mapping'
arch/powerpc/kernel/built-in.o:(.text+0x9de0): first defined here
kernel/built-in.o: In function `.irq_dispose_mapping':
(.text+0x146f4c): multiple definition of `.irq_dispose_mapping'
arch/powerpc/kernel/built-in.o:(.text+0x9684): first defined here

I am not sure what caused this. And have just left it broken.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: Kernel not booting when supplying boot parameter mem
From: tiejun.chen @ 2011-12-28  6:18 UTC (permalink / raw)
  To: Arshad, Farrukh; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <93CD5F41FDBC6042A6B449764F3B35CC050CB4E4@EU-MBX-03.mgc.mentorg.com>

Arshad, Farrukh wrote:
> Hi Tiejun,
> 
> Thanks for your response. Yes, I am running two kernels one on each core in SAMP configuration on P1022RDK board. Given is my memory partitioning. Core 0 is loading fine but Core 1 is not loading. CONFIG_RELOCATABLE is not set.
> 
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> Core                      	| Base Address  	|    Size                 			| Uboot parameters					| Kernel Configuration									|
> -----------------------------|---------------------------|-------------------------------------|------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|
> Core 0 (MEL RT Kernel) 	| 0x0000,0000   		| 0x1000,0000 - 256 (MB)   	|bootm_low = 0x0000,0000, bootm_size = 0x1000,0000	| CONFIG_PHYSICAL_START = 0x0000,0000, CONFIG_KERNEL_START = 0xC000,0000	|
> Core 1 (LTIB Kernel)      	|0x1000,0000    		| 0x0800,0000 - 128 (MB)   	|bootm_low = 0x1000,0000, bootm_size = 0x0800,0000	| CONFIG_PHYSICAL_START = 0x1000,0000, CONFIG_KERNEL_START = 0xC000,0000	|
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> 

Please check if the following commit is already in your kernel:
------
    powerpc: Fix memory limits when starting at a non-zero address

    memblock_enforce_memory_limit() takes the desired maximum quantity of memory
    to end up with, not an address above which memory will not be used.

Tiejun

^ permalink raw reply

* RE: Kernel not booting when supplying boot parameter mem
From: Arshad, Farrukh @ 2011-12-28  6:05 UTC (permalink / raw)
  To: tiejun.chen; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4EF9A6F2.8020708@windriver.com>

SGkgVGllanVuLA0KDQpUaGFua3MgZm9yIHlvdXIgcmVzcG9uc2UuIFllcywgSSBhbSBydW5uaW5n
IHR3byBrZXJuZWxzIG9uZSBvbiBlYWNoIGNvcmUgaW4gU0FNUCBjb25maWd1cmF0aW9uIG9uIFAx
MDIyUkRLIGJvYXJkLiBHaXZlbiBpcyBteSBtZW1vcnkgcGFydGl0aW9uaW5nLiBDb3JlIDAgaXMg
bG9hZGluZyBmaW5lIGJ1dCBDb3JlIDEgaXMgbm90IGxvYWRpbmcuIENPTkZJR19SRUxPQ0FUQUJM
RSBpcyBub3Qgc2V0Lg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0NCkNvcmUgICAgICAgICAgICAgICAgICAgICAgCXwgQmFzZSBBZGRyZXNzICAJfCAgICBTaXpl
ICAgICAgICAgICAgICAgICAJCQl8IFVib290IHBhcmFtZXRlcnMJCQkJCXwgS2VybmVsIENvbmZp
Z3VyYXRpb24JCQkJCQkJCQl8DQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS18DQpDb3JlIDAgKE1FTCBSVCBLZXJuZWwpIAl8IDB4MDAwMCwwMDAwICAgCQl8IDB4MTAwMCww
MDAwIC0gMjU2IChNQikgICAJfGJvb3RtX2xvdyA9IDB4MDAwMCwwMDAwLCBib290bV9zaXplID0g
MHgxMDAwLDAwMDAJfCBDT05GSUdfUEhZU0lDQUxfU1RBUlQgPSAweDAwMDAsMDAwMCwgQ09ORklH
X0tFUk5FTF9TVEFSVCA9IDB4QzAwMCwwMDAwCXwNCkNvcmUgMSAoTFRJQiBLZXJuZWwpICAgICAg
CXwweDEwMDAsMDAwMCAgICAJCXwgMHgwODAwLDAwMDAgLSAxMjggKE1CKSAgIAl8Ym9vdG1fbG93
ID0gMHgxMDAwLDAwMDAsIGJvb3RtX3NpemUgPSAweDA4MDAsMDAwMAl8IENPTkZJR19QSFlTSUNB
TF9TVEFSVCA9IDB4MTAwMCwwMDAwLCBDT05GSUdfS0VSTkVMX1NUQVJUID0gMHhDMDAwLDAwMDAJ
fA0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNClJlZ2FyZHMs
DQpGYXJydWtoIEFyc2hhZA0KDQotLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KRnJvbTogdGll
anVuLmNoZW4gW21haWx0bzp0aWVqdW4uY2hlbkB3aW5kcml2ZXIuY29tXSANClNlbnQ6IFR1ZXNk
YXksIERlY2VtYmVyIDI3LCAyMDExIDQ6MDggUE0NClRvOiBBcnNoYWQsIEZhcnJ1a2gNCkNjOiBs
aW51eHBwYy1kZXZAbGlzdHMub3psYWJzLm9yZw0KU3ViamVjdDogUmU6IEtlcm5lbCBub3QgYm9v
dGluZyB3aGVuIHN1cHBseWluZyBib290IHBhcmFtZXRlciBtZW0NCg0KQXJzaGFkLCBGYXJydWto
IHdyb3RlOg0KPiBHcmVldGluZ3MgQWxsLA0KPiANCj4gSSBoYXZlIGEgYmFzaWMgcXVlc3Rpb24u
IEkgaGF2ZSA1MTIgTUIgbWVtb3J5LiBJIHdhbnQgbXkga2VybmVsIHRvIHVzZSBvbmx5IGxhc3Qg
MTI4IE1CIG9mIG1lbW9yeSBzdGFydGluZyBmcm9tIGFkZHJlc3MgMHgxMDAwMDAwMC4gSSBoYXZl
IGNvbmZpZ3VyZWQgdGhlIGtlcm5lbCBDT05GSUdfUEhZU0lDQUxfU1RBUlQ9MHgxMDAwMDAwMCBh
bmQgaW4ga2VybmVsIGJvb3QgcGFyYW1ldGVyIEkgaGF2ZSBzZXQgbWVtPTEyOE0uIEluIHRoaXMg
c2NlbmFyaW8gbXkga2VybmVsIGlzIG5vdCBib290aW5nIGFuZCBpdCBqdXN0IHN0dWNrIGFmdGVy
IHVuY29tcHJlc3NpbmcgaXQuIElmIEkgZG8gbm90IHByb3ZpZGUgbWVtPTEyOE0gYm9vdCBwYXJh
bWV0ZXIgbXkga2VybmVsIGJvb3RzIGZpbmUsIGJ1dCBpbiB0aGF0IGNhc2UgSSBjYW4gbm90IHJl
c3RyaWN0IGtlcm5lbCB0byB1c2Ugb25seSAxMjhNIG1lbW9yeS4gV2h5IHN1cHBseWluZyBtZW09
MTI4TSBjYXVzaW5nIGtlcm5lbCB0byBmYWlsLg0KPiANCg0KQW55IGtlcm5lbCBvcHRpb24gZWxz
ZSBpcyBjb25maWd1cmVkLCBzdWNoIGFzIENPTkZJR19LRVJORUxfU1RBUlQgYW5kIENPTkZJR19S
RUxPQ0FUQUJMRT8NCg0KT3IgYW55IHUtYm9vdCBhcmd1bWVudCBpcyByZWNvbmZpZ3VyZWQsIHN1
Y2ggYXMgJ2Jvb3RtX2xvdycsICdib290bV9tYXBzaXplJyBhbmQgJ2Jvb3RtX3NpemUnLg0KDQpU
aWVqdW4NCg==

^ permalink raw reply

* linux-next: manual merge of the driver-core tree with the powerpc tree
From: Stephen Rothwell @ 2011-12-28  5:51 UTC (permalink / raw)
  To: Greg KH
  Cc: Deepthi Dharwar, Trinabh Gupta, Kay Sievers, linux-kernel,
	linux-next, Paul Mackerras, linuxppc-dev, Arun R Bharadwaj

[-- Attachment #1: Type: text/plain, Size: 3429 bytes --]

Hi Greg,

Today's linux-next merge of the driver-core tree got a conflict in
arch/powerpc/kernel/sysfs.c between commit 595fe91447b0 ("powerpc: Export
PIR data through sysfs") from the powerpc tree and commits 8a25a2fd126c
("cpu: convert 'cpu' and 'machinecheck' sysdev_class to a regular
subsystem") and 707827f3387d ("powerpc/cpuidle: cpuidle driver for
pSeries") from the driver-core tree.

I fixed it up (see below) and can carry the fix as necessary.
-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

diff --cc arch/powerpc/kernel/sysfs.c
index 6fdf5ff,5e7c165..0000000
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@@ -51,8 -50,7 +51,8 @@@ static ssize_t store_smt_snooze_delay(s
  	if (ret != 1)
  		return -EINVAL;
  
- 	per_cpu(smt_snooze_delay, cpu->sysdev.id) = snooze;
+ 	per_cpu(smt_snooze_delay, cpu->dev.id) = snooze;
 +	update_smt_snooze_delay(snooze);
  
  	return count;
  }
@@@ -179,13 -177,11 +179,13 @@@ SYSFS_PMCSETUP(mmcra, SPRN_MMCRA)
  SYSFS_PMCSETUP(purr, SPRN_PURR);
  SYSFS_PMCSETUP(spurr, SPRN_SPURR);
  SYSFS_PMCSETUP(dscr, SPRN_DSCR);
 +SYSFS_PMCSETUP(pir, SPRN_PIR);
  
- static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
- static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
- static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
- static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
- static SYSDEV_ATTR(pir, 0400, show_pir, NULL);
+ static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
+ static DEVICE_ATTR(spurr, 0600, show_spurr, NULL);
+ static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
+ static DEVICE_ATTR(purr, 0600, show_purr, store_purr);
++static DEVICE_ATTR(pir, 0400, show_pir, NULL);
  
  unsigned long dscr_default = 0;
  EXPORT_SYMBOL(dscr_default);
@@@ -386,19 -381,16 +385,19 @@@ static void __cpuinit register_cpu_onli
  
  #ifdef CONFIG_PPC64
  	if (cpu_has_feature(CPU_FTR_MMCRA))
- 		sysdev_create_file(s, &attr_mmcra);
+ 		device_create_file(s, &dev_attr_mmcra);
  
  	if (cpu_has_feature(CPU_FTR_PURR))
- 		sysdev_create_file(s, &attr_purr);
+ 		device_create_file(s, &dev_attr_purr);
  
  	if (cpu_has_feature(CPU_FTR_SPURR))
- 		sysdev_create_file(s, &attr_spurr);
+ 		device_create_file(s, &dev_attr_spurr);
  
  	if (cpu_has_feature(CPU_FTR_DSCR))
- 		sysdev_create_file(s, &attr_dscr);
+ 		device_create_file(s, &dev_attr_dscr);
 +
 +	if (cpu_has_feature(CPU_FTR_PPCAS_ARCH_V2))
- 		sysdev_create_file(s, &attr_pir);
++		device_create_file(s, &dev_attr_pir);
  #endif /* CONFIG_PPC64 */
  
  	cacheinfo_cpu_online(cpu);
@@@ -459,19 -451,16 +458,19 @@@ static void unregister_cpu_online(unsig
  
  #ifdef CONFIG_PPC64
  	if (cpu_has_feature(CPU_FTR_MMCRA))
- 		sysdev_remove_file(s, &attr_mmcra);
+ 		device_remove_file(s, &dev_attr_mmcra);
  
  	if (cpu_has_feature(CPU_FTR_PURR))
- 		sysdev_remove_file(s, &attr_purr);
+ 		device_remove_file(s, &dev_attr_purr);
  
  	if (cpu_has_feature(CPU_FTR_SPURR))
- 		sysdev_remove_file(s, &attr_spurr);
+ 		device_remove_file(s, &dev_attr_spurr);
  
  	if (cpu_has_feature(CPU_FTR_DSCR))
- 		sysdev_remove_file(s, &attr_dscr);
+ 		device_remove_file(s, &dev_attr_dscr);
 +
 +	if (cpu_has_feature(CPU_FTR_PPCAS_ARCH_V2))
- 		sysdev_remove_file(s, &attr_pir);
++		device_remove_file(s, &dev_attr_pir);
  #endif /* CONFIG_PPC64 */
  
  	cacheinfo_cpu_offline(cpu);

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: p1020 unstable with 3.2
From: Benjamin Herrenschmidt @ 2011-12-28  5:01 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Scott Wood, linuxppc-dev, Fleming Andy-AFLEMING
In-Reply-To: <025812DC-AB8E-4B60-9B16-50C3DE4DD561@suse.de>

On Sun, 2011-12-25 at 11:48 +0100, Alexander Graf wrote:
> On 24.12.2011, at 07:53, Benjamin Herrenschmidt wrote:
> 
> > On Fri, 2011-12-23 at 17:54 +0100, Alexander Graf wrote:
> >> Hi guys,
> >> 
> >> While trying to test my latest patch queue for ppc kvm, I realized
> >> that even though the device trees got updated, the p1020 box still is
> >> unstable. The trace below is the one I've seen the most. It only
> >> occurs during network I/O which happens a lot on that box, since I'm
> >> running it using NFS root.
> >> 
> >> As for configuration, I use kumar's "merge" branch from today and the
> >> p1020rdb.dts device tree provided in that tree.
> >> 
> >> The last known good configuration I'm aware of is 3.0.
> >> 
> >> Any ideas what's going wrong here?
> > 
> > Try SLAB instead of SLUB and let me know. It -could- be a bogon in SLUB
> > that should be fixed upstream now but I think did hit 3.2
> 
> Yup, things seem a lot more stable with SLAB now :).

BTW. Fix for slub should be upstream:

42d623a8cd08eb93ab221d22cee5a62618895bbf

Cheers,
Ben.

^ permalink raw reply

* [PATCH 1/2] powerpc/85xx: Add P1024rdb board support
From: b29983 @ 2011-12-28  3:41 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Tang Yuantian, Jin Qing, r66093, Tang Yuantian

From: Tang Yuantian <B29983@freescale.com>

The p1024rdb has the similar feature as the p1020rdb. Therefore, p1024rdb use
the same platform file as the p1/p2 rdb board.
Overview of P2020RDB platform
	- DDR3 1G
	- NOR flash 16M
	- 3 Ethernet interfaces
	- NAND Flash 32M
	- SPI EEPROM 16M
	- SD/MMC
	- 2 USB ports
	- 4 TDM ports

Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
---
 arch/powerpc/platforms/85xx/mpc85xx_rdb.c |   26 +++++++++++++++++++++++++-
 1 files changed, 25 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index 9feccbb..c436679 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -1,7 +1,7 @@
 /*
  * MPC85xx RDB Board Setup
  *
- * Copyright 2009 Freescale Semiconductor Inc.
+ * Copyright 2009-2011 Freescale Semiconductor Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -113,6 +113,7 @@ static void __init mpc85xx_rdb_setup_arch(void)
 
 machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices);
 machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices);
+machine_device_initcall(p1024_rdb, mpc85xx_common_publish_devices);
 
 /*
  * Called very early, device-tree isn't unflattened
@@ -135,6 +136,15 @@ static int __init p1020_rdb_probe(void)
 	return 0;
 }
 
+static int __init p1024_rdb_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "fsl,P1024RDB"))
+		return 1;
+	return 0;
+}
+
 define_machine(p2020_rdb) {
 	.name			= "P2020 RDB",
 	.probe			= p2020_rdb_probe,
@@ -162,3 +172,17 @@ define_machine(p1020_rdb) {
 	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= udbg_progress,
 };
+
+define_machine(p1024_rdb) {
+	.name           = "P1024 RDB",
+	.probe          = p1024_rdb_probe,
+	.setup_arch     = mpc85xx_rdb_setup_arch,
+	.init_IRQ       = mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus  = fsl_pcibios_fixup_bus,
+#endif
+	.get_irq        = mpic_get_irq,
+	.restart        = fsl_rstcr_restart,
+	.calibrate_decr     = generic_calibrate_decr,
+	.progress       = udbg_progress,
+};
-- 
1.6.4

^ permalink raw reply related

* [PATCH 2/2] powerpc/85xx: Adds Support for P2020RDB-PC board
From: b29983 @ 2011-12-28  3:41 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Tang Yuantian, r66093, Poonam Aggrwal, Prabhakar Kushwaha
In-Reply-To: <1325043707-23206-1-git-send-email-b29983@freescale.com>

From: Tang Yuantian <B29983@freescale.com>

P2020RDB-PC Board shares the same design(PCB) as P102x RDB style platforms.
The difference between this platform and the already existing P2020RDB
is mainly with respect to DDR. The P2020RDB-PC has a DDR3 memory.
The P2020RDB-PC also has a CPLD device connected to local bus.

The main differences from the P102x RDB-PC is 64-bit DDR and SYSCLK of
100Mhz.

Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
Signed-off-by: Tang Yuantian <b29983@freescale.com>
---
 arch/powerpc/platforms/85xx/mpc85xx_rdb.c |   24 ++++++++++++++++++++++++
 1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index c436679..576cef2 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
@@ -114,6 +114,7 @@ static void __init mpc85xx_rdb_setup_arch(void)
 machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices);
 machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices);
 machine_device_initcall(p1024_rdb, mpc85xx_common_publish_devices);
+machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices);
 
 /*
  * Called very early, device-tree isn't unflattened
@@ -145,6 +146,15 @@ static int __init p1024_rdb_probe(void)
 	return 0;
 }
 
+static int __init p2020_rdb_pc_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "fsl,P2020RDB-PC"))
+		return 1;
+	return 0;
+}
+
 define_machine(p2020_rdb) {
 	.name			= "P2020 RDB",
 	.probe			= p2020_rdb_probe,
@@ -185,4 +195,18 @@ define_machine(p1024_rdb) {
 	.restart        = fsl_rstcr_restart,
 	.calibrate_decr     = generic_calibrate_decr,
 	.progress       = udbg_progress,
+}
+
+define_machine(p2020_rdb_pc) {
+	.name			= "P2020RDB-PC",
+	.probe			= p2020_rdb_pc_probe,
+	.setup_arch		= mpc85xx_rdb_setup_arch,
+	.init_IRQ		= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
 };
-- 
1.6.4

^ permalink raw reply related

* NAND or other high density storage on MPC8260
From: Felix Radensky @ 2011-12-27 19:37 UTC (permalink / raw)
  To: linuxppc-dev@ozlabs.org

Hi,

On a custom board based on MPC8260 I have to replace end-of-life
2GB Sandisk mDoc H3 by other storage device of comparable density.
The most natural choice seems to be NAND connected to UPM.
However FSL UPM NAND driver in mainline does not support MPC82xx.
I have several questions in this regard:

1. How difficult would be to modify mainline UPM NAND driver to work
     on MPC8260 ?
2. What other options are feasible and cost effective? I was thinking 
about
     SPI NOR and Compact Flash on UPM.

Thanks.

Felix.

^ permalink raw reply

* Re: [PATCH] net/ucc_geth: some fix in current kernel
From: David Miller @ 2011-12-27 17:59 UTC (permalink / raw)
  To: X.Xie; +Cc: netdev, linuxppc-dev
In-Reply-To: <1324979328-32081-1-git-send-email-X.Xie@freescale.com>

From: Xie Xiaobo <X.Xie@freescale.com>
Date: Tue, 27 Dec 2011 17:48:48 +0800

> * Revert commit "ucc_geth: Fix hangs after switching from full to half duplex"
>   This commit impacted the driver in all link state change more than
>   duplex change.
> * Change some parameters.
>   Increased the BD ring length.
> 
> Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com>
> Signed-off-by: Xie Xiaobo <X.Xie@freescale.com>

Please, one major change per patch.

^ permalink raw reply

* RE: [PATCH 00/14] DMA-mapping framework redesign preparation
From: James Bottomley @ 2011-12-27 17:53 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-mips, linux-ia64, linux-sh, linux-mm, sparclinux,
	linux-arch, 'Stephen Rothwell', 'Jonathan Corbet',
	x86, 'Arnd Bergmann', 'Matthew Wilcox',
	microblaze-uclinux, linaro-mm-sig, Andrzej Pietrasiewicz,
	'Thomas Gleixner', linux-arm-kernel, discuss,
	linux-kernel, 'Kyungmin Park', linux-alpha,
	'Andrew Morton', linuxppc-dev
In-Reply-To: <000901ccc471$15db8bc0$4192a340$%szyprowski@samsung.com>

On Tue, 2011-12-27 at 09:25 +0100, Marek Szyprowski wrote:
[...]
> > > Usually these drivers don't touch the buffer data at all, so the mapping
> > > in kernel virtual address space is not needed. We can introduce
> > > DMA_ATTRIB_NO_KERNEL_MAPPING attribute which lets kernel to skip/ignore
> > > creation of kernel virtual mapping. This way we can save previous
> > > vmalloc area and simply some mapping operation on a few architectures.
> > 
> > I really think this wants to be a separate function.  dma_alloc_coherent
> > is for allocating memory to be shared between the kernel and a driver;
> > we already have dma_map_sg for mapping userspace I/O as an alternative
> > interface.  This feels like it's something different again rather than
> > an option to dma_alloc_coherent.
> 
> That is just a starting point for the discussion. 
> 
> I thought about this API a bit and came to conclusion that there is no much
> difference between a dma_alloc_coherent which creates a mapping in kernel
> virtual space and the one that does not. It is just a hint from the driver
> that it will not use that mapping at all. Of course this attribute makes sense
> only together with adding a dma_mmap_attrs() call, because otherwise drivers
> won't be able to get access to the buffer data.

This depends.  On Virtually indexed systems like PA-RISC, there are two
ways of making a DMA range coherent.  One is to make the range uncached.
This is incredibly slow and not what we do by default, but it can be
used to make multiple mappings coherent.  The other is to load the
virtual address up as a coherence index into the IOMMU.  This makes it a
full peer in the coherence process, but means we can only designate a
single virtual range to be coherent (not multiple mappings unless they
happen to be congruent).  Perhaps it doesn't matter that much, since I
don't see a use for this on PA, but if any other architecture works the
same, you'd have to designate a single mapping as the coherent one and
essentially promise not to use the other mapping if we followed our
normal coherence protocols.

Obviously, the usual range we currently make coherent is the kernel
mapping (that's actually the only virtual address we have by the time
we're deep in the iommu code), so designating a different virtual
address would need some surgery to the guts of the iommu code.

James

^ permalink raw reply

* [PATCH 2/2][v2] NAND Machine support for Integrated Flash Controller
From: Prabhakar Kushwaha @ 2011-12-27 12:09 UTC (permalink / raw)
  To: linuxppc-dev, linux-mtd
  Cc: Scott Wood, Dipen Dudhat, Liu Shuo, Prabhakar Kushwaha

Integrated Flash Controller(IFC) can be used to hook NAND Flash
chips using NAND Flash Machine available on it.

Signed-off-by: Dipen Dudhat <Dipen.Dudhat@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
---
 Based upon git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git (branch next)

 Tested on P1010RDB

 Changes for v2: Ported IFC driver for linux-3.2.0-rc3 
	- Use chip->bbt_options for BBT
	- Use mtd_device_parse_register instead of old parse_mtd_partitions

 drivers/mtd/nand/Kconfig        |   10 +
 drivers/mtd/nand/Makefile       |    1 +
 drivers/mtd/nand/fsl_ifc_nand.c | 1070 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 1081 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/nand/fsl_ifc_nand.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index cce7b70..2fff5c7 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -463,6 +463,16 @@ config MTD_NAND_FSL_ELBC
 	  Enabling this option will enable you to use this to control
 	  external NAND devices.
 
+config MTD_NAND_FSL_IFC
+	tristate "NAND support for Freescale IFC controller"
+	depends on MTD_NAND && FSL_SOC
+	select FSL_IFC
+	help
+	  Various Freescale chips e.g P1010, include a NAND Flash machine
+	  with built-in hardware ECC capabilities.
+	  Enabling this option will enable you to use this to control
+	  external NAND devices.
+
 config MTD_NAND_FSL_UPM
 	tristate "Support for NAND on Freescale UPM"
 	depends on PPC_83xx || PPC_85xx
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 618f4ba..19bc8cb 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_MTD_ALAUDA)		+= alauda.o
 obj-$(CONFIG_MTD_NAND_PASEMI)		+= pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)		+= orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)		+= fsl_elbc_nand.o
+obj-$(CONFIG_MTD_NAND_FSL_IFC)		+= fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)		+= fsl_upm.o
 obj-$(CONFIG_MTD_NAND_SH_FLCTL)		+= sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC)		+= mxc_nand.o
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
new file mode 100644
index 0000000..8475b88
--- /dev/null
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -0,0 +1,1070 @@
+/*
+ * Freescale Integrated Flash Controller NAND driver
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/fsl_ifc.h>
+
+#define ERR_BYTE		0xFF /* Value returned for read
+					bytes when read failed	*/
+#define IFC_TIMEOUT_MSECS	500  /* Maximum number of mSecs to wait
+					for IFC NAND Machine	*/
+
+struct fsl_ifc_ctrl;
+
+/* mtd information per set */
+struct fsl_ifc_mtd {
+	struct mtd_info mtd;
+	struct nand_chip chip;
+	struct fsl_ifc_ctrl *ctrl;
+
+	struct device *dev;
+	int bank;		/* Chip select bank number		*/
+	unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */
+	u8 __iomem *vbase;      /* Chip select base virtual address	*/
+};
+
+/* overview of the fsl ifc controller */
+struct fsl_ifc_nand_ctrl {
+	struct nand_hw_control controller;
+	struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT];
+
+	u8 __iomem *addr;	/* Address of assigned IFC buffer	*/
+	unsigned int page;	/* Last page written to / read from	*/
+	unsigned int read_bytes;/* Number of bytes read during command	*/
+	unsigned int column;	/* Saved column from SEQIN		*/
+	unsigned int index;	/* Pointer to next byte to 'read'	*/
+	unsigned int oob;	/* Non zero if operating on OOB data	*/
+	unsigned int eccread;	/* Non zero for a full-page ECC read	*/
+	unsigned int counter;	/* counter for the initializations	*/
+};
+
+static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
+
+/* 512-byte page with 4-bit ECC, 8-bit */
+static struct nand_ecclayout oob_512_8bit_ecc4 = {
+	.eccbytes = 8,
+	.eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+	.oobfree = { {0, 5}, {6, 2} },
+};
+
+/* 512-byte page with 4-bit ECC, 16-bit */
+static struct nand_ecclayout oob_512_16bit_ecc4 = {
+	.eccbytes = 8,
+	.eccpos = {8, 9, 10, 11, 12, 13, 14, 15},
+	.oobfree = { {2, 6}, },
+};
+
+/* 2048-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_2048_ecc4 = {
+	.eccbytes = 32,
+	.eccpos = {
+		8, 9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39,
+	},
+	.oobfree = { {2, 6}, {40, 24} },
+};
+
+/* 4096-byte page size with 4-bit ECC */
+static struct nand_ecclayout oob_4096_ecc4 = {
+	.eccbytes = 64,
+	.eccpos = {
+		8, 9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39,
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63,
+		64, 65, 66, 67, 68, 69, 70, 71,
+	},
+	.oobfree = { {2, 6}, {72, 56} },
+};
+
+/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */
+static struct nand_ecclayout oob_4096_ecc8 = {
+	.eccbytes = 128,
+	.eccpos = {
+		8, 9, 10, 11, 12, 13, 14, 15,
+		16, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 29, 30, 31,
+		32, 33, 34, 35, 36, 37, 38, 39,
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63,
+		64, 65, 66, 67, 68, 69, 70, 71,
+		72, 73, 74, 75, 76, 77, 78, 79,
+		80, 81, 82, 83, 84, 85, 86, 87,
+		88, 89, 90, 91, 92, 93, 94, 95,
+		96, 97, 98, 99, 100, 101, 102, 103,
+		104, 105, 106, 107, 108, 109, 110, 111,
+		112, 113, 114, 115, 116, 117, 118, 119,
+		120, 121, 122, 123, 124, 125, 126, 127,
+		128, 129, 130, 131, 132, 133, 134, 135,
+	},
+	.oobfree = { {2, 6}, {136, 82} },
+};
+
+
+/*
+ * Generic flash bbt descriptors
+ */
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = bbt_pattern,
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE |
+		   NAND_BBT_2BIT | NAND_BBT_VERSION,
+	.offs =	2, /* 0 on 8-bit small page */
+	.len = 4,
+	.veroffs = 6,
+	.maxblocks = 4,
+	.pattern = mirror_pattern,
+};
+
+/*
+ * Set up the IFC hardware block and page address fields, and the ifc nand
+ * structure addr field to point to the correct IFC buffer in memory
+ */
+static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	int buf_num;
+
+	ifc_nand_ctrl->page = page_addr;
+	/* Program ROW0/COL0 */
+	out_be32(&ifc->ifc_nand.row0, page_addr);
+	out_be32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column);
+
+	buf_num = page_addr & priv->bufnum_mask;
+
+	ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2);
+	ifc_nand_ctrl->index = column;
+
+	/* for OOB data point to the second half of the buffer */
+	if (oob)
+		ifc_nand_ctrl->index += mtd->writesize;
+}
+
+static int is_blank(struct mtd_info *mtd, unsigned int bufnum)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2);
+	u32 __iomem *mainarea = (u32 *)addr;
+	u8 __iomem *oob = addr + mtd->writesize;
+	int i;
+
+	for (i = 0; i < mtd->writesize / 4; i++) {
+		if (__raw_readl(&mainarea[i]) != 0xffffffff)
+			return 0;
+	}
+
+	for (i = 0; i < chip->ecc.layout->eccbytes; i++) {
+		int pos = chip->ecc.layout->eccpos[i];
+
+		if (__raw_readb(&oob[pos]) != 0xff)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* returns nonzero if entire page is blank */
+static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
+			  u32 *eccstat, unsigned int bufnum)
+{
+	u32 reg = eccstat[bufnum / 4];
+	int errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
+
+	if (errors == 15) { /* uncorrectable */
+		/* Blank pages fail hw ECC checks */
+		if (is_blank(mtd, bufnum))
+			return 1;
+
+		/*
+		 * We disable ECCER reporting in hardware due to
+		 * erratum IFC-A002770 -- so report it now if we
+		 * see an uncorrectable error in ECCSTAT.
+		 */
+		ctrl->nand_stat |= IFC_NAND_EVTER_STAT_ECCER;
+	} else if (errors > 0) {
+		mtd->ecc_stats.corrected += errors;
+	}
+
+	return 0;
+}
+
+/*
+ * execute IFC NAND command and wait for it to complete
+ */
+static void fsl_ifc_run_command(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	u32 eccstat[4];
+	int i;
+
+	/* set the chip select for NAND Transaction */
+	out_be32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
+
+	dev_vdbg(priv->dev,
+			"%s: fir0=%08x fcr0=%08x\n",
+			__func__,
+			in_be32(&ifc->ifc_nand.nand_fir0),
+			in_be32(&ifc->ifc_nand.nand_fcr0));
+
+	ctrl->nand_stat = 0;
+
+	/* start read/write seq */
+	out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
+
+	/* wait for command complete flag or timeout */
+	wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
+			   IFC_TIMEOUT_MSECS * HZ/1000);
+
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER)
+		dev_err(priv->dev, "NAND Flash Timeout Error\n");
+	if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
+		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+
+	if (nctrl->eccread) {
+		int bufperpage = mtd->writesize / 512;
+		int bufnum = (nctrl->page & priv->bufnum_mask) * bufperpage;
+		int bufnum_end = bufnum + bufperpage - 1;
+
+		for (i = bufnum / 4; i <= bufnum_end / 4; i++)
+			eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]);
+
+		for (i = bufnum; i <= bufnum_end; i++) {
+			if (check_read_ecc(mtd, ctrl, eccstat, i))
+				break;
+		}
+
+		nctrl->eccread = 0;
+	}
+}
+
+static void fsl_ifc_do_read(struct nand_chip *chip,
+			    int oob,
+			    struct mtd_info *mtd)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+	/* Program FIR/IFC_NAND_FCR0 for Small/Large page */
+	if (mtd->writesize > 512) {
+		out_be32(&ifc->ifc_nand.nand_fir0,
+			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+			 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+			 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+			(NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			(NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+	} else {
+		out_be32(&ifc->ifc_nand.nand_fir0,
+			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			 (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
+			 (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+
+		if (oob)
+			out_be32(&ifc->ifc_nand.nand_fcr0,
+				 NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
+		else
+			out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
+	}
+}
+
+/* cmdfunc send commands to the IFC NAND Machine */
+static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
+			     int column, int page_addr) {
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+	/* clear the read buffer */
+	ifc_nand_ctrl->read_bytes = 0;
+	if (command != NAND_CMD_PAGEPROG)
+		ifc_nand_ctrl->index = 0;
+
+	switch (command) {
+	/* READ0 read the entire buffer to use hardware ECC. */
+	case NAND_CMD_READ0:
+		out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+		set_addr(mtd, 0, page_addr, 0);
+
+		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+		ifc_nand_ctrl->index += column;
+
+		if (chip->ecc.mode == NAND_ECC_HW)
+			ifc_nand_ctrl->eccread = 1;
+
+		fsl_ifc_do_read(chip, 0, mtd);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		out_be32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column);
+		set_addr(mtd, column, page_addr, 1);
+
+		ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
+
+		fsl_ifc_do_read(chip, 1, mtd);
+		fsl_ifc_run_command(mtd);
+
+		return;
+
+	/* READID must read all 8 possible bytes */
+	case NAND_CMD_READID:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+				(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				(IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+				(IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
+		/* 8 bytes for manuf, device and exts */
+		out_be32(&ifc->ifc_nand.nand_fbcr, 8);
+		ifc_nand_ctrl->read_bytes = 8;
+
+		set_addr(mtd, 0, 0, 0);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		set_addr(mtd, 0, page_addr, 0);
+		return;
+
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+			 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+			 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+			 (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
+
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+			 (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+			 (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
+
+		out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+		ifc_nand_ctrl->read_bytes = 0;
+		fsl_ifc_run_command(mtd);
+		return;
+
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN: {
+		u32 nand_fcr0;
+		ifc_nand_ctrl->column = column;
+		ifc_nand_ctrl->oob = 0;
+
+		if (mtd->writesize > 512) {
+			nand_fcr0 =
+				(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
+				(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT);
+
+			out_be32(&ifc->ifc_nand.nand_fir0,
+				 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+				 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				 (IFC_FIR_OP_WBCD  << IFC_NAND_FIR0_OP3_SHIFT) |
+				 (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT));
+		} else {
+			nand_fcr0 = ((NAND_CMD_PAGEPROG <<
+					IFC_NAND_FCR0_CMD1_SHIFT) |
+				    (NAND_CMD_SEQIN <<
+					IFC_NAND_FCR0_CMD2_SHIFT));
+
+			out_be32(&ifc->ifc_nand.nand_fir0,
+				 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				 (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+				 (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+				 (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+				 (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
+			out_be32(&ifc->ifc_nand.nand_fir1,
+				 (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
+
+			if (column >= mtd->writesize) {
+				/* OOB area --> READOOB */
+				column -= mtd->writesize;
+				nand_fcr0 |= NAND_CMD_READOOB <<
+						IFC_NAND_FCR0_CMD0_SHIFT;
+				ifc_nand_ctrl->oob = 1;
+			} else if (column < 256)
+				/* First 256 bytes --> READ0 */
+				nand_fcr0 |=
+				NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT;
+			else
+				/* Second 256 bytes --> READ1 */
+				nand_fcr0 |=
+				NAND_CMD_READ1 << IFC_NAND_FCR0_CMD0_SHIFT;
+		}
+
+		out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
+		set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
+		return;
+	}
+
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG: {
+		int full_page;
+		if (ifc_nand_ctrl->oob) {
+			out_be32(&ifc->ifc_nand.nand_fbcr,
+					ifc_nand_ctrl->index);
+			full_page = 0;
+		} else {
+			out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+			full_page = 1;
+		}
+
+		fsl_ifc_run_command(mtd);
+		return;
+	}
+
+	case NAND_CMD_STATUS:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+				(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+				(IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
+		out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+		set_addr(mtd, 0, 0, 0);
+		ifc_nand_ctrl->read_bytes = 1;
+
+		fsl_ifc_run_command(mtd);
+
+		/*
+		 * The chip always seems to report that it is
+		 * write-protected, even when it is not.
+		 */
+		setbits8(ifc_nand_ctrl->addr, NAND_STATUS_WP);
+		return;
+
+	case NAND_CMD_RESET:
+		out_be32(&ifc->ifc_nand.nand_fir0,
+				IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
+		out_be32(&ifc->ifc_nand.nand_fcr0,
+				NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
+		fsl_ifc_run_command(mtd);
+		return;
+
+	default:
+		dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n",
+					__func__, command);
+	}
+}
+
+static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip)
+{
+	/* The hardware does not seem to support multiple
+	 * chips per bank.
+	 */
+}
+
+/*
+ * Write buf to the IFC NAND Controller Data Buffer
+ */
+static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	unsigned int bufsize = mtd->writesize + mtd->oobsize;
+
+	if (len <= 0) {
+		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+		return;
+	}
+
+	if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) {
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %u available)\n",
+			__func__, len, bufsize - ifc_nand_ctrl->index);
+		len = bufsize - ifc_nand_ctrl->index;
+	}
+
+	memcpy_toio(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index], buf, len);
+	ifc_nand_ctrl->index += len;
+}
+
+/*
+ * Read a byte from either the IFC hardware buffer
+ * read function for 8-bit buswidth
+ */
+static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes)
+		return in_8(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index++]);
+
+	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+	return ERR_BYTE;
+}
+
+/*
+ * Read two bytes from the IFC hardware buffer
+ * read function for 16-bit buswith
+ */
+static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	uint16_t data;
+
+	/*
+	 * If there are still bytes in the IFC buffer, then use the
+	 * next byte.
+	 */
+	if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) {
+		data = in_be16((uint16_t *)&ifc_nand_ctrl->
+					addr[ifc_nand_ctrl->index]);
+		ifc_nand_ctrl->index += 2;
+		return (uint8_t) data;
+	}
+
+	dev_err(priv->dev, "%s: beyond end of buffer\n", __func__);
+	return ERR_BYTE;
+}
+
+/*
+ * Read from the IFC Controller Data Buffer
+ */
+static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	int avail;
+
+	if (len < 0) {
+		dev_err(priv->dev, "%s: len %d bytes", __func__, len);
+		return;
+	}
+
+	avail = min((unsigned int)len,
+			ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index);
+	memcpy_fromio(buf, &ifc_nand_ctrl->addr[ifc_nand_ctrl->index], avail);
+	ifc_nand_ctrl->index += avail;
+
+	if (len > avail)
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %d available)\n",
+			__func__, len, avail);
+}
+
+/*
+ * Verify buffer against the IFC Controller Data Buffer
+ */
+static int fsl_ifc_verify_buf(struct mtd_info *mtd,
+			       const u_char *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
+	int i;
+
+	if (len < 0) {
+		dev_err(priv->dev, "%s: write_buf of %d bytes", __func__, len);
+		return -EINVAL;
+	}
+
+	if ((unsigned int)len > nctrl->read_bytes - nctrl->index) {
+		dev_err(priv->dev,
+			"%s: beyond end of buffer (%d requested, %u available)\n",
+			__func__, len, nctrl->read_bytes - nctrl->index);
+
+		nctrl->index = nctrl->read_bytes;
+		return -EINVAL;
+	}
+
+	for (i = 0; i < len; i++)
+		if (in_8(&nctrl->addr[nctrl->index + i]) != buf[i])
+			break;
+
+	nctrl->index += len;
+
+	if (i != len)
+		return -EIO;
+	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * This function is called after Program and Erase Operations to
+ * check for success or failure.
+ */
+static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	u32 nand_fsr;
+
+	/* Use READ_STATUS command, but wait for the device to be ready */
+	out_be32(&ifc->ifc_nand.nand_fir0,
+		 (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+		 (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
+	out_be32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS <<
+			IFC_NAND_FCR0_CMD0_SHIFT);
+	out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+	set_addr(mtd, 0, 0, 0);
+	ifc_nand_ctrl->read_bytes = 1;
+
+	fsl_ifc_run_command(mtd);
+
+	nand_fsr = in_be32(&ifc->ifc_nand.nand_fsr);
+
+	/*
+	 * The chip always seems to report that it is
+	 * write-protected, even when it is not.
+	 */
+	return nand_fsr | NAND_STATUS_WP;
+}
+
+static int fsl_ifc_read_page(struct mtd_info *mtd,
+			      struct nand_chip *chip,
+			      uint8_t *buf, int page)
+{
+	struct fsl_ifc_mtd *priv = chip->priv;
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+
+	fsl_ifc_read_buf(mtd, buf, mtd->writesize);
+	fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) {
+		dev_err(priv->dev, "NAND Flash Write Protect Error\n");
+		mtd->ecc_stats.failed++;
+	}
+
+	return 0;
+}
+
+/* ECC will be calculated automatically, and errors will be detected in
+ * waitfunc.
+ */
+static void fsl_ifc_write_page(struct mtd_info *mtd,
+				struct nand_chip *chip,
+				const uint8_t *buf)
+{
+	fsl_ifc_write_buf(mtd, buf, mtd->writesize);
+	fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct fsl_ifc_mtd *priv = chip->priv;
+
+	dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__,
+							chip->numchips);
+	dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__,
+							chip->chipsize);
+	dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__,
+							chip->pagemask);
+	dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__,
+							chip->chip_delay);
+	dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__,
+							chip->badblockpos);
+	dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__,
+							chip->chip_shift);
+	dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__,
+							chip->page_shift);
+	dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__,
+							chip->phys_erase_shift);
+	dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__,
+							chip->ecclayout);
+	dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__,
+							chip->ecc.mode);
+	dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__,
+							chip->ecc.steps);
+	dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__,
+							chip->ecc.bytes);
+	dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__,
+							chip->ecc.total);
+	dev_dbg(priv->dev, "%s: nand->ecc.layout = %p\n", __func__,
+							chip->ecc.layout);
+	dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags);
+	dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size);
+	dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__,
+							mtd->erasesize);
+	dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__,
+							mtd->writesize);
+	dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__,
+							mtd->oobsize);
+
+	return 0;
+}
+
+static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
+{
+	struct fsl_ifc_ctrl *ctrl = priv->ctrl;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	struct nand_chip *chip = &priv->chip;
+	struct nand_ecclayout *layout;
+	u32 csor;
+
+	/* Fill in fsl_ifc_mtd structure */
+	priv->mtd.priv = chip;
+	priv->mtd.owner = THIS_MODULE;
+
+	/* fill in nand_chip structure */
+	/* set up function call table */
+	if ((in_be32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16)
+		chip->read_byte = fsl_ifc_read_byte16;
+	else
+		chip->read_byte = fsl_ifc_read_byte;
+
+	chip->write_buf = fsl_ifc_write_buf;
+	chip->read_buf = fsl_ifc_read_buf;
+	chip->verify_buf = fsl_ifc_verify_buf;
+	chip->select_chip = fsl_ifc_select_chip;
+	chip->cmdfunc = fsl_ifc_cmdfunc;
+	chip->waitfunc = fsl_ifc_wait;
+
+	chip->bbt_td = &bbt_main_descr;
+	chip->bbt_md = &bbt_mirror_descr;
+
+	out_be32(&ifc->ifc_nand.ncfgr, 0x0);
+
+	/* set up nand options */
+	chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
+	chip->bbt_options = NAND_BBT_USE_FLASH;
+
+
+	if (in_be32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
+		chip->read_byte = fsl_ifc_read_byte16;
+		chip->options |= NAND_BUSWIDTH_16;
+	} else {
+		chip->read_byte = fsl_ifc_read_byte;
+	}
+
+	chip->controller = &ifc_nand_ctrl->controller;
+	chip->priv = priv;
+
+	chip->ecc.read_page = fsl_ifc_read_page;
+	chip->ecc.write_page = fsl_ifc_write_page;
+
+	csor = in_be32(&ifc->csor_cs[priv->bank].csor);
+
+	/* Hardware generates ECC per 512 Bytes */
+	chip->ecc.size = 512;
+	chip->ecc.bytes = 8;
+
+	switch (csor & CSOR_NAND_PGS_MASK) {
+	case CSOR_NAND_PGS_512:
+		if (chip->options & NAND_BUSWIDTH_16) {
+			layout = &oob_512_16bit_ecc4;
+		} else {
+			layout = &oob_512_8bit_ecc4;
+
+			/* Avoid conflict with bad block marker */
+			bbt_main_descr.offs = 0;
+			bbt_mirror_descr.offs = 0;
+		}
+
+		priv->bufnum_mask = 15;
+		break;
+
+	case CSOR_NAND_PGS_2K:
+		layout = &oob_2048_ecc4;
+		priv->bufnum_mask = 3;
+		break;
+
+	case CSOR_NAND_PGS_4K:
+		if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
+		    CSOR_NAND_ECC_MODE_4) {
+			layout = &oob_4096_ecc4;
+		} else {
+			layout = &oob_4096_ecc8;
+			chip->ecc.bytes = 16;
+		}
+
+		priv->bufnum_mask = 1;
+		break;
+
+	default:
+		dev_err(priv->dev, "bad csor %#x: bad page size\n", csor);
+		return -ENODEV;
+	}
+
+	/* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */
+	if (csor & CSOR_NAND_ECC_DEC_EN) {
+		chip->ecc.mode = NAND_ECC_HW;
+		chip->ecc.layout = layout;
+	} else {
+		chip->ecc.mode = NAND_ECC_SOFT;
+	}
+
+	return 0;
+}
+
+static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
+{
+	nand_release(&priv->mtd);
+
+	kfree(priv->mtd.name);
+
+	if (priv->vbase)
+		iounmap(priv->vbase);
+
+	ifc_nand_ctrl->chips[priv->bank] = NULL;
+	dev_set_drvdata(priv->dev, NULL);
+	kfree(priv);
+
+	return 0;
+}
+
+static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
+		      phys_addr_t addr)
+{
+	u32 cspr = in_be32(&ifc->cspr_cs[bank].cspr);
+
+	if (!(cspr & CSPR_V))
+		return 0;
+	if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND)
+		return 0;
+
+	return (cspr & CSPR_BA) == convert_ifc_address(addr);
+}
+
+static DEFINE_MUTEX(fsl_ifc_nand_mutex);
+
+static int __devinit fsl_ifc_nand_probe(struct platform_device *dev)
+{
+	struct fsl_ifc_regs __iomem *ifc;
+	struct fsl_ifc_mtd *priv;
+	struct resource res;
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", "ofpart", NULL };
+	int ret;
+	int bank;
+	struct device_node *node = dev->dev.of_node;
+	struct mtd_part_parser_data ppdata;
+
+	ppdata.of_node = dev->dev.of_node;
+	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+		return -ENODEV;
+	ifc = fsl_ifc_ctrl_dev->regs;
+
+	/* get, allocate and map the memory resource */
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret) {
+		dev_err(&dev->dev, "%s: failed to get resource\n", __func__);
+		return ret;
+	}
+
+	/* find which chip select it is connected to */
+	for (bank = 0; bank < FSL_IFC_BANK_COUNT; bank++) {
+		if (match_bank(ifc, bank, res.start))
+			break;
+	}
+
+	if (bank >= FSL_IFC_BANK_COUNT) {
+		dev_err(&dev->dev, "%s: address did not match any chip selects\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_lock(&fsl_ifc_nand_mutex);
+	if (!fsl_ifc_ctrl_dev->nand) {
+		ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
+		if (!ifc_nand_ctrl) {
+			dev_err(&dev->dev, "failed to allocate memory\n");
+			mutex_unlock(&fsl_ifc_nand_mutex);
+			return -ENOMEM;
+		}
+
+		ifc_nand_ctrl->read_bytes = 0;
+		ifc_nand_ctrl->index = 0;
+		ifc_nand_ctrl->addr = NULL;
+		fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
+
+		spin_lock_init(&ifc_nand_ctrl->controller.lock);
+		init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
+	} else {
+		ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
+	}
+	mutex_unlock(&fsl_ifc_nand_mutex);
+
+	ifc_nand_ctrl->chips[bank] = priv;
+	priv->bank = bank;
+	priv->ctrl = fsl_ifc_ctrl_dev;
+	priv->dev = &dev->dev;
+
+	priv->vbase = ioremap(res.start, resource_size(&res));
+	if (!priv->vbase) {
+		dev_err(priv->dev, "%s: failed to map chip region\n", __func__);
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	dev_set_drvdata(priv->dev, priv);
+
+	out_be32(&ifc->ifc_nand.nand_evter_en,
+			IFC_NAND_EVTER_EN_OPC_EN |
+			IFC_NAND_EVTER_EN_FTOER_EN |
+			IFC_NAND_EVTER_EN_WPER_EN);
+
+	/* enable NAND Machine Interrupts */
+	out_be32(&ifc->ifc_nand.nand_evter_intr_en,
+			IFC_NAND_EVTER_INTR_OPCIR_EN |
+			IFC_NAND_EVTER_INTR_FTOERIR_EN |
+			IFC_NAND_EVTER_INTR_WPERIR_EN);
+
+	priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
+	if (!priv->mtd.name) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = fsl_ifc_chip_init(priv);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_ident(&priv->mtd, 1, NULL);
+	if (ret)
+		goto err;
+
+	ret = fsl_ifc_chip_init_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+	ret = nand_scan_tail(&priv->mtd);
+	if (ret)
+		goto err;
+
+	/* First look for RedBoot table or partitions on the command
+	 * line, these take precedence over device tree information */
+	mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata,
+						NULL, 0);
+
+	dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n",
+		 (unsigned long long)res.start, priv->bank);
+	return 0;
+
+err:
+	fsl_ifc_chip_remove(priv);
+	return ret;
+}
+
+static int fsl_ifc_nand_remove(struct platform_device *dev)
+{
+	struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
+
+	fsl_ifc_chip_remove(priv);
+
+	mutex_lock(&fsl_ifc_nand_mutex);
+	ifc_nand_ctrl->counter--;
+	if (!ifc_nand_ctrl->counter) {
+		fsl_ifc_ctrl_dev->nand = NULL;
+		kfree(ifc_nand_ctrl);
+	}
+	mutex_unlock(&fsl_ifc_nand_mutex);
+
+	return 0;
+}
+
+static const struct of_device_id fsl_ifc_nand_match[] = {
+	{
+		.compatible = "fsl,ifc-nand",
+	},
+	{}
+};
+
+static struct platform_driver fsl_ifc_nand_driver = {
+	.driver = {
+		.name	= "fsl,ifc-nand",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_ifc_nand_match,
+	},
+	.probe       = fsl_ifc_nand_probe,
+	.remove      = fsl_ifc_nand_remove,
+};
+
+static int __init fsl_ifc_nand_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&fsl_ifc_nand_driver);
+	if (ret)
+		printk(KERN_ERR "fsl-ifc: Failed to register platform"
+				"driver\n");
+
+	return ret;
+}
+
+static void __exit fsl_ifc_nand_exit(void)
+{
+	platform_driver_unregister(&fsl_ifc_nand_driver);
+}
+
+module_init(fsl_ifc_nand_init);
+module_exit(fsl_ifc_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver");
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 1/2][v2] Integrated Flash Controller support
From: Prabhakar Kushwaha @ 2011-12-27 12:09 UTC (permalink / raw)
  To: linuxppc-dev, linux-mtd
  Cc: Scott Wood, Dipen Dudhat, Liu Shuo, Prabhakar Kushwaha
In-Reply-To: <1324987753-30318-1-git-send-email-prabhakar@freescale.com>

Integrated Flash Controller supports various flashes like NOR, NAND
and other devices using NOR, NAND and GPCM Machine available on it.
IFC supports four chip selects.

Signed-off-by: Dipen Dudhat <Dipen.Dudhat@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
---
 Based upon git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git (branch next)

 Tested on P1010RDB

 Changes for v2: Incorporated Artem Bityutskiy's comment
	- Error handling in fsl_ifc_ctrl_probe
	- Use module_platform_driver() insted of module_init and module_exit

 arch/powerpc/Kconfig               |    4 +
 arch/powerpc/include/asm/fsl_ifc.h |  834 ++++++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/Makefile       |    1 +
 arch/powerpc/sysdev/fsl_ifc.c      |  310 +++++++++++++
 4 files changed, 1149 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/fsl_ifc.h
 create mode 100644 arch/powerpc/sysdev/fsl_ifc.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 7c93c7e..d78cb6e 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -688,6 +688,10 @@ config FSL_LBC
 	  controller.  Also contains some common code used by
 	  drivers for specific local bus peripherals.
 
+config FSL_IFC
+	bool
+        depends on FSL_SOC
+
 config FSL_GTM
 	bool
 	depends on PPC_83xx || QUICC_ENGINE || CPM2
diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h
new file mode 100644
index 0000000..b955012
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_ifc.h
@@ -0,0 +1,834 @@
+/* Freescale Integrated Flash Controller
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <dipen.dudhat@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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_FSL_IFC_H
+#define __ASM_FSL_IFC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+
+#define FSL_IFC_BANK_COUNT 4
+
+/*
+ * CSPR - Chip Select Property Register
+ */
+#define CSPR_BA				0xFFFF0000
+#define CSPR_BA_SHIFT			16
+#define CSPR_PORT_SIZE			0x00000180
+#define CSPR_PORT_SIZE_SHIFT		7
+/* Port Size 8 bit */
+#define CSPR_PORT_SIZE_8		0x00000080
+/* Port Size 16 bit */
+#define CSPR_PORT_SIZE_16		0x00000100
+/* Port Size 32 bit */
+#define CSPR_PORT_SIZE_32		0x00000180
+/* Write Protect */
+#define CSPR_WP				0x00000040
+#define CSPR_WP_SHIFT			6
+/* Machine Select */
+#define CSPR_MSEL			0x00000006
+#define CSPR_MSEL_SHIFT			1
+/* NOR */
+#define CSPR_MSEL_NOR			0x00000000
+/* NAND */
+#define CSPR_MSEL_NAND			0x00000002
+/* GPCM */
+#define CSPR_MSEL_GPCM			0x00000004
+/* Bank Valid */
+#define CSPR_V				0x00000001
+#define CSPR_V_SHIFT			0
+
+/*
+ * Address Mask Register
+ */
+#define IFC_AMASK_MASK			0xFFFF0000
+#define IFC_AMASK_SHIFT			16
+#define IFC_AMASK(n)			(IFC_AMASK_MASK << \
+					(__ilog2(n) - IFC_AMASK_SHIFT))
+
+/*
+ * Chip Select Option Register IFC_NAND Machine
+ */
+/* Enable ECC Encoder */
+#define CSOR_NAND_ECC_ENC_EN		0x80000000
+#define CSOR_NAND_ECC_MODE_MASK		0x30000000
+/* 4 bit correction per 520 Byte sector */
+#define CSOR_NAND_ECC_MODE_4		0x00000000
+/* 8 bit correction per 528 Byte sector */
+#define CSOR_NAND_ECC_MODE_8		0x10000000
+/* Enable ECC Decoder */
+#define CSOR_NAND_ECC_DEC_EN		0x04000000
+/* Row Address Length */
+#define CSOR_NAND_RAL_MASK		0x01800000
+#define CSOR_NAND_RAL_SHIFT		20
+#define CSOR_NAND_RAL_1			0x00000000
+#define CSOR_NAND_RAL_2			0x00800000
+#define CSOR_NAND_RAL_3			0x01000000
+#define CSOR_NAND_RAL_4			0x01800000
+/* Page Size 512b, 2k, 4k */
+#define CSOR_NAND_PGS_MASK		0x00180000
+#define CSOR_NAND_PGS_SHIFT		16
+#define CSOR_NAND_PGS_512		0x00000000
+#define CSOR_NAND_PGS_2K		0x00080000
+#define CSOR_NAND_PGS_4K		0x00100000
+/* Spare region Size */
+#define CSOR_NAND_SPRZ_MASK		0x0000E000
+#define CSOR_NAND_SPRZ_SHIFT		13
+#define CSOR_NAND_SPRZ_16		0x00000000
+#define CSOR_NAND_SPRZ_64		0x00002000
+#define CSOR_NAND_SPRZ_128		0x00004000
+#define CSOR_NAND_SPRZ_210		0x00006000
+#define CSOR_NAND_SPRZ_218		0x00008000
+#define CSOR_NAND_SPRZ_224		0x0000A000
+/* Pages Per Block */
+#define CSOR_NAND_PB_MASK		0x00000700
+#define CSOR_NAND_PB_SHIFT		8
+#define CSOR_NAND_PB(n)		((__ilog2(n) - 5) << CSOR_NAND_PB_SHIFT)
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NAND_TRHZ_MASK		0x0000001C
+#define CSOR_NAND_TRHZ_SHIFT		2
+#define CSOR_NAND_TRHZ_20		0x00000000
+#define CSOR_NAND_TRHZ_40		0x00000004
+#define CSOR_NAND_TRHZ_60		0x00000008
+#define CSOR_NAND_TRHZ_80		0x0000000C
+#define CSOR_NAND_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_NAND_BCTLD			0x00000001
+
+/*
+ * Chip Select Option Register - NOR Flash Mode
+ */
+/* Enable Address shift Mode */
+#define CSOR_NOR_ADM_SHFT_MODE_EN	0x80000000
+/* Page Read Enable from NOR device */
+#define CSOR_NOR_PGRD_EN		0x10000000
+/* AVD Toggle Enable during Burst Program */
+#define CSOR_NOR_AVD_TGL_PGM_EN		0x01000000
+/* Address Data Multiplexing Shift */
+#define CSOR_NOR_ADM_MASK		0x0003E000
+#define CSOR_NOR_ADM_SHIFT_SHIFT	13
+#define CSOR_NOR_ADM_SHIFT(n)	((n) << CSOR_NOR_ADM_SHIFT_SHIFT)
+/* Type of the NOR device hooked */
+#define CSOR_NOR_NOR_MODE_AYSNC_NOR	0x00000000
+#define CSOR_NOR_NOR_MODE_AVD_NOR	0x00000020
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NOR_TRHZ_MASK		0x0000001C
+#define CSOR_NOR_TRHZ_SHIFT		2
+#define CSOR_NOR_TRHZ_20		0x00000000
+#define CSOR_NOR_TRHZ_40		0x00000004
+#define CSOR_NOR_TRHZ_60		0x00000008
+#define CSOR_NOR_TRHZ_80		0x0000000C
+#define CSOR_NOR_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_NOR_BCTLD			0x00000001
+
+/*
+ * Chip Select Option Register - GPCM Mode
+ */
+/* GPCM Mode - Normal */
+#define CSOR_GPCM_GPMODE_NORMAL		0x00000000
+/* GPCM Mode - GenericASIC */
+#define CSOR_GPCM_GPMODE_ASIC		0x80000000
+/* Parity Mode odd/even */
+#define CSOR_GPCM_PARITY_EVEN		0x40000000
+/* Parity Checking enable/disable */
+#define CSOR_GPCM_PAR_EN		0x20000000
+/* GPCM Timeout Count */
+#define CSOR_GPCM_GPTO_MASK		0x0F000000
+#define CSOR_GPCM_GPTO_SHIFT		24
+#define CSOR_GPCM_GPTO(n)	((__ilog2(n) - 8) << CSOR_GPCM_GPTO_SHIFT)
+/* GPCM External Access Termination mode for read access */
+#define CSOR_GPCM_RGETA_EXT		0x00080000
+/* GPCM External Access Termination mode for write access */
+#define CSOR_GPCM_WGETA_EXT		0x00040000
+/* Address Data Multiplexing Shift */
+#define CSOR_GPCM_ADM_MASK		0x0003E000
+#define CSOR_GPCM_ADM_SHIFT_SHIFT	13
+#define CSOR_GPCM_ADM_SHIFT(n)	((n) << CSOR_GPCM_ADM_SHIFT_SHIFT)
+/* Generic ASIC Parity error indication delay */
+#define CSOR_GPCM_GAPERRD_MASK		0x00000180
+#define CSOR_GPCM_GAPERRD_SHIFT		7
+#define CSOR_GPCM_GAPERRD(n)	(((n) - 1) << CSOR_GPCM_GAPERRD_SHIFT)
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_GPCM_TRHZ_MASK		0x0000001C
+#define CSOR_GPCM_TRHZ_20		0x00000000
+#define CSOR_GPCM_TRHZ_40		0x00000004
+#define CSOR_GPCM_TRHZ_60		0x00000008
+#define CSOR_GPCM_TRHZ_80		0x0000000C
+#define CSOR_GPCM_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_GPCM_BCTLD			0x00000001
+
+/*
+ * Ready Busy Status Register (RB_STAT)
+ */
+/* CSn is READY */
+#define IFC_RB_STAT_READY_CS0		0x80000000
+#define IFC_RB_STAT_READY_CS1		0x40000000
+#define IFC_RB_STAT_READY_CS2		0x20000000
+#define IFC_RB_STAT_READY_CS3		0x10000000
+
+/*
+ * General Control Register (GCR)
+ */
+#define IFC_GCR_MASK			0x8000F800
+/* reset all IFC hardware */
+#define IFC_GCR_SOFT_RST_ALL		0x80000000
+/* Turnaroud Time of external buffer */
+#define IFC_GCR_TBCTL_TRN_TIME		0x0000F800
+#define IFC_GCR_TBCTL_TRN_TIME_SHIFT	11
+
+/*
+ * Common Event and Error Status Register (CM_EVTER_STAT)
+ */
+/* Chip select error */
+#define IFC_CM_EVTER_STAT_CSER		0x80000000
+
+/*
+ * Common Event and Error Enable Register (CM_EVTER_EN)
+ */
+/* Chip select error checking enable */
+#define IFC_CM_EVTER_EN_CSEREN		0x80000000
+
+/*
+ * Common Event and Error Interrupt Enable Register (CM_EVTER_INTR_EN)
+ */
+/* Chip select error interrupt enable */
+#define IFC_CM_EVTER_INTR_EN_CSERIREN	0x80000000
+
+/*
+ * Common Transfer Error Attribute Register-0 (CM_ERATTR0)
+ */
+/* transaction type of error Read/Write */
+#define IFC_CM_ERATTR0_ERTYP_READ	0x80000000
+#define IFC_CM_ERATTR0_ERAID		0x0FF00000
+#define IFC_CM_ERATTR0_ERAID_SHIFT	20
+#define IFC_CM_ERATTR0_ESRCID		0x0000FF00
+#define IFC_CM_ERATTR0_ESRCID_SHIFT	8
+
+/*
+ * Clock Control Register (CCR)
+ */
+#define IFC_CCR_MASK			0x0F0F8800
+/* Clock division ratio */
+#define IFC_CCR_CLK_DIV_MASK		0x0F000000
+#define IFC_CCR_CLK_DIV_SHIFT		24
+#define IFC_CCR_CLK_DIV(n)		((n-1) << IFC_CCR_CLK_DIV_SHIFT)
+/* IFC Clock Delay */
+#define IFC_CCR_CLK_DLY_MASK		0x000F0000
+#define IFC_CCR_CLK_DLY_SHIFT		16
+#define IFC_CCR_CLK_DLY(n)		((n) << IFC_CCR_CLK_DLY_SHIFT)
+/* Invert IFC clock before sending out */
+#define IFC_CCR_INV_CLK_EN		0x00008000
+/* Fedback IFC Clock */
+#define IFC_CCR_FB_IFC_CLK_SEL		0x00000800
+
+/*
+ * Clock Status Register (CSR)
+ */
+/* Clk is stable */
+#define IFC_CSR_CLK_STAT_STABLE		0x80000000
+
+/*
+ * IFC_NAND Machine Specific Registers
+ */
+/*
+ * NAND Configuration Register (NCFGR)
+ */
+/* Auto Boot Mode */
+#define IFC_NAND_NCFGR_BOOT		0x80000000
+/* Addressing Mode-ROW0+n/COL0 */
+#define IFC_NAND_NCFGR_ADDR_MODE_RC0	0x00000000
+/* Addressing Mode-ROW0+n/COL0+n */
+#define IFC_NAND_NCFGR_ADDR_MODE_RC1	0x00400000
+/* Number of loop iterations of FIR sequences for multi page operations */
+#define IFC_NAND_NCFGR_NUM_LOOP_MASK	0x0000F000
+#define IFC_NAND_NCFGR_NUM_LOOP_SHIFT	12
+#define IFC_NAND_NCFGR_NUM_LOOP(n)	((n) << IFC_NAND_NCFGR_NUM_LOOP_SHIFT)
+/* Number of wait cycles */
+#define IFC_NAND_NCFGR_NUM_WAIT_MASK	0x000000FF
+#define IFC_NAND_NCFGR_NUM_WAIT_SHIFT	0
+
+/*
+ * NAND Flash Command Registers (NAND_FCR0/NAND_FCR1)
+ */
+/* General purpose FCM flash command bytes CMD0-CMD7 */
+#define IFC_NAND_FCR0_CMD0		0xFF000000
+#define IFC_NAND_FCR0_CMD0_SHIFT	24
+#define IFC_NAND_FCR0_CMD1		0x00FF0000
+#define IFC_NAND_FCR0_CMD1_SHIFT	16
+#define IFC_NAND_FCR0_CMD2		0x0000FF00
+#define IFC_NAND_FCR0_CMD2_SHIFT	8
+#define IFC_NAND_FCR0_CMD3		0x000000FF
+#define IFC_NAND_FCR0_CMD3_SHIFT	0
+#define IFC_NAND_FCR1_CMD4		0xFF000000
+#define IFC_NAND_FCR1_CMD4_SHIFT	24
+#define IFC_NAND_FCR1_CMD5		0x00FF0000
+#define IFC_NAND_FCR1_CMD5_SHIFT	16
+#define IFC_NAND_FCR1_CMD6		0x0000FF00
+#define IFC_NAND_FCR1_CMD6_SHIFT	8
+#define IFC_NAND_FCR1_CMD7		0x000000FF
+#define IFC_NAND_FCR1_CMD7_SHIFT	0
+
+/*
+ * Flash ROW and COL Address Register (ROWn, COLn)
+ */
+/* Main/spare region locator */
+#define IFC_NAND_COL_MS			0x80000000
+/* Column Address */
+#define IFC_NAND_COL_CA_MASK		0x00000FFF
+
+/*
+ * NAND Flash Byte Count Register (NAND_BC)
+ */
+/* Byte Count for read/Write */
+#define IFC_NAND_BC			0x000001FF
+
+/*
+ * NAND Flash Instruction Registers (NAND_FIR0/NAND_FIR1/NAND_FIR2)
+ */
+/* NAND Machine specific opcodes OP0-OP14*/
+#define IFC_NAND_FIR0_OP0		0xFC000000
+#define IFC_NAND_FIR0_OP0_SHIFT		26
+#define IFC_NAND_FIR0_OP1		0x03F00000
+#define IFC_NAND_FIR0_OP1_SHIFT		20
+#define IFC_NAND_FIR0_OP2		0x000FC000
+#define IFC_NAND_FIR0_OP2_SHIFT		14
+#define IFC_NAND_FIR0_OP3		0x00003F00
+#define IFC_NAND_FIR0_OP3_SHIFT		8
+#define IFC_NAND_FIR0_OP4		0x000000FC
+#define IFC_NAND_FIR0_OP4_SHIFT		2
+#define IFC_NAND_FIR1_OP5		0xFC000000
+#define IFC_NAND_FIR1_OP5_SHIFT		26
+#define IFC_NAND_FIR1_OP6		0x03F00000
+#define IFC_NAND_FIR1_OP6_SHIFT		20
+#define IFC_NAND_FIR1_OP7		0x000FC000
+#define IFC_NAND_FIR1_OP7_SHIFT		14
+#define IFC_NAND_FIR1_OP8		0x00003F00
+#define IFC_NAND_FIR1_OP8_SHIFT		8
+#define IFC_NAND_FIR1_OP9		0x000000FC
+#define IFC_NAND_FIR1_OP9_SHIFT		2
+#define IFC_NAND_FIR2_OP10		0xFC000000
+#define IFC_NAND_FIR2_OP10_SHIFT	26
+#define IFC_NAND_FIR2_OP11		0x03F00000
+#define IFC_NAND_FIR2_OP11_SHIFT	20
+#define IFC_NAND_FIR2_OP12		0x000FC000
+#define IFC_NAND_FIR2_OP12_SHIFT	14
+#define IFC_NAND_FIR2_OP13		0x00003F00
+#define IFC_NAND_FIR2_OP13_SHIFT	8
+#define IFC_NAND_FIR2_OP14		0x000000FC
+#define IFC_NAND_FIR2_OP14_SHIFT	2
+
+/*
+ * Instruction opcodes to be programmed
+ * in FIR registers- 6bits
+ */
+enum ifc_nand_fir_opcodes {
+	IFC_FIR_OP_NOP,
+	IFC_FIR_OP_CA0,
+	IFC_FIR_OP_CA1,
+	IFC_FIR_OP_CA2,
+	IFC_FIR_OP_CA3,
+	IFC_FIR_OP_RA0,
+	IFC_FIR_OP_RA1,
+	IFC_FIR_OP_RA2,
+	IFC_FIR_OP_RA3,
+	IFC_FIR_OP_CMD0,
+	IFC_FIR_OP_CMD1,
+	IFC_FIR_OP_CMD2,
+	IFC_FIR_OP_CMD3,
+	IFC_FIR_OP_CMD4,
+	IFC_FIR_OP_CMD5,
+	IFC_FIR_OP_CMD6,
+	IFC_FIR_OP_CMD7,
+	IFC_FIR_OP_CW0,
+	IFC_FIR_OP_CW1,
+	IFC_FIR_OP_CW2,
+	IFC_FIR_OP_CW3,
+	IFC_FIR_OP_CW4,
+	IFC_FIR_OP_CW5,
+	IFC_FIR_OP_CW6,
+	IFC_FIR_OP_CW7,
+	IFC_FIR_OP_WBCD,
+	IFC_FIR_OP_RBCD,
+	IFC_FIR_OP_BTRD,
+	IFC_FIR_OP_RDSTAT,
+	IFC_FIR_OP_NWAIT,
+	IFC_FIR_OP_WFR,
+	IFC_FIR_OP_SBRD,
+	IFC_FIR_OP_UA,
+	IFC_FIR_OP_RB,
+};
+
+/*
+ * NAND Chip Select Register (NAND_CSEL)
+ */
+#define IFC_NAND_CSEL			0x0C000000
+#define IFC_NAND_CSEL_SHIFT		26
+#define IFC_NAND_CSEL_CS0		0x00000000
+#define IFC_NAND_CSEL_CS1		0x04000000
+#define IFC_NAND_CSEL_CS2		0x08000000
+#define IFC_NAND_CSEL_CS3		0x0C000000
+
+/*
+ * NAND Operation Sequence Start (NANDSEQ_STRT)
+ */
+/* NAND Flash Operation Start */
+#define IFC_NAND_SEQ_STRT_FIR_STRT	0x80000000
+/* Automatic Erase */
+#define IFC_NAND_SEQ_STRT_AUTO_ERS	0x00800000
+/* Automatic Program */
+#define IFC_NAND_SEQ_STRT_AUTO_PGM	0x00100000
+/* Automatic Copyback */
+#define IFC_NAND_SEQ_STRT_AUTO_CPB	0x00020000
+/* Automatic Read Operation */
+#define IFC_NAND_SEQ_STRT_AUTO_RD	0x00004000
+/* Automatic Status Read */
+#define IFC_NAND_SEQ_STRT_AUTO_STAT_RD	0x00000800
+
+/*
+ * NAND Event and Error Status Register (NAND_EVTER_STAT)
+ */
+/* Operation Complete */
+#define IFC_NAND_EVTER_STAT_OPC		0x80000000
+/* Flash Timeout Error */
+#define IFC_NAND_EVTER_STAT_FTOER	0x08000000
+/* Write Protect Error */
+#define IFC_NAND_EVTER_STAT_WPER	0x04000000
+/* ECC Error */
+#define IFC_NAND_EVTER_STAT_ECCER	0x02000000
+/* RCW Load Done */
+#define IFC_NAND_EVTER_STAT_RCW_DN	0x00008000
+/* Boot Loadr Done */
+#define IFC_NAND_EVTER_STAT_BOOT_DN	0x00004000
+/* Bad Block Indicator search select */
+#define IFC_NAND_EVTER_STAT_BBI_SRCH_SE	0x00000800
+
+/*
+ * NAND Flash Page Read Completion Event Status Register
+ * (PGRDCMPL_EVT_STAT)
+ */
+#define PGRDCMPL_EVT_STAT_MASK		0xFFFF0000
+/* Small Page 0-15 Done */
+#define PGRDCMPL_EVT_STAT_SECTION_SP(n)	(1 << (31 - (n)))
+/* Large Page(2K) 0-3 Done */
+#define PGRDCMPL_EVT_STAT_LP_2K(n)	(0xF << (28 - (n)*4))
+/* Large Page(4K) 0-1 Done */
+#define PGRDCMPL_EVT_STAT_LP_4K(n)	(0xFF << (24 - (n)*8))
+
+/*
+ * NAND Event and Error Enable Register (NAND_EVTER_EN)
+ */
+/* Operation complete event enable */
+#define IFC_NAND_EVTER_EN_OPC_EN	0x80000000
+/* Page read complete event enable */
+#define IFC_NAND_EVTER_EN_PGRDCMPL_EN	0x20000000
+/* Flash Timeout error enable */
+#define IFC_NAND_EVTER_EN_FTOER_EN	0x08000000
+/* Write Protect error enable */
+#define IFC_NAND_EVTER_EN_WPER_EN	0x04000000
+/* ECC error logging enable */
+#define IFC_NAND_EVTER_EN_ECCER_EN	0x02000000
+
+/*
+ * NAND Event and Error Interrupt Enable Register (NAND_EVTER_INTR_EN)
+ */
+/* Enable interrupt for operation complete */
+#define IFC_NAND_EVTER_INTR_OPCIR_EN		0x80000000
+/* Enable interrupt for Page read complete */
+#define IFC_NAND_EVTER_INTR_PGRDCMPLIR_EN	0x20000000
+/* Enable interrupt for Flash timeout error */
+#define IFC_NAND_EVTER_INTR_FTOERIR_EN		0x08000000
+/* Enable interrupt for Write protect error */
+#define IFC_NAND_EVTER_INTR_WPERIR_EN		0x04000000
+/* Enable interrupt for ECC error*/
+#define IFC_NAND_EVTER_INTR_ECCERIR_EN		0x02000000
+
+/*
+ * NAND Transfer Error Attribute Register-0 (NAND_ERATTR0)
+ */
+#define IFC_NAND_ERATTR0_MASK		0x0C080000
+/* Error on CS0-3 for NAND */
+#define IFC_NAND_ERATTR0_ERCS_CS0	0x00000000
+#define IFC_NAND_ERATTR0_ERCS_CS1	0x04000000
+#define IFC_NAND_ERATTR0_ERCS_CS2	0x08000000
+#define IFC_NAND_ERATTR0_ERCS_CS3	0x0C000000
+/* Transaction type of error Read/Write */
+#define IFC_NAND_ERATTR0_ERTTYPE_READ	0x00080000
+
+/*
+ * NAND Flash Status Register (NAND_FSR)
+ */
+/* First byte of data read from read status op */
+#define IFC_NAND_NFSR_RS0		0xFF000000
+/* Second byte of data read from read status op */
+#define IFC_NAND_NFSR_RS1		0x00FF0000
+
+/*
+ * ECC Error Status Registers (ECCSTAT0-ECCSTAT3)
+ */
+/* Number of ECC errors on sector n (n = 0-15) */
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_SHIFT	24
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_SHIFT	16
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_SHIFT	8
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_SHIFT	0
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_SHIFT	24
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_SHIFT	16
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_SHIFT	8
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_SHIFT	0
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_SHIFT	24
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_SHIFT	16
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_SHIFT	8
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_SHIFT	0
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_SHIFT	24
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_SHIFT	16
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_SHIFT	8
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_SHIFT	0
+
+/*
+ * NAND Control Register (NANDCR)
+ */
+#define IFC_NAND_NCR_FTOCNT_MASK	0x1E000000
+#define IFC_NAND_NCR_FTOCNT_SHIFT	25
+#define IFC_NAND_NCR_FTOCNT(n)	((_ilog2(n) - 8)  << IFC_NAND_NCR_FTOCNT_SHIFT)
+
+/*
+ * NAND_AUTOBOOT_TRGR
+ */
+/* Trigger RCW load */
+#define IFC_NAND_AUTOBOOT_TRGR_RCW_LD	0x80000000
+/* Trigget Auto Boot */
+#define IFC_NAND_AUTOBOOT_TRGR_BOOT_LD	0x20000000
+
+/*
+ * NAND_MDR
+ */
+/* 1st read data byte when opcode SBRD */
+#define IFC_NAND_MDR_RDATA0		0xFF000000
+/* 2nd read data byte when opcode SBRD */
+#define IFC_NAND_MDR_RDATA1		0x00FF0000
+
+/*
+ * NOR Machine Specific Registers
+ */
+/*
+ * NOR Event and Error Status Register (NOR_EVTER_STAT)
+ */
+/* NOR Command Sequence Operation Complete */
+#define IFC_NOR_EVTER_STAT_OPC_NOR	0x80000000
+/* Write Protect Error */
+#define IFC_NOR_EVTER_STAT_WPER		0x04000000
+/* Command Sequence Timeout Error */
+#define IFC_NOR_EVTER_STAT_STOER	0x01000000
+
+/*
+ * NOR Event and Error Enable Register (NOR_EVTER_EN)
+ */
+/* NOR Command Seq complete event enable */
+#define IFC_NOR_EVTER_EN_OPCEN_NOR	0x80000000
+/* Write Protect Error Checking Enable */
+#define IFC_NOR_EVTER_EN_WPEREN		0x04000000
+/* Timeout Error Enable */
+#define IFC_NOR_EVTER_EN_STOEREN	0x01000000
+
+/*
+ * NOR Event and Error Interrupt Enable Register (NOR_EVTER_INTR_EN)
+ */
+/* Enable interrupt for OPC complete */
+#define IFC_NOR_EVTER_INTR_OPCEN_NOR	0x80000000
+/* Enable interrupt for write protect error */
+#define IFC_NOR_EVTER_INTR_WPEREN	0x04000000
+/* Enable interrupt for timeout error */
+#define IFC_NOR_EVTER_INTR_STOEREN	0x01000000
+
+/*
+ * NOR Transfer Error Attribute Register-0 (NOR_ERATTR0)
+ */
+/* Source ID for error transaction */
+#define IFC_NOR_ERATTR0_ERSRCID		0xFF000000
+/* AXI ID for error transation */
+#define IFC_NOR_ERATTR0_ERAID		0x000FF000
+/* Chip select corresponds to NOR error */
+#define IFC_NOR_ERATTR0_ERCS_CS0	0x00000000
+#define IFC_NOR_ERATTR0_ERCS_CS1	0x00000010
+#define IFC_NOR_ERATTR0_ERCS_CS2	0x00000020
+#define IFC_NOR_ERATTR0_ERCS_CS3	0x00000030
+/* Type of transaction read/write */
+#define IFC_NOR_ERATTR0_ERTYPE_READ	0x00000001
+
+/*
+ * NOR Transfer Error Attribute Register-2 (NOR_ERATTR2)
+ */
+#define IFC_NOR_ERATTR2_ER_NUM_PHASE_EXP	0x000F0000
+#define IFC_NOR_ERATTR2_ER_NUM_PHASE_PER	0x00000F00
+
+/*
+ * NOR Control Register (NORCR)
+ */
+#define IFC_NORCR_MASK			0x0F0F0000
+/* No. of Address/Data Phase */
+#define IFC_NORCR_NUM_PHASE_MASK	0x0F000000
+#define IFC_NORCR_NUM_PHASE_SHIFT	24
+#define IFC_NORCR_NUM_PHASE(n)	((n-1) << IFC_NORCR_NUM_PHASE_SHIFT)
+/* Sequence Timeout Count */
+#define IFC_NORCR_STOCNT_MASK		0x000F0000
+#define IFC_NORCR_STOCNT_SHIFT		16
+#define IFC_NORCR_STOCNT(n)	((__ilog2(n) - 8) << IFC_NORCR_STOCNT_SHIFT)
+
+/*
+ * GPCM Machine specific registers
+ */
+/*
+ * GPCM Event and Error Status Register (GPCM_EVTER_STAT)
+ */
+/* Timeout error */
+#define IFC_GPCM_EVTER_STAT_TOER	0x04000000
+/* Parity error */
+#define IFC_GPCM_EVTER_STAT_PER		0x01000000
+
+/*
+ * GPCM Event and Error Enable Register (GPCM_EVTER_EN)
+ */
+/* Timeout error enable */
+#define IFC_GPCM_EVTER_EN_TOER_EN	0x04000000
+/* Parity error enable */
+#define IFC_GPCM_EVTER_EN_PER_EN	0x01000000
+
+/*
+ * GPCM Event and Error Interrupt Enable Register (GPCM_EVTER_INTR_EN)
+ */
+/* Enable Interrupt for timeout error */
+#define IFC_GPCM_EEIER_TOERIR_EN	0x04000000
+/* Enable Interrupt for Parity error */
+#define IFC_GPCM_EEIER_PERIR_EN		0x01000000
+
+/*
+ * GPCM Transfer Error Attribute Register-0 (GPCM_ERATTR0)
+ */
+/* Source ID for error transaction */
+#define IFC_GPCM_ERATTR0_ERSRCID	0xFF000000
+/* AXI ID for error transaction */
+#define IFC_GPCM_ERATTR0_ERAID		0x000FF000
+/* Chip select corresponds to GPCM error */
+#define IFC_GPCM_ERATTR0_ERCS_CS0	0x00000000
+#define IFC_GPCM_ERATTR0_ERCS_CS1	0x00000040
+#define IFC_GPCM_ERATTR0_ERCS_CS2	0x00000080
+#define IFC_GPCM_ERATTR0_ERCS_CS3	0x000000C0
+/* Type of transaction read/Write */
+#define IFC_GPCM_ERATTR0_ERTYPE_READ	0x00000001
+
+/*
+ * GPCM Transfer Error Attribute Register-2 (GPCM_ERATTR2)
+ */
+/* On which beat of address/data parity error is observed */
+#define IFC_GPCM_ERATTR2_PERR_BEAT		0x00000C00
+/* Parity Error on byte */
+#define IFC_GPCM_ERATTR2_PERR_BYTE		0x000000F0
+/* Parity Error reported in addr or data phase */
+#define IFC_GPCM_ERATTR2_PERR_DATA_PHASE	0x00000001
+
+/*
+ * GPCM Status Register (GPCM_STAT)
+ */
+#define IFC_GPCM_STAT_BSY		0x80000000  /* GPCM is busy */
+
+/*
+ * IFC Controller NAND Machine registers
+ */
+struct fsl_ifc_nand {
+	__be32 ncfgr;
+	u32 res1[0x4];
+	__be32 nand_fcr0;
+	__be32 nand_fcr1;
+	u32 res2[0x8];
+	__be32 row0;
+	u32 res3;
+	__be32 col0;
+	u32 res4;
+	__be32 row1;
+	u32 res5;
+	__be32 col1;
+	u32 res6;
+	__be32 row2;
+	u32 res7;
+	__be32 col2;
+	u32 res8;
+	__be32 row3;
+	u32 res9;
+	__be32 col3;
+	u32 res10[0x24];
+	__be32 nand_fbcr;
+	u32 res11;
+	__be32 nand_fir0;
+	__be32 nand_fir1;
+	__be32 nand_fir2;
+	u32 res12[0x10];
+	__be32 nand_csel;
+	u32 res13;
+	__be32 nandseq_strt;
+	u32 res14;
+	__be32 nand_evter_stat;
+	u32 res15;
+	__be32 pgrdcmpl_evt_stat;
+	u32 res16[0x2];
+	__be32 nand_evter_en;
+	u32 res17[0x2];
+	__be32 nand_evter_intr_en;
+	u32 res18[0x2];
+	__be32 nand_erattr0;
+	__be32 nand_erattr1;
+	u32 res19[0x10];
+	__be32 nand_fsr;
+	u32 res20;
+	__be32 nand_eccstat[4];
+	u32 res21[0x20];
+	__be32 nanndcr;
+	u32 res22[0x2];
+	__be32 nand_autoboot_trgr;
+	u32 res23;
+	__be32 nand_mdr;
+	u32 res24[0x5C];
+};
+
+/*
+ * IFC controller NOR Machine registers
+ */
+struct fsl_ifc_nor {
+	__be32 nor_evter_stat;
+	u32 res1[0x2];
+	__be32 nor_evter_en;
+	u32 res2[0x2];
+	__be32 nor_evter_intr_en;
+	u32 res3[0x2];
+	__be32 nor_erattr0;
+	__be32 nor_erattr1;
+	__be32 nor_erattr2;
+	u32 res4[0x4];
+	__be32 norcr;
+	u32 res5[0xEF];
+};
+
+/*
+ * IFC controller GPCM Machine registers
+ */
+struct fsl_ifc_gpcm {
+	__be32 gpcm_evter_stat;
+	u32 res1[0x2];
+	__be32 gpcm_evter_en;
+	u32 res2[0x2];
+	__be32 gpcm_evter_intr_en;
+	u32 res3[0x2];
+	__be32 gpcm_erattr0;
+	__be32 gpcm_erattr1;
+	__be32 gpcm_erattr2;
+	__be32 gpcm_stat;
+	u32 res4[0x1F3];
+};
+
+/*
+ * IFC Controller Registers
+ */
+struct fsl_ifc_regs {
+	__be32 ifc_rev;
+	u32 res1[0x3];
+	struct {
+		__be32 cspr;
+		u32 res2[0x2];
+	} cspr_cs[FSL_IFC_BANK_COUNT];
+	u32 res3[0x18];
+	struct {
+		__be32 amask;
+		u32 res4[0x2];
+	} amask_cs[FSL_IFC_BANK_COUNT];
+	u32 res5[0x18];
+	struct {
+		__be32 csor;
+		u32 res6[0x2];
+	} csor_cs[FSL_IFC_BANK_COUNT];
+	u32 res7[0x18];
+	struct {
+		__be32 ftim[4];
+		u32 res8[0x8];
+	} ftim_cs[FSL_IFC_BANK_COUNT];
+	u32 res9[0x60];
+	__be32 rb_stat;
+	u32 res10[0x2];
+	__be32 ifc_gcr;
+	u32 res11[0x2];
+	__be32 cm_evter_stat;
+	u32 res12[0x2];
+	__be32 cm_evter_en;
+	u32 res13[0x2];
+	__be32 cm_evter_intr_en;
+	u32 res14[0x2];
+	__be32 cm_erattr0;
+	__be32 cm_erattr1;
+	u32 res15[0x2];
+	__be32 ifc_ccr;
+	__be32 ifc_csr;
+	u32 res16[0x2EB];
+	struct fsl_ifc_nand ifc_nand;
+	struct fsl_ifc_nor ifc_nor;
+	struct fsl_ifc_gpcm ifc_gpcm;
+};
+
+extern unsigned int convert_ifc_address(phys_addr_t addr_base);
+extern int fsl_ifc_find(phys_addr_t addr_base);
+
+/* overview of the fsl ifc controller */
+
+struct fsl_ifc_ctrl {
+	/* device info */
+	struct device			*dev;
+	struct fsl_ifc_regs __iomem	*regs;
+	int				irq;
+	int				nand_irq;
+	spinlock_t			lock;
+	void				*nand;
+
+	u32 nand_stat;
+	wait_queue_head_t nand_wait;
+};
+
+extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
+
+
+#endif /* __ASM_FSL_IFC_H */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 8dea593..5e37b47 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
 obj-$(CONFIG_FSL_PCI)		+= fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)		+= fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)		+= fsl_lbc.o
+obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_FSL_GTM)		+= fsl_gtm.o
 obj-$(CONFIG_FSL_85XX_CACHE_SRAM)	+= fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)	+= simple_gpio.o
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c
new file mode 100644
index 0000000..b31f19f
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_ifc.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Freescale Integrated Flash Controller
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@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 the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/fsl_ifc.h>
+
+struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
+EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
+
+/*
+ * convert_ifc_address - convert the base address
+ * @addr_base:	base address of the memory bank
+ */
+unsigned int convert_ifc_address(phys_addr_t addr_base)
+{
+	return addr_base & CSPR_BA;
+}
+EXPORT_SYMBOL(convert_ifc_address);
+
+/*
+ * fsl_ifc_find - find IFC bank
+ * @addr_base:	base address of the memory bank
+ *
+ * This function walks IFC banks comparing "Base address" field of the CSPR
+ * registers with the supplied addr_base argument. When bases match this
+ * function returns bank number (starting with 0), otherwise it returns
+ * appropriate errno value.
+ */
+int fsl_ifc_find(phys_addr_t addr_base)
+{
+	int i = 0;
+
+	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(fsl_ifc_ctrl_dev->regs->cspr_cs); i++) {
+		__be32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
+		if (cspr & CSPR_V && (cspr & CSPR_BA) ==
+				convert_ifc_address(addr_base))
+			return i;
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL(fsl_ifc_find);
+
+static int __devinit fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
+{
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+	/*
+	 * Clear all the common status and event registers
+	 */
+	if (in_be32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
+		out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
+
+	/* enable all error and events */
+	out_be32(&ifc->cm_evter_en, IFC_CM_EVTER_EN_CSEREN);
+
+	/* enable all error and event interrupts */
+	out_be32(&ifc->cm_evter_intr_en, IFC_CM_EVTER_INTR_EN_CSERIREN);
+	out_be32(&ifc->cm_erattr0, 0x0);
+	out_be32(&ifc->cm_erattr1, 0x0);
+
+	return 0;
+}
+
+static int fsl_ifc_ctrl_remove(struct platform_device *dev)
+{
+	struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
+
+	free_irq(ctrl->nand_irq, ctrl);
+	free_irq(ctrl->irq, ctrl);
+
+	irq_dispose_mapping(ctrl->nand_irq);
+	irq_dispose_mapping(ctrl->irq);
+
+	iounmap(ctrl->regs);
+
+	dev_set_drvdata(&dev->dev, NULL);
+	kfree(ctrl);
+
+	return 0;
+}
+
+/*
+ * NAND events are split between an operational interrupt which only
+ * receives OPC, and an error interrupt that receives everything else,
+ * including non-NAND errors.  Whichever interrupt gets to it first
+ * records the status and wakes the wait queue.
+ */
+static DEFINE_SPINLOCK(nand_irq_lock);
+
+static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
+{
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	unsigned long flags;
+	u32 stat;
+
+	spin_lock_irqsave(&nand_irq_lock, flags);
+
+	stat = in_be32(&ifc->ifc_nand.nand_evter_stat);
+	if (stat) {
+		out_be32(&ifc->ifc_nand.nand_evter_stat, stat);
+		ctrl->nand_stat = stat;
+		wake_up(&ctrl->nand_wait);
+	}
+
+	spin_unlock_irqrestore(&nand_irq_lock, flags);
+
+	return stat;
+}
+
+static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
+{
+	struct fsl_ifc_ctrl *ctrl = data;
+
+	if (check_nand_stat(ctrl))
+		return IRQ_HANDLED;
+
+	return IRQ_NONE;
+}
+
+/*
+ * NOTE: This interrupt is used to report ifc events of various kinds,
+ * such as transaction errors on the chipselects.
+ */
+static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
+{
+	struct fsl_ifc_ctrl *ctrl = data;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	u32 err_axiid, err_srcid, status, cs_err, err_addr;
+	irqreturn_t ret = IRQ_NONE;
+
+	/* read for chip select error */
+	cs_err = in_be32(&ifc->cm_evter_stat);
+	if (cs_err) {
+		dev_err(ctrl->dev, "transaction sent to IFC is not mapped to"
+				"any memory bank 0x%08X\n", cs_err);
+		/* clear the chip select error */
+		out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
+
+		/* read error attribute registers print the error information */
+		status = in_be32(&ifc->cm_erattr0);
+		err_addr = in_be32(&ifc->cm_erattr1);
+
+		if (status & IFC_CM_ERATTR0_ERTYP_READ)
+			dev_err(ctrl->dev, "Read transaction error"
+				"CM_ERATTR0 0x%08X\n", status);
+		else
+			dev_err(ctrl->dev, "Write transaction error"
+				"CM_ERATTR0 0x%08X\n", status);
+
+		err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
+					IFC_CM_ERATTR0_ERAID_SHIFT;
+		dev_err(ctrl->dev, "AXI ID of the error"
+					"transaction 0x%08X\n", err_axiid);
+
+		err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
+					IFC_CM_ERATTR0_ESRCID_SHIFT;
+		dev_err(ctrl->dev, "SRC ID of the error"
+					"transaction 0x%08X\n", err_srcid);
+
+		dev_err(ctrl->dev, "Transaction Address corresponding to error"
+					"ERADDR 0x%08X\n", err_addr);
+
+		ret = IRQ_HANDLED;
+	}
+
+	if (check_nand_stat(ctrl))
+		ret = IRQ_HANDLED;
+
+	return ret;
+}
+
+/*
+ * fsl_ifc_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_ifc_ctrl_probe(struct platform_device *dev)
+{
+	int ret = 0;
+
+
+	dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
+
+	fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
+	if (!fsl_ifc_ctrl_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
+
+	/* IOMAP the entire IFC region */
+	fsl_ifc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
+	if (!fsl_ifc_ctrl_dev->regs) {
+		dev_err(&dev->dev, "failed to get memory region\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* get the Controller level irq */
+	fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
+	if (fsl_ifc_ctrl_dev->irq == NO_IRQ) {
+		dev_err(&dev->dev, "failed to get irq resource "
+							"for IFC\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* get the nand machine irq */
+	fsl_ifc_ctrl_dev->nand_irq =
+			irq_of_parse_and_map(dev->dev.of_node, 1);
+	if (fsl_ifc_ctrl_dev->nand_irq == NO_IRQ) {
+		dev_err(&dev->dev, "failed to get irq resource "
+						"for NAND Machine\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	fsl_ifc_ctrl_dev->dev = &dev->dev;
+
+	ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
+	if (ret < 0)
+		goto err;
+
+	init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
+
+	ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
+			  "fsl-ifc", fsl_ifc_ctrl_dev);
+	if (ret != 0) {
+		dev_err(&dev->dev, "failed to install irq (%d)\n",
+			fsl_ifc_ctrl_dev->irq);
+		goto err_irq;
+	}
+
+	ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq, 0,
+			  "fsl-ifc-nand", fsl_ifc_ctrl_dev);
+	if (ret != 0) {
+		dev_err(&dev->dev, "failed to install irq (%d)\n",
+			fsl_ifc_ctrl_dev->nand_irq);
+		goto err_nandirq;
+	}
+
+	return 0;
+
+err_nandirq:
+	free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
+	irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
+err_irq:
+	free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
+	irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
+err:
+	return ret;
+}
+
+static const struct of_device_id fsl_ifc_match[] = {
+	{
+		.compatible = "fsl,ifc",
+	},
+	{},
+};
+
+static struct platform_driver fsl_ifc_ctrl_driver = {
+	.driver = {
+		.name	= "fsl-ifc",
+		.of_match_table = fsl_ifc_match,
+	},
+	.probe       = fsl_ifc_ctrl_probe,
+	.remove      = fsl_ifc_ctrl_remove,
+};
+
+module_platform_driver(fsl_ifc_ctrl_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 1/2][v2] Integrated Flash Controller support
From: Prabhakar Kushwaha @ 2011-12-27 12:09 UTC (permalink / raw)
  To: linuxppc-dev, linux-mtd
  Cc: Scott Wood, Dipen Dudhat, Liu Shuo, Prabhakar Kushwaha

Integrated Flash Controller supports various flashes like NOR, NAND
and other devices using NOR, NAND and GPCM Machine available on it.
IFC supports four chip selects.

Signed-off-by: Dipen Dudhat <Dipen.Dudhat@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com>
---
 Based upon git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git (branch next)

 Tested on P1010RDB

 Changes for v2: Incorporated Artem Bityutskiy's comment
	- Error handling in fsl_ifc_ctrl_probe
	- Use module_platform_driver() insted of module_init and module_exit

 arch/powerpc/Kconfig               |    4 +
 arch/powerpc/include/asm/fsl_ifc.h |  834 ++++++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/Makefile       |    1 +
 arch/powerpc/sysdev/fsl_ifc.c      |  310 +++++++++++++
 4 files changed, 1149 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/fsl_ifc.h
 create mode 100644 arch/powerpc/sysdev/fsl_ifc.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 7c93c7e..d78cb6e 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -688,6 +688,10 @@ config FSL_LBC
 	  controller.  Also contains some common code used by
 	  drivers for specific local bus peripherals.
 
+config FSL_IFC
+	bool
+        depends on FSL_SOC
+
 config FSL_GTM
 	bool
 	depends on PPC_83xx || QUICC_ENGINE || CPM2
diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h
new file mode 100644
index 0000000..b955012
--- /dev/null
+++ b/arch/powerpc/include/asm/fsl_ifc.h
@@ -0,0 +1,834 @@
+/* Freescale Integrated Flash Controller
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Author: Dipen Dudhat <dipen.dudhat@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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_FSL_IFC_H
+#define __ASM_FSL_IFC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+
+#define FSL_IFC_BANK_COUNT 4
+
+/*
+ * CSPR - Chip Select Property Register
+ */
+#define CSPR_BA				0xFFFF0000
+#define CSPR_BA_SHIFT			16
+#define CSPR_PORT_SIZE			0x00000180
+#define CSPR_PORT_SIZE_SHIFT		7
+/* Port Size 8 bit */
+#define CSPR_PORT_SIZE_8		0x00000080
+/* Port Size 16 bit */
+#define CSPR_PORT_SIZE_16		0x00000100
+/* Port Size 32 bit */
+#define CSPR_PORT_SIZE_32		0x00000180
+/* Write Protect */
+#define CSPR_WP				0x00000040
+#define CSPR_WP_SHIFT			6
+/* Machine Select */
+#define CSPR_MSEL			0x00000006
+#define CSPR_MSEL_SHIFT			1
+/* NOR */
+#define CSPR_MSEL_NOR			0x00000000
+/* NAND */
+#define CSPR_MSEL_NAND			0x00000002
+/* GPCM */
+#define CSPR_MSEL_GPCM			0x00000004
+/* Bank Valid */
+#define CSPR_V				0x00000001
+#define CSPR_V_SHIFT			0
+
+/*
+ * Address Mask Register
+ */
+#define IFC_AMASK_MASK			0xFFFF0000
+#define IFC_AMASK_SHIFT			16
+#define IFC_AMASK(n)			(IFC_AMASK_MASK << \
+					(__ilog2(n) - IFC_AMASK_SHIFT))
+
+/*
+ * Chip Select Option Register IFC_NAND Machine
+ */
+/* Enable ECC Encoder */
+#define CSOR_NAND_ECC_ENC_EN		0x80000000
+#define CSOR_NAND_ECC_MODE_MASK		0x30000000
+/* 4 bit correction per 520 Byte sector */
+#define CSOR_NAND_ECC_MODE_4		0x00000000
+/* 8 bit correction per 528 Byte sector */
+#define CSOR_NAND_ECC_MODE_8		0x10000000
+/* Enable ECC Decoder */
+#define CSOR_NAND_ECC_DEC_EN		0x04000000
+/* Row Address Length */
+#define CSOR_NAND_RAL_MASK		0x01800000
+#define CSOR_NAND_RAL_SHIFT		20
+#define CSOR_NAND_RAL_1			0x00000000
+#define CSOR_NAND_RAL_2			0x00800000
+#define CSOR_NAND_RAL_3			0x01000000
+#define CSOR_NAND_RAL_4			0x01800000
+/* Page Size 512b, 2k, 4k */
+#define CSOR_NAND_PGS_MASK		0x00180000
+#define CSOR_NAND_PGS_SHIFT		16
+#define CSOR_NAND_PGS_512		0x00000000
+#define CSOR_NAND_PGS_2K		0x00080000
+#define CSOR_NAND_PGS_4K		0x00100000
+/* Spare region Size */
+#define CSOR_NAND_SPRZ_MASK		0x0000E000
+#define CSOR_NAND_SPRZ_SHIFT		13
+#define CSOR_NAND_SPRZ_16		0x00000000
+#define CSOR_NAND_SPRZ_64		0x00002000
+#define CSOR_NAND_SPRZ_128		0x00004000
+#define CSOR_NAND_SPRZ_210		0x00006000
+#define CSOR_NAND_SPRZ_218		0x00008000
+#define CSOR_NAND_SPRZ_224		0x0000A000
+/* Pages Per Block */
+#define CSOR_NAND_PB_MASK		0x00000700
+#define CSOR_NAND_PB_SHIFT		8
+#define CSOR_NAND_PB(n)		((__ilog2(n) - 5) << CSOR_NAND_PB_SHIFT)
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NAND_TRHZ_MASK		0x0000001C
+#define CSOR_NAND_TRHZ_SHIFT		2
+#define CSOR_NAND_TRHZ_20		0x00000000
+#define CSOR_NAND_TRHZ_40		0x00000004
+#define CSOR_NAND_TRHZ_60		0x00000008
+#define CSOR_NAND_TRHZ_80		0x0000000C
+#define CSOR_NAND_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_NAND_BCTLD			0x00000001
+
+/*
+ * Chip Select Option Register - NOR Flash Mode
+ */
+/* Enable Address shift Mode */
+#define CSOR_NOR_ADM_SHFT_MODE_EN	0x80000000
+/* Page Read Enable from NOR device */
+#define CSOR_NOR_PGRD_EN		0x10000000
+/* AVD Toggle Enable during Burst Program */
+#define CSOR_NOR_AVD_TGL_PGM_EN		0x01000000
+/* Address Data Multiplexing Shift */
+#define CSOR_NOR_ADM_MASK		0x0003E000
+#define CSOR_NOR_ADM_SHIFT_SHIFT	13
+#define CSOR_NOR_ADM_SHIFT(n)	((n) << CSOR_NOR_ADM_SHIFT_SHIFT)
+/* Type of the NOR device hooked */
+#define CSOR_NOR_NOR_MODE_AYSNC_NOR	0x00000000
+#define CSOR_NOR_NOR_MODE_AVD_NOR	0x00000020
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_NOR_TRHZ_MASK		0x0000001C
+#define CSOR_NOR_TRHZ_SHIFT		2
+#define CSOR_NOR_TRHZ_20		0x00000000
+#define CSOR_NOR_TRHZ_40		0x00000004
+#define CSOR_NOR_TRHZ_60		0x00000008
+#define CSOR_NOR_TRHZ_80		0x0000000C
+#define CSOR_NOR_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_NOR_BCTLD			0x00000001
+
+/*
+ * Chip Select Option Register - GPCM Mode
+ */
+/* GPCM Mode - Normal */
+#define CSOR_GPCM_GPMODE_NORMAL		0x00000000
+/* GPCM Mode - GenericASIC */
+#define CSOR_GPCM_GPMODE_ASIC		0x80000000
+/* Parity Mode odd/even */
+#define CSOR_GPCM_PARITY_EVEN		0x40000000
+/* Parity Checking enable/disable */
+#define CSOR_GPCM_PAR_EN		0x20000000
+/* GPCM Timeout Count */
+#define CSOR_GPCM_GPTO_MASK		0x0F000000
+#define CSOR_GPCM_GPTO_SHIFT		24
+#define CSOR_GPCM_GPTO(n)	((__ilog2(n) - 8) << CSOR_GPCM_GPTO_SHIFT)
+/* GPCM External Access Termination mode for read access */
+#define CSOR_GPCM_RGETA_EXT		0x00080000
+/* GPCM External Access Termination mode for write access */
+#define CSOR_GPCM_WGETA_EXT		0x00040000
+/* Address Data Multiplexing Shift */
+#define CSOR_GPCM_ADM_MASK		0x0003E000
+#define CSOR_GPCM_ADM_SHIFT_SHIFT	13
+#define CSOR_GPCM_ADM_SHIFT(n)	((n) << CSOR_GPCM_ADM_SHIFT_SHIFT)
+/* Generic ASIC Parity error indication delay */
+#define CSOR_GPCM_GAPERRD_MASK		0x00000180
+#define CSOR_GPCM_GAPERRD_SHIFT		7
+#define CSOR_GPCM_GAPERRD(n)	(((n) - 1) << CSOR_GPCM_GAPERRD_SHIFT)
+/* Time for Read Enable High to Output High Impedance */
+#define CSOR_GPCM_TRHZ_MASK		0x0000001C
+#define CSOR_GPCM_TRHZ_20		0x00000000
+#define CSOR_GPCM_TRHZ_40		0x00000004
+#define CSOR_GPCM_TRHZ_60		0x00000008
+#define CSOR_GPCM_TRHZ_80		0x0000000C
+#define CSOR_GPCM_TRHZ_100		0x00000010
+/* Buffer control disable */
+#define CSOR_GPCM_BCTLD			0x00000001
+
+/*
+ * Ready Busy Status Register (RB_STAT)
+ */
+/* CSn is READY */
+#define IFC_RB_STAT_READY_CS0		0x80000000
+#define IFC_RB_STAT_READY_CS1		0x40000000
+#define IFC_RB_STAT_READY_CS2		0x20000000
+#define IFC_RB_STAT_READY_CS3		0x10000000
+
+/*
+ * General Control Register (GCR)
+ */
+#define IFC_GCR_MASK			0x8000F800
+/* reset all IFC hardware */
+#define IFC_GCR_SOFT_RST_ALL		0x80000000
+/* Turnaroud Time of external buffer */
+#define IFC_GCR_TBCTL_TRN_TIME		0x0000F800
+#define IFC_GCR_TBCTL_TRN_TIME_SHIFT	11
+
+/*
+ * Common Event and Error Status Register (CM_EVTER_STAT)
+ */
+/* Chip select error */
+#define IFC_CM_EVTER_STAT_CSER		0x80000000
+
+/*
+ * Common Event and Error Enable Register (CM_EVTER_EN)
+ */
+/* Chip select error checking enable */
+#define IFC_CM_EVTER_EN_CSEREN		0x80000000
+
+/*
+ * Common Event and Error Interrupt Enable Register (CM_EVTER_INTR_EN)
+ */
+/* Chip select error interrupt enable */
+#define IFC_CM_EVTER_INTR_EN_CSERIREN	0x80000000
+
+/*
+ * Common Transfer Error Attribute Register-0 (CM_ERATTR0)
+ */
+/* transaction type of error Read/Write */
+#define IFC_CM_ERATTR0_ERTYP_READ	0x80000000
+#define IFC_CM_ERATTR0_ERAID		0x0FF00000
+#define IFC_CM_ERATTR0_ERAID_SHIFT	20
+#define IFC_CM_ERATTR0_ESRCID		0x0000FF00
+#define IFC_CM_ERATTR0_ESRCID_SHIFT	8
+
+/*
+ * Clock Control Register (CCR)
+ */
+#define IFC_CCR_MASK			0x0F0F8800
+/* Clock division ratio */
+#define IFC_CCR_CLK_DIV_MASK		0x0F000000
+#define IFC_CCR_CLK_DIV_SHIFT		24
+#define IFC_CCR_CLK_DIV(n)		((n-1) << IFC_CCR_CLK_DIV_SHIFT)
+/* IFC Clock Delay */
+#define IFC_CCR_CLK_DLY_MASK		0x000F0000
+#define IFC_CCR_CLK_DLY_SHIFT		16
+#define IFC_CCR_CLK_DLY(n)		((n) << IFC_CCR_CLK_DLY_SHIFT)
+/* Invert IFC clock before sending out */
+#define IFC_CCR_INV_CLK_EN		0x00008000
+/* Fedback IFC Clock */
+#define IFC_CCR_FB_IFC_CLK_SEL		0x00000800
+
+/*
+ * Clock Status Register (CSR)
+ */
+/* Clk is stable */
+#define IFC_CSR_CLK_STAT_STABLE		0x80000000
+
+/*
+ * IFC_NAND Machine Specific Registers
+ */
+/*
+ * NAND Configuration Register (NCFGR)
+ */
+/* Auto Boot Mode */
+#define IFC_NAND_NCFGR_BOOT		0x80000000
+/* Addressing Mode-ROW0+n/COL0 */
+#define IFC_NAND_NCFGR_ADDR_MODE_RC0	0x00000000
+/* Addressing Mode-ROW0+n/COL0+n */
+#define IFC_NAND_NCFGR_ADDR_MODE_RC1	0x00400000
+/* Number of loop iterations of FIR sequences for multi page operations */
+#define IFC_NAND_NCFGR_NUM_LOOP_MASK	0x0000F000
+#define IFC_NAND_NCFGR_NUM_LOOP_SHIFT	12
+#define IFC_NAND_NCFGR_NUM_LOOP(n)	((n) << IFC_NAND_NCFGR_NUM_LOOP_SHIFT)
+/* Number of wait cycles */
+#define IFC_NAND_NCFGR_NUM_WAIT_MASK	0x000000FF
+#define IFC_NAND_NCFGR_NUM_WAIT_SHIFT	0
+
+/*
+ * NAND Flash Command Registers (NAND_FCR0/NAND_FCR1)
+ */
+/* General purpose FCM flash command bytes CMD0-CMD7 */
+#define IFC_NAND_FCR0_CMD0		0xFF000000
+#define IFC_NAND_FCR0_CMD0_SHIFT	24
+#define IFC_NAND_FCR0_CMD1		0x00FF0000
+#define IFC_NAND_FCR0_CMD1_SHIFT	16
+#define IFC_NAND_FCR0_CMD2		0x0000FF00
+#define IFC_NAND_FCR0_CMD2_SHIFT	8
+#define IFC_NAND_FCR0_CMD3		0x000000FF
+#define IFC_NAND_FCR0_CMD3_SHIFT	0
+#define IFC_NAND_FCR1_CMD4		0xFF000000
+#define IFC_NAND_FCR1_CMD4_SHIFT	24
+#define IFC_NAND_FCR1_CMD5		0x00FF0000
+#define IFC_NAND_FCR1_CMD5_SHIFT	16
+#define IFC_NAND_FCR1_CMD6		0x0000FF00
+#define IFC_NAND_FCR1_CMD6_SHIFT	8
+#define IFC_NAND_FCR1_CMD7		0x000000FF
+#define IFC_NAND_FCR1_CMD7_SHIFT	0
+
+/*
+ * Flash ROW and COL Address Register (ROWn, COLn)
+ */
+/* Main/spare region locator */
+#define IFC_NAND_COL_MS			0x80000000
+/* Column Address */
+#define IFC_NAND_COL_CA_MASK		0x00000FFF
+
+/*
+ * NAND Flash Byte Count Register (NAND_BC)
+ */
+/* Byte Count for read/Write */
+#define IFC_NAND_BC			0x000001FF
+
+/*
+ * NAND Flash Instruction Registers (NAND_FIR0/NAND_FIR1/NAND_FIR2)
+ */
+/* NAND Machine specific opcodes OP0-OP14*/
+#define IFC_NAND_FIR0_OP0		0xFC000000
+#define IFC_NAND_FIR0_OP0_SHIFT		26
+#define IFC_NAND_FIR0_OP1		0x03F00000
+#define IFC_NAND_FIR0_OP1_SHIFT		20
+#define IFC_NAND_FIR0_OP2		0x000FC000
+#define IFC_NAND_FIR0_OP2_SHIFT		14
+#define IFC_NAND_FIR0_OP3		0x00003F00
+#define IFC_NAND_FIR0_OP3_SHIFT		8
+#define IFC_NAND_FIR0_OP4		0x000000FC
+#define IFC_NAND_FIR0_OP4_SHIFT		2
+#define IFC_NAND_FIR1_OP5		0xFC000000
+#define IFC_NAND_FIR1_OP5_SHIFT		26
+#define IFC_NAND_FIR1_OP6		0x03F00000
+#define IFC_NAND_FIR1_OP6_SHIFT		20
+#define IFC_NAND_FIR1_OP7		0x000FC000
+#define IFC_NAND_FIR1_OP7_SHIFT		14
+#define IFC_NAND_FIR1_OP8		0x00003F00
+#define IFC_NAND_FIR1_OP8_SHIFT		8
+#define IFC_NAND_FIR1_OP9		0x000000FC
+#define IFC_NAND_FIR1_OP9_SHIFT		2
+#define IFC_NAND_FIR2_OP10		0xFC000000
+#define IFC_NAND_FIR2_OP10_SHIFT	26
+#define IFC_NAND_FIR2_OP11		0x03F00000
+#define IFC_NAND_FIR2_OP11_SHIFT	20
+#define IFC_NAND_FIR2_OP12		0x000FC000
+#define IFC_NAND_FIR2_OP12_SHIFT	14
+#define IFC_NAND_FIR2_OP13		0x00003F00
+#define IFC_NAND_FIR2_OP13_SHIFT	8
+#define IFC_NAND_FIR2_OP14		0x000000FC
+#define IFC_NAND_FIR2_OP14_SHIFT	2
+
+/*
+ * Instruction opcodes to be programmed
+ * in FIR registers- 6bits
+ */
+enum ifc_nand_fir_opcodes {
+	IFC_FIR_OP_NOP,
+	IFC_FIR_OP_CA0,
+	IFC_FIR_OP_CA1,
+	IFC_FIR_OP_CA2,
+	IFC_FIR_OP_CA3,
+	IFC_FIR_OP_RA0,
+	IFC_FIR_OP_RA1,
+	IFC_FIR_OP_RA2,
+	IFC_FIR_OP_RA3,
+	IFC_FIR_OP_CMD0,
+	IFC_FIR_OP_CMD1,
+	IFC_FIR_OP_CMD2,
+	IFC_FIR_OP_CMD3,
+	IFC_FIR_OP_CMD4,
+	IFC_FIR_OP_CMD5,
+	IFC_FIR_OP_CMD6,
+	IFC_FIR_OP_CMD7,
+	IFC_FIR_OP_CW0,
+	IFC_FIR_OP_CW1,
+	IFC_FIR_OP_CW2,
+	IFC_FIR_OP_CW3,
+	IFC_FIR_OP_CW4,
+	IFC_FIR_OP_CW5,
+	IFC_FIR_OP_CW6,
+	IFC_FIR_OP_CW7,
+	IFC_FIR_OP_WBCD,
+	IFC_FIR_OP_RBCD,
+	IFC_FIR_OP_BTRD,
+	IFC_FIR_OP_RDSTAT,
+	IFC_FIR_OP_NWAIT,
+	IFC_FIR_OP_WFR,
+	IFC_FIR_OP_SBRD,
+	IFC_FIR_OP_UA,
+	IFC_FIR_OP_RB,
+};
+
+/*
+ * NAND Chip Select Register (NAND_CSEL)
+ */
+#define IFC_NAND_CSEL			0x0C000000
+#define IFC_NAND_CSEL_SHIFT		26
+#define IFC_NAND_CSEL_CS0		0x00000000
+#define IFC_NAND_CSEL_CS1		0x04000000
+#define IFC_NAND_CSEL_CS2		0x08000000
+#define IFC_NAND_CSEL_CS3		0x0C000000
+
+/*
+ * NAND Operation Sequence Start (NANDSEQ_STRT)
+ */
+/* NAND Flash Operation Start */
+#define IFC_NAND_SEQ_STRT_FIR_STRT	0x80000000
+/* Automatic Erase */
+#define IFC_NAND_SEQ_STRT_AUTO_ERS	0x00800000
+/* Automatic Program */
+#define IFC_NAND_SEQ_STRT_AUTO_PGM	0x00100000
+/* Automatic Copyback */
+#define IFC_NAND_SEQ_STRT_AUTO_CPB	0x00020000
+/* Automatic Read Operation */
+#define IFC_NAND_SEQ_STRT_AUTO_RD	0x00004000
+/* Automatic Status Read */
+#define IFC_NAND_SEQ_STRT_AUTO_STAT_RD	0x00000800
+
+/*
+ * NAND Event and Error Status Register (NAND_EVTER_STAT)
+ */
+/* Operation Complete */
+#define IFC_NAND_EVTER_STAT_OPC		0x80000000
+/* Flash Timeout Error */
+#define IFC_NAND_EVTER_STAT_FTOER	0x08000000
+/* Write Protect Error */
+#define IFC_NAND_EVTER_STAT_WPER	0x04000000
+/* ECC Error */
+#define IFC_NAND_EVTER_STAT_ECCER	0x02000000
+/* RCW Load Done */
+#define IFC_NAND_EVTER_STAT_RCW_DN	0x00008000
+/* Boot Loadr Done */
+#define IFC_NAND_EVTER_STAT_BOOT_DN	0x00004000
+/* Bad Block Indicator search select */
+#define IFC_NAND_EVTER_STAT_BBI_SRCH_SE	0x00000800
+
+/*
+ * NAND Flash Page Read Completion Event Status Register
+ * (PGRDCMPL_EVT_STAT)
+ */
+#define PGRDCMPL_EVT_STAT_MASK		0xFFFF0000
+/* Small Page 0-15 Done */
+#define PGRDCMPL_EVT_STAT_SECTION_SP(n)	(1 << (31 - (n)))
+/* Large Page(2K) 0-3 Done */
+#define PGRDCMPL_EVT_STAT_LP_2K(n)	(0xF << (28 - (n)*4))
+/* Large Page(4K) 0-1 Done */
+#define PGRDCMPL_EVT_STAT_LP_4K(n)	(0xFF << (24 - (n)*8))
+
+/*
+ * NAND Event and Error Enable Register (NAND_EVTER_EN)
+ */
+/* Operation complete event enable */
+#define IFC_NAND_EVTER_EN_OPC_EN	0x80000000
+/* Page read complete event enable */
+#define IFC_NAND_EVTER_EN_PGRDCMPL_EN	0x20000000
+/* Flash Timeout error enable */
+#define IFC_NAND_EVTER_EN_FTOER_EN	0x08000000
+/* Write Protect error enable */
+#define IFC_NAND_EVTER_EN_WPER_EN	0x04000000
+/* ECC error logging enable */
+#define IFC_NAND_EVTER_EN_ECCER_EN	0x02000000
+
+/*
+ * NAND Event and Error Interrupt Enable Register (NAND_EVTER_INTR_EN)
+ */
+/* Enable interrupt for operation complete */
+#define IFC_NAND_EVTER_INTR_OPCIR_EN		0x80000000
+/* Enable interrupt for Page read complete */
+#define IFC_NAND_EVTER_INTR_PGRDCMPLIR_EN	0x20000000
+/* Enable interrupt for Flash timeout error */
+#define IFC_NAND_EVTER_INTR_FTOERIR_EN		0x08000000
+/* Enable interrupt for Write protect error */
+#define IFC_NAND_EVTER_INTR_WPERIR_EN		0x04000000
+/* Enable interrupt for ECC error*/
+#define IFC_NAND_EVTER_INTR_ECCERIR_EN		0x02000000
+
+/*
+ * NAND Transfer Error Attribute Register-0 (NAND_ERATTR0)
+ */
+#define IFC_NAND_ERATTR0_MASK		0x0C080000
+/* Error on CS0-3 for NAND */
+#define IFC_NAND_ERATTR0_ERCS_CS0	0x00000000
+#define IFC_NAND_ERATTR0_ERCS_CS1	0x04000000
+#define IFC_NAND_ERATTR0_ERCS_CS2	0x08000000
+#define IFC_NAND_ERATTR0_ERCS_CS3	0x0C000000
+/* Transaction type of error Read/Write */
+#define IFC_NAND_ERATTR0_ERTTYPE_READ	0x00080000
+
+/*
+ * NAND Flash Status Register (NAND_FSR)
+ */
+/* First byte of data read from read status op */
+#define IFC_NAND_NFSR_RS0		0xFF000000
+/* Second byte of data read from read status op */
+#define IFC_NAND_NFSR_RS1		0x00FF0000
+
+/*
+ * ECC Error Status Registers (ECCSTAT0-ECCSTAT3)
+ */
+/* Number of ECC errors on sector n (n = 0-15) */
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR0_SHIFT	24
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR1_SHIFT	16
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR2_SHIFT	8
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT0_ERRCNT_SECTOR3_SHIFT	0
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR4_SHIFT	24
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR5_SHIFT	16
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR6_SHIFT	8
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT1_ERRCNT_SECTOR7_SHIFT	0
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR8_SHIFT	24
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR9_SHIFT	16
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR10_SHIFT	8
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT2_ERRCNT_SECTOR11_SHIFT	0
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_MASK	0x0F000000
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR12_SHIFT	24
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_MASK	0x000F0000
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR13_SHIFT	16
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_MASK	0x00000F00
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR14_SHIFT	8
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_MASK	0x0000000F
+#define IFC_NAND_ECCSTAT3_ERRCNT_SECTOR15_SHIFT	0
+
+/*
+ * NAND Control Register (NANDCR)
+ */
+#define IFC_NAND_NCR_FTOCNT_MASK	0x1E000000
+#define IFC_NAND_NCR_FTOCNT_SHIFT	25
+#define IFC_NAND_NCR_FTOCNT(n)	((_ilog2(n) - 8)  << IFC_NAND_NCR_FTOCNT_SHIFT)
+
+/*
+ * NAND_AUTOBOOT_TRGR
+ */
+/* Trigger RCW load */
+#define IFC_NAND_AUTOBOOT_TRGR_RCW_LD	0x80000000
+/* Trigget Auto Boot */
+#define IFC_NAND_AUTOBOOT_TRGR_BOOT_LD	0x20000000
+
+/*
+ * NAND_MDR
+ */
+/* 1st read data byte when opcode SBRD */
+#define IFC_NAND_MDR_RDATA0		0xFF000000
+/* 2nd read data byte when opcode SBRD */
+#define IFC_NAND_MDR_RDATA1		0x00FF0000
+
+/*
+ * NOR Machine Specific Registers
+ */
+/*
+ * NOR Event and Error Status Register (NOR_EVTER_STAT)
+ */
+/* NOR Command Sequence Operation Complete */
+#define IFC_NOR_EVTER_STAT_OPC_NOR	0x80000000
+/* Write Protect Error */
+#define IFC_NOR_EVTER_STAT_WPER		0x04000000
+/* Command Sequence Timeout Error */
+#define IFC_NOR_EVTER_STAT_STOER	0x01000000
+
+/*
+ * NOR Event and Error Enable Register (NOR_EVTER_EN)
+ */
+/* NOR Command Seq complete event enable */
+#define IFC_NOR_EVTER_EN_OPCEN_NOR	0x80000000
+/* Write Protect Error Checking Enable */
+#define IFC_NOR_EVTER_EN_WPEREN		0x04000000
+/* Timeout Error Enable */
+#define IFC_NOR_EVTER_EN_STOEREN	0x01000000
+
+/*
+ * NOR Event and Error Interrupt Enable Register (NOR_EVTER_INTR_EN)
+ */
+/* Enable interrupt for OPC complete */
+#define IFC_NOR_EVTER_INTR_OPCEN_NOR	0x80000000
+/* Enable interrupt for write protect error */
+#define IFC_NOR_EVTER_INTR_WPEREN	0x04000000
+/* Enable interrupt for timeout error */
+#define IFC_NOR_EVTER_INTR_STOEREN	0x01000000
+
+/*
+ * NOR Transfer Error Attribute Register-0 (NOR_ERATTR0)
+ */
+/* Source ID for error transaction */
+#define IFC_NOR_ERATTR0_ERSRCID		0xFF000000
+/* AXI ID for error transation */
+#define IFC_NOR_ERATTR0_ERAID		0x000FF000
+/* Chip select corresponds to NOR error */
+#define IFC_NOR_ERATTR0_ERCS_CS0	0x00000000
+#define IFC_NOR_ERATTR0_ERCS_CS1	0x00000010
+#define IFC_NOR_ERATTR0_ERCS_CS2	0x00000020
+#define IFC_NOR_ERATTR0_ERCS_CS3	0x00000030
+/* Type of transaction read/write */
+#define IFC_NOR_ERATTR0_ERTYPE_READ	0x00000001
+
+/*
+ * NOR Transfer Error Attribute Register-2 (NOR_ERATTR2)
+ */
+#define IFC_NOR_ERATTR2_ER_NUM_PHASE_EXP	0x000F0000
+#define IFC_NOR_ERATTR2_ER_NUM_PHASE_PER	0x00000F00
+
+/*
+ * NOR Control Register (NORCR)
+ */
+#define IFC_NORCR_MASK			0x0F0F0000
+/* No. of Address/Data Phase */
+#define IFC_NORCR_NUM_PHASE_MASK	0x0F000000
+#define IFC_NORCR_NUM_PHASE_SHIFT	24
+#define IFC_NORCR_NUM_PHASE(n)	((n-1) << IFC_NORCR_NUM_PHASE_SHIFT)
+/* Sequence Timeout Count */
+#define IFC_NORCR_STOCNT_MASK		0x000F0000
+#define IFC_NORCR_STOCNT_SHIFT		16
+#define IFC_NORCR_STOCNT(n)	((__ilog2(n) - 8) << IFC_NORCR_STOCNT_SHIFT)
+
+/*
+ * GPCM Machine specific registers
+ */
+/*
+ * GPCM Event and Error Status Register (GPCM_EVTER_STAT)
+ */
+/* Timeout error */
+#define IFC_GPCM_EVTER_STAT_TOER	0x04000000
+/* Parity error */
+#define IFC_GPCM_EVTER_STAT_PER		0x01000000
+
+/*
+ * GPCM Event and Error Enable Register (GPCM_EVTER_EN)
+ */
+/* Timeout error enable */
+#define IFC_GPCM_EVTER_EN_TOER_EN	0x04000000
+/* Parity error enable */
+#define IFC_GPCM_EVTER_EN_PER_EN	0x01000000
+
+/*
+ * GPCM Event and Error Interrupt Enable Register (GPCM_EVTER_INTR_EN)
+ */
+/* Enable Interrupt for timeout error */
+#define IFC_GPCM_EEIER_TOERIR_EN	0x04000000
+/* Enable Interrupt for Parity error */
+#define IFC_GPCM_EEIER_PERIR_EN		0x01000000
+
+/*
+ * GPCM Transfer Error Attribute Register-0 (GPCM_ERATTR0)
+ */
+/* Source ID for error transaction */
+#define IFC_GPCM_ERATTR0_ERSRCID	0xFF000000
+/* AXI ID for error transaction */
+#define IFC_GPCM_ERATTR0_ERAID		0x000FF000
+/* Chip select corresponds to GPCM error */
+#define IFC_GPCM_ERATTR0_ERCS_CS0	0x00000000
+#define IFC_GPCM_ERATTR0_ERCS_CS1	0x00000040
+#define IFC_GPCM_ERATTR0_ERCS_CS2	0x00000080
+#define IFC_GPCM_ERATTR0_ERCS_CS3	0x000000C0
+/* Type of transaction read/Write */
+#define IFC_GPCM_ERATTR0_ERTYPE_READ	0x00000001
+
+/*
+ * GPCM Transfer Error Attribute Register-2 (GPCM_ERATTR2)
+ */
+/* On which beat of address/data parity error is observed */
+#define IFC_GPCM_ERATTR2_PERR_BEAT		0x00000C00
+/* Parity Error on byte */
+#define IFC_GPCM_ERATTR2_PERR_BYTE		0x000000F0
+/* Parity Error reported in addr or data phase */
+#define IFC_GPCM_ERATTR2_PERR_DATA_PHASE	0x00000001
+
+/*
+ * GPCM Status Register (GPCM_STAT)
+ */
+#define IFC_GPCM_STAT_BSY		0x80000000  /* GPCM is busy */
+
+/*
+ * IFC Controller NAND Machine registers
+ */
+struct fsl_ifc_nand {
+	__be32 ncfgr;
+	u32 res1[0x4];
+	__be32 nand_fcr0;
+	__be32 nand_fcr1;
+	u32 res2[0x8];
+	__be32 row0;
+	u32 res3;
+	__be32 col0;
+	u32 res4;
+	__be32 row1;
+	u32 res5;
+	__be32 col1;
+	u32 res6;
+	__be32 row2;
+	u32 res7;
+	__be32 col2;
+	u32 res8;
+	__be32 row3;
+	u32 res9;
+	__be32 col3;
+	u32 res10[0x24];
+	__be32 nand_fbcr;
+	u32 res11;
+	__be32 nand_fir0;
+	__be32 nand_fir1;
+	__be32 nand_fir2;
+	u32 res12[0x10];
+	__be32 nand_csel;
+	u32 res13;
+	__be32 nandseq_strt;
+	u32 res14;
+	__be32 nand_evter_stat;
+	u32 res15;
+	__be32 pgrdcmpl_evt_stat;
+	u32 res16[0x2];
+	__be32 nand_evter_en;
+	u32 res17[0x2];
+	__be32 nand_evter_intr_en;
+	u32 res18[0x2];
+	__be32 nand_erattr0;
+	__be32 nand_erattr1;
+	u32 res19[0x10];
+	__be32 nand_fsr;
+	u32 res20;
+	__be32 nand_eccstat[4];
+	u32 res21[0x20];
+	__be32 nanndcr;
+	u32 res22[0x2];
+	__be32 nand_autoboot_trgr;
+	u32 res23;
+	__be32 nand_mdr;
+	u32 res24[0x5C];
+};
+
+/*
+ * IFC controller NOR Machine registers
+ */
+struct fsl_ifc_nor {
+	__be32 nor_evter_stat;
+	u32 res1[0x2];
+	__be32 nor_evter_en;
+	u32 res2[0x2];
+	__be32 nor_evter_intr_en;
+	u32 res3[0x2];
+	__be32 nor_erattr0;
+	__be32 nor_erattr1;
+	__be32 nor_erattr2;
+	u32 res4[0x4];
+	__be32 norcr;
+	u32 res5[0xEF];
+};
+
+/*
+ * IFC controller GPCM Machine registers
+ */
+struct fsl_ifc_gpcm {
+	__be32 gpcm_evter_stat;
+	u32 res1[0x2];
+	__be32 gpcm_evter_en;
+	u32 res2[0x2];
+	__be32 gpcm_evter_intr_en;
+	u32 res3[0x2];
+	__be32 gpcm_erattr0;
+	__be32 gpcm_erattr1;
+	__be32 gpcm_erattr2;
+	__be32 gpcm_stat;
+	u32 res4[0x1F3];
+};
+
+/*
+ * IFC Controller Registers
+ */
+struct fsl_ifc_regs {
+	__be32 ifc_rev;
+	u32 res1[0x3];
+	struct {
+		__be32 cspr;
+		u32 res2[0x2];
+	} cspr_cs[FSL_IFC_BANK_COUNT];
+	u32 res3[0x18];
+	struct {
+		__be32 amask;
+		u32 res4[0x2];
+	} amask_cs[FSL_IFC_BANK_COUNT];
+	u32 res5[0x18];
+	struct {
+		__be32 csor;
+		u32 res6[0x2];
+	} csor_cs[FSL_IFC_BANK_COUNT];
+	u32 res7[0x18];
+	struct {
+		__be32 ftim[4];
+		u32 res8[0x8];
+	} ftim_cs[FSL_IFC_BANK_COUNT];
+	u32 res9[0x60];
+	__be32 rb_stat;
+	u32 res10[0x2];
+	__be32 ifc_gcr;
+	u32 res11[0x2];
+	__be32 cm_evter_stat;
+	u32 res12[0x2];
+	__be32 cm_evter_en;
+	u32 res13[0x2];
+	__be32 cm_evter_intr_en;
+	u32 res14[0x2];
+	__be32 cm_erattr0;
+	__be32 cm_erattr1;
+	u32 res15[0x2];
+	__be32 ifc_ccr;
+	__be32 ifc_csr;
+	u32 res16[0x2EB];
+	struct fsl_ifc_nand ifc_nand;
+	struct fsl_ifc_nor ifc_nor;
+	struct fsl_ifc_gpcm ifc_gpcm;
+};
+
+extern unsigned int convert_ifc_address(phys_addr_t addr_base);
+extern int fsl_ifc_find(phys_addr_t addr_base);
+
+/* overview of the fsl ifc controller */
+
+struct fsl_ifc_ctrl {
+	/* device info */
+	struct device			*dev;
+	struct fsl_ifc_regs __iomem	*regs;
+	int				irq;
+	int				nand_irq;
+	spinlock_t			lock;
+	void				*nand;
+
+	u32 nand_stat;
+	wait_queue_head_t nand_wait;
+};
+
+extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
+
+
+#endif /* __ASM_FSL_IFC_H */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 8dea593..5e37b47 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
 obj-$(CONFIG_FSL_PCI)		+= fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)		+= fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)		+= fsl_lbc.o
+obj-$(CONFIG_FSL_IFC)		+= fsl_ifc.o
 obj-$(CONFIG_FSL_GTM)		+= fsl_gtm.o
 obj-$(CONFIG_FSL_85XX_CACHE_SRAM)	+= fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)	+= simple_gpio.o
diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c
new file mode 100644
index 0000000..b31f19f
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_ifc.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc
+ *
+ * Freescale Integrated Flash Controller
+ *
+ * Author: Dipen Dudhat <Dipen.Dudhat@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 the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/fsl_ifc.h>
+
+struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev;
+EXPORT_SYMBOL(fsl_ifc_ctrl_dev);
+
+/*
+ * convert_ifc_address - convert the base address
+ * @addr_base:	base address of the memory bank
+ */
+unsigned int convert_ifc_address(phys_addr_t addr_base)
+{
+	return addr_base & CSPR_BA;
+}
+EXPORT_SYMBOL(convert_ifc_address);
+
+/*
+ * fsl_ifc_find - find IFC bank
+ * @addr_base:	base address of the memory bank
+ *
+ * This function walks IFC banks comparing "Base address" field of the CSPR
+ * registers with the supplied addr_base argument. When bases match this
+ * function returns bank number (starting with 0), otherwise it returns
+ * appropriate errno value.
+ */
+int fsl_ifc_find(phys_addr_t addr_base)
+{
+	int i = 0;
+
+	if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
+		return -ENODEV;
+
+	for (i = 0; i < ARRAY_SIZE(fsl_ifc_ctrl_dev->regs->cspr_cs); i++) {
+		__be32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
+		if (cspr & CSPR_V && (cspr & CSPR_BA) ==
+				convert_ifc_address(addr_base))
+			return i;
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL(fsl_ifc_find);
+
+static int __devinit fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
+{
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+
+	/*
+	 * Clear all the common status and event registers
+	 */
+	if (in_be32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
+		out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
+
+	/* enable all error and events */
+	out_be32(&ifc->cm_evter_en, IFC_CM_EVTER_EN_CSEREN);
+
+	/* enable all error and event interrupts */
+	out_be32(&ifc->cm_evter_intr_en, IFC_CM_EVTER_INTR_EN_CSERIREN);
+	out_be32(&ifc->cm_erattr0, 0x0);
+	out_be32(&ifc->cm_erattr1, 0x0);
+
+	return 0;
+}
+
+static int fsl_ifc_ctrl_remove(struct platform_device *dev)
+{
+	struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
+
+	free_irq(ctrl->nand_irq, ctrl);
+	free_irq(ctrl->irq, ctrl);
+
+	irq_dispose_mapping(ctrl->nand_irq);
+	irq_dispose_mapping(ctrl->irq);
+
+	iounmap(ctrl->regs);
+
+	dev_set_drvdata(&dev->dev, NULL);
+	kfree(ctrl);
+
+	return 0;
+}
+
+/*
+ * NAND events are split between an operational interrupt which only
+ * receives OPC, and an error interrupt that receives everything else,
+ * including non-NAND errors.  Whichever interrupt gets to it first
+ * records the status and wakes the wait queue.
+ */
+static DEFINE_SPINLOCK(nand_irq_lock);
+
+static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
+{
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	unsigned long flags;
+	u32 stat;
+
+	spin_lock_irqsave(&nand_irq_lock, flags);
+
+	stat = in_be32(&ifc->ifc_nand.nand_evter_stat);
+	if (stat) {
+		out_be32(&ifc->ifc_nand.nand_evter_stat, stat);
+		ctrl->nand_stat = stat;
+		wake_up(&ctrl->nand_wait);
+	}
+
+	spin_unlock_irqrestore(&nand_irq_lock, flags);
+
+	return stat;
+}
+
+static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
+{
+	struct fsl_ifc_ctrl *ctrl = data;
+
+	if (check_nand_stat(ctrl))
+		return IRQ_HANDLED;
+
+	return IRQ_NONE;
+}
+
+/*
+ * NOTE: This interrupt is used to report ifc events of various kinds,
+ * such as transaction errors on the chipselects.
+ */
+static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
+{
+	struct fsl_ifc_ctrl *ctrl = data;
+	struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
+	u32 err_axiid, err_srcid, status, cs_err, err_addr;
+	irqreturn_t ret = IRQ_NONE;
+
+	/* read for chip select error */
+	cs_err = in_be32(&ifc->cm_evter_stat);
+	if (cs_err) {
+		dev_err(ctrl->dev, "transaction sent to IFC is not mapped to"
+				"any memory bank 0x%08X\n", cs_err);
+		/* clear the chip select error */
+		out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER);
+
+		/* read error attribute registers print the error information */
+		status = in_be32(&ifc->cm_erattr0);
+		err_addr = in_be32(&ifc->cm_erattr1);
+
+		if (status & IFC_CM_ERATTR0_ERTYP_READ)
+			dev_err(ctrl->dev, "Read transaction error"
+				"CM_ERATTR0 0x%08X\n", status);
+		else
+			dev_err(ctrl->dev, "Write transaction error"
+				"CM_ERATTR0 0x%08X\n", status);
+
+		err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
+					IFC_CM_ERATTR0_ERAID_SHIFT;
+		dev_err(ctrl->dev, "AXI ID of the error"
+					"transaction 0x%08X\n", err_axiid);
+
+		err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
+					IFC_CM_ERATTR0_ESRCID_SHIFT;
+		dev_err(ctrl->dev, "SRC ID of the error"
+					"transaction 0x%08X\n", err_srcid);
+
+		dev_err(ctrl->dev, "Transaction Address corresponding to error"
+					"ERADDR 0x%08X\n", err_addr);
+
+		ret = IRQ_HANDLED;
+	}
+
+	if (check_nand_stat(ctrl))
+		ret = IRQ_HANDLED;
+
+	return ret;
+}
+
+/*
+ * fsl_ifc_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_ifc_ctrl_probe(struct platform_device *dev)
+{
+	int ret = 0;
+
+
+	dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
+
+	fsl_ifc_ctrl_dev = kzalloc(sizeof(*fsl_ifc_ctrl_dev), GFP_KERNEL);
+	if (!fsl_ifc_ctrl_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
+
+	/* IOMAP the entire IFC region */
+	fsl_ifc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
+	if (!fsl_ifc_ctrl_dev->regs) {
+		dev_err(&dev->dev, "failed to get memory region\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* get the Controller level irq */
+	fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
+	if (fsl_ifc_ctrl_dev->irq == NO_IRQ) {
+		dev_err(&dev->dev, "failed to get irq resource "
+							"for IFC\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	/* get the nand machine irq */
+	fsl_ifc_ctrl_dev->nand_irq =
+			irq_of_parse_and_map(dev->dev.of_node, 1);
+	if (fsl_ifc_ctrl_dev->nand_irq == NO_IRQ) {
+		dev_err(&dev->dev, "failed to get irq resource "
+						"for NAND Machine\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	fsl_ifc_ctrl_dev->dev = &dev->dev;
+
+	ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
+	if (ret < 0)
+		goto err;
+
+	init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
+
+	ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED,
+			  "fsl-ifc", fsl_ifc_ctrl_dev);
+	if (ret != 0) {
+		dev_err(&dev->dev, "failed to install irq (%d)\n",
+			fsl_ifc_ctrl_dev->irq);
+		goto err_irq;
+	}
+
+	ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq, 0,
+			  "fsl-ifc-nand", fsl_ifc_ctrl_dev);
+	if (ret != 0) {
+		dev_err(&dev->dev, "failed to install irq (%d)\n",
+			fsl_ifc_ctrl_dev->nand_irq);
+		goto err_nandirq;
+	}
+
+	return 0;
+
+err_nandirq:
+	free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
+	irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
+err_irq:
+	free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
+	irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
+err:
+	return ret;
+}
+
+static const struct of_device_id fsl_ifc_match[] = {
+	{
+		.compatible = "fsl,ifc",
+	},
+	{},
+};
+
+static struct platform_driver fsl_ifc_ctrl_driver = {
+	.driver = {
+		.name	= "fsl-ifc",
+		.of_match_table = fsl_ifc_match,
+	},
+	.probe       = fsl_ifc_ctrl_probe,
+	.remove      = fsl_ifc_ctrl_remove,
+};
+
+module_platform_driver(fsl_ifc_ctrl_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver");
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH v3] gianfar: add support for wake-on-packet
From: Zhao Chenhui @ 2011-12-27 11:30 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: netdev, devicetree-discuss, afleming

On certain chip like MPC8536 and P1022, system can be waked up from
sleep by user-defined packet and Magic Patcket.(The eTSEC cannot
supports both types of wake-up event simultaneously.) This patch
implements wake-up on user-defined patcket including ARP request
packet and unicast patcket to this station.

When entering suspend state, the gianfar driver sets receive queue
filer table to filter all of packets except ARP request packet and
unicast patcket to this station. The driver temporarily uses the last
receive queue to receive the user defined packet.

In suspend state, the receive part of eTSEC keeps working. When
receiving a user defined packet, it generates an interrupt to
wake up the system.

The rule of the filer table is as below.
  if (arp request to local ip address)
      accept it to the last queue
  elif (unicast packet to local mac address)
      accept it to the last queue
  else
      reject it
  endif
Note: The local ip/mac address is the ethernet primary IP/MAC address of
the station. Do not support multiple IP/MAC addresses.

Here is an example of enabling and testing wake up on user defined packet.
  ifconfig eth0 10.193.20.169
  ethtool -s eth0 wol a
  echo standby > /sys/power/state or echo mem > /sys/power/state

Ping from PC host to wake up the station:
  ping 10.193.20.169

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Acked-by: Andy Fleming <afleming@freescale.com>
---
This patch depends on my previous patches related to power management.

Changes for v3:
 - Add "CONFIG_FSL_PMC"

 .../devicetree/bindings/net/fsl-tsec-phy.txt       |    3 +
 drivers/net/ethernet/freescale/gianfar.c           |  363 +++++++++++++++++---
 drivers/net/ethernet/freescale/gianfar.h           |   33 ++-
 drivers/net/ethernet/freescale/gianfar_ethtool.c   |   52 ++-
 4 files changed, 373 insertions(+), 78 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
index 2c6be03..543e36c 100644
--- a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+++ b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
@@ -56,6 +56,9 @@ Properties:
     hardware.
   - fsl,magic-packet : If present, indicates that the hardware supports
     waking up via magic packet.
+  - fsl,wake-on-filer : If present, indicates that the hardware supports
+    waking up via arp request to local ip address or unicast packet to
+    local mac address.
   - bd-stash : If present, indicates that the hardware supports stashing
     buffer descriptors in the L2.
   - rx-stash-len : Denotes the number of bytes of a received buffer to stash
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 83199fd..d0a46d8 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -85,6 +85,8 @@
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/in.h>
+#include <linux/inetdevice.h>
+#include <sysdev/fsl_soc.h>
 #include <linux/net_tstamp.h>
 
 #include <asm/io.h>
@@ -147,6 +149,17 @@ static void gfar_clear_exact_match(struct net_device *dev);
 static void gfar_set_mac_for_addr(struct net_device *dev, int num,
 				  const u8 *addr);
 static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp);
+
+#ifdef CONFIG_PM
+static void gfar_halt_rx(struct net_device *dev);
+static void gfar_rx_start(struct net_device *dev);
+static void gfar_enable_filer(struct net_device *dev);
+static void gfar_disable_filer(struct net_device *dev);
+static void gfar_config_filer_table(struct net_device *dev);
+static void gfar_restore_filer_table(struct net_device *dev);
+static int gfar_get_ip(struct net_device *dev);
+#endif
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
@@ -751,7 +764,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 			FSL_GIANFAR_DEV_HAS_PADDING |
 			FSL_GIANFAR_DEV_HAS_CSUM |
 			FSL_GIANFAR_DEV_HAS_VLAN |
-			FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
 			FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
 			FSL_GIANFAR_DEV_HAS_TIMER;
 
@@ -763,9 +775,21 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 	else
 		priv->interface = PHY_INTERFACE_MODE_MII;
 
-	if (of_get_property(np, "fsl,magic-packet", NULL))
+	/* Init Wake-on-LAN */
+	priv->wol_opts = 0;
+	priv->wol_supported = 0;
+#ifdef CONFIG_FSL_PMC
+	if (of_get_property(np, "fsl,magic-packet", NULL)) {
 		priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
+		priv->wol_supported |= GIANFAR_WOL_MAGIC;
+	}
 
+	if (of_get_property(np, "fsl,wake-on-filer", NULL)) {
+		priv->device_flags |= FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER;
+		priv->wol_supported |= GIANFAR_WOL_ARP;
+		priv->wol_supported |= GIANFAR_WOL_UCAST;
+	}
+#endif
 	priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
 
 	/* Find the TBI PHY.  If it's not there, we don't support SGMII */
@@ -1168,8 +1192,10 @@ static int gfar_probe(struct platform_device *ofdev)
 		goto register_fail;
 	}
 
-	device_init_wakeup(&dev->dev,
-		priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+	if (priv->wol_supported) {
+		device_set_wakeup_capable(&ofdev->dev, true);
+		device_set_wakeup_enable(&ofdev->dev, false);
+	}
 
 	/* fill out IRQ number and name fields */
 	len_devname = strlen(dev->name);
@@ -1260,6 +1286,143 @@ static int gfar_remove(struct platform_device *ofdev)
 }
 
 #ifdef CONFIG_PM
+static void gfar_enable_filer(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
+	u32 temp;
+
+	lock_rx_qs(priv);
+
+	temp = gfar_read(&regs->rctrl);
+	temp &= ~(RCTRL_FSQEN | RCTRL_PRSDEP_MASK);
+	temp |= RCTRL_FILREN | RCTRL_PRSDEP_L2L3;
+	gfar_write(&regs->rctrl, temp);
+
+	unlock_rx_qs(priv);
+}
+
+static void gfar_disable_filer(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
+	u32 temp;
+
+	lock_rx_qs(priv);
+
+	temp = gfar_read(&regs->rctrl);
+	temp &= ~RCTRL_FILREN;
+	gfar_write(&regs->rctrl, temp);
+
+	unlock_rx_qs(priv);
+}
+
+static int gfar_get_ip(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct in_device *in_dev;
+	int ret = -ENOENT;
+
+	in_dev = in_dev_get(dev);
+	if (!in_dev)
+		return ret;
+
+	/* Get the primary IP address */
+	for_primary_ifa(in_dev) {
+		priv->ip_addr = ifa->ifa_address;
+		ret = 0;
+		break;
+	} endfor_ifa(in_dev);
+
+	in_dev_put(in_dev);
+	return ret;
+}
+
+static void gfar_restore_filer_table(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	u32 rqfcr, rqfpr;
+	int i;
+
+	lock_rx_qs(priv);
+
+	for (i = 0; i <= MAX_FILER_IDX; i++) {
+		rqfcr = priv->ftp_rqfcr[i];
+		rqfpr = priv->ftp_rqfpr[i];
+		gfar_write_filer(priv, i, rqfcr, rqfpr);
+	}
+
+	unlock_rx_qs(priv);
+}
+
+static void gfar_config_filer_table(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	u32 dest_mac_addr;
+	u32 rqfcr, rqfpr;
+	u8  rqfcr_queue = priv->num_rx_queues - 1;
+	unsigned int index;
+
+	if (gfar_get_ip(dev)) {
+		netif_err(priv, wol, dev, "WOL: get the ip address error\n");
+		return;
+	}
+
+	lock_rx_qs(priv);
+
+	/* init filer table */
+	rqfcr = RQFCR_RJE | RQFCR_CMP_MATCH;
+	rqfpr = 0x0;
+	for (index = 0; index <= MAX_FILER_IDX; index++)
+		gfar_write_filer(priv, index, rqfcr, rqfpr);
+
+	index = 0;
+	if (priv->wol_opts & GIANFAR_WOL_ARP) {
+		/* ARP request filer, filling the packet to the last queue */
+		rqfcr = (rqfcr_queue << 10) | RQFCR_AND |
+					RQFCR_CMP_EXACT | RQFCR_PID_MASK;
+		rqfpr = RQFPR_ARQ;
+		gfar_write_filer(priv, index++, rqfcr, rqfpr);
+
+		rqfcr = (rqfcr_queue << 10) | RQFCR_AND |
+					RQFCR_CMP_EXACT | RQFCR_PID_PARSE;
+		rqfpr = RQFPR_ARQ;
+		gfar_write_filer(priv, index++, rqfcr, rqfpr);
+
+		/*
+		 * DEST_IP address in ARP packet,
+		 * filling it to the last queue.
+		 */
+		rqfcr = (rqfcr_queue << 10) | RQFCR_AND |
+					RQFCR_CMP_EXACT | RQFCR_PID_MASK;
+		rqfpr = FPR_FILER_MASK;
+		gfar_write_filer(priv, index++, rqfcr, rqfpr);
+
+		rqfcr = (rqfcr_queue << 10) | RQFCR_GPI |
+					RQFCR_CMP_EXACT | RQFCR_PID_DIA;
+		rqfpr = priv->ip_addr;
+		gfar_write_filer(priv, index++, rqfcr, rqfpr);
+	}
+
+	if (priv->wol_opts & GIANFAR_WOL_UCAST) {
+		/* Unicast packet, filling it to the last queue */
+		dest_mac_addr = (dev->dev_addr[0] << 16) |
+				(dev->dev_addr[1] << 8) | dev->dev_addr[2];
+		rqfcr = (rqfcr_queue << 10) | RQFCR_AND |
+					RQFCR_CMP_EXACT | RQFCR_PID_DAH;
+		rqfpr = dest_mac_addr;
+		gfar_write_filer(priv, index++, rqfcr, rqfpr);
+
+		dest_mac_addr = (dev->dev_addr[3] << 16) |
+				(dev->dev_addr[4] << 8) | dev->dev_addr[5];
+		rqfcr = (rqfcr_queue << 10) | RQFCR_GPI |
+					RQFCR_CMP_EXACT | RQFCR_PID_DAL;
+		rqfpr = dest_mac_addr;
+		gfar_write_filer(priv, index++, rqfcr, rqfpr);
+	}
+
+	unlock_rx_qs(priv);
+}
 
 static int gfar_suspend(struct device *dev)
 {
@@ -1269,48 +1432,43 @@ static int gfar_suspend(struct device *dev)
 	unsigned long flags;
 	u32 tempval;
 
-	int magic_packet = priv->wol_en &&
-		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
-
 	netif_device_detach(ndev);
 
-	if (netif_running(ndev)) {
-
-		local_irq_save(flags);
-		lock_tx_qs(priv);
-		lock_rx_qs(priv);
-
-		gfar_halt_nodisable(ndev);
-
-		/* Disable Tx, and Rx if wake-on-LAN is disabled. */
-		tempval = gfar_read(&regs->maccfg1);
-
-		tempval &= ~MACCFG1_TX_EN;
+	if (!netif_running(ndev))
+		return 0;
 
-		if (!magic_packet)
-			tempval &= ~MACCFG1_RX_EN;
+	local_irq_save(flags);
+	lock_tx_qs(priv);
+	lock_rx_qs(priv);
 
-		gfar_write(&regs->maccfg1, tempval);
+	gfar_halt(ndev);
 
-		unlock_rx_qs(priv);
-		unlock_tx_qs(priv);
-		local_irq_restore(flags);
+	unlock_rx_qs(priv);
+	unlock_tx_qs(priv);
+	local_irq_restore(flags);
 
-		disable_napi(priv);
+	disable_napi(priv);
 
-		if (magic_packet) {
-			/* Enable interrupt on Magic Packet */
-			gfar_write(&regs->imask, IMASK_MAG);
+	if (!priv->wol_opts && priv->phydev) {
+		phy_stop(priv->phydev);
+		return 0;
+	}
 
-			/* Enable Magic Packet mode */
-			tempval = gfar_read(&regs->maccfg2);
-			tempval |= MACCFG2_MPEN;
-			gfar_write(&regs->maccfg2, tempval);
-		} else {
-			phy_stop(priv->phydev);
-		}
+	mpc85xx_pmc_set_wake(priv->ofdev, 1);
+	if (priv->wol_opts & GIANFAR_WOL_MAGIC) {
+		/* Enable Magic Packet mode */
+		tempval = gfar_read(&regs->maccfg2);
+		tempval |= MACCFG2_MPEN;
+		gfar_write(&regs->maccfg2, tempval);
 	}
 
+	if (priv->wol_opts & (GIANFAR_WOL_ARP | GIANFAR_WOL_UCAST)) {
+		mpc85xx_pmc_set_lossless_ethernet(1);
+		gfar_disable_filer(ndev);
+		gfar_config_filer_table(ndev);
+		gfar_enable_filer(ndev);
+	}
+	gfar_rx_start(ndev);
 	return 0;
 }
 
@@ -1320,39 +1478,49 @@ static int gfar_resume(struct device *dev)
 	struct net_device *ndev = priv->ndev;
 	struct gfar __iomem *regs = priv->gfargrp[0].regs;
 	unsigned long flags;
-	u32 tempval;
-	int magic_packet = priv->wol_en &&
-		(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+	u32 tempval, i;
 
 	if (!netif_running(ndev)) {
 		netif_device_attach(ndev);
 		return 0;
 	}
 
-	if (!magic_packet && priv->phydev)
+	if (!priv->wol_opts && priv->phydev) {
 		phy_start(priv->phydev);
+		goto out;
+	}
+
+	mpc85xx_pmc_set_wake(priv->ofdev, 0);
 
-	/* Disable Magic Packet mode, in case something
-	 * else woke us up.
-	 */
 	local_irq_save(flags);
-	lock_tx_qs(priv);
 	lock_rx_qs(priv);
-
-	tempval = gfar_read(&regs->maccfg2);
-	tempval &= ~MACCFG2_MPEN;
-	gfar_write(&regs->maccfg2, tempval);
-
-	gfar_start(ndev);
-
+	gfar_halt_rx(ndev);
 	unlock_rx_qs(priv);
-	unlock_tx_qs(priv);
 	local_irq_restore(flags);
 
-	netif_device_attach(ndev);
+	if (priv->wol_opts & (GIANFAR_WOL_ARP | GIANFAR_WOL_UCAST)) {
+		mpc85xx_pmc_set_lossless_ethernet(0);
+		gfar_disable_filer(ndev);
+		gfar_restore_filer_table(ndev);
+	}
+
+	if (priv->wol_opts & GIANFAR_WOL_MAGIC) {
+		/* Disable Magic Packet mode */
+		tempval = gfar_read(&regs->maccfg2);
+		tempval &= ~MACCFG2_MPEN;
+		gfar_write(&regs->maccfg2, tempval);
+	}
 
+out:
+	gfar_start(ndev);
+	netif_device_attach(ndev);
 	enable_napi(priv);
 
+	if (priv->wol_opts & (GIANFAR_WOL_ARP | GIANFAR_WOL_UCAST)) {
+		/* send requests to process the received packets */
+		for (i = 0; i < priv->num_grps; i++)
+			gfar_schedule_cleanup(&priv->gfargrp[i]);
+	}
 	return 0;
 }
 
@@ -1602,6 +1770,48 @@ static int __gfar_is_rx_idle(struct gfar_private *priv)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+/* Halt the receive queues */
+static void gfar_halt_rx(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
+	u32 tempval;
+	int i = 0;
+
+	for (i = 0; i < priv->num_grps; i++) {
+		regs = priv->gfargrp[i].regs;
+		/* Mask all interrupts */
+		gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+
+		/* Clear all interrupts */
+		gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
+	}
+
+	regs = priv->gfargrp[0].regs;
+	/* Stop the DMA, and wait for it to stop */
+	tempval = gfar_read(&regs->dmactrl);
+	if ((tempval & DMACTRL_GRS) != DMACTRL_GRS) {
+		int ret;
+
+		tempval |= DMACTRL_GRS;
+		gfar_write(&regs->dmactrl, tempval);
+
+		do {
+			ret = spin_event_timeout(((gfar_read(&regs->ievent) &
+				IEVENT_GRSC) == IEVENT_GRSC), 1000000, 0);
+			if (!ret && !(gfar_read(&regs->ievent) & IEVENT_GRSC))
+				ret = __gfar_is_rx_idle(priv);
+		} while (!ret);
+	}
+
+	/* Disable Rx in MACCFG1  */
+	tempval = gfar_read(&regs->maccfg1);
+	tempval &= ~MACCFG1_RX_EN;
+	gfar_write(&regs->maccfg1, tempval);
+}
+#endif
+
 /* Halt the receive and transmit queues */
 static void gfar_halt_nodisable(struct net_device *dev)
 {
@@ -1808,6 +2018,40 @@ void gfar_start(struct net_device *dev)
 	dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
+#ifdef CONFIG_PM
+void gfar_rx_start(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->gfargrp[0].regs;
+	u32 tempval;
+	int i = 0;
+
+	/* Enable Rx in MACCFG1 */
+	tempval = gfar_read(&regs->maccfg1);
+	tempval |= MACCFG1_RX_EN;
+	gfar_write(&regs->maccfg1, tempval);
+
+	/* Initialize DMACTRL to have WWR and WOP */
+	tempval = gfar_read(&regs->dmactrl);
+	tempval |= DMACTRL_INIT_SETTINGS;
+	gfar_write(&regs->dmactrl, tempval);
+
+	/* Make sure we aren't stopped */
+	tempval = gfar_read(&regs->dmactrl);
+	tempval &= ~DMACTRL_GRS;
+	gfar_write(&regs->dmactrl, tempval);
+
+	for (i = 0; i < priv->num_grps; i++) {
+		regs = priv->gfargrp[i].regs;
+		/* Clear RHLT, so that the DMA starts polling now */
+		gfar_write(&regs->rstat, priv->gfargrp[i].rstat);
+
+		/* Unmask the interrupts we look for */
+		gfar_write(&regs->imask, IMASK_DEFAULT);
+	}
+}
+#endif
+
 void gfar_configure_coalescing(struct gfar_private *priv,
 	unsigned long tx_mask, unsigned long rx_mask)
 {
@@ -1970,7 +2214,7 @@ static int gfar_enet_open(struct net_device *dev)
 
 	netif_tx_start_all_queues(dev);
 
-	device_set_wakeup_enable(&dev->dev, priv->wol_en);
+	device_set_wakeup_enable(&priv->ofdev->dev, priv->wol_opts);
 
 	return err;
 }
@@ -2657,6 +2901,17 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
 
 irqreturn_t gfar_receive(int irq, void *grp_id)
 {
+	struct gfar_priv_grp *gfargrp = grp_id;
+	struct gfar __iomem *regs = gfargrp->regs;
+	u32 ievent;
+
+	ievent = gfar_read(&regs->ievent);
+
+	if ((ievent & IEVENT_FGPI) == IEVENT_FGPI) {
+		gfar_write(&regs->ievent, ievent & IEVENT_RX_MASK);
+		return IRQ_HANDLED;
+	}
+
 	gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
 	return IRQ_HANDLED;
 }
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 9aa4377..1abebc4 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -232,6 +232,13 @@ extern const char gfar_driver_version[];
 #define RQUEUE_EN7		0x00000001
 #define RQUEUE_EN_ALL		0x000000FF
 
+/* Wake-On-Lan options */
+#define GIANFAR_WOL_UCAST	0x00000001	/* Unicast wakeup */
+#define GIANFAR_WOL_MCAST	0x00000002	/* Multicast wakeup */
+#define GIANFAR_WOL_BCAST	0x00000004	/* Broadcase wakeup */
+#define GIANFAR_WOL_ARP		0x00000008	/* ARP request wakeup */
+#define GIANFAR_WOL_MAGIC	0x00000010	/* Magic packet wakeup */
+
 /* Init to do tx snooping for buffers and descriptors */
 #define DMACTRL_INIT_SETTINGS   0x000000c3
 #define DMACTRL_GRS             0x00000010
@@ -277,11 +284,15 @@ extern const char gfar_driver_version[];
 #define RCTRL_PAL_MASK		0x001f0000
 #define RCTRL_VLEX		0x00002000
 #define RCTRL_FILREN		0x00001000
+#define RCTRL_FSQEN		0x00000800
 #define RCTRL_GHTX		0x00000400
 #define RCTRL_IPCSEN		0x00000200
 #define RCTRL_TUCSEN		0x00000100
 #define RCTRL_PRSDEP_MASK	0x000000c0
 #define RCTRL_PRSDEP_INIT	0x000000c0
+#define RCTRL_PRSDEP_L2		0x00000040
+#define RCTRL_PRSDEP_L2L3	0x00000080
+#define RCTRL_PRSDEP_L2L3L4	0x000000c0
 #define RCTRL_PRSFM		0x00000020
 #define RCTRL_PROM		0x00000008
 #define RCTRL_EMEN		0x00000002
@@ -327,18 +338,20 @@ extern const char gfar_driver_version[];
 #define IEVENT_MAG		0x00000800
 #define IEVENT_GRSC		0x00000100
 #define IEVENT_RXF0		0x00000080
+#define IEVENT_FGPI		0x00000010
 #define IEVENT_FIR		0x00000008
 #define IEVENT_FIQ		0x00000004
 #define IEVENT_DPE		0x00000002
 #define IEVENT_PERR		0x00000001
-#define IEVENT_RX_MASK          (IEVENT_RXB0 | IEVENT_RXF0 | IEVENT_BSY)
+#define IEVENT_RX_MASK          (IEVENT_RXB0 | IEVENT_RXF0 | \
+					IEVENT_FGPI | IEVENT_BSY)
 #define IEVENT_TX_MASK          (IEVENT_TXB | IEVENT_TXF)
 #define IEVENT_RTX_MASK         (IEVENT_RX_MASK | IEVENT_TX_MASK)
 #define IEVENT_ERR_MASK         \
-(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
- IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR \
- | IEVENT_MAG | IEVENT_BABR)
+	(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
+	 IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC | \
+	 IEVENT_CRL | IEVENT_XFUN | IEVENT_FIR | IEVENT_FIQ | \
+	 IEVENT_DPE | IEVENT_PERR | IEVENT_MAG | IEVENT_BABR)
 
 #define IMASK_INIT_CLEAR	0x00000000
 #define IMASK_BABR              0x80000000
@@ -359,14 +372,15 @@ extern const char gfar_driver_version[];
 #define IMASK_MAG		0x00000800
 #define IMASK_GRSC              0x00000100
 #define IMASK_RXFEN0		0x00000080
+#define IMASK_FGPI		0x00000010
 #define IMASK_FIR		0x00000008
 #define IMASK_FIQ		0x00000004
 #define IMASK_DPE		0x00000002
 #define IMASK_PERR		0x00000001
 #define IMASK_DEFAULT  (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
 		IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
-		IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
-		| IMASK_PERR)
+		IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_FGPI | \
+		IMASK_FIR | IMASK_FIQ | IMASK_DPE | IMASK_PERR | IMASK_MAG)
 #define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \
 			   & IMASK_DEFAULT)
 
@@ -883,6 +897,7 @@ struct gfar {
 #define FSL_GIANFAR_DEV_HAS_BD_STASHING		0x00000200
 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING	0x00000400
 #define FSL_GIANFAR_DEV_HAS_TIMER		0x00000800
+#define FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER	0x00001000
 
 #if (MAXGROUPS == 2)
 #define DEFAULT_MAPPING 	0xAA
@@ -1115,6 +1130,10 @@ struct gfar_private {
 
 	struct work_struct reset_task;
 
+	u32 ip_addr;
+	u32 wol_opts;
+	u32 wol_supported;
+
 	/* Network Statistics */
 	struct gfar_extra_stats extra_stats;
 
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 212736b..296e762 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -29,6 +29,7 @@
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -577,32 +578,49 @@ static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) {
-		wol->supported = WAKE_MAGIC;
-		wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0;
-	} else {
-		wol->supported = wol->wolopts = 0;
-	}
+	wol->supported = 0;
+	wol->wolopts = 0;
+
+	if (!priv->wol_supported || !device_can_wakeup(&priv->ofdev->dev))
+		return;
+
+	if (priv->wol_supported & GIANFAR_WOL_MAGIC)
+		wol->supported |= WAKE_MAGIC;
+
+	if (priv->wol_supported & GIANFAR_WOL_ARP)
+		wol->supported |= WAKE_ARP;
+
+	if (priv->wol_supported & GIANFAR_WOL_UCAST)
+		wol->supported |= WAKE_UCAST;
+
+	if (priv->wol_opts & GIANFAR_WOL_MAGIC)
+		wol->wolopts |= WAKE_MAGIC;
+
+	if (priv->wol_opts & GIANFAR_WOL_ARP)
+		wol->wolopts |= WAKE_ARP;
+
+	if (priv->wol_opts & GIANFAR_WOL_UCAST)
+		wol->wolopts |= WAKE_UCAST;
 }
 
 static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct gfar_private *priv = netdev_priv(dev);
-	unsigned long flags;
 
-	if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
-	    wol->wolopts != 0)
-		return -EINVAL;
-
-	if (wol->wolopts & ~WAKE_MAGIC)
-		return -EINVAL;
+	if (!priv->wol_supported || !device_can_wakeup(&priv->ofdev->dev) ||
+		(wol->wolopts & ~(WAKE_MAGIC | WAKE_ARP | WAKE_UCAST)))
+		return -EOPNOTSUPP;
 
-	device_set_wakeup_enable(&dev->dev, wol->wolopts & WAKE_MAGIC);
+	priv->wol_opts = 0;
 
-	spin_lock_irqsave(&priv->bflock, flags);
-	priv->wol_en =  !!device_may_wakeup(&dev->dev);
-	spin_unlock_irqrestore(&priv->bflock, flags);
+	if (wol->wolopts & WAKE_MAGIC)
+		priv->wol_opts |= GIANFAR_WOL_MAGIC;
+	if (wol->wolopts & WAKE_ARP)
+		priv->wol_opts |= GIANFAR_WOL_ARP;
+	if (wol->wolopts & WAKE_UCAST)
+		priv->wol_opts |= GIANFAR_WOL_UCAST;
 
+	device_set_wakeup_enable(&priv->ofdev->dev, (u32)priv->wol_opts);
 	return 0;
 }
 #endif
-- 
1.6.4.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox