If a panel needs to send DSI commands during initialization, it sets the prepare_prev_first flag, which allows the DSI host to initialize itself before the panel's prepare function is called. To support this, the DSI host must register a bridge and perform the necessary initialization steps in its pre_enable function.
Implement this for the Unisoc DSI driver by moving the initialization code from the encoder callbacks to a bridge and simplify the remaining encoder-related code which no longer needs any callbacks. Signed-off-by: Otto Pflüger <[email protected]> --- drivers/gpu/drm/sprd/Kconfig | 2 + drivers/gpu/drm/sprd/sprd_dsi.c | 143 +++++++++++++++++++++++++--------------- drivers/gpu/drm/sprd/sprd_dsi.h | 4 ++ 3 files changed, 97 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/sprd/Kconfig b/drivers/gpu/drm/sprd/Kconfig index e22b780fe82248296a7153d02269faf8cd63294f..1afcdbf6f0ee3304f2297835241c9bb10d422154 100644 --- a/drivers/gpu/drm/sprd/Kconfig +++ b/drivers/gpu/drm/sprd/Kconfig @@ -2,6 +2,8 @@ config DRM_SPRD tristate "DRM Support for Unisoc SoCs Platform" depends on ARCH_SPRD || COMPILE_TEST depends on DRM && OF + select DRM_BRIDGE_CONNECTOR + select DRM_DISPLAY_HELPER select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_MIPI_DSI diff --git a/drivers/gpu/drm/sprd/sprd_dsi.c b/drivers/gpu/drm/sprd/sprd_dsi.c index 23b0e1dc547a5023ee6ad7d5e1c49e2cec986bf0..43fff12d73f12619da57606a3c4785924e2c1507 100644 --- a/drivers/gpu/drm/sprd/sprd_dsi.c +++ b/drivers/gpu/drm/sprd/sprd_dsi.c @@ -11,8 +11,10 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> +#include <drm/drm_bridge_connector.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_simple_kms_helper.h> #include "sprd_drm.h" #include "sprd_dpu.h" @@ -778,19 +780,53 @@ static void sprd_dphy_fini(struct dsi_context *ctx) dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_RESET_N, RF_PHY_RESET_N); } -static void sprd_dsi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) +static int sprd_dsi_encoder_init(struct sprd_dsi *dsi, + struct device *dev) +{ + struct drm_encoder *encoder = &dsi->encoder; + u32 crtc_mask; + int ret; + + crtc_mask = drm_of_find_possible_crtcs(dsi->drm, dev->of_node); + if (!crtc_mask) { + drm_err(dsi->drm, "failed to find crtc mask\n"); + return -EINVAL; + } + + drm_dbg(dsi->drm, "find possible crtcs: 0x%08x\n", crtc_mask); + + encoder->possible_crtcs = crtc_mask; + ret = drm_simple_encoder_init(dsi->drm, encoder, DRM_MODE_ENCODER_DSI); + if (ret) { + drm_err(dsi->drm, "failed to init dsi encoder\n"); + return ret; + } + + return 0; +} + +static int sprd_dsi_bridge_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, + enum drm_bridge_attach_flags flags) +{ + struct sprd_dsi *dsi = bridge_to_dsi(bridge); + + return drm_bridge_attach(&dsi->encoder, dsi->panel_bridge, + bridge, flags); +} + +static void sprd_dsi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adj_mode) { - struct sprd_dsi *dsi = encoder_to_dsi(encoder); + struct sprd_dsi *dsi = bridge_to_dsi(bridge); drm_display_mode_to_videomode(adj_mode, &dsi->ctx.vm); } -static void sprd_dsi_encoder_enable(struct drm_encoder *encoder) +static void sprd_dsi_bridge_pre_enable(struct drm_bridge *bridge) { - struct sprd_dsi *dsi = encoder_to_dsi(encoder); - struct sprd_dpu *dpu = to_sprd_crtc(encoder->crtc); + struct sprd_dsi *dsi = bridge_to_dsi(bridge); struct dsi_context *ctx = &dsi->ctx; if (ctx->enabled) { @@ -819,15 +855,15 @@ static void sprd_dsi_encoder_enable(struct drm_encoder *encoder) dphy_wait_pll_locked(ctx); } - sprd_dpu_run(dpu); + /* DSI commands cannot be issued unless the DPU is running. */ + sprd_dpu_run(to_sprd_crtc(dsi->encoder.crtc)); ctx->enabled = true; } -static void sprd_dsi_encoder_disable(struct drm_encoder *encoder) +static void sprd_dsi_bridge_post_disable(struct drm_bridge *bridge) { - struct sprd_dsi *dsi = encoder_to_dsi(encoder); - struct sprd_dpu *dpu = to_sprd_crtc(encoder->crtc); + struct sprd_dsi *dsi = bridge_to_dsi(bridge); struct dsi_context *ctx = &dsi->ctx; if (!ctx->enabled) { @@ -835,51 +871,21 @@ static void sprd_dsi_encoder_disable(struct drm_encoder *encoder) return; } - sprd_dpu_stop(dpu); + sprd_dpu_stop(to_sprd_crtc(dsi->encoder.crtc)); + sprd_dphy_fini(ctx); sprd_dsi_fini(ctx); ctx->enabled = false; } -static const struct drm_encoder_helper_funcs sprd_encoder_helper_funcs = { - .mode_set = sprd_dsi_encoder_mode_set, - .enable = sprd_dsi_encoder_enable, - .disable = sprd_dsi_encoder_disable +static const struct drm_bridge_funcs sprd_dsi_bridge_funcs = { + .attach = sprd_dsi_bridge_attach, + .mode_set = sprd_dsi_bridge_mode_set, + .pre_enable = sprd_dsi_bridge_pre_enable, + .post_disable = sprd_dsi_bridge_post_disable, }; -static const struct drm_encoder_funcs sprd_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -static int sprd_dsi_encoder_init(struct sprd_dsi *dsi, - struct device *dev) -{ - struct drm_encoder *encoder = &dsi->encoder; - u32 crtc_mask; - int ret; - - crtc_mask = drm_of_find_possible_crtcs(dsi->drm, dev->of_node); - if (!crtc_mask) { - drm_err(dsi->drm, "failed to find crtc mask\n"); - return -EINVAL; - } - - drm_dbg(dsi->drm, "find possible crtcs: 0x%08x\n", crtc_mask); - - encoder->possible_crtcs = crtc_mask; - ret = drm_encoder_init(dsi->drm, encoder, &sprd_encoder_funcs, - DRM_MODE_ENCODER_DSI, NULL); - if (ret) { - drm_err(dsi->drm, "failed to init dsi encoder\n"); - return ret; - } - - drm_encoder_helper_add(encoder, &sprd_encoder_helper_funcs); - - return 0; -} - static int sprd_dsi_bridge_init(struct sprd_dsi *dsi, struct device *dev) { @@ -889,11 +895,35 @@ static int sprd_dsi_bridge_init(struct sprd_dsi *dsi, if (IS_ERR(dsi->panel_bridge)) return PTR_ERR(dsi->panel_bridge); - ret = drm_bridge_attach(&dsi->encoder, dsi->panel_bridge, NULL, 0); + dsi->bridge.funcs = &sprd_dsi_bridge_funcs; + dsi->bridge.of_node = dev->of_node; + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; + + drm_bridge_add(&dsi->bridge); + + ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) - return ret; + goto err_cleanup; + + dsi->connector = drm_bridge_connector_init(dsi->drm, &dsi->encoder); + if (IS_ERR(dsi->connector)) { + drm_err(dsi->drm, "Unable to create bridge connector\n"); + ret = PTR_ERR(dsi->connector); + goto err_cleanup; + } + + ret = drm_connector_attach_encoder(dsi->connector, &dsi->encoder); + if (ret < 0) + goto err_cleanup; return 0; + +err_cleanup: + drm_bridge_remove(&dsi->bridge); + drm_of_panel_bridge_remove(dev->of_node, 1, 0); + + return ret; } static int sprd_dsi_context_init(struct sprd_dsi *dsi, @@ -940,13 +970,21 @@ static int sprd_dsi_bind(struct device *dev, struct device *master, void *data) ret = sprd_dsi_bridge_init(dsi, dev); if (ret) - return ret; + goto err_cleanup_encoder; ret = sprd_dsi_context_init(dsi, dev); if (ret) - return ret; + goto err_cleanup_bridge; return 0; + +err_cleanup_encoder: + drm_encoder_cleanup(&dsi->encoder); +err_cleanup_bridge: + drm_bridge_remove(&dsi->bridge); + drm_of_panel_bridge_remove(dev->of_node, 1, 0); + + return ret; } static void sprd_dsi_unbind(struct device *dev, @@ -954,6 +992,7 @@ static void sprd_dsi_unbind(struct device *dev, { struct sprd_dsi *dsi = dev_get_drvdata(dev); + drm_bridge_remove(&dsi->bridge); drm_of_panel_bridge_remove(dev->of_node, 1, 0); drm_encoder_cleanup(&dsi->encoder); diff --git a/drivers/gpu/drm/sprd/sprd_dsi.h b/drivers/gpu/drm/sprd/sprd_dsi.h index d858ebb111150546e99403a87bc7cea42cad0158..f18f7398df6fa995df7ec2c59cf5c2745fbd28bd 100644 --- a/drivers/gpu/drm/sprd/sprd_dsi.h +++ b/drivers/gpu/drm/sprd/sprd_dsi.h @@ -18,6 +18,8 @@ #include <drm/drm_print.h> #include <drm/drm_panel.h> +#define bridge_to_dsi(bridge) \ + container_of(bridge, struct sprd_dsi, bridge) #define encoder_to_dsi(encoder) \ container_of(encoder, struct sprd_dsi, encoder) @@ -116,7 +118,9 @@ struct sprd_dsi { struct mipi_dsi_host host; struct mipi_dsi_device *slave; struct drm_encoder encoder; + struct drm_bridge bridge; struct drm_bridge *panel_bridge; + struct drm_connector *connector; struct dsi_context ctx; }; -- 2.50.0
