1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. 5 */ 6 #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ 7 8 #include "msm_drv.h" 9 #include "dpu_kms.h" 10 #include "dpu_hw_mdss.h" 11 #include "dpu_hw_util.h" 12 13 /* using a file static variables for debugfs access */ 14 static u32 dpu_hw_util_log_mask = DPU_DBG_MASK_NONE; 15 16 /* DPU_SCALER_QSEED3 */ 17 #define QSEED3_HW_VERSION 0x00 18 #define QSEED3_OP_MODE 0x04 19 #define QSEED3_RGB2Y_COEFF 0x08 20 #define QSEED3_PHASE_INIT 0x0C 21 #define QSEED3_PHASE_STEP_Y_H 0x10 22 #define QSEED3_PHASE_STEP_Y_V 0x14 23 #define QSEED3_PHASE_STEP_UV_H 0x18 24 #define QSEED3_PHASE_STEP_UV_V 0x1C 25 #define QSEED3_PRELOAD 0x20 26 #define QSEED3_DE_SHARPEN 0x24 27 #define QSEED3_DE_SHARPEN_CTL 0x28 28 #define QSEED3_DE_SHAPE_CTL 0x2C 29 #define QSEED3_DE_THRESHOLD 0x30 30 #define QSEED3_DE_ADJUST_DATA_0 0x34 31 #define QSEED3_DE_ADJUST_DATA_1 0x38 32 #define QSEED3_DE_ADJUST_DATA_2 0x3C 33 #define QSEED3_SRC_SIZE_Y_RGB_A 0x40 34 #define QSEED3_SRC_SIZE_UV 0x44 35 #define QSEED3_DST_SIZE 0x48 36 #define QSEED3_COEF_LUT_CTRL 0x4C 37 #define QSEED3_COEF_LUT_SWAP_BIT 0 38 #define QSEED3_COEF_LUT_DIR_BIT 1 39 #define QSEED3_COEF_LUT_Y_CIR_BIT 2 40 #define QSEED3_COEF_LUT_UV_CIR_BIT 3 41 #define QSEED3_COEF_LUT_Y_SEP_BIT 4 42 #define QSEED3_COEF_LUT_UV_SEP_BIT 5 43 #define QSEED3_BUFFER_CTRL 0x50 44 #define QSEED3_CLK_CTRL0 0x54 45 #define QSEED3_CLK_CTRL1 0x58 46 #define QSEED3_CLK_STATUS 0x5C 47 #define QSEED3_PHASE_INIT_Y_H 0x90 48 #define QSEED3_PHASE_INIT_Y_V 0x94 49 #define QSEED3_PHASE_INIT_UV_H 0x98 50 #define QSEED3_PHASE_INIT_UV_V 0x9C 51 #define QSEED3_COEF_LUT 0x100 52 #define QSEED3_FILTERS 5 53 #define QSEED3_LUT_REGIONS 4 54 #define QSEED3_CIRCULAR_LUTS 9 55 #define QSEED3_SEPARABLE_LUTS 10 56 #define QSEED3_LUT_SIZE 60 57 #define QSEED3_ENABLE 2 58 #define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32)) 59 #define QSEED3_CIR_LUT_SIZE \ 60 (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32)) 61 #define QSEED3_SEP_LUT_SIZE \ 62 (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32)) 63 64 /* DPU_SCALER_QSEED3LITE */ 65 #define QSEED3LITE_COEF_LUT_Y_SEP_BIT 4 66 #define QSEED3LITE_COEF_LUT_UV_SEP_BIT 5 67 #define QSEED3LITE_COEF_LUT_CTRL 0x4C 68 #define QSEED3LITE_COEF_LUT_SWAP_BIT 0 69 #define QSEED3LITE_DIR_FILTER_WEIGHT 0x60 70 #define QSEED3LITE_FILTERS 2 71 #define QSEED3LITE_SEPARABLE_LUTS 10 72 #define QSEED3LITE_LUT_SIZE 33 73 #define QSEED3LITE_SEP_LUT_SIZE \ 74 (QSEED3LITE_LUT_SIZE * QSEED3LITE_SEPARABLE_LUTS * sizeof(u32)) 75 76 /* QOS_LUT */ 77 #define QOS_DANGER_LUT 0x00 78 #define QOS_SAFE_LUT 0x04 79 #define QOS_CREQ_LUT 0x08 80 #define QOS_QOS_CTRL 0x0C 81 #define QOS_CREQ_LUT_0 0x14 82 #define QOS_CREQ_LUT_1 0x18 83 84 /* CMN_QOS_LUT */ 85 #define SSPP_CMN_QOS_CTRL 0x28 86 #define SSPP_CMN_DANGER_LUT 0x2c 87 #define SSPP_CMN_SAFE_LUT 0x30 88 #define SSPP_CMN_CREQ_LUT_0 0x34 89 #define SSPP_CMN_CREQ_LUT_1 0x38 90 91 /* QOS_QOS_CTRL */ 92 #define QOS_QOS_CTRL_DANGER_SAFE_EN BIT(0) 93 #define QOS_QOS_CTRL_DANGER_VBLANK_MASK GENMASK(5, 4) 94 #define QOS_QOS_CTRL_VBLANK_EN BIT(16) 95 #define QOS_QOS_CTRL_CREQ_VBLANK_MASK GENMASK(21, 20) 96 97 void dpu_reg_write(struct dpu_hw_blk_reg_map *c, 98 u32 reg_off, 99 u32 val, 100 const char *name) 101 { 102 /* don't need to mutex protect this */ 103 if (c->log_mask & dpu_hw_util_log_mask) 104 DPU_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n", 105 name, reg_off, val); 106 writel_relaxed(val, c->blk_addr + reg_off); 107 } 108 109 int dpu_reg_read(struct dpu_hw_blk_reg_map *c, u32 reg_off) 110 { 111 return readl_relaxed(c->blk_addr + reg_off); 112 } 113 114 u32 *dpu_hw_util_get_log_mask_ptr(void) 115 { 116 return &dpu_hw_util_log_mask; 117 } 118 119 static void _dpu_hw_setup_scaler3_lut(struct dpu_hw_blk_reg_map *c, 120 struct dpu_hw_scaler3_cfg *scaler3_cfg, u32 offset) 121 { 122 int i, j, filter; 123 int config_lut = 0x0; 124 unsigned long lut_flags; 125 u32 lut_addr, lut_offset, lut_len; 126 u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL}; 127 static const uint32_t off_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = { 128 {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} }, 129 {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} }, 130 {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} }, 131 {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} }, 132 {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} }, 133 }; 134 135 lut_flags = (unsigned long) scaler3_cfg->lut_flag; 136 if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) && 137 (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) { 138 lut[0] = scaler3_cfg->dir_lut; 139 config_lut = 1; 140 } 141 if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) && 142 (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && 143 (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { 144 lut[1] = scaler3_cfg->cir_lut + 145 scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE; 146 config_lut = 1; 147 } 148 if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) && 149 (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && 150 (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { 151 lut[2] = scaler3_cfg->cir_lut + 152 scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE; 153 config_lut = 1; 154 } 155 if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) && 156 (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && 157 (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { 158 lut[3] = scaler3_cfg->sep_lut + 159 scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE; 160 config_lut = 1; 161 } 162 if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) && 163 (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && 164 (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { 165 lut[4] = scaler3_cfg->sep_lut + 166 scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE; 167 config_lut = 1; 168 } 169 170 if (config_lut) { 171 for (filter = 0; filter < QSEED3_FILTERS; filter++) { 172 if (!lut[filter]) 173 continue; 174 lut_offset = 0; 175 for (i = 0; i < QSEED3_LUT_REGIONS; i++) { 176 lut_addr = QSEED3_COEF_LUT + offset 177 + off_tbl[filter][i][1]; 178 lut_len = off_tbl[filter][i][0] << 2; 179 for (j = 0; j < lut_len; j++) { 180 DPU_REG_WRITE(c, 181 lut_addr, 182 (lut[filter])[lut_offset++]); 183 lut_addr += 4; 184 } 185 } 186 } 187 } 188 189 if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags)) 190 DPU_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0)); 191 192 } 193 194 static void _dpu_hw_setup_scaler3lite_lut(struct dpu_hw_blk_reg_map *c, 195 struct dpu_hw_scaler3_cfg *scaler3_cfg, u32 offset) 196 { 197 int j, filter; 198 int config_lut = 0x0; 199 unsigned long lut_flags; 200 u32 lut_addr, lut_offset; 201 u32 *lut[QSEED3LITE_FILTERS] = {NULL, NULL}; 202 static const uint32_t off_tbl[QSEED3_FILTERS] = { 0x000, 0x200 }; 203 204 DPU_REG_WRITE(c, QSEED3LITE_DIR_FILTER_WEIGHT + offset, scaler3_cfg->dir_weight); 205 206 if (!scaler3_cfg->sep_lut) 207 return; 208 209 lut_flags = (unsigned long) scaler3_cfg->lut_flag; 210 if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) && 211 (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3LITE_SEPARABLE_LUTS) && 212 (scaler3_cfg->sep_len == QSEED3LITE_SEP_LUT_SIZE)) { 213 lut[0] = scaler3_cfg->sep_lut + 214 scaler3_cfg->y_rgb_sep_lut_idx * QSEED3LITE_LUT_SIZE; 215 config_lut = 1; 216 } 217 if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) && 218 (scaler3_cfg->uv_sep_lut_idx < QSEED3LITE_SEPARABLE_LUTS) && 219 (scaler3_cfg->sep_len == QSEED3LITE_SEP_LUT_SIZE)) { 220 lut[1] = scaler3_cfg->sep_lut + 221 scaler3_cfg->uv_sep_lut_idx * QSEED3LITE_LUT_SIZE; 222 config_lut = 1; 223 } 224 225 if (config_lut) { 226 for (filter = 0; filter < QSEED3LITE_FILTERS; filter++) { 227 if (!lut[filter]) 228 continue; 229 lut_offset = 0; 230 lut_addr = QSEED3_COEF_LUT + offset + off_tbl[filter]; 231 for (j = 0; j < QSEED3LITE_LUT_SIZE; j++) { 232 DPU_REG_WRITE(c, 233 lut_addr, 234 (lut[filter])[lut_offset++]); 235 lut_addr += 4; 236 } 237 } 238 } 239 240 if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags)) 241 DPU_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0)); 242 243 } 244 245 static void _dpu_hw_setup_scaler3_de(struct dpu_hw_blk_reg_map *c, 246 struct dpu_hw_scaler3_de_cfg *de_cfg, u32 offset) 247 { 248 u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr; 249 u32 adjust_a, adjust_b, adjust_c; 250 251 if (!de_cfg->enable) 252 return; 253 254 sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) | 255 ((de_cfg->sharpen_level2 & 0x1FF) << 16); 256 257 sharp_ctl = ((de_cfg->limit & 0xF) << 9) | 258 ((de_cfg->prec_shift & 0x7) << 13) | 259 ((de_cfg->clip & 0x7) << 16); 260 261 shape_ctl = (de_cfg->thr_quiet & 0xFF) | 262 ((de_cfg->thr_dieout & 0x3FF) << 16); 263 264 de_thr = (de_cfg->thr_low & 0x3FF) | 265 ((de_cfg->thr_high & 0x3FF) << 16); 266 267 adjust_a = (de_cfg->adjust_a[0] & 0x3FF) | 268 ((de_cfg->adjust_a[1] & 0x3FF) << 10) | 269 ((de_cfg->adjust_a[2] & 0x3FF) << 20); 270 271 adjust_b = (de_cfg->adjust_b[0] & 0x3FF) | 272 ((de_cfg->adjust_b[1] & 0x3FF) << 10) | 273 ((de_cfg->adjust_b[2] & 0x3FF) << 20); 274 275 adjust_c = (de_cfg->adjust_c[0] & 0x3FF) | 276 ((de_cfg->adjust_c[1] & 0x3FF) << 10) | 277 ((de_cfg->adjust_c[2] & 0x3FF) << 20); 278 279 DPU_REG_WRITE(c, QSEED3_DE_SHARPEN + offset, sharp_lvl); 280 DPU_REG_WRITE(c, QSEED3_DE_SHARPEN_CTL + offset, sharp_ctl); 281 DPU_REG_WRITE(c, QSEED3_DE_SHAPE_CTL + offset, shape_ctl); 282 DPU_REG_WRITE(c, QSEED3_DE_THRESHOLD + offset, de_thr); 283 DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_0 + offset, adjust_a); 284 DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_1 + offset, adjust_b); 285 DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_2 + offset, adjust_c); 286 287 } 288 289 void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, 290 struct dpu_hw_scaler3_cfg *scaler3_cfg, 291 u32 scaler_offset, u32 scaler_version, 292 const struct msm_format *format) 293 { 294 u32 op_mode = 0; 295 u32 phase_init, preload, src_y_rgb, src_uv, dst; 296 297 if (!scaler3_cfg->enable) 298 goto end; 299 300 op_mode |= BIT(0); 301 op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16; 302 303 if (format && MSM_FORMAT_IS_YUV(format)) { 304 op_mode |= BIT(12); 305 op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24; 306 } 307 308 op_mode |= (scaler3_cfg->blend_cfg & 1) << 31; 309 op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0; 310 311 preload = 312 ((scaler3_cfg->preload_x[0] & 0x7F) << 0) | 313 ((scaler3_cfg->preload_y[0] & 0x7F) << 8) | 314 ((scaler3_cfg->preload_x[1] & 0x7F) << 16) | 315 ((scaler3_cfg->preload_y[1] & 0x7F) << 24); 316 317 src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) | 318 ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16); 319 320 src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) | 321 ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16); 322 323 dst = (scaler3_cfg->dst_width & 0x1FFFF) | 324 ((scaler3_cfg->dst_height & 0x1FFFF) << 16); 325 326 if (scaler3_cfg->de.enable) { 327 _dpu_hw_setup_scaler3_de(c, &scaler3_cfg->de, scaler_offset); 328 op_mode |= BIT(8); 329 } 330 331 if (scaler3_cfg->lut_flag) { 332 if (scaler_version < 0x2004) 333 _dpu_hw_setup_scaler3_lut(c, scaler3_cfg, scaler_offset); 334 else 335 _dpu_hw_setup_scaler3lite_lut(c, scaler3_cfg, scaler_offset); 336 } 337 338 if (scaler_version == 0x1002) { 339 phase_init = 340 ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) | 341 ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) | 342 ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) | 343 ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24); 344 DPU_REG_WRITE(c, QSEED3_PHASE_INIT + scaler_offset, phase_init); 345 } else { 346 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_Y_H + scaler_offset, 347 scaler3_cfg->init_phase_x[0] & 0x1FFFFF); 348 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_Y_V + scaler_offset, 349 scaler3_cfg->init_phase_y[0] & 0x1FFFFF); 350 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_UV_H + scaler_offset, 351 scaler3_cfg->init_phase_x[1] & 0x1FFFFF); 352 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_UV_V + scaler_offset, 353 scaler3_cfg->init_phase_y[1] & 0x1FFFFF); 354 } 355 356 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_Y_H + scaler_offset, 357 scaler3_cfg->phase_step_x[0] & 0xFFFFFF); 358 359 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_Y_V + scaler_offset, 360 scaler3_cfg->phase_step_y[0] & 0xFFFFFF); 361 362 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_UV_H + scaler_offset, 363 scaler3_cfg->phase_step_x[1] & 0xFFFFFF); 364 365 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_UV_V + scaler_offset, 366 scaler3_cfg->phase_step_y[1] & 0xFFFFFF); 367 368 DPU_REG_WRITE(c, QSEED3_PRELOAD + scaler_offset, preload); 369 370 DPU_REG_WRITE(c, QSEED3_SRC_SIZE_Y_RGB_A + scaler_offset, src_y_rgb); 371 372 DPU_REG_WRITE(c, QSEED3_SRC_SIZE_UV + scaler_offset, src_uv); 373 374 DPU_REG_WRITE(c, QSEED3_DST_SIZE + scaler_offset, dst); 375 376 end: 377 if (format && !MSM_FORMAT_IS_DX(format)) 378 op_mode |= BIT(14); 379 380 if (format && format->alpha_enable) { 381 op_mode |= BIT(10); 382 if (scaler_version == 0x1002) 383 op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30; 384 else 385 op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29; 386 } 387 388 DPU_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode); 389 } 390 391 void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, 392 u32 csc_reg_off, 393 const struct dpu_csc_cfg *data, bool csc10) 394 { 395 static const u32 matrix_shift = 7; 396 u32 clamp_shift = csc10 ? 16 : 8; 397 u32 val; 398 399 /* matrix coeff - convert S15.16 to S4.9 */ 400 val = ((data->csc_mv[0] >> matrix_shift) & 0x1FFF) | 401 (((data->csc_mv[1] >> matrix_shift) & 0x1FFF) << 16); 402 DPU_REG_WRITE(c, csc_reg_off, val); 403 val = ((data->csc_mv[2] >> matrix_shift) & 0x1FFF) | 404 (((data->csc_mv[3] >> matrix_shift) & 0x1FFF) << 16); 405 DPU_REG_WRITE(c, csc_reg_off + 0x4, val); 406 val = ((data->csc_mv[4] >> matrix_shift) & 0x1FFF) | 407 (((data->csc_mv[5] >> matrix_shift) & 0x1FFF) << 16); 408 DPU_REG_WRITE(c, csc_reg_off + 0x8, val); 409 val = ((data->csc_mv[6] >> matrix_shift) & 0x1FFF) | 410 (((data->csc_mv[7] >> matrix_shift) & 0x1FFF) << 16); 411 DPU_REG_WRITE(c, csc_reg_off + 0xc, val); 412 val = (data->csc_mv[8] >> matrix_shift) & 0x1FFF; 413 DPU_REG_WRITE(c, csc_reg_off + 0x10, val); 414 415 /* Pre clamp */ 416 val = (data->csc_pre_lv[0] << clamp_shift) | data->csc_pre_lv[1]; 417 DPU_REG_WRITE(c, csc_reg_off + 0x14, val); 418 val = (data->csc_pre_lv[2] << clamp_shift) | data->csc_pre_lv[3]; 419 DPU_REG_WRITE(c, csc_reg_off + 0x18, val); 420 val = (data->csc_pre_lv[4] << clamp_shift) | data->csc_pre_lv[5]; 421 DPU_REG_WRITE(c, csc_reg_off + 0x1c, val); 422 423 /* Post clamp */ 424 val = (data->csc_post_lv[0] << clamp_shift) | data->csc_post_lv[1]; 425 DPU_REG_WRITE(c, csc_reg_off + 0x20, val); 426 val = (data->csc_post_lv[2] << clamp_shift) | data->csc_post_lv[3]; 427 DPU_REG_WRITE(c, csc_reg_off + 0x24, val); 428 val = (data->csc_post_lv[4] << clamp_shift) | data->csc_post_lv[5]; 429 DPU_REG_WRITE(c, csc_reg_off + 0x28, val); 430 431 /* Pre-Bias */ 432 DPU_REG_WRITE(c, csc_reg_off + 0x2c, data->csc_pre_bv[0]); 433 DPU_REG_WRITE(c, csc_reg_off + 0x30, data->csc_pre_bv[1]); 434 DPU_REG_WRITE(c, csc_reg_off + 0x34, data->csc_pre_bv[2]); 435 436 /* Post-Bias */ 437 DPU_REG_WRITE(c, csc_reg_off + 0x38, data->csc_post_bv[0]); 438 DPU_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]); 439 DPU_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]); 440 } 441 442 /** 443 * _dpu_hw_get_qos_lut - get LUT mapping based on fill level 444 * @tbl: Pointer to LUT table 445 * @total_fl: fill level 446 * Return: LUT setting corresponding to the fill level 447 */ 448 u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl, 449 u32 total_fl) 450 { 451 int i; 452 453 if (!tbl || !tbl->nentry || !tbl->entries) 454 return 0; 455 456 for (i = 0; i < tbl->nentry; i++) 457 if (total_fl <= tbl->entries[i].fl) 458 return tbl->entries[i].lut; 459 460 /* if last fl is zero, use as default */ 461 if (!tbl->entries[i-1].fl) 462 return tbl->entries[i-1].lut; 463 464 return 0; 465 } 466 467 void _dpu_hw_setup_qos_lut(struct dpu_hw_blk_reg_map *c, u32 offset, 468 bool qos_8lvl, 469 const struct dpu_hw_qos_cfg *cfg) 470 { 471 DPU_REG_WRITE(c, offset + QOS_DANGER_LUT, cfg->danger_lut); 472 DPU_REG_WRITE(c, offset + QOS_SAFE_LUT, cfg->safe_lut); 473 474 if (qos_8lvl) { 475 DPU_REG_WRITE(c, offset + QOS_CREQ_LUT_0, cfg->creq_lut); 476 DPU_REG_WRITE(c, offset + QOS_CREQ_LUT_1, cfg->creq_lut >> 32); 477 } else { 478 DPU_REG_WRITE(c, offset + QOS_CREQ_LUT, cfg->creq_lut); 479 } 480 481 DPU_REG_WRITE(c, offset + QOS_QOS_CTRL, 482 cfg->danger_safe_en ? QOS_QOS_CTRL_DANGER_SAFE_EN : 0); 483 } 484 485 void dpu_hw_setup_qos_lut_v13(struct dpu_hw_blk_reg_map *c, 486 const struct dpu_hw_qos_cfg *cfg) 487 { 488 DPU_REG_WRITE(c, SSPP_CMN_DANGER_LUT, cfg->danger_lut); 489 DPU_REG_WRITE(c, SSPP_CMN_SAFE_LUT, cfg->safe_lut); 490 DPU_REG_WRITE(c, SSPP_CMN_CREQ_LUT_0, cfg->creq_lut); 491 DPU_REG_WRITE(c, SSPP_CMN_CREQ_LUT_1, cfg->creq_lut >> 32); 492 DPU_REG_WRITE(c, SSPP_CMN_QOS_CTRL, 493 cfg->danger_safe_en ? QOS_QOS_CTRL_DANGER_SAFE_EN : 0); 494 } 495 496 /* 497 * note: Aside from encoders, input_sel should be set to 0x0 by default 498 */ 499 void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, 500 u32 misr_ctrl_offset, u8 input_sel) 501 { 502 u32 config = 0; 503 504 DPU_REG_WRITE(c, misr_ctrl_offset, MISR_CTRL_STATUS_CLEAR); 505 506 /* Clear old MISR value (in case it's read before a new value is calculated)*/ 507 wmb(); 508 509 config = MISR_FRAME_COUNT | MISR_CTRL_ENABLE | MISR_CTRL_FREE_RUN_MASK | 510 ((input_sel & 0xF) << 24); 511 DPU_REG_WRITE(c, misr_ctrl_offset, config); 512 } 513 514 int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c, 515 u32 misr_ctrl_offset, 516 u32 misr_signature_offset, 517 u32 *misr_value) 518 { 519 u32 ctrl = 0; 520 521 if (!misr_value) 522 return -EINVAL; 523 524 ctrl = DPU_REG_READ(c, misr_ctrl_offset); 525 526 if (!(ctrl & MISR_CTRL_ENABLE)) 527 return -ENODATA; 528 529 if (!(ctrl & MISR_CTRL_STATUS)) 530 return -EINVAL; 531 532 *misr_value = DPU_REG_READ(c, misr_signature_offset); 533 534 return 0; 535 } 536 537 #define CDP_ENABLE BIT(0) 538 #define CDP_UBWC_META_ENABLE BIT(1) 539 #define CDP_TILE_AMORTIZE_ENABLE BIT(2) 540 #define CDP_PRELOAD_AHEAD_64 BIT(3) 541 542 void dpu_setup_cdp(struct dpu_hw_blk_reg_map *c, u32 offset, 543 const struct msm_format *fmt, bool enable) 544 { 545 u32 cdp_cntl = CDP_PRELOAD_AHEAD_64; 546 547 if (enable) 548 cdp_cntl |= CDP_ENABLE; 549 if (MSM_FORMAT_IS_UBWC(fmt)) 550 cdp_cntl |= CDP_UBWC_META_ENABLE; 551 if (MSM_FORMAT_IS_UBWC(fmt) || 552 MSM_FORMAT_IS_TILE(fmt)) 553 cdp_cntl |= CDP_TILE_AMORTIZE_ENABLE; 554 555 DPU_REG_WRITE(c, offset, cdp_cntl); 556 } 557 558 bool dpu_hw_clk_force_ctrl(struct dpu_hw_blk_reg_map *c, 559 const struct dpu_clk_ctrl_reg *clk_ctrl_reg, 560 bool enable) 561 { 562 u32 reg_val, new_val; 563 bool clk_forced_on; 564 565 reg_val = DPU_REG_READ(c, clk_ctrl_reg->reg_off); 566 567 if (enable) 568 new_val = reg_val | BIT(clk_ctrl_reg->bit_off); 569 else 570 new_val = reg_val & ~BIT(clk_ctrl_reg->bit_off); 571 572 DPU_REG_WRITE(c, clk_ctrl_reg->reg_off, new_val); 573 574 clk_forced_on = !(reg_val & BIT(clk_ctrl_reg->bit_off)); 575 576 return clk_forced_on; 577 } 578 579 #define TO_S15D16(_x_)((_x_) << 7) 580 581 const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = { 582 { 583 /* S15.16 format */ 584 0x00012A00, 0x00000000, 0x00019880, 585 0x00012A00, 0xFFFF9B80, 0xFFFF3000, 586 0x00012A00, 0x00020480, 0x00000000, 587 }, 588 /* signed bias */ 589 { 0xfff0, 0xff80, 0xff80,}, 590 { 0x0, 0x0, 0x0,}, 591 /* unsigned clamp */ 592 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, 593 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, 594 }; 595 596 const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = { 597 { 598 /* S15.16 format */ 599 0x00012A00, 0x00000000, 0x00019880, 600 0x00012A00, 0xFFFF9B80, 0xFFFF3000, 601 0x00012A00, 0x00020480, 0x00000000, 602 }, 603 /* signed bias */ 604 { 0xffc0, 0xfe00, 0xfe00,}, 605 { 0x0, 0x0, 0x0,}, 606 /* unsigned clamp */ 607 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, 608 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, 609 }; 610 611 const struct dpu_csc_cfg dpu_csc10_rgb2yuv_601l = { 612 { 613 TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032), 614 TO_S15D16(0x1fb5), TO_S15D16(0x1f6c), TO_S15D16(0x00e1), 615 TO_S15D16(0x00e1), TO_S15D16(0x1f45), TO_S15D16(0x1fdc) 616 }, 617 { 0x00, 0x00, 0x00 }, 618 { 0x0040, 0x0200, 0x0200 }, 619 { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, 620 { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, 621 }; 622