drm/amd/display: fix odm pipe management
authorDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Sat, 9 Mar 2019 01:16:45 +0000 (20:16 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 21 Mar 2019 04:39:49 +0000 (23:39 -0500)
There are issues removing surfaces/streams when odm is active.
This is a step to fix that

Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/inc/resource.h

index 13f99b11aaa6f0d2d7156e03e4a2f0c466ce56f3..3c9df3703e46dcb5a6f0f5cd18bbb1c7b760cadb 100644 (file)
@@ -1251,6 +1251,40 @@ bool dc_add_plane_to_context(
        return true;
 }
 
+struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx)
+{
+       struct pipe_ctx *bottom_pipe = pipe_ctx->bottom_pipe;
+
+       /* ODM should only be updated once per otg */
+       if (pipe_ctx->top_pipe)
+               return NULL;
+
+       while (bottom_pipe) {
+               if (bottom_pipe->stream_res.opp != pipe_ctx->stream_res.opp)
+                       break;
+               bottom_pipe = bottom_pipe->bottom_pipe;
+       }
+
+       return bottom_pipe;
+}
+
+static bool dc_res_is_odm_bottom_pipe(struct pipe_ctx *pipe_ctx)
+{
+       struct pipe_ctx *top_pipe = pipe_ctx->top_pipe;
+       bool result = false;
+
+       if (top_pipe && top_pipe->stream_res.opp == pipe_ctx->stream_res.opp)
+               return false;
+
+       while (top_pipe) {
+               if (!top_pipe->top_pipe && top_pipe->stream_res.opp != pipe_ctx->stream_res.opp)
+                       result = true;
+               top_pipe = top_pipe->top_pipe;
+       }
+
+       return result;
+}
+
 bool dc_remove_plane_from_context(
                const struct dc *dc,
                struct dc_stream_state *stream,
@@ -1274,10 +1308,14 @@ bool dc_remove_plane_from_context(
 
        /* release pipe for plane*/
        for (i = pool->pipe_count - 1; i >= 0; i--) {
-               struct pipe_ctx *pipe_ctx;
+               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
 
-               if (context->res_ctx.pipe_ctx[i].plane_state == plane_state) {
-                       pipe_ctx = &context->res_ctx.pipe_ctx[i];
+               if (pipe_ctx->plane_state == plane_state) {
+                       if (dc_res_is_odm_bottom_pipe(pipe_ctx)) {
+                               pipe_ctx->plane_state = NULL;
+                               pipe_ctx->bottom_pipe = NULL;
+                               continue;
+                       }
 
                        if (pipe_ctx->top_pipe)
                                pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
@@ -1293,11 +1331,10 @@ bool dc_remove_plane_from_context(
                         * For head pipe detach surfaces from pipe for tail
                         * pipe just zero it out
                         */
-                       if (!pipe_ctx->top_pipe || (!pipe_ctx->top_pipe->top_pipe &&
-                                       pipe_ctx->top_pipe->stream_res.opp != pipe_ctx->stream_res.opp)) {
-                               pipe_ctx->top_pipe = NULL;
+                       if (!pipe_ctx->top_pipe) {
                                pipe_ctx->plane_state = NULL;
-                               pipe_ctx->bottom_pipe = NULL;
+                               if (!dc_res_get_odm_bottom_pipe(pipe_ctx))
+                                       pipe_ctx->bottom_pipe = NULL;
                        } else {
                                memset(pipe_ctx, 0, sizeof(*pipe_ctx));
                        }
@@ -1703,6 +1740,9 @@ enum dc_status dc_remove_stream_from_ctx(
        for (i = 0; i < MAX_PIPES; i++) {
                if (new_ctx->res_ctx.pipe_ctx[i].stream == stream &&
                                !new_ctx->res_ctx.pipe_ctx[i].top_pipe) {
+                       struct pipe_ctx *odm_pipe =
+                                       dc_res_get_odm_bottom_pipe(&new_ctx->res_ctx.pipe_ctx[i]);
+
                        del_pipe = &new_ctx->res_ctx.pipe_ctx[i];
 
                        ASSERT(del_pipe->stream_res.stream_enc);
@@ -1727,6 +1767,10 @@ enum dc_status dc_remove_stream_from_ctx(
                                dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
 
                        memset(del_pipe, 0, sizeof(*del_pipe));
+                       if (odm_pipe)
+                               memset(odm_pipe, 0, sizeof(*odm_pipe));
+
+                       break;
                }
        }
 
index 0086a2f1d21a1983d30bfd6509bdfc65ed731845..62e00a9f3184cb6261bfcc586465442a877250d2 100644 (file)
@@ -172,4 +172,6 @@ void update_audio_usage(
 
 unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format);
 
+struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx);
+
 #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */