From nobody Tue Dec 16 22:12:46 2025 Received: from mail-lj1-f180.google.com (mail-lj1-f180.google.com [209.85.208.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 19AD5226D0E for ; Wed, 26 Feb 2025 08:59:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740560380; cv=none; b=GdHUN+RlvwQwFDYxfYBkutKTYfcGGTiqHfhEbI8WAa9ps9U2iRBqFJNLUmCZu0euEYDAM0NsHpS/b4E9BBD72IXDWT4o6uTdMtHSpHZTP9mGT99apQSakc3ANl3RBMYSfYbGyr3DCdmEThPYhcdbnq3ZhfGXrWHSOK7jq+oNQes= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740560380; c=relaxed/simple; bh=JWfMAzHKBrvjx8XsFlKCouyCn4qTWY6JSGqPvUIjrF8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QFW39Hj4InXrdZvgpChvKUKvjCQRwJz3JHFRK1/24D7WGPqJhNsKKKwwH/l6J2PbGnqOJHQDLzrnaWxMhGos/qBVZR/xxTl/5R60pionQZOLwglREKRLypWq/SuNVhFgHj2BIseQUjvWWS5ZdfsizN4xdlmWnKFt70RboathWlI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=GOUYR81/; arc=none smtp.client-ip=209.85.208.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="GOUYR81/" Received: by mail-lj1-f180.google.com with SMTP id 38308e7fff4ca-30795988ebeso69062941fa.3 for ; Wed, 26 Feb 2025 00:59:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1740560376; x=1741165176; darn=vger.kernel.org; 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=L5UWZ36HDOSoNzBOvtjypUt2y7Tsh/Ad4uCiZepCnWw=; b=GOUYR81/nfolGm9dbjsx2u1v1wmdSHcWOEvXyJskqht83sUYIqBhw5cGIzVuCbGFdr 6whYMDkOswNizYTV6S58kmoFpnRaJzscFTkcJ31hTpVTG9cINiz4pi5d38EppHHzeHVh IkWC8xaPkV3JXmd6kIzeCcUJF0+4v3qFzYF55NXe+LiW8B08jZojtqbwEascIJjmnR7z sgENpZ3zeX3a3uTnz8IkQyDMetHag+pli3jdwHLxuAsUFp6+79S+n9kASbhks9ShpBsX bW2tK/8yy1d0HEy20LGR6BdCji8k9xUiTZLd3JAq8RGsO3LH1hv8Q9nMD+qgT7q4fUSc nBBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1740560376; x=1741165176; 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=L5UWZ36HDOSoNzBOvtjypUt2y7Tsh/Ad4uCiZepCnWw=; b=sy0YDf8qZdpTDxrWzwEzHI/Pc3UKpYgdn3Cek3rTf+T+dcfwhq8D190vPosxmmK9LH 1QsYysrWU790rfUHqwQ/AFrNLJZEYO3QgFK8gOAgKkqzsu4xLLaak6S3EenFOK3ANJlt UEAUUjbuWp+wxhdlTrXJcEMdk48c3++krGKD+D2zlgjI4Dww/DnLhhkoyXHKuuh2c9Ov eTKnp6fQSnjjI1/gY9nwVzC4ybGBYlhTKcs2Ki4dNkWQaR3MQIBjbo+ynsKvZw4YvtAH Hp+BswOT1agqKPvbHBW97SenW1Uv+w4R6nDKpnCNnEoeWr102LCcK4Z+V4M2wpPXM72z H9dw== X-Forwarded-Encrypted: i=1; AJvYcCUOGA0zmOQC44hDqCMnIjdG/UF0AM1vkP6foi73QKjz0vBUk058JTuWKkpHLQaksmRR0Fyk4sSnyQItb0U=@vger.kernel.org X-Gm-Message-State: AOJu0Yx9TGPJeJuFm7s379muZRKWX1JpEyv1gZ0stRRw/ctUupQhmqvG CGNc644ZUK3eXLUp8E2fZ8NgwQJfY/Wk9fMjuhnAt0oBsKFgYsxUi+RADK/lBtxhb8zhjUcIK8d qWMM= X-Gm-Gg: ASbGncsGZ3zDq4D2u/79deA1MmZNsKS1qz/eFHELnUXduQxCeT8HHdAMFO0qT1Fu2xu JGvNjff/rlwCb5gddQG2+919mmeHG8JIHE7dChikktnV7sqrByWOWXMPRZEOp4ITubiqUkAMTeQ PWfMyLdxo2xjyZBfMwClYc3njsoqx5+OPD81jGXkxiQgCWeXG0WvFVkS8Uhq5XRhmVWnR3zQYCe UU8B1FEC7ab+Bl0Q4S8p2VQ2KWXbxI04KjA//n3ojf7i/y0WbLjJliorL5H5S6Tz4ijzn9jxjzi 0w59FRfeQKprfjzhI6OebLYlDgnjAM3cTA== X-Google-Smtp-Source: AGHT+IHIIJC0Ly6wdNlabD1waCmNI0TuQag3fOGe30xLR7weWWc+i6Q/Ev/C5ClkADg3xiX/HTMYXw== X-Received: by 2002:a2e:8696:0:b0:307:ce2b:ed82 with SMTP id 38308e7fff4ca-30a80c41b6emr38928271fa.22.1740560375891; Wed, 26 Feb 2025 00:59:35 -0800 (PST) Received: from umbar.lan ([192.130.178.90]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-30a819e0c49sm4556641fa.10.2025.02.26.00.59.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Feb 2025 00:59:34 -0800 (PST) From: Dmitry Baryshkov Date: Wed, 26 Feb 2025 10:59:26 +0200 Subject: [PATCH v8 3/7] drm/msm/hdmi: make use of the drm_connector_hdmi framework Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250226-bridge-hdmi-connector-v8-3-340af24b35cc@linaro.org> References: <20250226-bridge-hdmi-connector-v8-0-340af24b35cc@linaro.org> In-Reply-To: <20250226-bridge-hdmi-connector-v8-0-340af24b35cc@linaro.org> To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Rob Clark , Abhinav Kumar , Sean Paul , Marijn Suijten , Simona Vetter , Simona Vetter Cc: dri-devel@lists.freedesktop.org, linux-arm-msm@vger.kernel.org, freedreno@lists.freedesktop.org, linux-kernel@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=20918; i=dmitry.baryshkov@linaro.org; h=from:subject:message-id; bh=JWfMAzHKBrvjx8XsFlKCouyCn4qTWY6JSGqPvUIjrF8=; b=owEBbQGS/pANAwAKAYs8ij4CKSjVAcsmYgBnvtftFP/t/sBn8qsKcLuhAYXMni2WfJ6zfM2c3 stvQnlrvmeJATMEAAEKAB0WIQRMcISVXLJjVvC4lX+LPIo+Aiko1QUCZ77X7QAKCRCLPIo+Aiko 1ceZB/9IlPZpE7DD/4dOZjY2FeJmdc+jPDh0E9HDOZ624ne3cIlIZnWxx5l70HfkEEHuGVL8VUt M5RitMpkKGl/nyAg+kk9s3EXSffvRD43PM2bASowuLyd2nTxJkFCxAFvSmPE8LE7myVJd/begzL zWx5qVgZNe8s6T+yL8uHf8TweUVeo07+yebvAzD9rvcWCW62ZsPox2xh55NJntSo6bnj0bqlMlk blFpRiaGpnnth7qrvf8asSRheamq/SC9WZtw5w9AOaFVHVmu1CnQE+Pz6C86G/oYg8eHyFuNuCZ bnaqS5CZZ9FxRlCkEiMRGyPCQBYaqhhNqiTgZm2XnKGaNG8b X-Developer-Key: i=dmitry.baryshkov@linaro.org; a=openpgp; fpr=8F88381DD5C873E4AE487DA5199BF1243632046A Setup the HDMI connector on the MSM HDMI outputs. Make use of atomic_check hook and of the provided Infoframe infrastructure. Acked-by: Maxime Ripard Reviewed-by: Abhinav Kumar Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/Kconfig | 2 + drivers/gpu/drm/msm/hdmi/hdmi.c | 45 ++------- drivers/gpu/drm/msm/hdmi/hdmi.h | 15 +-- drivers/gpu/drm/msm/hdmi/hdmi_audio.c | 72 ++++---------- drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 175 ++++++++++++++++++++++++-----= ---- 5 files changed, 162 insertions(+), 147 deletions(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 7ec833b6d8292f8cb26cfe5582812f2754cd4d35..974bc7c0ea761147d3326bdce90= 39d6f26f290d0 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -170,6 +170,8 @@ config DRM_MSM_HDMI bool "Enable HDMI support in MSM DRM driver" depends on DRM_MSM default y + select DRM_DISPLAY_HDMI_HELPER + select DRM_DISPLAY_HDMI_STATE_HELPER help Compile in support for the HDMI output MSM DRM driver. It can be a primary or a secondary display on device. Note that this is used diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdm= i.c index 37b3809c6bdd7c35aca6b475cb1f41c0ab4d3e6d..b14205cb9e977edd0d849e0eafe= 9b69c0da594bd 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -12,6 +12,7 @@ =20 #include #include +#include =20 #include #include "hdmi.h" @@ -165,8 +166,6 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi, hdmi->dev =3D dev; hdmi->encoder =3D encoder; =20 - hdmi_audio_infoframe_init(&hdmi->audio.infoframe); - ret =3D msm_hdmi_bridge_init(hdmi); if (ret) { DRM_DEV_ERROR(dev->dev, "failed to create HDMI bridge: %d\n", ret); @@ -254,40 +253,12 @@ static int msm_hdmi_audio_hw_params(struct device *de= v, void *data, struct hdmi_codec_params *params) { struct hdmi *hdmi =3D dev_get_drvdata(dev); - unsigned int chan; - unsigned int channel_allocation =3D 0; unsigned int rate; - unsigned int level_shift =3D 0; /* 0dB */ - bool down_mix =3D false; + int ret; =20 DRM_DEV_DEBUG(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate, params->sample_width, params->cea.channels); =20 - switch (params->cea.channels) { - case 2: - /* FR and FL speakers */ - channel_allocation =3D 0; - chan =3D MSM_HDMI_AUDIO_CHANNEL_2; - break; - case 4: - /* FC, LFE, FR and FL speakers */ - channel_allocation =3D 0x3; - chan =3D MSM_HDMI_AUDIO_CHANNEL_4; - break; - case 6: - /* RR, RL, FC, LFE, FR and FL speakers */ - channel_allocation =3D 0x0B; - chan =3D MSM_HDMI_AUDIO_CHANNEL_6; - break; - case 8: - /* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */ - channel_allocation =3D 0x1F; - chan =3D MSM_HDMI_AUDIO_CHANNEL_8; - break; - default: - return -EINVAL; - } - switch (params->sample_rate) { case 32000: rate =3D HDMI_SAMPLE_RATE_32KHZ; @@ -316,9 +287,12 @@ static int msm_hdmi_audio_hw_params(struct device *dev= , void *data, return -EINVAL; } =20 - msm_hdmi_audio_set_sample_rate(hdmi, rate); - msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation, - level_shift, down_mix); + ret =3D drm_atomic_helper_connector_hdmi_update_audio_infoframe(hdmi->con= nector, + ¶ms->cea); + if (ret) + return ret; + + msm_hdmi_audio_info_setup(hdmi, rate, params->cea.channels); =20 return 0; } @@ -327,7 +301,8 @@ static void msm_hdmi_audio_shutdown(struct device *dev,= void *data) { struct hdmi *hdmi =3D dev_get_drvdata(dev); =20 - msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0); + drm_atomic_helper_connector_hdmi_clear_audio_infoframe(hdmi->connector); + msm_hdmi_audio_disable(hdmi); } =20 static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops =3D { diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdm= i.h index a62d2aedfbb7239d37c826c4f96762f100a2be4a..8faad8440cf70f792da353978b9= 90861b0677ed8 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -24,8 +24,8 @@ struct hdmi_platform_config; =20 struct hdmi_audio { bool enabled; - struct hdmi_audio_infoframe infoframe; int rate; + int channels; }; =20 struct hdmi_hdcp_ctrl; @@ -207,12 +207,6 @@ static inline int msm_hdmi_pll_8998_init(struct platfo= rm_device *pdev) /* * audio: */ -/* Supported HDMI Audio channels and rates */ -#define MSM_HDMI_AUDIO_CHANNEL_2 0 -#define MSM_HDMI_AUDIO_CHANNEL_4 1 -#define MSM_HDMI_AUDIO_CHANNEL_6 2 -#define MSM_HDMI_AUDIO_CHANNEL_8 3 - #define HDMI_SAMPLE_RATE_32KHZ 0 #define HDMI_SAMPLE_RATE_44_1KHZ 1 #define HDMI_SAMPLE_RATE_48KHZ 2 @@ -222,11 +216,8 @@ static inline int msm_hdmi_pll_8998_init(struct platfo= rm_device *pdev) #define HDMI_SAMPLE_RATE_192KHZ 6 =20 int msm_hdmi_audio_update(struct hdmi *hdmi); -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, - uint32_t num_of_channels, uint32_t channel_allocation, - uint32_t level_shift, bool down_mix); -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate); - +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels); +int msm_hdmi_audio_disable(struct hdmi *hdmi); =20 /* * hdmi bridge: diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hd= mi/hdmi_audio.c index 4c2058c4adc1001a12e10f35e88a6d58f3bd2fdc..0b91ed5eabd234ff3bca0c2dfaa= 159dd2e6a9df5 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c @@ -7,9 +7,6 @@ #include #include "hdmi.h" =20 -/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of chann= els: */ -static int nchannels[] =3D { 2, 4, 6, 8 }; - /* Supported HDMI Audio sample rates */ #define MSM_HDMI_SAMPLE_RATE_32KHZ 0 #define MSM_HDMI_SAMPLE_RATE_44_1KHZ 1 @@ -74,16 +71,17 @@ static const struct hdmi_msm_audio_arcs *get_arcs(unsig= ned long int pixclock) int msm_hdmi_audio_update(struct hdmi *hdmi) { struct hdmi_audio *audio =3D &hdmi->audio; - struct hdmi_audio_infoframe *info =3D &audio->infoframe; const struct hdmi_msm_audio_arcs *arcs =3D NULL; bool enabled =3D audio->enabled; uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl; - uint32_t infofrm_ctrl, audio_config; + uint32_t audio_config; + + if (!hdmi->connector->display_info.is_hdmi) + return -EINVAL; + + DBG("audio: enabled=3D%d, channels=3D%d, rate=3D%d", + audio->enabled, audio->channels, audio->rate); =20 - DBG("audio: enabled=3D%d, channels=3D%d, channel_allocation=3D0x%x, " - "level_shift_value=3D%d, downmix_inhibit=3D%d, rate=3D%d", - audio->enabled, info->channels, info->channel_allocation, - info->level_shift_value, info->downmix_inhibit, audio->rate); DBG("video: power_on=3D%d, pixclock=3D%lu", hdmi->power_on, hdmi->pixcloc= k); =20 if (enabled && !(hdmi->power_on && hdmi->pixclock)) { @@ -104,7 +102,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) acr_pkt_ctrl =3D hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL); vbi_pkt_ctrl =3D hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL); aud_pkt_ctrl =3D hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1); - infofrm_ctrl =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); audio_config =3D hdmi_read(hdmi, REG_HDMI_AUDIO_CFG); =20 /* Clear N/CTS selection bits */ @@ -113,7 +110,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) if (enabled) { uint32_t n, cts, multiplier; enum hdmi_acr_cts select; - uint8_t buf[14]; =20 n =3D arcs->lut[audio->rate].n; cts =3D arcs->lut[audio->rate].cts; @@ -155,20 +151,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) HDMI_ACR_1_N(n)); =20 hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2, - COND(info->channels !=3D 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) | + COND(audio->channels !=3D 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) | HDMI_AUDIO_PKT_CTRL2_OVERRIDE); =20 acr_pkt_ctrl |=3D HDMI_ACR_PKT_CTRL_CONT; acr_pkt_ctrl |=3D HDMI_ACR_PKT_CTRL_SEND; =20 - /* configure infoframe: */ - hdmi_audio_infoframe_pack(info, buf, sizeof(buf)); - hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0, - (buf[3] << 0) | (buf[4] << 8) | - (buf[5] << 16) | (buf[6] << 24)); - hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1, - (buf[7] << 0) | (buf[8] << 8)); - hdmi_write(hdmi, REG_HDMI_GC, 0); =20 vbi_pkt_ctrl |=3D HDMI_VBI_PKT_CTRL_GC_ENABLE; @@ -176,11 +164,6 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) =20 aud_pkt_ctrl |=3D HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; =20 - infofrm_ctrl |=3D HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; - infofrm_ctrl |=3D HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; - infofrm_ctrl |=3D HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; - infofrm_ctrl |=3D HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; - audio_config &=3D ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK; audio_config |=3D HDMI_AUDIO_CFG_FIFO_WATERMARK(4); audio_config |=3D HDMI_AUDIO_CFG_ENGINE_ENABLE; @@ -190,17 +173,12 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) vbi_pkt_ctrl &=3D ~HDMI_VBI_PKT_CTRL_GC_ENABLE; vbi_pkt_ctrl &=3D ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME; aud_pkt_ctrl &=3D ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; - infofrm_ctrl &=3D ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; - infofrm_ctrl &=3D ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; - infofrm_ctrl &=3D ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; - infofrm_ctrl &=3D ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; audio_config &=3D ~HDMI_AUDIO_CFG_ENGINE_ENABLE; } =20 hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl); hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl); hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl); - hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl); =20 hdmi_write(hdmi, REG_HDMI_AUD_INT, COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) | @@ -214,41 +192,29 @@ int msm_hdmi_audio_update(struct hdmi *hdmi) return 0; } =20 -int msm_hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, - uint32_t num_of_channels, uint32_t channel_allocation, - uint32_t level_shift, bool down_mix) +int msm_hdmi_audio_info_setup(struct hdmi *hdmi, int rate, int channels) { - struct hdmi_audio *audio; - if (!hdmi) return -ENXIO; =20 - audio =3D &hdmi->audio; - - if (num_of_channels >=3D ARRAY_SIZE(nchannels)) + if ((rate < 0) || (rate >=3D MSM_HDMI_SAMPLE_RATE_MAX)) return -EINVAL; =20 - audio->enabled =3D enabled; - audio->infoframe.channels =3D nchannels[num_of_channels]; - audio->infoframe.channel_allocation =3D channel_allocation; - audio->infoframe.level_shift_value =3D level_shift; - audio->infoframe.downmix_inhibit =3D down_mix; + hdmi->audio.rate =3D rate; + hdmi->audio.channels =3D channels; + hdmi->audio.enabled =3D true; =20 return msm_hdmi_audio_update(hdmi); } =20 -void msm_hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate) +int msm_hdmi_audio_disable(struct hdmi *hdmi) { - struct hdmi_audio *audio; - if (!hdmi) - return; - - audio =3D &hdmi->audio; + return -ENXIO; =20 - if ((rate < 0) || (rate >=3D MSM_HDMI_SAMPLE_RATE_MAX)) - return; + hdmi->audio.rate =3D 0; + hdmi->audio.channels =3D 2; + hdmi->audio.enabled =3D false; =20 - audio->rate =3D rate; - msm_hdmi_audio_update(hdmi); + return msm_hdmi_audio_update(hdmi); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/h= dmi/hdmi_bridge.c index bd94b3a70f0e5e457a88f089b491103a8c09567b..4f8e4ffdb2e058ecf243bb319c1= 2c444cb2e5200 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include =20 #include "msm_kms.h" #include "hdmi.h" @@ -68,23 +70,17 @@ static void power_off(struct drm_bridge *bridge) =20 #define AVI_IFRAME_LINE_NUMBER 1 =20 -static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi) +static int msm_hdmi_config_avi_infoframe(struct hdmi *hdmi, + const u8 *buffer, size_t len) { - struct drm_crtc *crtc =3D hdmi->encoder->crtc; - const struct drm_display_mode *mode =3D &crtc->state->adjusted_mode; - union hdmi_infoframe frame; - u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; + u32 buf[4] =3D {}; u32 val; - int len; + int i; =20 - drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, - hdmi->connector, mode); - - len =3D hdmi_infoframe_pack(&frame, buffer, sizeof(buffer)); - if (len < 0) { + if (len !=3D HDMI_INFOFRAME_SIZE(AVI) || len - 3 > sizeof(buf)) { DRM_DEV_ERROR(&hdmi->pdev->dev, "failed to configure avi infoframe\n"); - return; + return -EINVAL; } =20 /* @@ -93,37 +89,118 @@ static void msm_hdmi_config_avi_infoframe(struct hdmi = *hdmi) * written to the LSB byte of AVI_INFO0 and the version is written to * the third byte from the LSB of AVI_INFO3 */ - hdmi_write(hdmi, REG_HDMI_AVI_INFO(0), + memcpy(buf, &buffer[3], len - 3); + + buf[3] |=3D buffer[1] << 24; + + for (i =3D 0; i < ARRAY_SIZE(buf); i++) + hdmi_write(hdmi, REG_HDMI_AVI_INFO(i), buf[i]); + + val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val |=3D HDMI_INFOFRAME_CTRL0_AVI_SEND | + HDMI_INFOFRAME_CTRL0_AVI_CONT; + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); + + val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val &=3D ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK; + val |=3D HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER); + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); + + return 0; +} + +static int msm_hdmi_config_audio_infoframe(struct hdmi *hdmi, + const u8 *buffer, size_t len) +{ + u32 val; + + if (len !=3D HDMI_INFOFRAME_SIZE(AUDIO)) { + DRM_DEV_ERROR(&hdmi->pdev->dev, + "failed to configure audio infoframe\n"); + return -EINVAL; + } + + hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0, buffer[3] | buffer[4] << 8 | buffer[5] << 16 | buffer[6] << 24); =20 - hdmi_write(hdmi, REG_HDMI_AVI_INFO(1), + hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1, buffer[7] | buffer[8] << 8 | buffer[9] << 16 | buffer[10] << 24); =20 - hdmi_write(hdmi, REG_HDMI_AVI_INFO(2), - buffer[11] | - buffer[12] << 8 | - buffer[13] << 16 | - buffer[14] << 24); + val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val |=3D HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); + + return 0; +} + +static int msm_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type) +{ + struct hdmi_bridge *hdmi_bridge =3D to_hdmi_bridge(bridge); + struct hdmi *hdmi =3D hdmi_bridge->hdmi; + u32 val; + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); + val &=3D ~(HDMI_INFOFRAME_CTRL0_AVI_SEND | + HDMI_INFOFRAME_CTRL0_AVI_CONT); + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); =20 - hdmi_write(hdmi, REG_HDMI_AVI_INFO(3), - buffer[15] | - buffer[16] << 8 | - buffer[1] << 24); + val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val &=3D ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK; + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); =20 - hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, - HDMI_INFOFRAME_CTRL0_AVI_SEND | - HDMI_INFOFRAME_CTRL0_AVI_CONT); + break; =20 - val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); - val &=3D ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK; - val |=3D HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER); - hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); + case HDMI_INFOFRAME_TYPE_AUDIO: + val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); + val &=3D ~(HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE | + HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE); + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, val); + + val =3D hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); + val &=3D ~HDMI_INFOFRAME_CTRL1_AUDIO_INFO_LINE__MASK; + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); + + break; + + default: + drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n",= type); + } + + return 0; +} + +static int msm_hdmi_bridge_write_infoframe(struct drm_bridge *bridge, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len) +{ + struct hdmi_bridge *hdmi_bridge =3D to_hdmi_bridge(bridge); + struct hdmi *hdmi =3D hdmi_bridge->hdmi; + + msm_hdmi_bridge_clear_infoframe(bridge, type); + + switch (type) { + case HDMI_INFOFRAME_TYPE_AVI: + return msm_hdmi_config_avi_infoframe(hdmi, buffer, len); + case HDMI_INFOFRAME_TYPE_AUDIO: + return msm_hdmi_config_audio_infoframe(hdmi, buffer, len); + default: + drm_dbg_driver(hdmi_bridge->base.dev, "Unsupported infoframe type %x\n",= type); + return 0; + } } =20 static void msm_hdmi_set_timings(struct hdmi *hdmi, @@ -147,18 +224,20 @@ static void msm_hdmi_bridge_atomic_pre_enable(struct = drm_bridge *bridge, conn_state =3D drm_atomic_get_new_connector_state(state, connector); crtc_state =3D drm_atomic_get_new_crtc_state(state, conn_state->crtc); =20 + hdmi->pixclock =3D conn_state->hdmi.tmds_char_rate; + msm_hdmi_set_timings(hdmi, &crtc_state->adjusted_mode); =20 if (!hdmi->power_on) { msm_hdmi_phy_resource_enable(phy); msm_hdmi_power_on(bridge); hdmi->power_on =3D true; - if (hdmi->hdmi_mode) { - msm_hdmi_config_avi_infoframe(hdmi); + if (hdmi->hdmi_mode) msm_hdmi_audio_update(hdmi); - } } =20 + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); + msm_hdmi_phy_powerup(phy, hdmi->pixclock); =20 msm_hdmi_set_mode(hdmi, true); @@ -197,8 +276,6 @@ static void msm_hdmi_set_timings(struct hdmi *hdmi, int hstart, hend, vstart, vend; uint32_t frame_ctrl; =20 - hdmi->pixclock =3D mode->clock * 1000; - hstart =3D mode->htotal - mode->hsync_start; hend =3D mode->htotal - mode->hsync_start + mode->hdisplay; =20 @@ -276,18 +353,16 @@ static const struct drm_edid *msm_hdmi_bridge_edid_re= ad(struct drm_bridge *bridg return drm_edid; } =20 -static enum drm_mode_status msm_hdmi_bridge_mode_valid(struct drm_bridge *= bridge, - const struct drm_display_info *info, - const struct drm_display_mode *mode) +static enum drm_mode_status msm_hdmi_bridge_tmds_char_rate_valid(const str= uct drm_bridge *bridge, + const struct drm_display_mode *mode, + unsigned long long tmds_rate) { struct hdmi_bridge *hdmi_bridge =3D to_hdmi_bridge(bridge); struct hdmi *hdmi =3D hdmi_bridge->hdmi; const struct hdmi_platform_config *config =3D hdmi->config; struct msm_drm_private *priv =3D bridge->dev->dev_private; struct msm_kms *kms =3D priv->kms; - long actual, requested; - - requested =3D 1000 * mode->clock; + long actual; =20 /* for mdp5/apq8074, we manage our own pixel clk (as opposed to * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder @@ -295,15 +370,16 @@ static enum drm_mode_status msm_hdmi_bridge_mode_vali= d(struct drm_bridge *bridge */ if (kms->funcs->round_pixclk) actual =3D kms->funcs->round_pixclk(kms, - requested, hdmi_bridge->hdmi->encoder); + tmds_rate, + hdmi_bridge->hdmi->encoder); else if (config->pwr_clk_cnt > 0) - actual =3D clk_round_rate(hdmi->pwr_clks[0], requested); + actual =3D clk_round_rate(hdmi->pwr_clks[0], tmds_rate); else - actual =3D requested; + actual =3D tmds_rate; =20 - DBG("requested=3D%ld, actual=3D%ld", requested, actual); + DBG("requested=3D%lld, actual=3D%ld", tmds_rate, actual); =20 - if (actual !=3D requested) + if (actual !=3D tmds_rate) return MODE_CLOCK_RANGE; =20 return 0; @@ -315,9 +391,11 @@ static const struct drm_bridge_funcs msm_hdmi_bridge_f= uncs =3D { .atomic_reset =3D drm_atomic_helper_bridge_reset, .atomic_pre_enable =3D msm_hdmi_bridge_atomic_pre_enable, .atomic_post_disable =3D msm_hdmi_bridge_atomic_post_disable, - .mode_valid =3D msm_hdmi_bridge_mode_valid, .edid_read =3D msm_hdmi_bridge_edid_read, .detect =3D msm_hdmi_bridge_detect, + .hdmi_tmds_char_rate_valid =3D msm_hdmi_bridge_tmds_char_rate_valid, + .hdmi_clear_infoframe =3D msm_hdmi_bridge_clear_infoframe, + .hdmi_write_infoframe =3D msm_hdmi_bridge_write_infoframe, }; =20 static void @@ -349,8 +427,11 @@ int msm_hdmi_bridge_init(struct hdmi *hdmi) bridge->funcs =3D &msm_hdmi_bridge_funcs; bridge->ddc =3D hdmi->i2c; bridge->type =3D DRM_MODE_CONNECTOR_HDMIA; + bridge->vendor =3D "Qualcomm"; + bridge->product =3D "Snapdragon"; bridge->ops =3D DRM_BRIDGE_OP_HPD | DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_HDMI | DRM_BRIDGE_OP_EDID; =20 ret =3D devm_drm_bridge_add(hdmi->dev->dev, bridge); --=20 2.39.5