LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: visible memory seems wrong in kexec crash dump kernel
From: Scott Wood @ 2013-07-31 16:50 UTC (permalink / raw)
  To: Friesen, Christopher
  Cc: Paul Mackerras, kexec@lists.infradead.org,
	linuxppc-dev@lists.ozlabs.org, Vivek Goyal
In-Reply-To: <CFBB0F4944BCD94BAC0398D7DB81D705EAF91D@CAMPUSMB5.usask.ca>

On 07/31/2013 11:40:05 AM, Friesen, Christopher wrote:
>=20
> From: Scott Wood [scottwood@freescale.com]
> Sent: Monday, July 29, 2013 5:10 PM
> To: Friesen, Christopher
> Cc: Michael Ellerman; kexec@lists.infradead.org; Paul Mackerras; =20
> linuxppc-dev@lists.ozlabs.org; Vivek Goyal
> Subject: Re: visible memory seems wrong in kexec crash dump kernel
>=20
> On 07/13/2013 01:30:50 AM, Chris Friesen wrote:
> > The upshot is that there seems to be a number of things that could =20
> be
> > improved:
> >
> > 1) kexec should accept "/memory" and not just "/memory@"
> > 2) lmb_reserve() should really respect the crashkernel memory limit
> > 3) the freescale stuff really shouldn't assume it can map things
> > wherever it feels like
>=20
> What "board-specific freescale code" are you referring to?
>=20
> -Scott
>=20
>=20
> Sorry for the crappy quoting, I'm using a web outlook portal.
>=20
> I've switched employers so I don't have access to the exact details =20
> any more.  The system in question was a Kontron AM4150 which uses the =20
> P5020.  As I recall, one of the Freescale drivers (I think it was the =20
> buffer or queue manager that the network driver makes use of) was =20
> attempting to call lmb_reserve() with a base address in the 4GB range =20
> even though the recovery kernel was limited to 224MB of memory.

That's not "board specific" code, and it's not even mainline Linux =20
code.  Unfortunately none of the datapath stuff is upstream, still.

> While I've got your attention, the other thing that I found was that =20
> the "dpa" network driver didn't properly work in a kexec'd kernel =20
> even when given lots of memory.  It would work for a little bit and =20
> then hang.

I'm not particularly surprised by this.  It doesn't help that there's =20
no way to do a device reset. :-(

Issues with Freescale SDK code should be reported on =20
https://community.freescale.com/, to support@freescale.com, or to your =20
FAE.

-Scott=

^ permalink raw reply

* Re: mm/slab: ppc: ubi: kmalloc_slab WARNING / PPC + UBI driver
From: Wladislav Wiebe @ 2013-07-31 16:33 UTC (permalink / raw)
  To: Christoph Lameter
  Cc: dedekind1, Mel Gorman, dwmw2, Pekka Enberg, linux-mm, linux-mtd,
	linuxppc-dev
In-Reply-To: <000001403567762a-60a27288-f0b2-4855-b88c-6a6f21ec537c-000000@email.amazonses.com>

Hi Christoph,

On 31/07/13 17:45, Christoph Lameter wrote:
> Crap you cannot do PAGE_SIZE allocations with kmalloc_large. Fails when
> freeing pages. Need to only do the multiple page allocs with
> kmalloc_large.
> 
> Subject: seq_file: Use kmalloc_large for page sized allocation
> 
> There is no point in using the slab allocation functions for
> large page order allocation. Use kmalloc_large().
> 
> This fixes the warning about large allocs but it will still cause
> large contiguous allocs that could fail because of memory fragmentation.

Thanks for the point, do you plan to make kmalloc_large available for extern access in a separate mainline patch?
Since kmalloc_large is statically defined in slub_def.h and when including it to seq_file.c
we have a lot of conflicting types:
..
In file included from ../linux/fs/seq_file.c:8:0:
../linux/include/linux/slub_def.h: In function 'kmalloc':
../linux/include/linux/slub_def.h:161:14: error: 'KMALLOC_MAX_CACHE_SIZE' undeclared (first use in this function)
../results/linux/include/linux/slub_def.h:161:14: note: each undeclared identifier is reported only once for each function it appears in
../linux/include/linux/slub_def.h:165:4: error: implicit declaration of function 'kmalloc_index' [-Werror=implicit-function-declaration]
../linux/include/linux/slub_def.h:168:12: error: 'ZERO_SIZE_PTR' undeclared (first use in this function)
../linux/include/linux/slub_def.h:170:34: error: 'kmalloc_caches' undeclared (first use in this function)
..


Thanks & BR
Wladislav Wiebe

> 
> Signed-off-by: Christoph Lameter <cl@linux.com>
> 
> Index: linux/fs/seq_file.c
> ===================================================================
> --- linux.orig/fs/seq_file.c	2013-07-31 10:39:03.050472030 -0500
> +++ linux/fs/seq_file.c	2013-07-31 10:39:03.050472030 -0500
> @@ -136,7 +136,7 @@ static int traverse(struct seq_file *m,
>  Eoverflow:
>  	m->op->stop(m, p);
>  	kfree(m->buf);
> -	m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
> +	m->buf = kmalloc_large(m->size <<= 1, GFP_KERNEL);
>  	return !m->buf ? -ENOMEM : -EAGAIN;
>  }
> 
> @@ -232,7 +232,7 @@ ssize_t seq_read(struct file *file, char
>  			goto Fill;
>  		m->op->stop(m, p);
>  		kfree(m->buf);
> -		m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
> +		m->buf = kmalloc_large(m->size <<= 1, GFP_KERNEL);
>  		if (!m->buf)
>  			goto Enomem;
>  		m->count = 0;
> 

^ permalink raw reply

* Re: mm/slab: ppc: ubi: kmalloc_slab WARNING / PPC + UBI driver
From: Christoph Lameter @ 2013-07-31 15:45 UTC (permalink / raw)
  To: Wladislav Wiebe
  Cc: dedekind1, Mel Gorman, dwmw2, Pekka Enberg, linux-mm, linux-mtd,
	linuxppc-dev
In-Reply-To: <alpine.DEB.2.02.1307311015320.30997@gentwo.org>

Crap you cannot do PAGE_SIZE allocations with kmalloc_large. Fails when
freeing pages. Need to only do the multiple page allocs with
kmalloc_large.

Subject: seq_file: Use kmalloc_large for page sized allocation

There is no point in using the slab allocation functions for
large page order allocation. Use kmalloc_large().

This fixes the warning about large allocs but it will still cause
large contiguous allocs that could fail because of memory fragmentation.

Signed-off-by: Christoph Lameter <cl@linux.com>

Index: linux/fs/seq_file.c
===================================================================
--- linux.orig/fs/seq_file.c	2013-07-31 10:39:03.050472030 -0500
+++ linux/fs/seq_file.c	2013-07-31 10:39:03.050472030 -0500
@@ -136,7 +136,7 @@ static int traverse(struct seq_file *m,
 Eoverflow:
 	m->op->stop(m, p);
 	kfree(m->buf);
-	m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
+	m->buf = kmalloc_large(m->size <<= 1, GFP_KERNEL);
 	return !m->buf ? -ENOMEM : -EAGAIN;
 }

@@ -232,7 +232,7 @@ ssize_t seq_read(struct file *file, char
 			goto Fill;
 		m->op->stop(m, p);
 		kfree(m->buf);
-		m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
+		m->buf = kmalloc_large(m->size <<= 1, GFP_KERNEL);
 		if (!m->buf)
 			goto Enomem;
 		m->count = 0;

^ permalink raw reply

* Re: [PATCH v3 2/3] powerpc/85xx: Add silicon device tree for C293
From: Scott Wood @ 2013-07-31 15:46 UTC (permalink / raw)
  To: Liu Po-B43644
  Cc: Wood Scott-B07421, Hu Mingkai-B21284, Fleming Andy-AFLEMING,
	linuxppc-dev@ozlabs.org
In-Reply-To: <D473A0D087F4EA47A30C37E4637E25E609DB5966@039-SN2MPN1-023.039d.mgd.msft.net>

On 07/30/2013 09:13:28 PM, Liu Po-B43644 wrote:
>=20
> >  -----Original Message-----
> >  From: Wood Scott-B07421
> >  Sent: Wednesday, July 31, 2013 2:28 AM
> >  To: Liu Po-B43644
> >  Cc: linuxppc-dev@ozlabs.org; galak@kernel.crashing.org; Fleming =20
> Andy-
> >  AFLEMING; Hu Mingkai-B21284; Liu Po-B43644
> >  Subject: Re: [PATCH v3 2/3] powerpc/85xx: Add silicon device tree =20
> for
> >  C293
> >
> >  On 07/30/2013 03:49:22 AM, Po Liu wrote:
> >  > +	crypto@80000 {
> >  > +/include/ "qoriq-sec6.0-0.dtsi"
> >  > +	};
> >  > +
> >  > +	crypto@80000 {
> >  > +		reg =3D <0x80000 0x20000>;
> >  > +		ranges =3D <0x0 0x80000 0x20000>;
> >  > +
> >  > +		jr@1000{
> >  > +			interrupts =3D <45 2 0 0>;
> >  > +		};
> >  > +		jr@2000{
> >  > +			interrupts =3D <57 2 0 0>;
> >  > +		};
> >  > +	};
> >
> >  Do these inline the way the example shows.
> Sorry, Scott, I just remember in this way, the node can't be =20
> recognized by system when run Uboot. The include can't be in the =20
> crypto@80000. See the discussion in =20
> http://git.am.freescale.net:8181/#/c/736/  .
> Maybe I should re-modify the example file.

git.am.freescale.net is not accessible outside of Freescale; don't =20
reference it on external lists.  In any case, I don't know what =20
specifically you want me to look at there.  Just put the explanation =20
here.

I do not expect the dtc output to be any different between the two =20
methods.  Could you check this (by using dtc to decompile the dtb =20
afterward) and point out exactly how the output differs between the two =20
approaches?

-Scott=

^ permalink raw reply

* Re: mm/slab: ppc: ubi: kmalloc_slab WARNING / PPC + UBI driver
From: Christoph Lameter @ 2013-07-31 15:17 UTC (permalink / raw)
  To: Wladislav Wiebe
  Cc: dedekind1, Mel Gorman, dwmw2, Pekka Enberg, linux-mm, linux-mtd,
	linuxppc-dev
In-Reply-To: <alpine.DEB.2.02.1307310858150.30572@gentwo.org>

This patch will suppress the warnings by using the page allocator wrappers
of the slab allocators. These are page sized allocs after all.


Subject: seq_file: Use kmalloc_large for page sized allocation

There is no point in using the slab allocation functions for large page
order allocation. Use the kmalloc_large() wrappers which will cause calls
to the page alocator instead.

This fixes the warning about large allocs but it will still cause
high order allocs to occur that could fail because of memory
fragmentation. Maybe switch to vmalloc if we really want to allocate multi
megabyte buffers for proc fs?

Signed-off-by: Christoph Lameter <cl@linux.com>

Index: linux/fs/seq_file.c
===================================================================
--- linux.orig/fs/seq_file.c	2013-07-10 14:03:15.367134544 -0500
+++ linux/fs/seq_file.c	2013-07-31 10:11:42.671736131 -0500
@@ -96,7 +96,7 @@ static int traverse(struct seq_file *m,
 		return 0;
 	}
 	if (!m->buf) {
-		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
+		m->buf = kmalloc_large(m->size = PAGE_SIZE, GFP_KERNEL);
 		if (!m->buf)
 			return -ENOMEM;
 	}
@@ -136,7 +136,7 @@ static int traverse(struct seq_file *m,
 Eoverflow:
 	m->op->stop(m, p);
 	kfree(m->buf);
-	m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
+	m->buf = kmalloc_large(m->size <<= 1, GFP_KERNEL);
 	return !m->buf ? -ENOMEM : -EAGAIN;
 }

@@ -191,7 +191,7 @@ ssize_t seq_read(struct file *file, char

 	/* grab buffer if we didn't have one */
 	if (!m->buf) {
-		m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
+		m->buf = kmalloc_large(m->size = PAGE_SIZE, GFP_KERNEL);
 		if (!m->buf)
 			goto Enomem;
 	}
@@ -232,7 +232,7 @@ ssize_t seq_read(struct file *file, char
 			goto Fill;
 		m->op->stop(m, p);
 		kfree(m->buf);
-		m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
+		m->buf = kmalloc_large(m->size <<= 1, GFP_KERNEL);
 		if (!m->buf)
 			goto Enomem;
 		m->count = 0;

^ permalink raw reply

* Re: [PATCH] powerpc/fsl-booke: Rename b4qds.dts -> b4qds.dtsi.
From: Ian Campbell @ 2013-07-31 14:45 UTC (permalink / raw)
  To: linux-kernel
  Cc: Poonam Aggrwal, Shaveta Leekha, Minghuan Lian, Andy Fleming,
	Ramneek Mehresh, Paul Mackerras, linuxppc-dev
In-Reply-To: <1369995280-20863-1-git-send-email-ian.campbell@citrix.com>

ping?

On Fri, 2013-05-31 at 11:14 +0100, Ian Campbell wrote:
> This file is a common include for B4860 and B4420 but is not a valid DTS itself:
> 	  DTC     arch/powerpc/boot/b4qds.dtb
> 	Error: arch/powerpc/boot/dts/b4qds.dts:35.1-2 syntax error
> 	FATAL ERROR: Unable to parse input tree
> 	make[1]: *** [arch/powerpc/boot/b4qds.dtb] Error 1
> 	make: *** [b4qds.dtb] Error 2
> 
> I spotted in build tests of device-tree.git, announcement
> https://lkml.org/lkml/2013/4/24/209, which builds *.dts. Probably no one would
> do this this in real life on linux.git but it still seems worth fixing.
> 
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> Cc: Shaveta Leekha <shaveta@freescale.com>
> Cc: Minghuan Lian <Minghuan.Lian@freescale.com>
> Cc: Andy Fleming <afleming@freescale.com>
> Cc: Poonam Aggrwal <poonam.aggrwal@freescale.com>
> Cc: Ramneek Mehresh <ramneek.mehresh@freescale.com>
> Cc: Kumar Gala <galak@kernel.crashing.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: linuxppc-dev@lists.ozlabs.org
> Cc: linux-kernel@vger.kernel.org
> ---
>  arch/powerpc/boot/dts/b4420qds.dts |    2 +-
>  arch/powerpc/boot/dts/b4860qds.dts |    2 +-
>  arch/powerpc/boot/dts/b4qds.dts    |  169 ------------------------------------
>  arch/powerpc/boot/dts/b4qds.dtsi   |  169 ++++++++++++++++++++++++++++++++++++
>  4 files changed, 171 insertions(+), 171 deletions(-)
>  delete mode 100644 arch/powerpc/boot/dts/b4qds.dts
>  create mode 100644 arch/powerpc/boot/dts/b4qds.dtsi
> 
> diff --git a/arch/powerpc/boot/dts/b4420qds.dts b/arch/powerpc/boot/dts/b4420qds.dts
> index 923156d..508dbdf 100644
> --- a/arch/powerpc/boot/dts/b4420qds.dts
> +++ b/arch/powerpc/boot/dts/b4420qds.dts
> @@ -33,7 +33,7 @@
>   */
>  
>  /include/ "fsl/b4420si-pre.dtsi"
> -/include/ "b4qds.dts"
> +/include/ "b4qds.dtsi"
>  
>  / {
>  	model = "fsl,B4420QDS";
> diff --git a/arch/powerpc/boot/dts/b4860qds.dts b/arch/powerpc/boot/dts/b4860qds.dts
> index 78907f3..6bb3707 100644
> --- a/arch/powerpc/boot/dts/b4860qds.dts
> +++ b/arch/powerpc/boot/dts/b4860qds.dts
> @@ -33,7 +33,7 @@
>   */
>  
>  /include/ "fsl/b4860si-pre.dtsi"
> -/include/ "b4qds.dts"
> +/include/ "b4qds.dtsi"
>  
>  / {
>  	model = "fsl,B4860QDS";
> diff --git a/arch/powerpc/boot/dts/b4qds.dts b/arch/powerpc/boot/dts/b4qds.dts
> deleted file mode 100644
> index e6d2f8f..0000000
> --- a/arch/powerpc/boot/dts/b4qds.dts
> +++ /dev/null
> @@ -1,169 +0,0 @@
> -/*
> - * B4420DS Device Tree Source
> - *
> - * Copyright 2012 Freescale Semiconductor, Inc.
> - *
> - * Redistribution and use in source and binary forms, with or without
> - * modification, are permitted provided that the following conditions are met:
> - *     * Redistributions of source code must retain the above copyright
> - *       notice, this list of conditions and the following disclaimer.
> - *     * Redistributions in binary form must reproduce the above copyright
> - *       notice, this list of conditions and the following disclaimer in the
> - *       documentation and/or other materials provided with the distribution.
> - *     * Neither the name of Freescale Semiconductor nor the
> - *       names of its contributors may be used to endorse or promote products
> - *       derived from this software without specific prior written permission.
> - *
> - *
> - * ALTERNATIVELY, this software may be distributed under the terms of the
> - * GNU General Public License ("GPL") as published by the Free Software
> - * Foundation, either version 2 of that License or (at your option) any
> - * later version.
> - *
> - * This software is provided by Freescale Semiconductor "as is" and any
> - * express or implied warranties, including, but not limited to, the implied
> - * warranties of merchantability and fitness for a particular purpose are
> - * disclaimed. In no event shall Freescale Semiconductor be liable for any
> - * direct, indirect, incidental, special, exemplary, or consequential damages
> - * (including, but not limited to, procurement of substitute goods or services;
> - * loss of use, data, or profits; or business interruption) however caused and
> - * on any theory of liability, whether in contract, strict liability, or tort
> - * (including negligence or otherwise) arising in any way out of the use of
> - * this software, even if advised of the possibility of such damage.
> - */
> -
> -/ {
> -	model = "fsl,B4QDS";
> -	compatible = "fsl,B4QDS";
> -	#address-cells = <2>;
> -	#size-cells = <2>;
> -	interrupt-parent = <&mpic>;
> -
> -	ifc: localbus@ffe124000 {
> -		reg = <0xf 0xfe124000 0 0x2000>;
> -		ranges = <0 0 0xf 0xe8000000 0x08000000
> -			  2 0 0xf 0xff800000 0x00010000
> -			  3 0 0xf 0xffdf0000 0x00008000>;
> -
> -		nor@0,0 {
> -			#address-cells = <1>;
> -			#size-cells = <1>;
> -			compatible = "cfi-flash";
> -			reg = <0x0 0x0 0x8000000>;
> -			bank-width = <2>;
> -			device-width = <1>;
> -		};
> -
> -		nand@2,0 {
> -			#address-cells = <1>;
> -			#size-cells = <1>;
> -			compatible = "fsl,ifc-nand";
> -			reg = <0x2 0x0 0x10000>;
> -
> -			partition@0 {
> -				/* This location must not be altered  */
> -				/* 1MB for u-boot Bootloader Image */
> -				reg = <0x0 0x00100000>;
> -				label = "NAND U-Boot Image";
> -				read-only;
> -			};
> -
> -			partition@100000 {
> -				/* 1MB for DTB Image */
> -				reg = <0x00100000 0x00100000>;
> -				label = "NAND DTB Image";
> -			};
> -
> -			partition@200000 {
> -				/* 10MB for Linux Kernel Image */
> -				reg = <0x00200000 0x00A00000>;
> -				label = "NAND Linux Kernel Image";
> -			};
> -
> -			partition@c00000 {
> -				/* 500MB for Root file System Image */
> -				reg = <0x00c00000 0x1F400000>;
> -				label = "NAND RFS Image";
> -			};
> -		};
> -
> -		board-control@3,0 {
> -			compatible = "fsl,b4qds-fpga", "fsl,fpga-qixis";
> -			reg = <3 0 0x300>;
> -		};
> -	};
> -
> -	memory {
> -		device_type = "memory";
> -	};
> -
> -	dcsr: dcsr@f00000000 {
> -		ranges = <0x00000000 0xf 0x00000000 0x01052000>;
> -	};
> -
> -	soc: soc@ffe000000 {
> -		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
> -		reg = <0xf 0xfe000000 0 0x00001000>;
> -		spi@110000 {
> -			flash@0 {
> -				#address-cells = <1>;
> -				#size-cells = <1>;
> -				compatible = "sst,sst25wf040";
> -				reg = <0>;
> -				spi-max-frequency = <40000000>; /* input clock */
> -			};
> -		};
> -
> -		sdhc@114000 {
> -			/*Disabled as there is no sdhc connector on B4420QDS board*/
> -			status = "disabled";
> -		};
> -
> -		i2c@118000 {
> -			eeprom@50 {
> -				compatible = "at24,24c64";
> -				reg = <0x50>;
> -			};
> -			eeprom@51 {
> -				compatible = "at24,24c256";
> -				reg = <0x51>;
> -			};
> -			eeprom@53 {
> -				compatible = "at24,24c256";
> -				reg = <0x53>;
> -			};
> -			eeprom@57 {
> -				compatible = "at24,24c256";
> -				reg = <0x57>;
> -			};
> -			rtc@68 {
> -				compatible = "dallas,ds3232";
> -				reg = <0x68>;
> -			};
> -		};
> -
> -		usb@210000 {
> -			dr_mode = "host";
> -			phy_type = "ulpi";
> -		};
> -
> -	};
> -
> -	pci0: pcie@ffe200000 {
> -		reg = <0xf 0xfe200000 0 0x10000>;
> -		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
> -			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
> -		pcie@0 {
> -			ranges = <0x02000000 0 0xe0000000
> -				  0x02000000 0 0xe0000000
> -				  0 0x20000000
> -
> -				  0x01000000 0 0x00000000
> -				  0x01000000 0 0x00000000
> -				  0 0x00010000>;
> -		};
> -	};
> -
> -};
> -
> -/include/ "fsl/b4si-post.dtsi"
> diff --git a/arch/powerpc/boot/dts/b4qds.dtsi b/arch/powerpc/boot/dts/b4qds.dtsi
> new file mode 100644
> index 0000000..e6d2f8f
> --- /dev/null
> +++ b/arch/powerpc/boot/dts/b4qds.dtsi
> @@ -0,0 +1,169 @@
> +/*
> + * B4420DS Device Tree Source
> + *
> + * Copyright 2012 Freescale Semiconductor, Inc.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are met:
> + *     * Redistributions of source code must retain the above copyright
> + *       notice, this list of conditions and the following disclaimer.
> + *     * Redistributions in binary form must reproduce the above copyright
> + *       notice, this list of conditions and the following disclaimer in the
> + *       documentation and/or other materials provided with the distribution.
> + *     * Neither the name of Freescale Semiconductor nor the
> + *       names of its contributors may be used to endorse or promote products
> + *       derived from this software without specific prior written permission.
> + *
> + *
> + * ALTERNATIVELY, this software may be distributed under the terms of the
> + * GNU General Public License ("GPL") as published by the Free Software
> + * Foundation, either version 2 of that License or (at your option) any
> + * later version.
> + *
> + * This software is provided by Freescale Semiconductor "as is" and any
> + * express or implied warranties, including, but not limited to, the implied
> + * warranties of merchantability and fitness for a particular purpose are
> + * disclaimed. In no event shall Freescale Semiconductor be liable for any
> + * direct, indirect, incidental, special, exemplary, or consequential damages
> + * (including, but not limited to, procurement of substitute goods or services;
> + * loss of use, data, or profits; or business interruption) however caused and
> + * on any theory of liability, whether in contract, strict liability, or tort
> + * (including negligence or otherwise) arising in any way out of the use of
> + * this software, even if advised of the possibility of such damage.
> + */
> +
> +/ {
> +	model = "fsl,B4QDS";
> +	compatible = "fsl,B4QDS";
> +	#address-cells = <2>;
> +	#size-cells = <2>;
> +	interrupt-parent = <&mpic>;
> +
> +	ifc: localbus@ffe124000 {
> +		reg = <0xf 0xfe124000 0 0x2000>;
> +		ranges = <0 0 0xf 0xe8000000 0x08000000
> +			  2 0 0xf 0xff800000 0x00010000
> +			  3 0 0xf 0xffdf0000 0x00008000>;
> +
> +		nor@0,0 {
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			compatible = "cfi-flash";
> +			reg = <0x0 0x0 0x8000000>;
> +			bank-width = <2>;
> +			device-width = <1>;
> +		};
> +
> +		nand@2,0 {
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			compatible = "fsl,ifc-nand";
> +			reg = <0x2 0x0 0x10000>;
> +
> +			partition@0 {
> +				/* This location must not be altered  */
> +				/* 1MB for u-boot Bootloader Image */
> +				reg = <0x0 0x00100000>;
> +				label = "NAND U-Boot Image";
> +				read-only;
> +			};
> +
> +			partition@100000 {
> +				/* 1MB for DTB Image */
> +				reg = <0x00100000 0x00100000>;
> +				label = "NAND DTB Image";
> +			};
> +
> +			partition@200000 {
> +				/* 10MB for Linux Kernel Image */
> +				reg = <0x00200000 0x00A00000>;
> +				label = "NAND Linux Kernel Image";
> +			};
> +
> +			partition@c00000 {
> +				/* 500MB for Root file System Image */
> +				reg = <0x00c00000 0x1F400000>;
> +				label = "NAND RFS Image";
> +			};
> +		};
> +
> +		board-control@3,0 {
> +			compatible = "fsl,b4qds-fpga", "fsl,fpga-qixis";
> +			reg = <3 0 0x300>;
> +		};
> +	};
> +
> +	memory {
> +		device_type = "memory";
> +	};
> +
> +	dcsr: dcsr@f00000000 {
> +		ranges = <0x00000000 0xf 0x00000000 0x01052000>;
> +	};
> +
> +	soc: soc@ffe000000 {
> +		ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
> +		reg = <0xf 0xfe000000 0 0x00001000>;
> +		spi@110000 {
> +			flash@0 {
> +				#address-cells = <1>;
> +				#size-cells = <1>;
> +				compatible = "sst,sst25wf040";
> +				reg = <0>;
> +				spi-max-frequency = <40000000>; /* input clock */
> +			};
> +		};
> +
> +		sdhc@114000 {
> +			/*Disabled as there is no sdhc connector on B4420QDS board*/
> +			status = "disabled";
> +		};
> +
> +		i2c@118000 {
> +			eeprom@50 {
> +				compatible = "at24,24c64";
> +				reg = <0x50>;
> +			};
> +			eeprom@51 {
> +				compatible = "at24,24c256";
> +				reg = <0x51>;
> +			};
> +			eeprom@53 {
> +				compatible = "at24,24c256";
> +				reg = <0x53>;
> +			};
> +			eeprom@57 {
> +				compatible = "at24,24c256";
> +				reg = <0x57>;
> +			};
> +			rtc@68 {
> +				compatible = "dallas,ds3232";
> +				reg = <0x68>;
> +			};
> +		};
> +
> +		usb@210000 {
> +			dr_mode = "host";
> +			phy_type = "ulpi";
> +		};
> +
> +	};
> +
> +	pci0: pcie@ffe200000 {
> +		reg = <0xf 0xfe200000 0 0x10000>;
> +		ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
> +			  0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
> +		pcie@0 {
> +			ranges = <0x02000000 0 0xe0000000
> +				  0x02000000 0 0xe0000000
> +				  0 0x20000000
> +
> +				  0x01000000 0 0x00000000
> +				  0x01000000 0 0x00000000
> +				  0 0x00010000>;
> +		};
> +	};
> +
> +};
> +
> +/include/ "fsl/b4si-post.dtsi"

^ permalink raw reply

* RE: [alsa-devel] [PATCH 2/3] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Chen Guangyu-B42378 @ 2013-07-31 14:12 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: alsa-devel@alsa-project.org, devicetree-discuss@lists.ozlabs.org,
	timur@tabi.org, rob.herring@calxeda.com, broonie@kernel.org,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <51F9001B.6070203@metafoo.de>

Hi Lars

Thank you for the sage advices.

I'll revise the patch and send the v2.
________________________________________
From: Lars-Peter Clausen [lars@metafoo.de]
Sent: Wednesday, July 31, 2013 8:16 PM
To: Chen Guangyu-B42378
Cc: broonie@kernel.org; timur@tabi.org; alsa-devel@alsa-project.org; linuxp=
pc-dev@lists.ozlabs.org; devicetree-discuss@lists.ozlabs.org; rob.herring@c=
alxeda.com
Subject: Re: [alsa-devel] [PATCH 2/3] ASoC: fsl: Add S/PDIF CPU DAI driver

[...]
a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
> new file mode 100644
> index 0000000..a655800
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
> @@ -0,0 +1,63 @@
> +Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller
> +
> +The Freescale S/PDIF audio block is a stereo transceiver that allows the
> +processor to receive and transmit digital audio via an coaxial cable or
> +a fibre cable.
> +
> +Required properties:
> +
> +  - compatible : Compatible list, contains "fsl,spdif".

That's not what the driver says though.

> +
> +  - reg : Offset and length of the register set for the device.
> +
> +  - interrupts : <a b> where a is the interrupt number and b is a field =
that
> +    represents an encoding of the sense and level information for the in=
terrupt.
> +    This should be encoded based on the information in section 2) depend=
ing on
> +    the type of interrupt controller you have.

The exact layout of the cell depends on the parent interrupt controller, so
you probably shouldn't describe it here.

> +
> +  - clocks : The phandle for the clock ID number registered in clock tre=
e.
> +
> +  - fsl,spdif-dma-events: The dma event ID numbers for Tx and Rx.
> +

Use the generic DMA bindings.

> +Optional properties:
> +
> +  - rx-clk-source : The clock cource for Rx. Need to set this source acc=
ording
> +  to the SoC datasheet in SPDIF_SRPC section. If absent, the default sou=
rce is
> +  value 0x0 - if (DPLL Locked) SPDIF_RxClk else extal.
> +
> +  - tx-clk-source : The clock cources for Tx. There're three sources, ea=
ch for
> +  different supported sample rate, sequentially 32000Hz, 44100Hz and 480=
00Hz.
> +  Need to set this source according to the SoC datasheet in SPDIF_STC se=
ction.
> +  If absent, the default source is value 0x1 - CCM spdif0_clk_root input=
.
> +
> +  - tx-clk-div : The clock divider factor for Tx clock. There're three v=
alues,
> +  each for different supported sample rate, sequentially 32000Hz 44100Hz=
 48000Hz.
> +  Need to set this source according to the clock rate from the clock sou=
rce.
> +  If absent, the default divider factor is <37 23 37> by using spdif0_cl=
k source.

Can't the driver figure out the divider values on its own based on the inpu=
t
clock rate?

- Lars

^ permalink raw reply

* Re: mm/slab: ppc: ubi: kmalloc_slab WARNING / PPC + UBI driver
From: Christoph Lameter @ 2013-07-31 13:59 UTC (permalink / raw)
  To: Wladislav Wiebe
  Cc: dedekind1, dwmw2, penberg, linux-mm, linux-mtd, linuxppc-dev
In-Reply-To: <51F8F827.6020108@gmail.com>

On Wed, 31 Jul 2013, Wladislav Wiebe wrote:

> on a PPC 32-Bit board with a Linux Kernel v3.10.0 I see trouble with kmalloc_slab.
> Basically at system startup, something request a size of 8388608 b,
> but KMALLOC_MAX_SIZE has 4194304 b in our case. It points a WARNING at:

> ..
> NIP [c0099fec] kmalloc_slab+0x60/0xe8
> LR [c0099fd4] kmalloc_slab+0x48/0xe8
> Call Trace:
> [ccd3be60] [c0099fd4] kmalloc_slab+0x48/0xe8 (unreliable)
> [ccd3be70] [c00ae650] __kmalloc+0x20/0x1b4
> [ccd3be90] [c00d46f4] seq_read+0x2a4/0x540
> [ccd3bee0] [c00fe09c] proc_reg_read+0x5c/0x90
> [ccd3bef0] [c00b4e1c] vfs_read+0xa4/0x150
> [ccd3bf10] [c00b500c] SyS_read+0x4c/0x84
> [ccd3bf40] [c000be80] ret_from_syscall+0x0/0x3c
> ..
>
> Do you have any idea how I can analyze where these 8388608 b coming from?

It comes from the kmalloc in seq_read(). And 8M read from the proc
filesystem? Wow. Maybe switch the kmalloc to vmalloc()?

^ permalink raw reply

* RE: [PATCH 1/3] ASoC: codec: spdif: Add S20_3LE and S24_LE support for dummy codec drivers
From: Chen Guangyu-B42378 @ 2013-07-31 14:10 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel@alsa-project.org, linuxppc-dev@lists.ozlabs.org,
	timur@tabi.org, rob.herring@calxeda.com
In-Reply-To: <20130731132849.GR9858@sirena.org.uk>

On Wed, Jul 31, 2013, Mark Brown wrote:
> Applied, thanks.  Please check the mailing lists you're posting to -
> you've got the DT list wrong here and you shouldn't post non-binding
> reviews there anyway.

Sorry that I forgot to update the DT list addr but using an old one.
I'll pay attention to it next time. Thank you.=

^ permalink raw reply

* RE: Build regressions/improvements in v3.11-rc3
From: Chen Peter-B29397 @ 2013-07-31 14:08 UTC (permalink / raw)
  To: Geert Uytterhoeven, Linux Kernel Development
  Cc: linux-usb@vger.kernel.org, Linux/PPC Development
In-Reply-To: <alpine.DEB.2.02.1307301049230.23054@ayla.of.borg>

My patches "usb: chipidea: fix the build error with randconfig" fixes chipi=
dea problem.=0A=
It has already at USB fixes for 3.11-rc4.=0A=
=0A=
On Tue, 30 Jul 2013, Geert Uytterhoeven wrote:=0A=
> JFYI, when comparing v3.11-rc3 to v3.11-rc2[3], the summaries are:=0A=
>   - build errors: +38/-14=0A=
=0A=
  + arch/powerpc/kvm/book3s_emulate.c: error: 'bat' may be used uninitializ=
ed in this function [-Werror=3Duninitialized]:  =3D> 349:2=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_ANDCOND' undeclared (first=
 use in this function):  =3D> 161:17, 86:16=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_AVPN' undeclared (first us=
e in this function):  =3D> 160:17, 85:16, 192:16=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_BULK_REMOVE' undeclared (f=
irst use in this function):  =3D> 246:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_CEDE' undeclared (first us=
e in this function):  =3D> 250:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_CPPR' undeclared (first us=
e in this function):  =3D> 257:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_ENTER' undeclared (first u=
se in this function):  =3D> 240:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_EOI' undeclared (first use=
 in this function):  =3D> 258:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_EXACT' undeclared (first u=
se in this function):  =3D> 50:6=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_IPI' undeclared (first use=
 in this function):  =3D> 259:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_IPOLL' undeclared (first u=
se in this function):  =3D> 260:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_NOT_FOUND' undeclared (fir=
st use in this function):  =3D> 193:27, 87:27=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_PARAMETER' undeclared (fir=
st use in this function):  =3D> 138:10=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_PROTECT' undeclared (first=
 use in this function):  =3D> 244:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_PTEG_FULL' undeclared (fir=
st use in this function):  =3D> 54:12=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_PUT_TCE' undeclared (first=
 use in this function):  =3D> 248:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_REMOVE' undeclared (first =
use in this function):  =3D> 242:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_RTAS' undeclared (first us=
e in this function):  =3D> 265:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_SUCCESS' undeclared (first=
 use in this function):  =3D> 67:26, 96:26, 211:26, 125:12=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_TOO_HARD' undeclared (firs=
t use in this function):  =3D> 224:12=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_XIRR' undeclared (first us=
e in this function):  =3D> 256:7=0A=
  + arch/powerpc/kvm/book3s_pr_papr.c: error: 'H_XIRR_X' undeclared (first =
use in this function):  =3D> 261:7=0A=
  + arch/powerpc/platforms/pseries/hotplug-memory.c: error: 'SECTION_SIZE_B=
ITS' undeclared (first use in this function):  =3D> 24:31=0A=
  + mm/memory_hotplug.c: error: 'PAGES_PER_SECTION' undeclared (first use i=
n this function):  =3D> 1630:46=0A=
  + mm/memory_hotplug.c: error: implicit declaration of function '__nr_to_s=
ection' [-Werror=3Dimplicit-function-declaration]:  =3D> 1635:3=0A=
  + mm/memory_hotplug.c: error: implicit declaration of function 'find_memo=
ry_block_hinted' [-Werror=3Dimplicit-function-declaration]:  =3D> 1642:3=0A=
  + mm/memory_hotplug.c: error: implicit declaration of function 'pfn_to_se=
ction_nr' [-Werror=3Dimplicit-function-declaration]:  =3D> 1631:3=0A=
  + mm/memory_hotplug.c: error: implicit declaration of function 'present_s=
ection_nr' [-Werror=3Dimplicit-function-declaration]:  =3D> 1632:3=0A=
=0A=
powerpc-randconfig=0A=
=0A=
  + drivers/md/dm-cache-policy-mq.c: error: conflicting types for 'remove_m=
apping':  =3D> 962:13=0A=
=0A=
sparc-allmodconfig, not a regression (was hidden due to a sparc64/sparc32=
=0A=
mixup on kissb), patch submitted=0A=
=0A=
  + error: "usb_add_gadget_udc" [drivers/usb/chipidea/ci_hdrc.ko] undefined=
!:  =3D> N/A=0A=
  + error: "usb_del_gadget_udc" [drivers/usb/chipidea/ci_hdrc.ko] undefined=
!:  =3D> N/A=0A=
  + error: "usb_gadget_map_request" [drivers/usb/chipidea/ci_hdrc.ko] undef=
ined!:  =3D> N/A=0A=
  + error: "usb_gadget_unmap_request" [drivers/usb/chipidea/ci_hdrc.ko] und=
efined!:  =3D> N/A=0A=
=0A=
x86_64-randconfig=0A=
=0A=
> [1] http://kisskb.ellerman.id.au/kisskb/head/6490/ (all 120 configs)=0A=
> [3] http://kisskb.ellerman.id.au/kisskb/head/6461/ (all 120 configs)=0A=
=0A=
Gr{oetje,eeting}s,=0A=
=0A=
                                                Geert=0A=
=0A=
--=0A=
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k=
.org=0A=
=0A=
In personal conversations with technical people, I call myself a hacker. Bu=
t=0A=
when I'm talking to journalists I just say "programmer" or something like t=
hat.=0A=
                                                            -- Linus Torval=
ds=0A=
--=0A=
To unsubscribe from this list: send the line "unsubscribe linux-usb" in=0A=
the body of a message to majordomo@vger.kernel.org=0A=
More majordomo info at  http://vger.kernel.org/majordomo-info.html=0A=
=0A=

^ permalink raw reply

* Re: [PATCH 1/3] ASoC: codec: spdif: Add S20_3LE and S24_LE support for dummy codec drivers
From: Mark Brown @ 2013-07-31 13:28 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: devicetree-discuss, alsa-devel, linuxppc-dev, timur, rob.herring
In-Reply-To: <ad8f9d8812c1823ae6f9e4a0d1e6d3c76b26a285.1375271745.git.b42378@freescale.com>

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

On Wed, Jul 31, 2013 at 08:07:05PM +0800, Nicolin Chen wrote:
> Generally, S/PDIF supports 20bit and optional 24bit samples. Thus add these
> two formats for the dummy codec drivers.

Applied, thanks.  Please check the mailing lists you're posting to -
you've got the DT list wrong here and you shouldn't post non-binding
reviews there anyway.

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

^ permalink raw reply

* Re: [alsa-devel] [PATCH 2/3] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Lars-Peter Clausen @ 2013-07-31 12:16 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: alsa-devel, devicetree-discuss, timur, rob.herring, broonie,
	linuxppc-dev
In-Reply-To: <30e7b0fec9e813b8765514e48296ebecc6ca1039.1375271745.git.b42378@freescale.com>

[...]
a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
> new file mode 100644
> index 0000000..a655800
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
> @@ -0,0 +1,63 @@
> +Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller
> +
> +The Freescale S/PDIF audio block is a stereo transceiver that allows the
> +processor to receive and transmit digital audio via an coaxial cable or
> +a fibre cable.
> +
> +Required properties:
> +
> +  - compatible : Compatible list, contains "fsl,spdif".

That's not what the driver says though.

> +
> +  - reg : Offset and length of the register set for the device.
> +
> +  - interrupts : <a b> where a is the interrupt number and b is a field that
> +    represents an encoding of the sense and level information for the interrupt.
> +    This should be encoded based on the information in section 2) depending on
> +    the type of interrupt controller you have.

The exact layout of the cell depends on the parent interrupt controller, so
you probably shouldn't describe it here.

> +
> +  - clocks : The phandle for the clock ID number registered in clock tree.
> +
> +  - fsl,spdif-dma-events: The dma event ID numbers for Tx and Rx.
> +

Use the generic DMA bindings.

> +Optional properties:
> +
> +  - rx-clk-source : The clock cource for Rx. Need to set this source according
> +  to the SoC datasheet in SPDIF_SRPC section. If absent, the default source is
> +  value 0x0 - if (DPLL Locked) SPDIF_RxClk else extal.
> +
> +  - tx-clk-source : The clock cources for Tx. There're three sources, each for
> +  different supported sample rate, sequentially 32000Hz, 44100Hz and 48000Hz.
> +  Need to set this source according to the SoC datasheet in SPDIF_STC section.
> +  If absent, the default source is value 0x1 - CCM spdif0_clk_root input.
> +
> +  - tx-clk-div : The clock divider factor for Tx clock. There're three values,
> +  each for different supported sample rate, sequentially 32000Hz 44100Hz 48000Hz.
> +  Need to set this source according to the clock rate from the clock source.
> +  If absent, the default divider factor is <37 23 37> by using spdif0_clk source.

Can't the driver figure out the divider values on its own based on the input
clock rate?

- Lars

^ permalink raw reply

* [PATCH 2/3] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Nicolin Chen @ 2013-07-31 12:07 UTC (permalink / raw)
  To: broonie, timur; +Cc: alsa-devel, linuxppc-dev, devicetree-discuss, rob.herring
In-Reply-To: <cover.1375271745.git.b42378@freescale.com>

This patch add S/PDIF controller driver for Freescale SoC.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 .../devicetree/bindings/sound/fsl,spdif.txt        |   63 +
 sound/soc/fsl/Kconfig                              |    3 +
 sound/soc/fsl/Makefile                             |    2 +
 sound/soc/fsl/fsl_spdif.c                          | 1276 ++++++++++++++++++++
 sound/soc/fsl/fsl_spdif.h                          |  233 ++++
 5 files changed, 1577 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,spdif.txt
 create mode 100644 sound/soc/fsl/fsl_spdif.c
 create mode 100644 sound/soc/fsl/fsl_spdif.h

diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
new file mode 100644
index 0000000..a655800
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -0,0 +1,63 @@
+Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Freescale S/PDIF audio block is a stereo transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+  - compatible : Compatible list, contains "fsl,spdif".
+
+  - reg : Offset and length of the register set for the device.
+
+  - interrupts : <a b> where a is the interrupt number and b is a field that
+    represents an encoding of the sense and level information for the interrupt.
+    This should be encoded based on the information in section 2) depending on
+    the type of interrupt controller you have.
+
+  - clocks : The phandle for the clock ID number registered in clock tree.
+
+  - fsl,spdif-dma-events: The dma event ID numbers for Tx and Rx.
+
+Optional properties:
+
+  - rx-clk-source : The clock cource for Rx. Need to set this source according
+  to the SoC datasheet in SPDIF_SRPC section. If absent, the default source is
+  value 0x0 - if (DPLL Locked) SPDIF_RxClk else extal.
+
+  - tx-clk-source : The clock cources for Tx. There're three sources, each for
+  different supported sample rate, sequentially 32000Hz, 44100Hz and 48000Hz.
+  Need to set this source according to the SoC datasheet in SPDIF_STC section.
+  If absent, the default source is value 0x1 - CCM spdif0_clk_root input.
+
+  - tx-clk-div : The clock divider factor for Tx clock. There're three values,
+  each for different supported sample rate, sequentially 32000Hz 44100Hz 48000Hz.
+  Need to set this source according to the clock rate from the clock source.
+  If absent, the default divider factor is <37 23 37> by using spdif0_clk source.
+
+Example:
+
+spdif: spdif@02004000 {
+	compatible = "fsl,fsl-spdif";
+	reg = <0x02004000 0x4000>;
+	interrupts = <0 52 0x04>;
+	clocks = <&clks 197>;
+	fsl,spdif-dma-events = <15 14>;
+
+	rx-clk-source = <0x0>;
+	tx-clk-source = <
+		0x1 /* Tx clk src for 32KHz: CCM spdif0_clk_root input */
+		0x1 /* Tx clk src for 44KHz: CCM spdif0_clk_root input */
+		0x1 /* Tx clk src for 48KHz: CCM spdif0_clk_root input */
+	>;
+
+	/*
+	 * In i.MX6Q SoC, the clock rate of spdif0_clk_root will be 454.7MHz.
+	 * 32KHz:   454.7MHz / 6(ccm) / 37(spdif) = 32,003 Hz ~ 0.01% error
+	 * 44.1KHz: 454.7MHz / 7(ccm) / 23(spdif) = 44,128 Hz ~ 0.06% error
+	 * 48KHz:   454.7MHz / 4(ccm) / 37(spdif) = 48,004 Hz ~ 0.01% error
+	 */
+	tx-clk-div = <37 23 37>;
+
+	status = "okay";
+};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3a79d01..156b794 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,6 +1,9 @@
 config SND_SOC_FSL_SSI
 	tristate
 
+config SND_SOC_FSL_SPDIF
+	tristate
+
 config SND_SOC_FSL_UTILS
 	tristate
 
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index d4b4aa8..4b5970e 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -12,9 +12,11 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 
 # Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-spdif-objs := fsl_spdif.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
+obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
new file mode 100644
index 0000000..7b10bed
--- /dev/null
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -0,0 +1,1276 @@
+/*
+ * Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Based on stmp3xxx_spdif_dai.c
+ * Vladimir Barinov <vbarinov@embeddedalley.com>
+ * Copyright 2008 SigmaTel, Inc
+ * Copyright 2008 Embedded Alley Solutions, Inc
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program  is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#include <sound/asoundef.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "fsl_spdif.h"
+#include "imx-pcm.h"
+
+#define FSL_SPDIF_TXFIFO_WML      0x8
+#define FSL_SPDIF_RXFIFO_WML      0x8
+
+#define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC)
+#define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL | INT_URX_OV|\
+		INT_QRX_FUL | INT_QRX_OV | INT_UQ_SYNC | INT_UQ_ERR |\
+		INT_RXFIFO_RESYNC | INT_LOSS_LOCK | INT_DPLL_LOCKED)
+
+enum fsl_spdif_type {
+	FSL_IMX6Q_SPDIF,
+	FSL_IMX6SL_SPDIF,
+};
+
+static struct platform_device_id fsl_spdif_devtype[] = {
+	{
+		.name = "imx6q-spdif",
+		.driver_data = FSL_IMX6Q_SPDIF,
+	},
+	{
+		.name = "imx6sl-spdif",
+		.driver_data = FSL_IMX6SL_SPDIF,
+	},
+};
+MODULE_DEVICE_TABLE(platform, fsl_spdif_devtype);
+
+static const struct of_device_id fsl_spdif_dt_ids[] = {
+	{ .compatible = "fsl,fsl-spdif", .data = &fsl_spdif_devtype[FSL_IMX6Q_SPDIF], },
+	{ .compatible = "fsl,imx6q-spdif", .data = &fsl_spdif_devtype[FSL_IMX6Q_SPDIF], },
+	{ .compatible = "fsl,imx6dl-spdif", .data = &fsl_spdif_devtype[FSL_IMX6SL_SPDIF], },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
+
+/* spdif_devtype indicates which module version is being used */
+static u8 spdif_devtype;
+
+/*
+ * SPDIF control structure
+ * Defines channel status, subcode and Q sub
+ */
+struct spdif_mixer_control {
+	/* spinlock to access control data */
+	spinlock_t ctl_lock;
+
+	/* IEC958 channel tx status bit */
+	unsigned char ch_status[4];
+
+	/* User bits */
+	unsigned char subcode[2 * SPDIF_UBITS_SIZE];
+
+	/* Q subcode part of user bits */
+	unsigned char qsub[2 * SPDIF_QSUB_SIZE];
+
+	/* buffer ptrs for writer */
+	u32 upos;
+	u32 qpos;
+
+	/* ready buffer index of the two buffers */
+	u32 ready_buf;
+};
+
+struct fsl_spdif_priv {
+	struct spdif_mixer_control fsl_spdif_control;
+	struct snd_soc_dai_driver cpu_dai_drv;
+	struct reg_spdif __iomem *spdif;
+	struct platform_device *pdev;
+	dma_addr_t spdif_phys;
+	atomic_t dpll_locked;
+	u32 irq;
+	u8 rxclk_src;
+	u8 txclk_src[SPDIF_TXRATE_MAX];
+	u8 txclk_div[SPDIF_TXRATE_MAX];
+	struct clk *clk;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+	struct imx_dma_data filter_data_tx;
+	struct imx_dma_data filter_data_rx;
+
+	char name[1];
+};
+
+
+/* All the registers of SPDIF are 24-bit implemented */
+static u32 spdif_read(u32 __iomem *addr)
+{
+	return __raw_readl(addr) & 0xffffff;
+}
+
+static void spdif_write(u32 __iomem *addr, u32 val)
+{
+	__raw_writel(val & 0xffffff, addr);
+}
+
+static void spdif_setbits(u32 __iomem *addr, u32 bits)
+{
+	u32 val;
+
+	val = spdif_read(addr);
+	val |= bits;
+	spdif_write(addr, val);
+}
+
+static void spdif_clrbits(u32 __iomem *addr, u32 bits)
+{
+	u32 val;
+
+	val = spdif_read(addr);
+	val &= ~bits;
+	spdif_write(addr, val);
+}
+
+static void spdif_setmask(u32 __iomem *addr, u32 mask, u32 bits)
+{
+	u32 val;
+
+	val = spdif_read(addr);
+	val = (val & ~mask) | (bits & mask);
+	spdif_write(addr, val);
+}
+
+#ifdef DEBUG
+static void dumpregs(struct fsl_spdif_priv *spdif_priv)
+{
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 val, i;
+
+	clk_enable(spdif_priv->clk);
+
+	/* Valid address set of SPDIF is {[0x0-0x38], 0x44, 0x50} */
+	for (i = 0 ; i <= 0x38 ; i += 4) {
+		val = spdif_read(&spdif->scr + i / 4);
+		dev_dbg(&pdev->dev, "REG 0x%02x = 0x%06x\n", i, val);
+	}
+
+	i = 0x44;
+	val = spdif_read(&spdif->scr + i / 4) & 0xffffff;
+	dev_dbg(&pdev->dev, "REG 0x%02x = 0x%06x\n", i, val);
+
+	i = 0x50;
+	val = spdif_read(&spdif->scr + i / 4) & 0xffffff;
+	dev_dbg(&pdev->dev, "REG 0x%02x = 0x%06x\n", i, val);
+
+	clk_disable(spdif_priv->clk);
+}
+#else
+static void dumpregs(struct fsl_spdif_priv *spdif_priv) {}
+#endif
+
+
+/* DPLL locked and lock loss interrupt handler */
+static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
+{
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 locked = spdif_read(&spdif->srpc) & SRPC_DPLL_LOCKED;
+
+	dev_dbg(&pdev->dev, "isr: Rx dpll %s \n",
+			locked ? "locked" : "loss lock");
+	atomic_set(&spdif_priv->dpll_locked, locked ? 1 : 0);
+}
+
+/* Receiver found illegal symbol interrupt handler */
+static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv)
+{
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+
+	dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n");
+	if (!atomic_read(&spdif_priv->dpll_locked)) {
+		/* dpll unlocked seems no audio stream */
+		spdif_clrbits(&spdif->sie, INT_SYM_ERR);
+	}
+}
+
+/* U/Q Channel receive register full */
+static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name)
+{
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 *pos, size, val;
+	u32 __iomem *reg;
+
+	switch (name) {
+	case 'U':
+		pos = &ctrl->upos;
+		size = SPDIF_UBITS_SIZE;
+		reg = &spdif->sru;
+		break;
+	case 'Q':
+		pos = &ctrl->qpos;
+		size = SPDIF_QSUB_SIZE;
+		reg = &spdif->srq;
+		break;
+	default:
+		return;
+	}
+
+	dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name);
+
+	if (*pos >= size * 2) {
+		*pos = 0;
+	} else if (unlikely((*pos % size) + 3 > size)) {
+		dev_err(&pdev->dev, "User bit receivce buffer overflow\n");
+		return;
+	}
+	val = spdif_read(reg);
+	ctrl->subcode[*pos++] = val >> 16;
+	ctrl->subcode[*pos++] = val >> 8;
+	ctrl->subcode[*pos++] = val;
+}
+
+/* U/Q Channel sync found */
+static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv) {
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct platform_device *pdev = spdif_priv->pdev;
+
+	dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n");
+
+	/* U/Q buffer reset */
+	if (ctrl->qpos == 0)
+		return;
+
+	/* set ready to this buffer */
+	ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1;
+}
+
+/* U/Q Channel framing error */
+static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv) {
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 val;
+
+	dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n");
+
+	/* read U/Q data and do buffer reset */
+	val = spdif_read(&spdif->sru);
+	val = spdif_read(&spdif->srq);
+
+	/* drop this U/Q buffer */
+	ctrl->ready_buf = 0;
+	ctrl->upos = 0;
+	ctrl->qpos = 0;
+}
+
+/* Get spdif interrupt status and clear the interrupt */
+static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv)
+{
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	u32 val = spdif_read(&spdif->sisc);
+
+	val &= spdif_read(&spdif->sie);
+	spdif_write(&spdif->sisc, val);
+
+	return val;
+}
+
+static irqreturn_t spdif_isr(int irq, void *devid)
+{
+	struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 sis;
+
+	sis = spdif_intr_status_clear(spdif_priv);
+
+	if (sis & INT_DPLL_LOCKED)
+		spdif_irq_dpll_lock(spdif_priv);
+
+	if (sis & INT_TXFIFO_UNOV)
+		dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n");
+
+	if (sis & INT_TXFIFO_RESYNC)
+		dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n");
+
+	if (sis & INT_CNEW)
+		dev_dbg(&pdev->dev, "isr: cstatus new\n");
+
+	if (sis & INT_VAL_NOGOOD)
+		dev_dbg(&pdev->dev, "isr: validity flag no good\n");
+
+	if (sis & INT_SYM_ERR)
+		spdif_irq_sym_error(spdif_priv);
+
+	if (sis & INT_BIT_ERR)
+		dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n");
+
+	if (sis & INT_URX_FUL)
+		spdif_irq_uqrx_full(spdif_priv, 'U');
+
+	if (sis & INT_URX_OV)
+		dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n");
+
+	if (sis & INT_QRX_FUL)
+		spdif_irq_uqrx_full(spdif_priv, 'Q');
+
+	if (sis & INT_QRX_OV)
+		dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n");
+
+	if (sis & INT_UQ_SYNC)
+		spdif_irq_uq_sync(spdif_priv);
+
+	if (sis & INT_UQ_ERR)
+		spdif_irq_uq_err(spdif_priv);
+
+	if (sis & INT_RXFIFO_UNOV)
+		dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n");
+
+	if (sis & INT_RXFIFO_RESYNC)
+		dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n");
+
+	if (sis & INT_LOSS_LOCK)
+		spdif_irq_dpll_lock(spdif_priv);
+
+	/* FIXME: Write Tx FIFO to clear TxEm */
+	if (sis & INT_TX_EM)
+		dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n");
+
+	/* FIXME: Read Rx FIFO to clear RxFIFOFul */
+	if (sis & INT_RXFIFO_FUL)
+		dev_dbg(&pdev->dev, "isr: Rx FIFO full\n");
+
+	return IRQ_HANDLED;
+}
+
+static void spdif_softreset(struct fsl_spdif_priv *spdif_priv)
+{
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	int cycle = 100;
+
+	spdif_write(&spdif->scr, SCR_SOFT_RESET);
+
+	/* RESET bit would be cleared after finishing its reset procedure */
+	while ((spdif_read(&spdif->scr) & SCR_SOFT_RESET) && cycle--);
+}
+
+static void spdif_set_cstatus(struct spdif_mixer_control *ctrl,
+				u8 mask, u8 cstatus)
+{
+	ctrl->ch_status[3] &= ~mask;
+	ctrl->ch_status[3] |= cstatus & mask;
+}
+
+static u8 reverse_bits(u8 input)
+{
+	u8 i, output = 0;
+	for (i = 8 ; i > 0 ; i--) {
+		output <<= 1;
+		output |= input & 0x01;
+		input >>= 1;
+	}
+	return output;
+}
+
+static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv)
+{
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 ch_status;
+
+	ch_status = (reverse_bits(ctrl->ch_status[0]) << 16) |
+		(reverse_bits(ctrl->ch_status[1]) << 8) |
+		reverse_bits(ctrl->ch_status[2]);
+	spdif_write(&spdif->stcsch, ch_status);
+
+	ch_status = reverse_bits(ctrl->ch_status[3]) << 16;
+	spdif_write(&spdif->stcscl, ch_status);
+
+	dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", spdif_read(&spdif->stcsch));
+	dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", spdif_read(&spdif->stcscl));
+}
+
+/*
+ * Check if the clock source setting cares about DPLL Locked condition
+ *
+ * The DPLL locked condition should depend on SoC design, being different
+ * between different spdif_devtype.
+ */
+static inline bool spdif_rxclk_lock_check(enum spdif_rxclk_src clksrc) {
+
+	switch (spdif_devtype) {
+	case FSL_IMX6Q_SPDIF:
+		if (clksrc <= SRPC_CLKSRC_4)
+			return true;
+		else if (clksrc <= SRPC_CLKSRC_9)
+			return false;
+		else if (clksrc <= SRPC_CLKSRC_11)
+			return true;
+		else
+			return false;
+		break;
+	case FSL_IMX6SL_SPDIF:
+		if (clksrc <= SRPC_CLKSRC_3)
+			return true;
+		else
+			return false;
+		break;
+	default:
+		return false;
+	}
+}
+
+/* Set SPDIF PhaseConfig register for rx clock */
+static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
+				enum spdif_gainsel gainsel, int dpll_locked)
+{
+	enum spdif_rxclk_src clksrc = spdif_priv->rxclk_src;
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+
+	if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX)
+		return -EINVAL;
+
+	if (!dpll_locked && spdif_rxclk_lock_check(clksrc))
+		clksrc += SRPC_CLKSRC_SEL_LOCKED;
+
+	spdif_setmask(&spdif->srpc, SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
+			SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel));
+
+	return 0;
+}
+
+static int spdif_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long rate_actual;
+
+	rate_actual = clk_round_rate(clk, rate);
+	clk_set_rate(clk, rate_actual);
+
+	return 0;
+}
+
+static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
+				int sample_rate)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+	unsigned long clk = -1, div = 1, csfs = 0;
+	u32 stc, mask;
+
+	switch (sample_rate) {
+	case 32000:
+		clk = spdif_priv->txclk_src[SPDIF_TXRATE_32000];
+		div = spdif_priv->txclk_div[SPDIF_TXRATE_32000];
+		csfs = IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		clk = spdif_priv->txclk_src[SPDIF_TXRATE_44100];
+		div = spdif_priv->txclk_div[SPDIF_TXRATE_44100];
+		csfs = IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		clk = spdif_priv->txclk_src[SPDIF_TXRATE_48000];
+		div = spdif_priv->txclk_div[SPDIF_TXRATE_48000];
+		csfs = IEC958_AES3_CON_FS_48000;
+		break;
+	default:
+		dev_err(&pdev->dev, "unsupported samplerate %d\n", sample_rate);
+		return -EINVAL;
+	}
+
+	if (clk < 0) {
+		dev_err(&pdev->dev, "no defined %d clk src\n", sample_rate);
+		return -EINVAL;
+	}
+
+	/*
+	 * The S/PDIF block needs a clock of 64 * fs * div.  The S/PDIF block
+	 * will divide by (div).  So request 64 * fs * (div+1) which will
+	 * get rounded.
+	 */
+	spdif_clk_set_rate(spdif_priv->clk, 64 * sample_rate * (div + 1));
+
+	dev_dbg(&pdev->dev, "expected clock rate = %d\n",
+			(int)(64 * sample_rate * div));
+	dev_dbg(&pdev->dev, "acutal clock rate = %d\n",
+			(int)clk_get_rate(spdif_priv->clk));
+
+	/* set fs field in consumer channel status */
+	spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs);
+
+	/* select clock source and divisor */
+	stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div);
+	mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK;
+	spdif_setmask(&spdif->stc, mask, stc);
+
+	dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate);
+
+	return 0;
+}
+
+int fsl_spdif_startup(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *cpu_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	u32 scr, mask;
+	int ret = 0;
+
+	/* enable spdif_xtal_clk */
+	ret = clk_enable(spdif_priv->clk);
+	if (ret)
+		return ret;
+
+	/* Reset module and interrupts only for first initialization */
+	if (!cpu_dai->active) {
+		spdif_softreset(spdif_priv);
+
+		/* disable all the interrupts */
+		spdif_clrbits(&spdif->sie, 0xffffff);
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL |
+			SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP |
+			SCR_TXFIFO_FSEL_IF8;
+		mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
+			SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
+			SCR_TXFIFO_FSEL_MASK;
+	} else {
+		scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
+		mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
+			SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
+	}
+	spdif_setmask(&spdif->scr, mask, scr);
+
+	/* Power up SPDIF module */
+	spdif_clrbits(&spdif->scr, SCR_LOW_POWER);
+
+	return 0;
+}
+
+static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *cpu_dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	u32 scr, mask;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		scr = 0;
+		mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
+			SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
+			SCR_TXFIFO_FSEL_MASK;
+	} else {
+		scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO;
+		mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
+			SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
+	}
+	spdif_setmask(&spdif->scr, mask, scr);
+
+	/* Power down SPDIF module only if tx&rx are both inactive */
+	if (!cpu_dai->active) {
+		spdif_intr_status_clear(spdif_priv);
+		spdif_setbits(&spdif->scr, SCR_LOW_POWER);
+	}
+
+	/* disable spdif clock  */
+	clk_disable(spdif_priv->clk);
+}
+
+static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 sample_rate = params_rate(params);
+	int ret = 0;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ret  = spdif_set_sample_rate(substream, sample_rate);
+		if (ret) {
+			dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
+					__func__, sample_rate);
+			return ret;
+		}
+		spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK,
+				IEC958_AES3_CON_CLOCK_1000PPM);
+		spdif_write_channel_status(spdif_priv);
+	} else {
+		/* setup rx clock source */
+		spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1);
+	}
+
+	return ret;
+}
+
+static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
+				int cmd, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	int is_playack = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+	u32 intr = is_playack ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE;
+	u32 dmaen = is_playack ? SCR_DMA_TX_EN : SCR_DMA_RX_EN;;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		spdif_setbits(&spdif->sie, intr);
+		spdif_setbits(&spdif->scr, dmaen);
+		dumpregs(spdif_priv);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		spdif_clrbits(&spdif->scr, dmaen);
+		spdif_clrbits(&spdif->sie, intr);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+	.startup = fsl_spdif_startup,
+	.hw_params = fsl_spdif_hw_params,
+	.trigger = fsl_spdif_trigger,
+	.shutdown = fsl_spdif_shutdown,
+};
+
+
+/*
+ * ============================================
+ * FSL SPDIF IEC958 controller(mixer) functions
+ *
+ *	Channel status get/put control
+ *	User bit value get/put control
+ *	Valid bit value get control
+ *	DPLL lock status get control
+ *	User bit sync mode selection control
+ * ============================================
+ */
+
+static int mxc_pb_spdif_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+
+	return 0;
+}
+
+static int mxc_pb_spdif_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *uvalue)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+
+	uvalue->value.iec958.status[0] = ctrl->ch_status[0];
+	uvalue->value.iec958.status[1] = ctrl->ch_status[1];
+	uvalue->value.iec958.status[2] = ctrl->ch_status[2];
+	uvalue->value.iec958.status[3] = ctrl->ch_status[3];
+
+	return 0;
+}
+
+static int mxc_pb_spdif_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *uvalue)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+
+	ctrl->ch_status[0] = uvalue->value.iec958.status[0];
+	ctrl->ch_status[1] = uvalue->value.iec958.status[1];
+	ctrl->ch_status[2] = uvalue->value.iec958.status[2];
+	ctrl->ch_status[3] = uvalue->value.iec958.status[3];
+
+	clk_enable(spdif_priv->clk);
+
+	spdif_write_channel_status(spdif_priv);
+
+	clk_disable(spdif_priv->clk);
+
+	return 0;
+}
+
+static int fsl_spdif_info(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+
+	return 0;
+}
+
+/* Get channel status from SPDIF_RX_CCHAN register */
+static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	u32 cstatus;
+
+	clk_enable(spdif_priv->clk);
+
+	if (!(spdif_read(&spdif->sisc) & INT_CNEW)) {
+		clk_disable(spdif_priv->clk);
+		return -EAGAIN;
+	}
+
+	cstatus = spdif_read(&spdif->srcsch);
+	ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF;
+	ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF;
+	ucontrol->value.iec958.status[2] = cstatus & 0xFF;
+
+	cstatus = spdif_read(&spdif->srcscl);
+	ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF;
+	ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF;
+	ucontrol->value.iec958.status[5] = cstatus & 0xFF;
+
+	/* clear intr */
+	spdif_write(&spdif->sisc, INT_CNEW);
+
+	clk_disable(spdif_priv->clk);
+
+	return 0;
+}
+
+/*
+ * Get User bits (subcode) from chip value which readed out
+ * in UChannel register.
+ */
+static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&ctrl->ctl_lock, flags);
+	if (ctrl->ready_buf) {
+		int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
+		memcpy(&ucontrol->value.iec958.subcode[0],
+				&ctrl->subcode[idx], SPDIF_UBITS_SIZE);
+	} else {
+		ret = -EAGAIN;
+	}
+	spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
+
+	return ret;
+}
+
+/* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */
+static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+	uinfo->count = SPDIF_QSUB_SIZE;
+
+	return 0;
+}
+
+/* Get Q subcode from chip value which readed out in QChannel register */
+static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&ctrl->ctl_lock, flags);
+	if (ctrl->ready_buf) {
+		int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
+		memcpy(&ucontrol->value.bytes.data[0],
+				&ctrl->qsub[idx], SPDIF_QSUB_SIZE);
+	} else {
+		ret = -EAGAIN;
+	}
+	spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
+
+	return ret;
+}
+
+/* Valid bit infomation */
+static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+/* Get valid good bit from interrupt status register */
+static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	u32 int_val;
+
+	clk_enable(spdif_priv->clk);
+
+	int_val = spdif_read(&spdif->sisc);
+	ucontrol->value.integer.value[0] = (int_val & INT_VAL_NOGOOD) != 0;
+	spdif_write(&spdif->sisc, INT_VAL_NOGOOD);
+
+	clk_disable(spdif_priv->clk);
+
+	return 0;
+}
+
+/* DPLL lock infomation */
+static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 16000;
+	uinfo->value.integer.max = 96000;
+
+	return 0;
+}
+
+static u32 gainsel_multi[GAINSEL_MULTI_MAX] = {
+	24, 16, 12, 8, 6, 4, 3,
+};
+
+/* Get RX data clock rate given the SPDIF bus_clk */
+static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
+				enum spdif_gainsel gainsel)
+{
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u64 tmpval64, freqmeas, phaseconf, busclk_freq = 0;
+	enum spdif_rxclk_src clksrc;
+
+	freqmeas = spdif_read(&spdif->srfm);
+	phaseconf = spdif_read(&spdif->srpc);
+
+	clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
+	if (spdif_rxclk_lock_check(clksrc) && (phaseconf & SRPC_DPLL_LOCKED)) {
+		/* get bus clock from system */
+		busclk_freq = clk_get_rate(spdif_priv->clk);
+	}
+
+	/* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
+	tmpval64 = (u64) busclk_freq * freqmeas;
+	do_div(tmpval64, gainsel_multi[gainsel] * 1024);
+	do_div(tmpval64, 128 * 1024);
+
+	dev_dbg(&pdev->dev, "FreqMeas: %d\n", (int)freqmeas);
+	dev_dbg(&pdev->dev, "BusclkFreq: %d\n", (int)busclk_freq);
+	dev_dbg(&pdev->dev, "RxRate: %d\n", (int)tmpval64);
+
+	return (int)tmpval64;
+}
+
+/*
+ * Get DPLL lock or not info from stable interrupt status register.
+ * User application must use this control to get locked,
+ * then can do next PCM operation
+ */
+static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+
+	if (atomic_read(&spdif_priv->dpll_locked)) {
+		clk_enable(spdif_priv->clk);
+		ucontrol->value.integer.value[0] =
+			spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL);
+		clk_disable(spdif_priv->clk);
+	} else {
+		ucontrol->value.integer.value[0] = 0;
+	}
+
+	return 0;
+}
+
+/* User bit sync mode info */
+static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+/*
+ * User bit sync mode:
+ * 1 CD User channel subcode
+ * 0 Non-CD data
+ */
+static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	u32 int_val;
+
+	clk_enable(spdif_priv->clk);
+
+	int_val = spdif_read(&spdif->srcd);
+	ucontrol->value.integer.value[0] = (int_val & SRCD_CD_USER) != 0;
+
+	clk_disable(spdif_priv->clk);
+
+	return 0;
+}
+
+/*
+ * User bit sync mode:
+ * 1 CD User channel subcode
+ * 0 Non-CD data
+ */
+static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+	struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct reg_spdif __iomem *spdif = spdif_priv->spdif;
+	u32 int_val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET;
+
+	clk_enable(spdif_priv->clk);
+
+	spdif_setmask(&spdif->srcd, SRCD_CD_USER, int_val);
+
+	clk_disable(spdif_priv->clk);
+
+	return 0;
+}
+
+/* FSL SPDIF IEC958 controller defines */
+static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
+	/* status cchanel controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_WRITE |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = mxc_pb_spdif_info,
+		.get = mxc_pb_spdif_get,
+		.put = mxc_pb_spdif_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_info,
+		.get = fsl_spdif_capture_get,
+	},
+	/* user bits controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 Subcode Capture Default",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_info,
+		.get = fsl_spdif_subcode_get,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 Q-subcode Capture Default",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_qinfo,
+		.get = fsl_spdif_qget,
+	},
+	/* valid bit error controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 V-Bit Errors",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_vbit_info,
+		.get = fsl_spdif_vbit_get,
+	},
+	/* DPLL lock info get controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "RX Sample Rate",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_rxrate_info,
+		.get = fsl_spdif_rxrate_get,
+	},
+	/* User bit sync mode set/get controller */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
+		.name = "IEC958 USyncMode CDText",
+		.access = SNDRV_CTL_ELEM_ACCESS_READ |
+			SNDRV_CTL_ELEM_ACCESS_WRITE |
+			SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+		.info = fsl_spdif_usync_info,
+		.get = fsl_spdif_usync_get,
+		.put = fsl_spdif_usync_put,
+	},
+};
+
+static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
+{
+	struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
+
+	dai->playback_dma_data = &spdif_private->dma_params_tx;
+	dai->capture_dma_data = &spdif_private->dma_params_rx;
+
+	snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
+
+	return 0;
+}
+
+struct snd_soc_dai_driver fsl_spdif_dai = {
+	.probe = &fsl_spdif_dai_probe,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = FSL_SPDIF_RATES_PLAYBACK,
+		.formats = FSL_SPDIF_FORMATS_PLAYBACK,
+	},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = FSL_SPDIF_RATES_CAPTURE,
+		.formats = FSL_SPDIF_FORMATS_CAPTURE,
+	},
+	.ops = &fsl_spdif_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_spdif_component = {
+	.name		= "fsl-spdif",
+};
+
+static int fsl_spdif_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(fsl_spdif_dt_ids, &pdev->dev);
+	struct fsl_spdif_priv *spdif_priv;
+	struct spdif_mixer_control *ctrl;
+	struct device_node *np = pdev->dev.of_node;
+	struct resource res;
+	const char *p;
+	u32 dma_events[2];
+	int ret = 0, i;
+
+	if (!of_device_is_available(np))
+		return -ENODEV;
+
+	/* The DAI name is the last part of the full name of the node. */
+	p = strrchr(np->full_name, '/') + 1;
+	spdif_priv = devm_kzalloc(&pdev->dev,
+			sizeof(struct fsl_spdif_priv) + strlen(p), GFP_KERNEL);
+	if (!spdif_priv) {
+		dev_err(&pdev->dev, "could not allocate DAI object\n");
+		return -ENOMEM;
+	}
+
+	strcpy(spdif_priv->name, p);
+
+	if (of_id)
+		pdev->id_entry = of_id->data;
+	spdif_devtype = pdev->id_entry->driver_data;
+
+	/* Initialize this copy of the CPU DAI driver structure */
+	memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
+	spdif_priv->cpu_dai_drv.name = spdif_priv->name;
+
+	/* Get the addresses and IRQ */
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret) {
+		dev_err(&pdev->dev, "could not determine device resources\n");
+		return ret;
+	}
+	spdif_priv->spdif = of_iomap(np, 0);
+	if (!spdif_priv->spdif) {
+		dev_err(&pdev->dev, "could not map device resources\n");
+		return ret;
+	}
+	spdif_priv->spdif_phys = res.start;
+
+	spdif_priv->irq = irq_of_parse_and_map(np, 0);
+	if (spdif_priv->irq == NO_IRQ) {
+		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+		ret = -ENXIO;
+		goto error_iomap;
+	}
+
+	/* The 'name' should not have any slashes in it. */
+	ret = devm_request_irq(&pdev->dev, spdif_priv->irq, spdif_isr, 0,
+			spdif_priv->name, spdif_priv);
+	if (ret) {
+		dev_err(&pdev->dev, "could not claim irq %u\n", spdif_priv->irq);
+		goto error_irqmap;
+	}
+
+	spdif_priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(spdif_priv->clk)) {
+		ret = PTR_ERR(spdif_priv->clk);
+		dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
+		goto error_irqmap;
+	}
+	clk_prepare(spdif_priv->clk);
+
+	ret = of_property_read_u8(pdev->dev.of_node,
+			"rx-clk-source", &spdif_priv->rxclk_src);
+	if (ret) {
+		dev_warn(&pdev->dev, "using default rx-clk-source\n");
+		spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC;
+	}
+
+	ret = of_property_read_u8_array(pdev->dev.of_node,
+			"tx-clk-source", spdif_priv->txclk_src, 3);
+	if (ret) {
+		dev_warn(&pdev->dev, "using default tx-clk-source\n");
+		for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+			spdif_priv->txclk_src[i] = DEFAULT_TXCLK_SRC;
+	}
+
+	ret = of_property_read_u8_array(pdev->dev.of_node,
+			"tx-clk-div", spdif_priv->txclk_div, 3);
+	if (ret) {
+		dev_warn(&pdev->dev, "using default tx-clk-div\n");
+		for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+			spdif_priv->txclk_div[i] = default_txclk_div[i];
+	}
+
+	ctrl = &spdif_priv->fsl_spdif_control;
+	/* initial spinlock for control data */
+	spin_lock_init(&ctrl->ctl_lock);
+
+	/* init tx channel status default value */
+	ctrl->ch_status[0] =
+		IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015;
+	ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID;
+	ctrl->ch_status[2] = 0x00;
+	ctrl->ch_status[3] =
+		IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM;
+
+	atomic_set(&spdif_priv->dpll_locked, 0);
+
+	spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML;
+	spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML;
+	spdif_priv->dma_params_tx.addr =
+			spdif_priv->spdif_phys + offsetof(struct reg_spdif, stl);
+	spdif_priv->dma_params_rx.addr =
+			spdif_priv->spdif_phys + offsetof(struct reg_spdif, srl);
+	spdif_priv->dma_params_tx.filter_data = &spdif_priv->filter_data_tx;
+	spdif_priv->dma_params_rx.filter_data = &spdif_priv->filter_data_rx;
+
+	ret = of_property_read_u32_array(pdev->dev.of_node,
+			"fsl,spdif-dma-events", dma_events, 2);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to get dma events\n");
+		goto error_clk;
+	}
+
+	imx_pcm_dma_params_init_data(&spdif_priv->filter_data_tx,
+			dma_events[0], IMX_DMATYPE_SPDIF);
+	imx_pcm_dma_params_init_data(&spdif_priv->filter_data_rx,
+			dma_events[1], IMX_DMATYPE_SPDIF);
+
+	/* Register with ASoC */
+	dev_set_drvdata(&pdev->dev, spdif_priv);
+
+	spdif_priv->pdev = pdev;
+
+	ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
+					 &spdif_priv->cpu_dai_drv, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+		goto error_dev;
+	}
+
+	ret = imx_pcm_dma_init(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
+		goto error_component;
+	}
+
+	return ret;
+
+error_component:
+	snd_soc_unregister_component(&pdev->dev);
+error_dev:
+	dev_set_drvdata(&pdev->dev, NULL);
+error_clk:
+	clk_unprepare(spdif_priv->clk);
+error_irqmap:
+	irq_dispose_mapping(spdif_priv->irq);
+error_iomap:
+	iounmap(spdif_priv->spdif);
+
+	return ret;
+}
+
+static int fsl_spdif_remove(struct platform_device *pdev)
+{
+	struct fsl_spdif_priv *spdif_priv = platform_get_drvdata(pdev);
+
+	imx_pcm_dma_exit(pdev);
+	snd_soc_unregister_component(&pdev->dev);
+
+	clk_unprepare(spdif_priv->clk);
+	irq_dispose_mapping(spdif_priv->irq);
+	iounmap(spdif_priv->spdif);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver fsl_spdif_driver = {
+	.driver = {
+		.name = "fsl-spdif-dai",
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_spdif_dt_ids,
+	},
+	.probe = fsl_spdif_probe,
+	.remove = fsl_spdif_remove,
+};
+
+module_platform_driver(fsl_spdif_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:fsl_spdif");
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
new file mode 100644
index 0000000..4ef9658
--- /dev/null
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -0,0 +1,233 @@
+/*
+ * fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <b42378@freescale.com>
+ *
+ * Based on fsl_ssi.h
+ * Author: Timur Tabi <timur@freescale.com>
+ * Copyright 2007-2008 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program  is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_SPDIF_DAI_H
+#define _FSL_SPDIF_DAI_H
+
+/* S/PDIF Register Map */
+struct reg_spdif {
+	__le32 scr;	/* 0x.0000 - SPDIF Configuration Register */
+	__le32 srcd;	/* 0x.0004 - CDText Control Register */
+	__le32 srpc;	/* 0x.0008 - PhaseConfig Register */
+	__le32 sie;	/* 0x.000C - InterruptEn Register */
+	__le32 sisc;	/* 0x.0010 - InterruptStat(R)/Clear(W) Register */
+	__le32 srl;	/* 0x.0014 - SPDIFRxLeft Register */
+	__le32 srr;	/* 0x.0018 - SPDIFRxRight Register */
+	__le32 srcsch;	/* 0x.001C - SPDIFRxCChannel_h Register */
+	__le32 srcscl;	/* 0x.0020 - SPDIFRxCChannel_l Register */
+	__le32 sru;	/* 0x.0024 - UchannelRx Register */
+	__le32 srq;	/* 0x.0028 - QchannelRx Register */
+	__le32 stl;	/* 0x.002C - SPDIFTxLeft Register */
+	__le32 str;	/* 0x.0030 - SPDIFTxRight Register */
+	__le32 stcsch;	/* 0x.0034 - SPDIFTxCChannelCons_h Register */
+	__le32 stcscl;	/* 0x.0038 - SPDIFTxCChannelCons_l Register */
+	__le32 null1;	/* 0x.003C - N/A */
+	__le32 null2;	/* 0x.0040 - N/A */
+	__le32 srfm;	/* 0x.0044 - FreqMeas Register */
+	__le32 null3;	/* 0x.0048 - N/A */
+	__le32 null4;	/* 0x.004C - N/A */
+	__le32 stc;	/* 0x.0050 - SPDIFTxClk Register */
+};
+
+/* SPDIF Configuration register */
+#define SCR_RXFIFO_CTL_OFFSET		23
+#define SCR_RXFIFO_CTL_MASK		(1 << SCR_RXFIFO_CTL_OFFSET)
+#define SCR_RXFIFO_CTL_ZERO		(1 << SCR_RXFIFO_CTL_OFFSET)
+#define SCR_RXFIFO_OFF_OFFSET		22
+#define SCR_RXFIFO_OFF_MASK		(1 << SCR_RXFIFO_OFF_OFFSET)
+#define SCR_RXFIFO_OFF			(1 << SCR_RXFIFO_OFF_OFFSET)
+#define SCR_RXFIFO_RST_OFFSET		21
+#define SCR_RXFIFO_RST_MASK		(1 << SCR_RXFIFO_RST_OFFSET)
+#define SCR_RXFIFO_RST			(1 << SCR_RXFIFO_RST_OFFSET)
+#define SCR_RXFIFO_FSEL_OFFSET		19
+#define SCR_RXFIFO_FSEL_MASK		(0x3 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF0		(0x0 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF4		(0x1 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF8		(0x2 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF12		(0x3 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_AUTOSYNC_OFFSET	18
+#define SCR_RXFIFO_AUTOSYNC_MASK	(1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
+#define SCR_RXFIFO_AUTOSYNC		(1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_AUTOSYNC_OFFSET	17
+#define SCR_TXFIFO_AUTOSYNC_MASK	(1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_AUTOSYNC		(1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_FSEL_OFFSET		15
+#define SCR_TXFIFO_FSEL_MASK		(0x3 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF0		(0x0 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF4		(0x1 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF8		(0x2 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF12		(0x3 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_LOW_POWER			(1 << 13)
+#define SCR_SOFT_RESET			(1 << 12)
+#define SCR_TXFIFO_CTRL_OFFSET		10
+#define SCR_TXFIFO_CTRL_MASK		(0x3 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_ZERO		(0x0 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_NORMAL		(0x1 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_ONESAMPLE	(0x2 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_DMA_RX_EN_OFFSET		9
+#define SCR_DMA_RX_EN_MASK		(1 << SCR_DMA_RX_EN_OFFSET)
+#define SCR_DMA_RX_EN			(1 << SCR_DMA_RX_EN_OFFSET)
+#define SCR_DMA_TX_EN_OFFSET		8
+#define SCR_DMA_TX_EN_MASK		(1 << SCR_DMA_TX_EN_OFFSET)
+#define SCR_DMA_TX_EN			(1 << SCR_DMA_TX_EN_OFFSET)
+#define SCR_VAL_OFFSET			5
+#define SCR_VAL_MASK			(1 << SCR_VAL_OFFSET)
+#define SCR_VAL_CLEAR			(1 << SCR_VAL_OFFSET)
+#define SCR_TXSEL_OFFSET		2
+#define SCR_TXSEL_MASK			(0x7 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_OFF			(0 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_RX			(1 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_NORMAL		(0x5 << SCR_TXSEL_OFFSET)
+#define SCR_USRC_SEL_OFFSET		0x0
+#define SCR_USRC_SEL_MASK		(0x3 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_NONE		(0x0 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_RECV		(0x1 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_CHIP		(0x3 << SCR_USRC_SEL_OFFSET)
+
+/* SPDIF CDText control */
+#define SRCD_CD_USER_OFFSET		1
+#define SRCD_CD_USER			(1 << SRCD_CD_USER_OFFSET)
+
+/* SPDIF Phase Configuration register */
+#define SRPC_DPLL_LOCKED		(1 << 6)
+#define SRPC_CLKSRC_SEL_OFFSET		7
+#define SRPC_CLKSRC_SEL_MASK		(0xf << SRPC_CLKSRC_SEL_OFFSET)
+#define SRPC_CLKSRC_SEL_SET(x)		((x << SRPC_CLKSRC_SEL_OFFSET) & SRPC_CLKSRC_SEL_MASK)
+#define SRPC_CLKSRC_SEL_LOCKED		5
+#define SRPC_GAINSEL_OFFSET		3
+#define SRPC_GAINSEL_MASK		(0x7 << SRPC_GAINSEL_OFFSET)
+#define SRPC_GAINSEL_SET(x)		((x << SRPC_GAINSEL_OFFSET) & SRPC_GAINSEL_MASK)
+
+/* SPDIF rx clock source */
+enum spdif_rxclk_src {
+	SRPC_CLKSRC_0 = 0,
+	SRPC_CLKSRC_1,
+	SRPC_CLKSRC_2,
+	SRPC_CLKSRC_3,
+	SRPC_CLKSRC_4,
+	SRPC_CLKSRC_5,
+	SRPC_CLKSRC_6,
+	SRPC_CLKSRC_7,
+	SRPC_CLKSRC_8,
+	SRPC_CLKSRC_9,
+	SRPC_CLKSRC_10,
+	SRPC_CLKSRC_11,
+	SRPC_CLKSRC_12,
+	SRPC_CLKSRC_13,
+	SRPC_CLKSRC_14,
+	SRPC_CLKSRC_15,
+};
+#define SRPC_CLKSRC_MAX			(SRPC_CLKSRC_15 + 1)
+#define DEFAULT_RXCLK_SRC		SRPC_CLKSRC_0
+
+enum spdif_gainsel {
+	GAINSEL_MULTI_24 = 0,
+	GAINSEL_MULTI_16,
+	GAINSEL_MULTI_12,
+	GAINSEL_MULTI_8,
+	GAINSEL_MULTI_6,
+	GAINSEL_MULTI_4,
+	GAINSEL_MULTI_3,
+};
+#define GAINSEL_MULTI_MAX		(GAINSEL_MULTI_3 + 1)
+#define SPDIF_DEFAULT_GAINSEL		GAINSEL_MULTI_8
+
+/* SPDIF interrupt mask define */
+#define INT_DPLL_LOCKED			(1 << 20)
+#define INT_TXFIFO_UNOV			(1 << 19)
+#define INT_TXFIFO_RESYNC		(1 << 18)
+#define INT_CNEW			(1 << 17)
+#define INT_VAL_NOGOOD			(1 << 16)
+#define INT_SYM_ERR			(1 << 15)
+#define INT_BIT_ERR			(1 << 14)
+#define INT_URX_FUL			(1 << 10)
+#define INT_URX_OV			(1 << 9)
+#define INT_QRX_FUL			(1 << 8)
+#define INT_QRX_OV			(1 << 7)
+#define INT_UQ_SYNC			(1 << 6)
+#define INT_UQ_ERR			(1 << 5)
+#define INT_RXFIFO_UNOV			(1 << 4)
+#define INT_RXFIFO_RESYNC		(1 << 3)
+#define INT_LOSS_LOCK			(1 << 2)
+#define INT_TX_EM			(1 << 1)
+#define INT_RXFIFO_FUL			(1 << 0)
+
+/* SPDIF Clock register */
+#define STC_SYSCLK_DIV_OFFSET		11
+#define STC_SYSCLK_DIV_MASK		(0x1ff << STC_TXCLK_SRC_OFFSET)
+#define STC_SYSCLK_DIV(x)		((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK)
+#define STC_TXCLK_SRC_OFFSET		8
+#define STC_TXCLK_SRC_MASK		(0x7 << STC_TXCLK_SRC_OFFSET)
+#define STC_TXCLK_SRC_SET(x)		((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK)
+#define STC_TXCLK_ALL_EN_OFFSET		7
+#define STC_TXCLK_ALL_EN_MASK		(1 << STC_TXCLK_ALL_EN_OFFSET)
+#define STC_TXCLK_ALL_EN		(1 << STC_TXCLK_ALL_EN_OFFSET)
+#define STC_TXCLK_DIV_OFFSET		0
+#define STC_TXCLK_DIV_MASK		(0x7ff << STC_TXCLK_DIV_OFFSET)
+#define STC_TXCLK_DIV(x)		((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK)
+
+/* SPDIF tx clksrc */
+enum spdif_txclk_src {
+	STC_TXCLK_SRC_0 = 0,
+	STC_TXCLK_SRC_1,
+	STC_TXCLK_SRC_2,
+	STC_TXCLK_SRC_3,
+	STC_TXCLK_SRC_4,
+	STC_TXCLK_SRC_5,
+	STC_TXCLK_SRC_6,
+	STC_TXCLK_SRC_7,
+};
+#define STC_TXCLK_SRC_MAX		(STC_TXCLK_SRC_7 + 1)
+#define DEFAULT_TXCLK_SRC		STC_TXCLK_SRC_1
+
+/* SPDIF tx rate */
+enum spdif_txrate {
+	SPDIF_TXRATE_32000 = 0,
+	SPDIF_TXRATE_44100,
+	SPDIF_TXRATE_48000,
+};
+#define SPDIF_TXRATE_MAX		(SPDIF_TXRATE_48000 + 1)
+
+static u8 default_txclk_div[SPDIF_TXRATE_MAX] = {
+	37,		/* Tx clk div for 32000 */
+	23,		/* Tx clk div for 44100 */
+	37,		/* Tx clk div for 48000 */
+};
+
+
+#define SPDIF_CSTATUS_BYTE		6
+#define SPDIF_UBITS_SIZE		96
+#define SPDIF_QSUB_SIZE			(SPDIF_UBITS_SIZE / 8)
+
+
+#define FSL_SPDIF_RATES_PLAYBACK	(SNDRV_PCM_RATE_32000 |	\
+					 SNDRV_PCM_RATE_44100 |	\
+					 SNDRV_PCM_RATE_48000)
+
+#define FSL_SPDIF_RATES_CAPTURE		(SNDRV_PCM_RATE_16000 | \
+					 SNDRV_PCM_RATE_32000 |	\
+					 SNDRV_PCM_RATE_44100 | \
+					 SNDRV_PCM_RATE_48000 |	\
+					 SNDRV_PCM_RATE_64000 | \
+					 SNDRV_PCM_RATE_96000)
+
+#define FSL_SPDIF_FORMATS_PLAYBACK	(SNDRV_PCM_FMTBIT_S16_LE | \
+					 SNDRV_PCM_FMTBIT_S20_3LE | \
+					 SNDRV_PCM_FMTBIT_S24_LE)
+
+#define FSL_SPDIF_FORMATS_CAPTURE	(SNDRV_PCM_FMTBIT_S24_LE)
+
+#endif /* _FSL_SPDIF_DAI_H */
-- 
1.7.1

^ permalink raw reply related

* [PATCH 3/3] ASoC: fsl: Add S/PDIF machine driver
From: Nicolin Chen @ 2013-07-31 12:07 UTC (permalink / raw)
  To: broonie, timur; +Cc: alsa-devel, linuxppc-dev, devicetree-discuss, rob.herring
In-Reply-To: <cover.1375271745.git.b42378@freescale.com>

Add S/PDIF machine driver for Freescale i.MX series SoC.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 .../devicetree/bindings/sound/imx-audio-spdif.txt  |   29 +++++
 sound/soc/fsl/Kconfig                              |   11 ++
 sound/soc/fsl/Makefile                             |    2 +
 sound/soc/fsl/imx-spdif.c                          |  134 ++++++++++++++++++++
 4 files changed, 176 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
 create mode 100644 sound/soc/fsl/imx-spdif.c

diff --git a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
new file mode 100644
index 0000000..9a3fa26
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
@@ -0,0 +1,29 @@
+Freescale i.MX audio complex with S/PDIF transceiver
+
+Required properties:
+
+  - compatible : "fsl,imx-audio-spdif"
+
+  - model : The user-visible name of this sound complex
+
+  - spdif-controller : The phandle of the i.MX S/PDIF controller
+
+
+Optional properties:
+
+  - spdif-transmitter : The phandle of the spdif-transmitter dummy codec
+
+  - spdif-receiver : The phandle of the spdif-receiver dummy codec
+
+* Note: At least one of these two properties should be set in the DT binding.
+
+
+Example:
+
+sound-spdif {
+	compatible = "fsl,imx-audio-spdif";
+	model = "imx-spdif";
+	spdif-controller = <&spdif>;
+	spdif-transmitter = <&spdif_tx_codec>;
+	spdif-receiver = <&spdif_rx_codec>;
+};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 156b794..ba0c7ff 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -195,6 +195,17 @@ config SND_SOC_IMX_SGTL5000
 	  Say Y if you want to add support for SoC audio on an i.MX board with
 	  a sgtl5000 codec.
 
+config SND_SOC_IMX_SPDIF
+	tristate "SoC Audio support for i.MX boards with S/PDIF"
+	select SND_SOC_IMX_PCM_DMA
+	select SND_SOC_FSL_SPDIF
+	select SND_SOC_FSL_UTILS
+	select SND_SOC_SPDIF
+	help
+	  SoC Audio support for i.MX boards with S/PDIF
+	  Say Y if you want to add support for SoC audio on an i.MX board with
+	  a S/DPDIF.
+
 config SND_SOC_IMX_MC13783
 	tristate "SoC Audio support for I.MX boards with mc13783"
 	depends on MFD_MC13783 && ARCH_ARM
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 4b5970e..e2aaff7 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -45,6 +45,7 @@ snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
 snd-soc-wm1133-ev1-objs := wm1133-ev1.o
 snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
 snd-soc-imx-wm8962-objs := imx-wm8962.o
+snd-soc-imx-spdif-objs :=imx-spdif.o
 snd-soc-imx-mc13783-objs := imx-mc13783.o
 
 obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
@@ -53,4 +54,5 @@ obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
 obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
 obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
 obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
+obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
 obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
new file mode 100644
index 0000000..893f3d1
--- /dev/null
+++ b/sound/soc/fsl/imx-spdif.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+
+struct imx_spdif_data {
+	struct snd_soc_dai_link dai[2];
+	struct snd_soc_card card;
+};
+
+static int imx_spdif_audio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *spdif_np, *codec_tx_np, *codec_rx_np;
+	struct platform_device *spdif_pdev;
+	struct imx_spdif_data *data;
+	int ret = 0, num_links = 0;
+
+	spdif_np = of_parse_phandle(np, "spdif-controller", 0);
+	if (!spdif_np) {
+		dev_err(&pdev->dev, "failed to find spdif-controller\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	spdif_pdev = of_find_device_by_node(spdif_np);
+	if (!spdif_pdev) {
+		dev_err(&pdev->dev, "failed to find S/PDIF device\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	codec_tx_np = of_parse_phandle(np, "spdif-transmitter", 0);
+	if (codec_tx_np) {
+		data->dai[num_links].name = "S/PDIF TX";
+		data->dai[num_links].stream_name = "S/PDIF PCM Playback";
+		data->dai[num_links].codec_dai_name = "dit-hifi";
+		data->dai[num_links].codec_of_node = codec_tx_np;
+		data->dai[num_links].cpu_of_node = spdif_np;
+		data->dai[num_links].platform_of_node = spdif_np;
+		num_links++;
+	}
+
+	codec_rx_np = of_parse_phandle(np, "spdif-receiver", 0);
+	if (codec_rx_np) {
+		data->dai[num_links].name = "S/PDIF RX";
+		data->dai[num_links].stream_name = "S/PDIF PCM Capture";
+		data->dai[num_links].codec_dai_name = "dir-hifi";
+		data->dai[num_links].codec_of_node = codec_rx_np;
+		data->dai[num_links].cpu_of_node = spdif_np;
+		data->dai[num_links].platform_of_node = spdif_np;
+		num_links++;
+	}
+
+	if (!num_links) {
+		dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
+		goto fail;
+	}
+
+	data->card.dev = &pdev->dev;
+	data->card.num_links = num_links;
+	data->card.dai_link = data->dai;
+
+	ret = snd_soc_of_parse_card_name(&data->card, "model");
+	if (ret)
+		goto fail;
+
+	ret = snd_soc_register_card(&data->card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+		goto fail;
+	}
+
+	platform_set_drvdata(pdev, data);
+
+fail:
+	if (codec_tx_np)
+		of_node_put(codec_tx_np);
+	if (codec_rx_np)
+		of_node_put(codec_rx_np);
+	if (spdif_np)
+		of_node_put(spdif_np);
+
+	return ret;
+}
+
+static int imx_spdif_audio_remove(struct platform_device *pdev)
+{
+	struct imx_spdif_data *data = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(&data->card);
+
+	return 0;
+}
+
+static const struct of_device_id imx_spdif_dt_ids[] = {
+	{ .compatible = "fsl,imx-audio-spdif", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
+
+static struct platform_driver imx_spdif_driver = {
+	.driver = {
+		.name = "imx-spdif",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_spdif_dt_ids,
+	},
+	.probe = imx_spdif_audio_probe,
+	.remove = imx_spdif_audio_remove,
+};
+
+module_platform_driver(imx_spdif_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-spdif");
-- 
1.7.1

^ permalink raw reply related

* [PATCH 1/3] ASoC: codec: spdif: Add S20_3LE and S24_LE support for dummy codec drivers
From: Nicolin Chen @ 2013-07-31 12:07 UTC (permalink / raw)
  To: broonie, timur; +Cc: alsa-devel, linuxppc-dev, devicetree-discuss, rob.herring
In-Reply-To: <cover.1375271745.git.b42378@freescale.com>

Generally, S/PDIF supports 20bit and optional 24bit samples. Thus add these
two formats for the dummy codec drivers.

If one S/PDIF controller has its own limitation, its CPU DAI driver should
set the supported format by its own circumstance, since the soc-pcm driver
will use the intersection of cpu_dai's formats and codec_dai's formats.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 sound/soc/codecs/spdif_receiver.c    |    2 ++
 sound/soc/codecs/spdif_transmitter.c |    5 +++--
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c
index e9d7881..26d3474 100644
--- a/sound/soc/codecs/spdif_receiver.c
+++ b/sound/soc/codecs/spdif_receiver.c
@@ -25,6 +25,8 @@
 
 #define STUB_RATES	SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE | \
 			SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
 static struct snd_soc_codec_driver soc_codec_spdif_dir;
diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c
index 1828049..efc3d88 100644
--- a/sound/soc/codecs/spdif_transmitter.c
+++ b/sound/soc/codecs/spdif_transmitter.c
@@ -25,8 +25,9 @@
 #define DRV_NAME "spdif-dit"
 
 #define STUB_RATES	SNDRV_PCM_RATE_8000_96000
-#define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
-
+#define STUB_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
+			SNDRV_PCM_FMTBIT_S20_3LE | \
+			SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_codec_driver soc_codec_spdif_dit;
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH 0/3] ASoC: Add Freescale i.MX S/PDIF controller driver
From: Nicolin Chen @ 2013-07-31 12:07 UTC (permalink / raw)
  To: broonie, timur; +Cc: alsa-devel, linuxppc-dev, devicetree-discuss, rob.herring

* This series of patches add i.MX S/PDIF drivers, including CPU DAI, machine.
* It also add two missing sample rates support for spdif dummy codec drivers

Nicolin Chen (3):
  ASoC: codec: spdif: Add S20_3LE and S24_LE support for dummy codec
    drivers
  ASoC: fsl: Add S/PDIF CPU DAI driver
  ASoC: fsl: Add S/PDIF machine driver

 .../devicetree/bindings/sound/fsl,spdif.txt        |   63 +
 .../devicetree/bindings/sound/imx-audio-spdif.txt  |   29 +
 sound/soc/codecs/spdif_receiver.c                  |    2 +
 sound/soc/codecs/spdif_transmitter.c               |    5 +-
 sound/soc/fsl/Kconfig                              |   14 +
 sound/soc/fsl/Makefile                             |    4 +
 sound/soc/fsl/fsl_spdif.c                          | 1276 ++++++++++++++++++++
 sound/soc/fsl/fsl_spdif.h                          |  233 ++++
 sound/soc/fsl/imx-spdif.c                          |  134 ++
 9 files changed, 1758 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/fsl,spdif.txt
 create mode 100644 Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
 create mode 100644 sound/soc/fsl/fsl_spdif.c
 create mode 100644 sound/soc/fsl/fsl_spdif.h
 create mode 100644 sound/soc/fsl/imx-spdif.c

^ permalink raw reply

* mm/slab: ppc: ubi: kmalloc_slab WARNING / PPC + UBI driver
From: Wladislav Wiebe @ 2013-07-31 11:42 UTC (permalink / raw)
  To: penberg, cl, linux-mm, linuxppc-dev, dedekind1, dwmw2, linux-mtd

Hello guys,

on a PPC 32-Bit board with a Linux Kernel v3.10.0 I see trouble with kmalloc_slab.
Basically at system startup, something request a size of 8388608 b,
but KMALLOC_MAX_SIZE has 4194304 b in our case. It points a WARNING at:
..
NIP [c0099fec] kmalloc_slab+0x60/0xe8
LR [c0099fd4] kmalloc_slab+0x48/0xe8
Call Trace:
[ccd3be60] [c0099fd4] kmalloc_slab+0x48/0xe8 (unreliable)
[ccd3be70] [c00ae650] __kmalloc+0x20/0x1b4
[ccd3be90] [c00d46f4] seq_read+0x2a4/0x540
[ccd3bee0] [c00fe09c] proc_reg_read+0x5c/0x90
[ccd3bef0] [c00b4e1c] vfs_read+0xa4/0x150
[ccd3bf10] [c00b500c] SyS_read+0x4c/0x84
[ccd3bf40] [c000be80] ret_from_syscall+0x0/0x3c
..

Do you have any idea how I can analyze where these 8388608 b coming from?
Kernel log show that UBI driver tries to do something, but I am unsure where it is in detail.

I enabled in the kernel config additionally this parts
- Debug slab memory allocations
- Verbose BUG() reporting (adds 70K)
- Debug VM
- Debug memory initialisation
- Debug page memory allocations

log snip:
...
UBI: attaching mtd0 to ubi0
UBI: scanning is finished
UBI: attached mtd0 (name "fs", size 47 MiB) to ubi0
UBI: PEB size: 131072 bytes (128 KiB), LEB size: 130944 bytes
UBI: min./max. I/O unit sizes: 1/8, sub-page size 1
UBI: VID header offset: 64 (aligned 64), data offset: 128
UBI: good PEBs: 376, bad PEBs: 0, corrupted PEBs: 0
UBI: user volume: 1, internal volumes: 1, max. volumes count: 128
UBI: max/mean erase counter: 8/5, WL threshold: 4096, image sequence number: 657495904
UBI: available PEBs: 0, total reserved PEBs: 376, PEBs reserved for bad PEB handling: 0
UBI: background thread "ubi_bgt0d" started, PID 892
DEBUG: xxx kmalloc_slab, requested 'size' = 8388608, KMALLOC_MAX_SIZE = 4194304
------------[ cut here ]------------
WARNING: at /var/fpwork/wiebe/newfsm/bld/bld-kernelsources-linux/results/linux/mm/slab_common.c:383
Modules linked in: ubi mddg_post(O) mddg_rpram(O) mddg_system_driver(O) mddg_watchdog(O)
CPU: 0 PID: 900 Comm: hexdump Tainted: G           O 3.10.0-0-sampleversion-fcmd #40
task: cf3e7280 ti: ccd3a000 task.ti: ccd3a000
NIP: c0099fec LR: c0099fd4 CTR: c018b0dc
REGS: ccd3bdb0 TRAP: 0700   Tainted: G           O  (3.10.0-0-sampleversion-fcmd)
MSR: 00029000 <CE,EE,ME>  CR: 22000442  XER: 20000000

GPR00: c0099fd4 ccd3be60 cf3e7280 00000000 d100e501 00000005 00000000 c0372ac0
GPR08: 00000004 00000001 00000000 ccd3be20 22000444 100a24dc 00000000 00000000
GPR16: 10076b54 00000000 fffff000 00000000 ccd3bea0 00000000 00000001 00000400
GPR24: 00000000 00000000 4801c000 c00d46f4 ccd3bf18 000000d0 00800000 000000d0
NIP [c0099fec] kmalloc_slab+0x60/0xe8
LR [c0099fd4] kmalloc_slab+0x48/0xe8
Call Trace:
[ccd3be60] [c0099fd4] kmalloc_slab+0x48/0xe8 (unreliable)
[ccd3be70] [c00ae650] __kmalloc+0x20/0x1b4
[ccd3be90] [c00d46f4] seq_read+0x2a4/0x540
[ccd3bee0] [c00fe09c] proc_reg_read+0x5c/0x90
[ccd3bef0] [c00b4e1c] vfs_read+0xa4/0x150
[ccd3bf10] [c00b500c] SyS_read+0x4c/0x84
[ccd3bf40] [c000be80] ret_from_syscall+0x0/0x3c
--- Exception: c01 at 0xfe63934
    LR = 0xfe1a6a8
Instruction dump:
3884dff0 3863e98c 38840094 3cc00040 4cc63182 481e9fc1 73e90200 38600000
40a20090 3d20c038 89291e69 69290001 <0f090000> 2f890000 41be0078 3d20c038
---[ end trace afdc4720a42f3f3c ]---
UBIFS: recovery needed
UBIFS: recovery deferred
UBIFS: mounted UBI device 0, volume 0, name "flash", R/O mode
UBIFS: LEB size: 130944 bytes (127 KiB), min./max. I/O unit sizes: 8 bytes/8 bytes
UBIFS: FS size: 47532672 bytes (45 MiB, 363 LEBs), journal size 2356992 bytes (2 MiB, 18 LEBs)
UBIFS: reserved for root: 0 bytes (0 KiB)
UBIFS: media format: w4/r0 (latest is w4/r0), UUID 7570E817-F0E4-4BF4-8AB5-552B4C55AF30, small LPT model
UBIFS: completing deferred recovery
UBIFS: background thread "ubifs_bgt0_0" started, PID 962
UBIFS: deferred recovery completed
..


Thanks & BR
Wladislav Wiebe

^ permalink raw reply

* [PATCH v3] powerpc/85xx: Add P1023RDB board support
From: Chunhe Lan @ 2013-07-30 21:39 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Chunhe Lan

P1023RDB Specification:
-----------------------
Memory subsystem:
   512MB DDR3 (Fixed DDR on board)
   64MB NOR flash
   128MB NAND flash

Ethernet:
   eTSEC1: Connected to Atheros AR8035 GETH PHY
   eTSEC2: Connected to Atheros AR8035 GETH PHY

PCIe:
   Three mini-PCIe slots

USB:
   Two USB2.0 Type A ports

I2C:
   AT24C08 8K Board EEPROM (8 bit address)

Signed-off-by: Chunhe Lan <Chunhe.Lan@freescale.com>
Cc: Scott Wood <scottwood@freescale.com>
---
Changes for v2:
	- Add the NAND flash node in the device tree
	- Rename defconfig from p1023rds_defconfig to p1023_defconfig
	- Delete a new p1023rdb Kconfig option
Changes for v3:
	- Add changes information for revision
	- Delete the a needless NAND partition from the device tree
	- Modify the name and description in the Kconfig file

 arch/powerpc/boot/dts/p1023rdb.dts                 |  234 ++++++++++++++++++++
 .../85xx/{p1023rds_defconfig => p1023_defconfig}   |   24 ++-
 arch/powerpc/platforms/85xx/Kconfig                |    4 +-
 arch/powerpc/platforms/85xx/p1023_rds.c            |   24 ++-
 4 files changed, 280 insertions(+), 6 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/p1023rdb.dts
 rename arch/powerpc/configs/85xx/{p1023rds_defconfig => p1023_defconfig} (88%)

diff --git a/arch/powerpc/boot/dts/p1023rdb.dts b/arch/powerpc/boot/dts/p1023rdb.dts
new file mode 100644
index 0000000..0a06a88
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1023rdb.dts
@@ -0,0 +1,234 @@
+/*
+ * P1023 RDB Device Tree Source
+ *
+ *    Copyright 2013 Freescale Semiconductor Inc.
+ *
+ * Author: Chunhe Lan <Chunhe.Lan@freescale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1023si-pre.dtsi"
+
+/ {
+	model = "fsl,P1023";
+	compatible = "fsl,P1023RDB";
+	#address-cells = <2>;
+	#size-cells = <2>;
+	interrupt-parent = <&mpic>;
+
+	memory {
+		device_type = "memory";
+	};
+
+	soc: soc@ff600000 {
+		ranges = <0x0 0x0 0xff600000 0x200000>;
+
+		i2c@3000 {
+			eeprom@53 {
+				compatible = "at24,24c04";
+				reg = <0x53>;
+			};
+
+			rtc@6f {
+				compatible = "microchip,mcp7941x";
+				reg = <0x6f>;
+			};
+		};
+
+		usb@22000 {
+			dr_mode = "host";
+			phy_type = "ulpi";
+		};
+	};
+
+	lbc: localbus@ff605000 {
+		reg = <0 0xff605000 0 0x1000>;
+
+		/* NOR, NAND Flashes */
+		ranges = <0x0 0x0 0x0 0xec000000 0x04000000
+			  0x1 0x0 0x0 0xffa00000 0x08000000>;
+
+		nor@0,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "cfi-flash";
+			reg = <0x0 0x0 0x04000000>;
+			bank-width = <2>;
+			device-width = <1>;
+
+			partition@0 {
+				/* 48MB for Root File System */
+				reg = <0x00000000 0x03000000>;
+				label = "NOR Root File System";
+			};
+
+			partition@3000000 {
+				/* 1MB for DTB Image */
+				reg = <0x03000000 0x00100000>;
+				label = "NOR DTB Image";
+			};
+
+			partition@3100000 {
+				/* 14MB for Linux Kernel Image */
+				reg = <0x03100000 0x00e00000>;
+				label = "NOR Linux Kernel Image";
+			};
+
+			partition@3f00000 {
+				/* This location must not be altered  */
+				/* 512KB for u-boot Bootloader Image */
+				/* 512KB for u-boot Environment Variables */
+				reg = <0x03f00000 0x00100000>;
+				label = "NOR U-Boot Image";
+				read-only;
+			};
+		};
+
+		nand@1,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "fsl,elbc-fcm-nand";
+			reg = <0x1 0x0 0x40000>;
+
+			partition@0 {
+				/* This location must not be altered  */
+				/* 1MB for u-boot Bootloader Image */
+				reg = <0x0 0x00100000>;
+				label = "NAND U-Boot Image";
+				read-only;
+			};
+
+			partition@100000 {
+				/* 1MB for DTB Image */
+				reg = <0x00100000 0x00100000>;
+				label = "NAND DTB Image";
+			};
+
+			partition@200000 {
+				/* 14MB for Linux Kernel Image */
+				reg = <0x00200000 0x00e00000>;
+				label = "NAND Linux Kernel Image";
+			};
+
+			partition@1000000 {
+				/* 96MB for Root File System Image */
+				reg = <0x01000000 0x06000000>;
+				label = "NAND Root File System";
+			};
+
+			partition@7000000 {
+				/* 16MB for User Writable Area */
+				reg = <0x07000000 0x01000000>;
+				label = "NAND Writable User area";
+			};
+		};
+	};
+
+	pci0: pcie@ff60a000 {
+		reg = <0 0xff60a000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+		pcie@0 {
+			/* IRQ[0:3] are pulled up on board, set to active-low */
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 0 1 0 0
+				0000 0 0 2 &mpic 1 1 0 0
+				0000 0 0 3 &mpic 2 1 0 0
+				0000 0 0 4 &mpic 3 1 0 0
+				>;
+			ranges = <0x2000000 0x0 0xc0000000
+				  0x2000000 0x0 0xc0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	board_pci1: pci1: pcie@ff609000 {
+		reg = <0 0xff609000 0 0x1000>;
+		ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+		pcie@0 {
+			/*
+			 * IRQ[4:6] only for PCIe, set to active-high,
+			 * IRQ[7] is pulled up on board, set to active-low
+			 */
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 4 2 0 0
+				0000 0 0 2 &mpic 5 2 0 0
+				0000 0 0 3 &mpic 6 2 0 0
+				0000 0 0 4 &mpic 7 1 0 0
+				>;
+			ranges = <0x2000000 0x0 0xa0000000
+				  0x2000000 0x0 0xa0000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+	pci2: pcie@ff60b000 {
+		reg = <0 0xff60b000 0 0x1000>;
+		ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+			  0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+		pcie@0 {
+			/*
+			 * IRQ[8:10] are pulled up on board, set to active-low
+			 * IRQ[11] only for PCIe, set to active-high,
+			 */
+			interrupt-map-mask = <0xf800 0 0 7>;
+			interrupt-map = <
+				/* IDSEL 0x0 */
+				0000 0 0 1 &mpic 8 1 0 0
+				0000 0 0 2 &mpic 9 1 0 0
+				0000 0 0 3 &mpic 10 1 0 0
+				0000 0 0 4 &mpic 11 2 0 0
+				>;
+			ranges = <0x2000000 0x0 0x80000000
+				  0x2000000 0x0 0x80000000
+				  0x0 0x20000000
+
+				  0x1000000 0x0 0x0
+				  0x1000000 0x0 0x0
+				  0x0 0x100000>;
+		};
+	};
+
+};
+
+/include/ "fsl/p1023si-post.dtsi"
diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023_defconfig
similarity index 88%
rename from arch/powerpc/configs/85xx/p1023rds_defconfig
rename to arch/powerpc/configs/85xx/p1023_defconfig
index b80bcc6..912ad28 100644
--- a/arch/powerpc/configs/85xx/p1023rds_defconfig
+++ b/arch/powerpc/configs/85xx/p1023_defconfig
@@ -1,14 +1,13 @@
 CONFIG_PPC_85xx=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_AUDIT=y
-CONFIG_IRQ_DOMAIN_DEBUG=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
+CONFIG_RCU_FANOUT=32
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
@@ -22,6 +21,8 @@ CONFIG_MODVERSIONS=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_MAC_PARTITION=y
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_P1023_RDB=y
 CONFIG_P1023_RDS=y
 CONFIG_QUICC_ENGINE=y
 CONFIG_QE_GPIO=y
@@ -63,10 +64,20 @@ CONFIG_IPV6=y
 CONFIG_IP_SCTP=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_FSL_ELBC=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_LEGACY=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
@@ -82,6 +93,8 @@ CONFIG_DUMMY=y
 CONFIG_FS_ENET=y
 CONFIG_FSL_PQ_MDIO=y
 CONFIG_E1000E=y
+CONFIG_PHYLIB=y
+CONFIG_AT803X_PHY=y
 CONFIG_MARVELL_PHY=y
 CONFIG_DAVICOM_PHY=y
 CONFIG_CICADA_PHY=y
@@ -96,12 +109,15 @@ CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_NR_UARTS=2
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_DETECT_IRQ=y
 CONFIG_SERIAL_8250_RSA=y
-CONFIG_SERIAL_QE=m
+CONFIG_HW_RANDOM=y
 CONFIG_NVRAM=y
 CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 CONFIG_GPIO_MPC8XXX=y
@@ -121,6 +137,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
 CONFIG_RTC_DRV_CMOS=y
 CONFIG_DMADEVICES=y
 CONFIG_FSL_DMA=y
@@ -161,6 +178,7 @@ CONFIG_DEBUG_FS=y
 CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_INFO=y
+CONFIG_STRICT_DEVMEM=y
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_SHA512=y
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index efdd37c..b8f0d32 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -112,10 +112,10 @@ config P1022_RDK
 	  reference board.
 
 config P1023_RDS
-	bool "Freescale P1023 RDS"
+	bool "Freescale P1023 RDS/RDB"
 	select DEFAULT_UIMAGE
 	help
-	  This option enables support for the P1023 RDS board
+	  This option enables support for the P1023 RDS and RDB boards
 
 config SOCRATES
 	bool "Socrates"
diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c
index 9cc60a7..2ae9d49 100644
--- a/arch/powerpc/platforms/85xx/p1023_rds.c
+++ b/arch/powerpc/platforms/85xx/p1023_rds.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright 2010-2011, 2013 Freescale Semiconductor, Inc.
  *
  * Author: Roy Zang <tie-fei.zang@freescale.com>
  *
@@ -86,6 +86,7 @@ static void __init mpc85xx_rds_setup_arch(void)
 }
 
 machine_arch_initcall(p1023_rds, mpc85xx_common_publish_devices);
+machine_arch_initcall(p1023_rdb, mpc85xx_common_publish_devices);
 
 static void __init mpc85xx_rds_pic_init(void)
 {
@@ -106,6 +107,14 @@ static int __init p1023_rds_probe(void)
 
 }
 
+static int __init p1023_rdb_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P1023RDB");
+
+}
+
 define_machine(p1023_rds) {
 	.name			= "P1023 RDS",
 	.probe			= p1023_rds_probe,
@@ -120,3 +129,16 @@ define_machine(p1023_rds) {
 #endif
 };
 
+define_machine(p1023_rdb) {
+	.name			= "P1023 RDB",
+	.probe			= p1023_rdb_probe,
+	.setup_arch		= mpc85xx_rds_setup_arch,
+	.init_IRQ		= mpc85xx_rds_pic_init,
+	.get_irq		= mpic_get_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+};
-- 
1.7.6.5

^ permalink raw reply related

* Re: [PATCH 4/5] powerpc/powernv: Pick up correct number of PEs
From: Benjamin Herrenschmidt @ 2013-07-31  9:18 UTC (permalink / raw)
  To: Gavin Shan; +Cc: linuxppc-dev
In-Reply-To: <1375260424-20777-4-git-send-email-shangw@linux.vnet.ibm.com>

On Wed, 2013-07-31 at 16:47 +0800, Gavin Shan wrote:
> Usually, the property "ibm,opal-num-pes" of PHB dev-tree node
> indicates the number of total PEs. If that property isn't existing
> or valid, we should fall back to pick the correct number of total
> PEs according to PHB type: IODA1 or IODA2.

Is that correct ? Don't we get the total number of PEs from a config
register on the bridge ? I didn't think the IODA architecture specified
the total number of PE of a given implementation...

For example, does Torrent implement 128 ?

I'd rather stick to safe here, if the firmware doesn't say, just use
one.

Now some of the PHB registers are actually architected in IODA afaik, so
we could just go look but let's not make a precedent here.

Cheers,
Ben.

> Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
> ---
>  arch/powerpc/platforms/powernv/pci-ioda.c |   11 +++++++----
>  1 files changed, 7 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
> index 829047b..6386bb4 100644
> --- a/arch/powerpc/platforms/powernv/pci-ioda.c
> +++ b/arch/powerpc/platforms/powernv/pci-ioda.c
> @@ -1172,11 +1172,14 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
>  
>  	/* Initialize more IODA stuff */
>  	prop32 = of_get_property(np, "ibm,opal-num-pes", NULL);
> -	if (!prop32)
> -		phb->ioda.total_pe = 1;
> -	else
> +	if (prop32)
>  		phb->ioda.total_pe = *prop32;
> -
> +	else if (phb->type == PNV_PHB_IODA1)
> +		phb->ioda.total_pe = 128;
> +	else if (phb->type == PNV_PHB_IODA2)
> +		phb->ioda.total_pe = 256;
> +	else
> +		phb->ioda.total_pe = 1;
>  	phb->ioda.m32_size = resource_size(&hose->mem_resources[0]);
>  	/* FW Has already off top 64k of M32 space (MSI space) */
>  	phb->ioda.m32_size += 0x10000;

^ permalink raw reply

* [PATCH 2/5] powerpc/powernv: Fetch PHB bus range from dev-tree
From: Gavin Shan @ 2013-07-31  8:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1375260424-20777-1-git-send-email-shangw@linux.vnet.ibm.com>

The patch enables fetching bus range from device-tree for the
specific PHB. If we can't get that from device-tree, the default
range [0 255] will be used.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/pci-ioda.c |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 9cccdc7..f472228 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1109,6 +1109,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 	unsigned long size, m32map_off, iomap_off, pemap_off;
 	const u64 *prop64;
 	const u32 *prop32;
+	int len;
 	u64 phb_id;
 	void *aux;
 	long rc;
@@ -1140,9 +1141,15 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 	}
 
 	spin_lock_init(&phb->lock);
-	/* XXX Use device-tree */
-	hose->first_busno = 0;
-	hose->last_busno = 0xff;
+	prop32 = of_get_property(np, "bus-range", &len);
+	if (prop32 && len == 8) {
+		hose->first_busno = prop32[0];
+		hose->last_busno = prop32[1];
+	} else {
+		pr_warn("  Broken <bus-range> on %s\n", np->full_name);
+		hose->first_busno = 0;
+		hose->last_busno = 0xff;
+	}
 	hose->private_data = phb;
 	phb->hub_id = hub_id;
 	phb->opal_id = phb_id;
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 3/5] powerpc/powernv: Check primary PHB through ID
From: Gavin Shan @ 2013-07-31  8:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1375260424-20777-1-git-send-email-shangw@linux.vnet.ibm.com>

The index of one specific PCI controller (struct pci_controller::
global_number) can tell that it's primary one or not. So we needn't
additional variable for that and just remove it.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/pci-ioda.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index f472228..829047b 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1104,7 +1104,6 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 				  u64 hub_id, int ioda_type)
 {
 	struct pci_controller *hose;
-	static int primary = 1;
 	struct pnv_phb *phb;
 	unsigned long size, m32map_off, iomap_off, pemap_off;
 	const u64 *prop64;
@@ -1164,8 +1163,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 		phb->model = PNV_PHB_MODEL_UNKNOWN;
 
 	/* Parse 32-bit and IO ranges (if any) */
-	pci_process_bridge_OF_ranges(phb->hose, np, primary);
-	primary = 0;
+	pci_process_bridge_OF_ranges(hose, np, !hose->global_number);
 
 	/* Get registers */
 	phb->regs = of_iomap(np, 0);
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 4/5] powerpc/powernv: Pick up correct number of PEs
From: Gavin Shan @ 2013-07-31  8:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1375260424-20777-1-git-send-email-shangw@linux.vnet.ibm.com>

Usually, the property "ibm,opal-num-pes" of PHB dev-tree node
indicates the number of total PEs. If that property isn't existing
or valid, we should fall back to pick the correct number of total
PEs according to PHB type: IODA1 or IODA2.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/pci-ioda.c |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 829047b..6386bb4 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1172,11 +1172,14 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 
 	/* Initialize more IODA stuff */
 	prop32 = of_get_property(np, "ibm,opal-num-pes", NULL);
-	if (!prop32)
-		phb->ioda.total_pe = 1;
-	else
+	if (prop32)
 		phb->ioda.total_pe = *prop32;
-
+	else if (phb->type == PNV_PHB_IODA1)
+		phb->ioda.total_pe = 128;
+	else if (phb->type == PNV_PHB_IODA2)
+		phb->ioda.total_pe = 256;
+	else
+		phb->ioda.total_pe = 1;
 	phb->ioda.m32_size = resource_size(&hose->mem_resources[0]);
 	/* FW Has already off top 64k of M32 space (MSI space) */
 	phb->ioda.m32_size += 0x10000;
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 5/5] powerpc/powernv: Needn't IO segment map for PHB3
From: Gavin Shan @ 2013-07-31  8:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1375260424-20777-1-git-send-email-shangw@linux.vnet.ibm.com>

PHB3 doesn't support IO ports and we needn't IO segment map for that.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/pci-ioda.c |   13 +++++++------
 1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 6386bb4..147f9b7 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1190,22 +1190,23 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 	phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe;
 	phb->ioda.io_pci_base = 0; /* XXX calculate this ? */
 
-	/* Allocate aux data & arrays
-	 *
-	 * XXX TODO: Don't allocate io segmap on PHB3
-	 */
+	/* Allocate aux data & arrays. We don't have IO ports on PHB3 */
 	size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long));
 	m32map_off = size;
 	size += phb->ioda.total_pe * sizeof(phb->ioda.m32_segmap[0]);
 	iomap_off = size;
-	size += phb->ioda.total_pe * sizeof(phb->ioda.io_segmap[0]);
+	if (phb->type == PNV_PHB_IODA1) {
+		iomap_off = size;
+		size += phb->ioda.total_pe * sizeof(phb->ioda.io_segmap[0]);
+	}
 	pemap_off = size;
 	size += phb->ioda.total_pe * sizeof(struct pnv_ioda_pe);
 	aux = alloc_bootmem(size);
 	memset(aux, 0, size);
 	phb->ioda.pe_alloc = aux;
 	phb->ioda.m32_segmap = aux + m32map_off;
-	phb->ioda.io_segmap = aux + iomap_off;
+	if (phb->type == PNV_PHB_IODA1)
+		phb->ioda.io_segmap = aux + iomap_off;
 	phb->ioda.pe_array = aux + pemap_off;
 	set_bit(0, phb->ioda.pe_alloc);
 
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH 1/5] powerpc/powernv: Free PHB instance upon error
From: Gavin Shan @ 2013-07-31  8:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan

We don't free PHB instance (struct pnv_phb) on error to creating
the associated PCI controler (struct pci_controller). The patch
fixes that. Also, the output messages have been cleaned for a bit
so that they looks unified for IODA_1/2 cases.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/pci-ioda.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index d8140b1..9cccdc7 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1113,7 +1113,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 	void *aux;
 	long rc;
 
-	pr_info(" Initializing IODA%d OPAL PHB %s\n", ioda_type, np->full_name);
+	pr_info("Initializing IODA%d OPAL PHB %s\n", ioda_type, np->full_name);
 
 	prop64 = of_get_property(np, "ibm,opal-phbid", NULL);
 	if (!prop64) {
@@ -1124,13 +1124,18 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 	pr_debug("  PHB-ID  : 0x%016llx\n", phb_id);
 
 	phb = alloc_bootmem(sizeof(struct pnv_phb));
-	if (phb) {
-		memset(phb, 0, sizeof(struct pnv_phb));
-		phb->hose = hose = pcibios_alloc_controller(np);
+	if (!phb) {
+		pr_err("  Out of memory !\n");
+		return;
 	}
-	if (!phb || !phb->hose) {
-		pr_err("PCI: Failed to allocate PCI controller for %s\n",
+
+	/* Allocate PCI controller */
+	memset(phb, 0, sizeof(struct pnv_phb));
+	phb->hose = hose = pcibios_alloc_controller(np);
+	if (!phb->hose) {
+		pr_err("  Can't allocate PCI controller for %s\n",
 		       np->full_name);
+		free_bootmem((unsigned long)phb, sizeof(struct pnv_phb));
 		return;
 	}
 
-- 
1.7.5.4

^ permalink raw reply related

* [PATCH] powerpc/pci: Remove duplicate check in pcibios_fixup_bus()
From: Gavin Shan @ 2013-07-31  8:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan

pci_read_bridge_bases() already checks if the PCI bus is root
bus or not, so we needn't do same check in pcibios_fixup_bus()
and just remove it.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
 arch/powerpc/kernel/pci-common.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 7d22a67..c55fb35 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1055,8 +1055,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 	 * bases. This is -not- called when generating the PCI tree from
 	 * the OF device-tree.
 	 */
-	if (bus->self != NULL)
-		pci_read_bridge_bases(bus);
+	pci_read_bridge_bases(bus);
 
 	/* Now fixup the bus bus */
 	pcibios_setup_bus_self(bus);
-- 
1.7.5.4

^ 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