Files
LibreELEC.tv/packages/linux/patches/rockchip-old/rockchip-0012-WIP-1000-drm-rockchip-dw-hdmi-add-bridge-and-switch-.patch
Christian Hewitt 16d8875e4f linux: update rockchip-old to Linux 6.16.7
Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
2025-09-22 13:54:39 +00:00

233 lines
7.4 KiB
Diff

From 2dae3de105101f59c449419add1b1b1f04beb69b Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 20 Dec 2019 08:12:42 +0000
Subject: [PATCH 12/59] WIP/1000: drm/rockchip: dw-hdmi: add bridge and switch
to drm_bridge_funcs
Switch the dw-hdmi driver to drm_bridge_funcs by implementing
a new local bridge, connecting it to the dw-hdmi bridge.
Also enable bridge format negotiation by implementing
atomic_get_input_bus_fmts and support for 8-bit RGB 4:4:4.
Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 118 ++++++++++++++------
1 file changed, 81 insertions(+), 37 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index c7841c7d5daf..a50218412fb0 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -5,6 +5,7 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
+#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
@@ -73,6 +74,7 @@ struct rockchip_hdmi_chip_data {
struct rockchip_hdmi {
struct device *dev;
struct regmap *regmap;
+ struct drm_bridge bridge;
struct rockchip_encoder encoder;
const struct rockchip_hdmi_chip_data *chip_data;
const struct dw_hdmi_plat_data *plat_data;
@@ -83,11 +85,9 @@ struct rockchip_hdmi {
struct phy *phy;
};
-static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_encoder *encoder)
+static struct rockchip_hdmi *to_rockchip_hdmi(struct drm_bridge *bridge)
{
- struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder);
-
- return container_of(rkencoder, struct rockchip_hdmi, encoder);
+ return container_of(bridge, struct rockchip_hdmi, bridge);
}
static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
@@ -343,31 +343,21 @@ dw_hdmi_rockchip_mode_valid(struct dw_hdmi *dw_hdmi, void *data,
return MODE_OK;
}
-
-static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
+static void
+dw_hdmi_rockchip_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
-}
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
-static bool
-dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adj_mode)
-{
- return true;
+ clk_set_rate(hdmi->ref_clk, adjusted_mode->clock * 1000);
}
-static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adj_mode)
+static void dw_hdmi_rockchip_bridge_enable(struct drm_bridge *bridge)
{
- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(bridge);
+ struct drm_encoder *encoder = bridge->encoder;
- clk_set_rate(hdmi->ref_clk, adj_mode->clock * 1000);
-}
-
-static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
-{
- struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
u32 val;
int ret;
@@ -394,10 +384,21 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
dev_dbg(hdmi->dev, "vop %s output to hdmi\n", ret ? "LIT" : "BIG");
}
+static bool is_rgb(u32 format)
+{
+ switch (format) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int
-dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
+dw_hdmi_rockchip_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
@@ -407,12 +408,38 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
return 0;
}
-static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
- .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
- .mode_set = dw_hdmi_rockchip_encoder_mode_set,
- .enable = dw_hdmi_rockchip_encoder_enable,
- .disable = dw_hdmi_rockchip_encoder_disable,
- .atomic_check = dw_hdmi_rockchip_encoder_atomic_check,
+static u32 *dw_hdmi_rockchip_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmt;
+
+ *num_input_fmts = 0;
+
+ if (!is_rgb(output_fmt))
+ return NULL;
+
+ input_fmt = kzalloc(sizeof(*input_fmt), GFP_KERNEL);
+ if (!input_fmt)
+ return NULL;
+
+ *num_input_fmts = 1;
+ *input_fmt = output_fmt;
+
+ return input_fmt;
+}
+
+static const struct drm_bridge_funcs dw_hdmi_rockchip_bridge_funcs = {
+ .mode_set = dw_hdmi_rockchip_bridge_mode_set,
+ .enable = dw_hdmi_rockchip_bridge_enable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_get_input_bus_fmts = dw_hdmi_rockchip_get_input_bus_fmts,
+ .atomic_check = dw_hdmi_rockchip_bridge_atomic_check,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
};
static int dw_hdmi_rockchip_genphy_init(struct dw_hdmi *dw_hdmi, void *data,
@@ -616,6 +643,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
struct dw_hdmi_plat_data *plat_data;
const struct of_device_id *match;
struct drm_device *drm = data;
+ struct drm_bridge *next_bridge;
struct drm_encoder *encoder;
struct rockchip_hdmi *hdmi;
int ret;
@@ -685,20 +713,21 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
RK3568_HDMI_SCLIN_MSK));
}
- drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
-
ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
if (ret) {
DRM_DEV_ERROR(hdmi->dev, "Failed to init encoder: %d\n", ret);
goto err_disable_clk;
}
+ hdmi->bridge.funcs = &dw_hdmi_rockchip_bridge_funcs;
+ drm_bridge_attach(encoder, &hdmi->bridge, NULL, 0);
+
platform_set_drvdata(pdev, hdmi);
- hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
+ hdmi->hdmi = dw_hdmi_probe(pdev, plat_data);
/*
- * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
+ * If dw_hdmi_probe() fails we'll never call dw_hdmi_unbind(),
* which would have called the encoder cleanup. Do it manually.
*/
if (IS_ERR(hdmi->hdmi)) {
@@ -706,8 +735,23 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
goto err_bind;
}
+ next_bridge = of_drm_find_bridge(pdev->dev.of_node);
+ if (!next_bridge) {
+ ret = -EPROBE_DEFER;
+ goto err_dw_hdmi_remove;
+ }
+
+ ret = drm_bridge_attach(encoder, next_bridge, &hdmi->bridge, 0);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ DRM_DEV_ERROR(hdmi->dev, "Failed to attach dw-hdmi bridge: %d\n", ret);
+ goto err_dw_hdmi_remove;
+ }
+
return 0;
+err_dw_hdmi_remove:
+ dw_hdmi_remove(hdmi->hdmi);
err_bind:
drm_encoder_cleanup(encoder);
err_disable_clk:
@@ -719,7 +763,7 @@ static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
{
struct rockchip_hdmi *hdmi = dev_get_drvdata(dev);
- dw_hdmi_unbind(hdmi->hdmi);
+ dw_hdmi_remove(hdmi->hdmi);
drm_encoder_cleanup(&hdmi->encoder.encoder);
}
--
2.34.1