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

drm/amd/display: fix and simplify pipe split logic

Current odm/mpc combine logic to detect which pipes need to split
logically is flawed leading to incorrect pipe merge/split operations
being taken.

This change cleans up the logic and fixes the logical errors.

Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: Eric Bernstein <Eric.Bernstein@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Dmytro Laktyushkin and committed by
Alex Deucher
570bc18c 14e49bb3

+93 -90
+19 -6
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
··· 532 532 *flip_horz_scan_dir = !*flip_horz_scan_dir; 533 533 } 534 534 535 + int get_num_mpc_splits(struct pipe_ctx *pipe) 536 + { 537 + int mpc_split_count = 0; 538 + struct pipe_ctx *other_pipe = pipe->bottom_pipe; 539 + 540 + while (other_pipe && other_pipe->plane_state == pipe->plane_state) { 541 + mpc_split_count++; 542 + other_pipe = other_pipe->bottom_pipe; 543 + } 544 + other_pipe = pipe->top_pipe; 545 + while (other_pipe && other_pipe->plane_state == pipe->plane_state) { 546 + mpc_split_count++; 547 + other_pipe = other_pipe->top_pipe; 548 + } 549 + 550 + return mpc_split_count; 551 + } 552 + 535 553 int get_num_odm_splits(struct pipe_ctx *pipe) 536 554 { 537 555 int odm_split_count = 0; ··· 574 556 /*Check for mpc split*/ 575 557 struct pipe_ctx *split_pipe = pipe_ctx->top_pipe; 576 558 559 + *split_count = get_num_mpc_splits(pipe_ctx); 577 560 while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) { 578 561 (*split_idx)++; 579 - (*split_count)++; 580 562 split_pipe = split_pipe->top_pipe; 581 - } 582 - split_pipe = pipe_ctx->bottom_pipe; 583 - while (split_pipe && split_pipe->plane_state == pipe_ctx->plane_state) { 584 - (*split_count)++; 585 - split_pipe = split_pipe->bottom_pipe; 586 563 } 587 564 } else { 588 565 /*Get odm split index*/
+68 -83
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
··· 1663 1663 } 1664 1664 1665 1665 1666 - static void acquire_dsc(const struct dc *dc, 1666 + void dcn20_acquire_dsc(const struct dc *dc, 1667 1667 struct resource_context *res_ctx, 1668 1668 struct display_stream_compressor **dsc, 1669 1669 int pipe_idx) ··· 1731 1731 if (pipe_ctx->stream_res.dsc) 1732 1732 continue; 1733 1733 1734 - acquire_dsc(dc, &dc_ctx->res_ctx, &pipe_ctx->stream_res.dsc, i); 1734 + dcn20_acquire_dsc(dc, &dc_ctx->res_ctx, &pipe_ctx->stream_res.dsc, i); 1735 1735 1736 1736 /* The number of DSCs can be less than the number of pipes */ 1737 1737 if (!pipe_ctx->stream_res.dsc) { ··· 1923 1923 } 1924 1924 next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; 1925 1925 if (next_odm_pipe->stream->timing.flags.DSC == 1) { 1926 - acquire_dsc(dc, res_ctx, &next_odm_pipe->stream_res.dsc, next_odm_pipe->pipe_idx); 1926 + dcn20_acquire_dsc(dc, res_ctx, &next_odm_pipe->stream_res.dsc, next_odm_pipe->pipe_idx); 1927 1927 ASSERT(next_odm_pipe->stream_res.dsc); 1928 1928 if (next_odm_pipe->stream_res.dsc == NULL) 1929 1929 return false; ··· 2586 2586 } 2587 2587 } 2588 2588 2589 - int dcn20_find_previous_split_count(struct pipe_ctx *pipe) 2590 - { 2591 - int previous_split = 1; 2592 - struct pipe_ctx *current_pipe = pipe; 2593 - 2594 - while (current_pipe->bottom_pipe) { 2595 - if (current_pipe->plane_state != current_pipe->bottom_pipe->plane_state) 2596 - break; 2597 - previous_split++; 2598 - current_pipe = current_pipe->bottom_pipe; 2599 - } 2600 - current_pipe = pipe; 2601 - while (current_pipe->top_pipe) { 2602 - if (current_pipe->plane_state != current_pipe->top_pipe->plane_state) 2603 - break; 2604 - previous_split++; 2605 - current_pipe = current_pipe->top_pipe; 2606 - } 2607 - return previous_split; 2608 - } 2609 - 2610 2589 int dcn20_validate_apply_pipe_split_flags( 2611 2590 struct dc *dc, 2612 2591 struct dc_state *context, ··· 2597 2618 int plane_count = 0; 2598 2619 bool force_split = false; 2599 2620 bool avoid_split = dc->debug.pipe_split_policy == MPC_SPLIT_AVOID; 2621 + struct vba_vars_st *v = &context->bw_ctx.dml.vba; 2622 + int max_mpc_comb = v->maxMpcComb; 2600 2623 2601 2624 if (context->stream_count > 1) { 2602 2625 if (dc->debug.pipe_split_policy == MPC_SPLIT_AVOID_MULT_DISP) ··· 2619 2638 2620 2639 /* Avoid split loop looks for lowest voltage level that allows most unsplit pipes possible */ 2621 2640 if (avoid_split) { 2622 - int max_mpc_comb = context->bw_ctx.dml.vba.maxMpcComb; 2623 - 2624 2641 for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { 2625 2642 if (!context->res_ctx.pipe_ctx[i].stream) 2626 2643 continue; 2627 2644 2628 2645 for (vlevel_split = vlevel; vlevel <= context->bw_ctx.dml.soc.num_states; vlevel++) 2629 - if (context->bw_ctx.dml.vba.NoOfDPP[vlevel][0][pipe_idx] == 1 && 2630 - context->bw_ctx.dml.vba.ModeSupport[vlevel][0]) 2646 + if (v->NoOfDPP[vlevel][0][pipe_idx] == 1 && 2647 + v->ModeSupport[vlevel][0]) 2631 2648 break; 2632 2649 /* Impossible to not split this pipe */ 2633 2650 if (vlevel > context->bw_ctx.dml.soc.num_states) ··· 2634 2655 max_mpc_comb = 0; 2635 2656 pipe_idx++; 2636 2657 } 2637 - context->bw_ctx.dml.vba.maxMpcComb = max_mpc_comb; 2658 + v->maxMpcComb = max_mpc_comb; 2638 2659 } 2639 2660 2640 2661 /* Split loop sets which pipe should be split based on dml outputs and dc flags */ 2641 2662 for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { 2642 2663 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 2643 - int pipe_plane = context->bw_ctx.dml.vba.pipe_plane[pipe_idx]; 2664 + int pipe_plane = v->pipe_plane[pipe_idx]; 2665 + bool split4mpc = context->stream_count == 1 && plane_count == 1 2666 + && dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4; 2644 2667 2645 2668 if (!context->res_ctx.pipe_ctx[i].stream) 2646 2669 continue; 2647 2670 2648 - if (force_split 2649 - || context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_plane] > 1) { 2650 - if (context->stream_count == 1 && plane_count == 1 2651 - && dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4) 2671 + if (force_split || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] > 1) { 2672 + if (split4mpc) 2652 2673 split[i] = 4; 2653 2674 else 2654 2675 split[i] = 2; ··· 2664 2685 split[i] = 2; 2665 2686 if (dc->debug.force_odm_combine & (1 << pipe->stream_res.tg->inst)) { 2666 2687 split[i] = 2; 2667 - context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_2to1; 2688 + v->ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_2to1; 2668 2689 } 2669 - context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] = 2670 - context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel][pipe_plane]; 2690 + v->ODMCombineEnabled[pipe_plane] = 2691 + v->ODMCombineEnablePerState[vlevel][pipe_plane]; 2671 2692 2672 - if (pipe->prev_odm_pipe && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] != dm_odm_combine_mode_disabled) { 2673 - /*Already split odm pipe tree, don't try to split again*/ 2674 - split[i] = 0; 2675 - split[pipe->prev_odm_pipe->pipe_idx] = 0; 2676 - } else if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state 2677 - && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) { 2678 - /*If 2 way split but can support 4 way split, then split each pipe again*/ 2679 - if (context->stream_count == 1 && plane_count == 1 2680 - && dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4) { 2681 - split[i] = 2; 2682 - } else { 2693 + if (v->ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) { 2694 + if (get_num_mpc_splits(pipe) == 1) { 2695 + /*If need split for mpc but 2 way split already*/ 2696 + if (split[i] == 4) 2697 + split[i] = 2; /* 2 -> 4 MPC */ 2698 + else if (split[i] == 2) 2699 + split[i] = 0; /* 2 -> 2 MPC */ 2700 + else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) 2701 + merge[i] = true; /* 2 -> 1 MPC */ 2702 + } else if (get_num_mpc_splits(pipe) == 3) { 2703 + /*If need split for mpc but 4 way split already*/ 2704 + if (split[i] == 2 && ((pipe->top_pipe && !pipe->top_pipe->top_pipe) 2705 + || !pipe->bottom_pipe)) { 2706 + merge[i] = true; /* 4 -> 2 MPC */ 2707 + } else if (split[i] == 0 && pipe->top_pipe && 2708 + pipe->top_pipe->plane_state == pipe->plane_state) 2709 + merge[i] = true; /* 4 -> 1 MPC */ 2683 2710 split[i] = 0; 2684 - split[pipe->top_pipe->pipe_idx] = 0; 2685 - } 2686 - } else if (pipe->prev_odm_pipe || (dcn20_find_previous_split_count(pipe) == 2 && pipe->top_pipe)) { 2687 - if (split[i] == 0) { 2688 - /*Exiting mpc/odm combine*/ 2689 - merge[i] = true; 2690 - } else { 2691 - /*Transition from mpc combine to odm combine or vice versa*/ 2692 - ASSERT(0); /*should not actually happen yet*/ 2693 - split[i] = 2; 2694 - merge[i] = true; 2711 + } else if (get_num_odm_splits(pipe)) { 2712 + /* ODM -> MPC transition */ 2713 + ASSERT(0); /* NOT expected yet */ 2695 2714 if (pipe->prev_odm_pipe) { 2696 - split[pipe->prev_odm_pipe->pipe_idx] = 2; 2697 - merge[pipe->prev_odm_pipe->pipe_idx] = true; 2698 - } else { 2699 - split[pipe->top_pipe->pipe_idx] = 2; 2700 - merge[pipe->top_pipe->pipe_idx] = true; 2715 + split[i] = 0; 2716 + merge[i] = true; 2701 2717 } 2702 2718 } 2703 - } else if (dcn20_find_previous_split_count(pipe) == 3) { 2704 - if (split[i] == 0 && !pipe->top_pipe) { 2705 - merge[pipe->bottom_pipe->pipe_idx] = true; 2706 - merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true; 2707 - } else if (split[i] == 2 && !pipe->top_pipe) { 2708 - merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true; 2719 + } else { 2720 + if (get_num_odm_splits(pipe) == 1) { 2721 + /*If need split for odm but 2 way split already*/ 2722 + if (split[i] == 4) 2723 + split[i] = 2; /* 2 -> 4 ODM */ 2724 + else if (split[i] == 2) 2725 + split[i] = 0; /* 2 -> 2 ODM */ 2726 + else if (pipe->prev_odm_pipe) { 2727 + ASSERT(0); /* NOT expected yet */ 2728 + merge[i] = true; /* exit ODM */ 2729 + } 2730 + } else if (get_num_odm_splits(pipe) == 3) { 2731 + /*If need split for odm but 4 way split already*/ 2732 + if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe) 2733 + || !pipe->next_odm_pipe)) { 2734 + ASSERT(0); /* NOT expected yet */ 2735 + merge[i] = true; /* 4 -> 2 ODM */ 2736 + } else if (split[i] == 0 && pipe->prev_odm_pipe) { 2737 + ASSERT(0); /* NOT expected yet */ 2738 + merge[i] = true; /* exit ODM */ 2739 + } 2709 2740 split[i] = 0; 2710 - } 2711 - } else if (dcn20_find_previous_split_count(pipe) == 4) { 2712 - if (split[i] == 0 && !pipe->top_pipe) { 2713 - merge[pipe->bottom_pipe->pipe_idx] = true; 2714 - merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true; 2715 - merge[pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx] = true; 2716 - } else if (split[i] == 2 && !pipe->top_pipe) { 2717 - merge[pipe->bottom_pipe->bottom_pipe->pipe_idx] = true; 2718 - merge[pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx] = true; 2719 - split[i] = 0; 2741 + } else if (get_num_mpc_splits(pipe)) { 2742 + /* MPC -> ODM transition */ 2743 + ASSERT(0); /* NOT expected yet */ 2744 + if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { 2745 + split[i] = 0; 2746 + merge[i] = true; 2747 + } 2720 2748 } 2721 2749 } 2722 2750 2723 2751 /* Adjust dppclk when split is forced, do not bother with dispclk */ 2724 - if (split[i] != 0 2725 - && context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] == 1) 2726 - context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] /= 2; 2752 + if (split[i] != 0 && v->NoOfDPP[vlevel][max_mpc_comb][pipe_idx] == 1) 2753 + v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] /= 2; 2727 2754 pipe_idx++; 2728 2755 } 2729 2756
+4 -1
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
··· 119 119 display_e2e_pipe_params_st *pipes, 120 120 int pipe_cnt); 121 121 bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate); 122 - int dcn20_find_previous_split_count(struct pipe_ctx *pipe); 123 122 int dcn20_validate_apply_pipe_split_flags( 124 123 struct dc *dc, 125 124 struct dc_state *context, ··· 139 140 struct resource_context *res_ctx, 140 141 struct pipe_ctx *prev_odm_pipe, 141 142 struct pipe_ctx *next_odm_pipe); 143 + void dcn20_acquire_dsc(const struct dc *dc, 144 + struct resource_context *res_ctx, 145 + struct display_stream_compressor **dsc, 146 + int pipe_idx); 142 147 struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, 143 148 struct resource_context *res_ctx, 144 149 const struct resource_pool *pool,
+2
drivers/gpu/drm/amd/display/dc/inc/resource.h
··· 177 177 void get_audio_check(struct audio_info *aud_modes, 178 178 struct audio_check *aud_chk); 179 179 180 + int get_num_mpc_splits(struct pipe_ctx *pipe); 181 + 180 182 int get_num_odm_splits(struct pipe_ctx *pipe); 181 183 182 184 #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */