Linux ARM-MSM sub-architecture
 help / color / mirror / Atom feed
From: Yongxing Mou <yongxing.mou@oss.qualcomm.com>
To: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Cc: Rob Clark <robin.clark@oss.qualcomm.com>,
	Dmitry Baryshkov <lumag@kernel.org>,
	Abhinav Kumar <abhinav.kumar@linux.dev>,
	Jessica Zhang <jessica.zhang@oss.qualcomm.com>,
	Sean Paul <sean@poorly.run>,
	Marijn Suijten <marijn.suijten@somainline.org>,
	David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
	linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org,
	freedreno@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	Abhinav Kumar <quic_abhinavk@quicinc.com>
Subject: Re: [PATCH v3 28/38] drm/msm/dp: add dp_mst_drm to manage DP MST bridge operations
Date: Tue, 7 Apr 2026 15:42:34 +0800	[thread overview]
Message-ID: <cda87928-c2e2-4f75-ade1-5a4ae49c4399@oss.qualcomm.com> (raw)
In-Reply-To: <h22zh2zcgdcv2k3mxc5rslpfd3xnerjfailehtaw3wbtpnisy3@s56vudwvoh4q>



On 8/27/2025 1:36 AM, Dmitry Baryshkov wrote:
> On Mon, Aug 25, 2025 at 10:16:14PM +0800, Yongxing Mou wrote:
>> From: Abhinav Kumar <quic_abhinavk@quicinc.com>
>>
>> Add a new file dp_mst_drm to manage the DP MST bridge operations
>> similar to the dp_drm file which manages the SST bridge operations.
>> Each MST encoder creates one bridge and each bridge is bound to its
>> own dp_panel abstraction to manage the operations of its pipeline.
>>
>> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
>> Signed-off-by: Yongxing Mou <yongxing.mou@oss.qualcomm.com>
>> ---
>>   drivers/gpu/drm/msm/Makefile        |   3 +-
>>   drivers/gpu/drm/msm/dp/dp_display.h |   3 +
>>   drivers/gpu/drm/msm/dp/dp_mst_drm.c | 556 ++++++++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/msm/dp/dp_mst_drm.h |  86 ++++++
>>   4 files changed, 647 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
>> index 0c0dfb25f01b193b10946fae20138caf32cf0ed2..a61fa2637ff317ed4dee715de5d12a7befa987f5 100644
>> --- a/drivers/gpu/drm/msm/Makefile
>> +++ b/drivers/gpu/drm/msm/Makefile
>> @@ -142,7 +142,8 @@ msm-display-$(CONFIG_DRM_MSM_DP)+= dp/dp_aux.o \
>>   	dp/dp_link.o \
>>   	dp/dp_panel.o \
>>   	dp/dp_audio.o \
>> -	dp/dp_utils.o
>> +	dp/dp_utils.o \
>> +	dp/dp_mst_drm.o
>>   
>>   msm-display-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o
>>   
>> diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
>> index d5889b801d190b6f33b180ead898c1e4ebcbf8f3..f958de6244b556df5452a5dbec6899fb79a57193 100644
>> --- a/drivers/gpu/drm/msm/dp/dp_display.h
>> +++ b/drivers/gpu/drm/msm/dp/dp_display.h
>> @@ -7,6 +7,7 @@
>>   #define _DP_DISPLAY_H_
>>   
>>   #include "dp_panel.h"
>> +#include "dp_mst_drm.h"
>>   #include "disp/msm_disp_snapshot.h"
>>   
>>   #define DP_MAX_PIXEL_CLK_KHZ	675000
>> @@ -25,6 +26,8 @@ struct msm_dp {
>>   	bool is_edp;
>>   	bool internal_hpd;
>>   
>> +	struct msm_dp_mst *msm_dp_mst;
>> +
>>   	struct msm_dp_audio *msm_dp_audio;
>>   	bool psr_supported;
>>   };
>> diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..73de29136801ef5f45e0b2d09280fe113021b68c
>> --- /dev/null
>> +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
>> @@ -0,0 +1,556 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
>> + */
>> +
>> +/*
>> + * Copyright © 2014 Red Hat.
> 
> Is it based on? Using the code? C&P?
> 
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and its
>> + * documentation for any purpose is hereby granted without fee, provided that
>> + * the above copyright notice appear in all copies and that both that copyright
>> + * notice and this permission notice appear in supporting documentation, and
>> + * that the name of the copyright holders not be used in advertising or
>> + * publicity pertaining to distribution of the software without specific,
>> + * written prior permission.  The copyright holders make no representations
>> + * about the suitability of this software for any purpose.  It is provided "as
>> + * is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
>> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
>> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
>> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
>> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
>> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
>> + * OF THIS SOFTWARE.
> 
> Why? Anyway, MIT licence would be absorbed into GPL-2.0-only (or it
> should be GPL-2.0-only OR MIT)
> 
>> + */
>> +
>> +#include "dp_mst_drm.h"
>> +
>> +#define to_msm_dp_mst_bridge(x)     container_of((x), struct msm_dp_mst_bridge, base)
>> +#define to_msm_dp_mst_bridge_priv(x) \
> 
> Unused
> 
>> +		container_of((x), struct msm_dp_mst_bridge, obj)
>> +#define to_msm_dp_mst_bridge_state_priv(x) \
> 
> Why is it _priv? There is no 'private' bridge state.
> 
>> +		container_of((x), struct msm_dp_mst_bridge_state, base)
>> +#define to_msm_dp_mst_bridge_state(x) \
>> +		to_msm_dp_mst_bridge_state_priv((x)->obj.state)
>> +#define to_msm_dp_mst_connector(x) \
>> +		container_of((x), struct msm_dp_mst_connector, connector)
>> +
>> +#define DP_MST_CONN_ID(bridge) ((bridge)->connector ? \
>> +		(bridge)->connector->base.id : 0)
>> +
>> +#define MAX_DPCD_TRANSACTION_BYTES 16
>> +
>> +static struct drm_private_state *msm_dp_mst_duplicate_bridge_state(struct drm_private_obj *obj)
>> +{
>> +	struct msm_dp_mst_bridge_state *mst_bridge_state;
>> +
>> +	mst_bridge_state = kmemdup(obj->state, sizeof(*mst_bridge_state), GFP_KERNEL);
>> +	if (!mst_bridge_state)
>> +		return NULL;
>> +
>> +	__drm_atomic_helper_private_obj_duplicate_state(obj, &mst_bridge_state->base);
>> +
>> +	return &mst_bridge_state->base;
>> +}
>> +
>> +static void msm_dp_mst_destroy_bridge_state(struct drm_private_obj *obj,
>> +					    struct drm_private_state *state)
>> +{
>> +	struct msm_dp_mst_bridge_state *mst_bridge_state =
>> +		to_msm_dp_mst_bridge_state_priv(state);
>> +
>> +	kfree(mst_bridge_state);
>> +}
>> +
>> +static const struct drm_private_state_funcs msm_dp_mst_bridge_state_funcs = {
>> +	.atomic_duplicate_state = msm_dp_mst_duplicate_bridge_state,
>> +	.atomic_destroy_state = msm_dp_mst_destroy_bridge_state,
>> +};
>> +
>> +/**
>> + * dp_mst_find_vcpi_slots() - Find VCPI slots for this PBN value
>> + * @mgr: manager to use
>> + * @pbn: payload bandwidth to convert into slots.
>> + *
>> + * Calculate the number of VCPI slots that will be required for the given PBN
>> + * value.
>> + *
>> + * RETURNS:
> 
> Return: foo, abc or def
> 
>> + * The total slots required for this port, or error.
>> + */
>> +static int msm_dp_mst_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, int pbn)
>> +{
>> +	int num_slots;
>> +	struct drm_dp_mst_topology_state *state;
>> +
>> +	state = to_drm_dp_mst_topology_state(mgr->base.state);
>> +	num_slots = DIV_ROUND_UP(pbn, dfixed_trunc(state->pbn_div));
> 
> Don't you get those as payload->time_slots ?
> 
Got it , will delete this.
>> +
>> +	/* max. time slots - one slot for MTP header */
>> +	if (num_slots > 63)
>> +		return -ENOSPC;
>> +	return num_slots;
>> +}
>> +
>> +static void msm_dp_mst_update_timeslots(struct msm_dp_mst *mst,
>> +					 struct msm_dp_mst_bridge *mst_bridge,
>> +					 struct drm_atomic_state *state,
>> +					 struct drm_dp_mst_port *port)
>> +{
>> +	int i;
>> +	struct msm_dp_mst_bridge *msm_dp_bridge;
>> +	struct drm_dp_mst_topology_state *mst_state;
>> +	struct drm_dp_mst_atomic_payload *payload;
>> +	struct msm_dp_mst_bridge_state *mst_bridge_state;
>> +	int prev_start = 0;
>> +	int prev_slots = 0;
>> +
>> +	mst_state = to_drm_dp_mst_topology_state(mst->mst_mgr.base.state);
>> +	payload = drm_atomic_get_mst_payload_state(mst_state, port);
>> +
>> +	if (!payload) {
>> +		DRM_ERROR("mst bridge [%d] update_timeslots failed, null payload\n",
>> +			  mst_bridge->id);
>> +		return;
>> +	}
>> +
>> +	for (i = 0; i < mst->max_streams; i++) {
>> +		msm_dp_bridge = mst->mst_bridge[i];
>> +		if (mst_bridge == msm_dp_bridge) {
>> +			mst_bridge_state = to_msm_dp_mst_bridge_state(msm_dp_bridge);
>> +			/*
>> +			 * When a payload was removed make sure to move any payloads after it
>> +			 * to the left so all payloads are aligned to the left.
>> +			 */
> 
> The comment is not valid anymore, as far as I understand.
> 
>> +			if (payload->vc_start_slot < 0) {
>> +				// cache the payload
>> +				prev_start = mst_bridge_state->start_slot;
>> +				prev_slots = mst_bridge_state->num_slots;
>> +				mst_bridge_state->pbn = 0;
>> +				mst_bridge_state->start_slot = 1;
>> +				mst_bridge_state->num_slots = 0;
>> +				mst_bridge_state->vcpi = 0;
>> +			} else { //add payload
>> +				mst_bridge_state->pbn = payload->pbn;
>> +				mst_bridge_state->start_slot = payload->vc_start_slot;
>> +				mst_bridge_state->num_slots = payload->time_slots;
>> +				mst_bridge_state->vcpi = payload->vcpi;
> 
> I still see a lot of manual slot management here. Can't we use the
> struct drm_dp_mst_atomic_payload directly instead of copying and caching
> everything?
> 
>> +			}
>> +		}
>> +	}
>> +
>> +	// Now commit all the updated payloads
>> +	for (i = 0; i < mst->max_streams; i++) {
>> +		msm_dp_bridge = mst->mst_bridge[i];
>> +
>> +		mst_bridge_state = to_msm_dp_mst_bridge_state(msm_dp_bridge);
>> +		//Shift payloads to the left if there was a removed payload.
>> +		if (payload->vc_start_slot < 0 && mst_bridge_state->start_slot > prev_start)
>> +			mst_bridge_state->start_slot -= prev_slots;
> 
> Well... Don't MST helpers do this already for you? I see corresponding
> part in drm_dp_remove_payload_part2().
> 
Here I wanted to reply together with the comment above.
This code seems to be trying to submit the channel_info for all streams 
in a single commit, which is why some manual management was added.
However, in the next revision I plan to remove this manual handling from 
the bridge state and use the payload directly instead.
And after those been moved... it seems that we don't need bridge_state 
anymore?
>> +
>> +		msm_dp_display_set_stream_info(mst->msm_dp, msm_dp_bridge->msm_dp_panel,
>> +					       msm_dp_bridge->id, mst_bridge_state->start_slot,
>> +					       mst_bridge_state->num_slots,
>> +					       mst_bridge_state->pbn, mst_bridge_state->vcpi);
>> +		drm_dbg_dp(mst->msm_dp->drm_dev,
>> +			   "conn:%d vcpi:%d start_slot:%d num_slots:%d, pbn:%d\n",
>> +			   DP_MST_CONN_ID(msm_dp_bridge), mst_bridge_state->vcpi,
>> +			   mst_bridge_state->start_slot,
>> +			   mst_bridge_state->num_slots, mst_bridge_state->pbn);
>> +	}
>> +}
>> +
>> +static int msm_dp_mst_bridge_pre_enable_part1(struct msm_dp_mst_bridge *dp_bridge,
>> +					       struct drm_atomic_state *state)
>> +{
>> +	struct msm_dp *dp_display = dp_bridge->display;
>> +	struct msm_dp_mst *mst = dp_display->msm_dp_mst;
>> +	struct msm_dp_mst_connector *mst_conn = to_msm_dp_mst_connector(dp_bridge->connector);
>> +	struct drm_dp_mst_port *port = mst_conn->mst_port;
>> +	struct drm_dp_mst_topology_state *mst_state;
>> +	struct drm_dp_mst_atomic_payload *payload;
>> +	struct msm_dp_panel *dp_panel = mst_conn->dp_panel;
>> +	int pbn, slots;
>> +	int rc = 0;
>> +
>> +	mst_state = drm_atomic_get_new_mst_topology_state(state, &mst->mst_mgr);
>> +
>> +	pbn = drm_dp_calc_pbn_mode(dp_panel->msm_dp_mode.drm_mode.clock,
>> +				   (mst_conn->connector.display_info.bpc * 3) << 4);
>> +
>> +	slots = msm_dp_mst_find_vcpi_slots(&mst->mst_mgr, pbn);
> 
> payload->time_slots ?
> 
Got it.
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "conn:%d pbn:%d, slots:%d\n", DP_MST_CONN_ID(dp_bridge),
>> +		   pbn, slots);
>> +
>> +	payload = drm_atomic_get_mst_payload_state(mst_state, port);
>> +	if (!payload || payload->time_slots <= 0) {
>> +		DRM_ERROR("time slots not allocated for conn:%d\n", DP_MST_CONN_ID(dp_bridge));
>> +		rc = -EINVAL;
>> +		return rc;
>> +	}
>> +
>> +	drm_dp_mst_update_slots(mst_state, DP_CAP_ANSI_8B10B);
>> +
>> +	rc = drm_dp_add_payload_part1(&mst->mst_mgr, mst_state, payload);
>> +	if (rc) {
>> +		DRM_ERROR("payload allocation failure for conn:%d\n", DP_MST_CONN_ID(dp_bridge));
>> +		return rc;
>> +	}
>> +
>> +	msm_dp_mst_update_timeslots(mst, dp_bridge, state, port);
>> +
>> +	return rc;
>> +}
>> +
>> +static void _msm_dp_mst_bridge_pre_enable_part2(struct msm_dp_mst_bridge *dp_bridge,
>> +						struct drm_atomic_state *state)
>> +{
>> +	struct msm_dp *dp_display = dp_bridge->display;
>> +	struct msm_dp_mst *mst = dp_display->msm_dp_mst;
>> +	struct msm_dp_mst_connector *mst_conn = to_msm_dp_mst_connector(dp_bridge->connector);
>> +	struct drm_dp_mst_port *port = mst_conn->mst_port;
>> +	struct drm_dp_mst_topology_state *mst_state;
>> +	struct drm_dp_mst_atomic_payload *payload;
>> +
>> +	drm_dp_check_act_status(&mst->mst_mgr);
>> +
>> +	mst_state = to_drm_dp_mst_topology_state(mst->mst_mgr.base.state);
>> +	payload = drm_atomic_get_mst_payload_state(mst_state, port);
>> +
>> +	if (!payload) {
> 
> Kill all defensive coding. If something can not happen, there is no need
> to check for it.
> 
Got it.
>> +		DRM_ERROR("mst bridge [%d] null payload\n", dp_bridge->id);
>> +		return;
>> +	}
>> +
>> +	if (!payload->port) {
>> +		DRM_ERROR("mst bridge [%d] null port\n", dp_bridge->id);
>> +		return;
>> +	}
>> +
>> +	if (!payload->port->connector) {
>> +		DRM_ERROR("mst bridge [%d] part-2 failed, null connector\n",
>> +			  dp_bridge->id);
>> +		return;
>> +	}
>> +
>> +	if (payload->vc_start_slot == -1) {
>> +		DRM_ERROR("mst bridge [%d] part-2 failed, payload alloc part 1 failed\n",
>> +			  dp_bridge->id);
>> +		return;
>> +	}
>> +
>> +	drm_dp_add_payload_part2(&mst->mst_mgr, payload);
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "mst bridge [%d] _pre enable part-2 complete\n",
>> +		   dp_bridge->id);
>> +}
>> +
>> +static void msm_dp_mst_bridge_pre_disable_part1(struct msm_dp_mst_bridge *dp_bridge,
>> +						 struct drm_atomic_state *state)
>> +{
>> +	struct msm_dp *dp_display = dp_bridge->display;
>> +	struct msm_dp_mst *mst = dp_display->msm_dp_mst;
>> +	struct msm_dp_mst_connector *mst_conn = to_msm_dp_mst_connector(dp_bridge->connector);
>> +	struct drm_dp_mst_port *port = mst_conn->mst_port;
>> +	struct drm_dp_mst_topology_state *old_mst_state;
>> +	struct drm_dp_mst_topology_state *new_mst_state;
>> +	const struct drm_dp_mst_atomic_payload *old_payload;
>> +	struct drm_dp_mst_atomic_payload *new_payload;
>> +
>> +	old_mst_state = drm_atomic_get_old_mst_topology_state(state, &mst->mst_mgr);
>> +
>> +	new_mst_state = drm_atomic_get_new_mst_topology_state(state, &mst->mst_mgr);
>> +
>> +	old_payload = drm_atomic_get_mst_payload_state(old_mst_state, port);
>> +	new_payload = drm_atomic_get_mst_payload_state(new_mst_state, port);
>> +
>> +	if (!old_payload || !new_payload) {
>> +		DRM_ERROR("mst bridge [%d] _pre disable part-1 failed, null payload\n",
>> +			  dp_bridge->id);
>> +		return;
>> +	}
>> +
>> +	drm_dp_remove_payload_part1(&mst->mst_mgr, new_mst_state, new_payload);
>> +	drm_dp_remove_payload_part2(&mst->mst_mgr, new_mst_state, old_payload, new_payload);
>> +
>> +	msm_dp_mst_update_timeslots(mst, dp_bridge, state, port);
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "mst bridge [%d] _pre disable part-1 complete\n",
>> +		   dp_bridge->id);
>> +}
>> +
>> +static void msm_dp_mst_bridge_atomic_pre_enable(struct drm_bridge *drm_bridge,
>> +						struct drm_atomic_state *state)
>> +{
>> +	int rc = 0;
>> +	struct msm_dp_mst_bridge *bridge;
>> +	struct msm_dp *dp_display;
>> +	struct msm_dp_mst_bridge_state *mst_bridge_state;
>> +	struct msm_dp_mst *dp_mst;
>> +
>> +	if (!drm_bridge) {
>> +		DRM_ERROR("Invalid params\n");
>> +		return;
>> +	}
>> +
>> +	bridge = to_msm_dp_mst_bridge(drm_bridge);
>> +	mst_bridge_state = to_msm_dp_mst_bridge_state(bridge);
>> +	dp_display = bridge->display;
>> +	dp_mst = dp_display->msm_dp_mst;
>> +
>> +	/* to cover cases of bridge_disable/bridge_enable without modeset */
>> +	bridge->connector = mst_bridge_state->connector;
>> +	bridge->msm_dp_panel = mst_bridge_state->msm_dp_panel;
>> +
>> +	if (!bridge->connector) {
>> +		DRM_ERROR("Invalid connector\n");
>> +		return;
>> +	}
>> +
>> +	mutex_lock(&dp_mst->mst_lock);
>> +	msm_dp_display_atomic_prepare(dp_display);
>> +
>> +	rc = msm_dp_mst_bridge_pre_enable_part1(bridge, state);
>> +	if (rc) {
>> +		DRM_ERROR("[%d] DP display pre-enable failed, rc=%d\n", bridge->id, rc);
>> +		msm_dp_display_unprepare(dp_display);
>> +		mutex_unlock(&dp_mst->mst_lock);
>> +		return;
>> +	}
>> +
>> +	msm_dp_display_enable_helper(dp_display, bridge->msm_dp_panel);
>> +
>> +	_msm_dp_mst_bridge_pre_enable_part2(bridge, state);
>> +
>> +	mutex_unlock(&dp_mst->mst_lock);
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "conn:%d mode:%s fps:%d vcpi:%d slots:%d to %d\n",
>> +		   DP_MST_CONN_ID(bridge), bridge->msm_dp_panel->msm_dp_mode.drm_mode.name,
>> +		   drm_mode_vrefresh(&bridge->msm_dp_panel->msm_dp_mode.drm_mode),
>> +		   mst_bridge_state->vcpi, mst_bridge_state->start_slot,
>> +		   mst_bridge_state->start_slot + mst_bridge_state->num_slots);
>> +}
>> +
>> +static void msm_dp_mst_bridge_atomic_disable(struct drm_bridge *drm_bridge,
>> +					     struct drm_atomic_state *state)
>> +{
>> +	struct msm_dp_mst_bridge *bridge;
>> +	struct msm_dp *dp_display;
>> +	struct msm_dp_mst *mst;
>> +
>> +	if (!drm_bridge) {
>> +		DRM_ERROR("Invalid params\n");
>> +		return;
>> +	}
>> +
>> +	bridge = to_msm_dp_mst_bridge(drm_bridge);
>> +	if (!bridge->connector) {
>> +		DRM_ERROR("Invalid connector\n");
>> +		return;
>> +	}
>> +
>> +	dp_display = bridge->display;
>> +	mst = dp_display->msm_dp_mst;
>> +
>> +	mutex_lock(&mst->mst_lock);
>> +
>> +	msm_dp_mst_bridge_pre_disable_part1(bridge, state);
>> +
>> +	msm_dp_display_disable_helper(dp_display, bridge->msm_dp_panel);
>> +
>> +	drm_dp_check_act_status(&mst->mst_mgr);
>> +
>> +	mutex_unlock(&mst->mst_lock);
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "mst bridge:%d conn:%d disable complete\n", bridge->id,
>> +		   DP_MST_CONN_ID(bridge));
>> +}
>> +
>> +static void msm_dp_mst_bridge_atomic_post_disable(struct drm_bridge *drm_bridge,
>> +						  struct drm_atomic_state *state)
>> +{
>> +	int conn = 0;
>> +	struct msm_dp_mst_bridge *bridge;
>> +	struct msm_dp *dp_display;
>> +	struct msm_dp_mst *mst;
>> +
>> +	if (!drm_bridge) {
>> +		DRM_ERROR("Invalid params\n");
>> +		return;
>> +	}
>> +
>> +	bridge = to_msm_dp_mst_bridge(drm_bridge);
>> +	if (!bridge->connector) {
>> +		DRM_ERROR("Invalid connector\n");
>> +		return;
>> +	}
>> +
>> +	conn = DP_MST_CONN_ID(bridge);
>> +
>> +	dp_display = bridge->display;
>> +	mst = dp_display->msm_dp_mst;
>> +
>> +	mutex_lock(&mst->mst_lock);
>> +
>> +	msm_dp_display_atomic_post_disable_helper(dp_display, bridge->msm_dp_panel);
>> +
>> +	if (!dp_display->mst_active)
>> +		msm_dp_display_unprepare(dp_display);
>> +
>> +	bridge->connector = NULL;
>> +	bridge->msm_dp_panel =  NULL;
>> +
>> +	mutex_unlock(&mst->mst_lock);
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "mst bridge:%d conn:%d post disable complete\n",
>> +		   bridge->id, conn);
>> +}
>> +
>> +static int msm_dp_mst_bridge_atomic_check(struct drm_bridge *drm_bridge,
>> +				struct drm_bridge_state *bridge_state,
>> +				struct drm_crtc_state *crtc_state,
>> +				struct drm_connector_state *conn_state)
>> +{
>> +	struct drm_atomic_state *state = crtc_state->state;
>> +	struct drm_connector *connector = conn_state->connector;
>> +	struct drm_dp_mst_topology_state *mst_state;
>> +	struct msm_dp_mst_connector *mst_conn;
>> +	struct msm_dp *dp_display;
>> +	struct msm_dp_mst *mst;
>> +	int rc = 0, pbn, slots;
>> +	u32 bpp;
>> +
>> +	if (!drm_atomic_crtc_needs_modeset(crtc_state) || !crtc_state->enable) {
>> +		return 0;
>> +	}
>> +
>> +	mst_conn = to_msm_dp_mst_connector(connector);
>> +	dp_display = mst_conn->msm_dp;
>> +	mst = dp_display->msm_dp_mst;
>> +
>> +	bpp = connector->display_info.bpc * 3;
>> +
>> +	if (!bpp)
>> +		bpp = 24;
>> +
>> +	pbn = drm_dp_calc_pbn_mode(crtc_state->mode.clock, bpp << 4);
>> +
>> +	mst_state = to_drm_dp_mst_topology_state(mst->mst_mgr.base.state);
>> +	if (IS_ERR(mst_state))
>> +		return PTR_ERR(mst_state);
>> +
>> +	if (!dfixed_trunc(mst_state->pbn_div)) {
>> +		mst_state->pbn_div =
>> +			drm_dp_get_vc_payload_bw(mst_conn->dp_panel->link_info.rate,
>> +						mst_conn->dp_panel->link_info.num_lanes);
>> +	}
>> +
>> +	slots = drm_dp_atomic_find_time_slots(state, &mst->mst_mgr, mst_conn->mst_port, pbn);
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "add slots, conn:%d pbn:%d slots:%d rc:%d\n",
>> +			connector->base.id, pbn, slots, rc);
>> +
>> +	return 0;
>> +}
>> +
>> +static void msm_dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,
>> +				       const struct drm_display_mode *mode,
>> +				       const struct drm_display_mode *adjusted_mode)
> 
> It's clearly defined as deprecated, not to be used by new drivers. Any
> reason for not following it?
> 
Will delete this.
>> +{
>> +	struct msm_dp_mst_bridge *bridge;
>> +	struct msm_dp_mst_bridge_state *mst_bridge_state;
>> +	struct msm_dp *dp_display;
>> +	struct msm_dp_panel *msm_dp_panel;
>> +
>> +	if (!drm_bridge || !mode || !adjusted_mode) {
> 
> Ugh. No overprotective coding.
> 
Got it.
>> +		DRM_ERROR("Invalid params\n");
>> +		return;
>> +	}
>> +
>> +	bridge = to_msm_dp_mst_bridge(drm_bridge);
>> +
>> +	mst_bridge_state = to_msm_dp_mst_bridge_state(bridge);
>> +	bridge->connector = mst_bridge_state->connector;
>> +	bridge->msm_dp_panel = mst_bridge_state->msm_dp_panel;
> 
> Why? All important functions should have access to bridge state and thus state fields.
> 
>> +
>> +	msm_dp_panel = bridge->msm_dp_panel;
>> +	dp_display = bridge->display;
>> +
>> +	msm_dp_display_mode_set_helper(dp_display, mode, adjusted_mode, bridge->msm_dp_panel);
>> +	msm_dp_panel->pbn = drm_dp_calc_pbn_mode(msm_dp_panel->msm_dp_mode.drm_mode.clock,
>> +							  (msm_dp_panel->msm_dp_mode.bpp << 4));
>> +	drm_dbg_dp(dp_display->drm_dev, "mst bridge:%d conn:%d mode set complete %s\n", bridge->id,
>> +		   DP_MST_CONN_ID(bridge), mode->name);
>> +}
>> +
>> +/* DP MST Bridge APIs */
>> +static const struct drm_bridge_funcs msm_dp_mst_bridge_ops = {
>> +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
>> +	.atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
>> +	.atomic_reset           = drm_atomic_helper_bridge_reset,
>> +	.atomic_pre_enable   = msm_dp_mst_bridge_atomic_pre_enable,
>> +	.atomic_disable      = msm_dp_mst_bridge_atomic_disable,
>> +	.atomic_post_disable = msm_dp_mst_bridge_atomic_post_disable,
>> +	.atomic_check = msm_dp_mst_bridge_atomic_check,
>> +	.mode_set     = msm_dp_mst_bridge_mode_set,
>> +};
>> +
>> +int msm_dp_mst_drm_bridge_init(struct msm_dp *dp_display, struct drm_encoder *encoder)
>> +{
>> +	int rc = 0;
>> +	struct msm_dp_mst_bridge *bridge = NULL;
>> +	struct msm_dp_mst_bridge_state *mst_bridge_state;
>> +	struct drm_device *dev;
>> +	struct msm_dp_mst *mst = dp_display->msm_dp_mst;
>> +	int i;
>> +
>> +	for (i = 0; i < mst->max_streams; i++) {
>> +		if (!mst->mst_bridge[i]->in_use) {
>> +			bridge = mst->mst_bridge[i];
>> +			bridge->encoder = encoder;
>> +			bridge->in_use = true;
>> +			bridge->id = i;
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (i == mst->max_streams) {
>> +		DRM_ERROR("mst supports only %d bridges\n", i);
>> +		rc = -EACCES;
>> +		goto end;
>> +	}
>> +
>> +	dev = dp_display->drm_dev;
>> +	bridge->display = dp_display;
>> +	bridge->base.funcs = &msm_dp_mst_bridge_ops;
>> +	bridge->base.encoder = encoder;
>> +	bridge->base.type = dp_display->connector_type;
>> +	bridge->base.ops = DRM_BRIDGE_OP_MODES;
>> +	drm_bridge_add(&bridge->base);
>> +
>> +	rc = drm_bridge_attach(encoder, &bridge->base, NULL, 0);
>> +	if (rc) {
>> +		DRM_ERROR("failed to attach bridge, rc=%d\n", rc);
>> +		goto end;
>> +	}
>> +
>> +	mst_bridge_state = kzalloc(sizeof(*mst_bridge_state), GFP_KERNEL);
>> +	if (!mst_bridge_state) {
>> +		rc = -ENOMEM;
>> +		goto end;
>> +	}
>> +
>> +	drm_atomic_private_obj_init(dev, &bridge->obj,
>> +				    &mst_bridge_state->base,
>> +				    &msm_dp_mst_bridge_state_funcs);
> 
> Why do you register a separate object if you already have bridge and you
> can use bridge's state?
> 
>> +
>> +	drm_dbg_dp(dp_display->drm_dev, "mst drm bridge init. bridge id:%d\n", i);
>> +
>> +	return 0;
>> +
>> +end:
>> +	return rc;
>> +}
>> diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..d75731ca2e5870377026e8ad1057bdcc5f0d4c78
>> --- /dev/null
>> +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
>> @@ -0,0 +1,86 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
>> + *
>> + * Permission to use, copy, modify, distribute, and sell this software and its
>> + * documentation for any purpose is hereby granted without fee, provided that
>> + * the above copyright notice appear in all copies and that both that copyright
>> + * notice and this permission notice appear in supporting documentation, and
>> + * that the name of the copyright holders not be used in advertising or
>> + * publicity pertaining to distribution of the software without specific,
>> + * written prior permission.  The copyright holders make no representations
>> + * about the suitability of this software for any purpose.  It is provided "as
>> + * is" without express or implied warranty.
>> + *
>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
>> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
>> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
>> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
>> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
>> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
>> + * OF THIS SOFTWARE.
> 
> Please check what you are sending. The SPDX header says GPL-2.0-only,
> while the licence text is MIT. Why?
> 
>> + */
>> +
>> +#ifndef _DP_MST_DRM_H_
>> +#define _DP_MST_DRM_H_
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/errno.h>
>> +#include <linux/version.h>
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_atomic.h>
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_fixed.h>
>> +#include <drm/drm_connector.h>
>> +#include <drm/display/drm_dp_helper.h>
>> +#include <drm/display/drm_dp_mst_helper.h>
> 
> Are all those includes necessary here? Replace them with forward struct
> definitions and move includes to the source file. Only keep those, which
> are actually necessary for the contents of the header.
> 
>> +
>> +#include "dp_panel.h"
>> +#include "dp_display.h"
>> +
>> +struct msm_dp_mst_bridge {
>> +	struct drm_bridge base;
>> +	struct drm_private_obj obj;
>> +	u32 id;
>> +
>> +	bool in_use;
> 
> What does it mean? In use currently for one of outputs?
> 
>> +
>> +	struct msm_dp *display;
>> +	struct drm_encoder *encoder;
>> +
>> +	struct drm_connector *connector;
> 
> Why do you have connector both as a part of the bridge and bridge state?
> 
> Please describe design decisions in the commit mesage or as comments.
> 
Sure will add it in commit message.
>> +	struct msm_dp_panel *msm_dp_panel;
>> +};
>> +
>> +struct msm_dp_mst_bridge_state {
>> +	struct drm_private_state base;
>> +	struct drm_connector *connector;
>> +	struct msm_dp_panel *msm_dp_panel;
>> +
>> +	int vcpi;
>> +	int pbn;
>> +	int num_slots;
>> +	int start_slot;
> 
> I'd definitely prefer to have payload pointer here, if that's also a
> part of the state.
> 
Here if we not need pbn/vcpi/slots/start_slot in bridge state, can we 
delete whole bridge state and move connector/dp_panel to bridge?
>> +};
>> +
>> +struct msm_dp_mst {
>> +	struct drm_dp_mst_topology_mgr mst_mgr;
>> +	struct msm_dp_mst_bridge *mst_bridge[DP_STREAM_MAX];
>> +	struct msm_dp *msm_dp;
>> +	u32 max_streams;
>> +	struct mutex mst_lock;
>> +};
>> +
>> +struct msm_dp_mst_connector {
>> +	struct drm_connector connector;
>> +	struct drm_dp_mst_port *mst_port;
>> +	struct msm_dp *msm_dp;
>> +	struct msm_dp_panel *dp_panel;
>> +};
>> +
>> +int msm_dp_mst_drm_bridge_init(struct msm_dp *dp, struct drm_encoder *encoder);
>> +
>> +#endif /* _DP_MST_DRM_H_ */
>>
>> -- 
>> 2.34.1
>>
> 


  parent reply	other threads:[~2026-04-07  7:42 UTC|newest]

Thread overview: 138+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-25 14:15 [PATCH v3 00/38] drm/msm/dp: Add MST support for MSM chipsets Yongxing Mou
2025-08-25 14:15 ` [PATCH v3 01/38] drm/msm/dp: remove cached drm_edid from panel Yongxing Mou
2025-08-25 16:41   ` Dmitry Baryshkov
2025-09-02  8:42     ` Yongxing Mou
2025-09-02  9:36       ` Dmitry Baryshkov
2025-09-02 10:19         ` Yongxing Mou
2025-09-02 12:34           ` Dmitry Baryshkov
2025-11-25  6:37     ` Yongxing Mou
2025-11-26  0:44       ` Dmitry Baryshkov
2025-08-25 14:15 ` [PATCH v3 02/38] drm/msm/dp: remove dp_display's dp_mode and use dp_panel's instead Yongxing Mou
2025-08-25 16:50   ` Dmitry Baryshkov
2026-03-30  7:51     ` Yongxing Mou
2025-08-25 14:15 ` [PATCH v3 03/38] drm/msm/dp: break up dp_display_enable into two parts Yongxing Mou
2025-08-25 17:13   ` Dmitry Baryshkov
2026-03-30  7:53     ` Yongxing Mou
2025-08-25 14:15 ` [PATCH v3 04/38] drm/msm/dp: re-arrange dp_display_disable() into functional parts Yongxing Mou
2025-08-25 17:25   ` Dmitry Baryshkov
2025-08-25 14:15 ` [PATCH v3 05/38] drm/msm/dp: splite msm_dp_ctrl_config_ctrl() into link parts and stream parts Yongxing Mou
2025-08-25 17:28   ` Dmitry Baryshkov
2026-03-30  9:00     ` Yongxing Mou
2026-03-30 10:33       ` Dmitry Baryshkov
2026-03-30 11:26         ` Yongxing Mou
2025-08-25 14:15 ` [PATCH v3 06/38] drm/msm/dp: extract MISC1_MISC0 configuration into a separate function Yongxing Mou
2025-08-25 17:30   ` Dmitry Baryshkov
2025-08-25 14:15 ` [PATCH v3 07/38] drm/msm/dp: allow dp_ctrl stream APIs to use any panel passed to it Yongxing Mou
2025-08-25 17:32   ` Dmitry Baryshkov
2025-08-25 14:15 ` [PATCH v3 08/38] drm/msm/dp: move the pixel clock control to its own API Yongxing Mou
2025-08-25 17:34   ` Dmitry Baryshkov
2025-08-25 14:15 ` [PATCH v3 09/38] drm/msm/dp: split dp_ctrl_off() into stream and link parts Yongxing Mou
2025-08-25 17:35   ` Dmitry Baryshkov
2025-08-25 14:15 ` [PATCH v3 10/38] drm/msm/dp: make bridge helpers use dp_display to allow re-use Yongxing Mou
2025-08-25 14:15 ` [PATCH v3 11/38] drm/msm/dp: separate dp_display_prepare() into its own API Yongxing Mou
2025-08-25 17:39   ` Dmitry Baryshkov
2026-03-30  9:46     ` Yongxing Mou
2026-03-30 10:33       ` Dmitry Baryshkov
2025-08-25 14:15 ` [PATCH v3 12/38] drm/msm/dp: introduce max_streams for DP controller MST support Yongxing Mou
2025-08-25 17:42   ` Dmitry Baryshkov
2026-03-30  9:57     ` Yongxing Mou
2026-03-30 10:35       ` Dmitry Baryshkov
2026-03-30 11:32         ` Yongxing Mou
2026-03-30 11:42           ` Dmitry Baryshkov
2026-03-30 11:52             ` Yongxing Mou
2025-09-02  9:41   ` Dmitry Baryshkov
2026-03-30  9:59     ` Yongxing Mou
2026-03-30 10:36       ` Dmitry Baryshkov
2026-03-30 11:36         ` Yongxing Mou
2025-08-25 14:15 ` [PATCH v3 13/38] drm/msm/dp: introduce stream_id for each DP panel Yongxing Mou
2025-08-25 17:56   ` Dmitry Baryshkov
2026-03-30 10:00     ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 14/38] drm/msm/dp: Add support for programming p1/p2/p3 register blocks Yongxing Mou
2025-08-25 17:59   ` Dmitry Baryshkov
2026-03-30 10:27     ` Yongxing Mou
2026-03-30 10:39       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 15/38] drm/msm/dp: use stream_id to change offsets in dp_catalog Yongxing Mou
2025-08-25 18:01   ` Dmitry Baryshkov
2026-04-01  6:33     ` Yongxing Mou
2026-04-01 11:26       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 16/38] drm/msm/dp: Add catalog support for 3rd/4th stream MST Yongxing Mou
2025-08-25 20:35   ` Dmitry Baryshkov
2026-04-01  6:40     ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 17/38] drm/msm/dp: add support to send ACT packets for MST Yongxing Mou
2025-08-25 21:10   ` Dmitry Baryshkov
2026-04-01  6:44     ` Yongxing Mou
2026-04-01  6:47       ` Dmitry Baryshkov
2026-04-01  6:55         ` Yongxing Mou
2026-04-01 11:27           ` Dmitry Baryshkov
2026-04-09 11:33             ` Yongxing Mou
2026-04-09 14:08               ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 18/38] drm/msm/dp: Add support to enable MST in mainlink control Yongxing Mou
2025-08-25 21:24   ` Dmitry Baryshkov
2026-04-01  6:46     ` Yongxing Mou
2026-04-01  6:49       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 19/38] drm/msm/dp: no need to update tu calculation for mst Yongxing Mou
2025-08-25 21:25   ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 20/38] drm/msm/dp: Add support for MST channel slot allocation Yongxing Mou
2025-08-25 21:52   ` Dmitry Baryshkov
2026-04-01  7:20     ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 21/38] drm/msm/dp: Add support for sending VCPF packets in DP controller Yongxing Mou
2025-08-26 21:28   ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 22/38] drm/msm/dp: Always program MST_FIFO_CONSTANT_FILL for MST use cases Yongxing Mou
2025-08-25 21:55   ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 23/38] drm/msm/dp: abstract out the dp_display stream helpers to accept a panel Yongxing Mou
2025-08-25 22:18   ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 24/38] drm/msm/dp: replace power_on with active_stream_cnt for dp_display Yongxing Mou
2025-08-25 22:22   ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 25/38] drm/msm/dp: Mark the SST bridge disconnected when mst is active Yongxing Mou
2025-08-25 22:23   ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 26/38] drm/msm/dp: add an API to initialize MST on sink side Yongxing Mou
2025-08-26  9:26   ` Dmitry Baryshkov
2026-04-07  4:19     ` Yongxing Mou
2026-04-09 14:11       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 27/38] drm/msm/dp: add dp_display_get_panel() to initialize DP panel Yongxing Mou
2025-08-26 16:33   ` Dmitry Baryshkov
2026-04-01  9:43     ` Yongxing Mou
2026-04-01 11:29       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 28/38] drm/msm/dp: add dp_mst_drm to manage DP MST bridge operations Yongxing Mou
2025-08-26 17:36   ` Dmitry Baryshkov
2026-04-01  7:07     ` Yongxing Mou
2026-04-01  7:29       ` Dmitry Baryshkov
2026-04-07  7:42     ` Yongxing Mou [this message]
2026-04-09 14:13       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 29/38] drm/msm/dp: add MST atomic check to msm_atomic_check() Yongxing Mou
2025-08-26 17:44   ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 30/38] drm/msm/dp: add connector abstraction for DP MST Yongxing Mou
2025-08-26 18:31   ` Dmitry Baryshkov
2026-04-09  4:01     ` Yongxing Mou
2026-04-09 14:50       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 31/38] drm/msm/dp: add HPD callback for dp MST Yongxing Mou
2025-08-26 18:40   ` Dmitry Baryshkov
2026-03-24 13:04     ` Yongxing Mou
2026-03-24 19:30       ` Dmitry Baryshkov
2026-04-14  9:51         ` Yongxing Mou
2026-04-14 18:43           ` Dmitry Baryshkov
2026-04-15 10:32             ` Yongxing Mou
2026-04-19  0:29               ` Dmitry Baryshkov
2026-05-14  7:12                 ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 32/38] drm/msm/dp: propagate MST state changes to dp mst module Yongxing Mou
2025-08-26 18:43   ` Dmitry Baryshkov
2026-04-07  2:38     ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 33/38] drm/msm: add support for MST non-blocking commits Yongxing Mou
2025-08-26 18:47   ` Dmitry Baryshkov
2026-04-07  2:36     ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 34/38] drm/msm: initialize DRM MST encoders for DP controllers Yongxing Mou
2025-08-26 18:55   ` Dmitry Baryshkov
2026-04-07  2:35     ` Yongxing Mou
2026-04-09 14:50       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 35/38] drm/msm/dp: initialize dp_mst module for each DP MST controller Yongxing Mou
2025-08-26 21:27   ` Dmitry Baryshkov
2026-04-07  2:33     ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 36/38] drm/msm/dpu: use msm_dp_get_mst_intf_id() to get the intf id Yongxing Mou
2025-08-26 23:42   ` Dmitry Baryshkov
2026-04-07  2:32     ` Yongxing Mou
2026-04-09 14:52       ` Dmitry Baryshkov
2025-08-25 14:16 ` [PATCH v3 37/38] drm/msm/dp: fix the intf_type of MST interfaces Yongxing Mou
2025-08-27  1:18   ` Dmitry Baryshkov
2025-11-25  6:47     ` Yongxing Mou
2025-08-25 14:16 ` [PATCH v3 38/38] drm/msm/dp: Add MST stream support for SA8775P DP controller 0 and 1 Yongxing Mou
2025-08-27  1:19   ` Dmitry Baryshkov

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=cda87928-c2e2-4f75-ade1-5a4ae49c4399@oss.qualcomm.com \
    --to=yongxing.mou@oss.qualcomm.com \
    --cc=abhinav.kumar@linux.dev \
    --cc=airlied@gmail.com \
    --cc=dmitry.baryshkov@oss.qualcomm.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=freedreno@lists.freedesktop.org \
    --cc=jessica.zhang@oss.qualcomm.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lumag@kernel.org \
    --cc=marijn.suijten@somainline.org \
    --cc=quic_abhinavk@quicinc.com \
    --cc=robin.clark@oss.qualcomm.com \
    --cc=sean@poorly.run \
    --cc=simona@ffwll.ch \
    /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