LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/4] Series short description
From: Grant Likely @ 2009-05-25 14:41 UTC (permalink / raw)
  To: linuxppc-dev, Roderick Colenbrander

Repost of ml510 series.  This time against 2.6.30-rc7 and with the .dts
file included.

g.

--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* [PATCH v5 3/4] powerpc/virtex: Add Xilinx ML510 reference design support
From: Grant Likely @ 2009-05-25 14:41 UTC (permalink / raw)
  To: linuxppc-dev, Roderick Colenbrander
In-Reply-To: <20090525144023.13016.23071.stgit@localhost.localdomain>

From: Roderick Colenbrander <thunderbird2k@gmail.com>

Signed-off-by: Roderick Colenbrander <thunderbird2k@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 arch/powerpc/platforms/44x/Kconfig        |   13 ++++++++++++-
 arch/powerpc/platforms/44x/Makefile       |    1 +
 arch/powerpc/platforms/44x/virtex_ml510.c |   29 +++++++++++++++++++++++++++++
 arch/powerpc/sysdev/xilinx_intc.c         |    5 +++++
 4 files changed, 47 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/platforms/44x/virtex_ml510.c


diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 0d83a6a..90e3192 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -156,7 +156,7 @@ config YOSEMITE
 #	  This option enables support for the IBM PPC440GX evaluation board.
 
 config XILINX_VIRTEX440_GENERIC_BOARD
-	bool "Generic Xilinx Virtex 440 board"
+	bool "Generic Xilinx Virtex 5 FXT board support"
 	depends on 44x
 	default n
 	select XILINX_VIRTEX_5_FXT
@@ -171,6 +171,17 @@ config XILINX_VIRTEX440_GENERIC_BOARD
 	  Most Virtex 5 designs should use this unless it needs to do some
 	  special configuration at board probe time.
 
+config XILINX_ML510
+	bool "Xilinx ML510 extra support"
+	depends on XILINX_VIRTEX440_GENERIC_BOARD
+	select PPC_PCI_CHOICE
+	select XILINX_PCI if PCI
+	select PPC_INDIRECT_PCI if PCI
+	select PPC_I8259 if PCI
+	help
+	  This option enables extra support for features on the Xilinx ML510
+	  board.  The ML510 has a PCI bus with ALI south bridge.
+
 config PPC44x_SIMPLE
 	bool "Simple PowerPC 44x board support"
 	depends on 44x
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 01f51da..ee6185a 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_EBONY)	+= ebony.o
 obj-$(CONFIG_SAM440EP) 	+= sam440ep.o
 obj-$(CONFIG_WARP)	+= warp.o
 obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
+obj-$(CONFIG_XILINX_ML510) += virtex_ml510.o
diff --git a/arch/powerpc/platforms/44x/virtex_ml510.c b/arch/powerpc/platforms/44x/virtex_ml510.c
new file mode 100644
index 0000000..ba4a6e3
--- /dev/null
+++ b/arch/powerpc/platforms/44x/virtex_ml510.c
@@ -0,0 +1,29 @@
+#include <asm/i8259.h>
+#include <linux/pci.h>
+#include "44x.h"
+
+/**
+ * ml510_ail_quirk
+ */
+static void __devinit ml510_ali_quirk(struct pci_dev *dev)
+{
+	/* Enable the IDE controller */
+	pci_write_config_byte(dev, 0x58, 0x4c);
+	/* Assign irq 14 to the primary ide channel */
+	pci_write_config_byte(dev, 0x44, 0x0d);
+	/* Assign irq 15 to the secondary ide channel */
+	pci_write_config_byte(dev, 0x75, 0x0f);
+	/* Set the ide controller in native mode */
+	pci_write_config_byte(dev, 0x09, 0xff);
+
+	/* INTB = disabled, INTA = disabled */
+	pci_write_config_byte(dev, 0x48, 0x00);
+	/* INTD = disabled, INTC = disabled */
+	pci_write_config_byte(dev, 0x4a, 0x00);
+	/* Audio = INT7, Modem = disabled. */
+	pci_write_config_byte(dev, 0x4b, 0x60);
+	/* USB = INT7 */
+	pci_write_config_byte(dev, 0x74, 0x06);
+}
+DECLARE_PCI_FIXUP_EARLY(0x10b9, 0x1533, ml510_ali_quirk);
+
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index 90b5772..3ee1fd3 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -257,6 +257,11 @@ static void __init xilinx_i8259_setup_cascade(void)
 	i8259_init(cascade_node, 0);
 	set_irq_chained_handler(cascade_irq, xilinx_i8259_cascade);
 
+	/* Program irq 7 (usb/audio), 14/15 (ide) to level sensitive */
+	/* This looks like a dirty hack to me --gcl */
+	outb(0xc0, 0x4d0);
+	outb(0xc0, 0x4d1);
+
  out:
 	of_node_put(cascade_node);
 }

^ permalink raw reply related

* [PATCH v5 4/4] powerpc/virtex: Add ml510 reference design device tree
From: Grant Likely @ 2009-05-25 14:41 UTC (permalink / raw)
  To: linuxppc-dev, Roderick Colenbrander
In-Reply-To: <20090525144023.13016.23071.stgit@localhost.localdomain>

From: Roderick Colenbrander <thunderbird2k@gmail.com>

As subject says, add dts files for Xilinx ML510 reference design with
the PCI host bridge device.

Signed-off-by: Roderick Colenbrander <thunderbird2k@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 arch/powerpc/boot/dts/virtex440-ml510.dts |  465 +++++++++++++++++++++++++++++
 1 files changed, 465 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/virtex440-ml510.dts


diff --git a/arch/powerpc/boot/dts/virtex440-ml510.dts b/arch/powerpc/boot/dts/virtex440-ml510.dts
new file mode 100644
index 0000000..81a8dc2
--- /dev/null
+++ b/arch/powerpc/boot/dts/virtex440-ml510.dts
@@ -0,0 +1,465 @@
+/*
+ * Xilinx ML510 Reference Design support
+ *
+ * This DTS file was created for the ml510_bsb1_pcores_ppc440 reference design.
+ * The reference design contains a bug which prevent PCI DMA from working
+ * properly.  A description of the bug is given in the plbv46_pci section. It
+ * needs to be fixed by the user until Xilinx updates their reference design.
+ *
+ * Copyright 2009, Roderick Colenbrander
+ */
+
+/dts-v1/;
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "xlnx,ml510-ref-design", "xlnx,virtex440";
+	dcr-parent = <&ppc440_0>;
+	DDR2_SDRAM_DIMM0: memory@0 {
+		device_type = "memory";
+		reg = < 0x0 0x20000000 >;
+	} ;
+	alias {
+		ethernet0 = &Hard_Ethernet_MAC;
+		serial0 = &RS232_Uart_1;
+	} ;
+	chosen {
+		bootargs = "console=ttyS0 root=/dev/ram";
+		linux,stdout-path = "/plb@0/serial@83e00000";
+	} ;
+	cpus {
+		#address-cells = <1>;
+		#cpus = <0x1>;
+		#size-cells = <0>;
+		ppc440_0: cpu@0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clock-frequency = <300000000>;
+			compatible = "PowerPC,440", "ibm,ppc440";
+			d-cache-line-size = <0x20>;
+			d-cache-size = <0x8000>;
+			dcr-access-method = "native";
+			dcr-controller ;
+			device_type = "cpu";
+			i-cache-line-size = <0x20>;
+			i-cache-size = <0x8000>;
+			model = "PowerPC,440";
+			reg = <0>;
+			timebase-frequency = <300000000>;
+			xlnx,apu-control = <0x2000>;
+			xlnx,apu-udi-0 = <0x0>;
+			xlnx,apu-udi-1 = <0x0>;
+			xlnx,apu-udi-10 = <0x0>;
+			xlnx,apu-udi-11 = <0x0>;
+			xlnx,apu-udi-12 = <0x0>;
+			xlnx,apu-udi-13 = <0x0>;
+			xlnx,apu-udi-14 = <0x0>;
+			xlnx,apu-udi-15 = <0x0>;
+			xlnx,apu-udi-2 = <0x0>;
+			xlnx,apu-udi-3 = <0x0>;
+			xlnx,apu-udi-4 = <0x0>;
+			xlnx,apu-udi-5 = <0x0>;
+			xlnx,apu-udi-6 = <0x0>;
+			xlnx,apu-udi-7 = <0x0>;
+			xlnx,apu-udi-8 = <0x0>;
+			xlnx,apu-udi-9 = <0x0>;
+			xlnx,dcr-autolock-enable = <0x1>;
+			xlnx,dcu-rd-ld-cache-plb-prio = <0x0>;
+			xlnx,dcu-rd-noncache-plb-prio = <0x0>;
+			xlnx,dcu-rd-touch-plb-prio = <0x0>;
+			xlnx,dcu-rd-urgent-plb-prio = <0x0>;
+			xlnx,dcu-wr-flush-plb-prio = <0x0>;
+			xlnx,dcu-wr-store-plb-prio = <0x0>;
+			xlnx,dcu-wr-urgent-plb-prio = <0x0>;
+			xlnx,dma0-control = <0x0>;
+			xlnx,dma0-plb-prio = <0x0>;
+			xlnx,dma0-rxchannelctrl = <0x1010000>;
+			xlnx,dma0-rxirqtimer = <0x3ff>;
+			xlnx,dma0-txchannelctrl = <0x1010000>;
+			xlnx,dma0-txirqtimer = <0x3ff>;
+			xlnx,dma1-control = <0x0>;
+			xlnx,dma1-plb-prio = <0x0>;
+			xlnx,dma1-rxchannelctrl = <0x1010000>;
+			xlnx,dma1-rxirqtimer = <0x3ff>;
+			xlnx,dma1-txchannelctrl = <0x1010000>;
+			xlnx,dma1-txirqtimer = <0x3ff>;
+			xlnx,dma2-control = <0x0>;
+			xlnx,dma2-plb-prio = <0x0>;
+			xlnx,dma2-rxchannelctrl = <0x1010000>;
+			xlnx,dma2-rxirqtimer = <0x3ff>;
+			xlnx,dma2-txchannelctrl = <0x1010000>;
+			xlnx,dma2-txirqtimer = <0x3ff>;
+			xlnx,dma3-control = <0x0>;
+			xlnx,dma3-plb-prio = <0x0>;
+			xlnx,dma3-rxchannelctrl = <0x1010000>;
+			xlnx,dma3-rxirqtimer = <0x3ff>;
+			xlnx,dma3-txchannelctrl = <0x1010000>;
+			xlnx,dma3-txirqtimer = <0x3ff>;
+			xlnx,endian-reset = <0x0>;
+			xlnx,generate-plb-timespecs = <0x1>;
+			xlnx,icu-rd-fetch-plb-prio = <0x0>;
+			xlnx,icu-rd-spec-plb-prio = <0x0>;
+			xlnx,icu-rd-touch-plb-prio = <0x0>;
+			xlnx,interconnect-imask = <0xffffffff>;
+			xlnx,mplb-allow-lock-xfer = <0x1>;
+			xlnx,mplb-arb-mode = <0x0>;
+			xlnx,mplb-awidth = <0x20>;
+			xlnx,mplb-counter = <0x500>;
+			xlnx,mplb-dwidth = <0x80>;
+			xlnx,mplb-max-burst = <0x8>;
+			xlnx,mplb-native-dwidth = <0x80>;
+			xlnx,mplb-p2p = <0x0>;
+			xlnx,mplb-prio-dcur = <0x2>;
+			xlnx,mplb-prio-dcuw = <0x3>;
+			xlnx,mplb-prio-icu = <0x4>;
+			xlnx,mplb-prio-splb0 = <0x1>;
+			xlnx,mplb-prio-splb1 = <0x0>;
+			xlnx,mplb-read-pipe-enable = <0x1>;
+			xlnx,mplb-sync-tattribute = <0x0>;
+			xlnx,mplb-wdog-enable = <0x1>;
+			xlnx,mplb-write-pipe-enable = <0x1>;
+			xlnx,mplb-write-post-enable = <0x1>;
+			xlnx,num-dma = <0x0>;
+			xlnx,pir = <0xf>;
+			xlnx,ppc440mc-addr-base = <0x0>;
+			xlnx,ppc440mc-addr-high = <0x1fffffff>;
+			xlnx,ppc440mc-arb-mode = <0x0>;
+			xlnx,ppc440mc-bank-conflict-mask = <0x1800000>;
+			xlnx,ppc440mc-control = <0xf810008f>;
+			xlnx,ppc440mc-max-burst = <0x8>;
+			xlnx,ppc440mc-prio-dcur = <0x2>;
+			xlnx,ppc440mc-prio-dcuw = <0x3>;
+			xlnx,ppc440mc-prio-icu = <0x4>;
+			xlnx,ppc440mc-prio-splb0 = <0x1>;
+			xlnx,ppc440mc-prio-splb1 = <0x0>;
+			xlnx,ppc440mc-row-conflict-mask = <0x7ffe00>;
+			xlnx,ppcdm-asyncmode = <0x0>;
+			xlnx,ppcds-asyncmode = <0x0>;
+			xlnx,user-reset = <0x0>;
+		} ;
+	} ;
+	plb_v46_0: plb@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "xlnx,plb-v46-1.03.a", "simple-bus";
+		ranges ;
+		FLASH: flash@fc000000 {
+			bank-width = <2>;
+			compatible = "xlnx,xps-mch-emc-2.00.a", "cfi-flash";
+			reg = < 0xfc000000 0x2000000 >;
+			xlnx,family = "virtex5";
+			xlnx,include-datawidth-matching-0 = <0x1>;
+			xlnx,include-datawidth-matching-1 = <0x0>;
+			xlnx,include-datawidth-matching-2 = <0x0>;
+			xlnx,include-datawidth-matching-3 = <0x0>;
+			xlnx,include-negedge-ioregs = <0x0>;
+			xlnx,include-plb-ipif = <0x1>;
+			xlnx,include-wrbuf = <0x1>;
+			xlnx,max-mem-width = <0x10>;
+			xlnx,mch-native-dwidth = <0x20>;
+			xlnx,mch-plb-clk-period-ps = <0x2710>;
+			xlnx,mch-splb-awidth = <0x20>;
+			xlnx,mch0-accessbuf-depth = <0x10>;
+			xlnx,mch0-protocol = <0x0>;
+			xlnx,mch0-rddatabuf-depth = <0x10>;
+			xlnx,mch1-accessbuf-depth = <0x10>;
+			xlnx,mch1-protocol = <0x0>;
+			xlnx,mch1-rddatabuf-depth = <0x10>;
+			xlnx,mch2-accessbuf-depth = <0x10>;
+			xlnx,mch2-protocol = <0x0>;
+			xlnx,mch2-rddatabuf-depth = <0x10>;
+			xlnx,mch3-accessbuf-depth = <0x10>;
+			xlnx,mch3-protocol = <0x0>;
+			xlnx,mch3-rddatabuf-depth = <0x10>;
+			xlnx,mem0-width = <0x10>;
+			xlnx,mem1-width = <0x20>;
+			xlnx,mem2-width = <0x20>;
+			xlnx,mem3-width = <0x20>;
+			xlnx,num-banks-mem = <0x1>;
+			xlnx,num-channels = <0x2>;
+			xlnx,priority-mode = <0x0>;
+			xlnx,synch-mem-0 = <0x0>;
+			xlnx,synch-mem-1 = <0x0>;
+			xlnx,synch-mem-2 = <0x0>;
+			xlnx,synch-mem-3 = <0x0>;
+			xlnx,synch-pipedelay-0 = <0x2>;
+			xlnx,synch-pipedelay-1 = <0x2>;
+			xlnx,synch-pipedelay-2 = <0x2>;
+			xlnx,synch-pipedelay-3 = <0x2>;
+			xlnx,tavdv-ps-mem-0 = <0x1adb0>;
+			xlnx,tavdv-ps-mem-1 = <0x3a98>;
+			xlnx,tavdv-ps-mem-2 = <0x3a98>;
+			xlnx,tavdv-ps-mem-3 = <0x3a98>;
+			xlnx,tcedv-ps-mem-0 = <0x1adb0>;
+			xlnx,tcedv-ps-mem-1 = <0x3a98>;
+			xlnx,tcedv-ps-mem-2 = <0x3a98>;
+			xlnx,tcedv-ps-mem-3 = <0x3a98>;
+			xlnx,thzce-ps-mem-0 = <0x88b8>;
+			xlnx,thzce-ps-mem-1 = <0x1b58>;
+			xlnx,thzce-ps-mem-2 = <0x1b58>;
+			xlnx,thzce-ps-mem-3 = <0x1b58>;
+			xlnx,thzoe-ps-mem-0 = <0x1b58>;
+			xlnx,thzoe-ps-mem-1 = <0x1b58>;
+			xlnx,thzoe-ps-mem-2 = <0x1b58>;
+			xlnx,thzoe-ps-mem-3 = <0x1b58>;
+			xlnx,tlzwe-ps-mem-0 = <0x88b8>;
+			xlnx,tlzwe-ps-mem-1 = <0x0>;
+			xlnx,tlzwe-ps-mem-2 = <0x0>;
+			xlnx,tlzwe-ps-mem-3 = <0x0>;
+			xlnx,twc-ps-mem-0 = <0x1adb0>;
+			xlnx,twc-ps-mem-1 = <0x3a98>;
+			xlnx,twc-ps-mem-2 = <0x3a98>;
+			xlnx,twc-ps-mem-3 = <0x3a98>;
+			xlnx,twp-ps-mem-0 = <0x11170>;
+			xlnx,twp-ps-mem-1 = <0x2ee0>;
+			xlnx,twp-ps-mem-2 = <0x2ee0>;
+			xlnx,twp-ps-mem-3 = <0x2ee0>;
+			xlnx,xcl0-linesize = <0x4>;
+			xlnx,xcl0-writexfer = <0x1>;
+			xlnx,xcl1-linesize = <0x4>;
+			xlnx,xcl1-writexfer = <0x1>;
+			xlnx,xcl2-linesize = <0x4>;
+			xlnx,xcl2-writexfer = <0x1>;
+			xlnx,xcl3-linesize = <0x4>;
+			xlnx,xcl3-writexfer = <0x1>;
+		} ;
+		Hard_Ethernet_MAC: xps-ll-temac@81c00000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "xlnx,compound";
+			ethernet@81c00000 {
+				compatible = "xlnx,xps-ll-temac-1.01.b";
+				device_type = "network";
+				interrupt-parent = <&xps_intc_0>;
+				interrupts = < 8 2 >;
+				llink-connected = <&Hard_Ethernet_MAC_fifo>;
+				local-mac-address = [ 02 00 00 00 00 00 ];
+				reg = < 0x81c00000 0x40 >;
+				xlnx,bus2core-clk-ratio = <0x1>;
+				xlnx,phy-type = <0x3>;
+				xlnx,phyaddr = <0x1>;
+				xlnx,rxcsum = <0x0>;
+				xlnx,rxfifo = <0x8000>;
+				xlnx,temac-type = <0x0>;
+				xlnx,txcsum = <0x0>;
+				xlnx,txfifo = <0x8000>;
+			} ;
+		} ;
+		Hard_Ethernet_MAC_fifo: xps-ll-fifo@81a00000 {
+			compatible = "xlnx,xps-ll-fifo-1.01.a";
+			interrupt-parent = <&xps_intc_0>;
+			interrupts = < 6 2 >;
+			reg = < 0x81a00000 0x10000 >;
+			xlnx,family = "virtex5";
+		} ;
+		IIC_EEPROM: i2c@81600000 {
+			compatible = "xlnx,xps-iic-2.00.a";
+			interrupt-parent = <&xps_intc_0>;
+			interrupts = < 9 2 >;
+			reg = < 0x81600000 0x10000 >;
+			xlnx,clk-freq = <0x5f5e100>;
+			xlnx,family = "virtex5";
+			xlnx,gpo-width = <0x1>;
+			xlnx,iic-freq = <0x186a0>;
+			xlnx,scl-inertial-delay = <0x5>;
+			xlnx,sda-inertial-delay = <0x5>;
+			xlnx,ten-bit-adr = <0x0>;
+		} ;
+		LCD_OPTIONAL: gpio@81420000 {
+			compatible = "xlnx,xps-gpio-1.00.a";
+			reg = < 0x81420000 0x10000 >;
+			xlnx,all-inputs = <0x0>;
+			xlnx,all-inputs-2 = <0x0>;
+			xlnx,dout-default = <0x0>;
+			xlnx,dout-default-2 = <0x0>;
+			xlnx,family = "virtex5";
+			xlnx,gpio-width = <0xb>;
+			xlnx,interrupt-present = <0x0>;
+			xlnx,is-bidir = <0x1>;
+			xlnx,is-bidir-2 = <0x1>;
+			xlnx,is-dual = <0x0>;
+			xlnx,tri-default = <0xffffffff>;
+			xlnx,tri-default-2 = <0xffffffff>;
+		} ;
+		LEDs_4Bit: gpio@81400000 {
+			compatible = "xlnx,xps-gpio-1.00.a";
+			reg = < 0x81400000 0x10000 >;
+			xlnx,all-inputs = <0x0>;
+			xlnx,all-inputs-2 = <0x0>;
+			xlnx,dout-default = <0x0>;
+			xlnx,dout-default-2 = <0x0>;
+			xlnx,family = "virtex5";
+			xlnx,gpio-width = <0x4>;
+			xlnx,interrupt-present = <0x0>;
+			xlnx,is-bidir = <0x1>;
+			xlnx,is-bidir-2 = <0x1>;
+			xlnx,is-dual = <0x0>;
+			xlnx,tri-default = <0xffffffff>;
+			xlnx,tri-default-2 = <0xffffffff>;
+		} ;
+		RS232_Uart_1: serial@83e00000 {
+			clock-frequency = <100000000>;
+			compatible = "xlnx,xps-uart16550-2.00.b", "ns16550";
+			current-speed = <9600>;
+			device_type = "serial";
+			interrupt-parent = <&xps_intc_0>;
+			interrupts = < 11 2 >;
+			reg = < 0x83e00000 0x10000 >;
+			reg-offset = <0x1003>;
+			reg-shift = <2>;
+			xlnx,family = "virtex5";
+			xlnx,has-external-rclk = <0x0>;
+			xlnx,has-external-xin = <0x0>;
+			xlnx,is-a-16550 = <0x1>;
+		} ;
+		SPI_EEPROM: xps-spi@feff8000 {
+			compatible = "xlnx,xps-spi-2.00.b";
+			interrupt-parent = <&xps_intc_0>;
+			interrupts = < 10 2 >;
+			reg = < 0xfeff8000 0x80 >;
+			xlnx,family = "virtex5";
+			xlnx,fifo-exist = <0x1>;
+			xlnx,num-ss-bits = <0x1>;
+			xlnx,num-transfer-bits = <0x8>;
+			xlnx,sck-ratio = <0x80>;
+		} ;
+		SysACE_CompactFlash: sysace@83600000 {
+			compatible = "xlnx,xps-sysace-1.00.a";
+			interrupt-parent = <&xps_intc_0>;
+			interrupts = < 7 2 >;
+			reg = < 0x83600000 0x10000 >;
+			xlnx,family = "virtex5";
+			xlnx,mem-width = <0x10>;
+		} ;
+		plbv46_pci_0: plbv46-pci@85e00000 {
+			#size-cells = <2>;
+			#address-cells = <3>;
+			compatible = "xlnx,plbv46-pci-1.03.a";
+			device_type = "pci";
+			reg = < 0x85e00000 0x10000 >;
+
+			/*
+			 * The default ML510 BSB has C_IPIFBAR2PCIBAR_0 set to
+			 * 0 which means that a read/write to the memory mapped
+			 * i/o region (which starts at 0xa0000000) for pci
+			 * bar 0 on the plb side translates to 0.
+			 * It is important to set this value to 0xa0000000, so
+			 * that inbound and outbound pci transactions work
+			 * properly including DMA.
+			 */
+			ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x20000000
+				  0x01000000 0 0x00000000 0xf0000000 0 0x00010000>;
+
+			#interrupt-cells = <1>;
+			interrupt-parent = <&xps_intc_0>;
+			interrupt-map-mask = <0xff00 0x0 0x0 0x7>;
+			interrupt-map = <
+				/* IRQ mapping for pci slots and ALI M1533
+				 * periperhals. In total there are 5 interrupt
+				 * lines connected to a xps_intc controller.
+				 * Four of them are PCI IRQ A, B, C, D and
+				 * which correspond to respectively xpx_intc
+				 * 5, 4, 3 and 2.  The fifth interrupt line is
+				 * connected to the south bridge and this one
+				 * uses irq 1 and is active high instead of
+				 * active low.
+				 *
+				 * The M1533 contains various peripherals
+				 * including AC97 audio, a modem, USB, IDE and
+				 * some power management stuff. The modem
+				 * isn't connected on the ML510 and the power
+				 * management core also isn't used.
+				 */
+
+				/* IDSEL 0x16 / dev=6, bus=0 / PCI slot 3 */
+				0x3000 0 0 1 &xps_intc_0 3 2
+				0x3000 0 0 2 &xps_intc_0 2 2
+				0x3000 0 0 3 &xps_intc_0 5 2
+				0x3000 0 0 4 &xps_intc_0 4 2
+
+				/* IDSEL 0x13 / dev=3, bus=1 / PCI slot 4 */
+				/*
+				0x11800 0 0 1 &xps_intc_0 5 0 2
+				0x11800 0 0 2 &xps_intc_0 4 0 2
+				0x11800 0 0 3 &xps_intc_0 3 0 2
+				0x11800 0 0 4 &xps_intc_0 2 0 2
+				*/
+
+				/* According to the datasheet + schematic
+				 * ABCD [FPGA] of slot 5 is mapped to DABC.
+				 * Testing showed that at least A maps to B,
+				 * the mapping of the other pins is a guess
+				 * and for that reason the lines have been
+				 * commented out.
+				 */
+				/* IDSEL 0x15 / dev=5, bus=0 / PCI slot 5 */
+				0x2800 0 0 1 &xps_intc_0 4 2
+				/*
+				0x2800 0 0 2 &xps_intc_0 3 2
+				0x2800 0 0 3 &xps_intc_0 2 2
+				0x2800 0 0 4 &xps_intc_0 5 2
+				*/
+
+				/* IDSEL 0x12 / dev=2, bus=1 / PCI slot 6 */
+				/*
+				0x11000 0 0 1 &xps_intc_0 4 0 2
+				0x11000 0 0 2 &xps_intc_0 3 0 2
+				0x11000 0 0 3 &xps_intc_0 2 0 2
+				0x11000 0 0 4 &xps_intc_0 5 0 2
+				*/
+
+				/* IDSEL 0x11 / dev=1, bus=0 / AC97 audio */
+				0x0800 0 0 1 &i8259 7 2
+
+				/* IDSEL 0x1b / dev=11, bus=0 / IDE */
+				0x5800 0 0 1 &i8259 14 2
+
+				/* IDSEL 0x1f / dev 15, bus=0 / 2x USB 1.1 */
+				0x7800 0 0 1 &i8259 7 2
+			>;
+			ali_m1533 {
+				#size-cells = <1>;
+				#address-cells = <2>;
+				i8259: interrupt-controller@20 {
+					reg = <1 0x20 2
+							1 0xa0 2
+							1 0x4d0 2>;
+					interrupt-controller;
+					device_type = "interrupt-controller";
+					#address-cells = <0>;
+					#interrupt-cells = <2>;
+					compatible = "chrp,iic";
+
+					/* south bridge irq is active high */
+					interrupts = <1 3>;
+					interrupt-parent = <&xps_intc_0>;
+				};
+			};
+		} ;
+		xps_bram_if_cntlr_1: xps-bram-if-cntlr@ffff0000 {
+			compatible = "xlnx,xps-bram-if-cntlr-1.00.a";
+			reg = < 0xffff0000 0x10000 >;
+			xlnx,family = "virtex5";
+		} ;
+		xps_intc_0: interrupt-controller@81800000 {
+			#interrupt-cells = <0x2>;
+			compatible = "xlnx,xps-intc-1.00.a";
+			interrupt-controller ;
+			reg = < 0x81800000 0x10000 >;
+			xlnx,num-intr-inputs = <0xc>;
+		} ;
+		xps_tft_0: tft@86e00000 {
+			compatible = "xlnx,xps-tft-1.00.a";
+			reg = < 0x86e00000 0x10000 >;
+			xlnx,dcr-splb-slave-if = <0x1>;
+			xlnx,default-tft-base-addr = <0x0>;
+			xlnx,family = "virtex5";
+			xlnx,i2c-slave-addr = <0x76>;
+			xlnx,mplb-awidth = <0x20>;
+			xlnx,mplb-dwidth = <0x80>;
+			xlnx,mplb-native-dwidth = <0x40>;
+			xlnx,mplb-smallest-slave = <0x20>;
+			xlnx,tft-interface = <0x1>;
+		} ;
+	} ;
+}  ;

^ permalink raw reply related

* [PATCH v5 1/4] powerpc/virtex: Add support for Xilinx PCI host bridge
From: Grant Likely @ 2009-05-25 14:41 UTC (permalink / raw)
  To: linuxppc-dev, Roderick Colenbrander
In-Reply-To: <20090525144023.13016.23071.stgit@localhost.localdomain>

From: Roderick Colenbrander <thunderbird2k@gmail.com>

This patch adds support for the Xilinx plbv46-pci-1.03.a PCI host
bridge IPcore.

Signed-off-by: Roderick Colenbrander <thunderbird2k@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 arch/powerpc/include/asm/xilinx_pci.h |   21 +++++
 arch/powerpc/platforms/40x/virtex.c   |    2 +
 arch/powerpc/platforms/44x/virtex.c   |    2 +
 arch/powerpc/platforms/Kconfig        |    4 +
 arch/powerpc/sysdev/Makefile          |    1 
 arch/powerpc/sysdev/xilinx_pci.c      |  132 +++++++++++++++++++++++++++++++++
 6 files changed, 162 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/xilinx_pci.h
 create mode 100644 arch/powerpc/sysdev/xilinx_pci.c


diff --git a/arch/powerpc/include/asm/xilinx_pci.h b/arch/powerpc/include/asm/xilinx_pci.h
new file mode 100644
index 0000000..7a8275c
--- /dev/null
+++ b/arch/powerpc/include/asm/xilinx_pci.h
@@ -0,0 +1,21 @@
+/*
+ * Xilinx pci external definitions
+ *
+ * Copyright 2009 Roderick Colenbrander
+ * Copyright 2009 Secret Lab Technologies Ltd.
+ *
+ * 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 INCLUDE_XILINX_PCI
+#define INCLUDE_XILINX_PCI
+
+#ifdef CONFIG_XILINX_PCI
+extern void __init xilinx_pci_init(void);
+#else
+static inline void __init xilinx_pci_init(void) { return; }
+#endif
+
+#endif /* INCLUDE_XILINX_PCI */
diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c
index fc7fb00..d0fc686 100644
--- a/arch/powerpc/platforms/40x/virtex.c
+++ b/arch/powerpc/platforms/40x/virtex.c
@@ -14,6 +14,7 @@
 #include <asm/prom.h>
 #include <asm/time.h>
 #include <asm/xilinx_intc.h>
+#include <asm/xilinx_pci.h>
 #include <asm/ppc4xx.h>
 
 static struct of_device_id xilinx_of_bus_ids[] __initdata = {
@@ -47,6 +48,7 @@ static int __init virtex_probe(void)
 define_machine(virtex) {
 	.name			= "Xilinx Virtex",
 	.probe			= virtex_probe,
+	.setup_arch		= xilinx_pci_init,
 	.init_IRQ		= xilinx_intc_init_tree,
 	.get_irq		= xilinx_intc_get_irq,
 	.restart		= ppc4xx_reset_system,
diff --git a/arch/powerpc/platforms/44x/virtex.c b/arch/powerpc/platforms/44x/virtex.c
index 68637fa..cf96cca 100644
--- a/arch/powerpc/platforms/44x/virtex.c
+++ b/arch/powerpc/platforms/44x/virtex.c
@@ -16,6 +16,7 @@
 #include <asm/prom.h>
 #include <asm/time.h>
 #include <asm/xilinx_intc.h>
+#include <asm/xilinx_pci.h>
 #include <asm/reg.h>
 #include <asm/ppc4xx.h>
 #include "44x.h"
@@ -53,6 +54,7 @@ static int __init virtex_probe(void)
 define_machine(virtex) {
 	.name			= "Xilinx Virtex440",
 	.probe			= virtex_probe,
+	.setup_arch		= xilinx_pci_init,
 	.init_IRQ		= xilinx_intc_init_tree,
 	.get_irq		= xilinx_intc_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index e3e8707..04a8061 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -329,4 +329,8 @@ config MCU_MPC8349EMITX
 	  also register MCU GPIOs with the generic GPIO API, so you'll able
 	  to use MCU pins as GPIOs.
 
+config XILINX_PCI
+	bool "Xilinx PCI host bridge support"
+	depends on PCI && XILINX_VIRTEX
+
 endmenu
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index b33b28a..2d1c87d 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_IPIC)		+= ipic.o
 obj-$(CONFIG_4xx)		+= uic.o
 obj-$(CONFIG_4xx_SOC)		+= ppc4xx_soc.o
 obj-$(CONFIG_XILINX_VIRTEX)	+= xilinx_intc.o
+obj-$(CONFIG_XILINX_PCI)	+= xilinx_pci.o
 obj-$(CONFIG_OF_RTC)		+= of_rtc.o
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_4xx)		+= ppc4xx_pci.o
diff --git a/arch/powerpc/sysdev/xilinx_pci.c b/arch/powerpc/sysdev/xilinx_pci.c
new file mode 100644
index 0000000..1453b0e
--- /dev/null
+++ b/arch/powerpc/sysdev/xilinx_pci.c
@@ -0,0 +1,132 @@
+/*
+ * PCI support for Xilinx plbv46_pci soft-core which can be used on
+ * Xilinx Virtex ML410 / ML510 boards.
+ *
+ * Copyright 2009 Roderick Colenbrander
+ * Copyright 2009 Secret Lab Technologies Ltd.
+ *
+ * The pci bridge fixup code was copied from ppc4xx_pci.c and was written
+ * by Benjamin Herrenschmidt.
+ * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ *
+ * 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/ioport.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <mm/mmu_decl.h>
+#include <asm/io.h>
+#include <asm/xilinx_pci.h>
+
+#define XPLB_PCI_ADDR 0x10c
+#define XPLB_PCI_DATA 0x110
+#define XPLB_PCI_BUS  0x114
+
+#define PCI_HOST_ENABLE_CMD PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY
+
+static struct of_device_id xilinx_pci_match[] = {
+	{ .compatible = "xlnx,plbv46-pci-1.03.a", },
+	{}
+};
+
+/**
+ * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration.
+ */
+static void xilinx_pci_fixup_bridge(struct pci_dev *dev)
+{
+	struct pci_controller *hose;
+	int i;
+
+	if (dev->devfn || dev->bus->self)
+		return;
+
+	hose = pci_bus_to_host(dev->bus);
+	if (!hose)
+		return;
+
+	if (!of_match_node(xilinx_pci_match, hose->dn))
+		return;
+
+	/* Hide the PCI host BARs from the kernel as their content doesn't
+	 * fit well in the resource management
+	 */
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		dev->resource[i].start = 0;
+		dev->resource[i].end = 0;
+		dev->resource[i].flags = 0;
+	}
+
+	dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n",
+		 pci_name(dev));
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge);
+
+/**
+ * xilinx_pci_exclude_device - Don't do config access for non-root bus
+ *
+ * This is a hack.  Config access to any bus other than bus 0 does not
+ * currently work on the ML510 so we prevent it here.
+ */
+static int
+xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn)
+{
+	return (bus != 0);
+}
+
+/**
+ * xilinx_pci_init - Find and register a Xilinx PCI host bridge
+ */
+void __init xilinx_pci_init(void)
+{
+	struct pci_controller *hose;
+	struct resource r;
+	void __iomem *pci_reg;
+	struct device_node *pci_node;
+
+	pci_node = of_find_matching_node(NULL, xilinx_pci_match);
+	if(!pci_node)
+		return;
+
+	if (of_address_to_resource(pci_node, 0, &r)) {
+		pr_err("xilinx-pci: cannot resolve base address\n");
+		return;
+	}
+
+	hose = pcibios_alloc_controller(pci_node);
+	if (!hose) {
+		pr_err("xilinx-pci: pcibios_alloc_controller() failed\n");
+		return;
+	}
+
+	/* Setup config space */
+	setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR,
+			   r.start + XPLB_PCI_DATA,
+			   PPC_INDIRECT_TYPE_SET_CFG_TYPE);
+
+	/* According to the xilinx plbv46_pci documentation the soft-core starts
+	 * a self-init when the bus master enable bit is set. Without this bit
+	 * set the pci bus can't be scanned.
+	 */
+	early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD);
+
+	/* Set the max latency timer to 255 */
+	early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff);
+
+	/* Set the max bus number to 255 */
+	pci_reg = of_iomap(pci_node, 0);
+	out_8(pci_reg + XPLB_PCI_BUS, 0xff);
+	iounmap(pci_reg);
+
+	/* Nothing past the root bridge is working right now.  By default
+	 * exclude config access to anything except bus 0 */
+	if (!ppc_md.pci_exclude_device)
+		ppc_md.pci_exclude_device = xilinx_pci_exclude_device;
+
+	/* Register the host bridge with the linux kernel! */
+	pci_process_bridge_OF_ranges(hose, pci_node, 1);
+
+	pr_info("xilinx-pci: Registered PCI host bridge\n");
+}

^ permalink raw reply related

* [PATCH v5 2/4] powerpc/virtex: refactor intc driver and add support for i8259 cascading
From: Grant Likely @ 2009-05-25 14:41 UTC (permalink / raw)
  To: linuxppc-dev, Roderick Colenbrander
In-Reply-To: <20090525144023.13016.23071.stgit@localhost.localdomain>

From: Grant Likely <grant.likely@secretlab.ca>

This patch refactors some of the xilinx_intc interrupt controller driver
and adds support for cascading an i8259 off one of the irq lines.

This patch was based on the ML510 support work done by Roderick
Colenbrander.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

 arch/powerpc/sysdev/xilinx_intc.c |   76 ++++++++++++++++++++++++++++---------
 1 files changed, 58 insertions(+), 18 deletions(-)


diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index c658b41..90b5772 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/i8259.h>
 #include <asm/irq.h>
 
 /*
@@ -191,20 +192,14 @@ struct irq_host * __init
 xilinx_intc_init(struct device_node *np)
 {
 	struct irq_host * irq;
-	struct resource res;
 	void * regs;
-	int rc;
 
 	/* Find and map the intc registers */
-	rc = of_address_to_resource(np, 0, &res);
-	if (rc) {
-		printk(KERN_ERR __FILE__ ": of_address_to_resource() failed\n");
+	regs = of_iomap(np, 0);
+	if (!regs) {
+		pr_err("xilinx_intc: could not map registers\n");
 		return NULL;
 	}
-	regs = ioremap(res.start, 32);
-
-	printk(KERN_INFO "Xilinx intc at 0x%08llx mapped to 0x%p\n",
-		(unsigned long long) res.start, regs);
 
 	/* Setup interrupt controller */
 	out_be32(regs + XINTC_IER, 0); /* disable all irqs */
@@ -217,6 +212,7 @@ xilinx_intc_init(struct device_node *np)
 	if (!irq)
 		panic(__FILE__ ": Cannot allocate IRQ host\n");
 	irq->host_data = regs;
+
 	return irq;
 }
 
@@ -227,23 +223,65 @@ int xilinx_intc_get_irq(void)
 	return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR));
 }
 
+#if defined(CONFIG_PPC_I8259)
+/*
+ * Support code for cascading to 8259 interrupt controllers
+ */
+static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned int cascade_irq = i8259_irq();
+	if (cascade_irq)
+		generic_handle_irq(cascade_irq);
+
+	/* Let xilinx_intc end the interrupt */
+	desc->chip->ack(irq);
+	desc->chip->unmask(irq);
+}
+
+static void __init xilinx_i8259_setup_cascade(void)
+{
+	struct device_node *cascade_node;
+	int cascade_irq;
+
+	/* Initialize i8259 controller */
+	cascade_node = of_find_compatible_node(NULL, NULL, "chrp,iic");
+	if (!cascade_node)
+		return;
+
+	cascade_irq = irq_of_parse_and_map(cascade_node, 0);
+	if (!cascade_irq) {
+		pr_err("virtex_ml510: Failed to map cascade interrupt\n");
+		goto out;
+	}
+
+	i8259_init(cascade_node, 0);
+	set_irq_chained_handler(cascade_irq, xilinx_i8259_cascade);
+
+ out:
+	of_node_put(cascade_node);
+}
+#else
+static inline void xilinx_i8259_setup_cascade(void) { return; }
+#endif /* defined(CONFIG_PPC_I8259) */
+
+static struct of_device_id xilinx_intc_match[] __initconst = {
+	{ .compatible = "xlnx,opb-intc-1.00.c", },
+	{ .compatible = "xlnx,xps-intc-1.00.a", },
+	{}
+};
+
+/*
+ * Initialize master Xilinx interrupt controller
+ */
 void __init xilinx_intc_init_tree(void)
 {
 	struct device_node *np;
 
 	/* find top level interrupt controller */
-	for_each_compatible_node(np, NULL, "xlnx,opb-intc-1.00.c") {
+	for_each_matching_node(np, xilinx_intc_match) {
 		if (!of_get_property(np, "interrupts", NULL))
 			break;
 	}
-	if (!np) {
-		for_each_compatible_node(np, NULL, "xlnx,xps-intc-1.00.a") {
-			if (!of_get_property(np, "interrupts", NULL))
-				break;
-		}
-	}
-
-	/* xilinx interrupt controller needs to be top level */
 	BUG_ON(!np);
 
 	master_irqhost = xilinx_intc_init(np);
@@ -251,4 +289,6 @@ void __init xilinx_intc_init_tree(void)
 
 	irq_set_default_host(master_irqhost);
 	of_node_put(np);
+
+	xilinx_i8259_setup_cascade();
 }

^ permalink raw reply related

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
From: Jon Smirl @ 2009-05-25 15:15 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, broonie
In-Reply-To: <fa686aa40905242316j3e8b46e7mcc71dc34df209003@mail.gmail.com>

On Mon, May 25, 2009 at 2:16 AM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>> +static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned sho=
rt reg)
>> +{
>> + =A0 =A0 =A0 int timeout;
>> + =A0 =A0 =A0 unsigned int val;
>> +
>> + =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>> +
>> + =A0 =A0 =A0 /* Wait for it to be ready */
>> + =A0 =A0 =A0 timeout =3D 1000;
>> + =A0 =A0 =A0 while ((--timeout) && (in_be16(&psc_dma->psc_regs->sr_csr.=
status) &
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_CMDSEND))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>
> Holy unbounded latency Batman! =A0This code waits up to 10ms for a regist=
er read!
>
> I hate spinning, but if it must be done; I'd like to see it small.
> What is the worst case latency? 125us for 8000Hz bus speed? =A0If you
> must spin; can a cpu_relax() be used instead of the udelay() while
> watch the timebase? =A0Timur recently posted a patch which makes this
> easier.
>
> http://patchwork.ozlabs.org/patch/27414/
>
> They *should* be appearing in Ben's -next branch soon.


The link always runs at 12.288Mhz. Each frame is 256 bits. Worst case
you wait for two frames, 42us. If it doesn't respond in 42us the codec
clock is not ticking ( a recurring problem I am running into). These
codecs may be going into a sleep mode I don't understand, but this is
not the right place to try and wake them up. I'll lower the retry
counts to 10 instead of 1000.

I played around with implementing this on a kernel thread with
interrupts. It can be done but the code is a lot more complex.

BTW, 8000Hz is implemented by slot stuffing. The link always runs at
12.288Mhz. The DACs are double buffered. When a sample is transfered
between buffers it sets a bit on the link back to the host, and the
host sends the next sample in the appropriate slot.


>
>> +
>> + =A0 =A0 =A0 if (!timeout) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("timeout on ac97 bus (rdy)\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 0xffff;
>> + =A0 =A0 =A0 }
>> +
>> + =A0 =A0 =A0 /* Do the read */
>> + =A0 =A0 =A0 out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0=
x7f) << 24));
>> +
>> + =A0 =A0 =A0 /* Wait for the answer */
>> + =A0 =A0 =A0 timeout =3D 1000;
>> + =A0 =A0 =A0 while ((--timeout) && !(in_be16(&psc_dma->psc_regs->sr_csr=
.status) &
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_DATA_VAL))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>
> ditto.
>
>> +static int psc_ac97_cold_reset_check(struct snd_ac97 *ac97)
>> +{
>> + =A0 =A0 =A0 int max_reset, timeout;
>> + =A0 =A0 =A0 struct mpc52xx_psc __iomem *regs =3D psc_dma->psc_regs;
>> +
>> + =A0 =A0 =A0 /* AC97 clock is generated by the codec.
>> + =A0 =A0 =A0 =A0* Ensure that it starts ticking after codec reset.
>> + =A0 =A0 =A0 =A0*/
>> + =A0 =A0 =A0 for (max_reset =3D 0; max_reset < 5; max_reset++) {
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Do a cold reset */
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->op1, MPC52xx_PSC_OP_RES);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->op0, MPC52xx_PSC_OP_RES);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(50);
>
> :-/ =A0Don't like, but don't know if there is an alternative.
>
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* PSC recover from cold reset
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* (cfr user manual, not sure if useful)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&regs->sicr, in_be32(&regs->sicr)=
);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_ac97_warm_reset(ac97);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* first make sure AC97 clock is low */
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (timeout =3D 0; ((in_8(&regs->ipcr_acr=
.ipcr) & 0x80) !=3D 0) &&
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (timeout <=
 100); timeout++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (timeout =3D=3D 100)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* then wait for the transition to high */
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (timeout =3D 0; ((in_8(&regs->ipcr_acr=
.ipcr) & 0x80) =3D=3D 0) &&
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (timeout <=
 100); timeout++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (timeout =3D=3D 100)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
>
> Using udelay makes this less accurate. =A0Only possible reason to use a
> udelay is if the register cannot be polled at full speed (which is
> possibly the case if it adds bus contention; but I don't think it is
> an issue here).
>
> g.
>
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
>



--=20
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
From: Jon Smirl @ 2009-05-25 15:21 UTC (permalink / raw)
  To: grant.likely; +Cc: linuxppc-dev, alsa-devel, Mark Brown
In-Reply-To: <20090525102647.GD18290@sirena.org.uk>

On Mon, May 25, 2009 at 6:26 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>> + =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&psc_dma->psc_regs->ac97_slots, psc_d=
ma->slots);
>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock(&psc_dma->lock);
>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>
> This locking looks wrong - I'd expect it to also cover the modification
> of psc_dma->slots? =A0Otherwise it's hard to see what it buys you.

Grant, why are you spin locking around register access?


--=20
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
From: Mark Brown @ 2009-05-25 15:22 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <9e4733910905250815r4a6fa205s26531f08fe99131a@mail.gmail.com>

On Mon, May 25, 2009 at 11:15:34AM -0400, Jon Smirl wrote:

> The link always runs at 12.288Mhz. Each frame is 256 bits. Worst case
> you wait for two frames, 42us. If it doesn't respond in 42us the codec

Note that some embedded systems will choose to vary the AC97 link clock.
The most common case is where there's a PLL on the CODEC - the CODEC
will start up misclocked at whatever the input frequency it's got is and
then be reclocked using register writes to configure the PLL.

^ permalink raw reply

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
From: Grant Likely @ 2009-05-25 15:59 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie
In-Reply-To: <9e4733910905250815r4a6fa205s26531f08fe99131a@mail.gmail.com>

On Mon, May 25, 2009 at 9:15 AM, Jon Smirl <jonsmirl@gmail.com> wrote:
> On Mon, May 25, 2009 at 2:16 AM, Grant Likely <grant.likely@secretlab.ca>=
 wrote:
>> On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>>> +static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned sh=
ort reg)
>>> +{
>>> + =A0 =A0 =A0 int timeout;
>>> + =A0 =A0 =A0 unsigned int val;
>>> +
>>> + =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>>> +
>>> + =A0 =A0 =A0 /* Wait for it to be ready */
>>> + =A0 =A0 =A0 timeout =3D 1000;
>>> + =A0 =A0 =A0 while ((--timeout) && (in_be16(&psc_dma->psc_regs->sr_csr=
.status) &
>>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_CMDSEND))
>>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>>
>> Holy unbounded latency Batman! =A0This code waits up to 10ms for a regis=
ter read!
>>
>> I hate spinning, but if it must be done; I'd like to see it small.
>> What is the worst case latency? 125us for 8000Hz bus speed? =A0If you
>> must spin; can a cpu_relax() be used instead of the udelay() while
>> watch the timebase? =A0Timur recently posted a patch which makes this
>> easier.
>>
>> http://patchwork.ozlabs.org/patch/27414/
>>
>> They *should* be appearing in Ben's -next branch soon.
>
>
> The link always runs at 12.288Mhz. Each frame is 256 bits. Worst case
> you wait for two frames, 42us. If it doesn't respond in 42us the codec
> clock is not ticking ( a recurring problem I am running into). These
> codecs may be going into a sleep mode I don't understand, but this is
> not the right place to try and wake them up. I'll lower the retry
> counts to 10 instead of 1000.

That still leaves the problem of unecessarily burning time.  udelay
shouldn't be passed any value larger than 1.  In fact, I think udelay
itself is too coarse grained.  Plus, I'd rather see the timebase used
as the exit condition (as mentioned in previous email).

> I played around with implementing this on a kernel thread with
> interrupts. It can be done but the code is a lot more complex.

A kernel thread is definitely the wrong approach.  However, if this is
non-atomic context and IRQs are available, then a wait queue can be
used.  42us is about 16k processor clocks.  I'm not sure what the IRQ
and scheduling overhead is so I don't know whether it would be a net
gain or loss in performance.  However, it would be a net gain in worst
case latency.

> BTW, 8000Hz is implemented by slot stuffing. The link always runs at
> 12.288Mhz. The DACs are double buffered. When a sample is transfered
> between buffers it sets a bit on the link back to the host, and the
> host sends the next sample in the appropriate slot.

ok.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
From: Grant Likely @ 2009-05-25 16:00 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, Mark Brown
In-Reply-To: <9e4733910905250821nf433121s6c161d3f2104b453@mail.gmail.com>

On Mon, May 25, 2009 at 9:21 AM, Jon Smirl <jonsmirl@gmail.com> wrote:
> On Mon, May 25, 2009 at 6:26 AM, Mark Brown
> <broonie@opensource.wolfsonmicro.com> wrote:
>>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>>> + =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&psc_dma->psc_regs->ac97_slots, psc_=
dma->slots);
>>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock(&psc_dma->lock);
>>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>>
>> This locking looks wrong - I'd expect it to also cover the modification
>> of psc_dma->slots? =A0Otherwise it's hard to see what it buys you.
>
> Grant, why are you spin locking around register access?

This lock/unlock is definitely bogus since a single register access is
already atomic.  Are there places in the code that I wrote where a
spin_lock/unlock is done around a single register access?

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: Weird 5200/mtd-ram problem
From: Albrecht Dreß @ 2009-05-25 17:41 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20090520200135.GB13287@pengutronix.de>

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

Hi Gary & Wolfram:

Thanks for youre help, and sorry for the late reply - I've been on  
vacation...

Am 20.05.09 21:59 schrieb(en) Gary Thomas:
> Try to access this without using the cache.

Unfortunately, this is not cache related - I switched the dcache off  
completely - same results.

Am 20.05.09 22:01 schrieb(en) Wolfram Sang:
> Does it work with byte, word and long accesses?

A word or long copy of 0x0055aaff with U-Boot works fine, but a byte  
copy filled the whole ram with 0x0000aaaa.  The reason is apparently  
that the chip is attached to the local bus in 16-bit mode, which is  
incompatible with byte accesses.  However, the Local Bus doesn't  
provide "low byte" or "high byte" indicators in non-muxed mode.  How is  
this supposed to work then?

For the mtd driver, I tracked down the problem via mapram_write() (in  
drivers/mtd/chips/map_ram.c) down to the call of map_copy_to() which is  
actually inline_map_copy_to(), which in turn calls memcpy_toio().  I  
*think* this is _memcpy_toio() in arch/powerpc/kernel/io.c, which  
copies all data in long (4-byte) moves, except for the last 4 bytes.  I  
guess I have to write my own copy function which respects the fact that  
byte writes actually must be a read word - modify - write word  
sequence, right?

Thanks, Albrecht.

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

^ permalink raw reply

* Re: [PATCH 1/2 v8] powerpc: introduce macro spin_event_timeout()
From: Jon Smirl @ 2009-05-25 17:46 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev, smaclennan
In-Reply-To: <1242761199-17875-2-git-send-email-timur@freescale.com>

On Tue, May 19, 2009 at 3:26 PM, Timur Tabi <timur@freescale.com> wrote:
> The macro spin_event_timeout() takes a condition and timeout value
> (in microseconds) as parameters. =A0It spins until either the condition i=
s true
> or the timeout expires. =A0It returns the result of the condition when th=
e loop
> was terminated.
>
> This primary purpose of this macro is to poll on a hardware register unti=
l a
> status bit changes. =A0The timeout ensures that the loop still terminates=
 if the
> bit doesn't change as expected. =A0This macro makes it easier for driver
> developers to perform this kind of operation properly.


I just tried using this. The !rc has the effect of making the error
return be zero instead the normal not zero.

	/* Wait for command send status zero =3D ready */
	spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
				MPC52xx_PSC_SR_CMDSEND), 100, 0, rc);
	if (rc =3D=3D 0) {
		pr_err("timeout on ac97 bus (rdy)\n");
		return -ENODEV;
	}

I want the register to be zero, would this be more obvious?

	/* Wait for command send status zero =3D ready */
	spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) &
				MPC52xx_PSC_SR_CMDSEND), 100, 0, rc);
	if (rc !=3D 0) {
		pr_err("timeout on ac97 bus (rdy)\n");
		return -ENODEV;
	}


>
> Signed-off-by: Timur Tabi <timur@freescale.com>
> ---
>
> v8: added a copyright notice
>
> =A0arch/powerpc/include/asm/delay.h | =A0 33 ++++++++++++++++++++++++++++=
+++++
> =A01 files changed, 33 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/delay.h b/arch/powerpc/include/asm/=
delay.h
> index f9200a6..af4a270 100644
> --- a/arch/powerpc/include/asm/delay.h
> +++ b/arch/powerpc/include/asm/delay.h
> @@ -2,8 +2,11 @@
> =A0#define _ASM_POWERPC_DELAY_H
> =A0#ifdef __KERNEL__
>
> +#include <asm/time.h>
> +
> =A0/*
> =A0* Copyright 1996, Paul Mackerras.
> + * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
> =A0*
> =A0* This program is free software; you can redistribute it and/or
> =A0* modify it under the terms of the GNU General Public License
> @@ -30,5 +33,35 @@ extern void udelay(unsigned long usecs);
> =A0#define mdelay(n) =A0 =A0 =A0udelay((n) * 1000)
> =A0#endif
>
> +/**
> + * spin_event_timeout - spin until a condition gets true or a timeout el=
apses
> + * @condition: a C expression to evalate
> + * @timeout: timeout, in microseconds
> + * @delay: the number of microseconds to delay between eache evaluation =
of
> + * =A0 =A0 =A0 =A0 @condition
> + * @rc: the last value of the condition
> + *
> + * The process spins until the condition evaluates to true (non-zero) or=
 the
> + * timeout elapses. =A0Upon exit, @rc contains the value of the conditio=
n. This
> + * allows you to test the condition without incurring any side effects.
> + *
> + * This primary purpose of this macro is to poll on a hardware register
> + * until a status bit changes. =A0The timeout ensures that the loop stil=
l
> + * terminates even if the bit never changes. =A0The delay is for devices=
 that
> + * need a delay in between successive reads.
> + *
> + * gcc will optimize out the if-statement if @delay is a constant.
> + */
> +#define spin_event_timeout(condition, timeout, delay, rc) =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 \
> +{ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 \
> + =A0 =A0 =A0 unsigned long __loops =3D tb_ticks_per_usec * timeout; =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0\
> + =A0 =A0 =A0 unsigned long __start =3D get_tbl(); =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
> + =A0 =A0 =A0 while (!(rc =3D (condition)) && (tb_ticks_since(__start) <=
=3D __loops)) \
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (delay) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(delay); =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
\
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cpu_relax(); =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\
> +}
> +
> =A0#endif /* __KERNEL__ */
> =A0#endif /* _ASM_POWERPC_DELAY_H */
> --
> 1.6.0.6
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>



--=20
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: U-boot and linux command line parameters
From: Wolfgang Denk @ 2009-05-25 17:54 UTC (permalink / raw)
  To: Mirek23; +Cc: linuxppc-dev
In-Reply-To: <23703397.post@talk.nabble.com>

Dear Mirek23,

In message <23703397.post@talk.nabble.com> you wrote:
> 
> Thank you for your answer. When studying the u-boot source code I have found

Will you please STOP posting the same questions on sevral mailing
lists, especially without any form of cross-reference?

Please read http://www.catb.org/~esr/faqs/smart-questions.html so you
understand why you might not receive any further replies.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
How many NASA managers does it take to screw in a lightbulb?  "That's
a known problem... don't worry about it."

^ permalink raw reply

* Re: Weird 5200/mtd-ram problem
From: Wolfgang Denk @ 2009-05-25 18:11 UTC (permalink / raw)
  To: Albrecht Dreß; +Cc: linuxppc-dev
In-Reply-To: <1243273283.3328.0@antares>

Dear Albrecht =?iso-8859-1?b?RHJl3w==?=,

In message <1243273283.3328.0@antares> you wrote:
>
> Thanks for youre help, and sorry for the late reply - I've been on  
> vacation...

Hally you...

> For the mtd driver, I tracked down the problem via mapram_write() (in  
> drivers/mtd/chips/map_ram.c) down to the call of map_copy_to() which is  
> actually inline_map_copy_to(), which in turn calls memcpy_toio().  I  
> *think* this is _memcpy_toio() in arch/powerpc/kernel/io.c, which  
> copies all data in long (4-byte) moves, except for the last 4 bytes.  I  
> guess I have to write my own copy function which respects the fact that  
> byte writes actually must be a read word - modify - write word  
> sequence, right?

I remember some nasty problems with memcpy*(),  especially  with  un-
aligned  accesses  over the LocalPlus Bus. I'm not sure if fixes ever
made it into 2.6; the only commit that might be related is 6989f5122f
"fec: do not use memcpy on physical addresses", but this doesn't  got
into details about the casue.

Please see here for an old (2.4.25) patch for this problem - maybe
it's worth a try on your system:

http://git.denx.de/?p=linuxppc_2_4_devel.git;a=commit;h=222bd702a59efb22bf66937f6ac844ed7327fd1a

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
If you're not part of the solution, you're part of the problem.

^ permalink raw reply

* Re: U-boot and linux command line parameters
From: Mirek23 @ 2009-05-25 20:40 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <23703397.post@talk.nabble.com>


I have done some experiments with u-boot (version 1.2.0) and with linux
kernel (version 2.6.23) and it seems to be that the limitation of 8MB is not
anymore the problem. I have built u-boot and linux for ppc405 (virtex-4). I
have set the CFG_BOOTMAPSZ to 16 MB:
#define CFG_BOOTMAPSZ             (8 << 21)  /* 16 MB */

and Linux has picked up the command line parameters which were set in
u-boot.

>/*
> * For booting Linux, the board info and command line data
> * have to be in the first 8 MB of memory, since this is
> * the maximum mapped by the Linux kernel during initialization.
> */
> #define CFG_BOOTMAPSZ             (8 << 20)   /* Initial Memory map for
> Linux */

-- 
View this message in context: http://www.nabble.com/U-boot-and-linux-command-line-parameters-tp23698384p23712750.html
Sent from the linuxppc-dev mailing list archive at Nabble.com.

^ permalink raw reply

* Re: [PATCH v5 0/4] Series short description
From: Roderick Colenbrander @ 2009-05-25 20:47 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <20090525144023.13016.23071.stgit@localhost.localdomain>

On Mon, May 25, 2009 at 4:41 PM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> Repost of ml510 series. =A0This time against 2.6.30-rc7 and with the .dts
> file included.
>
> g.
>
> --
> Grant Likely, B.Sc. P.Eng.
> Secret Lab Technologies Ltd.
>

Thanks, I will check it out tomorrow.

Roderick

^ permalink raw reply

* Re: Weird 5200/mtd-ram problem
From: Wolfram Sang @ 2009-05-25 21:47 UTC (permalink / raw)
  To: Albrecht Dreß; +Cc: linuxppc-dev
In-Reply-To: <1243273283.3328.0@antares>

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


> A word or long copy of 0x0055aaff with U-Boot works fine, but a byte  
> copy filled the whole ram with 0x0000aaaa.  The reason is apparently  
> that the chip is attached to the local bus in 16-bit mode, which is  
> incompatible with byte accesses.  However, the Local Bus doesn't provide 
> "low byte" or "high byte" indicators in non-muxed mode.  How is this 
> supposed to work then?

Hmm, as I feared... we were bitten by this, too:

http://thread.gmane.org/gmane.linux.drivers.mtd/21521

There is no generic solution yet :(

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

^ permalink raw reply

* Re: mpc8315e-rdb: pci_enable_msi() fails (using today's galak/powerpc.git tree)
From: Leon Woestenberg @ 2009-05-25 21:41 UTC (permalink / raw)
  To: michael; +Cc: Linux PPC, linux-kernel@vger.kernel.org
In-Reply-To: <1243147091.27293.3.camel@concordia>

Hello,

On Sun, May 24, 2009 at 8:38 AM, Michael Ellerman
<michael@ellerman.id.au> wrote:
> On Sun, 2009-05-24 at 00:12 +0200, Leon Woestenberg wrote:
>> Hello,
>>
>> On Sat, May 23, 2009 at 10:58 PM, Leon Woestenberg
>> <leon.woestenberg@gmail.com> wrote:
>> > using this tree: git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git
>> >
>> > pci_enable_msi() fails on my MPC8315E-RDB board with PCIe device in
>
> <snip good bug report>
>
> 'lspci -vvv' of the device in question is often useful too.
>
Good point. Here's the full list, the last device is my target:

0000:00:00.0 0b20: 1957:00b4 (rev 10)
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx-
	Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort+ >SERR- <PERR- INTx-
	Latency: 128, Cache Line Size: 32 bytes
	Interrupt: pin A routed to IRQ 17
	Region 2: Memory at <unassigned> (64-bit, prefetchable)
	Region 4: Memory at <unassigned> (64-bit, non-prefetchable)
	Capabilities: [48] CompactPCI hot-swap <?>
	Capabilities: [80] Power Management version 3
		Flags: PMEClk+ DSI+ D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold-)
		Status: D0 PME-Enable- DSel=0 DScale=0 PME-

0002:02:00.0 0000: 1957:00b4 (rev 10)
	!!! Invalid class 0000 for header type 01
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+
Stepping- SERR+ FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0, Cache Line Size: 32 bytes
	Bus: primary=02, secondary=03, subordinate=03, sec-latency=0
	I/O behind bridge: 00000000-00000fff
	Memory behind bridge: c0000000-cfffffff
	Prefetchable memory behind bridge: 0000000000100000-00000000000fffff
	Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- <SERR- <PERR-
	BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
		PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
	Capabilities: [44] Power Management version 2
		Flags: PMEClk- DSI+ D1+ D2+ AuxCurrent=0mA PME(D0+,D1+,D2+,D3hot+,D3cold-)
		Status: D0 PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [4c] Express (v1) Root Port (Slot-), MSI 00
		DevCap:	MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
			ExtTag- RBE- FLReset-
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
			MaxPayload 128 bytes, MaxReadReq 512 bytes
		DevSta:	CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
		LnkCap:	Port #0, Speed 2.5GT/s, Width x1, ASPM L0s, Latency L0 <2us,
L1 unlimited
			ClockPM- Surprise- LLActRep- BwNot-
		LnkCtl:	ASPM Disabled; RCB 128 bytes Disabled- Retrain- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk- DLActive-
BWMgmt- ABWMgmt-
		RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
		RootCap: CRSVisible-
		RootSta: PME ReqID 0000, PMEStatus- PMEPending-
	Capabilities: [100] Advanced Error Reporting
		UESta:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
		UEMsk:	DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
		UESvrt:	DLP+ SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+
MalfTLP+ ECRC- UnsupReq- ACSViol-
		CESta:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
		CEMsk:	RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
		AERCap:	First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
	Capabilities: [138] Virtual Channel <?>
	Capabilities: [3f8] Vendor Specific Information <?>

0002:03:00.0 ff00: 1172:0004 (rev 01)
	Subsystem: 1172:0004
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 25
	Region 0: Memory at c0000000 (32-bit, non-prefetchable) [size=32K]
	Capabilities: [50] MSI: Mask- 64bit+ Count=1/4 Enable+
		Address: 00000000e00007f8  Data: 0000
	Capabilities: [78] Power Management version 3
		Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
		Status: D0 PME-Enable- DSel=0 DScale=0 PME-
	Capabilities: [80] Express (v1) Endpoint, MSI 00
		DevCap:	MaxPayload 256 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
			ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
		DevCtl:	Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
			RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
			MaxPayload 128 bytes, MaxReadReq 512 bytes
		DevSta:	CorrErr+ UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
		LnkCap:	Port #1, Speed 2.5GT/s, Width x1, ASPM L0s L1, Latency L0
unlimited, L1 unlimited
			ClockPM- Surprise- LLActRep- BwNot-
		LnkCtl:	ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
			ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
		LnkSta:	Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive-
BWMgmt- ABWMgmt-
	Capabilities: [100] Virtual Channel <?>
	Kernel driver in use: altpciesgdma



-- 
Leon

^ permalink raw reply

* [PATCH V4 0/5] AC97 driver for mpc5200
From: Jon Smirl @ 2009-05-25 22:15 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie, timur

Version 4. Changed timeouts to use relax_cpu() instead of udelay(). Fixed locking to lock bestcomm instead of
registers. Code reorg as requested in the various comments. Removed sysfs over/underrun reporting. Removed 
reset retries. Removing the retries makes the driver fail to load about 5% of the time. An oscilliscope is 
needed to figure out what is going on with failed resets. Both pcm030 and Efika ocasionally fail to reset 
and they use different codec chips.

---

Jon Smirl (5):
      Fabric bindings for STAC9766 on the Efika
      Support for AC97 on Phytec pmc030 base board.
      AC97 driver for mpc5200
      Main rewite of the mpc5200 audio DMA code
      The macro spin_event_timeout() takes a condition and timeout value


 arch/powerpc/include/asm/delay.h    |   33 +++
 sound/soc/fsl/Kconfig               |   27 ++
 sound/soc/fsl/Makefile              |    5 
 sound/soc/fsl/efika-audio-fabric.c  |   90 +++++++
 sound/soc/fsl/mpc5200_dma.c         |  442 ++++++++++++++++++++++-------------
 sound/soc/fsl/mpc5200_dma.h         |   43 ++-
 sound/soc/fsl/mpc5200_psc_ac97.c    |  331 ++++++++++++++++++++++++++
 sound/soc/fsl/mpc5200_psc_ac97.h    |   15 +
 sound/soc/fsl/mpc5200_psc_i2s.c     |  247 +++-----------------
 sound/soc/fsl/mpc5200_psc_i2s.h     |   12 +
 sound/soc/fsl/pcm030-audio-fabric.c |   90 +++++++
 11 files changed, 946 insertions(+), 389 deletions(-)
 create mode 100644 sound/soc/fsl/efika-audio-fabric.c
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.c
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.h
 create mode 100644 sound/soc/fsl/mpc5200_psc_i2s.h
 create mode 100644 sound/soc/fsl/pcm030-audio-fabric.c

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* [PATCH V4 1/5] The macro spin_event_timeout() takes a condition and timeout value
From: Jon Smirl @ 2009-05-25 22:15 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie, timur
In-Reply-To: <20090525221406.21370.30326.stgit@terra>

(in microseconds) as parameters.  It spins until either the condition is true
or the timeout expires.  It returns the result of the condition when the loop
was terminated.

This primary purpose of this macro is to poll on a hardware register until a
status bit changes.  The timeout ensures that the loop still terminates if the
bit doesn't change as expected.  This macro makes it easier for driver
developers to perform this kind of operation properly.

Signed-off-by: Timur Tabi <timur@freescale.com>
---
 arch/powerpc/include/asm/delay.h |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/delay.h b/arch/powerpc/include/asm/delay.h
index f9200a6..fedf037 100644
--- a/arch/powerpc/include/asm/delay.h
+++ b/arch/powerpc/include/asm/delay.h
@@ -2,8 +2,11 @@
 #define _ASM_POWERPC_DELAY_H
 #ifdef __KERNEL__
 
+#include <asm/time.h>
+
 /*
  * Copyright 1996, Paul Mackerras.
+ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -30,5 +33,35 @@ extern void udelay(unsigned long usecs);
 #define mdelay(n)	udelay((n) * 1000)
 #endif
 
+/**
+ * spin_event_timeout - spin until a condition gets true or a timeout elapses
+ * @condition: a C expression to evalate
+ * @timeout: timeout, in microseconds
+ * @delay: the number of microseconds to delay between eache evaluation of
+ *         @condition
+ * @rc: the last value of the condition
+ *
+ * The process spins until the condition evaluates to true (non-zero) or the
+ * timeout elapses.  Upon exit, @rc contains the value of the condition. This
+ * allows you to test the condition without incurring any side effects.
+ *
+ * This primary purpose of this macro is to poll on a hardware register
+ * until a status bit changes.  The timeout ensures that the loop still
+ * terminates even if the bit never changes.  The delay is for devices that
+ * need a delay in between successive reads.
+ *
+ * gcc will optimize out the if-statement if @delay is a constant.
+ */
+#define spin_event_timeout(condition, timeout, delay, rc)                   \
+{                                                                           \
+	unsigned long __loops = tb_ticks_per_usec * timeout;                \
+	unsigned long __start = get_tbl();                                  \
+	while ((rc = (condition)) && (tb_ticks_since(__start) <= __loops)) \
+		if (delay)                                                  \
+			udelay(delay);                                      \
+		else	                                                    \
+			cpu_relax();                                        \
+}
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_DELAY_H */

^ permalink raw reply related

* [PATCH V4 2/5] Main rewite of the mpc5200 audio DMA code
From: Jon Smirl @ 2009-05-25 22:15 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie, timur
In-Reply-To: <20090525221406.21370.30326.stgit@terra>

Rewrite the mpc5200 audio DMA code to support both I2S and AC97.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
 sound/soc/fsl/Kconfig           |    1 
 sound/soc/fsl/mpc5200_dma.c     |  442 ++++++++++++++++++++++++---------------
 sound/soc/fsl/mpc5200_dma.h     |   43 ++--
 sound/soc/fsl/mpc5200_psc_i2s.c |  247 ++++------------------
 sound/soc/fsl/mpc5200_psc_i2s.h |   12 +
 5 files changed, 356 insertions(+), 389 deletions(-)
 create mode 100644 sound/soc/fsl/mpc5200_psc_i2s.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index dc79bdf..1918c78 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -25,7 +25,6 @@ config SND_SOC_MPC8610_HPCD
 config SND_SOC_MPC5200_I2S
 	tristate "Freescale MPC5200 PSC in I2S mode driver"
 	depends on PPC_MPC52xx && PPC_BESTCOMM
-	select SND_SOC_OF_SIMPLE
 	select SND_MPC52xx_DMA
 	select PPC_BESTCOMM_GEN_BD
 	help
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 6850392..efec33a 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -3,23 +3,13 @@
  * ALSA SoC Platform driver
  *
  * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
 #include <sysdev/bestcomm/bestcomm.h>
 #include <sysdev/bestcomm/gen_bd.h>
@@ -27,10 +17,6 @@
 
 #include "mpc5200_dma.h"
 
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
-MODULE_LICENSE("GPL");
-
 /*
  * Interrupt handlers
  */
@@ -50,7 +36,7 @@ static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma)
 	if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
 		psc_dma->stats.overrun_count++;
 
-	out_8(&regs->command, 4 << 4);	/* reset the error status */
+	out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
 
 	return IRQ_HANDLED;
 }
@@ -81,21 +67,36 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
 		s->period_next_pt = s->period_start;
 }
 
+static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
+{
+	while (s->appl_ptr < s->runtime->control->appl_ptr) {
+
+		if (bcom_queue_full(s->bcom_task))
+			return;
+
+		s->appl_ptr += s->period_size;
+
+		psc_dma_bcom_enqueue_next_buffer(s);
+	}
+}
+
 /* Bestcomm DMA irq handler */
-static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
+static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
 {
 	struct psc_dma_stream *s = _psc_dma_stream;
 
+	spin_lock(&s->psc_dma->lock);
 	/* For each finished period, dequeue the completed period buffer
 	 * and enqueue a new one in it's place. */
 	while (bcom_buffer_done(s->bcom_task)) {
 		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+
 		s->period_current_pt += s->period_bytes;
 		if (s->period_current_pt >= s->period_end)
 			s->period_current_pt = s->period_start;
-		psc_dma_bcom_enqueue_next_buffer(s);
-		bcom_enable(s->bcom_task);
 	}
+	psc_dma_bcom_enqueue_tx(s);
+	spin_unlock(&s->psc_dma->lock);
 
 	/* If the stream is active, then also inform the PCM middle layer
 	 * of the period finished event. */
@@ -105,49 +106,33 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
 	return IRQ_HANDLED;
 }
 
-/**
- * psc_dma_startup: create a new substream
- *
- * This is the first function called when a stream is opened.
- *
- * If this is the first stream open, then grab the IRQ and program most of
- * the PSC registers.
- */
-int psc_dma_startup(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai)
+static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
-	int rc;
+	struct psc_dma_stream *s = _psc_dma_stream;
 
-	dev_dbg(psc_dma->dev, "psc_dma_startup(substream=%p)\n", substream);
+	spin_lock(&s->psc_dma->lock);
+	/* For each finished period, dequeue the completed period buffer
+	 * and enqueue a new one in it's place. */
+	while (bcom_buffer_done(s->bcom_task)) {
+		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
 
-	if (!psc_dma->playback.active &&
-	    !psc_dma->capture.active) {
-		/* Setup the IRQs */
-		rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
-				 "psc-dma-status", psc_dma);
-		rc |= request_irq(psc_dma->capture.irq,
-				  &psc_dma_bcom_irq, IRQF_SHARED,
-				  "psc-dma-capture", &psc_dma->capture);
-		rc |= request_irq(psc_dma->playback.irq,
-				  &psc_dma_bcom_irq, IRQF_SHARED,
-				  "psc-dma-playback", &psc_dma->playback);
-		if (rc) {
-			free_irq(psc_dma->irq, psc_dma);
-			free_irq(psc_dma->capture.irq,
-				 &psc_dma->capture);
-			free_irq(psc_dma->playback.irq,
-				 &psc_dma->playback);
-			return -ENODEV;
-		}
+		s->period_current_pt += s->period_bytes;
+		if (s->period_current_pt >= s->period_end)
+			s->period_current_pt = s->period_start;
+
+		psc_dma_bcom_enqueue_next_buffer(s);
 	}
+	spin_unlock(&s->psc_dma->lock);
 
-	return 0;
+	/* If the stream is active, then also inform the PCM middle layer
+	 * of the period finished event. */
+	if (s->active)
+		snd_pcm_period_elapsed(s->stream);
+
+	return IRQ_HANDLED;
 }
 
-int psc_dma_hw_free(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai)
+static int psc_dma_hw_free(struct snd_pcm_substream *substream)
 {
 	snd_pcm_set_runtime_buffer(substream, NULL);
 	return 0;
@@ -159,8 +144,7 @@ int psc_dma_hw_free(struct snd_pcm_substream *substream,
  * This function is called by ALSA to start, stop, pause, and resume the DMA
  * transfer of data.
  */
-int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
-			   struct snd_soc_dai *dai)
+static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
@@ -168,8 +152,8 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
 	struct psc_dma_stream *s;
 	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
 	u16 imr;
-	u8 psc_cmd;
 	unsigned long flags;
+	int i;
 
 	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
 		s = &psc_dma->capture;
@@ -189,68 +173,48 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
 				(s->period_bytes * runtime->periods);
 		s->period_next_pt = s->period_start;
 		s->period_current_pt = s->period_start;
+		s->period_size = runtime->period_size;
 		s->active = 1;
 
-		/* First; reset everything */
+		/* track appl_ptr so that we have a better chance of detecting
+		 * end of stream and not over running it.
+		 */
+		s->runtime = runtime;
+		s->appl_ptr = s->runtime->control->appl_ptr -
+				(runtime->period_size * runtime->periods);
+
+		/* Fill up the bestcomm bd queue and enable DMA.
+		 * This will begin filling the PSC's fifo.
+		 */
+		spin_lock_irqsave(&psc_dma->lock, flags);
+
 		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			out_8(&regs->command, MPC52xx_PSC_RST_RX);
-			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+			bcom_gen_bd_rx_reset(s->bcom_task);
+			for (i = 0; i < runtime->periods; i++)
+				if (!bcom_queue_full(s->bcom_task))
+					psc_dma_bcom_enqueue_next_buffer(s);
 		} else {
-			out_8(&regs->command, MPC52xx_PSC_RST_TX);
-			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+			bcom_gen_bd_tx_reset(s->bcom_task);
+			psc_dma_bcom_enqueue_tx(s);
 		}
 
-		/* Next, fill up the bestcomm bd queue and enable DMA.
-		 * This will begin filling the PSC's fifo. */
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-			bcom_gen_bd_rx_reset(s->bcom_task);
-		else
-			bcom_gen_bd_tx_reset(s->bcom_task);
-		while (!bcom_queue_full(s->bcom_task))
-			psc_dma_bcom_enqueue_next_buffer(s);
 		bcom_enable(s->bcom_task);
-
-		/* Due to errata in the dma mode; need to line up enabling
-		 * the transmitter with a transition on the frame sync
-		 * line */
-
-		spin_lock_irqsave(&psc_dma->lock, flags);
-		/* first make sure it is low */
-		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
-			;
-		/* then wait for the transition to high */
-		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
-			;
-		/* Finally, enable the PSC.
-		 * Receiver must always be enabled; even when we only want
-		 * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
-		psc_cmd = MPC52xx_PSC_RX_ENABLE;
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			psc_cmd |= MPC52xx_PSC_TX_ENABLE;
-		out_8(&regs->command, psc_cmd);
 		spin_unlock_irqrestore(&psc_dma->lock, flags);
 
+		out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
-		/* Turn off the PSC */
 		s->active = 0;
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			if (!psc_dma->playback.active) {
-				out_8(&regs->command, 2 << 4);	/* reset rx */
-				out_8(&regs->command, 3 << 4);	/* reset tx */
-				out_8(&regs->command, 4 << 4);	/* reset err */
-			}
-		} else {
-			out_8(&regs->command, 3 << 4);	/* reset tx */
-			out_8(&regs->command, 4 << 4);	/* reset err */
-			if (!psc_dma->capture.active)
-				out_8(&regs->command, 2 << 4);	/* reset rx */
-		}
 
+		spin_lock_irqsave(&psc_dma->lock, flags);
 		bcom_disable(s->bcom_task);
-		while (!bcom_queue_empty(s->bcom_task))
-			bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+			bcom_gen_bd_rx_reset(s->bcom_task);
+		else
+			bcom_gen_bd_tx_reset(s->bcom_task);
+		spin_unlock_irqrestore(&psc_dma->lock, flags);
 
 		break;
 
@@ -265,44 +229,11 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
 		imr |= MPC52xx_PSC_IMR_TXEMP;
 	if (psc_dma->capture.active)
 		imr |= MPC52xx_PSC_IMR_ORERR;
-	out_be16(&regs->isr_imr.imr, imr);
+	out_be16(&regs->isr_imr.imr, psc_dma->imr | imr);
 
 	return 0;
 }
 
-/**
- * psc_dma_shutdown: shutdown the data transfer on a stream
- *
- * Shutdown the PSC if there are no other substreams open.
- */
-void psc_dma_shutdown(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
-
-	dev_dbg(psc_dma->dev, "psc_dma_shutdown(substream=%p)\n", substream);
-
-	/*
-	 * If this is the last active substream, disable the PSC and release
-	 * the IRQ.
-	 */
-	if (!psc_dma->playback.active &&
-	    !psc_dma->capture.active) {
-
-		/* Disable all interrupts and reset the PSC */
-		out_be16(&psc_dma->psc_regs->isr_imr.imr, 0);
-		out_8(&psc_dma->psc_regs->command, 3 << 4); /* reset tx */
-		out_8(&psc_dma->psc_regs->command, 2 << 4); /* reset rx */
-		out_8(&psc_dma->psc_regs->command, 1 << 4); /* reset mode */
-		out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
-
-		/* Release irqs */
-		free_irq(psc_dma->irq, psc_dma);
-		free_irq(psc_dma->capture.irq, &psc_dma->capture);
-		free_irq(psc_dma->playback.irq, &psc_dma->playback);
-	}
-}
 
 /* ---------------------------------------------------------------------
  * The PSC DMA 'ASoC platform' driver
@@ -312,62 +243,78 @@ void psc_dma_shutdown(struct snd_pcm_substream *substream,
  * interaction with the attached codec
  */
 
-static const struct snd_pcm_hardware psc_dma_pcm_hardware = {
+static const struct snd_pcm_hardware psc_dma_hardware = {
 	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
 		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		SNDRV_PCM_INFO_BATCH,
 	.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
-		   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
 	.rate_min = 8000,
 	.rate_max = 48000,
-	.channels_min = 2,
+	.channels_min = 1,
 	.channels_max = 2,
 	.period_bytes_max	= 1024 * 1024,
 	.period_bytes_min	= 32,
 	.periods_min		= 2,
 	.periods_max		= 256,
 	.buffer_bytes_max	= 2 * 1024 * 1024,
-	.fifo_size		= 0,
+	.fifo_size		= 512,
 };
 
-static int psc_dma_pcm_open(struct snd_pcm_substream *substream)
+static int psc_dma_open(struct snd_pcm_substream *substream)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
 	struct psc_dma_stream *s;
+	int rc;
 
-	dev_dbg(psc_dma->dev, "psc_dma_pcm_open(substream=%p)\n", substream);
+	dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream);
 
 	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
 		s = &psc_dma->capture;
 	else
 		s = &psc_dma->playback;
 
-	snd_soc_set_runtime_hwparams(substream, &psc_dma_pcm_hardware);
+	snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware);
+
+	rc = snd_pcm_hw_constraint_integer(runtime,
+		SNDRV_PCM_HW_PARAM_PERIODS);
+	if (rc < 0) {
+		dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+		return rc;
+	}
 
 	s->stream = substream;
 	return 0;
 }
 
-static int psc_dma_pcm_close(struct snd_pcm_substream *substream)
+static int psc_dma_close(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
 	struct psc_dma_stream *s;
 
-	dev_dbg(psc_dma->dev, "psc_dma_pcm_close(substream=%p)\n", substream);
+	dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
 
 	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
 		s = &psc_dma->capture;
 	else
 		s = &psc_dma->playback;
 
+	if (!psc_dma->playback.active &&
+	    !psc_dma->capture.active) {
+
+		/* Disable all interrupts and reset the PSC */
+		out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+		out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
+	}
 	s->stream = NULL;
 	return 0;
 }
 
 static snd_pcm_uframes_t
-psc_dma_pcm_pointer(struct snd_pcm_substream *substream)
+psc_dma_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
@@ -384,60 +331,78 @@ psc_dma_pcm_pointer(struct snd_pcm_substream *substream)
 	return bytes_to_frames(substream->runtime, count);
 }
 
-static struct snd_pcm_ops psc_dma_pcm_ops = {
-	.open		= psc_dma_pcm_open,
-	.close		= psc_dma_pcm_close,
+static int
+psc_dma_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static struct snd_pcm_ops psc_dma_ops = {
+	.open		= psc_dma_open,
+	.close		= psc_dma_close,
+	.hw_free	= psc_dma_hw_free,
 	.ioctl		= snd_pcm_lib_ioctl,
-	.pointer	= psc_dma_pcm_pointer,
+	.pointer	= psc_dma_pointer,
+	.trigger	= psc_dma_trigger,
+	.hw_params	= psc_dma_hw_params,
 };
 
-static u64 psc_dma_pcm_dmamask = 0xffffffff;
-static int psc_dma_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+static u64 psc_dma_dmamask = 0xffffffff;
+static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
 			   struct snd_pcm *pcm)
 {
 	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-	size_t size = psc_dma_pcm_hardware.buffer_bytes_max;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+	size_t size = psc_dma_hardware.buffer_bytes_max;
 	int rc = 0;
 
-	dev_dbg(rtd->socdev->dev, "psc_dma_pcm_new(card=%p, dai=%p, pcm=%p)\n",
+	dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
 		card, dai, pcm);
 
 	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &psc_dma_pcm_dmamask;
+		card->dev->dma_mask = &psc_dma_dmamask;
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = 0xffffffff;
 
 	if (pcm->streams[0].substream) {
-		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-					&pcm->streams[0].substream->dma_buffer);
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+				size, &pcm->streams[0].substream->dma_buffer);
 		if (rc)
 			goto playback_alloc_err;
 	}
 
 	if (pcm->streams[1].substream) {
-		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-					&pcm->streams[1].substream->dma_buffer);
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+				size, &pcm->streams[1].substream->dma_buffer);
 		if (rc)
 			goto capture_alloc_err;
 	}
 
+	if (rtd->socdev->card->codec->ac97)
+		rtd->socdev->card->codec->ac97->private_data = psc_dma;
+
 	return 0;
 
  capture_alloc_err:
 	if (pcm->streams[0].substream)
 		snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+
  playback_alloc_err:
 	dev_err(card->dev, "Cannot allocate buffer(s)\n");
+
 	return -ENOMEM;
 }
 
-static void psc_dma_pcm_free(struct snd_pcm *pcm)
+static void psc_dma_free(struct snd_pcm *pcm)
 {
 	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
 	struct snd_pcm_substream *substream;
 	int stream;
 
-	dev_dbg(rtd->socdev->dev, "psc_dma_pcm_free(pcm=%p)\n", pcm);
+	dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
 
 	for (stream = 0; stream < 2; stream++) {
 		substream = pcm->streams[stream].substream;
@@ -449,10 +414,151 @@ static void psc_dma_pcm_free(struct snd_pcm *pcm)
 	}
 }
 
-struct snd_soc_platform psc_dma_pcm_soc_platform = {
+struct snd_soc_platform mpc5200_audio_dma_platform = {
 	.name		= "mpc5200-psc-audio",
-	.pcm_ops	= &psc_dma_pcm_ops,
-	.pcm_new	= &psc_dma_pcm_new,
-	.pcm_free	= &psc_dma_pcm_free,
+	.pcm_ops	= &psc_dma_ops,
+	.pcm_new	= &psc_dma_new,
+	.pcm_free	= &psc_dma_free,
 };
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
+
+int mpc5200_audio_dma_create(struct of_device *op)
+{
+	phys_addr_t fifo;
+	struct psc_dma *psc_dma;
+	struct resource res;
+	int size, irq, rc;
+	const __be32 *prop;
+	void __iomem *regs;
+
+	/* Fetch the registers and IRQ of the PSC */
+	irq = irq_of_parse_and_map(op->node, 0);
+	if (of_address_to_resource(op->node, 0, &res)) {
+		dev_err(&op->dev, "Missing reg property\n");
+		return -ENODEV;
+	}
+	regs = ioremap(res.start, 1 + res.end - res.start);
+	if (!regs) {
+		dev_err(&op->dev, "Could not map registers\n");
+		return -ENODEV;
+	}
+
+	/* Allocate and initialize the driver private data */
+	psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);
+	if (!psc_dma) {
+		iounmap(regs);
+		return -ENOMEM;
+	}
+
+	/* Get the PSC ID */
+	prop = of_get_property(op->node, "cell-index", &size);
+	if (!prop || size < sizeof *prop)
+		return -ENODEV;
+
+	spin_lock_init(&psc_dma->lock);
+	psc_dma->id = be32_to_cpu(*prop);
+	psc_dma->irq = irq;
+	psc_dma->psc_regs = regs;
+	psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;
+	psc_dma->dev = &op->dev;
+	psc_dma->playback.psc_dma = psc_dma;
+	psc_dma->capture.psc_dma = psc_dma;
+	snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id);
+
+	/* Find the address of the fifo data registers and setup the
+	 * DMA tasks */
+	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+	psc_dma->capture.bcom_task =
+		bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);
+	psc_dma->playback.bcom_task =
+		bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo);
+	if (!psc_dma->capture.bcom_task ||
+	    !psc_dma->playback.bcom_task) {
+		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
+		iounmap(regs);
+		kfree(psc_dma);
+		return -ENODEV;
+	}
+
+	/* Disable all interrupts and reset the PSC */
+	out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+	 /* reset receiver */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX);
+	 /* reset transmitter */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX);
+	 /* reset error */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT);
+	 /* reset mode */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1);
+
+	/* Set up mode register;
+	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
+	 * Second write: register Normal mode for non loopback
+	 */
+	out_8(&psc_dma->psc_regs->mode, 0);
+	out_8(&psc_dma->psc_regs->mode, 0);
+
+	/* Set the TX and RX fifo alarm thresholds */
+	out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);
+	out_8(&psc_dma->fifo_regs->rfcntl, 0x4);
+	out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);
+	out_8(&psc_dma->fifo_regs->tfcntl, 0x7);
+
+	/* Lookup the IRQ numbers */
+	psc_dma->playback.irq =
+		bcom_get_task_irq(psc_dma->playback.bcom_task);
+	psc_dma->capture.irq =
+		bcom_get_task_irq(psc_dma->capture.bcom_task);
+
+	rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
+			 "psc-dma-status", psc_dma);
+	rc |= request_irq(psc_dma->capture.irq,
+			  &psc_dma_bcom_irq_rx, IRQF_SHARED,
+			  "psc-dma-capture", &psc_dma->capture);
+	rc |= request_irq(psc_dma->playback.irq,
+			  &psc_dma_bcom_irq_tx, IRQF_SHARED,
+			  "psc-dma-playback", &psc_dma->playback);
+	if (rc) {
+		free_irq(psc_dma->irq, psc_dma);
+		free_irq(psc_dma->capture.irq,
+			 &psc_dma->capture);
+		free_irq(psc_dma->playback.irq,
+			 &psc_dma->playback);
+		return -ENODEV;
+	}
 
+	/* Save what we've done so it can be found again later */
+	dev_set_drvdata(&op->dev, psc_dma);
+
+	/* Tell the ASoC OF helpers about it */
+	return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
+
+int mpc5200_audio_dma_destroy(struct of_device *op)
+{
+	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
+
+	dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
+
+	snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+
+	bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
+	bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
+
+	/* Release irqs */
+	free_irq(psc_dma->irq, psc_dma);
+	free_irq(psc_dma->capture.irq, &psc_dma->capture);
+	free_irq(psc_dma->playback.irq, &psc_dma->playback);
+
+	iounmap(psc_dma->psc_regs);
+	kfree(psc_dma);
+	dev_set_drvdata(&op->dev, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index a33232c..7414c6f 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -5,8 +5,10 @@
 #ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__
 #define __SOUND_SOC_FSL_MPC5200_DMA_H__
 
+#define PSC_STREAM_NAME_LEN 32
+
 /**
- * psc_dma_stream - Data specific to a single stream (playback or capture)
+ * psc_ac97_stream - Data specific to a single stream (playback or capture)
  * @active:		flag indicating if the stream is active
  * @psc_dma:		pointer back to parent psc_dma data structure
  * @bcom_task:		bestcomm task structure
@@ -17,6 +19,9 @@
  * @period_bytes:	size of DMA period in bytes
  */
 struct psc_dma_stream {
+	struct snd_pcm_runtime *runtime;
+	snd_pcm_uframes_t appl_ptr;
+
 	int active;
 	struct psc_dma *psc_dma;
 	struct bcom_task *bcom_task;
@@ -27,6 +32,7 @@ struct psc_dma_stream {
 	dma_addr_t period_next_pt;
 	dma_addr_t period_current_pt;
 	int period_bytes;
+	int period_size;
 };
 
 /**
@@ -48,9 +54,12 @@ struct psc_dma {
 	struct mpc52xx_psc_fifo __iomem *fifo_regs;
 	unsigned int irq;
 	struct device *dev;
-	struct snd_soc_dai dai;
 	spinlock_t lock;
 	u32 sicr;
+	uint sysclk;
+	int imr;
+	int id;
+	unsigned int slots;
 
 	/* per-stream data */
 	struct psc_dma_stream playback;
@@ -58,24 +67,28 @@ struct psc_dma {
 
 	/* Statistics */
 	struct {
-		int overrun_count;
-		int underrun_count;
+		unsigned long overrun_count;
+		unsigned long underrun_count;
 	} stats;
 };
 
+int mpc5200_audio_dma_create(struct of_device *op);
+int mpc5200_audio_dma_destroy(struct of_device *op);
 
-int psc_dma_startup(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai);
-
-int psc_dma_hw_free(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai);
-
-void psc_dma_shutdown(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai);
+extern struct snd_soc_platform mpc5200_audio_dma_platform;
 
-int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
-			   struct snd_soc_dai *dai);
+/* whack this after Timur's patch is merged in to arch/powerpc/include/asm/delay.h */
+#define spin_event_timeout(condition, timeout, delay, rc)                   \
+{                                                                           \
+       unsigned long __loops = tb_ticks_per_usec * timeout;                \
+       unsigned long __start = get_tbl();                                  \
+       while ((rc = (condition)) && (tb_ticks_since(__start) <= __loops)) \
+               if (delay)                                                  \
+                       udelay(delay);                                      \
+               else                                                        \
+                       cpu_relax();                                        \
+}
+/* whack this after Timur's patch is merged in to arch/powerpc/include/asm/delay.h */
 
-extern struct snd_soc_platform psc_dma_pcm_soc_platform;
 
 #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 12a7917..ce8de90 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -3,34 +3,22 @@
  * ALSA SoC Digital Audio Interface (DAI) driver
  *
  * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/gen_bd.h>
 #include <asm/mpc52xx_psc.h>
 
+#include "mpc5200_psc_i2s.h"
 #include "mpc5200_dma.h"
 
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
-MODULE_LICENSE("GPL");
-
 /**
  * PSC_I2S_RATES: sample rates supported by the I2S
  *
@@ -46,8 +34,7 @@ MODULE_LICENSE("GPL");
  * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
  */
 #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
-			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \
-			 SNDRV_PCM_FMTBIT_S32_BE)
+			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
@@ -82,8 +69,6 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
 	}
 	out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode);
 
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
 	return 0;
 }
 
@@ -140,16 +125,13 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
  * psc_i2s_dai_template: template CPU Digital Audio Interface
  */
 static struct snd_soc_dai_ops psc_i2s_dai_ops = {
-	.startup	= psc_dma_startup,
 	.hw_params	= psc_i2s_hw_params,
-	.hw_free	= psc_dma_hw_free,
-	.shutdown	= psc_dma_shutdown,
-	.trigger	= psc_dma_trigger,
 	.set_sysclk	= psc_i2s_set_sysclk,
 	.set_fmt	= psc_i2s_set_fmt,
 };
 
-static struct snd_soc_dai psc_i2s_dai_template = {
+struct snd_soc_dai psc_i2s_dai[] = {{
+	.name   = "I2S",
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
@@ -163,71 +145,8 @@ static struct snd_soc_dai psc_i2s_dai_template = {
 		.formats = PSC_I2S_FORMATS,
 	},
 	.ops = &psc_i2s_dai_ops,
-};
-
-/* ---------------------------------------------------------------------
- * Sysfs attributes for debugging
- */
-
-static ssize_t psc_i2s_status_show(struct device *dev,
-			   struct device_attribute *attr, char *buf)
-{
-	struct psc_dma *psc_dma = dev_get_drvdata(dev);
-
-	return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x "
-			"tfnum=%i tfstat=0x%.4x\n",
-			in_be16(&psc_dma->psc_regs->sr_csr.status),
-			in_be32(&psc_dma->psc_regs->sicr),
-			in_be16(&psc_dma->fifo_regs->rfnum) & 0x1ff,
-			in_be16(&psc_dma->fifo_regs->rfstat),
-			in_be16(&psc_dma->fifo_regs->tfnum) & 0x1ff,
-			in_be16(&psc_dma->fifo_regs->tfstat));
-}
-
-static int *psc_i2s_get_stat_attr(struct psc_dma *psc_dma, const char *name)
-{
-	if (strcmp(name, "playback_underrun") == 0)
-		return &psc_dma->stats.underrun_count;
-	if (strcmp(name, "capture_overrun") == 0)
-		return &psc_dma->stats.overrun_count;
-
-	return NULL;
-}
-
-static ssize_t psc_i2s_stat_show(struct device *dev,
-				 struct device_attribute *attr, char *buf)
-{
-	struct psc_dma *psc_dma = dev_get_drvdata(dev);
-	int *attrib;
-
-	attrib = psc_i2s_get_stat_attr(psc_dma, attr->attr.name);
-	if (!attrib)
-		return 0;
-
-	return sprintf(buf, "%i\n", *attrib);
-}
-
-static ssize_t psc_i2s_stat_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t count)
-{
-	struct psc_dma *psc_dma = dev_get_drvdata(dev);
-	int *attrib;
-
-	attrib = psc_i2s_get_stat_attr(psc_dma, attr->attr.name);
-	if (!attrib)
-		return 0;
-
-	*attrib = simple_strtoul(buf, NULL, 0);
-	return count;
-}
-
-static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);
-static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show,
-			psc_i2s_stat_store);
-static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,
-			psc_i2s_stat_store);
+} };
+EXPORT_SYMBOL_GPL(psc_i2s_dai);
 
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
@@ -237,82 +156,26 @@ static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,
 static int __devinit psc_i2s_of_probe(struct of_device *op,
 				      const struct of_device_id *match)
 {
-	phys_addr_t fifo;
+	int rc;
 	struct psc_dma *psc_dma;
-	struct resource res;
-	int size, psc_id, irq, rc;
-	const __be32 *prop;
-	void __iomem *regs;
-
-	dev_dbg(&op->dev, "probing psc i2s device\n");
-
-	/* Get the PSC ID */
-	prop = of_get_property(op->node, "cell-index", &size);
-	if (!prop || size < sizeof *prop)
-		return -ENODEV;
-	psc_id = be32_to_cpu(*prop);
-
-	/* Fetch the registers and IRQ of the PSC */
-	irq = irq_of_parse_and_map(op->node, 0);
-	if (of_address_to_resource(op->node, 0, &res)) {
-		dev_err(&op->dev, "Missing reg property\n");
-		return -ENODEV;
-	}
-	regs = ioremap(res.start, 1 + res.end - res.start);
-	if (!regs) {
-		dev_err(&op->dev, "Could not map registers\n");
-		return -ENODEV;
-	}
+	struct mpc52xx_psc __iomem *regs;
 
-	/* Allocate and initialize the driver private data */
-	psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);
-	if (!psc_dma) {
-		iounmap(regs);
-		return -ENOMEM;
-	}
-	spin_lock_init(&psc_dma->lock);
-	psc_dma->irq = irq;
-	psc_dma->psc_regs = regs;
-	psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;
-	psc_dma->dev = &op->dev;
-	psc_dma->playback.psc_dma = psc_dma;
-	psc_dma->capture.psc_dma = psc_dma;
-	snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_id+1);
-
-	/* Fill out the CPU DAI structure */
-	memcpy(&psc_dma->dai, &psc_i2s_dai_template, sizeof psc_dma->dai);
-	psc_dma->dai.private_data = psc_dma;
-	psc_dma->dai.name = psc_dma->name;
-	psc_dma->dai.id = psc_id;
-
-	/* Find the address of the fifo data registers and setup the
-	 * DMA tasks */
-	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
-	psc_dma->capture.bcom_task =
-		bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);
-	psc_dma->playback.bcom_task =
-		bcom_psc_gen_bd_tx_init(psc_id, 10, fifo);
-	if (!psc_dma->capture.bcom_task ||
-	    !psc_dma->playback.bcom_task) {
-		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
-		iounmap(regs);
-		kfree(psc_dma);
-		return -ENODEV;
+	rc = mpc5200_audio_dma_create(op);
+	if (rc != 0)
+		return rc;
+
+	rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+	if (rc != 0) {
+		pr_err("Failed to register DAI\n");
+		return 0;
 	}
 
-	/* Disable all interrupts and reset the PSC */
-	out_be16(&psc_dma->psc_regs->isr_imr.imr, 0);
-	out_8(&psc_dma->psc_regs->command, 3 << 4); /* reset transmitter */
-	out_8(&psc_dma->psc_regs->command, 2 << 4); /* reset receiver */
-	out_8(&psc_dma->psc_regs->command, 1 << 4); /* reset mode */
-	out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
+	psc_dma = dev_get_drvdata(&op->dev);
+	regs = psc_dma->psc_regs;
 
 	/* Configure the serial interface mode; defaulting to CODEC8 mode */
 	psc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
 			MPC52xx_PSC_SICR_CLKPOL;
-	if (of_get_property(op->node, "fsl,cellslave", NULL))
-		psc_dma->sicr |= MPC52xx_PSC_SICR_CELLSLAVE |
-				 MPC52xx_PSC_SICR_GENCLK;
 	out_be32(&psc_dma->psc_regs->sicr,
 		 psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
 
@@ -321,66 +184,37 @@ static int __devinit psc_i2s_of_probe(struct of_device *op,
 	if (!of_get_property(op->node, "codec-handle", NULL))
 		return 0;
 
-	/* Set up mode register;
-	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
-	 * Second write: register Normal mode for non loopback
-	 */
-	out_8(&psc_dma->psc_regs->mode, 0);
-	out_8(&psc_dma->psc_regs->mode, 0);
-
-	/* Set the TX and RX fifo alarm thresholds */
-	out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);
-	out_8(&psc_dma->fifo_regs->rfcntl, 0x4);
-	out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);
-	out_8(&psc_dma->fifo_regs->tfcntl, 0x7);
-
-	/* Lookup the IRQ numbers */
-	psc_dma->playback.irq =
-		bcom_get_task_irq(psc_dma->playback.bcom_task);
-	psc_dma->capture.irq =
-		bcom_get_task_irq(psc_dma->capture.bcom_task);
-
-	/* Save what we've done so it can be found again later */
-	dev_set_drvdata(&op->dev, psc_dma);
-
-	/* Register the SYSFS files */
-	rc = device_create_file(psc_dma->dev, &dev_attr_status);
-	rc |= device_create_file(psc_dma->dev, &dev_attr_capture_overrun);
-	rc |= device_create_file(psc_dma->dev, &dev_attr_playback_underrun);
-	if (rc)
-		dev_info(psc_dma->dev, "error creating sysfs files\n");
-
-	snd_soc_register_platform(&psc_dma_pcm_soc_platform);
-
-	/* Tell the ASoC OF helpers about it */
-	of_snd_soc_register_platform(&psc_dma_pcm_soc_platform, op->node,
-				     &psc_dma->dai);
+	/* Due to errata in the dma mode; need to line up enabling
+	 * the transmitter with a transition on the frame sync
+	 * line */
+
+	/* first make sure it is low */
+	while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
+		;
+	/* then wait for the transition to high */
+	while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
+		;
+	/* Finally, enable the PSC.
+	 * Receiver must always be enabled; even when we only want
+	 * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
+
+	/* Go */
+	out_8(&psc_dma->psc_regs->command,
+			MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
 
 	return 0;
+
 }
 
 static int __devexit psc_i2s_of_remove(struct of_device *op)
 {
-	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
-
-	dev_dbg(&op->dev, "psc_i2s_remove()\n");
-
-	snd_soc_unregister_platform(&psc_dma_pcm_soc_platform);
-
-	bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
-	bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
-
-	iounmap(psc_dma->psc_regs);
-	iounmap(psc_dma->fifo_regs);
-	kfree(psc_dma);
-	dev_set_drvdata(&op->dev, NULL);
-
-	return 0;
+	return mpc5200_audio_dma_destroy(op);
 }
 
 /* Match table for of_platform binding */
 static struct of_device_id psc_i2s_match[] __devinitdata = {
 	{ .compatible = "fsl,mpc5200-psc-i2s", },
+	{ .compatible = "fsl,mpc5200b-psc-i2s", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, psc_i2s_match);
@@ -411,4 +245,7 @@ static void __exit psc_i2s_exit(void)
 }
 module_exit(psc_i2s_exit);
 
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
+MODULE_LICENSE("GPL");
 
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h
new file mode 100644
index 0000000..ce55e07
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_i2s.h
@@ -0,0 +1,12 @@
+/*
+ * Freescale MPC5200 PSC in I2S mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+
+extern struct snd_soc_dai psc_i2s_dai[];
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */

^ permalink raw reply related

* [PATCH V4 3/5] AC97 driver for mpc5200
From: Jon Smirl @ 2009-05-25 22:15 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie, timur
In-Reply-To: <20090525221406.21370.30326.stgit@terra>

AC97 driver for mpc5200

I've implemented retries for when the AC97 hardware doesn't reset on
first try. About 10% of the time both the Efika and pcm030 AC97 codecs
don't reset on first try and need to be poked multiple times.  Failure
is indicated by not having the link clock start ticking. Every once in
a while even five pokes won't get the link started and I have to power
cycle.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
 sound/soc/fsl/Kconfig            |   11 +
 sound/soc/fsl/Makefile           |    1 
 sound/soc/fsl/mpc5200_psc_ac97.c |  331 ++++++++++++++++++++++++++++++++++++++
 sound/soc/fsl/mpc5200_psc_ac97.h |   15 ++
 4 files changed, 358 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.c
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 1918c78..3bce952 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -29,3 +29,14 @@ config SND_SOC_MPC5200_I2S
 	select PPC_BESTCOMM_GEN_BD
 	help
 	  Say Y here to support the MPC5200 PSCs in I2S mode.
+
+config SND_SOC_MPC5200_AC97
+	tristate "Freescale MPC5200 PSC in AC97 mode driver"
+	depends on PPC_MPC52xx && PPC_BESTCOMM
+	select AC97_BUS
+	select SND_MPC52xx_DMA
+	select PPC_BESTCOMM_GEN_BD
+	help
+	  Say Y here to support the MPC5200 PSCs in AC97 mode.
+
+
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 7731ef2..14631a1 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -13,4 +13,5 @@ obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
 obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
 
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
new file mode 100644
index 0000000..3e6838c
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -0,0 +1,331 @@
+/*
+ * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip.
+ *
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/time.h>
+#include <asm/delay.h>
+#include <asm/mpc52xx_psc.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+
+#define DRV_NAME "mpc5200-psc-ac97"
+
+/* ALSA only supports a single AC97 device so static is recommend here */
+static struct psc_dma *psc_dma;
+
+static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+	int rc;
+	unsigned int val;
+
+	/* Wait for command send status zero = ready */
+	spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) &
+				MPC52xx_PSC_SR_CMDSEND), 100, 0, rc);
+	if (rc != 0) {
+		pr_err("timeout on ac97 bus (rdy)\n");
+		return -ENODEV;
+	}
+	/* Send the read */
+	out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
+
+	/* Wait for the answer */
+	spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
+				MPC52xx_PSC_SR_DATA_VAL), 100, 0, rc);
+	if (rc != 0) {
+		pr_err("timeout on ac97 read (val) %x\n",
+				in_be16(&psc_dma->psc_regs->sr_csr.status));
+		return -ENODEV;
+	}
+	/* Get the data */
+	val = in_be32(&psc_dma->psc_regs->ac97_data);
+	if (((val >> 24) & 0x7f) != reg) {
+		pr_err("reg echo error on ac97 read\n");
+		return -ENODEV;
+	}
+	val = (val >> 8) & 0xffff;
+
+	return (unsigned short) val;
+}
+
+static void psc_ac97_write(struct snd_ac97 *ac97,
+				unsigned short reg, unsigned short val)
+{
+	int rc;
+
+	/* Wait for command status zero = ready */
+	spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) &
+				MPC52xx_PSC_SR_CMDSEND), 100, 0, rc);
+	if (rc != 0) {
+		pr_err("timeout on ac97 bus (write)\n");
+		return;
+	}
+	/* Write data */
+	out_be32(&psc_dma->psc_regs->ac97_cmd,
+			((reg & 0x7f) << 24) | (val << 8));
+}
+
+static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	int rc;
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
+	spin_event_timeout(1, 3, 0, rc);
+	out_be32(&regs->sicr, psc_dma->sicr);
+}
+
+static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	int rc;
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	/* Do a cold reset */
+	out_8(&regs->op1, MPC52xx_PSC_OP_RES);
+	spin_event_timeout(1, 10, 0, rc);
+	out_8(&regs->op0, MPC52xx_PSC_OP_RES);
+	spin_event_timeout(1, 50, 0, rc);
+	psc_ac97_warm_reset(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read		= psc_ac97_read,
+	.write		= psc_ac97_write,
+	.reset		= psc_ac97_cold_reset,
+	.warm_reset	= psc_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+
+	dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+		" periods=%i buffer_size=%i  buffer_bytes=%i channels=%i"
+		" rate=%i format=%i\n",
+		__func__, substream, params_period_size(params),
+		params_period_bytes(params), params_periods(params),
+		params_buffer_size(params), params_buffer_bytes(params),
+		params_channels(params), params_rate(params),
+		params_format(params));
+
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (params_channels(params) == 1)
+			psc_dma->slots |= 0x00000100;
+		else
+			psc_dma->slots |= 0x00000300;
+	} else {
+		if (params_channels(params) == 1)
+			psc_dma->slots |= 0x01000000;
+		else
+			psc_dma->slots |= 0x03000000;
+	}
+	out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+
+	return 0;
+}
+
+static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+
+	if (params_channels(params) == 1)
+		out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
+	else
+		out_be32(&psc_dma->psc_regs->ac97_slots, 0x03000000);
+
+	return 0;
+}
+
+static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+							struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+			psc_dma->slots &= 0xFFFF0000;
+		else
+			psc_dma->slots &= 0x0000FFFF;
+
+		out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+		break;
+	}
+	return 0;
+}
+
+static int psc_ac97_probe(struct platform_device *pdev,
+					struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	/* Go */
+	out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * ALSA SoC Bindings
+ *
+ * - Digital Audio Interface (DAI) template
+ * - create/destroy dai hooks
+ */
+
+/**
+ * psc_ac97_dai_template: template CPU Digital Audio Interface
+ */
+static struct snd_soc_dai_ops psc_ac97_analog_ops = {
+	.hw_params	= psc_ac97_hw_analog_params,
+	.trigger	= psc_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops psc_ac97_digital_ops = {
+	.hw_params	= psc_ac97_hw_digital_params,
+};
+
+struct snd_soc_dai psc_ac97_dai[] = {
+{
+	.name   = "AC97",
+	.ac97_control = 1,
+	.probe	= psc_ac97_probe,
+	.playback = {
+		.channels_min   = 1,
+		.channels_max   = 6,
+		.rates          = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_BE,
+	},
+	.capture = {
+		.channels_min   = 1,
+		.channels_max   = 2,
+		.rates          = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_BE,
+	},
+	.ops = &psc_ac97_analog_ops,
+},
+{
+	.name   = "SPDIF",
+	.ac97_control = 1,
+	.playback = {
+		.channels_min   = 1,
+		.channels_max   = 2,
+		.rates          = SNDRV_PCM_RATE_32000 | \
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
+	},
+	.ops = &psc_ac97_digital_ops,
+} };
+EXPORT_SYMBOL_GPL(psc_ac97_dai);
+
+
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit psc_ac97_of_probe(struct of_device *op,
+				      const struct of_device_id *match)
+{
+	int rc, i;
+	struct snd_ac97 ac97;
+	struct mpc52xx_psc __iomem *regs;
+
+	rc = mpc5200_audio_dma_create(op);
+	if (rc != 0)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+		psc_ac97_dai[i].dev = &op->dev;
+
+	rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+	if (rc != 0) {
+		dev_err(&op->dev, "Failed to register DAI\n");
+		return rc;
+	}
+
+	psc_dma = dev_get_drvdata(&op->dev);
+	regs = psc_dma->psc_regs;
+	ac97.private_data = psc_dma;
+
+	for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+		psc_ac97_dai[i].private_data = psc_dma;
+
+	psc_dma->imr = 0;
+	out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+
+	/* Configure the serial interface mode to AC97 */
+	psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97;
+	out_be32(&regs->sicr, psc_dma->sicr);
+
+	/* No slots active */
+	out_be32(&regs->ac97_slots, 0x00000000);
+
+	return 0;
+}
+
+static int __devexit psc_ac97_of_remove(struct of_device *op)
+{
+	return mpc5200_audio_dma_destroy(op);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id psc_ac97_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5200-psc-ac97", },
+	{ .compatible = "fsl,mpc5200b-psc-ac97", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, psc_ac97_match);
+
+static struct of_platform_driver psc_ac97_driver = {
+	.match_table = psc_ac97_match,
+	.probe = psc_ac97_of_probe,
+	.remove = __devexit_p(psc_ac97_of_remove),
+	.driver = {
+		.name = "mpc5200-psc-ac97",
+		.owner = THIS_MODULE,
+	},
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ * for the PSC in AC97 mode.
+ */
+static int __init psc_ac97_init(void)
+{
+	return of_register_platform_driver(&psc_ac97_driver);
+}
+module_init(psc_ac97_init);
+
+static void __exit psc_ac97_exit(void)
+{
+	of_unregister_platform_driver(&psc_ac97_driver);
+}
+module_exit(psc_ac97_exit);
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION("mpc5200 AC97 module");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
new file mode 100644
index 0000000..4bc18c3
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -0,0 +1,15 @@
+/*
+ * Freescale MPC5200 PSC in AC97 mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+
+extern struct snd_soc_dai psc_ac97_dai[];
+
+#define MPC5200_AC97_NORMAL 0
+#define MPC5200_AC97_SPDIF 1
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */

^ permalink raw reply related

* [PATCH V4 4/5] Support for AC97 on Phytec pmc030 base board.
From: Jon Smirl @ 2009-05-25 22:15 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie, timur
In-Reply-To: <20090525221406.21370.30326.stgit@terra>

Support for AC97 on Phytec pmc030 base board. A wm9712 AC97 codec is used.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
 sound/soc/fsl/Kconfig               |    7 +++
 sound/soc/fsl/Makefile              |    3 +
 sound/soc/fsl/pcm030-audio-fabric.c |   90 +++++++++++++++++++++++++++++++++++
 3 files changed, 100 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/fsl/pcm030-audio-fabric.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3bce952..79579ae 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -39,4 +39,11 @@ config SND_SOC_MPC5200_AC97
 	help
 	  Say Y here to support the MPC5200 PSCs in AC97 mode.
 
+config SND_MPC52xx_SOC_PCM030
+	tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712"
+	depends on PPC_MPC5200_SIMPLE
+	select SND_SOC_MPC5200_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for sound on the Phytec pcm030 baseboard.
 
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 14631a1..66d88c8 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -15,3 +15,6 @@ obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
 obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
 obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
 
+# MPC5200 Machine Support
+obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
+
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
new file mode 100644
index 0000000..8766f7a
--- /dev/null
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -0,0 +1,90 @@
+/*
+ * Phytec pcm030 driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/wm9712.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link pcm030_fabric_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 Analog",
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+	.name = "AC97",
+	.stream_name = "AC97 IEC958",
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int pcm030_fabric_init(void)
+{
+	struct platform_device *pdev;
+	int rc;
+
+	if (!machine_is_compatible("phytec,pcm030"))
+		return -ENODEV;
+
+	card.platform = &mpc5200_audio_dma_platform;
+	card.name = "pcm030";
+	card.dai_link = pcm030_fabric_dai;
+	card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
+
+	device.card = &card;
+	device.codec_dev = &soc_codec_dev_wm9712;
+
+	pdev = platform_device_alloc("soc-audio", 1);
+	if (!pdev) {
+		pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, &device);
+	device.dev = &pdev->dev;
+
+	rc = platform_device_add(pdev);
+	if (rc) {
+		pr_err("pcm030_fabric_init: platform_device_add() failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+module_init(pcm030_fabric_init);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 pcm030 fabric driver");
+MODULE_LICENSE("GPL");
+

^ permalink raw reply related

* [PATCH V4 5/5] Fabric bindings for STAC9766 on the Efika
From: Jon Smirl @ 2009-05-25 22:15 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie, timur
In-Reply-To: <20090525221406.21370.30326.stgit@terra>

Fabric bindings for STAC9766 AC97 codec on the Efika.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
 sound/soc/fsl/Kconfig              |    8 +++
 sound/soc/fsl/Makefile             |    1 
 sound/soc/fsl/efika-audio-fabric.c |   90 ++++++++++++++++++++++++++++++++++++
 3 files changed, 99 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/fsl/efika-audio-fabric.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 79579ae..f571c6e 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -47,3 +47,11 @@ config SND_MPC52xx_SOC_PCM030
 	help
 	  Say Y if you want to add support for sound on the Phytec pcm030 baseboard.
 
+config SND_MPC52xx_SOC_EFIKA
+	tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
+	depends on PPC_EFIKA
+	select SND_SOC_MPC5200_AC97
+	select SND_SOC_STAC9766
+	help
+	  Say Y if you want to add support for sound on the Efika.
+
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 66d88c8..a83a739 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
 
 # MPC5200 Machine Support
 obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
+obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
new file mode 100644
index 0000000..85b0e75
--- /dev/null
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -0,0 +1,90 @@
+/*
+ * Efika driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/stac9766.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link efika_fabric_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 Analog",
+	.codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+	.name = "AC97",
+	.stream_name = "AC97 IEC958",
+	.codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int efika_fabric_init(void)
+{
+	struct platform_device *pdev;
+	int rc;
+
+	if (!machine_is_compatible("bplan,efika"))
+		return -ENODEV;
+
+	card.platform = &mpc5200_audio_dma_platform;
+	card.name = "Efika";
+	card.dai_link = efika_fabric_dai;
+	card.num_links = ARRAY_SIZE(efika_fabric_dai);
+
+	device.card = &card;
+	device.codec_dev = &soc_codec_dev_stac9766;
+
+	pdev = platform_device_alloc("soc-audio", 1);
+	if (!pdev) {
+		pr_err("efika_fabric_init: platform_device_alloc() failed\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, &device);
+	device.dev = &pdev->dev;
+
+	rc = platform_device_add(pdev);
+	if (rc) {
+		pr_err("efika_fabric_init: platform_device_add() failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+module_init(efika_fabric_init);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 Efika fabric driver");
+MODULE_LICENSE("GPL");
+

^ permalink raw reply related

* Re: Initialize DBCR0 for PPC440 targets
From: David Gibson @ 2009-05-26  2:23 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: srikanth krishnakar, Linuxppc-dev
In-Reply-To: <1243235075.24376.60.camel@pasglop>

On Mon, May 25, 2009 at 05:04:35PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2009-05-20 at 16:00 +1000, David Gibson wrote:
> > On Wed, May 20, 2009 at 11:20:46AM +0530, srikanth krishnakar wrote:
> > > Hi David,
> > > 
> > > I am not sure how the IDM behaves on few of PPC440 targets which don't
> > > have boot loaders. I have a reference for your question:
> > > 
> > > http://www.nabble.com/Question-about-DBCR0-initialization-for-440-td23049044.html
> > > 
> > > Without this fix (given patch) I am facing problems with GDB, and
> > > further target hangs while running gdbserver !
> > 
> > That doesn't answer my question.  It's not enough to say "this fixes a
> > problem" you need to explain *how* it fixes the problem.
> > 
> > And I don't see why IDM would have any effect on *software*
> > breakpoints.
> 
> No but gdb can use the DABR emulation and single step would be busted
> too. GDB internally heavily uses single step in places you wouldn't
> expect it to :-) Like I think when breaking on main, it sometimes single
> step the whole init process of the executable until it hits it. At least
> I've seen it do that when I was debugging the debug support for 64-bit
> Book3E.

Right, but I believe the kernel does turn on IDM when it turns on
single step, or the DAC event bit.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply


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