Commit c81e13b9 authored by Alex Hung's avatar Alex Hung Committed by Alex Deucher

drm/amd/display: Hande writeback request from userspace

[WHAT]
Handle writeback requests and fill in the required information for DWB
programming and setup.
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Hung <alex.hung@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 1fb9d7b9
...@@ -416,6 +416,9 @@ struct amdgpu_crtc { ...@@ -416,6 +416,9 @@ struct amdgpu_crtc {
int otg_inst; int otg_inst;
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
bool wb_pending;
struct drm_writeback_connector *wb_conn;
}; };
struct amdgpu_encoder_atom_dig { struct amdgpu_encoder_atom_dig {
......
...@@ -578,6 +578,7 @@ static void dm_crtc_high_irq(void *interrupt_params) ...@@ -578,6 +578,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
{ {
struct common_irq_params *irq_params = interrupt_params; struct common_irq_params *irq_params = interrupt_params;
struct amdgpu_device *adev = irq_params->adev; struct amdgpu_device *adev = irq_params->adev;
struct drm_writeback_job *job;
struct amdgpu_crtc *acrtc; struct amdgpu_crtc *acrtc;
unsigned long flags; unsigned long flags;
int vrr_active; int vrr_active;
...@@ -586,6 +587,21 @@ static void dm_crtc_high_irq(void *interrupt_params) ...@@ -586,6 +587,21 @@ static void dm_crtc_high_irq(void *interrupt_params)
if (!acrtc) if (!acrtc)
return; return;
if (acrtc->wb_pending) {
if (acrtc->wb_conn) {
spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags);
job = list_first_entry_or_null(&acrtc->wb_conn->job_queue,
struct drm_writeback_job,
list_entry);
spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags);
if (job)
drm_writeback_signal_completion(acrtc->wb_conn, 0);
} else
DRM_ERROR("%s: no amdgpu_crtc wb_conn\n", __func__);
acrtc->wb_pending = false;
}
vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc);
drm_dbg_vbl(adev_to_drm(adev), drm_dbg_vbl(adev_to_drm(adev),
...@@ -8639,6 +8655,12 @@ static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_stat ...@@ -8639,6 +8655,12 @@ static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_stat
stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state); stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state);
} }
static void dm_clear_writeback(struct amdgpu_display_manager *dm,
struct dm_crtc_state *crtc_state)
{
dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0);
}
static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
struct dc_state *dc_state) struct dc_state *dc_state)
{ {
...@@ -8648,9 +8670,34 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, ...@@ -8648,9 +8670,34 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct drm_crtc_state *old_crtc_state, *new_crtc_state;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
struct drm_connector_state *old_con_state;
struct drm_connector *connector;
bool mode_set_reset_required = false; bool mode_set_reset_required = false;
u32 i; u32 i;
/* Disable writeback */
for_each_old_connector_in_state(state, connector, old_con_state, i) {
struct dm_connector_state *dm_old_con_state;
struct amdgpu_crtc *acrtc;
if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
continue;
old_crtc_state = NULL;
dm_old_con_state = to_dm_connector_state(old_con_state);
if (!dm_old_con_state->base.crtc)
continue;
acrtc = to_amdgpu_crtc(dm_old_con_state->base.crtc);
if (acrtc)
old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base);
dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
dm_clear_writeback(dm, dm_old_crtc_state);
}
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
new_crtc_state, i) { new_crtc_state, i) {
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
...@@ -8787,6 +8834,97 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, ...@@ -8787,6 +8834,97 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
} }
} }
static void dm_set_writeback(struct amdgpu_display_manager *dm,
struct dm_crtc_state *crtc_state,
struct drm_connector *connector,
struct drm_connector_state *new_con_state)
{
struct drm_writeback_connector *wb_conn = drm_connector_to_writeback(connector);
struct amdgpu_crtc *acrtc;
struct dc_writeback_info *wb_info;
struct pipe_ctx *pipe = NULL;
struct amdgpu_framebuffer *afb;
int i = 0;
wb_info = kzalloc(sizeof(*wb_info), GFP_KERNEL);
if (!wb_info) {
DRM_ERROR("Failed to allocate wb_info\n");
return;
}
acrtc = to_amdgpu_crtc(wb_conn->encoder.crtc);
if (!acrtc) {
DRM_ERROR("no amdgpu_crtc found\n");
return;
}
afb = to_amdgpu_framebuffer(new_con_state->writeback_job->fb);
if (!afb) {
DRM_ERROR("No amdgpu_framebuffer found\n");
return;
}
for (i = 0; i < MAX_PIPES; i++) {
if (dm->dc->current_state->res_ctx.pipe_ctx[i].stream == crtc_state->stream) {
pipe = &dm->dc->current_state->res_ctx.pipe_ctx[i];
break;
}
}
/* fill in wb_info */
wb_info->wb_enabled = true;
wb_info->dwb_pipe_inst = 0;
wb_info->dwb_params.dwbscl_black_color = 0;
wb_info->dwb_params.hdr_mult = 0x1F000;
wb_info->dwb_params.csc_params.gamut_adjust_type = CM_GAMUT_ADJUST_TYPE_BYPASS;
wb_info->dwb_params.csc_params.gamut_coef_format = CM_GAMUT_REMAP_COEF_FORMAT_S2_13;
wb_info->dwb_params.output_depth = DWB_OUTPUT_PIXEL_DEPTH_10BPC;
wb_info->dwb_params.cnv_params.cnv_out_bpc = DWB_CNV_OUT_BPC_10BPC;
/* width & height from crtc */
wb_info->dwb_params.cnv_params.src_width = acrtc->base.mode.crtc_hdisplay;
wb_info->dwb_params.cnv_params.src_height = acrtc->base.mode.crtc_vdisplay;
wb_info->dwb_params.dest_width = acrtc->base.mode.crtc_hdisplay;
wb_info->dwb_params.dest_height = acrtc->base.mode.crtc_vdisplay;
wb_info->dwb_params.cnv_params.crop_en = false;
wb_info->dwb_params.stereo_params.stereo_enabled = false;
wb_info->dwb_params.cnv_params.out_max_pix_val = 0x3ff; // 10 bits
wb_info->dwb_params.cnv_params.out_min_pix_val = 0;
wb_info->dwb_params.cnv_params.fc_out_format = DWB_OUT_FORMAT_32BPP_ARGB;
wb_info->dwb_params.cnv_params.out_denorm_mode = DWB_OUT_DENORM_BYPASS;
wb_info->dwb_params.out_format = dwb_scaler_mode_bypass444;
wb_info->dwb_params.capture_rate = dwb_capture_rate_0;
wb_info->dwb_params.scaler_taps.h_taps = 4;
wb_info->dwb_params.scaler_taps.v_taps = 4;
wb_info->dwb_params.scaler_taps.h_taps_c = 2;
wb_info->dwb_params.scaler_taps.v_taps_c = 2;
wb_info->dwb_params.subsample_position = DWB_INTERSTITIAL_SUBSAMPLING;
wb_info->mcif_buf_params.luma_pitch = afb->base.pitches[0];
wb_info->mcif_buf_params.chroma_pitch = afb->base.pitches[1];
for (i = 0; i < DWB_MCIF_BUF_COUNT; i++) {
wb_info->mcif_buf_params.luma_address[i] = afb->address;
wb_info->mcif_buf_params.chroma_address[i] = 0;
}
wb_info->mcif_buf_params.p_vmid = 1;
wb_info->mcif_warmup_params.p_vmid = 1;
wb_info->writeback_source_plane = pipe->plane_state;
dc_stream_add_writeback(dm->dc, crtc_state->stream, wb_info);
acrtc->wb_pending = true;
acrtc->wb_conn = wb_conn;
drm_writeback_queue_job(wb_conn, new_con_state);
}
/** /**
* amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation. * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation.
* @state: The atomic state to commit * @state: The atomic state to commit
...@@ -9119,6 +9257,27 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) ...@@ -9119,6 +9257,27 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
amdgpu_dm_commit_planes(state, dev, dm, crtc, wait_for_vblank); amdgpu_dm_commit_planes(state, dev, dm, crtc, wait_for_vblank);
} }
/* Enable writeback */
for_each_new_connector_in_state(state, connector, new_con_state, i) {
struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
continue;
if (!new_con_state->writeback_job)
continue;
new_crtc_state = NULL;
if (acrtc)
new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
dm_set_writeback(dm, dm_new_crtc_state, connector, new_con_state);
}
/* Update audio instances for each connector. */ /* Update audio instances for each connector. */
amdgpu_dm_commit_audio(dev, state); amdgpu_dm_commit_audio(dev, state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment