diff mbox series

ASoC: xilinx: Embed IEC958 sample rate val to channel status register

Message ID 20231219122955.104696-1-sunil.vaghela@softnautics.com (mailing list archive)
State New, archived
Headers show
Series ASoC: xilinx: Embed IEC958 sample rate val to channel status register | expand

Commit Message

Sunil Vaghela Dec. 19, 2023, 12:29 p.m. UTC
As per IEC 60958 specification, bits 24 to 27 of channel status register
indicates audio sample frequency. If these bits are not set, audio
analyzer always shows 44.1KHz sample rate, irrespective of any sample
rate audio is being played.

This patch fixes the issue by setting IEC958 specified channel status
values for different audio sample rate in [24:27] bits of MM2S Audio
channel status register.

Signed-off-by: Sunil Vaghela <sunil.vaghela@softnautics.com>
---
 sound/soc/xilinx/xlnx_formatter_pcm.c | 74 ++++++++++++++++++++++++++-
 1 file changed, 73 insertions(+), 1 deletion(-)

Comments

Mark Brown Dec. 19, 2023, 2:01 p.m. UTC | #1
On Tue, Dec 19, 2023 at 05:59:55PM +0530, Sunil Vaghela wrote:
> As per IEC 60958 specification, bits 24 to 27 of channel status register
> indicates audio sample frequency. If these bits are not set, audio
> analyzer always shows 44.1KHz sample rate, irrespective of any sample
> rate audio is being played.

This breaks an x86 allmodconfig build:

/build/stage/linux/sound/soc/xilinx/xlnx_formatter_pcm.c: In function ‘xlnx_form
atter_pcm_hw_params’:
/build/stage/linux/sound/soc/xilinx/xlnx_formatter_pcm.c:572:26: error: ‘struct 
xlnx_pcm_drv_data’ has no member named ‘nodes’
  572 |         if ((strstr(adata->nodes[XLNX_PLAYBACK]->name, "hdmi")) ||
      |                          ^~
/build/stage/linux/sound/soc/xilinx/xlnx_formatter_pcm.c:572:34: error: ‘XLNX_PL
AYBACK’ undeclared (first use in this function)
  572 |         if ((strstr(adata->nodes[XLNX_PLAYBACK]->name, "hdmi")) ||
      |                                  ^~~~~~~~~~~~~
/build/stage/linux/sound/soc/xilinx/xlnx_formatter_pcm.c:572:34: note: each unde
clared identifier is reported only once for each function it appears in
/build/stage/linux/sound/soc/xilinx/xlnx_formatter_pcm.c:573:26: error: ‘struct xlnx_pcm_drv_data’ has no member named ‘nodes’
  573 |             (strstr(adata->nodes[XLNX_PLAYBACK]->name, "dp"))) {
      |                          ^~
diff mbox series

Patch

diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index 299cfb5e2022..041010203ba5 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -451,12 +451,48 @@  xlnx_formatter_pcm_pointer(struct snd_soc_component *component,
 	return bytes_to_frames(runtime, pos);
 }
 
+static u32 xlnx_formatter_get_iec958_ch_status(u32 sample_rate)
+{
+	u32 tmp = 0;
+
+	switch (sample_rate) {
+	case 32000:
+		tmp = IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		tmp = IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		tmp = IEC958_AES3_CON_FS_48000;
+		break;
+	case 88200:
+		tmp = IEC958_AES3_CON_FS_88200;
+		break;
+	case 96000:
+		tmp = IEC958_AES3_CON_FS_96000;
+		break;
+	case 176400:
+		tmp = IEC958_AES3_CON_FS_176400;
+		break;
+	case 192000:
+		tmp = IEC958_AES3_CON_FS_192000;
+		break;
+	case 768000:
+		tmp = IEC958_AES3_CON_FS_768000;
+		break;
+	default:
+		tmp = IEC958_AES3_CON_FS_NOTID;
+	}
+		return tmp;
+}
+
 static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
 					struct snd_pcm_substream *substream,
 					struct snd_pcm_hw_params *params)
 {
+	void __iomem *reg;
 	u32 low, high, active_ch, val, bytes_per_ch, bits_per_sample;
-	u32 aes_reg1_val, aes_reg2_val;
+	u32 aes_reg1_val, aes_reg2_val, sample_rate, ch_sts;
 	u64 size;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct xlnx_pcm_stream_param *stream_data = runtime->private_data;
@@ -533,6 +569,42 @@  static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
 	bytes_per_ch = DIV_ROUND_UP(params_period_bytes(params), active_ch);
 	writel(bytes_per_ch, stream_data->mmio + XLNX_BYTES_PER_CH);
 
+	if ((strstr(adata->nodes[XLNX_PLAYBACK]->name, "hdmi")) ||
+	    (strstr(adata->nodes[XLNX_PLAYBACK]->name, "dp"))) {
+		sample_rate = params_rate(params);
+		dev_info(component->dev, "%s: sample_rate=%d\n", __func__, sample_rate);
+
+		/* As per IEC 60958 standards, whenever transmitting a valid audio
+		 * stream, HDMI/DP Sources shall always include valid and correct
+		 * information in Channel Status bits 24 through 27. For L-PCM audio,
+		 * these bits shall indicate the audio sample frequency. For
+		 * compressed audio formats, these bits shall indicate the IEC 60958
+		 * frame-rate.
+		 *
+		 * Channel Status Bit Number     Sample Frequency or Frame Rate
+		 *   24    25     26    27
+		 *   -----------------------     ------------------------------
+		 *    1     1      0     0                    32 kHz
+		 *    0     0      0     0                    44.1 kHz
+		 *    0     0      0     1                    88.2 kHz
+		 *    0     0      1     1                    176.4 kHz
+		 *    0     1      0     0                    48 kHz
+		 *    0     1      0     1                    96 kHz
+		 *    0     1      1     1                    192 kHz
+		 *    1     0      0     1                    768 kHz
+		 */
+
+		ch_sts = xlnx_formatter_get_iec958_ch_status(sample_rate);
+		dev_info(component->dev, "%s: iec60958 channel status bits 24 to 27 value for sample rate %dHz = 0x%08x\n",
+			 __func__, sample_rate, ch_sts);
+		ch_sts <<= 24;
+		reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_CH_STS_START;
+		aes_reg1_val = ioread32(reg);
+		aes_reg1_val |= ch_sts;
+		dev_info(component->dev, "%s: MM2S: AES Encode channel status register value 0x%08x\n",
+			 __func__, aes_reg1_val);
+		iowrite32(aes_reg1_val, reg);
+	}
 	return 0;
 }