@@ -2741,6 +2741,147 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx)
2741
2741
pipe_ctx -> plane_res .dpp , & opt_attr );
2742
2742
}
2743
2743
2744
+ /**
2745
+ * apply_front_porch_workaround TODO FPGA still need?
2746
+ *
2747
+ * This is a workaround for a bug that has existed since R5xx and has not been
2748
+ * fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
2749
+ */
2750
+ static void apply_front_porch_workaround (
2751
+ struct dc_crtc_timing * timing )
2752
+ {
2753
+ if (timing -> flags .INTERLACE == 1 ) {
2754
+ if (timing -> v_front_porch < 2 )
2755
+ timing -> v_front_porch = 2 ;
2756
+ } else {
2757
+ if (timing -> v_front_porch < 1 )
2758
+ timing -> v_front_porch = 1 ;
2759
+ }
2760
+ }
2761
+
2762
+ int get_vupdate_offset_from_vsync (struct pipe_ctx * pipe_ctx )
2763
+ {
2764
+ struct timing_generator * optc = pipe_ctx -> stream_res .tg ;
2765
+ const struct dc_crtc_timing * dc_crtc_timing = & pipe_ctx -> stream -> timing ;
2766
+ struct dc_crtc_timing patched_crtc_timing ;
2767
+ int vesa_sync_start ;
2768
+ int asic_blank_end ;
2769
+ int interlace_factor ;
2770
+ int vertical_line_start ;
2771
+
2772
+ patched_crtc_timing = * dc_crtc_timing ;
2773
+ apply_front_porch_workaround (& patched_crtc_timing );
2774
+
2775
+ interlace_factor = patched_crtc_timing .flags .INTERLACE ? 2 : 1 ;
2776
+
2777
+ vesa_sync_start = patched_crtc_timing .v_addressable +
2778
+ patched_crtc_timing .v_border_bottom +
2779
+ patched_crtc_timing .v_front_porch ;
2780
+
2781
+ asic_blank_end = (patched_crtc_timing .v_total -
2782
+ vesa_sync_start -
2783
+ patched_crtc_timing .v_border_top )
2784
+ * interlace_factor ;
2785
+
2786
+ vertical_line_start = asic_blank_end -
2787
+ optc -> dlg_otg_param .vstartup_start + 1 ;
2788
+
2789
+ return vertical_line_start ;
2790
+ }
2791
+
2792
+ static void calc_vupdate_position (
2793
+ struct pipe_ctx * pipe_ctx ,
2794
+ uint32_t * start_line ,
2795
+ uint32_t * end_line )
2796
+ {
2797
+ const struct dc_crtc_timing * dc_crtc_timing = & pipe_ctx -> stream -> timing ;
2798
+ int vline_int_offset_from_vupdate =
2799
+ pipe_ctx -> stream -> periodic_interrupt0 .lines_offset ;
2800
+ int vupdate_offset_from_vsync = get_vupdate_offset_from_vsync (pipe_ctx );
2801
+ int start_position ;
2802
+
2803
+ if (vline_int_offset_from_vupdate > 0 )
2804
+ vline_int_offset_from_vupdate -- ;
2805
+ else if (vline_int_offset_from_vupdate < 0 )
2806
+ vline_int_offset_from_vupdate ++ ;
2807
+
2808
+ start_position = vline_int_offset_from_vupdate + vupdate_offset_from_vsync ;
2809
+
2810
+ if (start_position >= 0 )
2811
+ * start_line = start_position ;
2812
+ else
2813
+ * start_line = dc_crtc_timing -> v_total + start_position - 1 ;
2814
+
2815
+ * end_line = * start_line + 2 ;
2816
+
2817
+ if (* end_line >= dc_crtc_timing -> v_total )
2818
+ * end_line = 2 ;
2819
+ }
2820
+
2821
+ static void cal_vline_position (
2822
+ struct pipe_ctx * pipe_ctx ,
2823
+ enum vline_select vline ,
2824
+ uint32_t * start_line ,
2825
+ uint32_t * end_line )
2826
+ {
2827
+ enum vertical_interrupt_ref_point ref_point = INVALID_POINT ;
2828
+
2829
+ if (vline == VLINE0 )
2830
+ ref_point = pipe_ctx -> stream -> periodic_interrupt0 .ref_point ;
2831
+ else if (vline == VLINE1 )
2832
+ ref_point = pipe_ctx -> stream -> periodic_interrupt1 .ref_point ;
2833
+
2834
+ switch (ref_point ) {
2835
+ case START_V_UPDATE :
2836
+ calc_vupdate_position (
2837
+ pipe_ctx ,
2838
+ start_line ,
2839
+ end_line );
2840
+ break ;
2841
+ case START_V_SYNC :
2842
+ // Suppose to do nothing because vsync is 0;
2843
+ break ;
2844
+ default :
2845
+ ASSERT (0 );
2846
+ break ;
2847
+ }
2848
+ }
2849
+
2850
+ static void dcn10_setup_periodic_interrupt (
2851
+ struct pipe_ctx * pipe_ctx ,
2852
+ enum vline_select vline )
2853
+ {
2854
+ struct timing_generator * tg = pipe_ctx -> stream_res .tg ;
2855
+
2856
+ if (vline == VLINE0 ) {
2857
+ uint32_t start_line = 0 ;
2858
+ uint32_t end_line = 0 ;
2859
+
2860
+ cal_vline_position (pipe_ctx , vline , & start_line , & end_line );
2861
+
2862
+ tg -> funcs -> setup_vertical_interrupt0 (tg , start_line , end_line );
2863
+
2864
+ } else if (vline == VLINE1 ) {
2865
+ pipe_ctx -> stream_res .tg -> funcs -> setup_vertical_interrupt1 (
2866
+ tg ,
2867
+ pipe_ctx -> stream -> periodic_interrupt1 .lines_offset );
2868
+ }
2869
+ }
2870
+
2871
+ static void dcn10_setup_vupdate_interrupt (struct pipe_ctx * pipe_ctx )
2872
+ {
2873
+ struct timing_generator * tg = pipe_ctx -> stream_res .tg ;
2874
+ int start_line = get_vupdate_offset_from_vsync (pipe_ctx );
2875
+
2876
+ if (start_line < 0 ) {
2877
+ ASSERT (0 );
2878
+ start_line = 0 ;
2879
+ }
2880
+
2881
+ if (tg -> funcs -> setup_vertical_interrupt2 )
2882
+ tg -> funcs -> setup_vertical_interrupt2 (tg , start_line );
2883
+ }
2884
+
2744
2885
static const struct hw_sequencer_funcs dcn10_funcs = {
2745
2886
.program_gamut_remap = program_gamut_remap ,
2746
2887
.init_hw = dcn10_init_hw ,
@@ -2790,7 +2931,9 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
2790
2931
.set_cursor_attribute = dcn10_set_cursor_attribute ,
2791
2932
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level ,
2792
2933
.disable_stream_gating = NULL ,
2793
- .enable_stream_gating = NULL
2934
+ .enable_stream_gating = NULL ,
2935
+ .setup_periodic_interrupt = dcn10_setup_periodic_interrupt ,
2936
+ .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt
2794
2937
};
2795
2938
2796
2939
0 commit comments