drm/amd/display: Add CRC support for DCN
authorDavid Francis <David.Francis@amd.com>
Tue, 26 Jun 2018 18:58:15 +0000 (14:58 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 13 Jul 2018 19:51:39 +0000 (14:51 -0500)
[Why]
Regamma/CTM tests require CRC support

[How]
The CRC registers that were used in DCE exist under different
names in DCN.  The code was copied from DCE (in
dc/dce110/dce110_timing_generator.c) into DCN, and changed to
use the DCN register access helper functions.

Signed-off-by: David Francis <David.Francis@amd.com>
Reviewed-by: Charlene Liu <Charlene.Liu@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h

index e6a3ade154b92f475c70c5ecfc904271dd6a231f..411f89218e0194fcd80980b239c9e514acc0d9f8 100644 (file)
@@ -1324,6 +1324,72 @@ bool optc1_is_optc_underflow_occurred(struct timing_generator *optc)
        return (underflow_occurred == 1);
 }
 
+bool optc1_configure_crc(struct timing_generator *optc,
+                         const struct crc_params *params)
+{
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+       /* Cannot configure crc on a CRTC that is disabled */
+       if (!optc1_is_tg_enabled(optc))
+               return false;
+
+       REG_WRITE(OTG_CRC_CNTL, 0);
+
+       if (!params->enable)
+               return true;
+
+       /* Program frame boundaries */
+       /* Window A x axis start and end. */
+       REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL,
+                       OTG_CRC0_WINDOWA_X_START, params->windowa_x_start,
+                       OTG_CRC0_WINDOWA_X_END, params->windowa_x_end);
+
+       /* Window A y axis start and end. */
+       REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL,
+                       OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start,
+                       OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end);
+
+       /* Window B x axis start and end. */
+       REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL,
+                       OTG_CRC0_WINDOWB_X_START, params->windowb_x_start,
+                       OTG_CRC0_WINDOWB_X_END, params->windowb_x_end);
+
+       /* Window B y axis start and end. */
+       REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL,
+                       OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start,
+                       OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end);
+
+       /* Set crc mode and selection, and enable. Only using CRC0*/
+       REG_UPDATE_3(OTG_CRC_CNTL,
+                       OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0,
+                       OTG_CRC0_SELECT, params->selection,
+                       OTG_CRC_EN, 1);
+
+       return true;
+}
+
+bool optc1_get_crc(struct timing_generator *optc,
+                   uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb)
+{
+       uint32_t field = 0;
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+       REG_GET(OTG_CRC_CNTL, OTG_CRC_EN, &field);
+
+       /* Early return if CRC is not enabled for this CRTC */
+       if (!field)
+               return false;
+
+       REG_GET_2(OTG_CRC0_DATA_RG,
+                       CRC0_R_CR, r_cr,
+                       CRC0_G_Y, g_y);
+
+       REG_GET(OTG_CRC0_DATA_B,
+                       CRC0_B_CB, b_cb);
+
+       return true;
+}
+
 static const struct timing_generator_funcs dcn10_tg_funcs = {
                .validate_timing = optc1_validate_timing,
                .program_timing = optc1_program_timing,
@@ -1360,6 +1426,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
                .is_tg_enabled = optc1_is_tg_enabled,
                .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred,
                .clear_optc_underflow = optc1_clear_optc_underflow,
+               .get_crc = optc1_get_crc,
+               .configure_crc = optc1_configure_crc,
 };
 
 void dcn10_timing_generator_init(struct optc *optc1)
index 59ed272e0c493e77a6bbc9cec3da169c7ebba90c..1df510f57377d9c2180c4c9f45550b9d1d117b6f 100644 (file)
        SRI(CONTROL, VTG, inst),\
        SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\
        SRI(OTG_MASTER_UPDATE_MODE, OTG, inst),\
-       SRI(OTG_GSL_CONTROL, OTG, inst)
+       SRI(OTG_GSL_CONTROL, OTG, inst),\
+       SRI(OTG_CRC_CNTL, OTG, inst),\
+       SRI(OTG_CRC0_DATA_RG, OTG, inst),\
+       SRI(OTG_CRC0_DATA_B, OTG, inst),\
+       SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\
+       SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\
+       SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\
+       SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst)
 
 #define TG_COMMON_REG_LIST_DCN1_0(inst) \
        TG_COMMON_REG_LIST_DCN(inst),\
@@ -138,6 +145,13 @@ struct dcn_optc_registers {
        uint32_t OTG_GSL_WINDOW_X;
        uint32_t OTG_GSL_WINDOW_Y;
        uint32_t OTG_VUPDATE_KEEPOUT;
+       uint32_t OTG_CRC_CNTL;
+       uint32_t OTG_CRC0_DATA_RG;
+       uint32_t OTG_CRC0_DATA_B;
+       uint32_t OTG_CRC0_WINDOWA_X_CONTROL;
+       uint32_t OTG_CRC0_WINDOWA_Y_CONTROL;
+       uint32_t OTG_CRC0_WINDOWB_X_CONTROL;
+       uint32_t OTG_CRC0_WINDOWB_Y_CONTROL;
 };
 
 #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\
@@ -232,7 +246,21 @@ struct dcn_optc_registers {
        SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\
        SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\
        SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\
-       SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh)
+       SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\
+       SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\
+       SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\
+       SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\
+       SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\
+       SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\
+       SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\
+       SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh)
 
 
 #define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\
@@ -363,7 +391,22 @@ struct dcn_optc_registers {
        type OTG_MASTER_UPDATE_LOCK_GSL_EN;\
        type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET;\
        type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET;\
-       type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN;
+       type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN;\
+       type OTG_CRC_CONT_EN;\
+       type OTG_CRC0_SELECT;\
+       type OTG_CRC_EN;\
+       type CRC0_R_CR;\
+       type CRC0_G_Y;\
+       type CRC0_B_CB;\
+       type OTG_CRC0_WINDOWA_X_START;\
+       type OTG_CRC0_WINDOWA_X_END;\
+       type OTG_CRC0_WINDOWA_Y_START;\
+       type OTG_CRC0_WINDOWA_Y_END;\
+       type OTG_CRC0_WINDOWB_X_START;\
+       type OTG_CRC0_WINDOWB_X_END;\
+       type OTG_CRC0_WINDOWB_Y_START;\
+       type OTG_CRC0_WINDOWB_Y_END;
+
 
 #define TG_REG_FIELD_LIST(type) \
        TG_REG_FIELD_LIST_DCN1_0(type)