All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
@ 2009-06-09 17:13 Daniel Ribeiro
  2009-06-10 11:44 ` Paul Shen
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Daniel Ribeiro @ 2009-06-09 17:13 UTC (permalink / raw)
  To: alsa-devel, Mark Brown
  Cc: Paul Shen, Philipp Zabel, Eric Miao, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 9556 bytes --]

* Extend set_tdm_slot to allow the user to arbitrarily set the frame
  width and active TX/RX slots.
* Reset SSCR0_EDSS and SSCR0_DSS on pxa_ssp_set_dai_fmt.
* Makes SSCR0_MOD optional.
* Automatically sets network mode when needed if set_tdm_slot was
  never called.
* Clears SSCR1_RWOT case SSCR0_MOD is set.
* Updates magician.c and wm9081.c for the new set_tdm_slot()

(Patch is based on Mark's for-2.6.32 branch)

Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>

---
 include/sound/soc-dai.h   |    5 +
 sound/soc/codecs/wm9081.c |    4 -
 sound/soc/pxa/magician.c  |    2 
 sound/soc/pxa/pxa-ssp.c   |  119 ++++++++++++++++++++++++++++------------------
 sound/soc/soc-core.c      |    9 ++-
 5 files changed, 85 insertions(+), 54 deletions(-)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 352d7ee..f96cc36 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -106,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
 
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
-	unsigned int mask, int slots);
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width);
 
 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 
@@ -140,7 +140,8 @@ struct snd_soc_dai_ops {
 	 */
 	int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
 	int (*set_tdm_slot)(struct snd_soc_dai *dai,
-		unsigned int mask, int slots);
+		unsigned int tx_mask, unsigned int rx_mask,
+		int slots, int frame_width);
 	int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
 
 	/*
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 86fc57e..85c720a 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1207,7 +1207,7 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
 }
 
 static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
-			       unsigned int mask, int slots)
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
 {
 	struct snd_soc_codec *codec = dai->codec;
 	unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
@@ -1219,7 +1219,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
 
 	aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
 
-	switch (mask) {
+	switch (tx_mask) {
 	case 1:
 		break;
 	case 2:
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index c89a3cd..2345869 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -188,7 +188,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 		return ret;
 
-	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1);
+	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1, 1, 16);
 	if (ret < 0)
 		return ret;
 
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 46d14f3..f0931e7 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
  * Set the active slots in TDM/Network mode
  */
 static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
-	unsigned int mask, int slots)
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
 {
 	struct ssp_priv *priv = cpu_dai->private_data;
 	struct ssp_device *ssp = priv->dev.ssp;
 	u32 sscr0;
 
-	sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7);
+	sscr0 = ssp_read_reg(ssp, SSCR0);
+	sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(7) | SSCR0_EDSS | SSCR0_DSS);
+
+	/* set frame width */
+	if (frame_width > 16)
+		sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
+	else
+		sscr0 |= SSCR0_DataSize(frame_width);
+
+	if (slots > 1) {
+		/* enable network mode */
+		sscr0 |= SSCR0_MOD;
 
-	/* set number of active slots */
-	sscr0 |= SSCR0_SlotsPerFrm(slots);
+		/* set number of active slots */
+		sscr0 |= SSCR0_SlotsPerFrm(slots);
+
+		/* set active slot mask */
+		ssp_write_reg(ssp, SSTSA, tx_mask);
+		ssp_write_reg(ssp, SSRSA, rx_mask);
+	}
 	ssp_write_reg(ssp, SSCR0, sscr0);
 
-	/* set active slot mask */
-	ssp_write_reg(ssp, SSTSA, mask);
-	ssp_write_reg(ssp, SSRSA, mask);
 	return 0;
 }
 
@@ -439,8 +452,8 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	}
 
 	/* reset port settings */
-	sscr0 = ssp_read_reg(ssp, SSCR0) &
-		(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+	sscr0 = ssp_read_reg(ssp, SSCR0) & (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD |
+			SSCR0_ACS | SSCR0_EDSS | SSCR0_DSS);
 	sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
 	sspsp = 0;
 
@@ -487,7 +500,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	case SND_SOC_DAIFMT_DSP_A:
 		sspsp |= SSPSP_FSRT;
 	case SND_SOC_DAIFMT_DSP_B:
-		sscr0 |= SSCR0_MOD | SSCR0_PSP;
+		sscr0 |= SSCR0_PSP;
 		sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
 
 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -537,48 +550,70 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 	struct ssp_priv *priv = cpu_dai->private_data;
 	struct ssp_device *ssp = priv->dev.ssp;
 	int chn = params_channels(params);
-	u32 sscr0;
-	u32 sspsp;
+	u32 sscr0, sscr1, sspsp;
 	int width = snd_pcm_format_physical_width(params_format(params));
-	int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
+	int frame_width;
+
+	/* check if the user explicitly set a frame_width */
+	sscr0 = ssp_read_reg(ssp, SSCR0);
+
+	if (sscr0 & (SSCR0_EDSS | SSCR0_DSS))
+		frame_width = (sscr0 & SSCR0_DSS) +
+			(sscr0 & SSCR0_EDSS ? 17 : 1);
+	else
+		frame_width = width * chn;
 
 	/* generate correct DMA params */
 	if (cpu_dai->dma_data)
 		kfree(cpu_dai->dma_data);
 
-	/* Network mode with one active slot (ttsa == 1) can be used
-	 * to force 16-bit frame width on the wire (for S16_LE), even
-	 * with two channels. Use 16-bit DMA transfers for this case.
-	 */
-	cpu_dai->dma_data = ssp_get_dma_params(ssp,
-			((chn == 2) && (ttsa != 1)) || (width == 32),
+	cpu_dai->dma_data = ssp_get_dma_params(ssp, frame_width > 16,
 			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
 	/* we can only change the settings if the port is not in use */
-	if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
+	if (sscr0 & SSCR0_SSE)
 		return 0;
 
-	/* clear selected SSP bits */
-	sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
-	ssp_write_reg(ssp, SSCR0, sscr0);
-
-	/* bit size */
-	sscr0 = ssp_read_reg(ssp, SSCR0);
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16_LE:
+	/* FIXME: What this is for? */
 #ifdef CONFIG_PXA3xx
-		if (cpu_is_pxa3xx())
-			sscr0 |= SSCR0_FPCKE;
+	if (width == 16 && cpu_is_pxa3xx())
+		sscr0 |= SSCR0_FPCKE;
 #endif
-		sscr0 |= SSCR0_DataSize(16);
-		break;
-	case SNDRV_PCM_FORMAT_S24_LE:
-		sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
-		break;
-	case SNDRV_PCM_FORMAT_S32_LE:
-		sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
-		break;
+
+	if (!(sscr0 & (SSCR0_EDSS | SSCR0_DSS))) {
+		/* Frame width not set yet, we are not using network mode */
+		if (frame_width > 16)
+			sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
+		else
+			sscr0 |= SSCR0_DataSize(frame_width);
+
+		if (frame_width > 32) {
+			/*
+			 * Network mode is needed to support this frame_width
+			 * We assume that the wire is not networked and setup
+			 * a "fake" network mode here.
+			 */
+			int slots = frame_width / 32;
+
+			sscr0 |= SSCR0_MOD;
+			sscr0 |= SSCR0_SlotsPerFrm(slots);
+
+			/*
+			 * Set active slots. Only set an active TX slot
+			 * if we are going to use it.
+			 */
+			ssp_write_reg(ssp, SSRSA, slots - 1);
+			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+				ssp_write_reg(ssp, SSTSA, slots - 1);
+		}
 	}
+
+	/* If SSCR0_MOD is set we can't use SSCR1_RWOT */
+	if (sscr0 & SSCR0_MOD) {
+		sscr1 = ssp_read_reg(ssp, SSCR1);
+		ssp_write_reg(ssp, SSCR1, sscr1 & ~SSCR1_RWOT);
+	}
+
 	ssp_write_reg(ssp, SSCR0, sscr0);
 
 	switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -625,14 +660,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
 		break;
 	}
 
-	/* When we use a network mode, we always require TDM slots
-	 * - complain loudly and fail if they've not been set up yet.
-	 */
-	if ((sscr0 & SSCR0_MOD) && !ttsa) {
-		dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
-		return -EINVAL;
-	}
-
 	dump_registers(ssp);
 
 	return 0;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index e1a920c..69becf2 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2133,17 +2133,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 /**
  * snd_soc_dai_set_tdm_slot - configure DAI TDM.
  * @dai: DAI
- * @mask: DAI specific mask representing used slots.
+ * @tx_mask: bitmask representing active TX slots.
+ * @rx_mask: bitmask representing active RX slots.
  * @slots: Number of slots in use.
+ * @frame_width: Width in bits for each slot.
  *
  * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
  * specific.
  */
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
-	unsigned int mask, int slots)
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
 {
 	if (dai->ops && dai->ops->set_tdm_slot)
-		return dai->ops->set_tdm_slot(dai, mask, slots);
+		return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
+				slots, frame_width);
 	else
 		return -EINVAL;
 }

-- 
Daniel Ribeiro

[-- Attachment #1.2: Esta é uma parte de mensagem assinada digitalmente --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-09 17:13 [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM Daniel Ribeiro
@ 2009-06-10 11:44 ` Paul Shen
  2009-06-10 12:05   ` pHilipp Zabel
  2009-06-10 14:17   ` Daniel Ribeiro
  2009-06-10 12:18 ` Mark Brown
  2009-06-10 14:44 ` pHilipp Zabel
  2 siblings, 2 replies; 10+ messages in thread
From: Paul Shen @ 2009-06-10 11:44 UTC (permalink / raw)
  To: Daniel Ribeiro
  Cc: alsa-devel, Eric Miao, Mark Brown, Philipp Zabel, linux-arm-kernel

2009/6/10 Daniel Ribeiro <drwyrm@gmail.com>:
> * Extend set_tdm_slot to allow the user to arbitrarily set the frame
>  width and active TX/RX slots.
> * Reset SSCR0_EDSS and SSCR0_DSS on pxa_ssp_set_dai_fmt.
> * Makes SSCR0_MOD optional.
> * Automatically sets network mode when needed if set_tdm_slot was
>  never called.
> * Clears SSCR1_RWOT case SSCR0_MOD is set.
> * Updates magician.c and wm9081.c for the new set_tdm_slot()
>
> (Patch is based on Mark's for-2.6.32 branch)
>
> Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
>
> ---
>  include/sound/soc-dai.h   |    5 +
>  sound/soc/codecs/wm9081.c |    4 -
>  sound/soc/pxa/magician.c  |    2
>  sound/soc/pxa/pxa-ssp.c   |  119 ++++++++++++++++++++++++++++------------------
>  sound/soc/soc-core.c      |    9 ++-
>  5 files changed, 85 insertions(+), 54 deletions(-)
>
> diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
> index 352d7ee..f96cc36 100644
> --- a/include/sound/soc-dai.h
> +++ b/include/sound/soc-dai.h
> @@ -106,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
>  int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
>
>  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
> -       unsigned int mask, int slots);
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width);
>
>  int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
>
> @@ -140,7 +140,8 @@ struct snd_soc_dai_ops {
>         */
>        int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
>        int (*set_tdm_slot)(struct snd_soc_dai *dai,
> -               unsigned int mask, int slots);
> +               unsigned int tx_mask, unsigned int rx_mask,
> +               int slots, int frame_width);
>        int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
>
>        /*
> diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
> index 86fc57e..85c720a 100644
> --- a/sound/soc/codecs/wm9081.c
> +++ b/sound/soc/codecs/wm9081.c
> @@ -1207,7 +1207,7 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
>  }
>
>  static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
> -                              unsigned int mask, int slots)
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>  {
>        struct snd_soc_codec *codec = dai->codec;
>        unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
> @@ -1219,7 +1219,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
>
>        aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
>
> -       switch (mask) {
> +       switch (tx_mask) {
>        case 1:
>                break;
>        case 2:
> diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
> index c89a3cd..2345869 100644
> --- a/sound/soc/pxa/magician.c
> +++ b/sound/soc/pxa/magician.c
> @@ -188,7 +188,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
>        if (ret < 0)
>                return ret;
>
> -       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1);
> +       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1, 1, 16);
>        if (ret < 0)
>                return ret;
>
> diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
> index 46d14f3..f0931e7 100644
> --- a/sound/soc/pxa/pxa-ssp.c
> +++ b/sound/soc/pxa/pxa-ssp.c
> @@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
>  * Set the active slots in TDM/Network mode
>  */
>  static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
> -       unsigned int mask, int slots)
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>  {
>        struct ssp_priv *priv = cpu_dai->private_data;
>        struct ssp_device *ssp = priv->dev.ssp;
>        u32 sscr0;
>
> -       sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7);
> +       sscr0 = ssp_read_reg(ssp, SSCR0);
> +       sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(7) | SSCR0_EDSS | SSCR0_DSS);
> +
> +       /* set frame width */
> +       if (frame_width > 16)
> +               sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
> +       else
> +               sscr0 |= SSCR0_DataSize(frame_width);
> +
> +       if (slots > 1) {
> +               /* enable network mode */
> +               sscr0 |= SSCR0_MOD;
>
Seems the frame_width has no  such relations with sampe width, the
sample width is defined on runtime by the audio files.
Make a example sample with  paly a often used 16bit sample width
stereo aduio file.

When you play 16bit audio sample with  2*16 bit frame ,
         frame   --|____________|------------------|_____________|---
         data      --<======>-<======>-<======>-
         here the datasize should be SSCR0_DataSize(16), the frame size is 32

also you can play 16bit audio sample with 2*32 frame,
         frame
--|_________________________|------------------------------------|____
         data     --<======>-------------------<======>-------------------<==
         here the datasize is also DataSize(16), but the frame size is 64.

Do I misunderstand you?

> -       /* set number of active slots */
> -       sscr0 |= SSCR0_SlotsPerFrm(slots);
> +               /* set number of active slots */
> +               sscr0 |= SSCR0_SlotsPerFrm(slots);
> +
> +               /* set active slot mask */
> +               ssp_write_reg(ssp, SSTSA, tx_mask);
> +               ssp_write_reg(ssp, SSRSA, rx_mask);
> +       }
>        ssp_write_reg(ssp, SSCR0, sscr0);
>
> -       /* set active slot mask */
> -       ssp_write_reg(ssp, SSTSA, mask);
> -       ssp_write_reg(ssp, SSRSA, mask);
>        return 0;
>  }
>
> @@ -439,8 +452,8 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
>        }
>
>        /* reset port settings */
> -       sscr0 = ssp_read_reg(ssp, SSCR0) &
> -               (SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
> +       sscr0 = ssp_read_reg(ssp, SSCR0) & (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD |
> +                       SSCR0_ACS | SSCR0_EDSS | SSCR0_DSS);
>        sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
>        sspsp = 0;
>
> @@ -487,7 +500,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
>        case SND_SOC_DAIFMT_DSP_A:
>                sspsp |= SSPSP_FSRT;
>        case SND_SOC_DAIFMT_DSP_B:
> -               sscr0 |= SSCR0_MOD | SSCR0_PSP;
> +               sscr0 |= SSCR0_PSP;
>                sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
>
>                switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> @@ -537,48 +550,70 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
>        struct ssp_priv *priv = cpu_dai->private_data;
>        struct ssp_device *ssp = priv->dev.ssp;
>        int chn = params_channels(params);
> -       u32 sscr0;
> -       u32 sspsp;
> +       u32 sscr0, sscr1, sspsp;
>        int width = snd_pcm_format_physical_width(params_format(params));
> -       int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
> +       int frame_width;
> +
> +       /* check if the user explicitly set a frame_width */
> +       sscr0 = ssp_read_reg(ssp, SSCR0);
> +
> +       if (sscr0 & (SSCR0_EDSS | SSCR0_DSS))
> +               frame_width = (sscr0 & SSCR0_DSS) +
> +                       (sscr0 & SSCR0_EDSS ? 17 : 1);
> +       else
> +               frame_width = width * chn;
>
>        /* generate correct DMA params */
>        if (cpu_dai->dma_data)
>                kfree(cpu_dai->dma_data);
>
> -       /* Network mode with one active slot (ttsa == 1) can be used
> -        * to force 16-bit frame width on the wire (for S16_LE), even
> -        * with two channels. Use 16-bit DMA transfers for this case.
> -        */
> -       cpu_dai->dma_data = ssp_get_dma_params(ssp,
> -                       ((chn == 2) && (ttsa != 1)) || (width == 32),
> +       cpu_dai->dma_data = ssp_get_dma_params(ssp, frame_width > 16,
>                        substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
>
>        /* we can only change the settings if the port is not in use */
> -       if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
> +       if (sscr0 & SSCR0_SSE)
>                return 0;
>
> -       /* clear selected SSP bits */
> -       sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
> -       ssp_write_reg(ssp, SSCR0, sscr0);
> -
> -       /* bit size */
> -       sscr0 = ssp_read_reg(ssp, SSCR0);
> -       switch (params_format(params)) {
> -       case SNDRV_PCM_FORMAT_S16_LE:
> +       /* FIXME: What this is for? */
>  #ifdef CONFIG_PXA3xx
> -               if (cpu_is_pxa3xx())
> -                       sscr0 |= SSCR0_FPCKE;
> +       if (width == 16 && cpu_is_pxa3xx())
> +               sscr0 |= SSCR0_FPCKE;
>  #endif
> -               sscr0 |= SSCR0_DataSize(16);
> -               break;
> -       case SNDRV_PCM_FORMAT_S24_LE:
> -               sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
> -               break;
> -       case SNDRV_PCM_FORMAT_S32_LE:
> -               sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
> -               break;
> +
> +       if (!(sscr0 & (SSCR0_EDSS | SSCR0_DSS))) {
> +               /* Frame width not set yet, we are not using network mode */
> +               if (frame_width > 16)
> +                       sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
> +               else
> +                       sscr0 |= SSCR0_DataSize(frame_width);
> +
> +               if (frame_width > 32) {
> +                       /*
> +                        * Network mode is needed to support this frame_width
> +                        * We assume that the wire is not networked and setup
> +                        * a "fake" network mode here.
> +                        */
> +                       int slots = frame_width / 32;
> +
> +                       sscr0 |= SSCR0_MOD;
> +                       sscr0 |= SSCR0_SlotsPerFrm(slots);
> +
> +                       /*
> +                        * Set active slots. Only set an active TX slot
> +                        * if we are going to use it.
> +                        */
> +                       ssp_write_reg(ssp, SSRSA, slots - 1);
> +                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +                               ssp_write_reg(ssp, SSTSA, slots - 1);
> +               }
>        }
> +
> +       /* If SSCR0_MOD is set we can't use SSCR1_RWOT */
> +       if (sscr0 & SSCR0_MOD) {
> +               sscr1 = ssp_read_reg(ssp, SSCR1);
> +               ssp_write_reg(ssp, SSCR1, sscr1 & ~SSCR1_RWOT);
> +       }
> +
>        ssp_write_reg(ssp, SSCR0, sscr0);
>
>        switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> @@ -625,14 +660,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
>                break;
>        }
>
> -       /* When we use a network mode, we always require TDM slots
> -        * - complain loudly and fail if they've not been set up yet.
> -        */
> -       if ((sscr0 & SSCR0_MOD) && !ttsa) {
> -               dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
> -               return -EINVAL;
> -       }
> -
>        dump_registers(ssp);
>
>        return 0;
> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
> index e1a920c..69becf2 100644
> --- a/sound/soc/soc-core.c
> +++ b/sound/soc/soc-core.c
> @@ -2133,17 +2133,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
>  /**
>  * snd_soc_dai_set_tdm_slot - configure DAI TDM.
>  * @dai: DAI
> - * @mask: DAI specific mask representing used slots.
> + * @tx_mask: bitmask representing active TX slots.
> + * @rx_mask: bitmask representing active RX slots.
>  * @slots: Number of slots in use.
> + * @frame_width: Width in bits for each slot.
>  *
>  * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
>  * specific.
>  */
>  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
> -       unsigned int mask, int slots)
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>  {
>        if (dai->ops && dai->ops->set_tdm_slot)
> -               return dai->ops->set_tdm_slot(dai, mask, slots);
> +               return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
> +                               slots, frame_width);
>        else
>                return -EINVAL;
>  }
>
> --
> Daniel Ribeiro
>



-- 
Paul Shen

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-10 11:44 ` Paul Shen
@ 2009-06-10 12:05   ` pHilipp Zabel
  2009-06-10 14:17     ` Daniel Ribeiro
  2009-06-10 14:17   ` Daniel Ribeiro
  1 sibling, 1 reply; 10+ messages in thread
From: pHilipp Zabel @ 2009-06-10 12:05 UTC (permalink / raw)
  To: Paul Shen
  Cc: alsa-devel, Eric Miao, Mark Brown, linux-arm-kernel, Daniel Ribeiro

On Wed, Jun 10, 2009 at 1:44 PM, Paul Shen<boshen9@gmail.com> wrote:
> 2009/6/10 Daniel Ribeiro <drwyrm@gmail.com>:
>> * Extend set_tdm_slot to allow the user to arbitrarily set the frame
>>  width and active TX/RX slots.
>> * Reset SSCR0_EDSS and SSCR0_DSS on pxa_ssp_set_dai_fmt.
>> * Makes SSCR0_MOD optional.
>> * Automatically sets network mode when needed if set_tdm_slot was
>>  never called.
>> * Clears SSCR1_RWOT case SSCR0_MOD is set.
>> * Updates magician.c and wm9081.c for the new set_tdm_slot()
>>
>> (Patch is based on Mark's for-2.6.32 branch)
>>
>> Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
>>
>> ---
>>  include/sound/soc-dai.h   |    5 +
>>  sound/soc/codecs/wm9081.c |    4 -
>>  sound/soc/pxa/magician.c  |    2
>>  sound/soc/pxa/pxa-ssp.c   |  119 ++++++++++++++++++++++++++++------------------
>>  sound/soc/soc-core.c      |    9 ++-
>>  5 files changed, 85 insertions(+), 54 deletions(-)
>>
>> diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
>> index 352d7ee..f96cc36 100644
>> --- a/include/sound/soc-dai.h
>> +++ b/include/sound/soc-dai.h
>> @@ -106,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
>>  int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
>>
>>  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
>> -       unsigned int mask, int slots);
>> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width);
>>
>>  int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
>>
>> @@ -140,7 +140,8 @@ struct snd_soc_dai_ops {
>>         */
>>        int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
>>        int (*set_tdm_slot)(struct snd_soc_dai *dai,
>> -               unsigned int mask, int slots);
>> +               unsigned int tx_mask, unsigned int rx_mask,
>> +               int slots, int frame_width);
>>        int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
>>
>>        /*
>> diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
>> index 86fc57e..85c720a 100644
>> --- a/sound/soc/codecs/wm9081.c
>> +++ b/sound/soc/codecs/wm9081.c
>> @@ -1207,7 +1207,7 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
>>  }
>>
>>  static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
>> -                              unsigned int mask, int slots)
>> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>>  {
>>        struct snd_soc_codec *codec = dai->codec;
>>        unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
>> @@ -1219,7 +1219,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
>>
>>        aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
>>
>> -       switch (mask) {
>> +       switch (tx_mask) {
>>        case 1:
>>                break;
>>        case 2:
>> diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
>> index c89a3cd..2345869 100644
>> --- a/sound/soc/pxa/magician.c
>> +++ b/sound/soc/pxa/magician.c
>> @@ -188,7 +188,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
>>        if (ret < 0)
>>                return ret;
>>
>> -       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1);
>> +       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1, 1, 16);
>>        if (ret < 0)
>>                return ret;
>>
>> diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
>> index 46d14f3..f0931e7 100644
>> --- a/sound/soc/pxa/pxa-ssp.c
>> +++ b/sound/soc/pxa/pxa-ssp.c
>> @@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
>>  * Set the active slots in TDM/Network mode
>>  */
>>  static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
>> -       unsigned int mask, int slots)
>> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>>  {
>>        struct ssp_priv *priv = cpu_dai->private_data;
>>        struct ssp_device *ssp = priv->dev.ssp;
>>        u32 sscr0;
>>
>> -       sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7);
>> +       sscr0 = ssp_read_reg(ssp, SSCR0);
>> +       sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(7) | SSCR0_EDSS | SSCR0_DSS);
>> +
>> +       /* set frame width */
>> +       if (frame_width > 16)
>> +               sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
>> +       else
>> +               sscr0 |= SSCR0_DataSize(frame_width);
>> +
>> +       if (slots > 1) {
>> +               /* enable network mode */
>> +               sscr0 |= SSCR0_MOD;
>>
> Seems the frame_width has no  such relations with sampe width, the
> sample width is defined on runtime by the audio files.
> Make a example sample with  paly a often used 16bit sample width
> stereo aduio file.
>
> When you play 16bit audio sample with  2*16 bit frame ,
>         frame   --|____________|------------------|_____________|---
>         data      --<======>-<======>-<======>-
>         here the datasize should be SSCR0_DataSize(16), the frame size is 32
>
> also you can play 16bit audio sample with 2*32 frame,
>         frame
> --|_________________________|------------------------------------|____
>         data     --<======>-------------------<======>-------------------<==
>         here the datasize is also DataSize(16), but the frame size is 64.
>
> Do I misunderstand you?

Hmm right, the real frame width is DataSize * slots. So maybe
       /* set data size */
       data_size = frame_width/slots;
       if (data_size > 16)
               sscr0 |= SSCR0_EDSS | SSCR0_DataSize(data_size - 16);
       else
               sscr0 |= SSCR0_DataSize(data_size);
would be more appropriate. Or have that parameter be sample_width
instead, as Mark initially proposed.

>> -       /* set number of active slots */
>> -       sscr0 |= SSCR0_SlotsPerFrm(slots);
>> +               /* set number of active slots */
>> +               sscr0 |= SSCR0_SlotsPerFrm(slots);
>> +
>> +               /* set active slot mask */
>> +               ssp_write_reg(ssp, SSTSA, tx_mask);
>> +               ssp_write_reg(ssp, SSRSA, rx_mask);
>> +       }
>>        ssp_write_reg(ssp, SSCR0, sscr0);
>>
>> -       /* set active slot mask */
>> -       ssp_write_reg(ssp, SSTSA, mask);
>> -       ssp_write_reg(ssp, SSRSA, mask);
>>        return 0;
>>  }
>>
>> @@ -439,8 +452,8 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
>>        }
>>
>>        /* reset port settings */
>> -       sscr0 = ssp_read_reg(ssp, SSCR0) &
>> -               (SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
>> +       sscr0 = ssp_read_reg(ssp, SSCR0) & (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD |
>> +                       SSCR0_ACS | SSCR0_EDSS | SSCR0_DSS);
>>        sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
>>        sspsp = 0;
>>
>> @@ -487,7 +500,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
>>        case SND_SOC_DAIFMT_DSP_A:
>>                sspsp |= SSPSP_FSRT;
>>        case SND_SOC_DAIFMT_DSP_B:
>> -               sscr0 |= SSCR0_MOD | SSCR0_PSP;
>> +               sscr0 |= SSCR0_PSP;
>>                sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
>>
>>                switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
>> @@ -537,48 +550,70 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
>>        struct ssp_priv *priv = cpu_dai->private_data;
>>        struct ssp_device *ssp = priv->dev.ssp;
>>        int chn = params_channels(params);
>> -       u32 sscr0;
>> -       u32 sspsp;
>> +       u32 sscr0, sscr1, sspsp;
>>        int width = snd_pcm_format_physical_width(params_format(params));
>> -       int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
>> +       int frame_width;
>> +
>> +       /* check if the user explicitly set a frame_width */
>> +       sscr0 = ssp_read_reg(ssp, SSCR0);
>> +
>> +       if (sscr0 & (SSCR0_EDSS | SSCR0_DSS))
>> +               frame_width = (sscr0 & SSCR0_DSS) +
>> +                       (sscr0 & SSCR0_EDSS ? 17 : 1);
>> +       else
>> +               frame_width = width * chn;
>>
>>        /* generate correct DMA params */
>>        if (cpu_dai->dma_data)
>>                kfree(cpu_dai->dma_data);
>>
>> -       /* Network mode with one active slot (ttsa == 1) can be used
>> -        * to force 16-bit frame width on the wire (for S16_LE), even
>> -        * with two channels. Use 16-bit DMA transfers for this case.
>> -        */
>> -       cpu_dai->dma_data = ssp_get_dma_params(ssp,
>> -                       ((chn == 2) && (ttsa != 1)) || (width == 32),
>> +       cpu_dai->dma_data = ssp_get_dma_params(ssp, frame_width > 16,
>>                        substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
>>
>>        /* we can only change the settings if the port is not in use */
>> -       if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
>> +       if (sscr0 & SSCR0_SSE)
>>                return 0;
>>
>> -       /* clear selected SSP bits */
>> -       sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
>> -       ssp_write_reg(ssp, SSCR0, sscr0);
>> -
>> -       /* bit size */
>> -       sscr0 = ssp_read_reg(ssp, SSCR0);
>> -       switch (params_format(params)) {
>> -       case SNDRV_PCM_FORMAT_S16_LE:
>> +       /* FIXME: What this is for? */
>>  #ifdef CONFIG_PXA3xx
>> -               if (cpu_is_pxa3xx())
>> -                       sscr0 |= SSCR0_FPCKE;
>> +       if (width == 16 && cpu_is_pxa3xx())
>> +               sscr0 |= SSCR0_FPCKE;
>>  #endif
>> -               sscr0 |= SSCR0_DataSize(16);
>> -               break;
>> -       case SNDRV_PCM_FORMAT_S24_LE:
>> -               sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
>> -               break;
>> -       case SNDRV_PCM_FORMAT_S32_LE:
>> -               sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
>> -               break;
>> +
>> +       if (!(sscr0 & (SSCR0_EDSS | SSCR0_DSS))) {
>> +               /* Frame width not set yet, we are not using network mode */
>> +               if (frame_width > 16)
>> +                       sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
>> +               else
>> +                       sscr0 |= SSCR0_DataSize(frame_width);
>> +
>> +               if (frame_width > 32) {
>> +                       /*
>> +                        * Network mode is needed to support this frame_width
>> +                        * We assume that the wire is not networked and setup
>> +                        * a "fake" network mode here.
>> +                        */
>> +                       int slots = frame_width / 32;
>> +
>> +                       sscr0 |= SSCR0_MOD;
>> +                       sscr0 |= SSCR0_SlotsPerFrm(slots);
>> +
>> +                       /*
>> +                        * Set active slots. Only set an active TX slot
>> +                        * if we are going to use it.
>> +                        */
>> +                       ssp_write_reg(ssp, SSRSA, slots - 1);
>> +                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
>> +                               ssp_write_reg(ssp, SSTSA, slots - 1);
>> +               }
>>        }
>> +
>> +       /* If SSCR0_MOD is set we can't use SSCR1_RWOT */
>> +       if (sscr0 & SSCR0_MOD) {
>> +               sscr1 = ssp_read_reg(ssp, SSCR1);
>> +               ssp_write_reg(ssp, SSCR1, sscr1 & ~SSCR1_RWOT);
>> +       }
>> +
>>        ssp_write_reg(ssp, SSCR0, sscr0);
>>
>>        switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
>> @@ -625,14 +660,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
>>                break;
>>        }
>>
>> -       /* When we use a network mode, we always require TDM slots
>> -        * - complain loudly and fail if they've not been set up yet.
>> -        */
>> -       if ((sscr0 & SSCR0_MOD) && !ttsa) {
>> -               dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
>> -               return -EINVAL;
>> -       }
>> -
>>        dump_registers(ssp);
>>
>>        return 0;
>> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
>> index e1a920c..69becf2 100644
>> --- a/sound/soc/soc-core.c
>> +++ b/sound/soc/soc-core.c
>> @@ -2133,17 +2133,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
>>  /**
>>  * snd_soc_dai_set_tdm_slot - configure DAI TDM.
>>  * @dai: DAI
>> - * @mask: DAI specific mask representing used slots.
>> + * @tx_mask: bitmask representing active TX slots.
>> + * @rx_mask: bitmask representing active RX slots.
>>  * @slots: Number of slots in use.
>> + * @frame_width: Width in bits for each slot.
>>  *
>>  * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
>>  * specific.
>>  */
>>  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
>> -       unsigned int mask, int slots)
>> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>>  {
>>        if (dai->ops && dai->ops->set_tdm_slot)
>> -               return dai->ops->set_tdm_slot(dai, mask, slots);
>> +               return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
>> +                               slots, frame_width);
>>        else
>>                return -EINVAL;
>>  }
>>
>> --
>> Daniel Ribeiro
>>
>
>
>
> --
> Paul Shen
>

regards
Philipp

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-09 17:13 [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM Daniel Ribeiro
  2009-06-10 11:44 ` Paul Shen
@ 2009-06-10 12:18 ` Mark Brown
  2009-06-10 14:39   ` [alsa-devel] " Daniel Ribeiro
  2009-06-10 14:44 ` pHilipp Zabel
  2 siblings, 1 reply; 10+ messages in thread
From: Mark Brown @ 2009-06-10 12:18 UTC (permalink / raw)
  To: Daniel Ribeiro
  Cc: Paul Shen, alsa-devel, Eric Miao, linux-arm-kernel, Philipp Zabel

On Tue, Jun 09, 2009 at 02:13:10PM -0300, Daniel Ribeiro wrote:
> * Extend set_tdm_slot to allow the user to arbitrarily set the frame
>   width and active TX/RX slots.
> * Reset SSCR0_EDSS and SSCR0_DSS on pxa_ssp_set_dai_fmt.
> * Makes SSCR0_MOD optional.
> * Automatically sets network mode when needed if set_tdm_slot was
>   never called.
> * Clears SSCR1_RWOT case SSCR0_MOD is set.
> * Updates magician.c and wm9081.c for the new set_tdm_slot()

Please split out the API change from the use of it in the PXA SSP driver
- just include enough to keep it building, then send a second patch
changing the internals of the SSP driver.  At the minute there's two
different changes in here.

>  static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
> -			       unsigned int mask, int slots)
> +	unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>  {
>  	struct snd_soc_codec *codec = dai->codec;
>  	unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
> @@ -1219,7 +1219,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
>  
>  	aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
>  
> -	switch (mask) {
> +	switch (tx_mask) {
>  	case 1:
>  		break;
>  	case 2:

This is wrong, the WM9081 is a DAC only part so it should be paying
attention to the RX mask, not the TX one.  We also need to handle the
sample size here.

I've not checked the SSP code yet.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-10 11:44 ` Paul Shen
  2009-06-10 12:05   ` pHilipp Zabel
@ 2009-06-10 14:17   ` Daniel Ribeiro
  1 sibling, 0 replies; 10+ messages in thread
From: Daniel Ribeiro @ 2009-06-10 14:17 UTC (permalink / raw)
  To: Paul Shen
  Cc: alsa-devel, Eric Miao, Mark Brown, Philipp Zabel, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 1458 bytes --]

Em Qua, 2009-06-10 às 19:44 +0800, Paul Shen escreveu:
> Seems the frame_width has no  such relations with sampe width, the
> sample width is defined on runtime by the audio files.
> Make a example sample with  paly a often used 16bit sample width
> stereo aduio file.

> When you play 16bit audio sample with  2*16 bit frame ,
>          frame   --|____________|------------------|_____________|---
>          data      --<======>-<======>-<======>-
>          here the datasize should be SSCR0_DataSize(16), the frame size is 32

No, the example above would be DataSize(32), SFRMWDTH(16). (LEFT_J?)

Or it could be DataSize(16) and 2 active TDM Slots.

But the point here is to not use SSCR0_MOD when its not needed
(sample * chn <= 32), we need to support real networked configurations,
set_tdm_slot() should only be called if you are really using network
mode. eg:

set_tdm_slots(3, 2) shouldn't ever be needed.

> also you can play 16bit audio sample with 2*32 frame,
>          frame
> --|_________________________|------------------------------------|____
>          data     --<======>-------------------<======>-------------------<==
>          here the datasize is also DataSize(16), but the frame size is 64.
> 
> Do I misunderstand you?

Sure you can waste bitclocks.. But we should try to only waste bitclocks
when it is really needed, eg for I2S. The patch is not considering I2S
yet.


-- 
Daniel Ribeiro

[-- Attachment #1.2: Esta é uma parte de mensagem assinada digitalmente --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-10 12:05   ` pHilipp Zabel
@ 2009-06-10 14:17     ` Daniel Ribeiro
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Ribeiro @ 2009-06-10 14:17 UTC (permalink / raw)
  To: pHilipp Zabel
  Cc: Paul Shen, alsa-devel, Eric Miao, Mark Brown, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 726 bytes --]

Em Qua, 2009-06-10 às 14:05 +0200, pHilipp Zabel escreveu:
> Hmm right, the real frame width is DataSize * slots. So maybe
>        /* set data size */
>        data_size = frame_width/slots;
>        if (data_size > 16)
>                sscr0 |= SSCR0_EDSS | SSCR0_DataSize(data_size - 16);
>        else
>                sscr0 |= SSCR0_DataSize(data_size);
> would be more appropriate. Or have that parameter be sample_width
> instead, as Mark initially proposed.

Ack.

Naming it frame_width was not a good idea. Im using frame_width for the
distance between each SFRM assertion when not networked and for the
duration of each slot when networked. I will name it slot_width instead.

-- 
Daniel Ribeiro

[-- Attachment #1.2: Esta é uma parte de mensagem assinada digitalmente --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [alsa-devel] [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-10 12:18 ` Mark Brown
@ 2009-06-10 14:39   ` Daniel Ribeiro
  2009-06-10 14:47     ` Mark Brown
  2009-06-10 14:48     ` Mark Brown
  0 siblings, 2 replies; 10+ messages in thread
From: Daniel Ribeiro @ 2009-06-10 14:39 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, Paul Shen, Philipp Zabel, Eric Miao, linux-arm-kernel


[-- Attachment #1.1: Type: text/plain, Size: 782 bytes --]

Em Qua, 2009-06-10 às 13:18 +0100, Mark Brown escreveu:
> Please split out the API change from the use of it in the PXA SSP driver
> - just include enough to keep it building, then send a second patch
> changing the internals of the SSP driver.  At the minute there's two
> different changes in here.

Ok.

> This is wrong, the WM9081 is a DAC only part so it should be paying
> attention to the RX mask, not the TX one.  We also need to handle the
> sample size here.

Ok, but I dont know how to handle slot_width for wm9081. Is a FIXME
comment here enough for a first version? Its hard for me to get this
working correctly on wm9081 as I dont have such hardware and PCAP2 only
supports 16bits slots.

> I've not checked the SSP code yet.

-- 
Daniel Ribeiro

[-- Attachment #1.2: Esta é uma parte de mensagem assinada digitalmente --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

[-- Attachment #2: Type: text/plain, Size: 271 bytes --]

-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ:        http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette:  http://www.arm.linux.org.uk/mailinglists/etiquette.php

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-09 17:13 [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM Daniel Ribeiro
  2009-06-10 11:44 ` Paul Shen
  2009-06-10 12:18 ` Mark Brown
@ 2009-06-10 14:44 ` pHilipp Zabel
  2 siblings, 0 replies; 10+ messages in thread
From: pHilipp Zabel @ 2009-06-10 14:44 UTC (permalink / raw)
  To: Daniel Ribeiro
  Cc: Paul Shen, alsa-devel, Eric Miao, Mark Brown, linux-arm-kernel

2009/6/9 Daniel Ribeiro <drwyrm@gmail.com>:
> * Extend set_tdm_slot to allow the user to arbitrarily set the frame
>  width and active TX/RX slots.
> * Reset SSCR0_EDSS and SSCR0_DSS on pxa_ssp_set_dai_fmt.
> * Makes SSCR0_MOD optional.
> * Automatically sets network mode when needed if set_tdm_slot was
>  never called.
> * Clears SSCR1_RWOT case SSCR0_MOD is set.
> * Updates magician.c and wm9081.c for the new set_tdm_slot()
>
> (Patch is based on Mark's for-2.6.32 branch)
>
> Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
>
> ---
>  include/sound/soc-dai.h   |    5 +
>  sound/soc/codecs/wm9081.c |    4 -
>  sound/soc/pxa/magician.c  |    2
>  sound/soc/pxa/pxa-ssp.c   |  119 ++++++++++++++++++++++++++++------------------
>  sound/soc/soc-core.c      |    9 ++-
>  5 files changed, 85 insertions(+), 54 deletions(-)
>
> diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
> index 352d7ee..f96cc36 100644
> --- a/include/sound/soc-dai.h
> +++ b/include/sound/soc-dai.h
> @@ -106,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
>  int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
>
>  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
> -       unsigned int mask, int slots);
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width);
>
>  int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
>
> @@ -140,7 +140,8 @@ struct snd_soc_dai_ops {
>         */
>        int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
>        int (*set_tdm_slot)(struct snd_soc_dai *dai,
> -               unsigned int mask, int slots);
> +               unsigned int tx_mask, unsigned int rx_mask,
> +               int slots, int frame_width);
>        int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
>
>        /*
> diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
> index 86fc57e..85c720a 100644
> --- a/sound/soc/codecs/wm9081.c
> +++ b/sound/soc/codecs/wm9081.c
> @@ -1207,7 +1207,7 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai,
>  }
>
>  static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
> -                              unsigned int mask, int slots)
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>  {
>        struct snd_soc_codec *codec = dai->codec;
>        unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1);
> @@ -1219,7 +1219,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
>
>        aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT;
>
> -       switch (mask) {
> +       switch (tx_mask) {
>        case 1:
>                break;
>        case 2:
> diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
> index c89a3cd..2345869 100644
> --- a/sound/soc/pxa/magician.c
> +++ b/sound/soc/pxa/magician.c
> @@ -188,7 +188,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
>        if (ret < 0)
>                return ret;
>
> -       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1);
> +       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1, 1, 16);

This will have to depend on the sample width. For S24_LE/S32_LE,
slot_width should be 32. Also the rx mask could be empty, the SSP link
is tx only on magician

>        if (ret < 0)
>                return ret;
>
> diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
> index 46d14f3..f0931e7 100644
> --- a/sound/soc/pxa/pxa-ssp.c
> +++ b/sound/soc/pxa/pxa-ssp.c
> @@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
>  * Set the active slots in TDM/Network mode
>  */
>  static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
> -       unsigned int mask, int slots)
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>  {
>        struct ssp_priv *priv = cpu_dai->private_data;
>        struct ssp_device *ssp = priv->dev.ssp;
>        u32 sscr0;
>
> -       sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7);
> +       sscr0 = ssp_read_reg(ssp, SSCR0);
> +       sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(7) | SSCR0_EDSS | SSCR0_DSS);
> +
> +       /* set frame width */
> +       if (frame_width > 16)
> +               sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
> +       else
> +               sscr0 |= SSCR0_DataSize(frame_width);
> +
> +       if (slots > 1) {
> +               /* enable network mode */
> +               sscr0 |= SSCR0_MOD;
>
> -       /* set number of active slots */
> -       sscr0 |= SSCR0_SlotsPerFrm(slots);
> +               /* set number of active slots */
> +               sscr0 |= SSCR0_SlotsPerFrm(slots);
> +
> +               /* set active slot mask */
> +               ssp_write_reg(ssp, SSTSA, tx_mask);
> +               ssp_write_reg(ssp, SSRSA, rx_mask);
> +       }
>        ssp_write_reg(ssp, SSCR0, sscr0);
>
> -       /* set active slot mask */
> -       ssp_write_reg(ssp, SSTSA, mask);
> -       ssp_write_reg(ssp, SSRSA, mask);
>        return 0;
>  }
>
> @@ -439,8 +452,8 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
>        }
>
>        /* reset port settings */
> -       sscr0 = ssp_read_reg(ssp, SSCR0) &
> -               (SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
> +       sscr0 = ssp_read_reg(ssp, SSCR0) & (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD |
> +                       SSCR0_ACS | SSCR0_EDSS | SSCR0_DSS);
>        sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
>        sspsp = 0;
>
> @@ -487,7 +500,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
>        case SND_SOC_DAIFMT_DSP_A:
>                sspsp |= SSPSP_FSRT;
>        case SND_SOC_DAIFMT_DSP_B:
> -               sscr0 |= SSCR0_MOD | SSCR0_PSP;
> +               sscr0 |= SSCR0_PSP;
>                sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
>
>                switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
> @@ -537,48 +550,70 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
>        struct ssp_priv *priv = cpu_dai->private_data;
>        struct ssp_device *ssp = priv->dev.ssp;
>        int chn = params_channels(params);
> -       u32 sscr0;
> -       u32 sspsp;
> +       u32 sscr0, sscr1, sspsp;
>        int width = snd_pcm_format_physical_width(params_format(params));
> -       int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
> +       int frame_width;
> +
> +       /* check if the user explicitly set a frame_width */
> +       sscr0 = ssp_read_reg(ssp, SSCR0);
> +
> +       if (sscr0 & (SSCR0_EDSS | SSCR0_DSS))
> +               frame_width = (sscr0 & SSCR0_DSS) +
> +                       (sscr0 & SSCR0_EDSS ? 17 : 1);
> +       else
> +               frame_width = width * chn;
>
>        /* generate correct DMA params */
>        if (cpu_dai->dma_data)
>                kfree(cpu_dai->dma_data);
>
> -       /* Network mode with one active slot (ttsa == 1) can be used
> -        * to force 16-bit frame width on the wire (for S16_LE), even
> -        * with two channels. Use 16-bit DMA transfers for this case.
> -        */
> -       cpu_dai->dma_data = ssp_get_dma_params(ssp,
> -                       ((chn == 2) && (ttsa != 1)) || (width == 32),
> +       cpu_dai->dma_data = ssp_get_dma_params(ssp, frame_width > 16,
>                        substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
>
>        /* we can only change the settings if the port is not in use */
> -       if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
> +       if (sscr0 & SSCR0_SSE)
>                return 0;
>
> -       /* clear selected SSP bits */
> -       sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
> -       ssp_write_reg(ssp, SSCR0, sscr0);
> -
> -       /* bit size */
> -       sscr0 = ssp_read_reg(ssp, SSCR0);
> -       switch (params_format(params)) {
> -       case SNDRV_PCM_FORMAT_S16_LE:
> +       /* FIXME: What this is for? */
>  #ifdef CONFIG_PXA3xx
> -               if (cpu_is_pxa3xx())
> -                       sscr0 |= SSCR0_FPCKE;
> +       if (width == 16 && cpu_is_pxa3xx())
> +               sscr0 |= SSCR0_FPCKE;
>  #endif
> -               sscr0 |= SSCR0_DataSize(16);
> -               break;
> -       case SNDRV_PCM_FORMAT_S24_LE:
> -               sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8));
> -               break;
> -       case SNDRV_PCM_FORMAT_S32_LE:
> -               sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
> -               break;
> +
> +       if (!(sscr0 & (SSCR0_EDSS | SSCR0_DSS))) {
> +               /* Frame width not set yet, we are not using network mode */
> +               if (frame_width > 16)
> +                       sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16);
> +               else
> +                       sscr0 |= SSCR0_DataSize(frame_width);
> +
> +               if (frame_width > 32) {
> +                       /*
> +                        * Network mode is needed to support this frame_width
> +                        * We assume that the wire is not networked and setup
> +                        * a "fake" network mode here.
> +                        */
> +                       int slots = frame_width / 32;
> +
> +                       sscr0 |= SSCR0_MOD;
> +                       sscr0 |= SSCR0_SlotsPerFrm(slots);
> +
> +                       /*
> +                        * Set active slots. Only set an active TX slot
> +                        * if we are going to use it.
> +                        */
> +                       ssp_write_reg(ssp, SSRSA, slots - 1);
> +                       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +                               ssp_write_reg(ssp, SSTSA, slots - 1);
> +               }
>        }
> +
> +       /* If SSCR0_MOD is set we can't use SSCR1_RWOT */
> +       if (sscr0 & SSCR0_MOD) {
> +               sscr1 = ssp_read_reg(ssp, SSCR1);
> +               ssp_write_reg(ssp, SSCR1, sscr1 & ~SSCR1_RWOT);
> +       }
> +
>        ssp_write_reg(ssp, SSCR0, sscr0);
>
>        switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
> @@ -625,14 +660,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
>                break;
>        }
>
> -       /* When we use a network mode, we always require TDM slots
> -        * - complain loudly and fail if they've not been set up yet.
> -        */
> -       if ((sscr0 & SSCR0_MOD) && !ttsa) {
> -               dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
> -               return -EINVAL;
> -       }
> -
>        dump_registers(ssp);
>
>        return 0;
> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
> index e1a920c..69becf2 100644
> --- a/sound/soc/soc-core.c
> +++ b/sound/soc/soc-core.c
> @@ -2133,17 +2133,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
>  /**
>  * snd_soc_dai_set_tdm_slot - configure DAI TDM.
>  * @dai: DAI
> - * @mask: DAI specific mask representing used slots.
> + * @tx_mask: bitmask representing active TX slots.
> + * @rx_mask: bitmask representing active RX slots.
>  * @slots: Number of slots in use.
> + * @frame_width: Width in bits for each slot.
>  *
>  * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
>  * specific.
>  */
>  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
> -       unsigned int mask, int slots)
> +       unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width)
>  {
>        if (dai->ops && dai->ops->set_tdm_slot)
> -               return dai->ops->set_tdm_slot(dai, mask, slots);
> +               return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
> +                               slots, frame_width);
>        else
>                return -EINVAL;
>  }
>
> --
> Daniel Ribeiro
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-10 14:39   ` [alsa-devel] " Daniel Ribeiro
@ 2009-06-10 14:47     ` Mark Brown
  2009-06-10 14:48     ` Mark Brown
  1 sibling, 0 replies; 10+ messages in thread
From: Mark Brown @ 2009-06-10 14:47 UTC (permalink / raw)
  To: Daniel Ribeiro
  Cc: Paul Shen, alsa-devel, Eric Miao, linux-arm-kernel, Philipp Zabel

On Wed, Jun 10, 2009 at 11:39:54AM -0300, Daniel Ribeiro wrote:
> Em Qua, 2009-06-10 às 13:18 +0100, Mark Brown escreveu:

> > This is wrong, the WM9081 is a DAC only part so it should be paying
> > attention to the RX mask, not the TX one.  We also need to handle the
> > sample size here.

> Ok, but I dont know how to handle slot_width for wm9081. Is a FIXME
> comment here enough for a first version? Its hard for me to get this
> working correctly on wm9081 as I dont have such hardware and PCAP2 only
> supports 16bits slots.

The sample size code from the hw_params() function should be copied in
here and the sample size remembered in the wm9081_priv structure.  Then
in hw_params() the sample size would get ignored if one had been
configured via set_tdm_slot().  A size of zero should be supported there
to allow dropping of TDM mode.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
  2009-06-10 14:39   ` [alsa-devel] " Daniel Ribeiro
  2009-06-10 14:47     ` Mark Brown
@ 2009-06-10 14:48     ` Mark Brown
  1 sibling, 0 replies; 10+ messages in thread
From: Mark Brown @ 2009-06-10 14:48 UTC (permalink / raw)
  To: Daniel Ribeiro
  Cc: Paul Shen, alsa-devel, Eric Miao, linux-arm-kernel, Philipp Zabel

On Wed, Jun 10, 2009 at 11:39:54AM -0300, Daniel Ribeiro wrote:

> Ok, but I dont know how to handle slot_width for wm9081. Is a FIXME
> comment here enough for a first version? Its hard for me to get this
> working correctly on wm9081 as I dont have such hardware and PCAP2 only
> supports 16bits slots.

Oh, and it's probably OK if you just leave bits of this undone - I'll
amend the code before applying it.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-06-10 14:48 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-09 17:13 [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM Daniel Ribeiro
2009-06-10 11:44 ` Paul Shen
2009-06-10 12:05   ` pHilipp Zabel
2009-06-10 14:17     ` Daniel Ribeiro
2009-06-10 14:17   ` Daniel Ribeiro
2009-06-10 12:18 ` Mark Brown
2009-06-10 14:39   ` [alsa-devel] " Daniel Ribeiro
2009-06-10 14:47     ` Mark Brown
2009-06-10 14:48     ` Mark Brown
2009-06-10 14:44 ` pHilipp Zabel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.