Skip to content

Commit

Permalink
drm/amd/display: Add support to configure CRC window on specific CRC …
Browse files Browse the repository at this point in the history
…instance

[Why]
Have the need to specify the CRC window on specific CRC engine.
dc_stream_configure_crc() today calculates CRC on crc engine 0 only and always
resets CRC engine at first.

[How]
Add index parameter to dc_stream_configure_crc() for selecting the desired crc
engine. Additionally, add another parameter to specify whether to skip the
default reset of crc engine.

Reviewed-by: HaoPing Liu <haoping.liu@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Wayne Lin authored and Alex Deucher committed Jan 10, 2025
1 parent 4a9a918 commit b6fcc38
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 137 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
/* Enable or disable CRTC CRC generation */
if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
if (!dc_stream_configure_crc(stream_state->ctx->dc,
stream_state, NULL, enable, enable)) {
stream_state, NULL, enable, enable, 0, true)) {
ret = -EINVAL;
goto unlock;
}
Expand Down
11 changes: 8 additions & 3 deletions drivers/gpu/drm/amd/display/dc/core/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -687,15 +687,17 @@ dc_stream_forward_multiple_crc_window(struct dc_stream_state *stream,
* @enable: Enable CRC if true, disable otherwise.
* @continuous: Capture CRC on every frame if true. Otherwise, only capture
* once.
* @idx: Capture CRC on which CRC engine instance
* @reset: Reset CRC engine before the configuration
*
* By default, only CRC0 is configured, and the entire frame is used to
* calculate the CRC.
* By default, the entire frame is used to calculate the CRC.
*
* Return: %false if the stream is not found or CRC capture is not supported;
* %true if the stream has been configured.
*/
bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
struct crc_params *crc_window, bool enable, bool continuous)
struct crc_params *crc_window, bool enable, bool continuous,
uint8_t idx, bool reset)
{
struct pipe_ctx *pipe;
struct crc_params param;
Expand Down Expand Up @@ -739,6 +741,9 @@ bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
param.continuous_mode = continuous;
param.enable = enable;

param.crc_eng_inst = idx;
param.reset = reset;

tg = pipe->stream_res.tg;

/* Only call if supported */
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/amd/display/dc/dc_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,9 @@ bool dc_stream_configure_crc(struct dc *dc,
struct dc_stream_state *stream,
struct crc_params *crc_window,
bool enable,
bool continuous);
bool continuous,
uint8_t idx,
bool reset);

bool dc_stream_get_crc(struct dc *dc,
struct dc_stream_state *stream,
Expand Down
169 changes: 115 additions & 54 deletions drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -2127,65 +2127,126 @@ bool dce110_configure_crc(struct timing_generator *tg,

cntl_addr = CRTC_REG(mmCRTC_CRC_CNTL);

/* First, disable CRC before we configure it. */
dm_write_reg(tg->ctx, cntl_addr, 0);
if (!params->enable || params->reset)
/* First, disable CRC before we configure it. */
dm_write_reg(tg->ctx, cntl_addr, 0);

if (!params->enable)
return true;

/* Program frame boundaries */
/* Window A x axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_X_CONTROL);
set_reg_field_value(value, params->windowa_x_start,
CRTC_CRC0_WINDOWA_X_CONTROL,
CRTC_CRC0_WINDOWA_X_START);
set_reg_field_value(value, params->windowa_x_end,
CRTC_CRC0_WINDOWA_X_CONTROL,
CRTC_CRC0_WINDOWA_X_END);
dm_write_reg(tg->ctx, addr, value);

/* Window A y axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_Y_CONTROL);
set_reg_field_value(value, params->windowa_y_start,
CRTC_CRC0_WINDOWA_Y_CONTROL,
CRTC_CRC0_WINDOWA_Y_START);
set_reg_field_value(value, params->windowa_y_end,
CRTC_CRC0_WINDOWA_Y_CONTROL,
CRTC_CRC0_WINDOWA_Y_END);
dm_write_reg(tg->ctx, addr, value);

/* Window B x axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_X_CONTROL);
set_reg_field_value(value, params->windowb_x_start,
CRTC_CRC0_WINDOWB_X_CONTROL,
CRTC_CRC0_WINDOWB_X_START);
set_reg_field_value(value, params->windowb_x_end,
CRTC_CRC0_WINDOWB_X_CONTROL,
CRTC_CRC0_WINDOWB_X_END);
dm_write_reg(tg->ctx, addr, value);

/* Window B y axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_Y_CONTROL);
set_reg_field_value(value, params->windowb_y_start,
CRTC_CRC0_WINDOWB_Y_CONTROL,
CRTC_CRC0_WINDOWB_Y_START);
set_reg_field_value(value, params->windowb_y_end,
CRTC_CRC0_WINDOWB_Y_CONTROL,
CRTC_CRC0_WINDOWB_Y_END);
dm_write_reg(tg->ctx, addr, value);

/* Set crc mode and selection, and enable. Only using CRC0*/
value = 0;
set_reg_field_value(value, params->continuous_mode ? 1 : 0,
CRTC_CRC_CNTL, CRTC_CRC_CONT_EN);
set_reg_field_value(value, params->selection,
CRTC_CRC_CNTL, CRTC_CRC0_SELECT);
set_reg_field_value(value, 1, CRTC_CRC_CNTL, CRTC_CRC_EN);
dm_write_reg(tg->ctx, cntl_addr, value);
switch (params->crc_eng_inst) {
case 0:
/* Window A x axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_X_CONTROL);
set_reg_field_value(value, params->windowa_x_start,
CRTC_CRC0_WINDOWA_X_CONTROL,
CRTC_CRC0_WINDOWA_X_START);
set_reg_field_value(value, params->windowa_x_end,
CRTC_CRC0_WINDOWA_X_CONTROL,
CRTC_CRC0_WINDOWA_X_END);
dm_write_reg(tg->ctx, addr, value);

/* Window A y axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWA_Y_CONTROL);
set_reg_field_value(value, params->windowa_y_start,
CRTC_CRC0_WINDOWA_Y_CONTROL,
CRTC_CRC0_WINDOWA_Y_START);
set_reg_field_value(value, params->windowa_y_end,
CRTC_CRC0_WINDOWA_Y_CONTROL,
CRTC_CRC0_WINDOWA_Y_END);
dm_write_reg(tg->ctx, addr, value);

/* Window B x axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_X_CONTROL);
set_reg_field_value(value, params->windowb_x_start,
CRTC_CRC0_WINDOWB_X_CONTROL,
CRTC_CRC0_WINDOWB_X_START);
set_reg_field_value(value, params->windowb_x_end,
CRTC_CRC0_WINDOWB_X_CONTROL,
CRTC_CRC0_WINDOWB_X_END);
dm_write_reg(tg->ctx, addr, value);

/* Window B y axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC0_WINDOWB_Y_CONTROL);
set_reg_field_value(value, params->windowb_y_start,
CRTC_CRC0_WINDOWB_Y_CONTROL,
CRTC_CRC0_WINDOWB_Y_START);
set_reg_field_value(value, params->windowb_y_end,
CRTC_CRC0_WINDOWB_Y_CONTROL,
CRTC_CRC0_WINDOWB_Y_END);
dm_write_reg(tg->ctx, addr, value);

/* Set crc mode and selection, and enable.*/
value = 0;
set_reg_field_value(value, params->continuous_mode ? 1 : 0,
CRTC_CRC_CNTL, CRTC_CRC_CONT_EN);
set_reg_field_value(value, params->selection,
CRTC_CRC_CNTL, CRTC_CRC0_SELECT);
set_reg_field_value(value, 1, CRTC_CRC_CNTL, CRTC_CRC_EN);
dm_write_reg(tg->ctx, cntl_addr, value);
break;
case 1:
/* Window A x axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC1_WINDOWA_X_CONTROL);
set_reg_field_value(value, params->windowa_x_start,
CRTC_CRC1_WINDOWA_X_CONTROL,
CRTC_CRC1_WINDOWA_X_START);
set_reg_field_value(value, params->windowa_x_end,
CRTC_CRC1_WINDOWA_X_CONTROL,
CRTC_CRC1_WINDOWA_X_END);
dm_write_reg(tg->ctx, addr, value);

/* Window A y axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC1_WINDOWA_Y_CONTROL);
set_reg_field_value(value, params->windowa_y_start,
CRTC_CRC1_WINDOWA_Y_CONTROL,
CRTC_CRC1_WINDOWA_Y_START);
set_reg_field_value(value, params->windowa_y_end,
CRTC_CRC1_WINDOWA_Y_CONTROL,
CRTC_CRC1_WINDOWA_Y_END);
dm_write_reg(tg->ctx, addr, value);

/* Window B x axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC1_WINDOWB_X_CONTROL);
set_reg_field_value(value, params->windowb_x_start,
CRTC_CRC1_WINDOWB_X_CONTROL,
CRTC_CRC1_WINDOWB_X_START);
set_reg_field_value(value, params->windowb_x_end,
CRTC_CRC1_WINDOWB_X_CONTROL,
CRTC_CRC1_WINDOWB_X_END);
dm_write_reg(tg->ctx, addr, value);

/* Window B y axis start and end. */
value = 0;
addr = CRTC_REG(mmCRTC_CRC1_WINDOWB_Y_CONTROL);
set_reg_field_value(value, params->windowb_y_start,
CRTC_CRC1_WINDOWB_Y_CONTROL,
CRTC_CRC1_WINDOWB_Y_START);
set_reg_field_value(value, params->windowb_y_end,
CRTC_CRC1_WINDOWB_Y_CONTROL,
CRTC_CRC1_WINDOWB_Y_END);
dm_write_reg(tg->ctx, addr, value);

/* Set crc mode and selection, and enable.*/
value = 0;
set_reg_field_value(value, params->continuous_mode ? 1 : 0,
CRTC_CRC_CNTL, CRTC_CRC_CONT_EN);
set_reg_field_value(value, params->selection,
CRTC_CRC_CNTL, CRTC_CRC1_SELECT);
set_reg_field_value(value, 1, CRTC_CRC_CNTL, CRTC_CRC_EN);
dm_write_reg(tg->ctx, cntl_addr, value);
break;
default:
return false;
}

return true;
}
Expand Down
90 changes: 62 additions & 28 deletions drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -1100,39 +1100,73 @@ static bool dce120_configure_crc(struct timing_generator *tg,
if (!dce120_is_tg_enabled(tg))
return false;

/* First, disable CRC before we configure it. */
dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL,
tg110->offsets.crtc, 0);
if (!params->enable || params->reset)
/* First, disable CRC before we configure it. */
dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL,
tg110->offsets.crtc, 0);

if (!params->enable)
return true;

/* Program frame boundaries */
/* Window A x axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_X_CONTROL,
CRTC_CRC0_WINDOWA_X_START, params->windowa_x_start,
CRTC_CRC0_WINDOWA_X_END, params->windowa_x_end);

/* Window A y axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_Y_CONTROL,
CRTC_CRC0_WINDOWA_Y_START, params->windowa_y_start,
CRTC_CRC0_WINDOWA_Y_END, params->windowa_y_end);

/* Window B x axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_X_CONTROL,
CRTC_CRC0_WINDOWB_X_START, params->windowb_x_start,
CRTC_CRC0_WINDOWB_X_END, params->windowb_x_end);

/* Window B y axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_Y_CONTROL,
CRTC_CRC0_WINDOWB_Y_START, params->windowb_y_start,
CRTC_CRC0_WINDOWB_Y_END, params->windowb_y_end);

/* Set crc mode and selection, and enable. Only using CRC0*/
CRTC_REG_UPDATE_3(CRTC0_CRTC_CRC_CNTL,
CRTC_CRC_EN, params->continuous_mode ? 1 : 0,
CRTC_CRC0_SELECT, params->selection,
CRTC_CRC_EN, 1);
switch (params->crc_eng_inst) {
case 0:
/* Window A x axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_X_CONTROL,
CRTC_CRC0_WINDOWA_X_START, params->windowa_x_start,
CRTC_CRC0_WINDOWA_X_END, params->windowa_x_end);

/* Window A y axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_Y_CONTROL,
CRTC_CRC0_WINDOWA_Y_START, params->windowa_y_start,
CRTC_CRC0_WINDOWA_Y_END, params->windowa_y_end);

/* Window B x axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_X_CONTROL,
CRTC_CRC0_WINDOWB_X_START, params->windowb_x_start,
CRTC_CRC0_WINDOWB_X_END, params->windowb_x_end);

/* Window B y axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_Y_CONTROL,
CRTC_CRC0_WINDOWB_Y_START, params->windowb_y_start,
CRTC_CRC0_WINDOWB_Y_END, params->windowb_y_end);

/* Set crc mode and selection, and enable.*/
CRTC_REG_UPDATE_3(CRTC0_CRTC_CRC_CNTL,
CRTC_CRC_CONT_EN, params->continuous_mode ? 1 : 0,
CRTC_CRC0_SELECT, params->selection,
CRTC_CRC_EN, 1);
break;
case 1:
/* Window A x axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC1_WINDOWA_X_CONTROL,
CRTC_CRC1_WINDOWA_X_START, params->windowa_x_start,
CRTC_CRC1_WINDOWA_X_END, params->windowa_x_end);

/* Window A y axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC1_WINDOWA_Y_CONTROL,
CRTC_CRC1_WINDOWA_Y_START, params->windowa_y_start,
CRTC_CRC1_WINDOWA_Y_END, params->windowa_y_end);

/* Window B x axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC1_WINDOWB_X_CONTROL,
CRTC_CRC1_WINDOWB_X_START, params->windowb_x_start,
CRTC_CRC1_WINDOWB_X_END, params->windowb_x_end);

/* Window B y axis start and end. */
CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC1_WINDOWB_Y_CONTROL,
CRTC_CRC1_WINDOWB_Y_START, params->windowb_y_start,
CRTC_CRC1_WINDOWB_Y_END, params->windowb_y_end);

/* Set crc mode and selection, and enable */
CRTC_REG_UPDATE_3(CRTC0_CRTC_CRC_CNTL,
CRTC_CRC_CONT_EN, params->continuous_mode ? 1 : 0,
CRTC_CRC1_SELECT, params->selection,
CRTC_CRC_EN, 1);
break;
default:
return false;
}

return true;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ struct crc_params {

bool continuous_mode;
bool enable;

uint8_t crc_eng_inst;
bool reset;
};

/**
Expand Down
Loading

0 comments on commit b6fcc38

Please sign in to comment.