summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
diff options
context:
space:
mode:
authorYongqiang Sun <yongqiang.sun@amd.com>2019-01-24 15:59:22 -0500
committerAlex Deucher <alexander.deucher@amd.com>2019-02-06 13:29:56 -0500
commit810ece19ee74c5705190ef18ccb292e7930a2377 (patch)
tree0720c038bda1efb653d844b1ac37d75e7e23c72c /drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
parent3f01f098a4e2ef30ef628497c43a3d568e720376 (diff)
drm/amd/display: Calc vline position in dc.
We need to calcualte vline position in DC for DCN. Signed-off-by: Yongqiang Sun <yongqiang.sun@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>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c80
1 files changed, 76 insertions, 4 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
index cefa322df8a6..0355dcb8554a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
@@ -92,22 +92,94 @@ static void optc1_disable_stereo(struct timing_generator *optc)
OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0);
}
+static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing)
+{
+ struct dc_crtc_timing patched_crtc_timing;
+ int vesa_sync_start;
+ int asic_blank_end;
+ int interlace_factor;
+ int vertical_line_start;
+
+ patched_crtc_timing = *dc_crtc_timing;
+ optc1_apply_front_porch_workaround(optc, &patched_crtc_timing);
+
+ vesa_sync_start = patched_crtc_timing.h_addressable +
+ patched_crtc_timing.h_border_right +
+ patched_crtc_timing.h_front_porch;
+
+ asic_blank_end = patched_crtc_timing.h_total -
+ vesa_sync_start -
+ patched_crtc_timing.h_border_left;
+
+ interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1;
+
+ vesa_sync_start = patched_crtc_timing.v_addressable +
+ patched_crtc_timing.v_border_bottom +
+ patched_crtc_timing.v_front_porch;
+
+ asic_blank_end = (patched_crtc_timing.v_total -
+ vesa_sync_start -
+ patched_crtc_timing.v_border_top)
+ * interlace_factor;
+
+ vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1;
+ if (vertical_line_start < 0) {
+ ASSERT(0);
+ vertical_line_start = 0;
+ }
+
+ return vertical_line_start;
+}
+
+static void calc_vline_position(
+ struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing,
+ unsigned long long vsync_delta,
+ uint32_t *start_line,
+ uint32_t *end_line)
+{
+ unsigned long long req_delta_tens_of_usec = div64_u64((vsync_delta + 9999), 10000);
+ unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_100hz + 999), 1000);
+ uint32_t req_delta_lines = (uint32_t) div64_u64(
+ (req_delta_tens_of_usec * pix_clk_hundreds_khz + dc_crtc_timing->h_total - 1),
+ dc_crtc_timing->h_total);
+
+ uint32_t vsync_line = get_start_vline(optc, dc_crtc_timing);
+
+ if (req_delta_lines != 0)
+ req_delta_lines--;
+
+ if (req_delta_lines > vsync_line)
+ *start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) - 1;
+ else
+ *start_line = vsync_line - req_delta_lines;
+
+ *end_line = *start_line + 2;
+
+ if (*end_line >= dc_crtc_timing->v_total)
+ *end_line = 2;
+}
+
void optc1_program_vline_interrupt(
struct timing_generator *optc,
+ const struct dc_crtc_timing *dc_crtc_timing,
enum vline_select vline,
- const struct vline_config *vline_config)
+ const union vline_config *vline_config)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ uint32_t start_line = 0;
+ uint32_t end_line = 0;
switch (vline) {
case VLINE0:
+ calc_vline_position(optc, dc_crtc_timing, vline_config->delta_in_ns, &start_line, &end_line);
REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0,
- OTG_VERTICAL_INTERRUPT0_LINE_START, vline_config->start_line,
- OTG_VERTICAL_INTERRUPT0_LINE_END, vline_config->end_line);
+ OTG_VERTICAL_INTERRUPT0_LINE_START, start_line,
+ OTG_VERTICAL_INTERRUPT0_LINE_END, end_line);
break;
case VLINE1:
REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0,
- OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->start_line);
+ OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->line_number);
break;
default:
break;