Commit 9a65df19 authored by Wayne Lin's avatar Wayne Lin Committed by Alex Deucher

drm/amd/display: Use PSP TA to read out crc

[Why & How]
To read back crc by sending command READ_ROI_CRC to
PSP TA to ask it to read out crc of crc window.
Signed-off-by: default avatarWayne Lin <Wayne.Lin@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: default avatarEryk Brol <eryk.brol@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 21cd403e
......@@ -1178,6 +1178,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
dc_init_callbacks(adev->dm.dc, &init_params);
}
#endif
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
adev->dm.crc_rd_wrk = amdgpu_dm_crtc_secure_display_create_work();
#endif
if (amdgpu_dm_initialize_drm_device(adev)) {
DRM_ERROR(
......@@ -1222,6 +1225,13 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
amdgpu_dm_destroy_drm_device(&adev->dm);
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
if (adev->dm.crc_rd_wrk) {
flush_work(&adev->dm.crc_rd_wrk->notify_ta_work);
kfree(adev->dm.crc_rd_wrk);
adev->dm.crc_rd_wrk = NULL;
}
#endif
#ifdef CONFIG_DRM_AMD_DC_HDCP
if (adev->dm.hdcp_workqueue) {
hdcp_destroy(&adev->dev->kobj, adev->dm.hdcp_workqueue);
......@@ -1887,6 +1897,9 @@ static int dm_suspend(void *handle)
return ret;
}
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
amdgpu_dm_crtc_secure_display_suspend(adev);
#endif
WARN_ON(adev->dm.cached_state);
adev->dm.cached_state = drm_atomic_helper_suspend(adev_to_drm(adev));
......@@ -2211,6 +2224,10 @@ static int dm_resume(void *handle)
dm->cached_state = NULL;
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
amdgpu_dm_crtc_secure_display_resume(adev);
#endif
amdgpu_dm_irq_resume_late(adev);
amdgpu_dm_smu_write_watermarks_table(adev);
......
......@@ -366,6 +366,9 @@ struct amdgpu_display_manager {
* number of currently active vblank irqs
*/
uint32_t active_vblank_irq_count;
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
struct crc_rd_work *crc_rd_wrk;
#endif
/**
* @mst_encoders:
......
......@@ -29,6 +29,7 @@
#include "amdgpu.h"
#include "amdgpu_dm.h"
#include "dc.h"
#include "amdgpu_securedisplay.h"
static const char *const pipe_crc_sources[] = {
"none",
......@@ -94,9 +95,46 @@ static void amdgpu_dm_set_crc_window_default(struct drm_crtc *crtc)
acrtc->dm_irq_params.crc_window.y_end = 0;
acrtc->dm_irq_params.crc_window.activated = false;
acrtc->dm_irq_params.crc_window.update_win = false;
acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
spin_unlock_irq(&drm_dev->event_lock);
}
static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work)
{
struct crc_rd_work *crc_rd_wrk;
struct amdgpu_device *adev;
struct psp_context *psp;
struct securedisplay_cmd *securedisplay_cmd;
struct drm_crtc *crtc;
uint8_t phy_id;
int ret;
crc_rd_wrk = container_of(work, struct crc_rd_work, notify_ta_work);
spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
crtc = crc_rd_wrk->crtc;
if (!crtc) {
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
return;
}
adev = drm_to_adev(crtc->dev);
psp = &adev->psp;
phy_id = crc_rd_wrk->phy_inst;
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id =
phy_id;
ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
if (!ret) {
if (securedisplay_cmd->status != TA_SECUREDISPLAY_STATUS__SUCCESS) {
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
}
}
}
bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc)
{
struct drm_device *drm_dev = crtc->dev;
......@@ -144,6 +182,20 @@ int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
/* Enable CRTC CRC generation if necessary. */
if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
if (!enable) {
if (adev->dm.crc_rd_wrk) {
flush_work(&adev->dm.crc_rd_wrk->notify_ta_work);
spin_lock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock);
if (adev->dm.crc_rd_wrk->crtc == crtc) {
dc_stream_stop_dmcu_crc_win_update(stream_state->ctx->dc,
dm_crtc_state->stream);
adev->dm.crc_rd_wrk->crtc = NULL;
}
spin_unlock_irq(&adev->dm.crc_rd_wrk->crc_rd_work_lock);
}
}
#endif
if (!dc_stream_configure_crc(stream_state->ctx->dc,
stream_state, NULL, enable, enable)) {
ret = -EINVAL;
......@@ -378,18 +430,27 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
struct drm_device *drm_dev = NULL;
enum amdgpu_dm_pipe_crc_source cur_crc_src;
struct amdgpu_crtc *acrtc = NULL;
struct amdgpu_device *adev = NULL;
struct crc_rd_work *crc_rd_wrk = NULL;
struct crc_params *crc_window = NULL, tmp_window;
unsigned long flags;
struct crtc_position position;
uint32_t v_blank;
uint32_t v_back_porch;
uint32_t crc_window_latch_up_line;
struct dc_crtc_timing *timing_out;
if (crtc == NULL)
return;
acrtc = to_amdgpu_crtc(crtc);
adev = drm_to_adev(crtc->dev);
drm_dev = crtc->dev;
spin_lock_irqsave(&drm_dev->event_lock, flags);
stream_state = acrtc->dm_irq_params.stream;
cur_crc_src = acrtc->dm_irq_params.crc_src;
timing_out = &stream_state->timing;
/* Early return if CRC capture is not enabled. */
if (!amdgpu_dm_is_valid_crc_source(cur_crc_src))
......@@ -398,6 +459,10 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
if (dm_is_crc_source_crtc(cur_crc_src)) {
if (acrtc->dm_irq_params.crc_window.activated) {
if (acrtc->dm_irq_params.crc_window.update_win) {
if (acrtc->dm_irq_params.crc_window.skip_frame_cnt) {
acrtc->dm_irq_params.crc_window.skip_frame_cnt -= 1;
goto cleanup;
}
crc_window = &tmp_window;
tmp_window.windowa_x_start =
......@@ -421,6 +486,37 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
stream_state, crc_window);
acrtc->dm_irq_params.crc_window.update_win = false;
dc_stream_get_crtc_position(stream_state->ctx->dc, &stream_state, 1,
&position.vertical_count,
&position.nominal_vcount);
v_blank = timing_out->v_total - timing_out->v_border_top -
timing_out->v_addressable - timing_out->v_border_bottom;
v_back_porch = v_blank - timing_out->v_front_porch -
timing_out->v_sync_width;
crc_window_latch_up_line = v_back_porch + timing_out->v_sync_width;
/* take 3 lines margin*/
if ((position.vertical_count + 3) >= crc_window_latch_up_line)
acrtc->dm_irq_params.crc_window.skip_frame_cnt = 1;
else
acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
} else {
if (acrtc->dm_irq_params.crc_window.skip_frame_cnt == 0) {
if (adev->dm.crc_rd_wrk) {
crc_rd_wrk = adev->dm.crc_rd_wrk;
spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
crc_rd_wrk->phy_inst =
stream_state->link->link_enc_hw_inst;
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
schedule_work(&crc_rd_wrk->notify_ta_work);
}
} else {
acrtc->dm_irq_params.crc_window.skip_frame_cnt -= 1;
}
}
}
}
......@@ -428,4 +524,80 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
cleanup:
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
}
void amdgpu_dm_crtc_secure_display_resume(struct amdgpu_device *adev)
{
struct drm_crtc *crtc;
enum amdgpu_dm_pipe_crc_source cur_crc_src;
struct crc_rd_work *crc_rd_wrk = adev->dm.crc_rd_wrk;
struct crc_window_parm cur_crc_window;
struct amdgpu_crtc *acrtc = NULL;
drm_for_each_crtc(crtc, &adev->ddev) {
acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&adev_to_drm(adev)->event_lock);
cur_crc_src = acrtc->dm_irq_params.crc_src;
cur_crc_window = acrtc->dm_irq_params.crc_window;
spin_unlock_irq(&adev_to_drm(adev)->event_lock);
if (amdgpu_dm_is_valid_crc_source(cur_crc_src)) {
amdgpu_dm_crtc_set_crc_source(crtc,
pipe_crc_sources[cur_crc_src]);
spin_lock_irq(&adev_to_drm(adev)->event_lock);
acrtc->dm_irq_params.crc_window = cur_crc_window;
if (acrtc->dm_irq_params.crc_window.activated) {
acrtc->dm_irq_params.crc_window.update_win = true;
acrtc->dm_irq_params.crc_window.skip_frame_cnt = 1;
spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
crc_rd_wrk->crtc = crtc;
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
}
spin_unlock_irq(&adev_to_drm(adev)->event_lock);
}
}
}
void amdgpu_dm_crtc_secure_display_suspend(struct amdgpu_device *adev)
{
struct drm_crtc *crtc;
struct crc_window_parm cur_crc_window;
enum amdgpu_dm_pipe_crc_source cur_crc_src;
struct amdgpu_crtc *acrtc = NULL;
drm_for_each_crtc(crtc, &adev->ddev) {
acrtc = to_amdgpu_crtc(crtc);
spin_lock_irq(&adev_to_drm(adev)->event_lock);
cur_crc_src = acrtc->dm_irq_params.crc_src;
cur_crc_window = acrtc->dm_irq_params.crc_window;
cur_crc_window.update_win = false;
spin_unlock_irq(&adev_to_drm(adev)->event_lock);
if (amdgpu_dm_is_valid_crc_source(cur_crc_src)) {
amdgpu_dm_crtc_set_crc_source(crtc, NULL);
spin_lock_irq(&adev_to_drm(adev)->event_lock);
/* For resume to set back crc source*/
acrtc->dm_irq_params.crc_src = cur_crc_src;
acrtc->dm_irq_params.crc_window = cur_crc_window;
spin_unlock_irq(&adev_to_drm(adev)->event_lock);
}
}
}
struct crc_rd_work *amdgpu_dm_crtc_secure_display_create_work(void)
{
struct crc_rd_work *crc_rd_wrk = NULL;
crc_rd_wrk = kzalloc(sizeof(*crc_rd_wrk), GFP_KERNEL);
if (!crc_rd_wrk)
return NULL;
spin_lock_init(&crc_rd_wrk->crc_rd_work_lock);
INIT_WORK(&crc_rd_wrk->notify_ta_work, amdgpu_dm_crtc_notify_ta_to_read);
return crc_rd_wrk;
}
#endif
......@@ -49,6 +49,16 @@ struct crc_window_parm {
bool activated;
/* Update crc window during vertical blank or not */
bool update_win;
/* skip reading/writing for few frames */
int skip_frame_cnt;
};
struct crc_rd_work {
struct work_struct notify_ta_work;
/* To protect crc_rd_work carried fields*/
spinlock_t crc_rd_work_lock;
struct drm_crtc *crtc;
uint8_t phy_inst;
};
#endif
......@@ -80,9 +90,15 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc);
#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc);
void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc);
struct crc_rd_work *amdgpu_dm_crtc_secure_display_create_work(void);
void amdgpu_dm_crtc_secure_display_resume(struct amdgpu_device *adev);
void amdgpu_dm_crtc_secure_display_suspend(struct amdgpu_device *adev);
#else
#define amdgpu_dm_crc_window_is_activated(x)
#define amdgpu_dm_crtc_handle_crc_window_irq(x)
#define amdgpu_dm_crtc_secure_display_create_work()
#define amdgpu_dm_crtc_secure_display_resume(x)
#define amdgpu_dm_crtc_secure_display_suspend(x)
#endif
#endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */
......@@ -2688,15 +2688,40 @@ DEFINE_DEBUGFS_ATTRIBUTE(crc_win_y_end_fops, crc_win_y_end_get,
*/
static int crc_win_update_set(void *data, u64 val)
{
struct drm_crtc *crtc = data;
struct drm_device *drm_dev = crtc->dev;
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
struct drm_crtc *new_crtc = data;
struct drm_crtc *old_crtc = NULL;
struct amdgpu_crtc *new_acrtc, *old_acrtc;
struct amdgpu_device *adev = drm_to_adev(new_crtc->dev);
struct crc_rd_work *crc_rd_wrk = adev->dm.crc_rd_wrk;
if (val) {
spin_lock_irq(&drm_dev->event_lock);
acrtc->dm_irq_params.crc_window.activated = true;
acrtc->dm_irq_params.crc_window.update_win = true;
spin_unlock_irq(&drm_dev->event_lock);
spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
spin_lock_irq(&adev_to_drm(adev)->event_lock);
if (crc_rd_wrk && crc_rd_wrk->crtc) {
old_crtc = crc_rd_wrk->crtc;
old_acrtc = to_amdgpu_crtc(old_crtc);
flush_work(&adev->dm.crc_rd_wrk->notify_ta_work);
}
new_acrtc = to_amdgpu_crtc(new_crtc);
if (old_crtc && old_crtc != new_crtc) {
old_acrtc->dm_irq_params.crc_window.activated = false;
old_acrtc->dm_irq_params.crc_window.update_win = false;
old_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
new_acrtc->dm_irq_params.crc_window.activated = true;
new_acrtc->dm_irq_params.crc_window.update_win = true;
new_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
crc_rd_wrk->crtc = new_crtc;
} else {
new_acrtc->dm_irq_params.crc_window.activated = true;
new_acrtc->dm_irq_params.crc_window.update_win = true;
new_acrtc->dm_irq_params.crc_window.skip_frame_cnt = 0;
crc_rd_wrk->crtc = new_crtc;
}
spin_unlock_irq(&adev_to_drm(adev)->event_lock);
spin_unlock_irq(&crc_rd_wrk->crc_rd_work_lock);
}
return 0;
......
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