On 2025/6/16 22:41, Dmitry Baryshkov wrote:
On 16/06/2025 17:09, Yongxing Mou wrote:Emm, It may be because the number of MST connectors is not fixed, but rather determined by the number of output ports on the dongle. For example, in a 2-MST case, there are 2 encoders, but there could be four MST connectors if the dongle has four DP output ports. add_connector() creates MST connectors based on the number of outputs on the dongle, rather than the actual number of connected devices.
On 2025/6/11 22:31, Dmitry Baryshkov wrote:
On Wed, Jun 11, 2025 at 08:06:28PM +0800, Yongxing Mou wrote:1.Emm, for my current understanding, if DSC is enabled, the BPP should change and recaculated.
On 2025/6/9 23:44, Dmitry Baryshkov wrote:
On Mon, Jun 09, 2025 at 08:21:48PM +0800, Yongxing Mou wrote:Actually, in this patch series, MST not support DSC. So we just don't
From: Abhinav Kumar <quic_abhinavk@xxxxxxxxxxx>
Add connector abstraction for the DP MST. Each MST encoder
is connected through a DRM bridge to a MST connector and each
MST connector has a DP panel abstraction attached to it.
Signed-off-by: Abhinav Kumar <quic_abhinavk@xxxxxxxxxxx>
Signed-off-by: Yongxing Mou <quic_yongmou@xxxxxxxxxxx>
---
drivers/gpu/drm/msm/dp/dp_mst_drm.c | 515 ++++++++++++++++++++ + + ++++++++++++++
drivers/gpu/drm/msm/dp/dp_mst_drm.h | 3 +
2 files changed, 518 insertions(+)
It generally feels liks 80% of this patch is a generic code. Please
extract generic DP MST connector and push it under drm/display. Other DP
MST drivers should be able to use it.
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/ drm/ msm/dp/dp_mst_drm.c
index a3ea34ae63511db0ac920cbeebe30c4e2320b8c4..489fa46aa518ff1cc5f4769b2153fc5153c4cb41 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -25,8 +25,12 @@
* OF THIS SOFTWARE.
*/
+#include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
#include "dp_mst_drm.h"
+#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 *state;
@@ -79,6 +83,61 @@ static int msm_dp_mst_find_vcpi_slots(struct drm_dp_mst_topology_mgr *mgr, int p
return num_slots;
}
+static int msm_dp_mst_get_mst_pbn_div(struct msm_dp_panel *msm_dp_panel)
+{
+ struct msm_dp_link_info *link_info;
+
+ link_info = &msm_dp_panel->link_info;
+
+ return link_info->rate * link_info->num_lanes / 54000;
+}
+
+static int msm_dp_mst_compute_config(struct drm_atomic_state *state,
+ struct msm_dp_mst *mst, struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ int slots = 0, pbn;
+ struct msm_dp_mst_connector *mst_conn = to_msm_dp_mst_connector(connector);
+ int rc = 0;
+ struct drm_dp_mst_topology_state *mst_state;
+ int pbn_div;
+ struct msm_dp *dp_display = mst->msm_dp;
+ u32 bpp;
+
+ bpp = connector->display_info.bpc * 3;
+
+ pbn = drm_dp_calc_pbn_mode(mode->clock, bpp << 4);
Is this going to change if DSC is in place? Will it bring fractional BPP
here?
consider this scenario.
But you still can answer the question.
[...]
Will it bring fractional BPP here?
That's what I am asking
>>>I'm not entirely sure about this answer. I checked how other drivers call this function, and they all use bpp << 4, so can we assume that this way of calling it is valid?
It is valid. I'm trying to understand the implications and future changes.
Sorry, I didn't mean to skip any questions — I just planned to reply a bit later. Apologies for the confusion.+
+ return msm_dp_display_mode_valid(dp_display, &dp_display- >connector->display_info, mode);
+}
+
+static struct drm_encoder *
+msm_dp_mst_atomic_best_encoder(struct drm_connector *connector, struct drm_atomic_state *state)
Do we need this callback? Don't we have a fixed relationship between
connectors and encoders?
This was left unanswered.
For this question, yes , we don't have the fixed relationship between them. Under the current codes, the Connector selects the available encoder and bridge in order from index 0 to 4 (up to max_streams) when the connector's status changes to 'connected'.
Why? Can we have 1:1 relationship as we do with other bridges?
Maybe we don't need to move to bridge's atomic_check(). Connector's atomic_check() do 2 things: 1.Call drm_dp_atomic_release_time_slots when unplug, 2. Call drm_dp_atomic_find_time_slots and drm_dp_mst_atomic_check when plug in.Emm, the bridge does not implement atomic_check(). All MST-related checks (such as drm_dp_atomic_release_time_slots, drm_dp_mst_atomic_check, or others) are performed in the connector's atomic_check function. I believe this is because both num_slots and pbn are stored in the bridge, and we call this to get the drm_bridge..
+{
+ struct msm_dp_mst_connector *mst_conn = to_msm_dp_mst_connector(connector);
+ struct msm_dp *dp_display = mst_conn->msm_dp;
+ struct msm_dp_mst *mst = dp_display->msm_dp_mst;
+ struct drm_encoder *enc = NULL;
+ struct msm_dp_mst_bridge_state *bridge_state;
+ u32 i;
+ struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state,
+ connector);
+
[...]
+ if (drm_atomic_crtc_needs_modeset(crtc_state)) {
+ if (WARN_ON(!old_conn_state->best_encoder)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ drm_bridge = drm_bridge_chain_get_first_bridge(old_conn_state->best_encoder);
This really looks like this should be a bridge's callback.
And this one
So, please split them into connector and bridge checks, calling them from corresponding hooks. It might be easier to migrate completely to the bridge's atomic_check(). At least it will save us from this clumsy code getting the bridge for the connector.
3 functions need drm_atomic_state, but it seems that drm_bridge_funcs.atomic_check() does not pass in drm_atomic_state.
Actually both 2 actions only occur when need modeset. Maybe we can optimize this function in the following ways: (1) reduce unnecessary references to drm_bridge, especially since bridge_state- >num_slots can replace with payload->time_slots; (2)As your comments, split the function into smaller parts to better reflect the logic.
Emm , just as above reply.. when we need modeset, call drm_dp_atomic_release_time_slots to release payload and then clear bridge_state cached ..
Got it.. this code only do one thing, check and try to release time_slots.. we can try to package it into small functions..
+ if (WARN_ON(!drm_bridge)) {
+ rc = -EINVAL;
+ goto end;
+ }
+ bridge = to_msm_dp_mst_bridge(drm_bridge);
+
+ bridge_state = msm_dp_mst_br_priv_state(state, bridge);
+ if (IS_ERR(bridge_state)) {
+ rc = PTR_ERR(bridge_state);
+ goto end;
+ }
+
+ if (WARN_ON(bridge_state->connector != connector)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ slots = bridge_state->num_slots;
+ if (slots > 0) {
+ rc = drm_dp_atomic_release_time_slots(state,
+ &mst->mst_mgr,
+ mst_conn->mst_port);
+ if (rc) {
+ DRM_ERROR("failed releasing %d vcpi slots %d\n", slots, rc);
+ goto end;
+ }
+ vcpi_released = true;
+ }
+
+ if (!new_conn_state->crtc) {
+ /* for cases where crtc is not disabled the slots are not
+ * freed by drm_dp_atomic_release_time_slots. this results
+ * in subsequent atomic_check failing since internal slots
+ * were freed but not the dp mst mgr's
+ */
+ bridge_state->num_slots = 0;
+ bridge_state->connector = NULL;
+ bridge_state->msm_dp_panel = NULL;
+
+ drm_dbg_dp(dp_display->drm_dev, "clear best encoder: %d\n", bridge->id);
+ }
+ }
This looks like there are several functions fused together. Please
unfuse those into small and neat code blocks.
And this :-D
I still don't understand, why do we need to release time_slots here instead of using MST helpers.
Got it , so maybe drm_crtc_state::enable might more appropriate here..Sorry, I'm still not quite sure where the issue is. Could you please help point it out? Thanks~~
+
+mode_set:
+ if (!new_conn_state->crtc)
+ goto end;
+
+ crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
+
+ if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state- >active) {
Use of crtc_state->active doesn't look correct.
...
Please refer to the documentation for drm_crtc_state::active. The drivers are not supposed to use this field in checks.
Got it. Let me test a few different cases to see if these scenarios occur.Actually not, I haven't encountered it yet. I'm not sure how to trigger it, but it might occur under race conditions? Or we just remove it untill some case it really happen..
+ if (WARN_ON(!new_conn_state->best_encoder)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ drm_bridge = drm_bridge_chain_get_first_bridge(new_conn_state->best_encoder);
+ if (WARN_ON(!drm_bridge)) {
+ rc = -EINVAL;
+ goto end;
+ }
+ bridge = to_msm_dp_mst_bridge(drm_bridge);
+
+ bridge_state = msm_dp_mst_br_priv_state(state, bridge);
+ if (IS_ERR(bridge_state)) {
+ rc = PTR_ERR(bridge_state);
+ goto end;
+ }
+
+ if (WARN_ON(bridge_state->connector != connector)) {
+ rc = -EINVAL;
+ goto end;
+ }
Can all of this actually happen?
...
No. You actually think whether this condition can happen, then keep it if it can (and drop it if it can not happen).