LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: Critical Interrupt Input
From: Benjamin Herrenschmidt @ 2013-08-20 23:08 UTC (permalink / raw)
  To: Henry Bausley; +Cc: linuxppc-dev
In-Reply-To: <1377038913.25385.194.camel@lx-henry>

On Tue, 2013-08-20 at 15:48 -0700, Henry Bausley wrote:
> Ben,
> 
> 
> After your hints I suspected the read of a real world i/o variable *piom
> which came from ioremap_nocache in the 3 line critical interrupt handler
> 
> void critintr_handler(void *dev)
> {
>   critintrcount++;          // increment a variable
>   iodata = *piom;           // read an I/O location 
>   mtdcr(0x0c0, 0x00002000); // clear critical interrupt 
> } 
> 
> is what caused the problem. Commenting it out seems to make the system stable.  

Right, definitely would do that. BTW. You may want to use proper IO
accessors while at it, to get the right memory barriers etc...

> This led us to disable the critical interrupt when in the
> DataTLBError44x and InstructionTLBError44x exceptions.  Now the critical
> interrupt handler seems to make things more stable when reading real
> world i/o for our application.
>
> 
>   /* Data TLB Error Interrupt */
>   START_EXCEPTION(DataTLBError44x)
>   mtspr	SPRN_SPRG_WSCRATCH0, r10  /* Save some working */
> +  mfmsr r10                      /*  Disable the */
> +  rlwinm r10,r10,0,15,13         /*  MSR's CE bit */
> +  mtmsr r10                     
> 
> 
> Do you see any potential problems with this approach?
> 
> If so can you advise us on how to better take care of this.

 - You potentially still have an exposure ... between the mtspr to
scratch and the mfmsr, a CRIC can occur, causing a re-entrancy which
would than clobber the scratch register. That can be handled by saving
that scratc SPRG into the stack frame on entry/exit from the crit
interrupt. Look at crit_transfer_to_handler, how it already handles
MMUCR:

	mfspr	r0,SPRN_MMUCR
	stw	r0,MMUCR(r11)

Probably add saving of the SPRG_WSCRATCH0 in there (need to add a frame
slot for it) and do the restore in RESTORE_MMU_REGS

 - You need to handle Instructions TLB miss as well

 - You add overhead to the TLB miss handlers which are fairly
performance critical pieces of code. You might be able to alleviate
that by making the whole thing support re-entrancy properly but that's
harder. To do that you would have to:

    * Save *all* the SPRGs used by the TLB miss during crit entry/exit

    * Detect in crit_transfer_to_handler (check the CSRR0 bounds) that 
      the crit code interrupted finish_tlb_load_44x before or at the
      last tlbwe instruction. In that case, immediately clear the 
      partially written TLB entry (index in r13) and change the
      return address to skip right past the last tlbwe.

Cheers,
Ben.


> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> On Tue, 2013-08-20 at 06:56 +1000, Benjamin Herrenschmidt wrote:
> > On Mon, 2013-08-19 at 12:00 -0700, Henry Bausley wrote:
> > > 
> > > Support does appear to be present but there is a problem returning
> > > back to user space I suspect.
> > 
> > Probably a problem with TLB misses vs. crit interrupts.
> > 
> > A critical interrupt can re-enter a TLB miss.
> > 
> > I can see two potential issues there:
> > 
> >  - A bug where we don't properly restore "something" (I thought we did
> > save and restore MMUCR though, but that's worth dbl checking if it works
> > properly) accross the crit entry/exit
> > 
> >  - Something in your crit code causing a TLB miss (the
> > kernel .text/.data/.bss should be bolted but anything else can). We
> > don't currently support re-entering the TLB miss that way.
> > 
> > If we were to support the latter, we'd need to detect on entering a crit
> > that the PC is within the TLB miss handler, and setup a return context
> > to the original instruction (replay the miss) rather than trying to
> > resume it..
> > 
> > Cheers,
> > Ben.
> > 
> > > What fails is it causes Linux user space programs to get Segmentation
> > > errors.
> > > Issuing a simple ls causes a segmentation fault sometimes.  The shell
> > > gets terminated 
> > > and you cannot log back in.  INIT: Id "T0" respawning too fast:
> > > disabled for 5 minutes pops up.
> > > 
> > > However, the critical interrupt handler keeps running.  I know this by
> > > adding the reading 
> > > of a physical I/O location in the handler and can see it is being read
> > > on the scope.
> > > 
> > > 
> > > The only code in the handler is below.
> > > 
> > > void critintr_handler(void *dev)
> > > {
> > >   critintrcount++;          // increment a variable
> > >   iodata = *piom;           // read an I/O location 
> > >   mtdcr(0x0c0, 0x00002000); // clear critical interrupt
> > > }
> > > 
> > > 
> > > Below is a log of the type of crashes that occur:
> > > 
> > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > Segmentation fault
> > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > Segmentation fault
> > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > Makefile        ktest.c    ktest.ko     ktest.mod.o  modules.order
> > > Module.symvers  ktest.cbp  ktest.mod.c  ktest.o
> > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > 
> > > Debian GNU/Linux 7 powerpmac ttyS0
> > > 
> > > powerpmac login: root
> > > 
> > > Debian GNU/Linux 7 powerpmac ttyS0
> > > 
> > > powerpmac login: root
> > > 
> > > Debian GNU/Linux 7 powerpmac ttyS0
> > > 
> > > powerpmac login: root
> > > 
> > > Debian GNU/Linux 7 powerpmac ttyS0
> > > 
> > > powerpmac login: root
> > > Password: 
> > > Last login: Thu Nov 30 20:42:16 UTC 1933 on ttyS0
> > > Linux powerpmac 3.2.21-aspen_2.01.09 #10 Mon Aug 19 08:49:12 PDT 2013
> > > ppc
> > > 
> > > The programs included with the Debian GNU/Linux system are free
> > > software;
> > > the exact distribution terms for each program are described in the
> > > individual files in /usr/share/doc/*/copyright.
> > > 
> > > Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
> > > permitted by applicable law.
> > > INIT: Id "T0" respawning too fast: disabled for 5 minutes
> > > 
> > > 
> > > ______________________________________________________________________
> > > From: "Benjamin Herrenschmidt" <benh@kernel.crashing.org>
> > > Sent: Saturday, August 17, 2013 3:05 PM
> > > To: "Kumar Gala" <galak@kernel.crashing.org>
> > > Cc: linuxppc-dev@lists.ozlabs.org, hbausley@deltatau.com
> > > Subject: Re: Critical Interrupt Input
> > > 
> > > On Fri, 2013-08-16 at 06:04 -0500, Kumar Gala wrote:
> > > > The 44x low level code needs to handle exception stacks properly for
> > > > this to work. Since its possible to have a critical exception occur
> > > > while in a normal exception level, you have to have proper saving of
> > > > additional register state and a stack frame for the critical
> > > > exception, etc. I'm not sure if that was ever done for 44x.
> > > 
> > > Don't 44x and FSL BookE share the same macros ? I would think 44x does
> > > indeed implement the same crit support as e500...
> > > 
> > > What does the crash look like ?
> > > 
> > > Ben.
> > > 
> > > 
> > > _______________________________________________
> > > Linuxppc-dev mailing list
> > > Linuxppc-dev@lists.ozlabs.org
> > > https://lists.ozlabs.org/listinfo/linuxppc-dev
> > > 
> > > 
> > >   ­­  
> > 
> > 
> 
> 
> 
> 
> 
> Outbound scan for Spam or Virus by Barracuda at Delta Tau

^ permalink raw reply

* Re: [RFC PATCH 1/1] powerpc/embedded6xx: Add support for Motorola/Emerson MVME5100.
From: Scott Wood @ 2013-08-20 23:20 UTC (permalink / raw)
  To: Stephen N Chivers; +Cc: linuxppc-dev, paulus, Chris Proctor
In-Reply-To: <OFE172B06C.BE11BDC5-ONCA257BCC.007C0097-CA257BCD.000D984C@csc.com>

On Tue, 2013-08-20 at 13:28 +1100, Stephen N Chivers wrote:
> Scott Wood <scottwood@freescale.com> wrote on 08/09/2013 11:35:20 AM:
> 
> > From: Scott Wood <scottwood@freescale.com>
> > To: Stephen N Chivers <schivers@csc.com.au>
> > Cc: <benh@kernel.crashing.org>, <paulus@samba.org>, Chris Proctor 
> > <cproctor@csc.com.au>, <linuxppc-dev@lists.ozlabs.org>
> > Date: 08/09/2013 11:36 AM
> > Subject: Re: [RFC PATCH 1/1] powerpc/embedded6xx: Add support for 
> > Motorola/Emerson MVME5100.
> > 
> > simple-bus may be applicable here (in addition to a specific
> > compatible).
> >
> The HAWK ASIC is a difficult beast. I still cannot get a positive
> identification as to what it is (Motorola/Freescale part number
> unknown, not even the part number on the chip on the board helps....).
> The best I can come up with is that it is a tsi108 without
> the ethenets.
> So device_type will be tsi-bridge and compatible will be
> tsi108-bridge.

Don't use device_type.  compatible should include "hawk" in the name
(especially if you're not sure what's really in it), and/or the part
number on the chip.  If you're convinced it's fully compatible with
tsi108-bridge you can add that as a second compatible value, though
given the uncertainty it's probably better to just teach Linux to look
for the new compatible.

If devices on the bus can be used without any special bus setup or
knowledge, then you can add a compatible of "simple-bus" to the end.

> > Why not just look for a chrp,iic node directly?
> >
> I was following the model used in other places, like chrp/setup.c.

Not all examples are good examples. :-)

> > > +       if ((np = of_find_compatible_node(NULL, "pci", "mpc10x-pci"))) 
> {
> > 
> > Why insist on the device_type?
> >
> Following the model in the linkstation (kurobox) platform support. 

Drop the device_type check.

> > > +static void
> > > +mvme5100_restart(char *cmd)
> > > +{
> > > +       volatile ulong          i = 10000000;
> > > +
> > > +
> > > +       local_irq_disable();
> > > +       _nmask_and_or_msr(0, MSR_IP);
> > 
> > Does "mtmsr(mfmsr() | MSR_IP)" not work?
> >
> Don't know. Is from the original code by Matt Porter.

It actually appears that there are no callers remaining that use the
"and" portion of the functionality.  In fact there are no callers that
use it for anything other than setting MSR_IP. :-P

> > > +       out_8((u_char *) BOARD_MODRST_REG, 0x01);
> > > +
> > > +       while (i-- > 0);
> > 
> > Do not use a loop to implement a delay.
> >
> Taken from the original code. But at this point the board
> is going to reset and reboot via firmware, as /sbin/reboot
> or /sbin/halt has been invoked.

Still, it's just a bad idea.  What's wrong with udelay()?

Or just use an infinite loop.  How much value is there really in timing
out here?

> > > +static void __init
> > > +mvme5100_set_bat(void)
> > > +{
> > > +
> > > +
> > > +       mb();
> > > +       mtspr(SPRN_DBAT1U, 0xf0001ffe);
> > > +       mtspr(SPRN_DBAT1L, 0xf000002a);
> > > +       mb();
> > > +       setbat(1, 0xfe000000, 0xfe000000, 0x02000000, 
> PAGE_KERNEL_NCG);
> > > +}
> > 
> > It is no longer allowed to squat on random virtual address space like
> > this.  If you really need a BAT you'll have to allocate the virtual
> > address properly.
> >
> Yes. I found that this was an anathema when researching the port in
> 2010 but I couldn't find any practical solution at the time.
> The code is called early to ensure that the hawk registers are available.
> sysdev/cpm_common.c does the same thing.

> What is the correct solution?

ioremap() has special code to function early (using ioremap_bot).

If you still need to use a BAT that early, reserve the space with
asm/fixmap.h or by adding a function to the early ioremap code to just
reserve the space.  Or better, improve the ioremap code to be capable of
creating a BAT (or equivalent) when requested.

-Scott

^ permalink raw reply

* Re: [PATCH v4 0/7] net: use platform_{get,set}_drvdata()
From: David Miller @ 2013-08-21  0:19 UTC (permalink / raw)
  To: clbchenlibo.chen
  Cc: sergei.shtylyov, gregkh, netdev, jg1.han, lizefan, vbordug,
	linuxppc-dev
In-Reply-To: <52120859.7060200@huawei.com>

From: Libo Chen <clbchenlibo.chen@huawei.com>
Date: Mon, 19 Aug 2013 19:58:17 +0800

> 
> Use the wrapper functions for getting and setting the driver data using
> platform_device instead of using dev_{get,set}_drvdata() with &pdev->dev,
> so we can directly pass a struct platform_device.
> 
> changelog v4:
> 	remove modify about happy_meal_pci_probe && happy_meal_pci_remove
> changelog v3:
> 	remove modify about dev_set_drvdata()
> changelog v2:
> 	this version add modify record about dev_set_drvdata().

Series applied.

^ permalink raw reply

* Re: linux-next: build failure after merge of the final tree
From: Stephen Rothwell @ 2013-08-21  0:22 UTC (permalink / raw)
  To: Ben Myers
  Cc: cbe-oss-dev, Arnd Bergmann, Dwight Engen, linux-kernel, xfs,
	linux-next, Jeremy Kerr, linuxppc-dev, Gao feng
In-Reply-To: <20130820192844.GC5262@sgi.com>

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

Hi Ben,

On Tue, 20 Aug 2013 14:28:44 -0500 Ben Myers <bpm@sgi.com> wrote:
>
> I'd prefer not to break Stephen's tree two days in a row.  We could just revert
> d6970d4b726c in the xfs tree for the time being as Stephen has done, but given
> the choice would prefer the fix.  Do you have a preference between the two
> approaches that Dwight has posted?  The first seems more conservative...

I will automatically revert that commit when I merge the xfs tree until
some other solution is forthcoming (so you don't have to do the revert in
the xfs tree).  This does need to be fixed fairly soon, though.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

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

^ permalink raw reply

* Re: [PATCH] Kconfig: Remove hotplug enable hints in CONFIG_KEXEC help texts
From: Stephen Rothwell @ 2013-08-21  1:13 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: linux-mips, linux-ia64, linux-sh, Greg Kroah-Hartman, x86,
	linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1377027483-17025-1-git-send-email-geert@linux-m68k.org>

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

Hi Geert,

On Tue, 20 Aug 2013 21:38:03 +0200 Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>
> commit 40b313608ad4ea655addd2ec6cdd106477ae8e15 ("Finally eradicate
> CONFIG_HOTPLUG") removed remaining references to CONFIG_HOTPLUG, but missed
> a few plain English references in the CONFIG_KEXEC help texts.
> 
> Remove them, too.
> 
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>

Looks good to me.  Thanks.

Acked-by: Stephen Rothwell <sfr@canb.auug.org.au>

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

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

^ permalink raw reply

* [PATCH 1/4] powerpc: Convert some mftb/mftbu into mfspr
From: Scott Wood @ 2013-08-21  2:12 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Catalin Udma
In-Reply-To: <1377051162-2588-1-git-send-email-scottwood@freescale.com>

Some CPUs (such as e500v1/v2) don't implement mftb and will take a
trap.  mfspr should work on everything that has a timebase, and is the
preferred instruction according to ISA v2.06.

Currently we get away with mftb on 85xx because the assembler converts
it to mfspr due to -Wa,-me500.  However, that flag has other effects
that are undesireable for certain targets (e.g.  lwsync is converted to
sync), and is hostile to multiplatform kernels.  Thus we would like to
stop setting it for all e500-family builds.

mftb/mftbu instances which are in 85xx code or common code are
converted.  Instances which will never run on 85xx are left alone.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/boot/ppc_asm.h               |  3 +++
 arch/powerpc/boot/util.S                  | 10 +++++-----
 arch/powerpc/include/asm/ppc_asm.h        |  4 ++--
 arch/powerpc/include/asm/reg.h            | 15 ++++++++++-----
 arch/powerpc/include/asm/timex.h          |  4 ++--
 arch/powerpc/kernel/vdso32/gettimeofday.S |  6 +++---
 arch/powerpc/platforms/85xx/smp.c         |  6 ++++--
 7 files changed, 29 insertions(+), 19 deletions(-)

diff --git a/arch/powerpc/boot/ppc_asm.h b/arch/powerpc/boot/ppc_asm.h
index 1c2c281..eb0e98b 100644
--- a/arch/powerpc/boot/ppc_asm.h
+++ b/arch/powerpc/boot/ppc_asm.h
@@ -59,4 +59,7 @@
 #define	r30	30
 #define	r31	31
 
+#define SPRN_TBRL	268
+#define SPRN_TBRU	269
+
 #endif /* _PPC64_PPC_ASM_H */
diff --git a/arch/powerpc/boot/util.S b/arch/powerpc/boot/util.S
index 427ddfc..5143228 100644
--- a/arch/powerpc/boot/util.S
+++ b/arch/powerpc/boot/util.S
@@ -71,18 +71,18 @@ udelay:
 	add	r4,r4,r5
 	addi	r4,r4,-1
 	divw	r4,r4,r5	/* BUS ticks */
-1:	mftbu	r5
-	mftb	r6
-	mftbu	r7
+1:	mfspr	r5, SPRN_TBRU
+	mfspr	r6, SPRN_TBRL
+	mfspr	r7, SPRN_TBRU
 	cmpw	0,r5,r7
 	bne	1b		/* Get [synced] base time */
 	addc	r9,r6,r4	/* Compute end time */
 	addze	r8,r5
-2:	mftbu	r5
+2:	mfspr	r5, SPRN_TBRU
 	cmpw	0,r5,r8
 	blt	2b
 	bgt	3f
-	mftb	r6
+	mfspr	r6, SPRN_TBRL
 	cmpw	0,r6,r9
 	blt	2b
 3:	blr
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 8fdd3da..5995457 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -433,13 +433,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
 
 #if defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_FSL_BOOK3E)
 #define MFTB(dest)			\
-90:	mftb  dest;			\
+90:	mfspr dest, SPRN_TBRL;		\
 BEGIN_FTR_SECTION_NESTED(96);		\
 	cmpwi dest,0;			\
 	beq-  90b;			\
 END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
 #else
-#define MFTB(dest)			mftb dest
+#define MFTB(dest)			mfspr dest, SPRN_TBRL
 #endif
 
 #ifndef CONFIG_SMP
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 55b0307..64264bf 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -1120,7 +1120,7 @@
 #if defined(CONFIG_PPC_CELL) || defined(CONFIG_PPC_FSL_BOOK3E)
 #define mftb()		({unsigned long rval;				\
 			asm volatile(					\
-				"90:	mftb %0;\n"			\
+				"90:	mfspr %0, %2;\n"		\
 				"97:	cmpwi %0,0;\n"			\
 				"	beq- 90b;\n"			\
 				"99:\n"					\
@@ -1134,18 +1134,23 @@
 				"	.llong 0\n"			\
 				"	.llong 0\n"			\
 				".previous"				\
-			: "=r" (rval) : "i" (CPU_FTR_CELL_TB_BUG)); rval;})
+			: "=r" (rval) \
+			: "i" (CPU_FTR_CELL_TB_BUG), "i" (SPRN_TBRL)); \
+			rval;})
 #else
 #define mftb()		({unsigned long rval;	\
-			asm volatile("mftb %0" : "=r" (rval)); rval;})
+			asm volatile("mfspr %0, %1" : \
+				     "=r" (rval) : "i" (SPRN_TBRL)); rval;})
 #endif /* !CONFIG_PPC_CELL */
 
 #else /* __powerpc64__ */
 
 #define mftbl()		({unsigned long rval;	\
-			asm volatile("mftbl %0" : "=r" (rval)); rval;})
+			asm volatile("mfspr %0, %1" : "=r" (rval) : \
+				"i" (SPRN_TBRL)); rval;})
 #define mftbu()		({unsigned long rval;	\
-			asm volatile("mftbu %0" : "=r" (rval)); rval;})
+			asm volatile("mfspr %0, %1" : "=r" (rval) : \
+				"i" (SPRN_TBRU)); rval;})
 #endif /* !__powerpc64__ */
 
 #define mttbl(v)	asm volatile("mttbl %0":: "r"(v))
diff --git a/arch/powerpc/include/asm/timex.h b/arch/powerpc/include/asm/timex.h
index c55e14f..18908ca 100644
--- a/arch/powerpc/include/asm/timex.h
+++ b/arch/powerpc/include/asm/timex.h
@@ -29,7 +29,7 @@ static inline cycles_t get_cycles(void)
 	ret = 0;
 
 	__asm__ __volatile__(
-		"97:	mftb %0\n"
+		"97:	mfspr %0, %2\n"
 		"99:\n"
 		".section __ftr_fixup,\"a\"\n"
 		".align 2\n"
@@ -41,7 +41,7 @@ static inline cycles_t get_cycles(void)
 		"	.long 0\n"
 		"	.long 0\n"
 		".previous"
-		: "=r" (ret) : "i" (CPU_FTR_601));
+		: "=r" (ret) : "i" (CPU_FTR_601), "i" (SPRN_TBRL));
 	return ret;
 #endif
 }
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
index 27e2f62..6b1f2a6 100644
--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -232,9 +232,9 @@ __do_get_tspec:
 	lwz	r6,(CFG_TB_ORIG_STAMP+4)(r9)
 
 	/* Get a stable TB value */
-2:	mftbu	r3
-	mftbl	r4
-	mftbu	r0
+2:	mfspr	r3, SPRN_TBRU
+	mfspr	r4, SPRN_TBRL
+	mfspr	r0, SPRN_TBRU
 	cmplw	cr0,r3,r0
 	bne-	2b
 
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index ea7e629..281b7f0 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -83,11 +83,13 @@ static void mpc85xx_give_timebase(void)
 	{
 		u64 prev;
 
-		asm volatile("mftb %0" : "=r" (timebase));
+		asm volatile("mfspr %0, %1" : "=r" (timebase) :
+			     "i" (SPRN_TBRL));
 
 		do {
 			prev = timebase;
-			asm volatile("mftb %0" : "=r" (timebase));
+			asm volatile("mfspr %0, %1" : "=r" (timebase) :
+				     "i" (SPRN_TBRL));
 		} while (prev != timebase);
 	}
 #else
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 0/4] powerpc/e500: rework compiler flags
From: Scott Wood @ 2013-08-21  2:12 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Catalin Udma

This replaces the reverted "powerpc/e500: Update compilation flags with
core specific options" with a more multiplatform friendly approach
(on 64-bit) and hopefully without breaking anything this time. :-)

This patchset touches parts of code that are also touched by
http://patchwork.ozlabs.org/patch/261248/, so that patch is a
prerequisite.

Scott Wood (4):
  powerpc: Convert some mftb/mftbu into mfspr
  powerpc/85xx: Remove -Wa,-me500
  powerpc/booke64: Use appropriate -mcpu
  powerpc/e500: Set -mcpu flag for 32-bit e500

 arch/powerpc/Makefile                     | 18 +++++++++++++++++-
 arch/powerpc/boot/ppc_asm.h               |  3 +++
 arch/powerpc/boot/util.S                  | 10 +++++-----
 arch/powerpc/include/asm/ppc_asm.h        |  4 ++--
 arch/powerpc/include/asm/reg.h            | 15 ++++++++++-----
 arch/powerpc/include/asm/timex.h          |  4 ++--
 arch/powerpc/kernel/vdso32/gettimeofday.S |  6 +++---
 arch/powerpc/platforms/85xx/smp.c         |  6 ++++--
 arch/powerpc/platforms/Kconfig.cputype    | 13 +++++++++++++
 9 files changed, 59 insertions(+), 20 deletions(-)

-- 
1.8.1.2

^ permalink raw reply

* [PATCH 3/4] powerpc/booke64: Use appropriate -mcpu
From: Scott Wood @ 2013-08-21  2:12 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Catalin Udma
In-Reply-To: <1377051162-2588-1-git-send-email-scottwood@freescale.com>

By default use -mcpu=powerpc64 rather than -mtune=power7

Add options for e5500/e6500, with fallbacks for older compilers.

Hide the POWER cpu options in booke configs.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/Makefile                  |  9 +++++++++
 arch/powerpc/platforms/Kconfig.cputype | 13 +++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 6930c93..32dfd5d 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -88,13 +88,22 @@ CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mcmodel=medium,-mminimal-toc)
 CFLAGS-$(CONFIG_PPC64)	+= $(call cc-option,-mno-pointers-to-nested-functions)
 CFLAGS-$(CONFIG_PPC32)	:= -ffixed-r2 -mmultiple
 
+ifeq ($(CONFIG_PPC_BOOK3S_64),y)
 CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,-mtune=power4)
+else
+CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=powerpc64
+endif
+
 CFLAGS-$(CONFIG_CELL_CPU) += $(call cc-option,-mcpu=cell)
 CFLAGS-$(CONFIG_POWER4_CPU) += $(call cc-option,-mcpu=power4)
 CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
 CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
 CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
 
+E5500_CPU := $(call cc-option,-mcpu=e500mc64,-mcpu=powerpc64)
+CFLAGS-$(CONFIG_E5500_CPU) += $(E5500_CPU)
+CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU))
+
 CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
 
 KBUILD_CPPFLAGS	+= -Iarch/$(ARCH)
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 47d9a03..6704e2e 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -96,18 +96,31 @@ config GENERIC_CPU
 
 config CELL_CPU
 	bool "Cell Broadband Engine"
+	depends on PPC_BOOK3S_64
 
 config POWER4_CPU
 	bool "POWER4"
+	depends on PPC_BOOK3S_64
 
 config POWER5_CPU
 	bool "POWER5"
+	depends on PPC_BOOK3S_64
 
 config POWER6_CPU
 	bool "POWER6"
+	depends on PPC_BOOK3S_64
 
 config POWER7_CPU
 	bool "POWER7"
+	depends on PPC_BOOK3S_64
+
+config E5500_CPU
+	bool "Freescale e5500"
+	depends on E500
+
+config E6500_CPU
+	bool "Freescale e6500"
+	depends on E500
 
 endchoice
 
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 2/4] powerpc/85xx: Remove -Wa,-me500
From: Scott Wood @ 2013-08-21  2:12 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Catalin Udma
In-Reply-To: <1377051162-2588-1-git-send-email-scottwood@freescale.com>

This caused lwsync to be converted to sync on 64-bit (on 32-bit lwsync
is generated at runtime, and so wasn't affected).  Not using lwsync
caused a significant slowdown on certain workloads.

Setting this flag for any e500-enabled build is also not friendly to
multiplatform kernels.

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/Makefile | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 967fd23..6930c93 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -139,7 +139,6 @@ endif
 
 cpu-as-$(CONFIG_4xx)		+= -Wa,-m405
 cpu-as-$(CONFIG_ALTIVEC)	+= -Wa,-maltivec
-cpu-as-$(CONFIG_E500)		+= -Wa,-me500
 cpu-as-$(CONFIG_E200)		+= -Wa,-me200
 
 KBUILD_AFLAGS += $(cpu-as-y)
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 4/4] powerpc/e500: Set -mcpu flag for 32-bit e500
From: Scott Wood @ 2013-08-21  2:12 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Catalin Udma
In-Reply-To: <1377051162-2588-1-git-send-email-scottwood@freescale.com>

Unlike 64-bit, we don't currently support multiplatform between e500
and non-e500, so the -mcpu is not configurable at this time.

-msoft-float is specified when testing for -mcpu=8540 because otherwise
some older toolchains will fail with "error: E500 and FPRs not
supported".

Signed-off-by: Scott Wood <scottwood@freescale.com>
---
 arch/powerpc/Makefile | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 32dfd5d..51cfb78 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -104,6 +104,14 @@ E5500_CPU := $(call cc-option,-mcpu=e500mc64,-mcpu=powerpc64)
 CFLAGS-$(CONFIG_E5500_CPU) += $(E5500_CPU)
 CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU))
 
+ifeq ($(CONFIG_PPC32),y)
+ifeq ($(CONFIG_PPC_E500MC),y)
+CFLAGS-y += $(call cc-option,-mcpu=e500mc,-mcpu=powerpc)
+else
+CFLAGS-$(CONFIG_E500) += $(call cc-option,-mcpu=8540 -msoft-float,-mcpu=powerpc)
+endif
+endif
+
 CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
 
 KBUILD_CPPFLAGS	+= -Iarch/$(ARCH)
-- 
1.8.1.2

^ permalink raw reply related

* Re: [alsa-devel] [PATCH v8 2/2] ASoC: fsl: Add S/PDIF machine driver
From: Nicolin Chen @ 2013-08-21  2:18 UTC (permalink / raw)
  To: Mark Brown
  Cc: mark.rutland, devicetree, alsa-devel, lars, Stephen Warren,
	linuxppc-dev, s.hauer, timur, rob.herring, tomasz.figa, p.zabel,
	R65777, shawn.guo, festevam
In-Reply-To: <20130820222810.GU30073@sirena.org.uk>

On Tue, Aug 20, 2013 at 11:28:10PM +0100, Mark Brown wrote:
> On Tue, Aug 20, 2013 at 01:53:49PM -0600, Stephen Warren wrote:
> > On 08/20/2013 01:07 PM, Mark Brown wrote:
> 
> > > The point is that it might turn into a more correct binding
> > > depending on what the S/PDIF device actually is.
> 
> > There's *never* an object on the board called a "dummy codec".
> 
> Oh, is that what you're talking about?  Yes, that makes sense.  I had
> been responding to the comments about the transceivers.

I'll remove the 'dummy' words in the next version from the binding doc.

Thank you
Nicolin

^ permalink raw reply

* [PATCH v10 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Nicolin Chen @ 2013-08-21  3:13 UTC (permalink / raw)
  To: broonie, s.hauer
  Cc: mark.rutland, devicetree, alsa-devel, lars, swarren, festevam,
	timur, rob.herring, tomasz.figa, p.zabel, R65777, shawn.guo,
	linuxppc-dev
In-Reply-To: <cover.1377054540.git.b42378@freescale.com>

This patch implements a device-tree-only CPU DAI driver for Freescale
S/PDIF controller that supports stereo playback and record feature.

Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
 .../devicetree/bindings/sound/fsl,spdif.txt        |   54 +
 sound/soc/fsl/Kconfig                              |    3 +
 sound/soc/fsl/Makefile                             |    2 +
 sound/soc/fsl/fsl_spdif.c                          | 1236 ++++++++++++++++++++
 sound/soc/fsl/fsl_spdif.h                          |  191 +++
 5 files changed, 1486 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..f2ae335
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -0,0 +1,54 @@
+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, must contain "fsl,imx35-spdif".
+
+  - reg : Offset and length of the register set for the device.
+
+  - interrupts : Contains the spdif interrupt.
+
+  - dmas : Generic dma devicetree binding as described in
+  Documentation/devicetree/bindings/dma/dma.txt.
+
+  - dma-names : Two dmas have to be defined, "tx" and "rx".
+
+  - clocks : Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+	"core"		The core clock of spdif controller
+	"rxtx<0-7>"	Clock source list for tx and rx clock.
+			This clock list should be identical to
+			the source list connecting to the spdif
+			clock mux in "SPDIF Transceiver Clock
+			Diagram" of SoC reference manual. It
+			can also be referred to TxClk_Source
+			bit of register SPDIF_STC.
+
+Example:
+
+spdif: spdif@02004000 {
+	compatible = "fsl,imx35-spdif";
+	reg = <0x02004000 0x4000>;
+	interrupts = <0 52 0x04>;
+	dmas = <&sdma 14 18 0>,
+	       <&sdma 15 18 0>;
+	dma-names = "rx", "tx";
+
+	clocks = <&clks 197>, <&clks 3>,
+	       <&clks 197>, <&clks 107>,
+	       <&clks 0>, <&clks 118>,
+	       <&clks 62>, <&clks 139>,
+	       <&clks 0>;
+	clock-names = "core", "rxtx0",
+		"rxtx1", "rxtx2",
+		"rxtx3", "rxtx4",
+		"rxtx5", "rxtx6",
+		"rxtx7";
+
+	status = "okay";
+};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3a4808d..cd088cc 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..42a4382
--- /dev/null
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -0,0 +1,1236 @@
+/*
+ * 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/clk-private.h>
+#include <linux/bitrev.h>
+#include <linux/regmap.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)
+
+/* Index list for the values that has if (DPLL Locked) condition */
+static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
+#define SRPC_NODPLL_START1	0x5
+#define SRPC_NODPLL_START2	0xc
+
+#define DEFAULT_RXCLK_SRC	1
+
+/*
+ * 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 offset for U/Q */
+	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 platform_device *pdev;
+	struct regmap *regmap;
+	bool dpll_locked;
+	u8 txclk_div[SPDIF_TXRATE_MAX];
+	u8 txclk_src[SPDIF_TXRATE_MAX];
+	u8 rxclk_src;
+	struct clk *txclk[SPDIF_TXRATE_MAX];
+	struct clk *rxclk;
+	struct snd_dmaengine_dai_dma_data dma_params_tx;
+	struct snd_dmaengine_dai_dma_data dma_params_rx;
+
+	/* The name space will be allocated dynamically */
+	char name[0];
+};
+
+
+/* DPLL locked and lock loss interrupt handler */
+static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 locked;
+
+	regmap_read(regmap, REG_SPDIF_SRPC, &locked);
+	locked &= SRPC_DPLL_LOCKED;
+
+	dev_dbg(&pdev->dev, "isr: Rx dpll %s \n",
+			locked ? "locked" : "loss lock");
+
+	spdif_priv->dpll_locked = locked ? true : false;
+}
+
+/* Receiver found illegal symbol interrupt handler */
+static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+
+	dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n");
+
+	if (!spdif_priv->dpll_locked) {
+		/* DPLL unlocked seems no audio stream */
+		regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0);
+	}
+}
+
+/* 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 regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 *pos, size, val, reg;
+
+	switch (name) {
+	case 'U':
+		pos = &ctrl->upos;
+		size = SPDIF_UBITS_SIZE;
+		reg = REG_SPDIF_SRU;
+		break;
+	case 'Q':
+		pos = &ctrl->qpos;
+		size = SPDIF_QSUB_SIZE;
+		reg = REG_SPDIF_SRQ;
+		break;
+	default:
+		dev_err(&pdev->dev, "unsupported channel name\n");
+		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;
+	}
+
+	regmap_read(regmap, reg, &val);
+	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 regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 val;
+
+	dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n");
+
+	/* Read U/Q data to clear the irq and do buffer reset */
+	regmap_read(regmap, REG_SPDIF_SRU, &val);
+	regmap_read(regmap, REG_SPDIF_SRQ, &val);
+
+	/* 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 regmap *regmap = spdif_priv->regmap;
+	u32 val, val2;
+
+	regmap_read(regmap, REG_SPDIF_SIS, &val);
+	regmap_read(regmap, REG_SPDIF_SIE, &val2);
+
+	regmap_write(regmap, REG_SPDIF_SIC, val & val2);
+
+	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 int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 val, cycle = 1000;
+
+	regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET);
+
+	/*
+	 * RESET bit would be cleared after finishing its reset procedure,
+	 * which typically lasts 8 cycles. 1000 cycles will keep it safe.
+	 */
+	do {
+		regmap_read(regmap, REG_SPDIF_SCR, &val);
+	} while ((val & SCR_SOFT_RESET) && cycle--);
+
+	if (cycle)
+		return 0;
+	else
+		return -EBUSY;
+}
+
+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 void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv)
+{
+	struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+	struct regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u32 ch_status;
+
+	ch_status = (bitrev8(ctrl->ch_status[0]) << 16) |
+		(bitrev8(ctrl->ch_status[1]) << 8) |
+		bitrev8(ctrl->ch_status[2]);
+	regmap_write(regmap, REG_SPDIF_STCSCH, ch_status);
+
+	dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status);
+
+	ch_status = bitrev8(ctrl->ch_status[3]) << 16;
+	regmap_write(regmap, REG_SPDIF_STCSCL, ch_status);
+
+	dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status);
+}
+
+/* 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)
+{
+	struct regmap *regmap = spdif_priv->regmap;
+	u8 clksrc = spdif_priv->rxclk_src;
+
+	if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX)
+		return -EINVAL;
+
+	regmap_update_bits(regmap, REG_SPDIF_SRPC,
+			SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
+			SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel));
+
+	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 regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	unsigned long csfs = 0;
+	u32 stc, mask, rate;
+	u8 clk, div;
+	int ret;
+
+	switch (sample_rate) {
+	case 32000:
+		rate = SPDIF_TXRATE_32000;
+		csfs = IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		rate = SPDIF_TXRATE_44100;
+		csfs = IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		rate = SPDIF_TXRATE_48000;
+		csfs = IEC958_AES3_CON_FS_48000;
+		break;
+	default:
+		dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate);
+		return -EINVAL;
+	}
+
+	clk = spdif_priv->txclk_src[rate];
+	if (clk >= STC_TXCLK_SRC_MAX) {
+		dev_err(&pdev->dev, "tx clock source is out of range\n");
+		return -EINVAL;
+	}
+
+	div = spdif_priv->txclk_div[rate];
+	if (div == 0) {
+		dev_err(&pdev->dev, "the divisor can't be zero\n");
+		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.
+	 */
+	ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1));
+	if (ret) {
+		dev_err(&pdev->dev, "failed to set tx clock rate\n");
+		return ret;
+	}
+
+	dev_dbg(&pdev->dev, "expected clock rate = %d\n",
+			(64 * sample_rate * div));
+	dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
+			clk_get_rate(spdif_priv->txclk[rate]));
+
+	/* 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;
+	regmap_update_bits(regmap, REG_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 platform_device *pdev = spdif_priv->pdev;
+	struct regmap *regmap = spdif_priv->regmap;
+	u32 scr, mask, i;
+	int ret;
+
+	/* Reset module and interrupts only for first initialization */
+	if (!cpu_dai->active) {
+		ret = spdif_softreset(spdif_priv);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to soft reset\n");
+			return ret;
+		}
+
+		/* Disable all the interrupts */
+		regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0);
+	}
+
+	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;
+		for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+			clk_prepare_enable(spdif_priv->txclk[i]);
+	} 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;
+		clk_prepare_enable(spdif_priv->rxclk);
+	}
+	regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
+
+	/* Power up SPDIF module */
+	regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
+
+	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 regmap *regmap = spdif_priv->regmap;
+	u32 scr, mask, i;
+
+	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;
+		for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+			clk_disable_unprepare(spdif_priv->txclk[i]);
+	} 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;
+		clk_disable_unprepare(spdif_priv->rxclk);
+	}
+	regmap_update_bits(regmap, REG_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);
+		regmap_update_bits(regmap, REG_SPDIF_SCR,
+				SCR_LOW_POWER, SCR_LOW_POWER);
+	}
+}
+
+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 */
+		ret = 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 regmap *regmap = spdif_priv->regmap;
+	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:
+		regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr);
+		regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0);
+		regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0);
+		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 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;
+}
+
+static int fsl_spdif_pb_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 fsl_spdif_pb_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];
+
+	spdif_write_channel_status(spdif_priv);
+
+	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 regmap *regmap = spdif_priv->regmap;
+	u32 cstatus, val;
+
+	regmap_read(regmap, REG_SPDIF_SIS, &val);
+	if (!(val & INT_CNEW)) {
+		return -EAGAIN;
+	}
+
+	regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus);
+	ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF;
+	ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF;
+	ucontrol->value.iec958.status[2] = cstatus & 0xFF;
+
+	regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus);
+	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 */
+	regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW);
+
+	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 regmap *regmap = spdif_priv->regmap;
+	u32 val;
+
+	val = regmap_read(regmap, REG_SPDIF_SIS, &val);
+	ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0;
+	regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD);
+
+	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 regmap *regmap = spdif_priv->regmap;
+	struct platform_device *pdev = spdif_priv->pdev;
+	u64 tmpval64, busclk_freq = 0;
+	u32 freqmeas, phaseconf;
+	u8 clksrc;
+
+	regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas);
+	regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf);
+
+	clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
+	if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) {
+		/* Get bus clock from system */
+		busclk_freq = clk_get_rate(spdif_priv->rxclk);
+	}
+
+	/* 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", freqmeas);
+	dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq);
+	dev_dbg(&pdev->dev, "RxRate: %lld\n", 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);
+	int rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL);
+
+	if (spdif_priv->dpll_locked)
+		ucontrol->value.integer.value[0] = rate;
+	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 regmap *regmap = spdif_priv->regmap;
+	u32 val;
+
+	regmap_read(regmap, REG_SPDIF_SRCD, &val);
+	ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0;
+
+	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 regmap *regmap = spdif_priv->regmap;
+	u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET;
+
+	regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val);
+
+	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 = fsl_spdif_info,
+		.get = fsl_spdif_pb_get,
+		.put = fsl_spdif_pb_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",
+};
+
+/*
+ * ================
+ * FSL SPDIF REGMAP
+ * ================
+ */
+
+static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_SPDIF_SCR:
+	case REG_SPDIF_SRCD:
+	case REG_SPDIF_SRPC:
+	case REG_SPDIF_SIE:
+	case REG_SPDIF_SIS:
+	case REG_SPDIF_SRL:
+	case REG_SPDIF_SRR:
+	case REG_SPDIF_SRCSH:
+	case REG_SPDIF_SRCSL:
+	case REG_SPDIF_SRU:
+	case REG_SPDIF_SRQ:
+	case REG_SPDIF_STCSCH:
+	case REG_SPDIF_STCSCL:
+	case REG_SPDIF_SRFM:
+	case REG_SPDIF_STC:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case REG_SPDIF_SCR:
+	case REG_SPDIF_SRCD:
+	case REG_SPDIF_SRPC:
+	case REG_SPDIF_SIE:
+	case REG_SPDIF_SIC:
+	case REG_SPDIF_STL:
+	case REG_SPDIF_STR:
+	case REG_SPDIF_STCSCH:
+	case REG_SPDIF_STCSCL:
+	case REG_SPDIF_STC:
+		return true;
+	default:
+		return false;
+	};
+}
+
+static const struct regmap_config fsl_spdif_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+
+	.max_register = REG_SPDIF_STC,
+	.readable_reg = fsl_spdif_readable_reg,
+	.writeable_reg = fsl_spdif_writeable_reg,
+};
+
+static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
+				struct clk *clk, u64 savesub,
+				enum spdif_txrate index)
+{
+	const u32 rate[] = { 32000, 44100, 48000 };
+	u64 rate_ideal, rate_actual, sub;
+	u32 div, arate;
+
+	for (div = 1; div <= 128; div++) {
+		rate_ideal = rate[index] * (div + 1) * 64;
+		rate_actual = clk_round_rate(clk, rate_ideal);
+
+		arate = rate_actual / 64;
+		arate /= div;
+
+		if (arate == rate[index]) {
+			/* We are lucky */
+			savesub = 0;
+			spdif_priv->txclk_div[index] = div;
+			break;
+		} else if (arate / rate[index] == 1) {
+			/* A little bigger than expect */
+			sub = (arate - rate[index]) * 100000;
+			do_div(sub, rate[index]);
+			if (sub < savesub) {
+				savesub = sub;
+				spdif_priv->txclk_div[index] = div;
+			}
+		} else if (rate[index] / arate == 1) {
+			/* A little smaller than expect */
+			sub = (rate[index] - arate) * 100000;
+			do_div(sub, rate[index]);
+			if (sub < savesub) {
+				savesub = sub;
+				spdif_priv->txclk_div[index] = div;
+			}
+		}
+	}
+
+	return savesub;
+}
+
+static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
+				enum spdif_txrate index)
+{
+	const u32 rate[] = { 32000, 44100, 48000 };
+	struct platform_device *pdev = spdif_priv->pdev;
+	struct device *dev = &pdev->dev;
+	u64 savesub = 100000, ret;
+	struct clk *clk;
+	char tmp[16];
+	int i;
+
+	for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
+		sprintf(tmp, "rxtx%d", i);
+		clk = devm_clk_get(&pdev->dev, tmp);
+		if (IS_ERR(clk)) {
+			dev_err(dev, "no rxtx%d clock in devicetree\n", i);
+			return PTR_ERR(clk);
+		}
+		if (!clk_get_rate(clk))
+			continue;
+
+		ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index);
+		if (savesub == ret)
+			continue;
+
+		savesub = ret;
+		spdif_priv->txclk[index] = clk;
+		spdif_priv->txclk_src[index] = i;
+
+		/* To quick catch a divisor, we allow a 0.1% deviation */
+		if (savesub < 100)
+			break;
+	}
+
+	dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate",
+			spdif_priv->txclk_src[index], rate[index]);
+	dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate",
+			spdif_priv->txclk_div[index], rate[index]);
+
+	return 0;
+}
+
+static int fsl_spdif_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct fsl_spdif_priv *spdif_priv;
+	struct spdif_mixer_control *ctrl;
+	struct resource *res;
+	void __iomem *regs;
+	int irq, ret, i;
+
+	if (!np)
+		return -ENODEV;
+
+	spdif_priv = devm_kzalloc(&pdev->dev,
+			sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1,
+			GFP_KERNEL);
+	if (!spdif_priv)
+		return -ENOMEM;
+
+	strcpy(spdif_priv->name, np->name);
+
+	spdif_priv->pdev = pdev;
+
+	/* 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 */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (IS_ERR(res)) {
+		dev_err(&pdev->dev, "could not determine device resources\n");
+		return PTR_ERR(res);
+	}
+
+	regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(regs)) {
+		dev_err(&pdev->dev, "could not map device resources\n");
+		return PTR_ERR(regs);
+	}
+
+	spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+			"core", regs, &fsl_spdif_regmap_config);
+	if (IS_ERR(spdif_priv->regmap)) {
+		dev_err(&pdev->dev, "regmap init failed\n");
+		return PTR_ERR(spdif_priv->regmap);
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+			spdif_priv->name, spdif_priv);
+	if (ret) {
+		dev_err(&pdev->dev, "could not claim irq %u\n", irq);
+		return ret;
+	}
+
+	/* Select clock source for rx/tx clock */
+	spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
+	if (IS_ERR(spdif_priv->rxclk)) {
+		dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n");
+		return PTR_ERR(spdif_priv->rxclk);
+	}
+	spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC;
+
+	for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
+		ret = fsl_spdif_probe_txclk(spdif_priv, i);
+		if (ret)
+			return ret;
+	}
+
+	/* Initial spinlock for control data */
+	ctrl = &spdif_priv->fsl_spdif_control;
+	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;
+
+	spdif_priv->dpll_locked = false;
+
+	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 = res->start + REG_SPDIF_STL;
+	spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
+
+	/* Register with ASoC */
+	dev_set_drvdata(&pdev->dev, spdif_priv);
+
+	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);
+
+	return ret;
+}
+
+static int fsl_spdif_remove(struct platform_device *pdev)
+{
+	imx_pcm_dma_exit(pdev);
+	snd_soc_unregister_component(&pdev->dev);
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static const struct of_device_id fsl_spdif_dt_ids[] = {
+	{ .compatible = "fsl,imx35-spdif", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
+
+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-dai");
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
new file mode 100644
index 0000000..b126679
--- /dev/null
+++ b/sound/soc/fsl/fsl_spdif.h
@@ -0,0 +1,191 @@
+/*
+ * 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 */
+#define REG_SPDIF_SCR 			0x0	/* SPDIF Configuration Register */
+#define REG_SPDIF_SRCD		 	0x4	/* CDText Control Register */
+#define REG_SPDIF_SRPC			0x8	/* PhaseConfig Register */
+#define REG_SPDIF_SIE			0xc	/* InterruptEn Register */
+#define REG_SPDIF_SIS			0x10	/* InterruptStat Register */
+#define REG_SPDIF_SIC			0x10	/* InterruptClear Register */
+#define REG_SPDIF_SRL			0x14	/* SPDIFRxLeft Register */
+#define REG_SPDIF_SRR			0x18	/* SPDIFRxRight Register */
+#define REG_SPDIF_SRCSH			0x1c	/* SPDIFRxCChannel_h Register */
+#define REG_SPDIF_SRCSL			0x20	/* SPDIFRxCChannel_l Register */
+#define REG_SPDIF_SRU			0x24	/* UchannelRx Register */
+#define REG_SPDIF_SRQ			0x28	/* QchannelRx Register */
+#define REG_SPDIF_STL			0x2C	/* SPDIFTxLeft Register */
+#define REG_SPDIF_STR			0x30	/* SPDIFTxRight Register */
+#define REG_SPDIF_STCSCH		0x34	/* SPDIFTxCChannelCons_h Register */
+#define REG_SPDIF_STCSCL		0x38	/* SPDIFTxCChannelCons_l Register */
+#define REG_SPDIF_SRFM			0x44	/* FreqMeas Register */
+#define REG_SPDIF_STC			0x50	/* 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_OFFSET1	5
+#define SRPC_CLKSRC_SEL_LOCKED_OFFSET2	2
+#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)
+
+#define SRPC_CLKSRC_MAX			16
+
+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)
+#define STC_TXCLK_SRC_MAX		8
+
+/* SPDIF tx rate */
+enum spdif_txrate {
+	SPDIF_TXRATE_32000 = 0,
+	SPDIF_TXRATE_44100,
+	SPDIF_TXRATE_48000,
+};
+#define SPDIF_TXRATE_MAX		(SPDIF_TXRATE_48000 + 1)
+
+
+#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 v10 2/2] ASoC: fsl: Add S/PDIF machine driver
From: Nicolin Chen @ 2013-08-21  3:13 UTC (permalink / raw)
  To: broonie, s.hauer
  Cc: mark.rutland, devicetree, alsa-devel, lars, swarren, festevam,
	timur, rob.herring, tomasz.figa, p.zabel, R65777, shawn.guo,
	linuxppc-dev
In-Reply-To: <cover.1377054540.git.b42378@freescale.com>

This patch implements a device-tree-only machine driver for Freescale
i.MX series Soc. It works with spdif_transmitter/spdif_receiver and
fsl_spdif.c drivers.

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..08a129a
--- /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 codec
+
+  - spdif-receiver : The phandle of the spdif-receiver 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 cd088cc..a708380 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -193,6 +193,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 && 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 v10 0/2] Add freescale S/PDIF CPU DAI and machine drivers
From: Nicolin Chen @ 2013-08-21  3:13 UTC (permalink / raw)
  To: broonie, s.hauer
  Cc: mark.rutland, devicetree, alsa-devel, lars, swarren, festevam,
	timur, rob.herring, tomasz.figa, p.zabel, R65777, shawn.guo,
	linuxppc-dev

Changelog:
v9->v10:
 * Removed "dummy" words from binding doc in PATCH-2.
v8->v9:
 * Use bool instead of atomic_t.
 * Use clk_prepare_enable() instead.
 * Dropped dumpregs().
 * Dropped unnecessary clk_round_rate().
 * Dropped unused clock source enum.
 * Revised dev_err() message.
v7->v8:
 * Revised DT binding doc.
 * Revised dev_err() error msg.
 * Check return value of clk_set_rate().
v6->v7:
 * Removed extra comma in array.
 * Revised some comments.
 * Added some dev_err().
 * Check the return value of soft reset.
 * Use bitrev8() instead of extra reverse_bits().
 * Use cache_bypass as default for regmap.
v5->v6:
 * Sorted out rxtx clk source in DT binding.
 * Use devm_xxxx() functions.
 * Use platform_get_resource() instead.
v4->v5:
 * Dropped rx/tx-clksrc-names DT bindings.
 * Use standard clock binding instead to pass the clock source list.
 * Update the compatible list by using "imx35", the first SoC that has spdif.
v3->v4:
 * Use regmap for CPU DAI driver.
 * Use individual clock source for 32KHz, 44KHz, 48KHz playback.
 * Determine clock source configuration from 'clocks' entry.
 * Added imx53 to compatible list, merged imx6q and imx6dl in the list.
 * Improve the algorism of reverse_bits().
 * Dropped the unneeded clk_put().
v2->v3:
 * Removed a wrong tag from the commit of patch-1.
v1->v2:
 * Dropped one applied patch for spdif dummy codec drivers.
 * Use generic DMA DT binding.
 * Let spdif controller driver calculate the clock div.
 * Added one optional clock source for spdif tx.
 * Reivsed documentation accordingly.

Nicolin Chen (2):
  ASoC: fsl: Add S/PDIF CPU DAI driver
  ASoC: fsl: Add S/PDIF machine driver

 .../devicetree/bindings/sound/fsl,spdif.txt        |   54 +
 .../devicetree/bindings/sound/imx-audio-spdif.txt  |   29 +
 sound/soc/fsl/Kconfig                              |   14 +
 sound/soc/fsl/Makefile                             |    4 +
 sound/soc/fsl/fsl_spdif.c                          | 1236 ++++++++++++++++++++
 sound/soc/fsl/fsl_spdif.h                          |  191 +++
 sound/soc/fsl/imx-spdif.c                          |  134 +++
 7 files changed, 1662 insertions(+), 0 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

* [PATCH v2] powerpc/powernv: Return secondary CPUs to firmware on kexec
From: Benjamin Herrenschmidt @ 2013-08-21  3:03 UTC (permalink / raw)
  To: linuxppc-dev

With OPAL v3 we can return secondary CPUs to firmware on kexec. This
allows firmware to do various cleanups making things generally more
reliable, and will enable the "new" kernel to call OPAL to perform
some reconfiguration tasks early on that can only be done while
all the CPUs are in firmware.

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

v2: Actually applies on top of current kernels rather than some
obscure internal branch :-)

 arch/powerpc/include/asm/opal.h                |  2 ++
 arch/powerpc/platforms/powernv/opal-wrappers.S |  1 +
 arch/powerpc/platforms/powernv/setup.c         | 11 +++++++++++
 3 files changed, 14 insertions(+)

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 029fe85..eebb221 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -124,6 +124,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_PCI_POLL				62
 #define OPAL_PCI_MSI_EOI			63
 #define OPAL_PCI_GET_PHB_DIAG_DATA2		64
+#define OPAL_RETURN_CPU				69
 
 #ifndef __ASSEMBLY__
 
@@ -631,6 +632,7 @@ int64_t opal_set_system_attention_led(uint8_t led_action);
 int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
 			    uint16_t *pci_error_type, uint16_t *severity);
 int64_t opal_pci_poll(uint64_t phb_id);
+int64_t opal_return_cpu(void);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index e88863f..874e5ff 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -111,3 +111,4 @@ OPAL_CALL(opal_pci_next_error,			OPAL_PCI_NEXT_ERROR);
 OPAL_CALL(opal_pci_poll,			OPAL_PCI_POLL);
 OPAL_CALL(opal_pci_msi_eoi,			OPAL_PCI_MSI_EOI);
 OPAL_CALL(opal_pci_get_phb_diag_data2,		OPAL_PCI_GET_PHB_DIAG_DATA2);
+OPAL_CALL(opal_return_cpu,			OPAL_RETURN_CPU);
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 84438af..7e3b464 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -31,6 +31,7 @@
 #include <asm/xics.h>
 #include <asm/rtas.h>
 #include <asm/opal.h>
+#include <asm/kexec.h>
 
 #include "powernv.h"
 
@@ -147,6 +148,16 @@ static void pnv_shutdown(void)
 static void pnv_kexec_cpu_down(int crash_shutdown, int secondary)
 {
 	xics_kexec_teardown_cpu(secondary);
+
+	/* Return secondary CPUs to firmware on OPAL v3 */
+	if (firmware_has_feature(FW_FEATURE_OPALv3) && secondary) {
+		mb();
+		get_paca()->kexec_state = KEXEC_STATE_REAL_MODE;
+		mb();
+
+		/* Return the CPU to OPAL */
+		opal_return_cpu();
+	}
 }
 #endif /* CONFIG_KEXEC */
 

^ permalink raw reply related

* Re: [RFC PATCH V3 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver.
From: Deepthi Dharwar @ 2013-08-21  4:53 UTC (permalink / raw)
  To: Scott Wood
  Cc: Wood Scott-B07421, daniel.lezcano@linaro.org,
	Wang Dongsheng-B40534, preeti@linux.vnet.ibm.com,
	linux-pm@lists.linux-foundation.org,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1376936241.31636.352.camel@snotra.buserror.net>

On 08/19/2013 11:47 PM, Scott Wood wrote:
> On Mon, 2013-08-19 at 15:48 +0530, Deepthi Dharwar wrote:
>> Hi Dongsheng,
>>
>> On 08/19/2013 11:22 AM, Wang Dongsheng-B40534 wrote:
>>> I think we should move the states and handle function to arch/power/platform*
>>> The states and handle function is belong to backend driver, not for this, different platform have different state.
>>> Different platforms to make their own deal with these states.
>>>
>>> I think we cannot put all the status of different platforms and handler in this driver.
>>
>> The idea here is a single powerpc back-end driver, which does a runtime
>> detection of the platform it is running and choose the right
>> idle states table. This was one of outcome of V2 discussion.
> 
> I see a lot more in there than just detecting a platform and choosing a
> driver.
> 
>> I feel there is no harm in keeping the state information in the same
>> file. We do have x86, which has all its variants information in one
>> file. One place will have all the idle consolidated information of
>> all the platform variants. If community does feel, we need to
>> have just the states information in arch specific file, we can do so.
> 
> What actual functionality is common to all powerpc but not common to
> other arches?
> 
>>>> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
>>>> index 0e2cd5c..99ee5d4 100644
>>>> --- a/drivers/cpuidle/Kconfig
>>>> +++ b/drivers/cpuidle/Kconfig
>>>> @@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ
>>>>  	help
>>>>  	  Select this to enable cpuidle on Xilinx Zynq processors.
>>>>
>>>> +config CPU_IDLE_POWERPC
>>>> +	bool "CPU Idle driver for POWERPC platforms"
>>>> +	depends on PPC64
>>>
>>> Why not PPC?
>>
>> PPC64 seems to a good place to began the consolidation work. This
>> patch-set has not been tested for PPC32 currently.
> 
> PPC64 is a bad place to start if you want it to be generic, because it
> means you'll end up growing dependencies on other things that are PPC64
> only.  There are too many arbitrary 32/64 differences as is.

Hi Scott,

>From my understanding, PPC64 includes BOOK3E and BOOK3S archs.
PPC includes PPC32 and PPC64.

It seemed logical to start consolidating at PPC64 as
one does not want to get into 32/64 bit differences.

>From your comments above,  I just wanted to clarify if PPC or PPC64 is
bad place to start. If PPC64 is bad place to start, then whats the way
forward ?  Can you please throw some more light on it.

Thanks!
Deepthi



> -Scott
> 
> 
> 
> 

^ permalink raw reply

* Re: linux-next: build failure after merge of the final tree
From: Dwight Engen @ 2013-08-21  5:08 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: cbe-oss-dev, Stephen Rothwell, linux-kernel, xfs, Ben Myers,
	linux-next, Gao feng, linuxppc-dev, Jeremy Kerr
In-Reply-To: <201308202246.30869.arnd@arndb.de>

On Tue, 20 Aug 2013 22:46:30 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> On Tuesday 20 August 2013, Dwight Engen wrote:
> > diff --git a/arch/powerpc/platforms/cell/spufs/inode.c
> > b/arch/powerpc/platforms/cell/spufs/inode.c index f390042..90fb308
> > 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c
> > +++ b/arch/powerpc/platforms/cell/spufs/inode.c
> > @@ -620,12 +620,12 @@ spufs_parse_options(struct super_block *sb,
> > char *options, struct inode *root) case Opt_uid:
> >                         if (match_int(&args[0], &option))
> >                                 return 0;
> > -                       root->i_uid = option;
> > +                       root->i_uid = make_kuid(&init_user_ns,
> > option); break;
> >                 case Opt_gid:
> >                         if (match_int(&args[0], &option))
> >                                 return 0;
> > -                       root->i_gid = option;
> > +                       root->i_gid = make_kgid(&init_user_ns,
> > option); break;
> >                 case Opt_mode:
> >                         if (match_octal(&args[0], &option))
> 
> Doesn't this mean the uid/gid is taken from the initial namespace
> rather than from the namespace of the 'mount' process calling this? I
> think the logical choice would be to have the UID be the one that
> gets passed here in the caller's namespace.

Yes, I agree. The other filesystems that take an Opt_uid as well do use
current_user_ns() and not init_user_ns. They also do a uid_valid()
check and fail the mount (or fallback to GLOBAL_ROOT_UID). So I think
that would look like this:

diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index f390042..87ba7cf 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -620,12 +620,16 @@ spufs_parse_options(struct super_block *sb, char *options, struct inode *root)
                case Opt_uid:
                        if (match_int(&args[0], &option))
                                return 0;
-                       root->i_uid = option;
+                       root->i_uid = make_kuid(current_user_ns(), option);
+                       if (!uid_valid(root->i_uid))
+                               return 0;
                        break;
                case Opt_gid:
                        if (match_int(&args[0], &option))
                                return 0;
-                       root->i_gid = option;
+                       root->i_gid = make_kgid(current_user_ns(), option);
+                       if (!gid_valid(root->i_gid))
+                               return 0;
                        break;
                case Opt_mode:
                        if (match_octal(&args[0], &option))

Again, I have not run tested this so we may just want to disable SPU_FS
with USER_NS until they can be tested together.

^ permalink raw reply related

* Re: [RFC PATCH 2/4] openrisc: remove undefined of_get_cpu_node declaration
From: Jonas Bonn @ 2013-08-21  5:10 UTC (permalink / raw)
  To: Sudeep KarkadaNagesha
  Cc: devicetree@vger.kernel.org, Michal Simek,
	linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org,
	rob.herring@calxeda.com, Rafael J. Wysocki,
	grant.likely@linaro.org, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <520DF3BD.2070904@arm.com>

On 08/16/13 11:41, Sudeep KarkadaNagesha wrote:
> On 15/08/13 18:09, Sudeep KarkadaNagesha wrote:
>> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>>
>> This patch removes the declaration of the function 'of_get_cpu_node'
>> which is not defined for openrisc. This is in preparation to move
>> it's definition from PPC to DT common code.
>>
>> Again it could be there as it was originally copied from powerpc.
>>
>> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>> Cc: Jonas Bonn <jonas@southpole.se>
> Hi Jonas,
>
> Since both microblaze and openrisc have moderated lists which I am not
> member of, these patches were blocked. Michal Simek agreed to remove
> this for microblaze. Do you see any concern with this patch for openrisc
> ? Can I have you ACK if it looks fine ?

Hi Sudeep,
Yes, thanks, the patch looks good.

Acked-by: Jonas Bonn <jonas@southpole.se>

/Jonas

>
> Regards,
> Sudeep
>> ---
>>   arch/openrisc/include/asm/prom.h | 3 ---
>>   1 file changed, 3 deletions(-)
>>
>> diff --git a/arch/openrisc/include/asm/prom.h b/arch/openrisc/include/asm/prom.h
>> index bbb34e5..eb59bfe 100644
>> --- a/arch/openrisc/include/asm/prom.h
>> +++ b/arch/openrisc/include/asm/prom.h
>> @@ -44,9 +44,6 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>>   
>>   extern void kdump_move_device_tree(void);
>>   
>> -/* CPU OF node matching */
>> -struct device_node *of_get_cpu_node(int cpu, unsigned int *thread);
>> -
>>   /* Get the MAC address */
>>   extern const void *of_get_mac_address(struct device_node *np);
>>   
>>
>

^ permalink raw reply

* Re: linux-next: build failure after merge of the final tree
From: Jeremy Kerr @ 2013-08-21  6:30 UTC (permalink / raw)
  To: Dwight Engen
  Cc: cbe-oss-dev, Stephen Rothwell, Arnd Bergmann, linux-kernel, xfs,
	Ben Myers, linux-next, Gao feng, linuxppc-dev
In-Reply-To: <20130821010822.220f592a@oracle.com>

Hi all,

> Yes, I agree. The other filesystems that take an Opt_uid as well do use
> current_user_ns() and not init_user_ns. They also do a uid_valid()
> check and fail the mount (or fallback to GLOBAL_ROOT_UID). So I think
> that would look like this:

Looks good to me. Builds and mounts as expected.

Acked-by: Jeremy Kerr <jk@ozlabs.org>

Cheers,


Jeremy

^ permalink raw reply

* Re: [PATCH v7 0/3] DMA: Freescale: Add support for 8-channel DMA engine
From: Hongbo Zhang @ 2013-08-21  6:59 UTC (permalink / raw)
  To: Vinod Koul, devicetree, rob.herring, pawel.moll, mark.rutland,
	swarren, ian.campbell
  Cc: linux-kernel, grant.likely, djbw, scottwood, linuxppc-dev
In-Reply-To: <20130820081522.GC5810@intel.com>

Hi DT maintainers,
Rob Herring, Pawel Moll, Mark Rutland, Stephen Warren, Ian Campbell, 
could you please have a look at [1/3] and [2/3] of these patch set.
These patches have been fully reviewed by Scott Wood, and the DMA 
maintainer Vinod needs a Acted-by: from DT maintainers.
Thanks.

On 08/20/2013 04:15 PM, Vinod Koul wrote:
> On Tue, Aug 20, 2013 at 04:33:46PM +0800, Hongbo Zhang wrote:
>> On 07/29/2013 06:59 PM, Vinod Koul wrote:
>>> On Mon, Jul 29, 2013 at 06:49:01PM +0800, hongbo.zhang@freescale.com wrote:
>>>> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>>>>
>>>> Hi Vinod, Dan, Scott and Leo, please have a look at these V7 patches.
>>> The dma relates changes look okay to me.
>>>
>>> I need someone to review and ACK the DT bindings.
>>>
>>> ~Vinod
>> Vinod,
>> Are you using this tree?
>> http://git.infradead.org/users/vkoul/slave-dma.git
> Yes
>
>> Did you merge these patches?
> No
>
> As I said I would like someone who know DT and dma binding to ack them. I see
> devicetree ML has been cced, can Arnd or someone else review these...
>
> ~Vinod
>

^ permalink raw reply

* [PATCH 2/8] net: ucc_geth: remove unnecessary dev_set_drvdata()
From: Libo Chen @ 2013-08-21  7:02 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-kernel, libo.chen, lizefan, linuxppc-dev

Unnecessary dev_set_drvdata() is removed, because the driver core
clears the driver data to NULL after device_release or on probe failure.

Signed-off-by: Libo Chen <libo.chen@huawei.com>
---
 drivers/net/ethernet/freescale/ucc_geth.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 533885c..5930c39 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -3917,7 +3917,6 @@ static int ucc_geth_remove(struct platform_device* ofdev)
 	unregister_netdev(dev);
 	free_netdev(dev);
 	ucc_geth_memclean(ugeth);
-	dev_set_drvdata(device, NULL);
 
 	return 0;
 }
-- 
1.7.1

^ permalink raw reply related

* [PATCH 0/8] net: remove unnecessary dev_set_drvdata()
From: Libo Chen @ 2013-08-21  7:05 UTC (permalink / raw)
  To: davem
  Cc: mugunthanvnm, sergei.shtylyov, netdev, jg1.han, libo.chen,
	lizefan, gregkh, linuxppc-dev

Unnecessary dev_set_drvdata() is removed, because the driver core
clears the driver data to NULL after device_release or on probe failure.

Libo Chen (8):
  net: fsl_pq_mdio: remove unnecessary dev_set_drvdata()
  net: ucc_geth: remove unnecessary dev_set_drvdata()
  net: fec_mpc52xx_phy: remove unnecessary dev_set_drvdata()
  net: sunbmac: remove unnecessary dev_set_drvdata()
  net: sunhme: remove unnecessary dev_set_drvdata()
  net: xilinx_emaclite: remove unnecessary dev_set_drvdata()
  net: davinci_mdio: remove unnecessary dev_set_drvdata()
  net: emac: remove unnecessary dev_set_drvdata()

 drivers/net/ethernet/freescale/fec_mpc52xx_phy.c |    1 -
 drivers/net/ethernet/freescale/fsl_pq_mdio.c     |    2 --
 drivers/net/ethernet/freescale/ucc_geth.c        |    1 -
 drivers/net/ethernet/ibm/emac/core.c             |    2 --
 drivers/net/ethernet/sun/sunbmac.c               |    2 --
 drivers/net/ethernet/sun/sunhme.c                |    2 --
 drivers/net/ethernet/ti/davinci_mdio.c           |    2 --
 drivers/net/ethernet/xilinx/xilinx_emaclite.c    |    1 -
 8 files changed, 0 insertions(+), 13 deletions(-)

^ permalink raw reply

* Re: [PATCH] Kconfig: Remove hotplug enable hints in CONFIG_KEXEC help texts
From: Ingo Molnar @ 2013-08-21  7:26 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Stephen Rothwell, x86, linux-ia64, linux-mips, Greg Kroah-Hartman,
	linux-sh, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <1377027483-17025-1-git-send-email-geert@linux-m68k.org>


* Geert Uytterhoeven <geert@linux-m68k.org> wrote:

> commit 40b313608ad4ea655addd2ec6cdd106477ae8e15 ("Finally eradicate
> CONFIG_HOTPLUG") removed remaining references to CONFIG_HOTPLUG, but missed
> a few plain English references in the CONFIG_KEXEC help texts.
> 
> Remove them, too.
> 
> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
> ---
>  arch/arm/Kconfig     |    3 +--
>  arch/ia64/Kconfig    |    6 +++---
>  arch/mips/Kconfig    |    6 +++---
>  arch/powerpc/Kconfig |    6 +++---
>  arch/sh/Kconfig      |    6 +++---
>  arch/x86/Kconfig     |    6 +++---
>  6 files changed, 16 insertions(+), 17 deletions(-)
[...]
>  	bool "kernel crash dumps (EXPERIMENTAL)"
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index b32ebf9..6ace5de 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1627,9 +1627,9 @@ config KEXEC
>  
>  	  It is an ongoing process to be certain the hardware in a machine
>  	  is properly shutdown, so do not be surprised if this code does not
> -	  initially work for you.  It may help to enable device hotplugging
> -	  support.  As of this writing the exact hardware interface is
> -	  strongly in flux, so no good recommendation can be made.
> +	  initially work for you.  As of this writing the exact hardware
> +	  interface is strongly in flux, so no good recommendation can be
> +	  made.
>  
>  config CRASH_DUMP
>  	bool "kernel crash dumps"

Acked-by: Ingo Molnar <mingo@kernel.org>

Thanks,

	Ingo

^ permalink raw reply

* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Mark Rutland @ 2013-08-21  8:50 UTC (permalink / raw)
  To: Mike Turquette
  Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org,
	lars@metafoo.de, ian.campbell@citrix.com, Pawel Moll,
	swarren@wwwdotorg.org, festevam@gmail.com, Sascha Hauer,
	Nicolin Chen, Tomasz Figa, rob.herring@calxeda.com,
	timur@tabi.org, broonie@kernel.org, p.zabel@pengutronix.de,
	galak@codeaurora.org, shawn.guo@linaro.org,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20130820000625.4443.23018@quantum>

On Tue, Aug 20, 2013 at 01:06:25AM +0100, Mike Turquette wrote:
> Quoting Mark Rutland (2013-08-19 02:35:43)
> > On Sat, Aug 17, 2013 at 04:17:18PM +0100, Tomasz Figa wrote:
> > > On Saturday 17 of August 2013 16:53:16 Sascha Hauer wrote:
> > > > On Sat, Aug 17, 2013 at 02:28:04PM +0200, Tomasz Figa wrote:
> > > > > > > > Also I would make this option required. Use a dummy clock for
> > > > > > > > mux
> > > > > > > > inputs that are grounded for a specific SoC.
> > > > > > > 
> > > > > > > Some clocks are not from CCM and we haven't defined in
> > > > > > > imx6q-clk.txt,
> > > > > > > so in most cases we can't provide a phandle for them, eg:
> > > > > > > spdif_ext.
> > > > > > > I think it's a bit hard to force it to be 'required'. An
> > > > > > > 'optional'
> > > > > > > looks more flexible to me and a default one is ensured even if
> > > > > > > it's
> > > > > > > missing.
> > > > > > 
> > > > > > <&clks 0> is the dummy clock. This can be used for all input clocks
> > > > > > not
> > > > > > defined by the SoC.
> > > > > 
> > > > > Where does this assumption come from? Is it documented anywhere?
> > > > 
> > > > This is how all i.MX clock bindings currently are. See
> > > > Documentation/devicetree/bindings/clock/imx*-clock.txt
> > > 
> > > OK, thanks.
> > > 
> > > I guess we need some discussion on dummy clocks vs skipped clocks. I think 
> > > we want some consistency on this, don't we?
> > > 
> > > If we really need a dummy clock, then we might also want a generic way to 
> > > specify it.
> > 
> > What do we actually mean by a "dummy clock"? We already have bindings
> > for "fixed-clock" and co friends describe relatively simple
> > preconfigured clocks.
> 
> Some platforms have a fake clock which defines noops callbacks and
> basically doesn't do anything. This is analogous to the dummy regulator
> implementation. A central one could be registered by the clock core, as
> is done by the regulator core.

When you say some platforms, you presumably mean the platform code in
Linux? A dummy clock sounds like a completely Linux-specific abstraction
rather than a description of the hardware, and I don't see why we need
that in the DT:

* If a clock is wired up and running (as presumably the dummy clock is),
  then surely it's a fixed-clock (it's running, we and we have no
  control over it, but we presumably know its rate) and can be described
  as such?

* If no clock is wired up, then we should be able to describe that. If a
  driver believes that a clock is required when it isn't (for some level
  of functionality), then that driver should be fixed up to support the
  clock as being optional.

Am I missing something?

Thanks,
Mark.

^ permalink raw reply

* [PATCH] Device Tree bindings for DSP clusters and DSP CPUs
From: Poonam Aggrwal @ 2013-08-21  9:25 UTC (permalink / raw)
  To: devicetree, linuxppc-dev; +Cc: Poonam Aggrwal

Binding for DSP CPU clusters and DSP CPUs for Freescale SOCs which
have DSP CPUs in addition to PowerPC CPUs. For example B4860.

Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com>
---
 .../devicetree/bindings/powerpc/fsl/dsp-cpus.txt   |   78 ++++++++++++++++++++
 1 files changed, 78 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/powerpc/fsl/dsp-cpus.txt

diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dsp-cpus.txt b/Documentation/devicetree/bindings/powerpc/fsl/dsp-cpus.txt
new file mode 100644
index 0000000..da7f5d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/dsp-cpus.txt
@@ -0,0 +1,78 @@
+===================================================================
+Binding for DSP CPU clusters and DSP CPUs for Freescale SOCs which
+have DSP CPUs in addition to PowerPC cpus.
+Copyright 2013 Freescale Semiconductor Inc.
+
+Power Architecture CPUs in Freescale SOCs are represented in device trees as
+per the definition in ePAPR.
+
+Required properties for DSP CPU cluster:
+- compatible : should be "fsl,dsp-cluster" or "fsl,sc3900-cluster".
+- reg : should contain the cluster index
+
+Required properties for DSP CPU:
+- compatible : should be "fsl,dsp" or "fsl,sc3900".
+- reg : should contain index of DSP CPU within the DSP clsuter. 
+- next-level-cache : should point to the phandle of the next-level L2 cache.
+
+Example for B4860:
+B4860 SOC of Freescale has 3 DSP clusters. Each DSP cluster has 2 DSP CPUs each.
+The DSP CPUs are SC3900. There is a shared L2 cache per DSP cluster.
+	dsp-clusters {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		dsp-cluster0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,sc3900-cluster";
+			reg = <0>;
+
+			dsp0: dsp@0 {
+				compatible = "fsl,sc3900";
+				reg = <0>;
+				next-level-cache = <&L2_2>;
+			};
+			dsp1: dsp@1 {
+				compatible = "fsl,sc3900";
+				reg = <1>;
+				next-level-cache = <&L2_2>;
+			};
+		};
+
+		dsp-cluster1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,sc3900-cluster";
+			reg = <1>;
+
+			dsp2: dsp@2 {
+				compatible = "fsl,sc3900";
+				reg = <2>;
+				next-level-cache = <&L2_3>;
+			};
+			dsp3: dsp@3 {
+				compatible = "fsl,sc3900";
+				reg = <3>;
+				next-level-cache = <&L2_3>;
+			};
+		};
+
+		dsp-cluster2 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,sc3900-cluster";
+			reg = <2>;
+
+			dsp4: dsp@4 {
+				compatible = "fsl,sc3900";
+				reg = <4>;
+				next-level-cache = <&L2_4>;
+			};
+			dsp5: dsp@5 {
+				compatible = "fsl,sc3900";
+				reg = <5>;
+				next-level-cache = <&L2_4>;
+			};
+		};
+	};
-- 
1.7.4.1

^ permalink raw reply related


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