aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-5.15/950-0715-drm-vc4-Convert-vc4_dsi-to-using-a-bridge-instead-of.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-5.15/950-0715-drm-vc4-Convert-vc4_dsi-to-using-a-bridge-instead-of.patch')
-rw-r--r--target/linux/bcm27xx/patches-5.15/950-0715-drm-vc4-Convert-vc4_dsi-to-using-a-bridge-instead-of.patch264
1 files changed, 264 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.15/950-0715-drm-vc4-Convert-vc4_dsi-to-using-a-bridge-instead-of.patch b/target/linux/bcm27xx/patches-5.15/950-0715-drm-vc4-Convert-vc4_dsi-to-using-a-bridge-instead-of.patch
new file mode 100644
index 0000000000..74cae273f8
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.15/950-0715-drm-vc4-Convert-vc4_dsi-to-using-a-bridge-instead-of.patch
@@ -0,0 +1,264 @@
+From 3e6793632310f9991b75c3095a9795b6a8d1d859 Mon Sep 17 00:00:00 2001
+From: Dave Stevenson <dave.stevenson@raspberrypi.com>
+Date: Wed, 15 Dec 2021 17:57:45 +0000
+Subject: [PATCH] drm/vc4: Convert vc4_dsi to using a bridge instead of
+ encoder.
+
+Remove the encoder functions, and create a bridge attached to
+this dumb encoder which implements the same functionality.
+
+As a bridge has state which an encoder doesn't, we need to
+add the state management functions as well.
+
+As there is no bridge atomic_mode_set, move the initialisation
+code that was in mode_set into _pre_enable.
+The code to actually enable and disable sending video are split
+from the general control into _enable and _disable.
+
+Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
+---
+ drivers/gpu/drm/vc4/vc4_dsi.c | 124 ++++++++++++++++++++++++----------
+ 1 file changed, 90 insertions(+), 34 deletions(-)
+
+--- a/drivers/gpu/drm/vc4/vc4_dsi.c
++++ b/drivers/gpu/drm/vc4/vc4_dsi.c
+@@ -554,6 +554,7 @@ struct vc4_dsi {
+ struct mipi_dsi_host dsi_host;
+ struct drm_encoder *encoder;
+ struct drm_bridge *out_bridge;
++ struct drm_bridge bridge;
+
+ void __iomem *regs;
+
+@@ -655,6 +656,12 @@ to_vc4_dsi_encoder(struct drm_encoder *e
+ return container_of(encoder, struct vc4_dsi_encoder, base.base);
+ }
+
++static inline struct vc4_dsi *
++bridge_to_vc4_dsi(struct drm_bridge *bridge)
++{
++ return container_of(bridge, struct vc4_dsi, bridge);
++}
++
+ static const struct debugfs_reg32 dsi0_regs[] = {
+ VC4_REG32(DSI0_CTRL),
+ VC4_REG32(DSI0_STAT),
+@@ -792,11 +799,21 @@ dsi_esc_timing(u32 ns)
+ return DIV_ROUND_UP(ns, ESC_TIME_NS);
+ }
+
+-static void vc4_dsi_encoder_disable(struct drm_encoder *encoder,
+- struct drm_atomic_state *state)
++static void vc4_dsi_bridge_disable(struct drm_bridge *bridge,
++ struct drm_bridge_state *state)
++{
++ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
++ u32 disp0_ctrl;
++
++ disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
++ disp0_ctrl &= ~DSI_DISP0_ENABLE;
++ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);
++}
++
++static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge,
++ struct drm_bridge_state *state)
+ {
+- struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
+- struct vc4_dsi *dsi = vc4_encoder->dsi;
++ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+ struct device *dev = &dsi->pdev->dev;
+
+ vc4_dsi_ulps(dsi, true);
+@@ -821,12 +838,11 @@ static void vc4_dsi_encoder_disable(stru
+ * higher-than-expected clock rate to the panel, but that's what the
+ * firmware does too.
+ */
+-static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
+- const struct drm_display_mode *mode,
+- struct drm_display_mode *adjusted_mode)
++static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
++ const struct drm_display_mode *mode,
++ struct drm_display_mode *adjusted_mode)
+ {
+- struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
+- struct vc4_dsi *dsi = vc4_encoder->dsi;
++ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
+ struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock);
+ unsigned long parent_rate = clk_get_rate(phy_parent);
+ unsigned long pixel_clock_hz = mode->clock * 1000;
+@@ -858,16 +874,18 @@ static bool vc4_dsi_encoder_mode_fixup(s
+ return true;
+ }
+
+-static void vc4_dsi_encoder_mode_set(struct drm_encoder *encoder,
+- struct drm_crtc_state *crtc_state,
+- struct drm_connector_state *conn_state)
++static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
++ struct drm_bridge_state *old_state)
+ {
+- struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
+- struct vc4_dsi *dsi = vc4_encoder->dsi;
++ struct drm_atomic_state *state = old_state->base.state;
++ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
++ const struct drm_crtc_state *crtc_state;
+ struct device *dev = &dsi->pdev->dev;
+ const struct drm_display_mode *mode;
++ struct drm_connector *connector;
+ bool debug_dump_regs = false;
+ unsigned long hs_clock;
++ struct drm_crtc *crtc;
+ u32 ui_ns;
+ /* Minimum LP state duration in escape clock cycles. */
+ u32 lpx = dsi_esc_timing(60);
+@@ -888,6 +906,14 @@ static void vc4_dsi_encoder_mode_set(str
+ drm_print_regset32(&p, &dsi->regset);
+ }
+
++ /*
++ * Retrieve the CRTC adjusted mode. This requires a little dance to go
++ * from the bridge to the encoder, to the connector and to the CRTC.
++ */
++ connector = drm_atomic_get_new_connector_for_encoder(state,
++ bridge->encoder);
++ crtc = drm_atomic_get_new_connector_state(state, connector)->crtc;
++ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ mode = &crtc_state->adjusted_mode;
+
+ pixel_clock_hz = mode->clock * 1000;
+@@ -1102,14 +1128,6 @@ static void vc4_dsi_encoder_mode_set(str
+ ~DSI_PORT_BIT(PHY_AFEC0_RESET));
+
+ vc4_dsi_ulps(dsi, false);
+-}
+-
+-static void vc4_dsi_encoder_enable(struct drm_encoder *encoder,
+- struct drm_atomic_state *state)
+-{
+- struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder);
+- struct vc4_dsi *dsi = vc4_encoder->dsi;
+- bool debug_dump_regs = false;
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ DSI_PORT_WRITE(DISP0_CTRL,
+@@ -1118,13 +1136,23 @@ static void vc4_dsi_encoder_enable(struc
+ VC4_SET_FIELD(dsi->format, DSI_DISP0_PFORMAT) |
+ VC4_SET_FIELD(DSI_DISP0_LP_STOP_PERFRAME,
+ DSI_DISP0_LP_STOP_CTRL) |
+- DSI_DISP0_ST_END |
+- DSI_DISP0_ENABLE);
++ DSI_DISP0_ST_END);
+ } else {
+ DSI_PORT_WRITE(DISP0_CTRL,
+- DSI_DISP0_COMMAND_MODE |
+- DSI_DISP0_ENABLE);
++ DSI_DISP0_COMMAND_MODE);
+ }
++}
++
++static void vc4_dsi_bridge_enable(struct drm_bridge *bridge,
++ struct drm_bridge_state *old_state)
++{
++ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
++ bool debug_dump_regs = false;
++ u32 disp0_ctrl;
++
++ disp0_ctrl = DSI_PORT_READ(DISP0_CTRL);
++ disp0_ctrl |= DSI_DISP0_ENABLE;
++ DSI_PORT_WRITE(DISP0_CTRL, disp0_ctrl);
+
+ if (debug_dump_regs) {
+ struct drm_printer p = drm_info_printer(&dsi->pdev->dev);
+@@ -1133,6 +1161,16 @@ static void vc4_dsi_encoder_enable(struc
+ }
+ }
+
++static int vc4_dsi_bridge_attach(struct drm_bridge *bridge,
++ enum drm_bridge_attach_flags flags)
++{
++ struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
++
++ /* Attach the panel or bridge to the dsi bridge */
++ return drm_bridge_attach(bridge->encoder, dsi->out_bridge,
++ &dsi->bridge, flags);
++}
++
+ static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+ {
+@@ -1309,6 +1347,7 @@ static int vc4_dsi_host_attach(struct mi
+ struct mipi_dsi_device *device)
+ {
+ struct vc4_dsi *dsi = host_to_dsi(host);
++ int ret;
+
+ dsi->lanes = device->lanes;
+ dsi->channel = device->channel;
+@@ -1343,7 +1382,15 @@ static int vc4_dsi_host_attach(struct mi
+ return 0;
+ }
+
+- return component_add(&dsi->pdev->dev, &vc4_dsi_ops);
++ drm_bridge_add(&dsi->bridge);
++
++ ret = component_add(&dsi->pdev->dev, &vc4_dsi_ops);
++ if (ret) {
++ drm_bridge_remove(&dsi->bridge);
++ return ret;
++ }
++
++ return 0;
+ }
+
+ static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
+@@ -1352,6 +1399,7 @@ static int vc4_dsi_host_detach(struct mi
+ struct vc4_dsi *dsi = host_to_dsi(host);
+
+ component_del(&dsi->pdev->dev, &vc4_dsi_ops);
++ drm_bridge_remove(&dsi->bridge);
+ return 0;
+ }
+
+@@ -1361,11 +1409,16 @@ static const struct mipi_dsi_host_ops vc
+ .transfer = vc4_dsi_host_transfer,
+ };
+
+-static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = {
+- .atomic_disable = vc4_dsi_encoder_disable,
+- .atomic_enable = vc4_dsi_encoder_enable,
+- .mode_fixup = vc4_dsi_encoder_mode_fixup,
+- .atomic_mode_set = vc4_dsi_encoder_mode_set,
++static const struct drm_bridge_funcs vc4_dsi_bridge_funcs = {
++ .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 = vc4_dsi_bridge_pre_enable,
++ .atomic_enable = vc4_dsi_bridge_enable,
++ .atomic_disable = vc4_dsi_bridge_disable,
++ .atomic_post_disable = vc4_dsi_bridge_post_disable,
++ .attach = vc4_dsi_bridge_attach,
++ .mode_fixup = vc4_dsi_bridge_mode_fixup,
+ };
+
+ static const struct vc4_dsi_variant bcm2711_dsi1_variant = {
+@@ -1691,9 +1744,8 @@ static int vc4_dsi_bind(struct device *d
+ goto err_free_dma;
+
+ drm_simple_encoder_init(drm, dsi->encoder, DRM_MODE_ENCODER_DSI);
+- drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
+
+- ret = drm_bridge_attach(dsi->encoder, dsi->out_bridge, NULL, 0);
++ ret = drm_bridge_attach(dsi->encoder, &dsi->bridge, NULL, 0);
+ if (ret) {
+ dev_err(dev, "bridge attach failed: %d\n", ret);
+ goto err_free_dma;
+@@ -1755,6 +1807,10 @@ static int vc4_dsi_dev_probe(struct plat
+ return -ENOMEM;
+ dev_set_drvdata(dev, dsi);
+
++ dsi->bridge.funcs = &vc4_dsi_bridge_funcs;
++ dsi->bridge.of_node = dev->of_node;
++ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
++
+ dsi->pdev = pdev;
+ dsi->dsi_host.ops = &vc4_dsi_host_ops;
+ dsi->dsi_host.dev = dev;