From nobody Sat Sep 21 11:40:21 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DCC53C43217 for ; Fri, 4 Nov 2022 14:14:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231545AbiKDOOu (ORCPT ); Fri, 4 Nov 2022 10:14:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57934 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231689AbiKDOOb (ORCPT ); Fri, 4 Nov 2022 10:14:31 -0400 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFA4227926 for ; Fri, 4 Nov 2022 07:14:23 -0700 (PDT) Received: by mail-wr1-x430.google.com with SMTP id k8so7286859wrh.1 for ; Fri, 04 Nov 2022 07:14:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20210112.gappssmtp.com; s=20210112; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=7j8J0GyRQ+3FBMQUBdmjs2oV8Oh7JyCUOZ1fdQPOAqU=; b=IMJ0/xILZLVnEBkansscKE2Eh+TOqfaPGt6+fS5MoahXAw4xQWsMFptqup5TY0PCAo GZGcCUKP6SWPPT0FSv4pmMx0ylBNC9wV1e4eqo5kQ5LwXXvbnP1JfSShO3Z3bU/eI/PM FZckgLajLIuLcrLT5f9s6QcvxqBeBDwQ088uQjQQ8ocitX3xPwFlKkTvbX829K/hMmGi Q1pdrFIKwAZKSqF95C9egvE+pux2nfW1fYOEAWDcSWs/UIDYG0XEHNCjbffd/UpWvlVf zSfyd8MX20w9V+DVRsQfd9eCJOa7zoZ59SUrI6ZD2mJDJl7bN2QJE3NFyhALdc75JYBu +Dnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7j8J0GyRQ+3FBMQUBdmjs2oV8Oh7JyCUOZ1fdQPOAqU=; b=QouOtS/8XTWgSRV3fA+5xyCb1zZIS8zul47nz9wnjH+6R5BO/8hNGAaa/gPv+Ss1+1 asy0gZRj/hvd6rDafIzU+Q3VSzTJT3ZNtzo42E3UAZzYYfBUaVgoT2tcBmgkkIvaZ7Lq BwnjDPmWbsdkCOjne/jk+SeUCCDvel8Zrjg+wkGKfT9Oot5QhK1RnCRVNfbv5imEyfZ+ 2AVhQnF+tRTqB8aVARVNegWLu2KqJYX4t+POSosHSKH/wS5VHpfdZzAYmgXLNmqAOINX ZNtm0jWqWFaZ0itKaXl0+t7oSOkTujZvZkl9GIOGN4aD1vNae9olghTGS9eEe2tulcGE gtTQ== X-Gm-Message-State: ACrzQf1bdKfTIr/Su7dqjdVhJSff87FMTokRX5dpZ6lPlqEkjIENITWk 8W3EophfhgVyFq/VXbHvojYAaw== X-Google-Smtp-Source: AMsMyM6HXnNdQ/QYpBAAIlY6JikFdXDRR5XgC5IY58zXDJatWjhm7npzfVuwgaj50mUZ3olhGPjZ1Q== X-Received: by 2002:a05:6000:689:b0:236:6c3e:ec88 with SMTP id bo9-20020a056000068900b002366c3eec88mr22263000wrb.346.1667571262227; Fri, 04 Nov 2022 07:14:22 -0700 (PDT) Received: from [127.0.0.1] (2a02-8440-6440-7fff-3074-96af-9642-0003.rev.sfr.net. [2a02:8440:6440:7fff:3074:96af:9642:3]) by smtp.gmail.com with ESMTPSA id bj9-20020a0560001e0900b002365cd93d05sm3594512wrb.102.2022.11.04.07.14.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Nov 2022 07:14:21 -0700 (PDT) From: Guillaume Ranquet Date: Fri, 04 Nov 2022 15:09:54 +0100 Subject: [PATCH v3 08/12] drm/mediatek: hdmi: v2: add audio support MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20220919-v3-8-a803f2660127@baylibre.com> References: <20220919-v3-0-a803f2660127@baylibre.com> In-Reply-To: <20220919-v3-0-a803f2660127@baylibre.com> To: Rob Herring , Chun-Kuang Hu , Chunfeng Yun , Jitao shi , Matthias Brugger , Vinod Koul , CK Hu , Daniel Vetter , David Airlie , Krzysztof Kozlowski , Philipp Zabel , Kishon Vijay Abraham I Cc: Krzysztof Kozlowski , linux-arm-kernel@lists.infradead.org, stuart.lee@mediatek.com, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, AngeloGioacchino Del Regno , linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org, Guillaume Ranquet , mac.shen@mediatek.com, linux-phy@lists.infradead.org X-Mailer: b4 0.11.0-dev Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add HDMI audio support for v2 Signed-off-by: Guillaume Ranquet --- drivers/gpu/drm/mediatek/mtk_hdmi_common.c | 1 + drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c | 2 +- drivers/gpu/drm/mediatek/mtk_hdmi_v2.c | 213 +++++++++++++++++++++++++= ++++ drivers/gpu/drm/mediatek/mtk_hdmi_v2.h | 2 + 4 files changed, 217 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/m= ediatek/mtk_hdmi_common.c index e43c938a9aa5..1ea91f8bb6c7 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c @@ -386,6 +386,7 @@ static const struct mtk_hdmi_conf mtk_hdmi_conf_v2 =3D { .mtk_hdmi_output_init =3D mtk_hdmi_output_init_v2, .mtk_hdmi_clk_disable =3D mtk_hdmi_clk_disable_v2, .mtk_hdmi_clk_enable =3D mtk_hdmi_clk_enable_v2, + .set_hdmi_codec_pdata =3D set_hdmi_codec_pdata_v2, .mtk_hdmi_clock_names =3D mtk_hdmi_clk_names_v2, .num_clocks =3D MTK_HDMIV2_CLK_COUNT, }; diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c b/drivers/gpu/drm/m= ediatek/mtk_hdmi_ddc_v2.c index 61696d255e51..26456802a5c4 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc_v2.c @@ -309,7 +309,7 @@ static int mtk_hdmi_ddc_probe(struct platform_device *p= dev) ddc->regs =3D device_node_to_regmap(hdmi); of_node_put(hdmi); if (IS_ERR(ddc->regs)) - return dev_err_probe(dev, PTR_ERR(ddc->regs), "Unable to get mt8195-hdmi= syscon"); + return dev_err_probe(dev, PTR_ERR(ddc->regs), "Unable to get hdmi syscon= "); =20 ddc->clk =3D devm_clk_get_enabled(dev, "ddc"); if (IS_ERR(ddc->clk)) diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/media= tek/mtk_hdmi_v2.c index e8457429964d..b391b22fa9f5 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c @@ -211,6 +211,26 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdm= i, bool black) mtk_hdmi_mask(hdmi, TOP_VMUTE_CFG1, 0, REG_VMUTE_EN); } =20 +static void mtk_hdmi_hw_aud_mute(struct mtk_hdmi *hdmi) +{ + u32 val; + + val =3D mtk_hdmi_read(hdmi, AIP_CTRL, &val); + + if (val & DSD_EN) + mtk_hdmi_mask(hdmi, AIP_TXCTRL, + DSD_MUTE_DATA | AUD_MUTE_FIFO_EN, + DSD_MUTE_DATA | AUD_MUTE_FIFO_EN); + else + mtk_hdmi_mask(hdmi, AIP_TXCTRL, AUD_MUTE_FIFO_EN, + AUD_MUTE_FIFO_EN); +} + +static void mtk_hdmi_hw_aud_unmute(struct mtk_hdmi *hdmi) +{ + mtk_hdmi_mask(hdmi, AIP_TXCTRL, AUD_MUTE_DIS, AUD_MUTE_FIFO_EN); +} + static void mtk_hdmi_hw_reset(struct mtk_hdmi *hdmi) { mtk_hdmi_mask(hdmi, HDMITX_CONFIG, 0x0, HDMITX_SW_RSTB); @@ -889,6 +909,7 @@ static void mtk_hdmi_audio_reset(struct mtk_hdmi *hdmi,= bool rst) static void mtk_hdmi_aud_output_config(struct mtk_hdmi *hdmi, struct drm_display_mode *display_mode) { + mtk_hdmi_hw_aud_mute(hdmi); mtk_hdmi_aud_enable_packet(hdmi, false); mtk_hdmi_audio_reset(hdmi, true); mtk_hdmi_aip_ctrl_init(hdmi); @@ -901,6 +922,7 @@ static void mtk_hdmi_aud_output_config(struct mtk_hdmi = *hdmi, usleep_range(25, 50); mtk_hdmi_aud_on_off_hw_ncts(hdmi, true); mtk_hdmi_aud_enable_packet(hdmi, true); + mtk_hdmi_hw_aud_unmute(hdmi); } =20 void mtk_hdmi_output_init_v2(struct mtk_hdmi *hdmi) @@ -935,6 +957,28 @@ static void mtk_hdmi_reset_colorspace_setting(struct m= tk_hdmi *hdmi) hdmi->ycc_quantization_range =3D HDMI_YCC_QUANTIZATION_RANGE_LIMITED; } =20 +static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi) +{ + mtk_hdmi_aud_enable_packet(hdmi, true); + hdmi->audio_enable =3D true; +} + +static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi) +{ + mtk_hdmi_aud_enable_packet(hdmi, false); + hdmi->audio_enable =3D false; +} + +static void mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi, + struct hdmi_audio_param *param) +{ + if (!hdmi->audio_enable) + return; + + memcpy(&hdmi->aud_param, param, sizeof(*param)); + mtk_hdmi_aud_output_config(hdmi, &hdmi->mode); +} + static void mtk_hdmi_change_video_resolution(struct mtk_hdmi *hdmi) { bool is_over_340M =3D false; @@ -955,6 +999,7 @@ static void mtk_hdmi_change_video_resolution(struct mtk= _hdmi *hdmi) =20 usleep_range(5, 10); mtk_hdmi_hw_vid_black(hdmi, true); + mtk_hdmi_hw_aud_mute(hdmi); mtk_hdmi_hw_send_av_unmute(hdmi); =20 mtk_hdmi_mask(hdmi, TOP_CFG01, NULL_PKT_VSYNC_HIGH_EN, @@ -1285,6 +1330,7 @@ static void mtk_hdmi_bridge_disable(struct drm_bridge= *bridge, mtk_hdmi_hw_send_av_mute(hdmi); usleep_range(50000, 50050); mtk_hdmi_hw_vid_black(hdmi, true); + mtk_hdmi_hw_aud_mute(hdmi); mtk_hdmi_disable_hdcp_encrypt(hdmi); usleep_range(50000, 50050); =20 @@ -1293,6 +1339,14 @@ static void mtk_hdmi_bridge_disable(struct drm_bridg= e *bridge, hdmi->enabled =3D false; } =20 +static void mtk_hdmi_handle_plugged_change(struct mtk_hdmi *hdmi, bool plu= gged) +{ + mutex_lock(&hdmi->update_plugged_status_lock); + if (hdmi->plugged_cb && hdmi->codec_dev) + hdmi->plugged_cb(hdmi->codec_dev, plugged); + mutex_unlock(&hdmi->update_plugged_status_lock); +} + static void mtk_hdmi_bridge_post_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_state) { @@ -1306,6 +1360,9 @@ static void mtk_hdmi_bridge_post_disable(struct drm_b= ridge *bridge, hdmi->powered =3D false; =20 mtk_hdmi_reset_colorspace_setting(hdmi); + + /* signal the disconnect event to audio codec */ + mtk_hdmi_handle_plugged_change(hdmi, false); } =20 static void mtk_hdmi_bridge_pre_enable(struct drm_bridge *bridge, @@ -1338,6 +1395,10 @@ static void mtk_hdmi_bridge_enable(struct drm_bridge= *bridge, mtk_hdmi_hw_avi_infoframe(hdmi, buffer_avi, sizeof(buffer_avi)); =20 mtk_hdmi_hw_vid_black(hdmi, false); + mtk_hdmi_hw_aud_unmute(hdmi); + + /* signal the connect event to audio codec */ + mtk_hdmi_handle_plugged_change(hdmi, true); =20 hdmi->enabled =3D true; } @@ -1377,3 +1438,155 @@ const struct drm_bridge_funcs mtk_v2_hdmi_bridge_fu= ncs =3D { .get_edid =3D mtk_hdmi_bridge_get_edid, .detect =3D mtk_hdmi_bridge_detect, }; + +static void mtk_hdmi_set_plugged_cb(struct mtk_hdmi *hdmi, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + bool plugged; + + mutex_lock(&hdmi->update_plugged_status_lock); + hdmi->plugged_cb =3D fn; + hdmi->codec_dev =3D codec_dev; + plugged =3D (hdmi->hpd =3D=3D HDMI_PLUG_IN_AND_SINK_POWER_ON) ? true : fa= lse; + mutex_unlock(&hdmi->update_plugged_status_lock); + + mtk_hdmi_handle_plugged_change(hdmi, plugged); +} + +/* + * HDMI audio codec callbacks + */ +static int mtk_hdmi_audio_hook_plugged_cb(struct device *dev, void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (!hdmi) + return -ENODEV; + + mtk_hdmi_set_plugged_cb(hdmi, fn, codec_dev); + return 0; +} + +static int mtk_hdmi_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + struct hdmi_audio_param hdmi_params; + unsigned int chan =3D params->cea.channels; + + if (!hdmi->bridge.encoder) + return -ENODEV; + + switch (chan) { + case 2: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_2_0; + break; + case 4: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_4_0; + break; + case 6: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_5_1; + break; + case 8: + hdmi_params.aud_input_chan_type =3D HDMI_AUD_CHAN_TYPE_7_1; + break; + default: + return -EINVAL; + } + + switch (params->sample_rate) { + case 32000: + case 44100: + case 48000: + case 88200: + case 96000: + case 176400: + case 192000: + break; + default: + return -EINVAL; + } + + switch (daifmt->fmt) { + case HDMI_I2S: + hdmi_params.aud_codec =3D HDMI_AUDIO_CODING_TYPE_PCM; + hdmi_params.aud_sampe_size =3D HDMI_AUDIO_SAMPLE_SIZE_16; + hdmi_params.aud_input_type =3D HDMI_AUD_INPUT_I2S; + hdmi_params.aud_i2s_fmt =3D HDMI_I2S_MODE_I2S_24BIT; + hdmi_params.aud_mclk =3D HDMI_AUD_MCLK_128FS; + break; + default: + return -EINVAL; + } + + memcpy(&hdmi_params.codec_params, params, + sizeof(hdmi_params.codec_params)); + + mtk_hdmi_audio_set_param(hdmi, &hdmi_params); + + return 0; +} + +static int mtk_hdmi_audio_startup(struct device *dev, void *data) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + mtk_hdmi_audio_enable(hdmi); + + return 0; +} + +static void mtk_hdmi_audio_shutdown(struct device *dev, void *data) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + mtk_hdmi_audio_disable(hdmi); +} + +static int mtk_hdmi_audio_mute(struct device *dev, void *data, bool enable, + int direction) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (direction !=3D SNDRV_PCM_STREAM_PLAYBACK) + return 0; + + if (enable) + mtk_hdmi_hw_aud_mute(hdmi); + else + mtk_hdmi_hw_aud_unmute(hdmi); + + return 0; +} + +static int mtk_hdmi_audio_get_eld(struct device *dev, void *data, uint8_t = *buf, + size_t len) +{ + struct mtk_hdmi *hdmi =3D dev_get_drvdata(dev); + + if (hdmi->enabled) + memcpy(buf, hdmi->conn.eld, min(sizeof(hdmi->conn.eld), len)); + else + memset(buf, 0, len); + return 0; +} + +static const struct hdmi_codec_ops mtk_hdmi_audio_codec_ops =3D { + .hw_params =3D mtk_hdmi_audio_hw_params, + .audio_startup =3D mtk_hdmi_audio_startup, + .audio_shutdown =3D mtk_hdmi_audio_shutdown, + .mute_stream =3D mtk_hdmi_audio_mute, + .get_eld =3D mtk_hdmi_audio_get_eld, + .hook_plugged_cb =3D mtk_hdmi_audio_hook_plugged_cb, +}; + +void set_hdmi_codec_pdata_v2(struct hdmi_codec_pdata *codec_data) +{ + codec_data->ops =3D &mtk_hdmi_audio_codec_ops; + codec_data->max_i2s_channels =3D 2; + codec_data->i2s =3D 1; +} diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h b/drivers/gpu/drm/media= tek/mtk_hdmi_v2.h index 53cb62e4389d..8a397f2ad2c6 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.h @@ -9,6 +9,7 @@ =20 #include #include +#include =20 struct mtk_hdmi; =20 @@ -17,6 +18,7 @@ extern const struct drm_bridge_funcs mtk_v2_hdmi_bridge_f= uncs; void mtk_hdmi_output_init_v2(struct mtk_hdmi *hdmi); int mtk_hdmi_clk_enable_v2(struct mtk_hdmi *hdmi); void mtk_hdmi_clk_disable_v2(struct mtk_hdmi *hdmi); +void set_hdmi_codec_pdata_v2(struct hdmi_codec_pdata *codec_data); =20 enum mtk_hdmi_clk_id_v2 { MTK_HDMIV2_HDCP_SEL, --=20 b4 0.11.0-dev