diff options
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.patch | 264 |
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; |