[PATCH 08/15] drm/tidss: Add mechanism to detect DPI output
Tomi Valkeinen
tomi.valkeinen at ideasonboard.com
Mon Apr 20 05:54:15 PDT 2026
There are situations where the driver needs to know if the output is
going to the DPI output or not. There is no trivial way to get this
information, as there is no "DPI bridge". We can only find this out in
reverse: check if the output is NOT DPI, and if that is negative, then
it must be DPI.
At the moment we have two non-DPI outputs: DSI and OLDI. DSI always has
"ti,j721e-dsi" DSI bridge connected to the DSI, so we can use that for
checking. OLDI doesn't have a compatible property, but we can check if
the DT node has "oldi-transmitters" node as a parent, and the dss node
itself as a grand-parent.
If the output is not connected to either of the above, it must be DPI.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen at ideasonboard.com>
---
drivers/gpu/drm/tidss/tidss_crtc.c | 10 +++++--
drivers/gpu/drm/tidss/tidss_crtc.h | 4 ++-
drivers/gpu/drm/tidss/tidss_dispc.c | 5 +++-
drivers/gpu/drm/tidss/tidss_dispc.h | 3 +-
drivers/gpu/drm/tidss/tidss_kms.c | 55 ++++++++++++++++++++++++++++++++++++-
5 files changed, 70 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c b/drivers/gpu/drm/tidss/tidss_crtc.c
index a31c21c5f855..dfdf61b01dcd 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.c
+++ b/drivers/gpu/drm/tidss/tidss_crtc.c
@@ -192,7 +192,8 @@ static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
return;
/* Write vp properties to HW if needed. */
- dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false);
+ dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, false,
+ tcrtc->dpi_output);
/* Update plane positions if needed. */
tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false);
@@ -235,7 +236,8 @@ static void tidss_crtc_atomic_enable(struct drm_crtc *crtc,
if (r != 0)
return;
- dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true);
+ dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state, true,
+ tcrtc->dpi_output);
tidss_crtc_position_planes(tidss, crtc, old_state, true);
/* Turn vertical blanking interrupt reporting on. */
@@ -417,7 +419,8 @@ static const struct drm_crtc_funcs tidss_crtc_funcs = {
struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
u32 hw_videoport,
- struct drm_plane *primary)
+ struct drm_plane *primary,
+ bool dpi_output)
{
struct tidss_crtc *tcrtc;
struct drm_crtc *crtc;
@@ -430,6 +433,7 @@ struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
return ERR_PTR(-ENOMEM);
tcrtc->hw_videoport = hw_videoport;
+ tcrtc->dpi_output = dpi_output;
init_completion(&tcrtc->framedone_completion);
crtc = &tcrtc->crtc;
diff --git a/drivers/gpu/drm/tidss/tidss_crtc.h b/drivers/gpu/drm/tidss/tidss_crtc.h
index 040d1205496b..65df220698f6 100644
--- a/drivers/gpu/drm/tidss/tidss_crtc.h
+++ b/drivers/gpu/drm/tidss/tidss_crtc.h
@@ -20,6 +20,7 @@ struct tidss_crtc {
struct drm_crtc crtc;
u32 hw_videoport;
+ bool dpi_output;
struct drm_pending_vblank_event *event;
@@ -44,5 +45,6 @@ void tidss_crtc_error_irq(struct drm_crtc *crtc, u64 irqstatus);
struct tidss_crtc *tidss_crtc_create(struct tidss_device *tidss,
u32 hw_videoport,
- struct drm_plane *primary);
+ struct drm_plane *primary,
+ bool dpi_output);
#endif
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
index 58d5eb033bdb..c21ac3f51720 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
@@ -448,6 +448,7 @@ static const u16 *dispc_common_regmap;
struct dss_vp_data {
u32 *gamma_table;
+ bool dpi_output;
};
struct dispc_device {
@@ -2770,8 +2771,10 @@ static void dispc_vp_set_color_mgmt(struct dispc_device *dispc,
}
void dispc_vp_setup(struct dispc_device *dispc, u32 hw_videoport,
- const struct drm_crtc_state *state, bool newmodeset)
+ const struct drm_crtc_state *state, bool newmodeset,
+ bool dpi_output)
{
+ dispc->vp_data[hw_videoport].dpi_output = dpi_output;
dispc_vp_set_default_color(dispc, hw_videoport, 0);
dispc_vp_set_color_mgmt(dispc, hw_videoport, state, newmodeset);
}
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h b/drivers/gpu/drm/tidss/tidss_dispc.h
index 739d211d0018..6f53d554259c 100644
--- a/drivers/gpu/drm/tidss/tidss_dispc.h
+++ b/drivers/gpu/drm/tidss/tidss_dispc.h
@@ -131,7 +131,8 @@ void dispc_vp_disable_clk(struct dispc_device *dispc, u32 hw_videoport);
int dispc_vp_set_clk_rate(struct dispc_device *dispc, u32 hw_videoport,
unsigned long rate);
void dispc_vp_setup(struct dispc_device *dispc, u32 hw_videoport,
- const struct drm_crtc_state *state, bool newmodeset);
+ const struct drm_crtc_state *state, bool newmodeset,
+ bool dpi_output);
int dispc_runtime_suspend(struct dispc_device *dispc);
int dispc_runtime_resume(struct dispc_device *dispc);
diff --git a/drivers/gpu/drm/tidss/tidss_kms.c b/drivers/gpu/drm/tidss/tidss_kms.c
index 8bb93194e5ac..bc8b10af9a48 100644
--- a/drivers/gpu/drm/tidss/tidss_kms.c
+++ b/drivers/gpu/drm/tidss/tidss_kms.c
@@ -122,6 +122,50 @@ static const struct drm_mode_config_funcs mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
+static const char * const tidss_internal_bridge_compatibles[] = {
+ "ti,j721e-dsi",
+};
+
+/*
+ * Detect whether the bridge is internal to the SoC or not. This is needed
+ * to find out whether we are using DPI output (thus no internal bridge).
+ * We detect this via two means:
+ * - If the bridge's of_node has a compatible, compare to known internal values.
+ * - If the bridge is a grand-child of DSS, and has "oldi-transmitters" parent.
+ */
+static bool tidss_is_bridge_internal(struct tidss_device *tidss,
+ struct drm_bridge *bridge)
+{
+ struct device_node *parent, *grand_parent;
+ struct property *prop;
+ bool is_internal;
+
+ if (WARN_ON(!bridge->of_node))
+ return false;
+
+ prop = of_find_property(bridge->of_node, "compatible", NULL);
+ for (const char *cp = of_prop_next_string(prop, NULL); cp;
+ cp = of_prop_next_string(prop, cp)) {
+ for (unsigned int i = 0;
+ i < ARRAY_SIZE(tidss_internal_bridge_compatibles); ++i) {
+ if (strcmp(cp, tidss_internal_bridge_compatibles[i]) == 0)
+ return true;
+ }
+ }
+
+ parent = of_get_parent(bridge->of_node);
+ grand_parent = of_get_parent(parent);
+
+ is_internal = parent && grand_parent &&
+ tidss->dev->of_node == grand_parent &&
+ of_node_name_eq(parent, "oldi-transmitters");
+
+ of_node_put(grand_parent);
+ of_node_put(parent);
+
+ return is_internal;
+}
+
static int tidss_dispc_modeset_init(struct tidss_device *tidss)
{
struct device *dev = tidss->dev;
@@ -133,6 +177,7 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
u32 hw_videoport;
struct drm_bridge *bridge;
u32 enc_type;
+ bool dpi_output;
};
const struct dispc_features *feat = tidss->feat;
@@ -149,6 +194,7 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
struct drm_panel *panel;
struct drm_bridge *bridge;
u32 enc_type = DRM_MODE_ENCODER_NONE;
+ bool dpi_output;
int ret;
ret = drm_of_find_panel_or_bridge(dev->of_node, i, 0,
@@ -160,6 +206,11 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
return dev_err_probe(dev, ret, "port %d probe failed\n", i);
}
+ if (bridge)
+ dpi_output = !tidss_is_bridge_internal(tidss, bridge);
+ else
+ dpi_output = true;
+
if (panel) {
u32 conn_type;
@@ -199,6 +250,7 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
pipes[num_pipes].hw_videoport = i;
pipes[num_pipes].bridge = bridge;
pipes[num_pipes].enc_type = enc_type;
+ pipes[num_pipes].dpi_output = dpi_output;
num_pipes++;
}
@@ -224,7 +276,8 @@ static int tidss_dispc_modeset_init(struct tidss_device *tidss)
tidss->planes[tidss->num_planes++] = &tplane->plane;
tcrtc = tidss_crtc_create(tidss, pipes[i].hw_videoport,
- &tplane->plane);
+ &tplane->plane,
+ pipes[i].dpi_output);
if (IS_ERR(tcrtc)) {
dev_err(tidss->dev, "crtc create failed\n");
return PTR_ERR(tcrtc);
--
2.43.0
More information about the linux-arm-kernel
mailing list