Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/amd/display: Disconnect pipe separetely when disable pipe split

[Why]
When changing pixel formats for HDR (e.g. ARGB -> FP16)
there are configurations that change from 2 pipes to 1 pipe.
In these cases, it seems that disconnecting MPCC and doing
a surface update at the same time(after unlocking) causes
some registers to be updated slightly faster than others
after unlocking (e.g. if the pixel format is updated to FP16
before the new surface address is programmed, we get
corruption on the screen because the pixel formats aren't
matching). We separate disconnecting MPCC from the rest
of the pipe programming sequence to prevent this.

[How]
Move MPCC disconnect into separate operation than the
rest of the pipe programming.

Signed-off-by: Alvin Lee <alvin.lee2@amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Alvin Lee and committed by
Alex Deucher
81b437f5 073e7cd5

+174
+10
drivers/gpu/drm/amd/display/dc/core/dc.c
··· 2300 2300 enum surface_update_type update_type, 2301 2301 struct dc_state *context) 2302 2302 { 2303 + bool mpcc_disconnected = false; 2303 2304 int i, j; 2304 2305 struct pipe_ctx *top_pipe_to_program = NULL; 2305 2306 ··· 2329 2328 dc->hwss.prepare_bandwidth(dc, context); 2330 2329 2331 2330 context_clock_trace(dc, context); 2331 + } 2332 + 2333 + if (update_type != UPDATE_TYPE_FAST && dc->hwss.interdependent_update_lock && 2334 + dc->hwss.disconnect_pipes && dc->hwss.wait_for_pending_cleared){ 2335 + dc->hwss.interdependent_update_lock(dc, context, true); 2336 + mpcc_disconnected = dc->hwss.disconnect_pipes(dc, context); 2337 + dc->hwss.interdependent_update_lock(dc, context, false); 2338 + if (mpcc_disconnected) 2339 + dc->hwss.wait_for_pending_cleared(dc, context); 2332 2340 } 2333 2341 2334 2342 for (j = 0; j < dc->res_pool->pipe_count; j++) {
+146
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
··· 2752 2752 return NULL; 2753 2753 } 2754 2754 2755 + bool dcn10_disconnect_pipes( 2756 + struct dc *dc, 2757 + struct dc_state *context) 2758 + { 2759 + bool found_stream = false; 2760 + int i, j; 2761 + struct dce_hwseq *hws = dc->hwseq; 2762 + struct dc_state *old_ctx = dc->current_state; 2763 + bool mpcc_disconnected = false; 2764 + struct pipe_ctx *old_pipe; 2765 + struct pipe_ctx *new_pipe; 2766 + DC_LOGGER_INIT(dc->ctx->logger); 2767 + 2768 + /* Set pipe update flags and lock pipes */ 2769 + for (i = 0; i < dc->res_pool->pipe_count; i++) { 2770 + old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 2771 + new_pipe = &context->res_ctx.pipe_ctx[i]; 2772 + new_pipe->update_flags.raw = 0; 2773 + 2774 + if (!old_pipe->plane_state && !new_pipe->plane_state) 2775 + continue; 2776 + 2777 + if (old_pipe->plane_state && !new_pipe->plane_state) 2778 + new_pipe->update_flags.bits.disable = 1; 2779 + 2780 + /* Check for scl update */ 2781 + if (memcmp(&old_pipe->plane_res.scl_data, &new_pipe->plane_res.scl_data, sizeof(struct scaler_data))) 2782 + new_pipe->update_flags.bits.scaler = 1; 2783 + 2784 + /* Check for vp update */ 2785 + if (memcmp(&old_pipe->plane_res.scl_data.viewport, &new_pipe->plane_res.scl_data.viewport, sizeof(struct rect)) 2786 + || memcmp(&old_pipe->plane_res.scl_data.viewport_c, 2787 + &new_pipe->plane_res.scl_data.viewport_c, sizeof(struct rect))) 2788 + new_pipe->update_flags.bits.viewport = 1; 2789 + 2790 + } 2791 + 2792 + if (!IS_DIAG_DC(dc->ctx->dce_environment)) { 2793 + /* Disconnect mpcc here only if losing pipe split*/ 2794 + for (i = 0; i < dc->res_pool->pipe_count; i++) { 2795 + if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && 2796 + old_ctx->res_ctx.pipe_ctx[i].top_pipe) { 2797 + 2798 + /* Find the top pipe in the new ctx for the bottom pipe that we 2799 + * want to remove by comparing the streams. If both pipes are being 2800 + * disabled then do it in the regular pipe programming sequence 2801 + */ 2802 + for (j = 0; j < dc->res_pool->pipe_count; j++) { 2803 + if (old_ctx->res_ctx.pipe_ctx[i].top_pipe->stream == context->res_ctx.pipe_ctx[j].stream && 2804 + !context->res_ctx.pipe_ctx[j].top_pipe && 2805 + !context->res_ctx.pipe_ctx[j].update_flags.bits.disable) { 2806 + found_stream = true; 2807 + break; 2808 + } 2809 + } 2810 + 2811 + // Disconnect if the top pipe lost it's pipe split 2812 + if (found_stream && !context->res_ctx.pipe_ctx[j].bottom_pipe) { 2813 + hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); 2814 + DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); 2815 + mpcc_disconnected = true; 2816 + } 2817 + } 2818 + found_stream = false; 2819 + } 2820 + } 2821 + 2822 + if (mpcc_disconnected) { 2823 + for (i = 0; i < dc->res_pool->pipe_count; i++) { 2824 + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 2825 + struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 2826 + struct dc_plane_state *plane_state = pipe_ctx->plane_state; 2827 + struct hubp *hubp = pipe_ctx->plane_res.hubp; 2828 + 2829 + if (!pipe_ctx || !plane_state || !pipe_ctx->stream) 2830 + continue; 2831 + 2832 + // Only update scaler and viewport here if we lose a pipe split. 2833 + // This is to prevent half the screen from being black when we 2834 + // unlock after disconnecting MPCC. 2835 + if (!(old_pipe && !pipe_ctx->top_pipe && 2836 + !pipe_ctx->bottom_pipe && old_pipe->bottom_pipe)) 2837 + continue; 2838 + 2839 + if (pipe_ctx->update_flags.raw || pipe_ctx->plane_state->update_flags.raw || pipe_ctx->stream->update_flags.raw) { 2840 + if (pipe_ctx->update_flags.bits.scaler || 2841 + plane_state->update_flags.bits.scaling_change || 2842 + plane_state->update_flags.bits.position_change || 2843 + plane_state->update_flags.bits.per_pixel_alpha_change || 2844 + pipe_ctx->stream->update_flags.bits.scaling) { 2845 + 2846 + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; 2847 + ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_30BPP); 2848 + /* scaler configuration */ 2849 + pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( 2850 + pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); 2851 + } 2852 + 2853 + if (pipe_ctx->update_flags.bits.viewport || 2854 + (context == dc->current_state && plane_state->update_flags.bits.position_change) || 2855 + (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || 2856 + (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { 2857 + 2858 + hubp->funcs->mem_program_viewport( 2859 + hubp, 2860 + &pipe_ctx->plane_res.scl_data.viewport, 2861 + &pipe_ctx->plane_res.scl_data.viewport_c); 2862 + } 2863 + } 2864 + } 2865 + } 2866 + return mpcc_disconnected; 2867 + } 2868 + 2869 + void dcn10_wait_for_pending_cleared(struct dc *dc, 2870 + struct dc_state *context) 2871 + { 2872 + struct pipe_ctx *pipe_ctx; 2873 + struct timing_generator *tg; 2874 + int i; 2875 + 2876 + for (i = 0; i < dc->res_pool->pipe_count; i++) { 2877 + pipe_ctx = &context->res_ctx.pipe_ctx[i]; 2878 + tg = pipe_ctx->stream_res.tg; 2879 + 2880 + /* 2881 + * Only wait for top pipe's tg penindg bit 2882 + * Also skip if pipe is disabled. 2883 + */ 2884 + if (pipe_ctx->top_pipe || 2885 + !pipe_ctx->stream || !pipe_ctx->plane_state || 2886 + !tg->funcs->is_tg_enabled(tg)) 2887 + continue; 2888 + 2889 + /* 2890 + * Wait for VBLANK then VACTIVE to ensure we get VUPDATE. 2891 + * For some reason waiting for OTG_UPDATE_PENDING cleared 2892 + * seems to not trigger the update right away, and if we 2893 + * lock again before VUPDATE then we don't get a separated 2894 + * operation. 2895 + */ 2896 + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK); 2897 + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); 2898 + } 2899 + } 2900 + 2755 2901 void dcn10_apply_ctx_for_surface( 2756 2902 struct dc *dc, 2757 2903 const struct dc_stream_state *stream,
+6
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h
··· 194 194 void dcn10_get_hdr_visual_confirm_color( 195 195 struct pipe_ctx *pipe_ctx, 196 196 struct tg_color *color); 197 + bool dcn10_disconnect_pipes( 198 + struct dc *dc, 199 + struct dc_state *context); 200 + 201 + void dcn10_wait_for_pending_cleared(struct dc *dc, 202 + struct dc_state *context); 197 203 void dcn10_set_hdr_multiplier(struct pipe_ctx *pipe_ctx); 198 204 void dcn10_verify_allow_pstate_change_high(struct dc *dc); 199 205
+2
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c
··· 34 34 .apply_ctx_to_hw = dce110_apply_ctx_to_hw, 35 35 .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, 36 36 .post_unlock_program_front_end = dcn10_post_unlock_program_front_end, 37 + .disconnect_pipes = dcn10_disconnect_pipes, 38 + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, 37 39 .update_plane_addr = dcn10_update_plane_addr, 38 40 .update_dchub = dcn10_update_dchub, 39 41 .update_pending_status = dcn10_update_pending_status,
+2
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c
··· 34 34 .apply_ctx_to_hw = dce110_apply_ctx_to_hw, 35 35 .apply_ctx_for_surface = NULL, 36 36 .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, 37 + .disconnect_pipes = dcn10_disconnect_pipes, 38 + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, 37 39 .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, 38 40 .update_plane_addr = dcn20_update_plane_addr, 39 41 .update_dchub = dcn10_update_dchub,
+2
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c
··· 35 35 .apply_ctx_to_hw = dce110_apply_ctx_to_hw, 36 36 .apply_ctx_for_surface = NULL, 37 37 .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, 38 + .disconnect_pipes = dcn10_disconnect_pipes, 39 + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, 38 40 .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, 39 41 .update_plane_addr = dcn20_update_plane_addr, 40 42 .update_dchub = dcn10_update_dchub,
+2
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c
··· 35 35 .apply_ctx_to_hw = dce110_apply_ctx_to_hw, 36 36 .apply_ctx_for_surface = NULL, 37 37 .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, 38 + .disconnect_pipes = dcn10_disconnect_pipes, 39 + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, 38 40 .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, 39 41 .update_plane_addr = dcn20_update_plane_addr, 40 42 .update_dchub = dcn10_update_dchub,
+4
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
··· 67 67 int num_planes, struct dc_state *context); 68 68 void (*program_front_end_for_ctx)(struct dc *dc, 69 69 struct dc_state *context); 70 + bool (*disconnect_pipes)(struct dc *dc, 71 + struct dc_state *context); 72 + void (*wait_for_pending_cleared)(struct dc *dc, 73 + struct dc_state *context); 70 74 void (*post_unlock_program_front_end)(struct dc *dc, 71 75 struct dc_state *context); 72 76 void (*update_plane_addr)(const struct dc *dc,