mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Cássio Gabriel" <cassiogabrielcontato@gmail.com>
To: Takashi Iwai <tiwai@suse.com>,
	 Thierry Reding <thierry.reding@kernel.org>,
	 Jonathan Hunter <jonathanh@nvidia.com>,
	Jaroslav Kysela <perex@perex.cz>
Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-tegra@vger.kernel.org, notify@kernel.org,
	"Cássio Gabriel" <cassiogabrielcontato@gmail.com>
Subject: [PATCH RFC 4/4] ALSA: x86: Use common CEA channel allocations
Date: Fri, 12 Jun 2026 01:53:26 -0300	[thread overview]
Message-ID: <20260612-alsa-cea-channel-allocation-v1-4-b1bcbb6b1051@gmail.com> (raw)
In-Reply-To: <20260612-alsa-cea-channel-allocation-v1-0-b1bcbb6b1051@gmail.com>

Replace the Intel HDMI LPE copy of the CEA allocation table and selector
with the common PCM ELD helpers. Preserve the driver's existing limits:
only ELD speaker bits 0 through 6 participate, only CA values through
0x1f are considered, and an incompatible ELD does not use HDA's fallback.

Select SND_PCM_ELD for the new helper dependency.

Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
 sound/x86/Kconfig            |   1 +
 sound/x86/intel_hdmi_audio.c | 158 ++++++-------------------------------------
 sound/x86/intel_hdmi_audio.h |   9 ---
 3 files changed, 20 insertions(+), 148 deletions(-)

diff --git a/sound/x86/Kconfig b/sound/x86/Kconfig
index 4ffcc5e623c2..a990989a12b9 100644
--- a/sound/x86/Kconfig
+++ b/sound/x86/Kconfig
@@ -12,6 +12,7 @@ config HDMI_LPE_AUDIO
 	tristate "HDMI audio without HDAudio on Intel Atom platforms"
 	depends on DRM_I915
 	select SND_PCM
+	select SND_PCM_ELD
 	help
 	 Choose this option to support HDMI LPE Audio mode
 
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
index 91dfcf47e979..4ea29c3ea6c5 100644
--- a/sound/x86/intel_hdmi_audio.c
+++ b/sound/x86/intel_hdmi_audio.c
@@ -26,6 +26,7 @@
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/pcm.h>
+#include <sound/pcm_drm_eld.h>
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/control.h>
@@ -57,72 +58,6 @@ module_param(single_port, bool, 0444);
 MODULE_PARM_DESC(single_port,
 		"Single-port mode (for compatibility)");
 
-/*
- * ELD SA bits in the CEA Speaker Allocation data block
- */
-static const int eld_speaker_allocation_bits[] = {
-	[0] = FL | FR,
-	[1] = LFE,
-	[2] = FC,
-	[3] = RL | RR,
-	[4] = RC,
-	[5] = FLC | FRC,
-	[6] = RLC | RRC,
-	/* the following are not defined in ELD yet */
-	[7] = 0,
-};
-
-/*
- * This is an ordered list!
- *
- * The preceding ones have better chances to be selected by
- * hdmi_channel_allocation().
- */
-static struct cea_channel_speaker_allocation channel_allocations[] = {
-/*                        channel:   7     6    5    4    3     2    1    0  */
-{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
-				/* 2.1 */
-{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
-				/* Dolby Surround */
-{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
-				/* surround40 */
-{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
-				/* surround41 */
-{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
-				/* surround50 */
-{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
-				/* surround51 */
-{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
-				/* 6.1 */
-{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-				/* surround71 */
-{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-
-{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
-{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
-{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
-{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
-{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
-{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
-{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
-{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
-};
-
 static const struct channel_map_table map_tables[] = {
 	{ SNDRV_CHMAP_FL,       0x00,   FL },
 	{ SNDRV_CHMAP_FR,       0x01,   FR },
@@ -384,68 +319,13 @@ static int had_init_audio_ctrl(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-/*
- * Compute derived values in channel_allocations[].
- */
-static void init_channel_allocations(void)
-{
-	int i, j;
-	struct cea_channel_speaker_allocation *p;
-
-	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-		p = channel_allocations + i;
-		p->channels = 0;
-		p->spk_mask = 0;
-		for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
-			if (p->speakers[j]) {
-				p->channels++;
-				p->spk_mask |= p->speakers[j];
-			}
-	}
-}
-
-/*
- * The transformation takes two steps:
- *
- *      eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
- *            spk_mask => (channel_allocations[])         => ai->CA
- *
- * TODO: it could select the wrong CA from multiple candidates.
- */
 static int had_channel_allocation(struct snd_intelhad *intelhaddata,
 				  int channels)
 {
-	int i;
-	int ca = 0;
-	int spk_mask = 0;
-
-	/*
-	 * CA defaults to 0 for basic stereo audio
-	 */
-	if (channels <= 2)
-		return 0;
-
-	/*
-	 * expand ELD's speaker allocation mask
-	 *
-	 * ELD tells the speaker mask in a compact(paired) form,
-	 * expand ELD's notions to match the ones used by Audio InfoFrame.
-	 */
-
-	for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
-		if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
-			spk_mask |= eld_speaker_allocation_bits[i];
-	}
+	int ca;
 
-	/* search for the first working match in the CA table */
-	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-		if (channels == channel_allocations[i].channels &&
-		(spk_mask & channel_allocations[i].spk_mask) ==
-				channel_allocations[i].spk_mask) {
-			ca = channel_allocations[i].ca_index;
-			break;
-		}
-	}
+	ca = snd_cea_channel_allocation(intelhaddata->eld[DRM_ELD_SPEAKER] & 0x7f,
+					channels, 0x1f, false);
 
 	dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels);
 
@@ -487,7 +367,7 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
 	/*
 	 * Sink may support more than 8 channels, if eld_high has more than
 	 * one bit set. SOC supports max 8 channels.
-	 * Refer eld_speaker_allocation_bits, for sink speaker allocation
+	 * Refer the CEA ELD speaker allocation mapping for sink allocation.
 	 */
 
 	/* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
@@ -505,24 +385,25 @@ static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
 		}
 	}
 
-	for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
-		if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
-			spk_mask |= eld_speaker_allocation_bits[i];
-	}
+	spk_mask = snd_cea_spk_mask_from_alloc(intelhaddata->eld[DRM_ELD_SPEAKER] &
+						 0x7f);
 
-	for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
-		if (spk_mask == channel_allocations[i].spk_mask) {
-			for (c = 0; c < channel_allocations[i].channels; c++) {
-				chmap->map[c] = spk_to_chmap(
-					channel_allocations[i].speakers[
-						(MAX_SPEAKERS - 1) - c]);
-			}
-			chmap->channels = channel_allocations[i].channels;
+	for (i = 0; i < snd_cea_channel_allocations_count; i++) {
+		const struct snd_cea_channel_speaker_allocation *ca;
+
+		ca = &snd_cea_channel_allocations[i];
+		if (ca->ca_index > 0x1f)
+			continue;
+		if (spk_mask == ca->spk_mask) {
+			for (c = 0; c < ca->channels; c++)
+				chmap->map[c] =
+					spk_to_chmap(ca->speakers[MAX_SPEAKERS - 1 - c]);
+			chmap->channels = ca->channels;
 			intelhaddata->chmap->chmap = chmap;
 			break;
 		}
 	}
-	if (i >= ARRAY_SIZE(channel_allocations))
+	if (i >= snd_cea_channel_allocations_count)
 		kfree(chmap);
 }
 
@@ -1723,7 +1604,6 @@ static int __hdmi_lpe_audio_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	init_channel_allocations();
 
 	card_ctx->num_pipes = pdata->num_pipes;
 	card_ctx->num_ports = single_port ? 1 : pdata->num_ports;
diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h
index 88bf9ef2c491..21cec605a879 100644
--- a/sound/x86/intel_hdmi_audio.h
+++ b/sound/x86/intel_hdmi_audio.h
@@ -44,15 +44,6 @@ enum cea_speaker_placement {
 	LFE = (1 << 10),        /* Low Frequency Effect */
 };
 
-struct cea_channel_speaker_allocation {
-	int ca_index;
-	int speakers[8];
-
-	/* derived values, just for convenience */
-	int channels;
-	int spk_mask;
-};
-
 struct channel_map_table {
 	unsigned char map;              /* ALSA API channel map position */
 	unsigned char cea_slot;         /* CEA slot value */

-- 
2.54.0


  parent reply	other threads:[~2026-06-12  4:53 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-12  4:53 [PATCH RFC 0/4] ALSA: Consolidate CEA channel allocation data Cássio Gabriel
2026-06-12  4:53 ` [PATCH RFC 1/4] ALSA: pcm: Add common CEA channel allocation helpers Cássio Gabriel
2026-06-12  4:53 ` [PATCH RFC 2/4] ALSA: hda: Make CEA channel allocation interfaces const Cássio Gabriel
2026-06-12  4:53 ` [PATCH RFC 3/4] ALSA: hda: Use common CEA channel allocations Cássio Gabriel
2026-06-12  4:53 ` Cássio Gabriel [this message]
2026-06-12  9:13 ` [PATCH RFC 0/4] ALSA: Consolidate CEA channel allocation data Takashi Iwai
2026-06-12 11:44   ` Cássio Gabriel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260612-alsa-cea-channel-allocation-v1-4-b1bcbb6b1051@gmail.com \
    --to=cassiogabrielcontato@gmail.com \
    --cc=jonathanh@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=notify@kernel.org \
    --cc=perex@perex.cz \
    --cc=thierry.reding@kernel.org \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®