diff options
author | Sylvia Tsai <sylvia.tsai@amd.com> | 2017-04-11 15:15:28 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2017-09-26 17:23:47 -0400 |
commit | 81c509633aa93442d58b895f773892b3e8d936cf (patch) | |
tree | e3a42a842efa15b5863092ddb15d00889bfc2082 | |
parent | 1ce71fcd5dddf4a3198a96e422122edc210847e9 (diff) |
drm/amd/display: Parse scanline registers
They could differ between ASIC generations
Signed-off-by: Sylvia Tsai <sylvia.tsai@amd.com>
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Acked-by: Harry Wentland <Harry.Wentland@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
7 files changed, 89 insertions, 66 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 93f10bc772c4..84995a48ec61 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | |||
@@ -103,6 +103,8 @@ static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc) | |||
103 | static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, | 103 | static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, |
104 | u32 *vbl, u32 *position) | 104 | u32 *vbl, u32 *position) |
105 | { | 105 | { |
106 | uint32_t v_blank_start, v_blank_end, h_position, v_position; | ||
107 | |||
106 | if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) | 108 | if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) |
107 | return -EINVAL; | 109 | return -EINVAL; |
108 | else { | 110 | else { |
@@ -113,7 +115,18 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, | |||
113 | return 0; | 115 | return 0; |
114 | } | 116 | } |
115 | 117 | ||
116 | return dc_stream_get_scanoutpos(acrtc->stream, vbl, position); | 118 | /* |
119 | * TODO rework base driver to use values directly. | ||
120 | * for now parse it back into reg-format | ||
121 | */ | ||
122 | dc_stream_get_scanoutpos(acrtc->stream, | ||
123 | &v_blank_start, | ||
124 | &v_blank_end, | ||
125 | &h_position, | ||
126 | &v_position); | ||
127 | |||
128 | *position = (v_position) || (h_position << 16); | ||
129 | *vbl = (v_blank_start) || (v_blank_end << 16); | ||
117 | } | 130 | } |
118 | 131 | ||
119 | return 0; | 132 | return 0; |
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index bf209f7bbf98..3dbd6c0885d8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c | |||
@@ -282,12 +282,14 @@ uint32_t dc_stream_get_vblank_counter(const struct dc_stream *dc_stream) | |||
282 | return 0; | 282 | return 0; |
283 | } | 283 | } |
284 | 284 | ||
285 | uint32_t dc_stream_get_scanoutpos( | 285 | bool dc_stream_get_scanoutpos(const struct dc_stream *dc_stream, |
286 | const struct dc_stream *dc_stream, | 286 | uint32_t *v_blank_start, |
287 | uint32_t *vbl, | 287 | uint32_t *v_blank_end, |
288 | uint32_t *position) | 288 | uint32_t *h_position, |
289 | uint32_t *v_position) | ||
289 | { | 290 | { |
290 | uint8_t i; | 291 | uint8_t i; |
292 | bool ret = false; | ||
291 | struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream); | 293 | struct core_stream *stream = DC_STREAM_TO_CORE(dc_stream); |
292 | struct core_dc *core_dc = DC_TO_CORE(stream->ctx->dc); | 294 | struct core_dc *core_dc = DC_TO_CORE(stream->ctx->dc); |
293 | struct resource_context *res_ctx = | 295 | struct resource_context *res_ctx = |
@@ -299,10 +301,17 @@ uint32_t dc_stream_get_scanoutpos( | |||
299 | if (res_ctx->pipe_ctx[i].stream != stream) | 301 | if (res_ctx->pipe_ctx[i].stream != stream) |
300 | continue; | 302 | continue; |
301 | 303 | ||
302 | return tg->funcs->get_scanoutpos(tg, vbl, position); | 304 | tg->funcs->get_scanoutpos(tg, |
305 | v_blank_start, | ||
306 | v_blank_end, | ||
307 | h_position, | ||
308 | v_position); | ||
309 | |||
310 | ret = true; | ||
311 | break; | ||
303 | } | 312 | } |
304 | 313 | ||
305 | return 0; | 314 | return ret; |
306 | } | 315 | } |
307 | 316 | ||
308 | 317 | ||
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 97af8f63eec3..7d548b4d0299 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h | |||
@@ -484,8 +484,11 @@ uint32_t dc_stream_get_vblank_counter(const struct dc_stream *stream); | |||
484 | * This has a dependency on the caller (amdgpu_get_crtc_scanoutpos) | 484 | * This has a dependency on the caller (amdgpu_get_crtc_scanoutpos) |
485 | * being refactored properly to be dce-specific | 485 | * being refactored properly to be dce-specific |
486 | */ | 486 | */ |
487 | uint32_t dc_stream_get_scanoutpos( | 487 | bool dc_stream_get_scanoutpos(const struct dc_stream *stream, |
488 | const struct dc_stream *stream, uint32_t *vbl, uint32_t *position); | 488 | uint32_t *v_blank_start, |
489 | uint32_t *v_blank_end, | ||
490 | uint32_t *h_position, | ||
491 | uint32_t *v_position); | ||
489 | 492 | ||
490 | /* | 493 | /* |
491 | * Structure to store surface/stream associations for validation | 494 | * Structure to store surface/stream associations for validation |
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c index 006412be7a02..7070aaf9e433 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c | |||
@@ -574,29 +574,26 @@ void dce110_timing_generator_get_crtc_positions( | |||
574 | * @param [out] vpos, hpos | 574 | * @param [out] vpos, hpos |
575 | ***************************************************************************** | 575 | ***************************************************************************** |
576 | */ | 576 | */ |
577 | uint32_t dce110_timing_generator_get_crtc_scanoutpos( | 577 | void dce110_timing_generator_get_crtc_scanoutpos( |
578 | struct timing_generator *tg, | 578 | struct timing_generator *tg, |
579 | uint32_t *vbl, | 579 | uint32_t *v_blank_start, |
580 | uint32_t *position) | 580 | uint32_t *v_blank_end, |
581 | uint32_t *h_position, | ||
582 | uint32_t *v_position) | ||
581 | { | 583 | { |
582 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); | 584 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); |
583 | /* TODO 1: Update the implementation once caller is updated | ||
584 | * WARNING!! This function is returning the whole register value | ||
585 | * because the caller is expecting it instead of proper vertical and | ||
586 | * horizontal position. This should be a temporary implementation | ||
587 | * until the caller is updated. */ | ||
588 | 585 | ||
589 | /* TODO 2: re-use dce110_timing_generator_get_crtc_positions() */ | 586 | uint32_t v_blank_start_end = dm_read_reg(tg->ctx, |
590 | |||
591 | *vbl = dm_read_reg(tg->ctx, | ||
592 | CRTC_REG(mmCRTC_V_BLANK_START_END)); | 587 | CRTC_REG(mmCRTC_V_BLANK_START_END)); |
593 | 588 | ||
594 | *position = dm_read_reg(tg->ctx, | 589 | *v_blank_start = get_reg_field_value(v_blank_start_end, |
595 | CRTC_REG(mmCRTC_STATUS_POSITION)); | 590 | CRTC_V_BLANK_START_END, |
591 | CRTC_V_BLANK_START); | ||
592 | *v_blank_end = get_reg_field_value(v_blank_start_end, | ||
593 | CRTC_V_BLANK_START_END, | ||
594 | CRTC_V_BLANK_END); | ||
596 | 595 | ||
597 | /* @TODO: return value should indicate if current | 596 | dce110_timing_generator_get_crtc_positions(tg, h_position, v_position); |
598 | * crtc is inside vblank*/ | ||
599 | return 0; | ||
600 | } | 597 | } |
601 | 598 | ||
602 | /* TODO: is it safe to assume that mask/shift of Primary and Underlay | 599 | /* TODO: is it safe to assume that mask/shift of Primary and Underlay |
@@ -1875,34 +1872,31 @@ void dce110_tg_set_colors(struct timing_generator *tg, | |||
1875 | bool dce110_arm_vert_intr(struct timing_generator *tg, uint8_t width) | 1872 | bool dce110_arm_vert_intr(struct timing_generator *tg, uint8_t width) |
1876 | { | 1873 | { |
1877 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); | 1874 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); |
1878 | uint32_t vbl = 0; | 1875 | uint32_t v_blank_start = 0; |
1876 | uint32_t v_blank_end = 0; | ||
1879 | uint32_t val = 0; | 1877 | uint32_t val = 0; |
1880 | uint32_t position, vbl_start; | 1878 | uint32_t h_position, v_position; |
1881 | 1879 | ||
1882 | tg->funcs->get_scanoutpos( | 1880 | tg->funcs->get_scanoutpos( |
1883 | tg, | 1881 | tg, |
1884 | &vbl, | 1882 | &v_blank_start, |
1885 | &position); | 1883 | &v_blank_end, |
1884 | &h_position, | ||
1885 | &v_position); | ||
1886 | 1886 | ||
1887 | if (vbl == 0) | 1887 | if (v_blank_start == 0 || v_blank_end == 0) |
1888 | return false; | 1888 | return false; |
1889 | 1889 | ||
1890 | vbl_start = | ||
1891 | get_reg_field_value( | ||
1892 | vbl, | ||
1893 | CRTC_V_BLANK_START_END, | ||
1894 | CRTC_V_BLANK_START); | ||
1895 | |||
1896 | set_reg_field_value( | 1890 | set_reg_field_value( |
1897 | val, | 1891 | val, |
1898 | vbl_start, | 1892 | v_blank_start, |
1899 | CRTC_VERTICAL_INTERRUPT0_POSITION, | 1893 | CRTC_VERTICAL_INTERRUPT0_POSITION, |
1900 | CRTC_VERTICAL_INTERRUPT0_LINE_START); | 1894 | CRTC_VERTICAL_INTERRUPT0_LINE_START); |
1901 | 1895 | ||
1902 | /* Set interaval width for interrupt to fire to 1 scanline */ | 1896 | /* Set interval width for interrupt to fire to 1 scanline */ |
1903 | set_reg_field_value( | 1897 | set_reg_field_value( |
1904 | val, | 1898 | val, |
1905 | vbl_start + width, | 1899 | v_blank_start + width, |
1906 | CRTC_VERTICAL_INTERRUPT0_POSITION, | 1900 | CRTC_VERTICAL_INTERRUPT0_POSITION, |
1907 | CRTC_VERTICAL_INTERRUPT0_LINE_END); | 1901 | CRTC_VERTICAL_INTERRUPT0_LINE_END); |
1908 | 1902 | ||
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h index ca387b40fc67..f14a4d91cd8e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h | |||
@@ -230,10 +230,12 @@ void dce110_timing_generator_set_static_screen_control( | |||
230 | struct timing_generator *tg, | 230 | struct timing_generator *tg, |
231 | uint32_t value); | 231 | uint32_t value); |
232 | 232 | ||
233 | uint32_t dce110_timing_generator_get_crtc_scanoutpos( | 233 | void dce110_timing_generator_get_crtc_scanoutpos( |
234 | struct timing_generator *tg, | 234 | struct timing_generator *tg, |
235 | uint32_t *vbl, | 235 | uint32_t *v_blank_start, |
236 | uint32_t *position); | 236 | uint32_t *v_blank_end, |
237 | uint32_t *h_position, | ||
238 | uint32_t *v_position); | ||
237 | 239 | ||
238 | void dce110_timing_generator_enable_advanced_request( | 240 | void dce110_timing_generator_enable_advanced_request( |
239 | struct timing_generator *tg, | 241 | struct timing_generator *tg, |
diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c index 95cb1768aeb5..1318df7ed47e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c | |||
@@ -576,24 +576,28 @@ void dce120_timing_generator_set_drr( | |||
576 | } | 576 | } |
577 | } | 577 | } |
578 | 578 | ||
579 | uint32_t dce120_timing_generator_get_crtc_scanoutpos( | 579 | void dce120_timing_generator_get_crtc_scanoutpos( |
580 | struct timing_generator *tg, | 580 | struct timing_generator *tg, |
581 | uint32_t *vbl, | 581 | uint32_t *v_blank_start, |
582 | uint32_t *position) | 582 | uint32_t *v_blank_end, |
583 | uint32_t *h_position, | ||
584 | uint32_t *v_position) | ||
583 | { | 585 | { |
584 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); | 586 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); |
585 | 587 | ||
586 | *vbl = dm_read_reg_soc15( | 588 | uint32_t v_blank_start_end = dm_read_reg_soc15( |
587 | tg->ctx, | 589 | tg->ctx, |
588 | mmCRTC0_CRTC_V_BLANK_START_END, | 590 | mmCRTC0_CRTC_V_BLANK_START_END, |
589 | tg110->offsets.crtc); | 591 | tg110->offsets.crtc); |
590 | 592 | ||
591 | *position = dm_read_reg_soc15( | 593 | *v_blank_start = get_reg_field_value(v_blank_start_end, |
592 | tg->ctx, | 594 | CRTC0_CRTC_V_BLANK_START_END, |
593 | mmCRTC0_CRTC_STATUS_POSITION, | 595 | CRTC_V_BLANK_START); |
594 | tg110->offsets.crtc); | 596 | *v_blank_end = get_reg_field_value(v_blank_start_end, |
597 | CRTC0_CRTC_V_BLANK_START_END, | ||
598 | CRTC_V_BLANK_END); | ||
595 | 599 | ||
596 | return 0; | 600 | dce120_timing_generator_get_crtc_positions(tg, h_position, v_position); |
597 | } | 601 | } |
598 | 602 | ||
599 | void dce120_timing_generator_enable_advanced_request( | 603 | void dce120_timing_generator_enable_advanced_request( |
@@ -1044,26 +1048,22 @@ static bool dce120_arm_vert_intr( | |||
1044 | uint8_t width) | 1048 | uint8_t width) |
1045 | { | 1049 | { |
1046 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); | 1050 | struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); |
1047 | uint32_t vbl, position, vbl_start; | 1051 | uint32_t v_blank_start, v_blank_end, h_position, v_position; |
1048 | 1052 | ||
1049 | tg->funcs->get_scanoutpos( | 1053 | tg->funcs->get_scanoutpos( |
1050 | tg, | 1054 | tg, |
1051 | &vbl, | 1055 | &v_blank_start, |
1052 | &position); | 1056 | &v_blank_end, |
1057 | &h_position, | ||
1058 | &v_position); | ||
1053 | 1059 | ||
1054 | if (vbl == 0) | 1060 | if (v_blank_start == 0 || v_blank_end == 0) |
1055 | return false; | 1061 | return false; |
1056 | 1062 | ||
1057 | vbl_start = | ||
1058 | get_reg_field_value( | ||
1059 | vbl, | ||
1060 | CRTC0_CRTC_V_BLANK_START_END, | ||
1061 | CRTC_V_BLANK_START); | ||
1062 | |||
1063 | CRTC_REG_SET_2( | 1063 | CRTC_REG_SET_2( |
1064 | CRTC0_CRTC_VERTICAL_INTERRUPT0_POSITION, | 1064 | CRTC0_CRTC_VERTICAL_INTERRUPT0_POSITION, |
1065 | CRTC_VERTICAL_INTERRUPT0_LINE_START, vbl_start, | 1065 | CRTC_VERTICAL_INTERRUPT0_LINE_START, v_blank_start, |
1066 | CRTC_VERTICAL_INTERRUPT0_LINE_END, vbl_start + width); | 1066 | CRTC_VERTICAL_INTERRUPT0_LINE_END, v_blank_start + width); |
1067 | 1067 | ||
1068 | return true; | 1068 | return true; |
1069 | } | 1069 | } |
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 51902a4f8798..b3deaf2d8173 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h | |||
@@ -120,10 +120,12 @@ struct timing_generator_funcs { | |||
120 | int32_t *h_position, | 120 | int32_t *h_position, |
121 | int32_t *v_position); | 121 | int32_t *v_position); |
122 | uint32_t (*get_frame_count)(struct timing_generator *tg); | 122 | uint32_t (*get_frame_count)(struct timing_generator *tg); |
123 | uint32_t (*get_scanoutpos)( | 123 | void (*get_scanoutpos)( |
124 | struct timing_generator *tg, | 124 | struct timing_generator *tg, |
125 | uint32_t *vbl, | 125 | uint32_t *v_blank_start, |
126 | uint32_t *position); | 126 | uint32_t *v_blank_end, |
127 | uint32_t *h_position, | ||
128 | uint32_t *v_position); | ||
127 | void (*set_early_control)(struct timing_generator *tg, | 129 | void (*set_early_control)(struct timing_generator *tg, |
128 | uint32_t early_cntl); | 130 | uint32_t early_cntl); |
129 | void (*wait_for_state)(struct timing_generator *tg, | 131 | void (*wait_for_state)(struct timing_generator *tg, |