From patchwork Thu Jan 2 21:29:35 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell King X-Patchwork-Id: 3431761 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B0AB99F2E9 for ; Fri, 3 Jan 2014 15:23:08 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 82CA620108 for ; Fri, 3 Jan 2014 15:23:07 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id C919620122 for ; Fri, 3 Jan 2014 15:23:02 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 0C2ECFAAC0; Fri, 3 Jan 2014 07:22:44 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from pandora.arm.linux.org.uk (gw-1.arm.linux.org.uk [78.32.30.217]) by gabe.freedesktop.org (Postfix) with ESMTP id 72B4CFB93D for ; Thu, 2 Jan 2014 13:37:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=arm.linux.org.uk; s=pandora; h=Date:Sender:Message-Id:Subject:Cc:To:From:References:In-Reply-To; bh=Cgmj/wpAqY8C6S1v7zgiVrQBzedDtP7/JIT85SEIJLI=; b=fPyr2BSG0Nk7HTNyyNLjUyV2Udd2jQ/2ucDUCt+zGeTJ5hZ9SOCw813/zZlwe3m0DK5iKls8LP4LdtG5nhXpccnQ2fvA3aSurhuZzcpmEgG4/v9YSI85CuAILtLdbmu2tgfwH26VJoMxVZUZ8TDigImi2NbXZNN8AB5QkUugN7E=; Received: from e0022681537dd.dyn.arm.linux.org.uk ([2002:4e20:1eda:1:222:68ff:fe15:37dd]:46467 helo=rmk-PC.arm.linux.org.uk) by pandora.arm.linux.org.uk with esmtpsa (TLSv1:AES256-SHA:256) (Exim 4.76) (envelope-from ) id 1Vyppg-0004CX-CY; Thu, 02 Jan 2014 21:29:36 +0000 Received: from rmk by rmk-PC.arm.linux.org.uk with local (Exim 4.76) (envelope-from ) id 1Vyppf-0007GW-RY; Thu, 02 Jan 2014 21:29:35 +0000 In-Reply-To: <20140102212528.GD7383@n2100.arm.linux.org.uk> References: <20140102212528.GD7383@n2100.arm.linux.org.uk> From: Russell King To: David Airlie , Greg Kroah-Hartman , Sascha Hauer , Shawn Guo Subject: [PATCH RFC 45/46] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver Message-Id: Date: Thu, 02 Jan 2014 21:29:35 +0000 X-Mailman-Approved-At: Fri, 03 Jan 2014 07:21:56 -0800 Cc: devel@driverdev.osuosl.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Parse the ELD (EDID like data) stored from the HDMI driver to restrict the sample rates and channels which are available to ALSA. This causes the ALSA device to reflect the capabilities of the overall audio path, not just what is supported at the HDMI source interface level. Signed-off-by: Russell King --- drivers/staging/imx-drm/dw-hdmi-audio.c | 50 +++++++++++++++++++++++++++++++ drivers/staging/imx-drm/imx-hdmi.c | 8 +++++ drivers/staging/imx-drm/imx-hdmi.h | 1 + 3 files changed, 59 insertions(+), 0 deletions(-) diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c index 946055d2a975..8f70e6565d22 100644 --- a/drivers/staging/imx-drm/dw-hdmi-audio.c +++ b/drivers/staging/imx-drm/dw-hdmi-audio.c @@ -274,6 +274,55 @@ static struct snd_pcm_hardware dw_hdmi_hw = { .fifo_size = 0, }; +static unsigned rates_mask[] = { + SNDRV_PCM_RATE_32000, + SNDRV_PCM_RATE_44100, + SNDRV_PCM_RATE_48000, + SNDRV_PCM_RATE_88200, + SNDRV_PCM_RATE_96000, + SNDRV_PCM_RATE_176400, + SNDRV_PCM_RATE_192000, +}; + +static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw, struct snd_pcm_runtime *runtime) +{ + uint8_t *sad, *eld = imx_hdmi_get_eld(dw->hdmi); + unsigned eld_ver, mnl, sad_count, rates, rate_mask, i; + unsigned max_channels; + + eld_ver = eld[0] >> 3; + if (eld_ver != 2 && eld_ver != 31) + return; + + mnl = eld[4] & 0x1f; + if (mnl > 16) + return; + + sad_count = eld[5] >> 4; + sad = eld + 20 + mnl; + + /* Start from the basic audio settings */ + max_channels = 2; + rates = 7; + while (sad_count > 0) { + switch (sad[0] & 0x78) { + case 0x08: /* PCM */ + max_channels = max(max_channels, (sad[0] & 7) + 1u); + rates |= sad[1]; + break; + } + sad += 3; + sad_count -= 1; + } + + for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++) + if (rates & 1 << i) + rate_mask |= rates_mask[i]; + + runtime->hw.rates &= rate_mask; + runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels); +} + static int dw_hdmi_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -302,6 +351,7 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream) dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0); runtime->hw = dw_hdmi_hw; + dw_hdmi_parse_eld(dw, runtime); snd_pcm_limit_hw_rates(runtime); return 0; diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index eb196c0862c8..949dd7c25166 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -375,6 +375,12 @@ void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate) } EXPORT_SYMBOL(imx_hdmi_set_sample_rate); +uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi) +{ + return hdmi->connector.eld; +} +EXPORT_SYMBOL(imx_hdmi_get_eld); + /* * this submodule is responsible for the video data synchronization. * for example, for RGB 4:4:4 input, the data map is defined as @@ -1406,6 +1412,8 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector) drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); + /* Store the ELD */ + drm_edid_to_eld(connector, edid); kfree(edid); } else { dev_dbg(hdmi->dev, "failed to get edid\n"); diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h index 8029febdbabe..5baaa9cba943 100644 --- a/drivers/staging/imx-drm/imx-hdmi.h +++ b/drivers/staging/imx-drm/imx-hdmi.h @@ -1032,5 +1032,6 @@ enum { struct imx_hdmi; void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate); +uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi); #endif /* __IMX_HDMI_H__ */