dpu_hw_util.c (14980B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. 3 */ 4#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ 5 6#include "msm_drv.h" 7#include "dpu_kms.h" 8#include "dpu_hw_mdss.h" 9#include "dpu_hw_util.h" 10 11/* using a file static variables for debugfs access */ 12static u32 dpu_hw_util_log_mask = DPU_DBG_MASK_NONE; 13 14/* DPU_SCALER_QSEED3 */ 15#define QSEED3_HW_VERSION 0x00 16#define QSEED3_OP_MODE 0x04 17#define QSEED3_RGB2Y_COEFF 0x08 18#define QSEED3_PHASE_INIT 0x0C 19#define QSEED3_PHASE_STEP_Y_H 0x10 20#define QSEED3_PHASE_STEP_Y_V 0x14 21#define QSEED3_PHASE_STEP_UV_H 0x18 22#define QSEED3_PHASE_STEP_UV_V 0x1C 23#define QSEED3_PRELOAD 0x20 24#define QSEED3_DE_SHARPEN 0x24 25#define QSEED3_DE_SHARPEN_CTL 0x28 26#define QSEED3_DE_SHAPE_CTL 0x2C 27#define QSEED3_DE_THRESHOLD 0x30 28#define QSEED3_DE_ADJUST_DATA_0 0x34 29#define QSEED3_DE_ADJUST_DATA_1 0x38 30#define QSEED3_DE_ADJUST_DATA_2 0x3C 31#define QSEED3_SRC_SIZE_Y_RGB_A 0x40 32#define QSEED3_SRC_SIZE_UV 0x44 33#define QSEED3_DST_SIZE 0x48 34#define QSEED3_COEF_LUT_CTRL 0x4C 35#define QSEED3_COEF_LUT_SWAP_BIT 0 36#define QSEED3_COEF_LUT_DIR_BIT 1 37#define QSEED3_COEF_LUT_Y_CIR_BIT 2 38#define QSEED3_COEF_LUT_UV_CIR_BIT 3 39#define QSEED3_COEF_LUT_Y_SEP_BIT 4 40#define QSEED3_COEF_LUT_UV_SEP_BIT 5 41#define QSEED3_BUFFER_CTRL 0x50 42#define QSEED3_CLK_CTRL0 0x54 43#define QSEED3_CLK_CTRL1 0x58 44#define QSEED3_CLK_STATUS 0x5C 45#define QSEED3_PHASE_INIT_Y_H 0x90 46#define QSEED3_PHASE_INIT_Y_V 0x94 47#define QSEED3_PHASE_INIT_UV_H 0x98 48#define QSEED3_PHASE_INIT_UV_V 0x9C 49#define QSEED3_COEF_LUT 0x100 50#define QSEED3_FILTERS 5 51#define QSEED3_LUT_REGIONS 4 52#define QSEED3_CIRCULAR_LUTS 9 53#define QSEED3_SEPARABLE_LUTS 10 54#define QSEED3_LUT_SIZE 60 55#define QSEED3_ENABLE 2 56#define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32)) 57#define QSEED3_CIR_LUT_SIZE \ 58 (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32)) 59#define QSEED3_SEP_LUT_SIZE \ 60 (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32)) 61 62/* DPU_SCALER_QSEED3LITE */ 63#define QSEED3LITE_COEF_LUT_Y_SEP_BIT 4 64#define QSEED3LITE_COEF_LUT_UV_SEP_BIT 5 65#define QSEED3LITE_COEF_LUT_CTRL 0x4C 66#define QSEED3LITE_COEF_LUT_SWAP_BIT 0 67#define QSEED3LITE_DIR_FILTER_WEIGHT 0x60 68#define QSEED3LITE_FILTERS 2 69#define QSEED3LITE_SEPARABLE_LUTS 10 70#define QSEED3LITE_LUT_SIZE 33 71#define QSEED3LITE_SEP_LUT_SIZE \ 72 (QSEED3LITE_LUT_SIZE * QSEED3LITE_SEPARABLE_LUTS * sizeof(u32)) 73 74 75void dpu_reg_write(struct dpu_hw_blk_reg_map *c, 76 u32 reg_off, 77 u32 val, 78 const char *name) 79{ 80 /* don't need to mutex protect this */ 81 if (c->log_mask & dpu_hw_util_log_mask) 82 DPU_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n", 83 name, c->blk_off + reg_off, val); 84 writel_relaxed(val, c->base_off + c->blk_off + reg_off); 85} 86 87int dpu_reg_read(struct dpu_hw_blk_reg_map *c, u32 reg_off) 88{ 89 return readl_relaxed(c->base_off + c->blk_off + reg_off); 90} 91 92u32 *dpu_hw_util_get_log_mask_ptr(void) 93{ 94 return &dpu_hw_util_log_mask; 95} 96 97static void _dpu_hw_setup_scaler3_lut(struct dpu_hw_blk_reg_map *c, 98 struct dpu_hw_scaler3_cfg *scaler3_cfg, u32 offset) 99{ 100 int i, j, filter; 101 int config_lut = 0x0; 102 unsigned long lut_flags; 103 u32 lut_addr, lut_offset, lut_len; 104 u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL}; 105 static const uint32_t off_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = { 106 {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} }, 107 {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} }, 108 {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} }, 109 {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} }, 110 {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} }, 111 }; 112 113 lut_flags = (unsigned long) scaler3_cfg->lut_flag; 114 if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) && 115 (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) { 116 lut[0] = scaler3_cfg->dir_lut; 117 config_lut = 1; 118 } 119 if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) && 120 (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && 121 (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { 122 lut[1] = scaler3_cfg->cir_lut + 123 scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE; 124 config_lut = 1; 125 } 126 if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) && 127 (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && 128 (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { 129 lut[2] = scaler3_cfg->cir_lut + 130 scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE; 131 config_lut = 1; 132 } 133 if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) && 134 (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && 135 (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { 136 lut[3] = scaler3_cfg->sep_lut + 137 scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE; 138 config_lut = 1; 139 } 140 if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) && 141 (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && 142 (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { 143 lut[4] = scaler3_cfg->sep_lut + 144 scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE; 145 config_lut = 1; 146 } 147 148 if (config_lut) { 149 for (filter = 0; filter < QSEED3_FILTERS; filter++) { 150 if (!lut[filter]) 151 continue; 152 lut_offset = 0; 153 for (i = 0; i < QSEED3_LUT_REGIONS; i++) { 154 lut_addr = QSEED3_COEF_LUT + offset 155 + off_tbl[filter][i][1]; 156 lut_len = off_tbl[filter][i][0] << 2; 157 for (j = 0; j < lut_len; j++) { 158 DPU_REG_WRITE(c, 159 lut_addr, 160 (lut[filter])[lut_offset++]); 161 lut_addr += 4; 162 } 163 } 164 } 165 } 166 167 if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags)) 168 DPU_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0)); 169 170} 171 172static void _dpu_hw_setup_scaler3lite_lut(struct dpu_hw_blk_reg_map *c, 173 struct dpu_hw_scaler3_cfg *scaler3_cfg, u32 offset) 174{ 175 int j, filter; 176 int config_lut = 0x0; 177 unsigned long lut_flags; 178 u32 lut_addr, lut_offset; 179 u32 *lut[QSEED3LITE_FILTERS] = {NULL, NULL}; 180 static const uint32_t off_tbl[QSEED3_FILTERS] = { 0x000, 0x200 }; 181 182 DPU_REG_WRITE(c, QSEED3LITE_DIR_FILTER_WEIGHT + offset, scaler3_cfg->dir_weight); 183 184 if (!scaler3_cfg->sep_lut) 185 return; 186 187 lut_flags = (unsigned long) scaler3_cfg->lut_flag; 188 if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) && 189 (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3LITE_SEPARABLE_LUTS) && 190 (scaler3_cfg->sep_len == QSEED3LITE_SEP_LUT_SIZE)) { 191 lut[0] = scaler3_cfg->sep_lut + 192 scaler3_cfg->y_rgb_sep_lut_idx * QSEED3LITE_LUT_SIZE; 193 config_lut = 1; 194 } 195 if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) && 196 (scaler3_cfg->uv_sep_lut_idx < QSEED3LITE_SEPARABLE_LUTS) && 197 (scaler3_cfg->sep_len == QSEED3LITE_SEP_LUT_SIZE)) { 198 lut[1] = scaler3_cfg->sep_lut + 199 scaler3_cfg->uv_sep_lut_idx * QSEED3LITE_LUT_SIZE; 200 config_lut = 1; 201 } 202 203 if (config_lut) { 204 for (filter = 0; filter < QSEED3LITE_FILTERS; filter++) { 205 if (!lut[filter]) 206 continue; 207 lut_offset = 0; 208 lut_addr = QSEED3_COEF_LUT + offset + off_tbl[filter]; 209 for (j = 0; j < QSEED3LITE_LUT_SIZE; j++) { 210 DPU_REG_WRITE(c, 211 lut_addr, 212 (lut[filter])[lut_offset++]); 213 lut_addr += 4; 214 } 215 } 216 } 217 218 if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags)) 219 DPU_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0)); 220 221} 222 223static void _dpu_hw_setup_scaler3_de(struct dpu_hw_blk_reg_map *c, 224 struct dpu_hw_scaler3_de_cfg *de_cfg, u32 offset) 225{ 226 u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr; 227 u32 adjust_a, adjust_b, adjust_c; 228 229 if (!de_cfg->enable) 230 return; 231 232 sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) | 233 ((de_cfg->sharpen_level2 & 0x1FF) << 16); 234 235 sharp_ctl = ((de_cfg->limit & 0xF) << 9) | 236 ((de_cfg->prec_shift & 0x7) << 13) | 237 ((de_cfg->clip & 0x7) << 16); 238 239 shape_ctl = (de_cfg->thr_quiet & 0xFF) | 240 ((de_cfg->thr_dieout & 0x3FF) << 16); 241 242 de_thr = (de_cfg->thr_low & 0x3FF) | 243 ((de_cfg->thr_high & 0x3FF) << 16); 244 245 adjust_a = (de_cfg->adjust_a[0] & 0x3FF) | 246 ((de_cfg->adjust_a[1] & 0x3FF) << 10) | 247 ((de_cfg->adjust_a[2] & 0x3FF) << 20); 248 249 adjust_b = (de_cfg->adjust_b[0] & 0x3FF) | 250 ((de_cfg->adjust_b[1] & 0x3FF) << 10) | 251 ((de_cfg->adjust_b[2] & 0x3FF) << 20); 252 253 adjust_c = (de_cfg->adjust_c[0] & 0x3FF) | 254 ((de_cfg->adjust_c[1] & 0x3FF) << 10) | 255 ((de_cfg->adjust_c[2] & 0x3FF) << 20); 256 257 DPU_REG_WRITE(c, QSEED3_DE_SHARPEN + offset, sharp_lvl); 258 DPU_REG_WRITE(c, QSEED3_DE_SHARPEN_CTL + offset, sharp_ctl); 259 DPU_REG_WRITE(c, QSEED3_DE_SHAPE_CTL + offset, shape_ctl); 260 DPU_REG_WRITE(c, QSEED3_DE_THRESHOLD + offset, de_thr); 261 DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_0 + offset, adjust_a); 262 DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_1 + offset, adjust_b); 263 DPU_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_2 + offset, adjust_c); 264 265} 266 267void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, 268 struct dpu_hw_scaler3_cfg *scaler3_cfg, 269 u32 scaler_offset, u32 scaler_version, 270 const struct dpu_format *format) 271{ 272 u32 op_mode = 0; 273 u32 phase_init, preload, src_y_rgb, src_uv, dst; 274 275 if (!scaler3_cfg->enable) 276 goto end; 277 278 op_mode |= BIT(0); 279 op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16; 280 281 if (format && DPU_FORMAT_IS_YUV(format)) { 282 op_mode |= BIT(12); 283 op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24; 284 } 285 286 op_mode |= (scaler3_cfg->blend_cfg & 1) << 31; 287 op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0; 288 289 preload = 290 ((scaler3_cfg->preload_x[0] & 0x7F) << 0) | 291 ((scaler3_cfg->preload_y[0] & 0x7F) << 8) | 292 ((scaler3_cfg->preload_x[1] & 0x7F) << 16) | 293 ((scaler3_cfg->preload_y[1] & 0x7F) << 24); 294 295 src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) | 296 ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16); 297 298 src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) | 299 ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16); 300 301 dst = (scaler3_cfg->dst_width & 0x1FFFF) | 302 ((scaler3_cfg->dst_height & 0x1FFFF) << 16); 303 304 if (scaler3_cfg->de.enable) { 305 _dpu_hw_setup_scaler3_de(c, &scaler3_cfg->de, scaler_offset); 306 op_mode |= BIT(8); 307 } 308 309 if (scaler3_cfg->lut_flag) { 310 if (scaler_version < 0x2004) 311 _dpu_hw_setup_scaler3_lut(c, scaler3_cfg, scaler_offset); 312 else 313 _dpu_hw_setup_scaler3lite_lut(c, scaler3_cfg, scaler_offset); 314 } 315 316 if (scaler_version == 0x1002) { 317 phase_init = 318 ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) | 319 ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) | 320 ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) | 321 ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24); 322 DPU_REG_WRITE(c, QSEED3_PHASE_INIT + scaler_offset, phase_init); 323 } else { 324 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_Y_H + scaler_offset, 325 scaler3_cfg->init_phase_x[0] & 0x1FFFFF); 326 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_Y_V + scaler_offset, 327 scaler3_cfg->init_phase_y[0] & 0x1FFFFF); 328 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_UV_H + scaler_offset, 329 scaler3_cfg->init_phase_x[1] & 0x1FFFFF); 330 DPU_REG_WRITE(c, QSEED3_PHASE_INIT_UV_V + scaler_offset, 331 scaler3_cfg->init_phase_y[1] & 0x1FFFFF); 332 } 333 334 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_Y_H + scaler_offset, 335 scaler3_cfg->phase_step_x[0] & 0xFFFFFF); 336 337 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_Y_V + scaler_offset, 338 scaler3_cfg->phase_step_y[0] & 0xFFFFFF); 339 340 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_UV_H + scaler_offset, 341 scaler3_cfg->phase_step_x[1] & 0xFFFFFF); 342 343 DPU_REG_WRITE(c, QSEED3_PHASE_STEP_UV_V + scaler_offset, 344 scaler3_cfg->phase_step_y[1] & 0xFFFFFF); 345 346 DPU_REG_WRITE(c, QSEED3_PRELOAD + scaler_offset, preload); 347 348 DPU_REG_WRITE(c, QSEED3_SRC_SIZE_Y_RGB_A + scaler_offset, src_y_rgb); 349 350 DPU_REG_WRITE(c, QSEED3_SRC_SIZE_UV + scaler_offset, src_uv); 351 352 DPU_REG_WRITE(c, QSEED3_DST_SIZE + scaler_offset, dst); 353 354end: 355 if (format && !DPU_FORMAT_IS_DX(format)) 356 op_mode |= BIT(14); 357 358 if (format && format->alpha_enable) { 359 op_mode |= BIT(10); 360 if (scaler_version == 0x1002) 361 op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30; 362 else 363 op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29; 364 } 365 366 DPU_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode); 367} 368 369u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, 370 u32 scaler_offset) 371{ 372 return DPU_REG_READ(c, QSEED3_HW_VERSION + scaler_offset); 373} 374 375void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, 376 u32 csc_reg_off, 377 const struct dpu_csc_cfg *data, bool csc10) 378{ 379 static const u32 matrix_shift = 7; 380 u32 clamp_shift = csc10 ? 16 : 8; 381 u32 val; 382 383 /* matrix coeff - convert S15.16 to S4.9 */ 384 val = ((data->csc_mv[0] >> matrix_shift) & 0x1FFF) | 385 (((data->csc_mv[1] >> matrix_shift) & 0x1FFF) << 16); 386 DPU_REG_WRITE(c, csc_reg_off, val); 387 val = ((data->csc_mv[2] >> matrix_shift) & 0x1FFF) | 388 (((data->csc_mv[3] >> matrix_shift) & 0x1FFF) << 16); 389 DPU_REG_WRITE(c, csc_reg_off + 0x4, val); 390 val = ((data->csc_mv[4] >> matrix_shift) & 0x1FFF) | 391 (((data->csc_mv[5] >> matrix_shift) & 0x1FFF) << 16); 392 DPU_REG_WRITE(c, csc_reg_off + 0x8, val); 393 val = ((data->csc_mv[6] >> matrix_shift) & 0x1FFF) | 394 (((data->csc_mv[7] >> matrix_shift) & 0x1FFF) << 16); 395 DPU_REG_WRITE(c, csc_reg_off + 0xc, val); 396 val = (data->csc_mv[8] >> matrix_shift) & 0x1FFF; 397 DPU_REG_WRITE(c, csc_reg_off + 0x10, val); 398 399 /* Pre clamp */ 400 val = (data->csc_pre_lv[0] << clamp_shift) | data->csc_pre_lv[1]; 401 DPU_REG_WRITE(c, csc_reg_off + 0x14, val); 402 val = (data->csc_pre_lv[2] << clamp_shift) | data->csc_pre_lv[3]; 403 DPU_REG_WRITE(c, csc_reg_off + 0x18, val); 404 val = (data->csc_pre_lv[4] << clamp_shift) | data->csc_pre_lv[5]; 405 DPU_REG_WRITE(c, csc_reg_off + 0x1c, val); 406 407 /* Post clamp */ 408 val = (data->csc_post_lv[0] << clamp_shift) | data->csc_post_lv[1]; 409 DPU_REG_WRITE(c, csc_reg_off + 0x20, val); 410 val = (data->csc_post_lv[2] << clamp_shift) | data->csc_post_lv[3]; 411 DPU_REG_WRITE(c, csc_reg_off + 0x24, val); 412 val = (data->csc_post_lv[4] << clamp_shift) | data->csc_post_lv[5]; 413 DPU_REG_WRITE(c, csc_reg_off + 0x28, val); 414 415 /* Pre-Bias */ 416 DPU_REG_WRITE(c, csc_reg_off + 0x2c, data->csc_pre_bv[0]); 417 DPU_REG_WRITE(c, csc_reg_off + 0x30, data->csc_pre_bv[1]); 418 DPU_REG_WRITE(c, csc_reg_off + 0x34, data->csc_pre_bv[2]); 419 420 /* Post-Bias */ 421 DPU_REG_WRITE(c, csc_reg_off + 0x38, data->csc_post_bv[0]); 422 DPU_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]); 423 DPU_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]); 424} 425 426/** 427 * _dpu_hw_get_qos_lut - get LUT mapping based on fill level 428 * @tbl: Pointer to LUT table 429 * @total_fl: fill level 430 * Return: LUT setting corresponding to the fill level 431 */ 432u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl, 433 u32 total_fl) 434{ 435 int i; 436 437 if (!tbl || !tbl->nentry || !tbl->entries) 438 return 0; 439 440 for (i = 0; i < tbl->nentry; i++) 441 if (total_fl <= tbl->entries[i].fl) 442 return tbl->entries[i].lut; 443 444 /* if last fl is zero, use as default */ 445 if (!tbl->entries[i-1].fl) 446 return tbl->entries[i-1].lut; 447 448 return 0; 449}