From patchwork Fri Oct 9 12:28:49 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vinod Koul X-Patchwork-Id: 7361331 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9D144BEEA4 for ; Fri, 9 Oct 2015 12:36:00 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A5FA6204EB for ; Fri, 9 Oct 2015 12:35:59 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 4BAF620435 for ; Fri, 9 Oct 2015 12:35:58 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 75B2B2669A9; Fri, 9 Oct 2015 14:35:57 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 99299266891; Fri, 9 Oct 2015 14:34:14 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 865A1266887; Fri, 9 Oct 2015 14:34:12 +0200 (CEST) Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by alsa0.perex.cz (Postfix) with ESMTP id CDB51265173 for ; Fri, 9 Oct 2015 14:34:02 +0200 (CEST) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga101.jf.intel.com with ESMTP; 09 Oct 2015 05:33:59 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,657,1437462000"; d="scan'208";a="577291525" Received: from vkoul-mobl.iind.intel.com ([10.252.23.6]) by FMSMGA003.fm.intel.com with ESMTP; 09 Oct 2015 05:29:06 -0700 From: Vinod Koul To: alsa-devel@alsa-project.org Date: Fri, 9 Oct 2015 13:28:49 +0100 Message-Id: <1444393729-19745-5-git-send-email-vinod.koul@intel.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1444393729-19745-1-git-send-email-vinod.koul@intel.com> References: <1444393729-19745-1-git-send-email-vinod.koul@intel.com> Cc: Lars-Peter Clausen , Russell King - ARM Linux , tiwai@suse.de, Arnaud Pouliquen , liam.r.girdwood@linux.intel.com, patches.audio@intel.com, broonie@kernel.org, Yakir Yang , Vinod Koul , "Subhransu S. Prusty" Subject: [alsa-devel] [RFC 4/4] ASoC: hdac_hdmi: Setup and start infoframe X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP From: "Subhransu S. Prusty" Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul --- sound/soc/codecs/hdac_hdmi.c | 133 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 309d84122c72..2aca9ce6f423 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -63,6 +63,39 @@ struct hdac_hdmi_priv { struct hdac_hdmi_dai_pin_map dai_map[3]; }; +struct hdmi_audio_infoframe { + u8 type; /* 0x84 */ + u8 ver; /* 0x01 */ + u8 len; /* 0x0a */ + + u8 checksum; + + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; +}; + +struct dp_audio_infoframe { + u8 type; /* 0x84 */ + u8 len; /* 0x1b */ + u8 ver; /* 0x11 << 2 */ + + u8 CC02_CT47; /* match with HDMI infoframe from this on */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; +}; + +union audio_infoframe { + struct hdmi_audio_infoframe hdmi; + struct dp_audio_infoframe dp; + u8 bytes[0]; +}; + + static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) { struct hdac_device *hdac = container_of(dev, struct hdac_device, dev); @@ -85,6 +118,104 @@ static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, hda_nid_t cvt_ni return 0; } +static void hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, + int packet_index, int byte_index) +{ + int val; + + val = (packet_index << 5) | (byte_index & 0x1f); + + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); +} + +static void hdac_hdmi_write_dip_byte(struct hdac_ext_device *hdac, hda_nid_t pin_nid, + unsigned char val) +{ + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); +} + +static void hdac_hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai) +{ + u8 *bytes = (u8 *)hdmi_ai; + u8 sum = 0; + int i; + + hdmi_ai->checksum = 0; + + for (i = 0; i < sizeof(*hdmi_ai); i++) + sum += bytes[i]; + + hdmi_ai->checksum = -sum; +} + +static void hdac_hdmi_fill_audio_infoframe(struct hdac_ext_device *hdac, + hda_nid_t pin_nid, + u8 *dip, int size) +{ + int i; + + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + for (i = 0; i < size; i++) + hdac_hdmi_write_dip_byte(hdac, pin_nid, dip[i]); +} + +/* + * Enable Audio InfoFrame Transmission + */ +static void hdac_hdmi_start_infoframe_trans(struct hdac_ext_device *hdac, + hda_nid_t pin_nid) +{ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_BEST); +} + +/* + * Disable Audio InfoFrame Transmission + */ +static void hdac_hdmi_stop_infoframe_trans(struct hdac_ext_device *hdac, + hda_nid_t pin_nid) +{ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_DISABLE); +} + +static void hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, + hda_nid_t cvt_nid, hda_nid_t pin_nid) +{ + union audio_infoframe ai; + int ca = 0; /* Default stereo for now */ + int channels = 2; + struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; + + /* setup channel count */ + snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, + AC_VERB_SET_CVT_CHAN_COUNT, channels - 1); + + /* Set up infoframe */ + memset(&ai, 0, sizeof(ai)); + + /* Only HDMI for now */ + hdmi_ai->type = 0x84; + hdmi_ai->ver = 0x01; + hdmi_ai->len = 0x0a; + hdmi_ai->CC02_CT47 = channels - 1; + hdmi_ai->CA = ca; + hdac_hdmi_checksum_audio_infoframe(hdmi_ai); + + /* + * sizeof(ai) is used instead of sizeof(*hdmi_ai) or + * sizeof(*dp_ai) to avoid partial match/update problems when + * the user switches between HDMI/DP monitors. + */ + dev_dbg(&hdac->hdac.dev, "hdmi_pin_setup_infoframe: pin=%d channels=%d ca=0x%02x\n", + pin_nid, channels, ca); + hdac_hdmi_stop_infoframe_trans(hdac, pin_nid); + hdac_hdmi_fill_audio_infoframe(hdac, pin_nid, ai.bytes, sizeof(ai)); + hdac_hdmi_start_infoframe_trans(hdac, pin_nid); +} + static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) { @@ -118,6 +249,8 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", dd->stream_tag, dd->format); + hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt.nid, dai_map->pin.nid); + return hdac_hdmi_setup_stream(hdac, dai_map->cvt.nid, dai_map->pin.nid, dd->stream_tag, dd->format); }