1 /* 2 * Copyright 2012-17 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 27 #include "reg_helper.h" 28 #include "resource.h" 29 #include "dwb.h" 30 #include "dcn20_dwb.h" 31 32 33 #define REG(reg)\ 34 dwbc20->dwbc_regs->reg 35 36 #define CTX \ 37 dwbc20->base.ctx 38 39 #define DC_LOGGER \ 40 dwbc20->base.ctx->logger 41 #undef FN 42 #define FN(reg_name, field_name) \ 43 dwbc20->dwbc_shift->field_name, dwbc20->dwbc_mask->field_name 44 45 enum dwb_outside_pix_strategy { 46 DWB_OUTSIDE_PIX_STRATEGY_BLACK = 0, 47 DWB_OUTSIDE_PIX_STRATEGY_EDGE = 1 48 }; 49 50 static bool dwb2_get_caps(struct dwbc *dwbc, struct dwb_caps *caps) 51 { 52 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 53 if (caps) { 54 caps->adapter_id = 0; /* we only support 1 adapter currently */ 55 caps->hw_version = DCN_VERSION_2_0; 56 caps->num_pipes = 1; 57 memset(&caps->reserved, 0, sizeof(caps->reserved)); 58 memset(&caps->reserved2, 0, sizeof(caps->reserved2)); 59 caps->sw_version = dwb_ver_1_0; 60 caps->caps.support_dwb = true; 61 caps->caps.support_ogam = false; 62 caps->caps.support_wbscl = false; 63 caps->caps.support_ocsc = false; 64 DC_LOG_DWB("%s SUPPORTED! inst = %d", __func__, dwbc20->base.inst); 65 return true; 66 } else { 67 DC_LOG_DWB("%s NOT SUPPORTED! inst = %d", __func__, dwbc20->base.inst); 68 return false; 69 } 70 } 71 72 void dwb2_config_dwb_cnv(struct dwbc *dwbc, struct dc_dwb_params *params) 73 { 74 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 75 DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); 76 77 /* Set DWB source size */ 78 REG_UPDATE_2(CNV_SOURCE_SIZE, CNV_SOURCE_WIDTH, params->cnv_params.src_width, 79 CNV_SOURCE_HEIGHT, params->cnv_params.src_height); 80 81 /* source size is not equal the source size, then enable cropping. */ 82 if (params->cnv_params.crop_en) { 83 REG_UPDATE(CNV_MODE, CNV_WINDOW_CROP_EN, 1); 84 REG_UPDATE(CNV_WINDOW_START, CNV_WINDOW_START_X, params->cnv_params.crop_x); 85 REG_UPDATE(CNV_WINDOW_START, CNV_WINDOW_START_Y, params->cnv_params.crop_y); 86 REG_UPDATE(CNV_WINDOW_SIZE, CNV_WINDOW_WIDTH, params->cnv_params.crop_width); 87 REG_UPDATE(CNV_WINDOW_SIZE, CNV_WINDOW_HEIGHT, params->cnv_params.crop_height); 88 } else { 89 REG_UPDATE(CNV_MODE, CNV_WINDOW_CROP_EN, 0); 90 } 91 92 /* Set CAPTURE_RATE */ 93 REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_RATE, params->capture_rate); 94 95 /* Set CNV output pixel depth */ 96 REG_UPDATE(CNV_MODE, CNV_OUT_BPC, params->cnv_params.cnv_out_bpc); 97 } 98 99 static bool dwb2_enable(struct dwbc *dwbc, struct dc_dwb_params *params) 100 { 101 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 102 103 /* Only chroma scaling (sub-sampling) is supported in DCN2 */ 104 if ((params->cnv_params.src_width != params->dest_width) || 105 (params->cnv_params.src_height != params->dest_height)) { 106 107 DC_LOG_DWB("%s inst = %d, FAILED!LUMA SCALING NOT SUPPORTED", __func__, dwbc20->base.inst); 108 return false; 109 } 110 DC_LOG_DWB("%s inst = %d, ENABLED", __func__, dwbc20->base.inst); 111 112 /* disable power gating */ 113 //REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 1, 114 // DISPCLK_G_WB_GATE_DIS, 1, DISPCLK_G_WBSCL_GATE_DIS, 1, 115 // WB_LB_LS_DIS, 1, WB_LUT_LS_DIS, 1); 116 117 /* Set WB_ENABLE (not double buffered; capture not enabled) */ 118 REG_UPDATE(WB_ENABLE, WB_ENABLE, 1); 119 120 /* Set CNV parameters */ 121 dwb2_config_dwb_cnv(dwbc, params); 122 123 /* Set scaling parameters */ 124 dwb2_set_scaler(dwbc, params); 125 126 /* Enable DWB capture enable (double buffered) */ 127 REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_EN, DWB_FRAME_CAPTURE_ENABLE); 128 129 // disable warmup 130 REG_UPDATE(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, 0); 131 132 return true; 133 } 134 135 bool dwb2_disable(struct dwbc *dwbc) 136 { 137 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 138 DC_LOG_DWB("%s inst = %d, Disabled", __func__, dwbc20->base.inst); 139 140 /* disable CNV */ 141 REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_EN, DWB_FRAME_CAPTURE_DISABLE); 142 143 /* disable WB */ 144 REG_UPDATE(WB_ENABLE, WB_ENABLE, 0); 145 146 /* soft reset */ 147 REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 1); 148 REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 0); 149 150 /* enable power gating */ 151 //REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 0, 152 // DISPCLK_G_WB_GATE_DIS, 0, DISPCLK_G_WBSCL_GATE_DIS, 0, 153 // WB_LB_LS_DIS, 0, WB_LUT_LS_DIS, 0); 154 155 return true; 156 } 157 158 static bool dwb2_update(struct dwbc *dwbc, struct dc_dwb_params *params) 159 { 160 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 161 unsigned int pre_locked; 162 163 /* Only chroma scaling (sub-sampling) is supported in DCN2 */ 164 if ((params->cnv_params.src_width != params->dest_width) || 165 (params->cnv_params.src_height != params->dest_height)) { 166 DC_LOG_DWB("%s inst = %d, FAILED!LUMA SCALING NOT SUPPORTED", __func__, dwbc20->base.inst); 167 return false; 168 } 169 DC_LOG_DWB("%s inst = %d, scaling", __func__, dwbc20->base.inst); 170 171 /* 172 * Check if the caller has already locked CNV registers. 173 * If so: assume the caller will unlock, so don't touch the lock. 174 * If not: lock them for this update, then unlock after the 175 * update is complete. 176 */ 177 REG_GET(CNV_UPDATE, CNV_UPDATE_LOCK, &pre_locked); 178 179 if (pre_locked == 0) { 180 /* Lock DWB registers */ 181 REG_UPDATE(CNV_UPDATE, CNV_UPDATE_LOCK, 1); 182 } 183 184 /* Set CNV parameters */ 185 dwb2_config_dwb_cnv(dwbc, params); 186 187 /* Set scaling parameters */ 188 dwb2_set_scaler(dwbc, params); 189 190 if (pre_locked == 0) { 191 /* Unlock DWB registers */ 192 REG_UPDATE(CNV_UPDATE, CNV_UPDATE_LOCK, 0); 193 } 194 195 return true; 196 } 197 198 bool dwb2_is_enabled(struct dwbc *dwbc) 199 { 200 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 201 unsigned int wb_enabled = 0; 202 unsigned int cnv_frame_capture_en = 0; 203 204 REG_GET(WB_ENABLE, WB_ENABLE, &wb_enabled); 205 REG_GET(CNV_MODE, CNV_FRAME_CAPTURE_EN, &cnv_frame_capture_en); 206 207 return ((wb_enabled != 0) && (cnv_frame_capture_en != 0)); 208 } 209 210 void dwb2_set_stereo(struct dwbc *dwbc, 211 struct dwb_stereo_params *stereo_params) 212 { 213 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 214 DC_LOG_DWB("%s inst = %d, enabled =%d", __func__,\ 215 dwbc20->base.inst, stereo_params->stereo_enabled); 216 217 if (stereo_params->stereo_enabled) { 218 REG_UPDATE(CNV_MODE, CNV_STEREO_TYPE, stereo_params->stereo_type); 219 REG_UPDATE(CNV_MODE, CNV_EYE_SELECTION, stereo_params->stereo_eye_select); 220 REG_UPDATE(CNV_MODE, CNV_STEREO_POLARITY, stereo_params->stereo_polarity); 221 } else { 222 REG_UPDATE(CNV_MODE, CNV_EYE_SELECTION, 0); 223 } 224 } 225 226 void dwb2_set_new_content(struct dwbc *dwbc, 227 bool is_new_content) 228 { 229 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 230 DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); 231 232 REG_UPDATE(CNV_MODE, CNV_NEW_CONTENT, is_new_content); 233 } 234 235 static void dwb2_set_warmup(struct dwbc *dwbc, 236 struct dwb_warmup_params *warmup_params) 237 { 238 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 239 DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); 240 241 REG_UPDATE(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, warmup_params->warmup_en); 242 REG_UPDATE(WB_WARM_UP_MODE_CTL1, WIDTH_WARMUP, warmup_params->warmup_width); 243 REG_UPDATE(WB_WARM_UP_MODE_CTL1, HEIGHT_WARMUP, warmup_params->warmup_height); 244 245 REG_UPDATE(WB_WARM_UP_MODE_CTL2, DATA_VALUE_WARMUP, warmup_params->warmup_data); 246 REG_UPDATE(WB_WARM_UP_MODE_CTL2, MODE_WARMUP, warmup_params->warmup_mode); 247 REG_UPDATE(WB_WARM_UP_MODE_CTL2, DATA_DEPTH_WARMUP, warmup_params->warmup_depth); 248 } 249 250 void dwb2_set_scaler(struct dwbc *dwbc, struct dc_dwb_params *params) 251 { 252 struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); 253 DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); 254 255 /* Program scaling mode */ 256 REG_UPDATE_2(WBSCL_MODE, WBSCL_MODE, params->out_format, 257 WBSCL_OUT_BIT_DEPTH, params->output_depth); 258 259 if (params->out_format != dwb_scaler_mode_bypass444) { 260 /* Program output size */ 261 REG_UPDATE(WBSCL_DEST_SIZE, WBSCL_DEST_WIDTH, params->dest_width); 262 REG_UPDATE(WBSCL_DEST_SIZE, WBSCL_DEST_HEIGHT, params->dest_height); 263 264 /* Program round offsets */ 265 REG_UPDATE(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_Y_RGB, 0x40); 266 REG_UPDATE(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_CBCR, 0x200); 267 268 /* Program clamp values */ 269 REG_UPDATE(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_UPPER_Y_RGB, 0x3fe); 270 REG_UPDATE(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_LOWER_Y_RGB, 0x1); 271 REG_UPDATE(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_UPPER_CBCR, 0x3fe); 272 REG_UPDATE(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_LOWER_CBCR, 0x1); 273 274 /* Program outside pixel strategy to use edge pixels */ 275 REG_UPDATE(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_OUTSIDE_PIX_STRATEGY, DWB_OUTSIDE_PIX_STRATEGY_EDGE); 276 277 if (params->cnv_params.crop_en) { 278 /* horizontal scale */ 279 dwb_program_horz_scalar(dwbc20, params->cnv_params.crop_width, 280 params->dest_width, 281 params->scaler_taps); 282 283 /* vertical scale */ 284 dwb_program_vert_scalar(dwbc20, params->cnv_params.crop_height, 285 params->dest_height, 286 params->scaler_taps, 287 params->subsample_position); 288 } else { 289 /* horizontal scale */ 290 dwb_program_horz_scalar(dwbc20, params->cnv_params.src_width, 291 params->dest_width, 292 params->scaler_taps); 293 294 /* vertical scale */ 295 dwb_program_vert_scalar(dwbc20, params->cnv_params.src_height, 296 params->dest_height, 297 params->scaler_taps, 298 params->subsample_position); 299 } 300 } 301 302 303 if (dwbc20->dwbc_mask->WBSCL_COEF_RAM_SEL) { 304 /* Swap double buffered coefficient set */ 305 uint32_t wbscl_mode = REG_READ(WBSCL_MODE); 306 bool coef_ram_current = get_reg_field_value_ex( 307 wbscl_mode, dwbc20->dwbc_mask->WBSCL_COEF_RAM_SEL_CURRENT, 308 dwbc20->dwbc_shift->WBSCL_COEF_RAM_SEL_CURRENT); 309 310 REG_UPDATE(WBSCL_MODE, WBSCL_COEF_RAM_SEL, !coef_ram_current); 311 } 312 313 } 314 315 static const struct dwbc_funcs dcn20_dwbc_funcs = { 316 .get_caps = dwb2_get_caps, 317 .enable = dwb2_enable, 318 .disable = dwb2_disable, 319 .update = dwb2_update, 320 .is_enabled = dwb2_is_enabled, 321 .set_stereo = dwb2_set_stereo, 322 .set_new_content = dwb2_set_new_content, 323 .set_warmup = dwb2_set_warmup, 324 .dwb_set_scaler = dwb2_set_scaler, 325 }; 326 327 void dcn20_dwbc_construct(struct dcn20_dwbc *dwbc20, 328 struct dc_context *ctx, 329 const struct dcn20_dwbc_registers *dwbc_regs, 330 const struct dcn20_dwbc_shift *dwbc_shift, 331 const struct dcn20_dwbc_mask *dwbc_mask, 332 int inst) 333 { 334 dwbc20->base.ctx = ctx; 335 336 dwbc20->base.inst = inst; 337 dwbc20->base.funcs = &dcn20_dwbc_funcs; 338 339 dwbc20->dwbc_regs = dwbc_regs; 340 dwbc20->dwbc_shift = dwbc_shift; 341 dwbc20->dwbc_mask = dwbc_mask; 342 } 343 344