131aec354SLeo (Sunpeng) Li /*
231aec354SLeo (Sunpeng) Li * Copyright 2015 Advanced Micro Devices, Inc.
331aec354SLeo (Sunpeng) Li *
431aec354SLeo (Sunpeng) Li * Permission is hereby granted, free of charge, to any person obtaining a
531aec354SLeo (Sunpeng) Li * copy of this software and associated documentation files (the "Software"),
631aec354SLeo (Sunpeng) Li * to deal in the Software without restriction, including without limitation
731aec354SLeo (Sunpeng) Li * the rights to use, copy, modify, merge, publish, distribute, sublicense,
831aec354SLeo (Sunpeng) Li * and/or sell copies of the Software, and to permit persons to whom the
931aec354SLeo (Sunpeng) Li * Software is furnished to do so, subject to the following conditions:
1031aec354SLeo (Sunpeng) Li *
1131aec354SLeo (Sunpeng) Li * The above copyright notice and this permission notice shall be included in
1231aec354SLeo (Sunpeng) Li * all copies or substantial portions of the Software.
1331aec354SLeo (Sunpeng) Li *
1431aec354SLeo (Sunpeng) Li * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1531aec354SLeo (Sunpeng) Li * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1631aec354SLeo (Sunpeng) Li * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1731aec354SLeo (Sunpeng) Li * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1831aec354SLeo (Sunpeng) Li * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1931aec354SLeo (Sunpeng) Li * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2031aec354SLeo (Sunpeng) Li * OTHER DEALINGS IN THE SOFTWARE.
2131aec354SLeo (Sunpeng) Li *
2231aec354SLeo (Sunpeng) Li * Authors: AMD
2331aec354SLeo (Sunpeng) Li *
2431aec354SLeo (Sunpeng) Li */
2531aec354SLeo (Sunpeng) Li
2631aec354SLeo (Sunpeng) Li #include <drm/drm_crtc.h>
27f867723bSSam Ravnborg #include <drm/drm_vblank.h>
2831aec354SLeo (Sunpeng) Li
2931aec354SLeo (Sunpeng) Li #include "amdgpu.h"
3031aec354SLeo (Sunpeng) Li #include "amdgpu_dm.h"
3131aec354SLeo (Sunpeng) Li #include "dc.h"
329a65df19SWayne Lin #include "amdgpu_securedisplay.h"
3331aec354SLeo (Sunpeng) Li
348fb843d1SDingchen Zhang static const char *const pipe_crc_sources[] = {
358fb843d1SDingchen Zhang "none",
368fb843d1SDingchen Zhang "crtc",
37f1cdc98fSDingchen Zhang "crtc dither",
388fb843d1SDingchen Zhang "dprx",
39f1cdc98fSDingchen Zhang "dprx dither",
408fb843d1SDingchen Zhang "auto",
418fb843d1SDingchen Zhang };
428fb843d1SDingchen Zhang
dm_parse_crc_source(const char * source)4331aec354SLeo (Sunpeng) Li static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source)
4431aec354SLeo (Sunpeng) Li {
4531aec354SLeo (Sunpeng) Li if (!source || !strcmp(source, "none"))
4631aec354SLeo (Sunpeng) Li return AMDGPU_DM_PIPE_CRC_SOURCE_NONE;
4714b25846SDingchen Zhang if (!strcmp(source, "auto") || !strcmp(source, "crtc"))
4814b25846SDingchen Zhang return AMDGPU_DM_PIPE_CRC_SOURCE_CRTC;
4914b25846SDingchen Zhang if (!strcmp(source, "dprx"))
5014b25846SDingchen Zhang return AMDGPU_DM_PIPE_CRC_SOURCE_DPRX;
51f1cdc98fSDingchen Zhang if (!strcmp(source, "crtc dither"))
52f1cdc98fSDingchen Zhang return AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER;
53f1cdc98fSDingchen Zhang if (!strcmp(source, "dprx dither"))
54f1cdc98fSDingchen Zhang return AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER;
5531aec354SLeo (Sunpeng) Li
5631aec354SLeo (Sunpeng) Li return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID;
5731aec354SLeo (Sunpeng) Li }
5831aec354SLeo (Sunpeng) Li
dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src)59f1cdc98fSDingchen Zhang static bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src)
60f1cdc98fSDingchen Zhang {
61f1cdc98fSDingchen Zhang return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) ||
62f1cdc98fSDingchen Zhang (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER);
63f1cdc98fSDingchen Zhang }
64f1cdc98fSDingchen Zhang
dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src)65f1cdc98fSDingchen Zhang static bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src)
66f1cdc98fSDingchen Zhang {
67f1cdc98fSDingchen Zhang return (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) ||
68f1cdc98fSDingchen Zhang (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER);
69f1cdc98fSDingchen Zhang }
70f1cdc98fSDingchen Zhang
dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)71f1cdc98fSDingchen Zhang static bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src)
72f1cdc98fSDingchen Zhang {
73f1cdc98fSDingchen Zhang return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER) ||
74f1cdc98fSDingchen Zhang (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER) ||
75f1cdc98fSDingchen Zhang (src == AMDGPU_DM_PIPE_CRC_SOURCE_NONE);
76f1cdc98fSDingchen Zhang }
77f1cdc98fSDingchen Zhang
amdgpu_dm_crtc_get_crc_sources(struct drm_crtc * crtc,size_t * count)788fb843d1SDingchen Zhang const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc,
798fb843d1SDingchen Zhang size_t *count)
808fb843d1SDingchen Zhang {
818fb843d1SDingchen Zhang *count = ARRAY_SIZE(pipe_crc_sources);
828fb843d1SDingchen Zhang return pipe_crc_sources;
838fb843d1SDingchen Zhang }
848fb843d1SDingchen Zhang
8586bc2219SWayne Lin #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
amdgpu_dm_set_crc_window_default(struct drm_crtc * crtc,struct dc_stream_state * stream)86785b250eSAlan Liu static void amdgpu_dm_set_crc_window_default(struct drm_crtc *crtc, struct dc_stream_state *stream)
8786bc2219SWayne Lin {
8886bc2219SWayne Lin struct drm_device *drm_dev = crtc->dev;
89785b250eSAlan Liu struct amdgpu_display_manager *dm = &drm_to_adev(drm_dev)->dm;
9086bc2219SWayne Lin struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
91785b250eSAlan Liu bool was_activated;
9286bc2219SWayne Lin
9386bc2219SWayne Lin spin_lock_irq(&drm_dev->event_lock);
94785b250eSAlan Liu was_activated = acrtc->dm_irq_params.window_param.activated;
9562fa035bSAlan Liu acrtc->dm_irq_params.window_param.x_start = 0;
9662fa035bSAlan Liu acrtc->dm_irq_params.window_param.y_start = 0;
9762fa035bSAlan Liu acrtc->dm_irq_params.window_param.x_end = 0;
9862fa035bSAlan Liu acrtc->dm_irq_params.window_param.y_end = 0;
99c0459bddSAlan Liu acrtc->dm_irq_params.window_param.activated = false;
100c0459bddSAlan Liu acrtc->dm_irq_params.window_param.update_win = false;
101c0459bddSAlan Liu acrtc->dm_irq_params.window_param.skip_frame_cnt = 0;
10286bc2219SWayne Lin spin_unlock_irq(&drm_dev->event_lock);
103785b250eSAlan Liu
104785b250eSAlan Liu /* Disable secure_display if it was enabled */
105785b250eSAlan Liu if (was_activated) {
106785b250eSAlan Liu /* stop ROI update on this crtc */
107785b250eSAlan Liu flush_work(&dm->secure_display_ctxs[crtc->index].notify_ta_work);
108785b250eSAlan Liu flush_work(&dm->secure_display_ctxs[crtc->index].forward_roi_work);
109785b250eSAlan Liu dc_stream_forward_crc_window(stream, NULL, true);
110785b250eSAlan Liu }
11186bc2219SWayne Lin }
11286bc2219SWayne Lin
amdgpu_dm_crtc_notify_ta_to_read(struct work_struct * work)1139a65df19SWayne Lin static void amdgpu_dm_crtc_notify_ta_to_read(struct work_struct *work)
1149a65df19SWayne Lin {
1151b11ff76SAlan Liu struct secure_display_context *secure_display_ctx;
1169a65df19SWayne Lin struct psp_context *psp;
117f6e856e7SAaron Liu struct ta_securedisplay_cmd *securedisplay_cmd;
1189a65df19SWayne Lin struct drm_crtc *crtc;
1191b11ff76SAlan Liu struct dc_stream_state *stream;
1201b11ff76SAlan Liu uint8_t phy_inst;
1219a65df19SWayne Lin int ret;
1229a65df19SWayne Lin
1231b11ff76SAlan Liu secure_display_ctx = container_of(work, struct secure_display_context, notify_ta_work);
1241b11ff76SAlan Liu crtc = secure_display_ctx->crtc;
1259a65df19SWayne Lin
126*30a97a21SSrinivasan Shanmugam if (!crtc)
1279a65df19SWayne Lin return;
1289a65df19SWayne Lin
1291b11ff76SAlan Liu psp = &drm_to_adev(crtc->dev)->psp;
130cbd8f20bSAlan Liu
131cbd8f20bSAlan Liu if (!psp->securedisplay_context.context.initialized) {
132cbd8f20bSAlan Liu DRM_DEBUG_DRIVER("Secure Display fails to notify PSP TA\n");
133cbd8f20bSAlan Liu return;
134cbd8f20bSAlan Liu }
135cbd8f20bSAlan Liu
1361b11ff76SAlan Liu stream = to_amdgpu_crtc(crtc)->dm_irq_params.stream;
1371b11ff76SAlan Liu phy_inst = stream->link->link_enc_hw_inst;
1389a65df19SWayne Lin
1391b11ff76SAlan Liu /* need lock for multiple crtcs to use the command buffer */
1407117007eSAlan Liu mutex_lock(&psp->securedisplay_context.mutex);
1417117007eSAlan Liu
1429a65df19SWayne Lin psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
1439a65df19SWayne Lin TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
1441b11ff76SAlan Liu
1451b11ff76SAlan Liu securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = phy_inst;
1461b11ff76SAlan Liu
1471b11ff76SAlan Liu /* PSP TA is expected to finish data transmission over I2C within current frame,
1481b11ff76SAlan Liu * even there are up to 4 crtcs request to send in this frame.
1491b11ff76SAlan Liu */
1509a65df19SWayne Lin ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
1511b11ff76SAlan Liu
1529a65df19SWayne Lin if (!ret) {
153*30a97a21SSrinivasan Shanmugam if (securedisplay_cmd->status != TA_SECUREDISPLAY_STATUS__SUCCESS)
1549a65df19SWayne Lin psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
1559a65df19SWayne Lin }
1567117007eSAlan Liu
1577117007eSAlan Liu mutex_unlock(&psp->securedisplay_context.mutex);
1589a65df19SWayne Lin }
1599a65df19SWayne Lin
160c0459bddSAlan Liu static void
amdgpu_dm_forward_crc_window(struct work_struct * work)161c0459bddSAlan Liu amdgpu_dm_forward_crc_window(struct work_struct *work)
162c0459bddSAlan Liu {
1631b11ff76SAlan Liu struct secure_display_context *secure_display_ctx;
164c0459bddSAlan Liu struct amdgpu_display_manager *dm;
1651b11ff76SAlan Liu struct drm_crtc *crtc;
1661b11ff76SAlan Liu struct dc_stream_state *stream;
167c0459bddSAlan Liu
1681b11ff76SAlan Liu secure_display_ctx = container_of(work, struct secure_display_context, forward_roi_work);
1691b11ff76SAlan Liu crtc = secure_display_ctx->crtc;
1701b11ff76SAlan Liu
1711b11ff76SAlan Liu if (!crtc)
1721b11ff76SAlan Liu return;
1731b11ff76SAlan Liu
1741b11ff76SAlan Liu dm = &drm_to_adev(crtc->dev)->dm;
1751b11ff76SAlan Liu stream = to_amdgpu_crtc(crtc)->dm_irq_params.stream;
176c0459bddSAlan Liu
177c0459bddSAlan Liu mutex_lock(&dm->dc_lock);
1781b11ff76SAlan Liu dc_stream_forward_crc_window(stream, &secure_display_ctx->rect, false);
179c0459bddSAlan Liu mutex_unlock(&dm->dc_lock);
180c0459bddSAlan Liu }
181c0459bddSAlan Liu
amdgpu_dm_crc_window_is_activated(struct drm_crtc * crtc)18286bc2219SWayne Lin bool amdgpu_dm_crc_window_is_activated(struct drm_crtc *crtc)
18386bc2219SWayne Lin {
18486bc2219SWayne Lin struct drm_device *drm_dev = crtc->dev;
18586bc2219SWayne Lin struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
18686bc2219SWayne Lin bool ret = false;
18786bc2219SWayne Lin
18886bc2219SWayne Lin spin_lock_irq(&drm_dev->event_lock);
189c0459bddSAlan Liu ret = acrtc->dm_irq_params.window_param.activated;
19086bc2219SWayne Lin spin_unlock_irq(&drm_dev->event_lock);
19186bc2219SWayne Lin
19286bc2219SWayne Lin return ret;
19386bc2219SWayne Lin }
19486bc2219SWayne Lin #endif
19586bc2219SWayne Lin
1963b3b8448SMahesh Kumar int
amdgpu_dm_crtc_verify_crc_source(struct drm_crtc * crtc,const char * src_name,size_t * values_cnt)1973b3b8448SMahesh Kumar amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
1983b3b8448SMahesh Kumar size_t *values_cnt)
1993b3b8448SMahesh Kumar {
2003b3b8448SMahesh Kumar enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
2013b3b8448SMahesh Kumar
2023b3b8448SMahesh Kumar if (source < 0) {
2033b3b8448SMahesh Kumar DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n",
2043b3b8448SMahesh Kumar src_name, crtc->index);
2053b3b8448SMahesh Kumar return -EINVAL;
2063b3b8448SMahesh Kumar }
2073b3b8448SMahesh Kumar
2083b3b8448SMahesh Kumar *values_cnt = 3;
2093b3b8448SMahesh Kumar return 0;
2103b3b8448SMahesh Kumar }
2113b3b8448SMahesh Kumar
amdgpu_dm_crtc_configure_crc_source(struct drm_crtc * crtc,struct dm_crtc_state * dm_crtc_state,enum amdgpu_dm_pipe_crc_source source)21257638021SNicholas Kazlauskas int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc,
21357638021SNicholas Kazlauskas struct dm_crtc_state *dm_crtc_state,
21457638021SNicholas Kazlauskas enum amdgpu_dm_pipe_crc_source source)
21531aec354SLeo (Sunpeng) Li {
2161348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(crtc->dev);
21757638021SNicholas Kazlauskas struct dc_stream_state *stream_state = dm_crtc_state->stream;
21857638021SNicholas Kazlauskas bool enable = amdgpu_dm_is_valid_crc_source(source);
21957638021SNicholas Kazlauskas int ret = 0;
22057638021SNicholas Kazlauskas
22157638021SNicholas Kazlauskas /* Configuration will be deferred to stream enable. */
22257638021SNicholas Kazlauskas if (!stream_state)
223bbc49fc0SWayne Lin return -EINVAL;
22457638021SNicholas Kazlauskas
22557638021SNicholas Kazlauskas mutex_lock(&adev->dm.dc_lock);
22657638021SNicholas Kazlauskas
2271b11ff76SAlan Liu /* Enable or disable CRTC CRC generation */
2281c26a1bfSWayne Lin if (dm_is_crc_source_crtc(source) || source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE) {
22957638021SNicholas Kazlauskas if (!dc_stream_configure_crc(stream_state->ctx->dc,
230e2881d6dSRodrigo Siqueira stream_state, NULL, enable, enable)) {
23157638021SNicholas Kazlauskas ret = -EINVAL;
23257638021SNicholas Kazlauskas goto unlock;
23357638021SNicholas Kazlauskas }
23457638021SNicholas Kazlauskas }
23557638021SNicholas Kazlauskas
23657638021SNicholas Kazlauskas /* Configure dithering */
23790d26874SRobin Singh if (!dm_need_crc_dither(source)) {
23857638021SNicholas Kazlauskas dc_stream_set_dither_option(stream_state, DITHER_OPTION_TRUN8);
23990d26874SRobin Singh dc_stream_set_dyn_expansion(stream_state->ctx->dc, stream_state,
24090d26874SRobin Singh DYN_EXPANSION_DISABLE);
24190d26874SRobin Singh } else {
24257638021SNicholas Kazlauskas dc_stream_set_dither_option(stream_state,
24357638021SNicholas Kazlauskas DITHER_OPTION_DEFAULT);
24490d26874SRobin Singh dc_stream_set_dyn_expansion(stream_state->ctx->dc, stream_state,
24590d26874SRobin Singh DYN_EXPANSION_AUTO);
24690d26874SRobin Singh }
24757638021SNicholas Kazlauskas
24857638021SNicholas Kazlauskas unlock:
24957638021SNicholas Kazlauskas mutex_unlock(&adev->dm.dc_lock);
25057638021SNicholas Kazlauskas
25157638021SNicholas Kazlauskas return ret;
25257638021SNicholas Kazlauskas }
25357638021SNicholas Kazlauskas
amdgpu_dm_crtc_set_crc_source(struct drm_crtc * crtc,const char * src_name)25457638021SNicholas Kazlauskas int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
25557638021SNicholas Kazlauskas {
256452575c5SNicholas Kazlauskas enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
2578e7b6feeSWayne Lin enum amdgpu_dm_pipe_crc_source cur_crc_src;
258452575c5SNicholas Kazlauskas struct drm_crtc_commit *commit;
259452575c5SNicholas Kazlauskas struct dm_crtc_state *crtc_state;
2608e7b6feeSWayne Lin struct drm_device *drm_dev = crtc->dev;
2618e7b6feeSWayne Lin struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
26214b25846SDingchen Zhang struct drm_dp_aux *aux = NULL;
26314b25846SDingchen Zhang bool enable = false;
26414b25846SDingchen Zhang bool enabled = false;
265452575c5SNicholas Kazlauskas int ret = 0;
26631aec354SLeo (Sunpeng) Li
26731aec354SLeo (Sunpeng) Li if (source < 0) {
26831aec354SLeo (Sunpeng) Li DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n",
26931aec354SLeo (Sunpeng) Li src_name, crtc->index);
27031aec354SLeo (Sunpeng) Li return -EINVAL;
27131aec354SLeo (Sunpeng) Li }
27231aec354SLeo (Sunpeng) Li
273452575c5SNicholas Kazlauskas ret = drm_modeset_lock(&crtc->mutex, NULL);
274452575c5SNicholas Kazlauskas if (ret)
275452575c5SNicholas Kazlauskas return ret;
276452575c5SNicholas Kazlauskas
277452575c5SNicholas Kazlauskas spin_lock(&crtc->commit_lock);
278452575c5SNicholas Kazlauskas commit = list_first_entry_or_null(&crtc->commit_list,
279452575c5SNicholas Kazlauskas struct drm_crtc_commit, commit_entry);
280452575c5SNicholas Kazlauskas if (commit)
281452575c5SNicholas Kazlauskas drm_crtc_commit_get(commit);
282452575c5SNicholas Kazlauskas spin_unlock(&crtc->commit_lock);
283452575c5SNicholas Kazlauskas
284452575c5SNicholas Kazlauskas if (commit) {
285452575c5SNicholas Kazlauskas /*
286452575c5SNicholas Kazlauskas * Need to wait for all outstanding programming to complete
287452575c5SNicholas Kazlauskas * in commit tail since it can modify CRC related fields and
288452575c5SNicholas Kazlauskas * hardware state. Since we're holding the CRTC lock we're
289452575c5SNicholas Kazlauskas * guaranteed that no other commit work can be queued off
290452575c5SNicholas Kazlauskas * before we modify the state below.
291452575c5SNicholas Kazlauskas */
292452575c5SNicholas Kazlauskas ret = wait_for_completion_interruptible_timeout(
293452575c5SNicholas Kazlauskas &commit->hw_done, 10 * HZ);
294452575c5SNicholas Kazlauskas if (ret)
295452575c5SNicholas Kazlauskas goto cleanup;
296452575c5SNicholas Kazlauskas }
297452575c5SNicholas Kazlauskas
29814b25846SDingchen Zhang enable = amdgpu_dm_is_valid_crc_source(source);
299452575c5SNicholas Kazlauskas crtc_state = to_dm_crtc_state(crtc->state);
3008e7b6feeSWayne Lin spin_lock_irq(&drm_dev->event_lock);
3018e7b6feeSWayne Lin cur_crc_src = acrtc->dm_irq_params.crc_src;
3028e7b6feeSWayne Lin spin_unlock_irq(&drm_dev->event_lock);
303428da2bdSNicholas Kazlauskas
30414b25846SDingchen Zhang /*
30514b25846SDingchen Zhang * USER REQ SRC | CURRENT SRC | BEHAVIOR
30614b25846SDingchen Zhang * -----------------------------
30714b25846SDingchen Zhang * None | None | Do nothing
308f1cdc98fSDingchen Zhang * None | CRTC | Disable CRTC CRC, set default to dither
309f1cdc98fSDingchen Zhang * None | DPRX | Disable DPRX CRC, need 'aux', set default to dither
310f1cdc98fSDingchen Zhang * None | CRTC DITHER | Disable CRTC CRC
311f1cdc98fSDingchen Zhang * None | DPRX DITHER | Disable DPRX CRC, need 'aux'
312f1cdc98fSDingchen Zhang * CRTC | XXXX | Enable CRTC CRC, no dither
313f1cdc98fSDingchen Zhang * DPRX | XXXX | Enable DPRX CRC, need 'aux', no dither
314f1cdc98fSDingchen Zhang * CRTC DITHER | XXXX | Enable CRTC CRC, set dither
315f1cdc98fSDingchen Zhang * DPRX DITHER | XXXX | Enable DPRX CRC, need 'aux', set dither
31614b25846SDingchen Zhang */
317f1cdc98fSDingchen Zhang if (dm_is_crc_source_dprx(source) ||
31814b25846SDingchen Zhang (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE &&
3198e7b6feeSWayne Lin dm_is_crc_source_dprx(cur_crc_src))) {
320df61eae4SNicholas Kazlauskas struct amdgpu_dm_connector *aconn = NULL;
321df61eae4SNicholas Kazlauskas struct drm_connector *connector;
322df61eae4SNicholas Kazlauskas struct drm_connector_list_iter conn_iter;
323df61eae4SNicholas Kazlauskas
324df61eae4SNicholas Kazlauskas drm_connector_list_iter_begin(crtc->dev, &conn_iter);
325df61eae4SNicholas Kazlauskas drm_for_each_connector_iter(connector, &conn_iter) {
326df61eae4SNicholas Kazlauskas if (!connector->state || connector->state->crtc != crtc)
327df61eae4SNicholas Kazlauskas continue;
328df61eae4SNicholas Kazlauskas
329df61eae4SNicholas Kazlauskas aconn = to_amdgpu_dm_connector(connector);
330df61eae4SNicholas Kazlauskas break;
331df61eae4SNicholas Kazlauskas }
332df61eae4SNicholas Kazlauskas drm_connector_list_iter_end(&conn_iter);
33314b25846SDingchen Zhang
33414b25846SDingchen Zhang if (!aconn) {
33514b25846SDingchen Zhang DRM_DEBUG_DRIVER("No amd connector matching CRTC-%d\n", crtc->index);
336452575c5SNicholas Kazlauskas ret = -EINVAL;
337452575c5SNicholas Kazlauskas goto cleanup;
33814b25846SDingchen Zhang }
33914b25846SDingchen Zhang
340f0127cb1SWayne Lin aux = (aconn->mst_output_port) ? &aconn->mst_output_port->aux : &aconn->dm_dp_aux.aux;
34114b25846SDingchen Zhang
34214b25846SDingchen Zhang if (!aux) {
34314b25846SDingchen Zhang DRM_DEBUG_DRIVER("No dp aux for amd connector\n");
344452575c5SNicholas Kazlauskas ret = -EINVAL;
345452575c5SNicholas Kazlauskas goto cleanup;
34643a6a02eSNicholas Kazlauskas }
3472da34b7bSPerry Yuan
3482da34b7bSPerry Yuan if ((aconn->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
3492da34b7bSPerry Yuan (aconn->base.connector_type != DRM_MODE_CONNECTOR_eDP)) {
3502da34b7bSPerry Yuan DRM_DEBUG_DRIVER("No DP connector available for CRC source\n");
3512da34b7bSPerry Yuan ret = -EINVAL;
3522da34b7bSPerry Yuan goto cleanup;
3532da34b7bSPerry Yuan }
3542da34b7bSPerry Yuan
35514b25846SDingchen Zhang }
356428da2bdSNicholas Kazlauskas
35786bc2219SWayne Lin #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
3581b11ff76SAlan Liu /* Reset secure_display when we change crc source from debugfs */
359785b250eSAlan Liu amdgpu_dm_set_crc_window_default(crtc, crtc_state->stream);
36086bc2219SWayne Lin #endif
36186bc2219SWayne Lin
362452575c5SNicholas Kazlauskas if (amdgpu_dm_crtc_configure_crc_source(crtc, crtc_state, source)) {
363452575c5SNicholas Kazlauskas ret = -EINVAL;
364452575c5SNicholas Kazlauskas goto cleanup;
365452575c5SNicholas Kazlauskas }
36643a6a02eSNicholas Kazlauskas
367428da2bdSNicholas Kazlauskas /*
368428da2bdSNicholas Kazlauskas * Reading the CRC requires the vblank interrupt handler to be
369428da2bdSNicholas Kazlauskas * enabled. Keep a reference until CRC capture stops.
370428da2bdSNicholas Kazlauskas */
3718e7b6feeSWayne Lin enabled = amdgpu_dm_is_valid_crc_source(cur_crc_src);
37214b25846SDingchen Zhang if (!enabled && enable) {
3737a235125SNicholas Kazlauskas ret = drm_crtc_vblank_get(crtc);
3747a235125SNicholas Kazlauskas if (ret)
375452575c5SNicholas Kazlauskas goto cleanup;
3767a235125SNicholas Kazlauskas
377f1cdc98fSDingchen Zhang if (dm_is_crc_source_dprx(source)) {
37814b25846SDingchen Zhang if (drm_dp_start_crc(aux, crtc)) {
37914b25846SDingchen Zhang DRM_DEBUG_DRIVER("dp start crc failed\n");
380452575c5SNicholas Kazlauskas ret = -EINVAL;
381452575c5SNicholas Kazlauskas goto cleanup;
38214b25846SDingchen Zhang }
38314b25846SDingchen Zhang }
38414b25846SDingchen Zhang } else if (enabled && !enable) {
385428da2bdSNicholas Kazlauskas drm_crtc_vblank_put(crtc);
386f1cdc98fSDingchen Zhang if (dm_is_crc_source_dprx(source)) {
38714b25846SDingchen Zhang if (drm_dp_stop_crc(aux)) {
38814b25846SDingchen Zhang DRM_DEBUG_DRIVER("dp stop crc failed\n");
389452575c5SNicholas Kazlauskas ret = -EINVAL;
390452575c5SNicholas Kazlauskas goto cleanup;
39114b25846SDingchen Zhang }
39214b25846SDingchen Zhang }
39314b25846SDingchen Zhang }
394428da2bdSNicholas Kazlauskas
3958e7b6feeSWayne Lin spin_lock_irq(&drm_dev->event_lock);
3968e7b6feeSWayne Lin acrtc->dm_irq_params.crc_src = source;
3978e7b6feeSWayne Lin spin_unlock_irq(&drm_dev->event_lock);
39831aec354SLeo (Sunpeng) Li
399a0a31ec4SLeo (Sunpeng) Li /* Reset crc_skipped on dm state */
400a0a31ec4SLeo (Sunpeng) Li crtc_state->crc_skip_count = 0;
401452575c5SNicholas Kazlauskas
402452575c5SNicholas Kazlauskas cleanup:
403452575c5SNicholas Kazlauskas if (commit)
404452575c5SNicholas Kazlauskas drm_crtc_commit_put(commit);
405452575c5SNicholas Kazlauskas
406452575c5SNicholas Kazlauskas drm_modeset_unlock(&crtc->mutex);
407452575c5SNicholas Kazlauskas
408452575c5SNicholas Kazlauskas return ret;
40931aec354SLeo (Sunpeng) Li }
41031aec354SLeo (Sunpeng) Li
41131aec354SLeo (Sunpeng) Li /**
41231aec354SLeo (Sunpeng) Li * amdgpu_dm_crtc_handle_crc_irq: Report to DRM the CRC on given CRTC.
41331aec354SLeo (Sunpeng) Li * @crtc: DRM CRTC object.
41431aec354SLeo (Sunpeng) Li *
41531aec354SLeo (Sunpeng) Li * This function should be called at the end of a vblank, when the fb has been
41631aec354SLeo (Sunpeng) Li * fully processed through the pipe.
41731aec354SLeo (Sunpeng) Li */
amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc * crtc)41831aec354SLeo (Sunpeng) Li void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
41931aec354SLeo (Sunpeng) Li {
420dddc0557SNicholas Kazlauskas struct dm_crtc_state *crtc_state;
421dddc0557SNicholas Kazlauskas struct dc_stream_state *stream_state;
4228e7b6feeSWayne Lin struct drm_device *drm_dev = NULL;
4238e7b6feeSWayne Lin enum amdgpu_dm_pipe_crc_source cur_crc_src;
4248e7b6feeSWayne Lin struct amdgpu_crtc *acrtc = NULL;
42531aec354SLeo (Sunpeng) Li uint32_t crcs[3];
4268e7b6feeSWayne Lin unsigned long flags;
42731aec354SLeo (Sunpeng) Li
428dddc0557SNicholas Kazlauskas if (crtc == NULL)
429dddc0557SNicholas Kazlauskas return;
430dddc0557SNicholas Kazlauskas
431dddc0557SNicholas Kazlauskas crtc_state = to_dm_crtc_state(crtc->state);
432dddc0557SNicholas Kazlauskas stream_state = crtc_state->stream;
4338e7b6feeSWayne Lin acrtc = to_amdgpu_crtc(crtc);
4348e7b6feeSWayne Lin drm_dev = crtc->dev;
4358e7b6feeSWayne Lin
4368e7b6feeSWayne Lin spin_lock_irqsave(&drm_dev->event_lock, flags);
4378e7b6feeSWayne Lin cur_crc_src = acrtc->dm_irq_params.crc_src;
4388e7b6feeSWayne Lin spin_unlock_irqrestore(&drm_dev->event_lock, flags);
439dddc0557SNicholas Kazlauskas
440d1bd7d61SLeo (Sunpeng) Li /* Early return if CRC capture is not enabled. */
4418e7b6feeSWayne Lin if (!amdgpu_dm_is_valid_crc_source(cur_crc_src))
442d1bd7d61SLeo (Sunpeng) Li return;
443d1bd7d61SLeo (Sunpeng) Li
44431aec354SLeo (Sunpeng) Li /*
44531aec354SLeo (Sunpeng) Li * Since flipping and crc enablement happen asynchronously, we - more
44631aec354SLeo (Sunpeng) Li * often than not - will be returning an 'uncooked' crc on first frame.
447a0a31ec4SLeo (Sunpeng) Li * Probably because hw isn't ready yet. For added security, skip the
448a0a31ec4SLeo (Sunpeng) Li * first two CRC values.
44931aec354SLeo (Sunpeng) Li */
450a0a31ec4SLeo (Sunpeng) Li if (crtc_state->crc_skip_count < 2) {
451a0a31ec4SLeo (Sunpeng) Li crtc_state->crc_skip_count += 1;
45231aec354SLeo (Sunpeng) Li return;
45331aec354SLeo (Sunpeng) Li }
45431aec354SLeo (Sunpeng) Li
4558e7b6feeSWayne Lin if (dm_is_crc_source_crtc(cur_crc_src)) {
45631aec354SLeo (Sunpeng) Li if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
45731aec354SLeo (Sunpeng) Li &crcs[0], &crcs[1], &crcs[2]))
45831aec354SLeo (Sunpeng) Li return;
45931aec354SLeo (Sunpeng) Li
46031aec354SLeo (Sunpeng) Li drm_crtc_add_crc_entry(crtc, true,
46131aec354SLeo (Sunpeng) Li drm_crtc_accurate_vblank_count(crtc), crcs);
46231aec354SLeo (Sunpeng) Li }
46314b25846SDingchen Zhang }
46486bc2219SWayne Lin
46586bc2219SWayne Lin #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc * crtc)46686bc2219SWayne Lin void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc *crtc)
46786bc2219SWayne Lin {
46886bc2219SWayne Lin struct drm_device *drm_dev = NULL;
46986bc2219SWayne Lin enum amdgpu_dm_pipe_crc_source cur_crc_src;
47086bc2219SWayne Lin struct amdgpu_crtc *acrtc = NULL;
4719a65df19SWayne Lin struct amdgpu_device *adev = NULL;
4721b11ff76SAlan Liu struct secure_display_context *secure_display_ctx = NULL;
4731b11ff76SAlan Liu unsigned long flags1;
47486bc2219SWayne Lin
47586bc2219SWayne Lin if (crtc == NULL)
47686bc2219SWayne Lin return;
47786bc2219SWayne Lin
47886bc2219SWayne Lin acrtc = to_amdgpu_crtc(crtc);
4799a65df19SWayne Lin adev = drm_to_adev(crtc->dev);
48086bc2219SWayne Lin drm_dev = crtc->dev;
48186bc2219SWayne Lin
482cd95ef00SWayne Lin spin_lock_irqsave(&drm_dev->event_lock, flags1);
48386bc2219SWayne Lin cur_crc_src = acrtc->dm_irq_params.crc_src;
48486bc2219SWayne Lin
48586bc2219SWayne Lin /* Early return if CRC capture is not enabled. */
4861b11ff76SAlan Liu if (!amdgpu_dm_is_valid_crc_source(cur_crc_src) ||
4871b11ff76SAlan Liu !dm_is_crc_source_crtc(cur_crc_src))
488c0459bddSAlan Liu goto cleanup;
489c0459bddSAlan Liu
490c0459bddSAlan Liu if (!acrtc->dm_irq_params.window_param.activated)
491c0459bddSAlan Liu goto cleanup;
492c0459bddSAlan Liu
493c0459bddSAlan Liu if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
494c0459bddSAlan Liu acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
4959a65df19SWayne Lin goto cleanup;
4969a65df19SWayne Lin }
49786bc2219SWayne Lin
4981b11ff76SAlan Liu secure_display_ctx = &adev->dm.secure_display_ctxs[acrtc->crtc_id];
499b8ff7e08SAlan Liu if (WARN_ON(secure_display_ctx->crtc != crtc)) {
500b8ff7e08SAlan Liu /* We have set the crtc when creating secure_display_context,
501b8ff7e08SAlan Liu * don't expect it to be changed here.
502b8ff7e08SAlan Liu */
5031b11ff76SAlan Liu secure_display_ctx->crtc = crtc;
504b8ff7e08SAlan Liu }
50586bc2219SWayne Lin
5061b11ff76SAlan Liu if (acrtc->dm_irq_params.window_param.update_win) {
5071b11ff76SAlan Liu /* prepare work for dmub to update ROI */
5081b11ff76SAlan Liu secure_display_ctx->rect.x = acrtc->dm_irq_params.window_param.x_start;
5091b11ff76SAlan Liu secure_display_ctx->rect.y = acrtc->dm_irq_params.window_param.y_start;
5101b11ff76SAlan Liu secure_display_ctx->rect.width = acrtc->dm_irq_params.window_param.x_end -
51162fa035bSAlan Liu acrtc->dm_irq_params.window_param.x_start;
5121b11ff76SAlan Liu secure_display_ctx->rect.height = acrtc->dm_irq_params.window_param.y_end -
51362fa035bSAlan Liu acrtc->dm_irq_params.window_param.y_start;
5141b11ff76SAlan Liu schedule_work(&secure_display_ctx->forward_roi_work);
51586bc2219SWayne Lin
516c0459bddSAlan Liu acrtc->dm_irq_params.window_param.update_win = false;
5171b11ff76SAlan Liu
5181b11ff76SAlan Liu /* Statically skip 1 frame, because we may need to wait below things
5191b11ff76SAlan Liu * before sending ROI to dmub:
5201b11ff76SAlan Liu * 1. We defer the work by using system workqueue.
5211b11ff76SAlan Liu * 2. We may need to wait for dc_lock before accessing dmub.
5221b11ff76SAlan Liu */
523c0459bddSAlan Liu acrtc->dm_irq_params.window_param.skip_frame_cnt = 1;
5249a65df19SWayne Lin
5259a65df19SWayne Lin } else {
5261b11ff76SAlan Liu /* prepare work for psp to read ROI/CRC and send to I2C */
5271b11ff76SAlan Liu schedule_work(&secure_display_ctx->notify_ta_work);
52886bc2219SWayne Lin }
52986bc2219SWayne Lin
53086bc2219SWayne Lin cleanup:
531cd95ef00SWayne Lin spin_unlock_irqrestore(&drm_dev->event_lock, flags1);
53286bc2219SWayne Lin }
5339a65df19SWayne Lin
5341b11ff76SAlan Liu struct secure_display_context *
amdgpu_dm_crtc_secure_display_create_contexts(struct amdgpu_device * adev)535b8ff7e08SAlan Liu amdgpu_dm_crtc_secure_display_create_contexts(struct amdgpu_device *adev)
5369a65df19SWayne Lin {
5371b11ff76SAlan Liu struct secure_display_context *secure_display_ctxs = NULL;
5381b11ff76SAlan Liu int i;
5399a65df19SWayne Lin
540c3d74960SHamza Mahfooz secure_display_ctxs = kcalloc(adev->mode_info.num_crtc,
541c3d74960SHamza Mahfooz sizeof(struct secure_display_context),
542c3d74960SHamza Mahfooz GFP_KERNEL);
5439a65df19SWayne Lin
5441b11ff76SAlan Liu if (!secure_display_ctxs)
5459a65df19SWayne Lin return NULL;
5469a65df19SWayne Lin
547c3d74960SHamza Mahfooz for (i = 0; i < adev->mode_info.num_crtc; i++) {
5481b11ff76SAlan Liu INIT_WORK(&secure_display_ctxs[i].forward_roi_work, amdgpu_dm_forward_crc_window);
5491b11ff76SAlan Liu INIT_WORK(&secure_display_ctxs[i].notify_ta_work, amdgpu_dm_crtc_notify_ta_to_read);
550b8ff7e08SAlan Liu secure_display_ctxs[i].crtc = &adev->mode_info.crtcs[i]->base;
5511b11ff76SAlan Liu }
5529a65df19SWayne Lin
5531b11ff76SAlan Liu return secure_display_ctxs;
5549a65df19SWayne Lin }
55586bc2219SWayne Lin #endif
556