[Qemu-devel] [PATCH V5] Add AACI audio playback support to the ARM Versatile/PB platform

2011-10-18 Thread Mathieu Sonet

This driver emulates the ARM AACI interface (PL041) connected to a LM4549 codec.
It enables audio playback for the Versatile/PB platform.

Limitations:
- Supports only a playback on one channel (Versatile/Vexpress)
- Supports only one TX FIFO in compact-mode or non-compact mode.
- Supports playback of 12, 16, 18 and 20 bits samples.
- Record is not supported.
- The PL041 is hardwired to a LM4549 codec.

Versatile/PB test build:
linux-2.6.38.5
buildroot-2010.11
alsa-lib-1.0.22
alsa-utils-1.0.22
mpg123-0.66

Qemu host: Ubuntu 10.04 in Vmware/OS X

Playback tested successfully with speaker-test/aplay/mpg123.

Signed-off-by: Mathieu Sonet 
---
v4->v5

* Move the lm4549 post_load hook in lm4549.c
* Fix naked debug printf in lm4549.c
* Clarify the size of the lm4549 audio buffer

 Makefile.target  |1 +
 hw/lm4549.c  |  336 
 hw/lm4549.h  |   43 
 hw/pl041.c   |  636 ++
 hw/pl041.h   |  135 
 hw/pl041.hx  |   81 +++
 hw/versatilepb.c |8 +
 7 files changed, 1240 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm4549.c
 create mode 100644 hw/lm4549.h
 create mode 100644 hw/pl041.c
 create mode 100644 hw/pl041.h
 create mode 100644 hw/pl041.hx

diff --git a/Makefile.target b/Makefile.target
index 417f23e..25b9fc1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -355,6 +355,7 @@ obj-arm-y += syborg_virtio.o
 obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
+obj-arm-y += pl041.o lm4549.o

 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/lm4549.c b/hw/lm4549.c
new file mode 100644
index 000..4d5b831
--- /dev/null
+++ b/hw/lm4549.c
@@ -0,0 +1,336 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *
+ *
+ * This driver emulates the LM4549 codec.
+ *
+ * It supports only one playback voice and no record voice.
+ */
+
+#include "hw.h"
+#include "audio/audio.h"
+#include "lm4549.h"
+
+#if 0
+#define LM4549_DEBUG  1
+#endif
+
+#if 0
+#define LM4549_DUMP_DAC_INPUT 1
+#endif
+
+#ifdef LM4549_DEBUG
+#define DPRINTF(fmt, ...) \
+do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+#include 
+static FILE *fp_dac_input;
+#endif
+
+/* LM4549 register list */
+enum {
+LM4549_Reset= 0x00,
+LM4549_Master_Volume= 0x02,
+LM4549_Line_Out_Volume  = 0x04,
+LM4549_Master_Volume_Mono   = 0x06,
+LM4549_PC_Beep_Volume   = 0x0A,
+LM4549_Phone_Volume = 0x0C,
+LM4549_Mic_Volume   = 0x0E,
+LM4549_Line_In_Volume   = 0x10,
+LM4549_CD_Volume= 0x12,
+LM4549_Video_Volume = 0x14,
+LM4549_Aux_Volume   = 0x16,
+LM4549_PCM_Out_Volume   = 0x18,
+LM4549_Record_Select= 0x1A,
+LM4549_Record_Gain  = 0x1C,
+LM4549_General_Purpose  = 0x20,
+LM4549_3D_Control   = 0x22,
+LM4549_Powerdown_Ctrl_Stat  = 0x26,
+LM4549_Ext_Audio_ID = 0x28,
+LM4549_Ext_Audio_Stat_Ctrl  = 0x2A,
+LM4549_PCM_Front_DAC_Rate   = 0x2C,
+LM4549_PCM_ADC_Rate = 0x32,
+LM4549_Vendor_ID1   = 0x7C,
+LM4549_Vendor_ID2   = 0x7E
+};
+
+static void lm4549_reset(lm4549_state *s)
+{
+uint16_t *regfile = s->regfile;
+
+regfile[LM4549_Reset]   = 0x0d50;
+regfile[LM4549_Master_Volume]   = 0x8008;
+regfile[LM4549_Line_Out_Volume] = 0x8000;
+regfile[LM4549_Master_Volume_Mono]  = 0x8000;
+regfile[LM4549_PC_Beep_Volume]  = 0x;
+regfile[LM4549_Phone_Volume]= 0x8008;
+regfile[LM4549_Mic_Volume]  = 0x8008;
+regfile[LM4549_Line_In_Volume]  = 0x8808;
+regfile[LM4549_CD_Volume]   = 0x8808;
+regfile[LM4549_Video_Volume]= 0x8808;
+regfile[LM4549_Aux_Volume]  = 0x8808;
+regfile[LM4549_PCM_Out_Volume]  = 0x8808;
+regfile[LM4549_Record_Select]   = 0x;
+regfile[LM4549_Record_Gain] = 0x8000;
+regfile[LM4549_General_Purpose] = 0x;
+regfile[LM4549_3D_Control]  = 0x0101;
+regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
+regfile[LM4549_Ext_Audio_ID]= 0x0001;
+regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x;
+regfile[LM4549_PCM_Front_DAC_Rate]  = 0xbb80;
+regfile[LM4549_PCM_ADC_Rate]= 0xbb80;
+regfile[LM4549_Vendor_ID1]  = 0x4e53;
+regfile[LM4549_Vendor_ID2]  = 0x4331;
+}
+
+static void lm4549_au

[Qemu-devel] [PATCH V4] Add AACI audio playback support to the ARM Versatile/PB platform

2011-10-12 Thread Mathieu Sonet

This driver emulates the ARM AACI interface (PL041) connected to a LM4549 codec.
It enables audio playback for the Versatile/PB platform.

Limitations:
- Supports only a playback on one channel (Versatile/Vexpress)
- Supports only one TX FIFO in compact-mode or non-compact mode.
- Supports playback of 12, 16, 18 and 20 bits samples.
- Record is not supported.
- The PL041 is hardwired to a LM4549 codec.

Versatile/PB test build:
linux-2.6.38.5
buildroot-2010.11
alsa-lib-1.0.22
alsa-utils-1.0.22
mpg123-0.66

Qemu host: Ubuntu 10.04 in Vmware/OS X

Playback tested successfully with speaker-test/aplay/mpg123.

Signed-off-by: Mathieu Sonet 
---
v3->v4

* Fix debug message compile error
* Remove Versatile/PB reference in pl041.c
* Use 20-bit samples in the LM4549 API
* Add support for non-compact mode
* Now support 12, 16, 18 and 20 bit sample size
* A FIFO reset is triggered when the AACIFE bit is reset

 Makefile.target  |1 +
 hw/lm4549.c  |  332 
 hw/lm4549.h  |   44 
 hw/pl041.c   |  644 ++
 hw/pl041.h   |  135 
 hw/pl041.hx  |   81 +++
 hw/versatilepb.c |8 +
 7 files changed, 1245 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm4549.c
 create mode 100644 hw/lm4549.h
 create mode 100644 hw/pl041.c
 create mode 100644 hw/pl041.h
 create mode 100644 hw/pl041.hx

diff --git a/Makefile.target b/Makefile.target
index 42adfec..00173cd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -355,6 +355,7 @@ obj-arm-y += syborg_virtio.o
 obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
+obj-arm-y += pl041.o lm4549.o

 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/lm4549.c b/hw/lm4549.c
new file mode 100644
index 000..883ef60
--- /dev/null
+++ b/hw/lm4549.c
@@ -0,0 +1,332 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *
+ *
+ * This driver emulates the LM4549 codec.
+ *
+ * It supports only one playback voice and no record voice.
+ */
+
+#include "hw.h"
+#include "audio/audio.h"
+#include "lm4549.h"
+
+#if 0
+#define LM4549_DEBUG  1
+#endif
+
+#if 0
+#define LM4549_DUMP_DAC_INPUT 1
+#endif
+
+#ifdef LM4549_DEBUG
+#define DPRINTF(fmt, ...) \
+do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+#include 
+static FILE *fp_dac_input;
+#endif
+
+/* LM4549 register list */
+enum {
+LM4549_Reset= 0x00,
+LM4549_Master_Volume= 0x02,
+LM4549_Line_Out_Volume  = 0x04,
+LM4549_Master_Volume_Mono   = 0x06,
+LM4549_PC_Beep_Volume   = 0x0A,
+LM4549_Phone_Volume = 0x0C,
+LM4549_Mic_Volume   = 0x0E,
+LM4549_Line_In_Volume   = 0x10,
+LM4549_CD_Volume= 0x12,
+LM4549_Video_Volume = 0x14,
+LM4549_Aux_Volume   = 0x16,
+LM4549_PCM_Out_Volume   = 0x18,
+LM4549_Record_Select= 0x1A,
+LM4549_Record_Gain  = 0x1C,
+LM4549_General_Purpose  = 0x20,
+LM4549_3D_Control   = 0x22,
+LM4549_Powerdown_Ctrl_Stat  = 0x26,
+LM4549_Ext_Audio_ID = 0x28,
+LM4549_Ext_Audio_Stat_Ctrl  = 0x2A,
+LM4549_PCM_Front_DAC_Rate   = 0x2C,
+LM4549_PCM_ADC_Rate = 0x32,
+LM4549_Vendor_ID1   = 0x7C,
+LM4549_Vendor_ID2   = 0x7E
+};
+
+static void lm4549_reset(lm4549_state *s)
+{
+uint16_t *regfile = s->regfile;
+
+regfile[LM4549_Reset]   = 0x0d50;
+regfile[LM4549_Master_Volume]   = 0x8008;
+regfile[LM4549_Line_Out_Volume] = 0x8000;
+regfile[LM4549_Master_Volume_Mono]  = 0x8000;
+regfile[LM4549_PC_Beep_Volume]  = 0x;
+regfile[LM4549_Phone_Volume]= 0x8008;
+regfile[LM4549_Mic_Volume]  = 0x8008;
+regfile[LM4549_Line_In_Volume]  = 0x8808;
+regfile[LM4549_CD_Volume]   = 0x8808;
+regfile[LM4549_Video_Volume]= 0x8808;
+regfile[LM4549_Aux_Volume]  = 0x8808;
+regfile[LM4549_PCM_Out_Volume]  = 0x8808;
+regfile[LM4549_Record_Select]   = 0x;
+regfile[LM4549_Record_Gain] = 0x8000;
+regfile[LM4549_General_Purpose] = 0x;
+regfile[LM4549_3D_Control]  = 0x0101;
+regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
+regfile[LM4549_Ext_Audio_ID]= 0x0001;
+regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x;
+regfile[LM4549_PCM_Front_DAC_Rate]  = 0xbb80;
+regfile[LM4549_PCM_ADC_Rate]= 0xbb80;
+  

Re: [Qemu-devel] [PATCH v3] Add AACI audio playback support to the ARM Versatile/PB platform

2011-10-09 Thread Mathieu Sonet

Peter Maydell wrote:

On 29 September 2011 18:31, Mathieu Sonet  wrote:

This driver emulates the ARM AACI interface (PL041) connected to a LM4549
codec.
It enables audio playback for the Versatile/PB platform.

Limitations:
- Supports only a playback on one channel (Versatile/Vexpress)
- Supports only a TX FIFO in compact-mode.


Actually you seem to have implemented a weird hybrid of compact
and non-compact modes.

Non-compact mode: FIFOs are 20 bits wide; a word write from the
CPU writes to bits [19:0] of the FIFO slot; each 'slot' of data
to the LM4549 reads 20 bits from the FIFO.
Compact mode: FIFOs are 40 bits wide (and half as deep); a word
write from the CPU writes to bits [31:0] of the FIFO slot; each
'slot' of data to the LM4549 reads 16 bits from the FIFO (bits
[15:0] then [31:16], and you have to read two slots (ie the
2 channels of stereo).

You've implemented a single 32 bit depth FIFO which one CPU
write writes to and which always passes one 32 bit word to the
LM4549. There are two issues here:
 (1) the LM4549 can take up to 18 bits of data per slot,
which your current lm4549_write_sample() API doesn't allow.
Passing two 32 bit words here would fix that. [My point here
is that we shouldn't hardwire the missing non-compact mode
support into the API between the two components.]
 (2) when the Linux driver dynamically identifies the size
of the FIFO it does it in non-compact mode, so it will return
a value half as big as is actually right for the compact-mode
behaviour you've implemented.

(Also your FIFO is twice as deep as it should be if we're
only implementing compact mode.)


Playback tested successfully with speaker-test/aplay/mpg123.


I find that on vexpress mpg123 playback works but can be quite stuttery.
madplay (integer only) is somewhat better, so I suspect that qemu is
spending ages emulating Neon/VFP in mpg123...

Further (minor) comments below.


+regfile[LM4549_PCM_Front_DAC_Rate]  = 0xBB80;
+regfile[LM4549_PCM_ADC_Rate]= 0xBB80;
+regfile[LM4549_Vendor_ID1]  = 0x4e53;
+regfile[LM4549_Vendor_ID2]  = 0x4331;


Can we be consistent about upper or lower case for the hex?


+#define MAX_FIFO_DEPTH (1024)
+#define VERSATILEPB_DEFAULT_FIFO_DEPTH (256)  /* AN115B - Table 1.1 */


pl041.c shouldn't know anything about VersatilePB. The default
fifo depth should be 8 (same as the hardware PL041).


+static uint8_t pl041_compute_periphid3(pl041_state *s)
+{
+uint8_t id3 = (1 | ((s->fifo_depth >> 4) << 3));
+return id3;
+}


This isn't right.

[5:3] FIFO depth (non-compact mode)
b000  8
b001  16
b010  32
b011  64
b100  128
b101  256
b110  512
b111  1024

...which isn't what your function calculates.
(Linux determines FIFO depth programmatically by stuffing words
into the FIFO until the status register says it's full, which is
why it doesn't complain.)

NB that some of the board TRMs have what seem to be incorrect
labelling on the tables of depth vs ID register bits.


+/* Update the irq state */
+qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0);
+DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n",
+   s->regs.sr1, s->regs.isr1, s->regs.isr1 & mask);
+}


This debug printf won't compile if enabled -- you forgot
to update it when you changed the main code to remove the
'mask' variable.


+static int pl041_post_load(void *opaque, int version_id)
+{
+pl041_state *s = opaque;
+lm4549_post_load(&s->codec);
+return 0;
+}


Is it not possible to just register lm4549_post_load()
as the post_load function for lm4549_state, rather than
having a pl041 post_load hook which only passes it through?


The lm4549 model has no knowledge of its pl041 client and uses a separate 
context structure.
The opaque pointer passed to the post_load hook can not be used directly to 
setup the lm4549.

I would prefer to keep the two models separated.



(Something in your mailsending path is wrapping long lines, by the way.)

-- PMM


 Mathieu



[Qemu-devel] [PATCH v3] Add AACI audio playback support to the ARM Versatile/PB platform

2011-09-29 Thread Mathieu Sonet
This driver emulates the ARM AACI interface (PL041) connected to a 
LM4549 codec.

It enables audio playback for the Versatile/PB platform.

Limitations:
- Supports only a playback on one channel (Versatile/Vexpress)
- Supports only a TX FIFO in compact-mode.
- Record is not supported.
- The PL041 is hardwired to a LM4549 codec.

Versatile/PB test build:
linux-2.6.38.5
buildroot-2010.11
alsa-lib-1.0.22
alsa-utils-1.0.22
mpg123-0.66

Qemu host: Ubuntu 10.04 in Vmware/OS X

Playback tested successfully with speaker-test/aplay/mpg123.

Signed-off-by: Mathieu Sonet 
---
v2->v3

This version takes into account the remarks from Peter Maydell's review:
* Both pl041 and lm4549 source code has been simplified by removing 
extraneous abstractions.

* hw_error occurences has been replaced by warnings.
* The FIFO depth is now a qdev property.
* The model now has load/save support.

 Makefile.target  |1 +
 hw/lm4549.c  |  326 +++
 hw/lm4549.h  |   44 +
 hw/pl041.c   |  501 
++

 hw/pl041.h   |  135 +++
 hw/pl041.hx  |   81 +
 hw/versatilepb.c |8 +
 7 files changed, 1096 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm4549.c
 create mode 100644 hw/lm4549.h
 create mode 100644 hw/pl041.c
 create mode 100644 hw/pl041.h
 create mode 100644 hw/pl041.hx

diff --git a/Makefile.target b/Makefile.target
index 88d2f1f..cb1e86a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -355,6 +355,7 @@ obj-arm-y += syborg_virtio.o
 obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
+obj-arm-y += pl041.o lm4549.o

 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/lm4549.c b/hw/lm4549.c
new file mode 100644
index 000..55b7105
--- /dev/null
+++ b/hw/lm4549.c
@@ -0,0 +1,326 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *
+ *
+ * This driver emulates the LM4549 codec.
+ *
+ * It supports only one playback voice and no record voice.
+ */
+
+#include "hw.h"
+#include "audio/audio.h"
+#include "lm4549.h"
+
+#if 0
+#define LM4549_DEBUG  1
+#endif
+
+#if 0
+#define LM4549_DUMP_DAC_INPUT 1
+#endif
+
+#ifdef LM4549_DEBUG
+#define DPRINTF(fmt, ...) \
+do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+#include 
+static FILE *fp_dac_input;
+#endif
+
+/* LM4549 register list */
+enum {
+LM4549_Reset= 0x00,
+LM4549_Master_Volume= 0x02,
+LM4549_Line_Out_Volume  = 0x04,
+LM4549_Master_Volume_Mono   = 0x06,
+LM4549_PC_Beep_Volume   = 0x0A,
+LM4549_Phone_Volume = 0x0C,
+LM4549_Mic_Volume   = 0x0E,
+LM4549_Line_In_Volume   = 0x10,
+LM4549_CD_Volume= 0x12,
+LM4549_Video_Volume = 0x14,
+LM4549_Aux_Volume   = 0x16,
+LM4549_PCM_Out_Volume   = 0x18,
+LM4549_Record_Select= 0x1A,
+LM4549_Record_Gain  = 0x1C,
+LM4549_General_Purpose  = 0x20,
+LM4549_3D_Control   = 0x22,
+LM4549_Powerdown_Ctrl_Stat  = 0x26,
+LM4549_Ext_Audio_ID = 0x28,
+LM4549_Ext_Audio_Stat_Ctrl  = 0x2A,
+LM4549_PCM_Front_DAC_Rate   = 0x2C,
+LM4549_PCM_ADC_Rate = 0x32,
+LM4549_Vendor_ID1   = 0x7C,
+LM4549_Vendor_ID2   = 0x7E
+};
+
+static void lm4549_reset(lm4549_state *s)
+{
+uint16_t *regfile = s->regfile;
+
+regfile[LM4549_Reset]   = 0x0d50;
+regfile[LM4549_Master_Volume]   = 0x8008;
+regfile[LM4549_Line_Out_Volume] = 0x8000;
+regfile[LM4549_Master_Volume_Mono]  = 0x8000;
+regfile[LM4549_PC_Beep_Volume]  = 0x;
+regfile[LM4549_Phone_Volume]= 0x8008;
+regfile[LM4549_Mic_Volume]  = 0x8008;
+regfile[LM4549_Line_In_Volume]  = 0x8808;
+regfile[LM4549_CD_Volume]   = 0x8808;
+regfile[LM4549_Video_Volume]= 0x8808;
+regfile[LM4549_Aux_Volume]  = 0x8808;
+regfile[LM4549_PCM_Out_Volume]  = 0x8808;
+regfile[LM4549_Record_Select]   = 0x;
+regfile[LM4549_Record_Gain] = 0x8000;
+regfile[LM4549_General_Purpose] = 0x;
+regfile[LM4549_3D_Control]  = 0x0101;
+regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
+regfile[LM4549_Ext_Audio_ID]= 0x0001;
+regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x;
+regfile[LM4549_PCM_Front_DAC_Rate]  = 0xBB80;
+regfile[LM4549_PCM_ADC_Rate]= 0xBB80;
+regfile

[Qemu-devel] [PATCH v2] Add AACI audio playback support to the ARM Versatile/PB platform

2011-05-13 Thread Mathieu Sonet
The ACLink bus has been removed.
The PL041/AACI driver now directly control the LM4549 codec driver.

The AC97 emulation in ac97.c has not been reused. Making the current
implementation sharable is not trivial and could bring regression
to other platforms.

Versatile/PB test build:
linux-2.6.38.5
buildroot-2010.11
alsa-lib-1.0.22
alsa-utils-1.0.22
mpg123-0.66

Qemu host: Ubuntu 10.04 in Vmware/OS X

Playback tested successfully with aplay and mpg123.

Signed-off-by: Mathieu Sonet 
---
 Makefile.target  |1 +
 hw/lm4549.c  |  307 +
 hw/lm4549.h  |   45 ++
 hw/pl041.c   |  406 ++
 hw/pl041.h   |  125 +
 hw/pl041.hx  |   61 
 hw/versatilepb.c |3 +
 7 files changed, 948 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm4549.c
 create mode 100644 hw/lm4549.h
 create mode 100644 hw/pl041.c
 create mode 100644 hw/pl041.h
 create mode 100644 hw/pl041.hx

diff --git a/Makefile.target b/Makefile.target
index 21f864a..1a6565f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -354,6 +354,7 @@ obj-arm-y += syborg_virtio.o
 obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
+obj-arm-y += pl041.o lm4549.o

 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/lm4549.c b/hw/lm4549.c
new file mode 100644
index 000..e58d4d4
--- /dev/null
+++ b/hw/lm4549.c
@@ -0,0 +1,307 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *
+ *
+ * This driver emulates the LM4549 codec.
+ *
+ */
+
+#include "hw.h"
+#include "audio/audio.h"
+#include "lm4549.h"
+
+/* #define LM4549_DEBUG  1 */
+/* #define LM4549_DUMP_DAC_INPUT 1 */
+
+#ifdef LM4549_DEBUG
+#define DPRINTF(fmt, ...) \
+do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+#include 
+static FILE *fp_dac_input;
+#endif
+
+/*** LM4549 register list ***/
+
+enum {
+LM4549_Reset= 0x00,
+LM4549_Master_Volume= 0x02,
+LM4549_Line_Out_Volume  = 0x04,
+LM4549_Master_Volume_Mono   = 0x06,
+LM4549_PC_Beep_Volume   = 0x0A,
+LM4549_Phone_Volume = 0x0C,
+LM4549_Mic_Volume   = 0x0E,
+LM4549_Line_In_Volume   = 0x10,
+LM4549_CD_Volume= 0x12,
+LM4549_Video_Volume = 0x14,
+LM4549_Aux_Volume   = 0x16,
+LM4549_PCM_Out_Volume   = 0x18,
+LM4549_Record_Select= 0x1A,
+LM4549_Record_Gain  = 0x1C,
+LM4549_General_Purpose  = 0x20,
+LM4549_3D_Control   = 0x22,
+LM4549_Powerdown_Ctrl_Stat  = 0x26,
+LM4549_Extended_Audio_ID= 0x28,
+LM4549_Extended_Audio_Stat_Ctrl = 0x2A,
+LM4549_PCM_Front_DAC_Rate   = 0x2C,
+LM4549_PCM_ADC_Rate = 0x32,
+LM4549_Vendor_ID1   = 0x7C,
+LM4549_Vendor_ID2   = 0x7E
+};
+
+/*** Functions ***/
+
+static void lm4549_store_init(lm4549_state *s, uint32_t offset, uint32_t value,
+  uint32_t is_read_only)
+{
+lm4549_registers *r = &s->codec_regs;
+
+if (offset > 128) {
+DPRINTF("store_init: Out of bound offset 0x%x\n", (int)offset);
+}
+
+r->data[offset].value = value & 0x;
+r->data[offset].default_value = value & 0x;
+r->data[offset].read_only = (is_read_only > 0) ? 1 : 0;
+}
+
+static void lm4549_store_reset(lm4549_state *s)
+{
+lm4549_registers *r = &s->codec_regs;
+int i;
+
+for (i = 0; i < 128; i++) {
+r->data[i].value = r->data[i].default_value;
+}
+}
+
+static void lm4549_store(lm4549_state *s, uint32_t offset, uint16_t value)
+{
+lm4549_registers *r = &s->codec_regs;
+
+if (offset > 128) {
+DPRINTF("store: Out of bound offset 0x%x\n", (int)offset);
+}
+
+if (r->data[offset].read_only) {
+DPRINTF("store: Read-only offset 0x%x\n", (int)offset);
+return;
+}
+
+r->data[offset].value = value & 0x;
+}
+
+static uint16_t lm4549_load(lm4549_state *s, uint32_t offset)
+{
+lm4549_registers *r = &s->codec_regs;
+
+if (offset > 128) {
+hw_error("load: Out of bound offset 0x%x\n", (int)offset);
+}
+
+return r->data[offset].value;
+}
+
+static void lm4549_audio_transfer(lm4549_state *s)
+{
+uint32_t written_bytes, written_samples;
+uint32_t i;
+
+/* Activate the voice */
+AUD_set_active_out(s->v

Re: [Qemu-devel] [PATCH] Add AACI audio playback support to the ARM Versatile/PB platform

2011-05-12 Thread Mathieu Sonet

Paul Brook wrote:

On the other hand the current ac97.c implementation is a closely coupled
combination of a PCI/ACLink bridge (Intel 82801AA) with a generic AC97
codec. This has prevent me to easily reuse this code.

The milkymist-ac97 implementation is another case. It looks like a basic
implementation with the AC97 registers directly mapped on the system bus.

Using the ACLink bus I defined, it could be interesting to implement
separately the PCI/ACLink bridge from ac97.c.

Is it what you mean by saying this should be shared with the other AC97
devices ?


Yes. The whole point of AClink is that it separates the host bridge from the 
codec. We now have at least three devices implementing this.  Your aclink 
implementation is only used by one of these, which gives me little confidence 
it actually does what it claims.


Paul


I understand your concern.

In fact after digging the Intel PCI bridge documentation, I see that it 
 offers a mapping of the AC97 registers in the PCI I/O space.


Reusing my current ACLink bus with this bridge would mean to encode 
register accesses into ACLink frames and then to decode them again on 
the codec side. Not very simple just for the sake of device models 
correctness and no added value.


Also QEMU may not need N different re-implemention of an AC97 codec.

So I will ditch ACLink/LM4549 and will instead interface the PL041 
driver with the codec defined in ac97.c.


  PCI---AC97
PL041--/

Thanks for your input
Mathieu





Re: [Qemu-devel] [PATCH] Add AACI audio playback support to the ARM Versatile/PB platform

2011-05-11 Thread Mathieu Sonet

Paul Brook wrote:

The PL041 driver provides an interface to an ACLink bus.
The LM4549 driver emulates a DAC connected on the ACLink bus.
Only audio playback is implemented.


Shouldn't this be shared with the other AC97 devices?

Paul


I organized the code in 3 different drivers (PL041 <=> ACLink <=> 
LM4549) to decorrelate the codec interface from its implementation. This 
could allow the use of alternative AC97 models with the same PL041 
implementation.


On the other hand the current ac97.c implementation is a closely coupled 
combination of a PCI/ACLink bridge (Intel 82801AA) with a generic AC97 
codec. This has prevent me to easily reuse this code.


The milkymist-ac97 implementation is another case. It looks like a basic 
implementation with the AC97 registers directly mapped on the system bus.


Using the ACLink bus I defined, it could be interesting to implement 
separately the PCI/ACLink bridge from ac97.c.


Is it what you mean by saying this should be shared with the other AC97 
devices ?


Mathieu



[Qemu-devel] [PATCH] Add AACI audio playback support to the ARM Versatile/PB platform

2011-05-10 Thread Mathieu Sonet
The PL041 driver provides an interface to an ACLink bus.
The LM4549 driver emulates a DAC connected on the ACLink bus.
Only audio playback is implemented.

Versatile/PB test build:
linux-2.6.38.5
buildroot-2010.11
alsa-lib-1.0.22
alsa-utils-1.0.22
mpg123-0.66

Qemu host: Ubuntu 10.04 in Vmware/OS X

Playback tested successfully with aplay and mpg123.

Signed-off-by: Mathieu Sonet 
---
 Makefile.target  |1 +
 hw/aclink.c  |  121 +++
 hw/aclink.h  |   63 
 hw/lm4549.c  |  368 +
 hw/pl041.c   |  436 ++
 hw/pl041.h   |  126 
 hw/pl041.hx  |   62 
 hw/versatilepb.c |6 +
 8 files changed, 1183 insertions(+), 0 deletions(-)
 create mode 100644 hw/aclink.c
 create mode 100644 hw/aclink.h
 create mode 100644 hw/lm4549.c
 create mode 100644 hw/pl041.c
 create mode 100644 hw/pl041.h
 create mode 100644 hw/pl041.hx

diff --git a/Makefile.target b/Makefile.target
index 21f864a..cdd7b40 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -354,6 +354,7 @@ obj-arm-y += syborg_virtio.o
 obj-arm-y += vexpress.o
 obj-arm-y += strongarm.o
 obj-arm-y += collie.o
+obj-arm-y += pl041.o aclink.o lm4549.o

 obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
 obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
diff --git a/hw/aclink.c b/hw/aclink.c
new file mode 100644
index 000..c335f60
--- /dev/null
+++ b/hw/aclink.c
@@ -0,0 +1,121 @@
+/*
+ * ACLink Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licenced under the GPL.
+ *
+ * *
+ *
+ * This file defines the ACLink bus interface to exchange data
+ * between an host and a codec.
+ *
+ */
+
+#include "aclink.h"
+
+/*** Types ***/
+
+struct ACLinkBus {
+BusState qbus;
+ACLinkControllerInfo *controller_info;
+uint32_t bitclk;
+};
+
+struct BusInfo aclink_bus_info = {
+.name = "aclink",
+.size = sizeof(ACLinkBus),
+};
+
+/*** Functions ***/
+
+ACLinkBus *aclink_create_bus(DeviceState *parent, const char *name)
+{
+BusState *bus;
+bus = qbus_create(&aclink_bus_info, parent, name);
+return FROM_QBUS(ACLinkBus, bus);
+}
+
+void aclink_set_controller_info(ACLinkBus *bus, ACLinkControllerInfo *info)
+{
+bus->controller_info = info;
+}
+
+static int aclink_device_init(DeviceState *dev, DeviceInfo *base_info)
+{
+ACLinkDeviceInfo *info = container_of(base_info, ACLinkDeviceInfo, qdev);
+ACLinkDevice *s = ACLINK_DEVICE_FROM_QDEV(dev);
+ACLinkBus *bus;
+
+bus = FROM_QBUS(ACLinkBus, qdev_get_parent_bus(dev));
+if (QLIST_FIRST(&bus->qbus.children) != dev
+|| QLIST_NEXT(dev, sibling) != NULL) {
+hw_error("Too many devices on the ACLINK bus");
+}
+
+s->info = info;
+return info->init(s);
+}
+
+void aclink_register_device(ACLinkDeviceInfo *info)
+{
+assert(info->qdev.size >= sizeof(ACLinkDevice));
+info->qdev.init = aclink_device_init;
+info->qdev.bus_info = &aclink_bus_info;
+qdev_register(&info->qdev);
+}
+
+DeviceState *aclink_create_device(ACLinkBus *bus, const char *name)
+{
+DeviceState *dev;
+dev = qdev_create(&bus->qbus, name);
+qdev_init_nofail(dev);
+return dev;
+}
+
+static ACLinkDevice *aclink_get_device(ACLinkBus *bus)
+{
+DeviceState *dev = QLIST_FIRST(&bus->qbus.children);
+if (!dev) {
+return NULL;
+}
+return ACLINK_DEVICE_FROM_QDEV(dev);
+}
+
+void aclink_bitclk_enable(ACLinkDevice *dev, uint32_t on)
+{
+ACLinkBus *bus = FROM_QBUS(ACLinkBus, qdev_get_parent_bus(&dev->qdev));
+uint32_t has_changed;
+
+on = (on > 0) ? 1 : 0;
+has_changed = (bus->bitclk != on) ? 1 : 0;
+
+bus->bitclk = on;
+if (has_changed) {
+bus->controller_info->bitclk_state_changed(bus->qbus.parent);
+}
+}
+
+uint32_t aclink_bitclk_is_enabled(ACLinkBus *bus)
+{
+return bus->bitclk;
+}
+
+void aclink_sdataout_slot12(ACLinkBus *bus, uint32_t slot1, uint32_t slot2)
+{
+ACLinkDevice *device = aclink_get_device(bus);
+device->info->sdataout_slot12(device, slot1, slot2);
+}
+
+void aclink_sdataout_slot34(ACLinkBus *bus, uint32_t slot3, uint32_t slot4)
+{
+ACLinkDevice *device = aclink_get_device(bus);
+device->info->sdataout_slot34(device, slot3, slot4);
+}
+
+void aclink_sdatain_slot12(ACLinkDevice *dev, uint32_t slot1, uint32_t slot2)
+{
+ACLinkBus *bus = FROM_QBUS(ACLinkBus, qdev_get_parent_bus(&dev->qdev));
+bus->controller_info->sdatain_slot12(bus->qbus.parent, slot1, slot2);
+}
diff --git a/hw/aclink.h b/hw/aclink.h
new file mode 100644
index 000..d360d4b
--- /dev/null
+++ b/hw/aclink.h
@@ -0,0 +1,63 @@
+/*