1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. 4 * Author: James.Qian.Wang <james.qian.wang@arm.com> 5 * 6 */ 7 8 #include <drm/drm_print.h> 9 #include "d71_dev.h" 10 #include "komeda_kms.h" 11 #include "malidp_io.h" 12 #include "komeda_framebuffer.h" 13 #include "komeda_color_mgmt.h" 14 15 static void get_resources_id(u32 hw_id, u32 *pipe_id, u32 *comp_id) 16 { 17 u32 id = BLOCK_INFO_BLK_ID(hw_id); 18 u32 pipe = id; 19 20 switch (BLOCK_INFO_BLK_TYPE(hw_id)) { 21 case D71_BLK_TYPE_LPU_WB_LAYER: 22 id = KOMEDA_COMPONENT_WB_LAYER; 23 break; 24 case D71_BLK_TYPE_CU_SPLITTER: 25 id = KOMEDA_COMPONENT_SPLITTER; 26 break; 27 case D71_BLK_TYPE_CU_SCALER: 28 pipe = id / D71_PIPELINE_MAX_SCALERS; 29 id %= D71_PIPELINE_MAX_SCALERS; 30 id += KOMEDA_COMPONENT_SCALER0; 31 break; 32 case D71_BLK_TYPE_CU: 33 id += KOMEDA_COMPONENT_COMPIZ0; 34 break; 35 case D71_BLK_TYPE_LPU_LAYER: 36 pipe = id / D71_PIPELINE_MAX_LAYERS; 37 id %= D71_PIPELINE_MAX_LAYERS; 38 id += KOMEDA_COMPONENT_LAYER0; 39 break; 40 case D71_BLK_TYPE_DOU_IPS: 41 id += KOMEDA_COMPONENT_IPS0; 42 break; 43 case D71_BLK_TYPE_CU_MERGER: 44 id = KOMEDA_COMPONENT_MERGER; 45 break; 46 case D71_BLK_TYPE_DOU: 47 id = KOMEDA_COMPONENT_TIMING_CTRLR; 48 break; 49 default: 50 id = 0xFFFFFFFF; 51 } 52 53 if (comp_id) 54 *comp_id = id; 55 56 if (pipe_id) 57 *pipe_id = pipe; 58 } 59 60 static u32 get_valid_inputs(struct block_header *blk) 61 { 62 u32 valid_inputs = 0, comp_id; 63 int i; 64 65 for (i = 0; i < PIPELINE_INFO_N_VALID_INPUTS(blk->pipeline_info); i++) { 66 get_resources_id(blk->input_ids[i], NULL, &comp_id); 67 if (comp_id == 0xFFFFFFFF) 68 continue; 69 valid_inputs |= BIT(comp_id); 70 } 71 72 return valid_inputs; 73 } 74 75 static void get_values_from_reg(void __iomem *reg, u32 offset, 76 u32 count, u32 *val) 77 { 78 u32 i, addr; 79 80 for (i = 0; i < count; i++) { 81 addr = offset + (i << 2); 82 /* 0xA4 is WO register */ 83 if (addr != 0xA4) 84 val[i] = malidp_read32(reg, addr); 85 else 86 val[i] = 0xDEADDEAD; 87 } 88 } 89 90 static void dump_block_header(struct seq_file *sf, void __iomem *reg) 91 { 92 struct block_header hdr; 93 u32 i, n_input, n_output; 94 95 d71_read_block_header(reg, &hdr); 96 seq_printf(sf, "BLOCK_INFO:\t\t0x%X\n", hdr.block_info); 97 seq_printf(sf, "PIPELINE_INFO:\t\t0x%X\n", hdr.pipeline_info); 98 99 n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info); 100 n_input = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info); 101 102 for (i = 0; i < n_input; i++) 103 seq_printf(sf, "VALID_INPUT_ID%u:\t0x%X\n", 104 i, hdr.input_ids[i]); 105 106 for (i = 0; i < n_output; i++) 107 seq_printf(sf, "OUTPUT_ID%u:\t\t0x%X\n", 108 i, hdr.output_ids[i]); 109 } 110 111 static u32 to_rot_ctrl(u32 rot) 112 { 113 u32 lr_ctrl = 0; 114 115 switch (rot & DRM_MODE_ROTATE_MASK) { 116 case DRM_MODE_ROTATE_0: 117 lr_ctrl |= L_ROT(L_ROT_R0); 118 break; 119 case DRM_MODE_ROTATE_90: 120 lr_ctrl |= L_ROT(L_ROT_R90); 121 break; 122 case DRM_MODE_ROTATE_180: 123 lr_ctrl |= L_ROT(L_ROT_R180); 124 break; 125 case DRM_MODE_ROTATE_270: 126 lr_ctrl |= L_ROT(L_ROT_R270); 127 break; 128 } 129 130 if (rot & DRM_MODE_REFLECT_X) 131 lr_ctrl |= L_HFLIP; 132 if (rot & DRM_MODE_REFLECT_Y) 133 lr_ctrl |= L_VFLIP; 134 135 return lr_ctrl; 136 } 137 138 static u32 to_ad_ctrl(u64 modifier) 139 { 140 u32 afbc_ctrl = AD_AEN; 141 142 if (!modifier) 143 return 0; 144 145 if ((modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) == 146 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) 147 afbc_ctrl |= AD_WB; 148 149 if (modifier & AFBC_FORMAT_MOD_YTR) 150 afbc_ctrl |= AD_YT; 151 if (modifier & AFBC_FORMAT_MOD_SPLIT) 152 afbc_ctrl |= AD_BS; 153 if (modifier & AFBC_FORMAT_MOD_TILED) 154 afbc_ctrl |= AD_TH; 155 156 return afbc_ctrl; 157 } 158 159 static inline u32 to_d71_input_id(struct komeda_component_output *output) 160 { 161 struct komeda_component *comp = output->component; 162 163 return comp ? (comp->hw_id + output->output_port) : 0; 164 } 165 166 static void d71_layer_update_fb(struct komeda_component *c, 167 struct komeda_fb *kfb, 168 dma_addr_t *addr) 169 { 170 struct drm_framebuffer *fb = &kfb->base; 171 const struct drm_format_info *info = fb->format; 172 u32 __iomem *reg = c->reg; 173 int block_h; 174 175 if (info->num_planes > 2) 176 malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]); 177 178 if (info->num_planes > 1) { 179 block_h = drm_format_info_block_height(info, 1); 180 malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h); 181 malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]); 182 } 183 184 block_h = drm_format_info_block_height(info, 0); 185 malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h); 186 malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]); 187 malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id); 188 } 189 190 static void d71_layer_disable(struct komeda_component *c) 191 { 192 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0); 193 } 194 195 static void d71_layer_update(struct komeda_component *c, 196 struct komeda_component_state *state) 197 { 198 struct komeda_layer_state *st = to_layer_st(state); 199 struct drm_plane_state *plane_st = state->plane->state; 200 struct drm_framebuffer *fb = plane_st->fb; 201 struct komeda_fb *kfb = to_kfb(fb); 202 u32 __iomem *reg = c->reg; 203 u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN; 204 u32 ctrl = L_EN | to_rot_ctrl(st->rot); 205 206 d71_layer_update_fb(c, kfb, st->addr); 207 208 malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier)); 209 if (fb->modifier) { 210 u64 addr; 211 212 malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l, 213 st->afbc_crop_r)); 214 malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t, 215 st->afbc_crop_b)); 216 /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */ 217 if (fb->modifier & AFBC_FORMAT_MOD_TILED) 218 addr = st->addr[0] + kfb->offset_payload; 219 else 220 addr = st->addr[0] + kfb->afbc_size - 1; 221 222 malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr)); 223 malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr)); 224 } 225 226 if (fb->format->is_yuv) { 227 u32 upsampling = 0; 228 229 switch (kfb->format_caps->fourcc) { 230 case DRM_FORMAT_YUYV: 231 upsampling = fb->modifier ? LR_CHI422_BILINEAR : 232 LR_CHI422_REPLICATION; 233 break; 234 case DRM_FORMAT_UYVY: 235 upsampling = LR_CHI422_REPLICATION; 236 break; 237 case DRM_FORMAT_NV12: 238 case DRM_FORMAT_YUV420_8BIT: 239 case DRM_FORMAT_YUV420_10BIT: 240 case DRM_FORMAT_YUV420: 241 case DRM_FORMAT_P010: 242 /* these fmt support MPGE/JPEG both, here perfer JPEG*/ 243 upsampling = LR_CHI420_JPEG; 244 break; 245 case DRM_FORMAT_X0L2: 246 upsampling = LR_CHI420_JPEG; 247 break; 248 default: 249 break; 250 } 251 252 malidp_write32(reg, LAYER_R_CONTROL, upsampling); 253 malidp_write_group(reg, LAYER_YUV_RGB_COEFF0, 254 KOMEDA_N_YUV2RGB_COEFFS, 255 komeda_select_yuv2rgb_coeffs( 256 plane_st->color_encoding, 257 plane_st->color_range)); 258 } 259 260 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize)); 261 262 if (kfb->is_va) 263 ctrl |= L_TBU_EN; 264 malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl); 265 } 266 267 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf) 268 { 269 u32 v[15], i; 270 bool rich, rgb2rgb; 271 char *prefix; 272 273 get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]); 274 if (v[14] & 0x1) { 275 rich = true; 276 prefix = "LR_"; 277 } else { 278 rich = false; 279 prefix = "LS_"; 280 } 281 282 rgb2rgb = !!(v[14] & L_INFO_CM); 283 284 dump_block_header(sf, c->reg); 285 286 seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]); 287 288 get_values_from_reg(c->reg, 0xD0, 1, v); 289 seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]); 290 if (rich) { 291 get_values_from_reg(c->reg, 0xD4, 1, v); 292 seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]); 293 } 294 get_values_from_reg(c->reg, 0xD8, 4, v); 295 seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]); 296 seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]); 297 seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]); 298 seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]); 299 300 get_values_from_reg(c->reg, 0x100, 3, v); 301 seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]); 302 seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]); 303 seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]); 304 305 get_values_from_reg(c->reg, 0x110, 2, v); 306 seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]); 307 seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]); 308 if (rich) { 309 get_values_from_reg(c->reg, 0x118, 1, v); 310 seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]); 311 312 get_values_from_reg(c->reg, 0x120, 2, v); 313 seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]); 314 seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]); 315 316 get_values_from_reg(c->reg, 0x130, 12, v); 317 for (i = 0; i < 12; i++) 318 seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]); 319 } 320 321 if (rgb2rgb) { 322 get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v); 323 for (i = 0; i < 12; i++) 324 seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]); 325 } 326 327 get_values_from_reg(c->reg, 0x160, 3, v); 328 seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]); 329 seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]); 330 seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]); 331 } 332 333 static const struct komeda_component_funcs d71_layer_funcs = { 334 .update = d71_layer_update, 335 .disable = d71_layer_disable, 336 .dump_register = d71_layer_dump, 337 }; 338 339 static int d71_layer_init(struct d71_dev *d71, 340 struct block_header *blk, u32 __iomem *reg) 341 { 342 struct komeda_component *c; 343 struct komeda_layer *layer; 344 u32 pipe_id, layer_id, layer_info; 345 346 get_resources_id(blk->block_info, &pipe_id, &layer_id); 347 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer), 348 layer_id, 349 BLOCK_INFO_INPUT_ID(blk->block_info), 350 &d71_layer_funcs, 0, 351 get_valid_inputs(blk), 352 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id); 353 if (IS_ERR(c)) { 354 DRM_ERROR("Failed to add layer component\n"); 355 return PTR_ERR(c); 356 } 357 358 layer = to_layer(c); 359 layer_info = malidp_read32(reg, LAYER_INFO); 360 361 if (layer_info & L_INFO_RF) 362 layer->layer_type = KOMEDA_FMT_RICH_LAYER; 363 else 364 layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER; 365 366 set_range(&layer->hsize_in, 4, d71->max_line_size); 367 set_range(&layer->vsize_in, 4, d71->max_vsize); 368 369 malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP); 370 371 layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK; 372 373 return 0; 374 } 375 376 static void d71_wb_layer_update(struct komeda_component *c, 377 struct komeda_component_state *state) 378 { 379 struct komeda_layer_state *st = to_layer_st(state); 380 struct drm_connector_state *conn_st = state->wb_conn->state; 381 struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb); 382 u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN; 383 u32 __iomem *reg = c->reg; 384 385 d71_layer_update_fb(c, kfb, st->addr); 386 387 if (kfb->is_va) 388 ctrl |= LW_TBU_EN; 389 390 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize)); 391 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0])); 392 malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); 393 } 394 395 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf) 396 { 397 u32 v[12], i; 398 399 dump_block_header(sf, c->reg); 400 401 get_values_from_reg(c->reg, 0x80, 1, v); 402 seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]); 403 404 get_values_from_reg(c->reg, 0xD0, 3, v); 405 seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]); 406 seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]); 407 seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]); 408 409 get_values_from_reg(c->reg, 0xE0, 1, v); 410 seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]); 411 412 for (i = 0; i < 2; i++) { 413 get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v); 414 seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]); 415 seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]); 416 seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]); 417 } 418 419 get_values_from_reg(c->reg, 0x130, 12, v); 420 for (i = 0; i < 12; i++) 421 seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]); 422 } 423 424 static void d71_wb_layer_disable(struct komeda_component *c) 425 { 426 malidp_write32(c->reg, BLK_INPUT_ID0, 0); 427 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0); 428 } 429 430 static const struct komeda_component_funcs d71_wb_layer_funcs = { 431 .update = d71_wb_layer_update, 432 .disable = d71_wb_layer_disable, 433 .dump_register = d71_wb_layer_dump, 434 }; 435 436 static int d71_wb_layer_init(struct d71_dev *d71, 437 struct block_header *blk, u32 __iomem *reg) 438 { 439 struct komeda_component *c; 440 struct komeda_layer *wb_layer; 441 u32 pipe_id, layer_id; 442 443 get_resources_id(blk->block_info, &pipe_id, &layer_id); 444 445 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer), 446 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info), 447 &d71_wb_layer_funcs, 448 1, get_valid_inputs(blk), 0, reg, 449 "LPU%d_LAYER_WR", pipe_id); 450 if (IS_ERR(c)) { 451 DRM_ERROR("Failed to add wb_layer component\n"); 452 return PTR_ERR(c); 453 } 454 455 wb_layer = to_layer(c); 456 wb_layer->layer_type = KOMEDA_FMT_WB_LAYER; 457 458 set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size); 459 set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize); 460 461 return 0; 462 } 463 464 static void d71_component_disable(struct komeda_component *c) 465 { 466 u32 __iomem *reg = c->reg; 467 u32 i; 468 469 malidp_write32(reg, BLK_CONTROL, 0); 470 471 for (i = 0; i < c->max_active_inputs; i++) { 472 malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0); 473 474 /* Besides clearing the input ID to zero, D71 compiz also has 475 * input enable bit in CU_INPUTx_CONTROL which need to be 476 * cleared. 477 */ 478 if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS)) 479 malidp_write32(reg, CU_INPUT0_CONTROL + 480 i * CU_PER_INPUT_REGS * 4, 481 CU_INPUT_CTRL_ALPHA(0xFF)); 482 } 483 } 484 485 static void compiz_enable_input(u32 __iomem *id_reg, 486 u32 __iomem *cfg_reg, 487 u32 input_hw_id, 488 struct komeda_compiz_input_cfg *cin) 489 { 490 u32 ctrl = CU_INPUT_CTRL_EN; 491 u8 blend = cin->pixel_blend_mode; 492 493 if (blend == DRM_MODE_BLEND_PIXEL_NONE) 494 ctrl |= CU_INPUT_CTRL_PAD; 495 else if (blend == DRM_MODE_BLEND_PREMULTI) 496 ctrl |= CU_INPUT_CTRL_PMUL; 497 498 ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha); 499 500 malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id); 501 502 malidp_write32(cfg_reg, CU_INPUT0_SIZE, 503 HV_SIZE(cin->hsize, cin->vsize)); 504 malidp_write32(cfg_reg, CU_INPUT0_OFFSET, 505 HV_OFFSET(cin->hoffset, cin->voffset)); 506 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl); 507 } 508 509 static void d71_compiz_update(struct komeda_component *c, 510 struct komeda_component_state *state) 511 { 512 struct komeda_compiz_state *st = to_compiz_st(state); 513 u32 __iomem *reg = c->reg; 514 u32 __iomem *id_reg, *cfg_reg; 515 u32 index, input_hw_id; 516 517 for_each_changed_input(state, index) { 518 id_reg = reg + index; 519 cfg_reg = reg + index * CU_PER_INPUT_REGS; 520 input_hw_id = to_d71_input_id(&state->inputs[index]); 521 if (state->active_inputs & BIT(index)) { 522 compiz_enable_input(id_reg, cfg_reg, 523 input_hw_id, &st->cins[index]); 524 } else { 525 malidp_write32(id_reg, BLK_INPUT_ID0, 0); 526 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0); 527 } 528 } 529 530 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); 531 } 532 533 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf) 534 { 535 u32 v[8], i; 536 537 dump_block_header(sf, c->reg); 538 539 get_values_from_reg(c->reg, 0x80, 5, v); 540 for (i = 0; i < 5; i++) 541 seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]); 542 543 get_values_from_reg(c->reg, 0xA0, 5, v); 544 seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]); 545 seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]); 546 seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]); 547 seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]); 548 seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]); 549 550 get_values_from_reg(c->reg, 0xD0, 2, v); 551 seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]); 552 seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]); 553 554 get_values_from_reg(c->reg, 0xDC, 1, v); 555 seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]); 556 557 for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) { 558 get_values_from_reg(c->reg, v[4], 3, v); 559 seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]); 560 seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]); 561 seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]); 562 } 563 564 get_values_from_reg(c->reg, 0x130, 2, v); 565 seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]); 566 seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]); 567 } 568 569 static const struct komeda_component_funcs d71_compiz_funcs = { 570 .update = d71_compiz_update, 571 .disable = d71_component_disable, 572 .dump_register = d71_compiz_dump, 573 }; 574 575 static int d71_compiz_init(struct d71_dev *d71, 576 struct block_header *blk, u32 __iomem *reg) 577 { 578 struct komeda_component *c; 579 struct komeda_compiz *compiz; 580 u32 pipe_id, comp_id; 581 582 get_resources_id(blk->block_info, &pipe_id, &comp_id); 583 584 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz), 585 comp_id, 586 BLOCK_INFO_INPUT_ID(blk->block_info), 587 &d71_compiz_funcs, 588 CU_NUM_INPUT_IDS, get_valid_inputs(blk), 589 CU_NUM_OUTPUT_IDS, reg, 590 "CU%d", pipe_id); 591 if (IS_ERR(c)) 592 return PTR_ERR(c); 593 594 compiz = to_compiz(c); 595 596 set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size); 597 set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize); 598 599 return 0; 600 } 601 602 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in, 603 u32 vsize_in, u32 hsize_out, 604 u32 vsize_out) 605 { 606 u32 val = 0; 607 608 if (hsize_in <= hsize_out) 609 val |= 0x62; 610 else if (hsize_in <= (hsize_out + hsize_out / 2)) 611 val |= 0x63; 612 else if (hsize_in <= hsize_out * 2) 613 val |= 0x64; 614 else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4) 615 val |= 0x65; 616 else 617 val |= 0x66; 618 619 if (vsize_in <= vsize_out) 620 val |= SC_VTSEL(0x6A); 621 else if (vsize_in <= (vsize_out + vsize_out / 2)) 622 val |= SC_VTSEL(0x6B); 623 else if (vsize_in <= vsize_out * 2) 624 val |= SC_VTSEL(0x6C); 625 else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4) 626 val |= SC_VTSEL(0x6D); 627 else 628 val |= SC_VTSEL(0x6E); 629 630 malidp_write32(reg, SC_COEFFTAB, val); 631 } 632 633 static void d71_scaler_update(struct komeda_component *c, 634 struct komeda_component_state *state) 635 { 636 struct komeda_scaler_state *st = to_scaler_st(state); 637 u32 __iomem *reg = c->reg; 638 u32 init_ph, delta_ph, ctrl; 639 640 d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in, 641 st->hsize_out, st->vsize_out); 642 643 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in)); 644 malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out)); 645 646 init_ph = (st->hsize_in << 15) / st->hsize_out; 647 malidp_write32(reg, SC_H_INIT_PH, init_ph); 648 649 delta_ph = (st->hsize_in << 16) / st->hsize_out; 650 malidp_write32(reg, SC_H_DELTA_PH, delta_ph); 651 652 init_ph = (st->vsize_in << 15) / st->vsize_out; 653 malidp_write32(reg, SC_V_INIT_PH, init_ph); 654 655 delta_ph = (st->vsize_in << 16) / st->vsize_out; 656 malidp_write32(reg, SC_V_DELTA_PH, delta_ph); 657 658 ctrl = 0; 659 ctrl |= st->en_scaling ? SC_CTRL_SCL : 0; 660 ctrl |= st->en_alpha ? SC_CTRL_AP : 0; 661 ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0; 662 663 malidp_write32(reg, BLK_CONTROL, ctrl); 664 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(&state->inputs[0])); 665 } 666 667 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf) 668 { 669 u32 v[9]; 670 671 dump_block_header(sf, c->reg); 672 673 get_values_from_reg(c->reg, 0x80, 1, v); 674 seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]); 675 676 get_values_from_reg(c->reg, 0xD0, 1, v); 677 seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]); 678 679 get_values_from_reg(c->reg, 0xDC, 9, v); 680 seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]); 681 seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]); 682 seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]); 683 seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]); 684 seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]); 685 seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]); 686 seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]); 687 seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]); 688 seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]); 689 } 690 691 static const struct komeda_component_funcs d71_scaler_funcs = { 692 .update = d71_scaler_update, 693 .disable = d71_component_disable, 694 .dump_register = d71_scaler_dump, 695 }; 696 697 static int d71_scaler_init(struct d71_dev *d71, 698 struct block_header *blk, u32 __iomem *reg) 699 { 700 struct komeda_component *c; 701 struct komeda_scaler *scaler; 702 u32 pipe_id, comp_id; 703 704 get_resources_id(blk->block_info, &pipe_id, &comp_id); 705 706 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler), 707 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info), 708 &d71_scaler_funcs, 709 1, get_valid_inputs(blk), 1, reg, 710 "CU%d_SCALER%d", 711 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info)); 712 713 if (IS_ERR(c)) { 714 DRM_ERROR("Failed to initialize scaler"); 715 return PTR_ERR(c); 716 } 717 718 scaler = to_scaler(c); 719 set_range(&scaler->hsize, 4, d71->max_line_size); 720 set_range(&scaler->vsize, 4, 4096); 721 scaler->max_downscaling = 6; 722 scaler->max_upscaling = 64; 723 724 malidp_write32(c->reg, BLK_CONTROL, 0); 725 726 return 0; 727 } 728 729 static int d71_downscaling_clk_check(struct komeda_pipeline *pipe, 730 struct drm_display_mode *mode, 731 unsigned long mclk_rate, 732 struct komeda_data_flow_cfg *dflow) 733 { 734 u32 h_in = dflow->in_w; 735 u32 v_in = dflow->in_h; 736 u32 v_out = dflow->out_h; 737 u64 fraction, denominator; 738 739 /* D71 downscaling must satisfy the following equation 740 * 741 * MCLK h_in * v_in 742 * ------- >= --------------------------------------------- 743 * PXLCLK (h_total - (1 + 2 * v_in / v_out)) * v_out 744 * 745 * In only horizontal downscaling situation, the right side should be 746 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes 747 * 748 * MCLK h_in 749 * ------- >= ---------------- 750 * PXLCLK (h_active - 3) 751 * 752 * To avoid precision lost the equation 1 will be convert to: 753 * 754 * MCLK h_in * v_in 755 * ------- >= ----------------------------------- 756 * PXLCLK (h_total -1 ) * v_out - 2 * v_in 757 */ 758 if (v_in == v_out) { 759 fraction = h_in; 760 denominator = mode->hdisplay - 3; 761 } else { 762 fraction = h_in * v_in; 763 denominator = (mode->htotal - 1) * v_out - 2 * v_in; 764 } 765 766 return mclk_rate * denominator >= mode->clock * 1000 * fraction ? 767 0 : -EINVAL; 768 } 769 770 static void d71_improc_update(struct komeda_component *c, 771 struct komeda_component_state *state) 772 { 773 struct komeda_improc_state *st = to_improc_st(state); 774 u32 __iomem *reg = c->reg; 775 u32 index, input_hw_id; 776 777 for_each_changed_input(state, index) { 778 input_hw_id = state->active_inputs & BIT(index) ? 779 to_d71_input_id(&state->inputs[index]) : 0; 780 malidp_write32(reg, BLK_INPUT_ID0 + index * 4, input_hw_id); 781 } 782 783 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); 784 } 785 786 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf) 787 { 788 u32 v[12], i; 789 790 dump_block_header(sf, c->reg); 791 792 get_values_from_reg(c->reg, 0x80, 2, v); 793 seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]); 794 seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]); 795 796 get_values_from_reg(c->reg, 0xC0, 1, v); 797 seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]); 798 799 get_values_from_reg(c->reg, 0xD0, 3, v); 800 seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]); 801 seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]); 802 seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]); 803 804 get_values_from_reg(c->reg, 0x130, 12, v); 805 for (i = 0; i < 12; i++) 806 seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]); 807 808 get_values_from_reg(c->reg, 0x170, 12, v); 809 for (i = 0; i < 12; i++) 810 seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]); 811 } 812 813 static const struct komeda_component_funcs d71_improc_funcs = { 814 .update = d71_improc_update, 815 .disable = d71_component_disable, 816 .dump_register = d71_improc_dump, 817 }; 818 819 static int d71_improc_init(struct d71_dev *d71, 820 struct block_header *blk, u32 __iomem *reg) 821 { 822 struct komeda_component *c; 823 struct komeda_improc *improc; 824 u32 pipe_id, comp_id, value; 825 826 get_resources_id(blk->block_info, &pipe_id, &comp_id); 827 828 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc), 829 comp_id, 830 BLOCK_INFO_INPUT_ID(blk->block_info), 831 &d71_improc_funcs, IPS_NUM_INPUT_IDS, 832 get_valid_inputs(blk), 833 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id); 834 if (IS_ERR(c)) { 835 DRM_ERROR("Failed to add improc component\n"); 836 return PTR_ERR(c); 837 } 838 839 improc = to_improc(c); 840 improc->supported_color_depths = BIT(8) | BIT(10); 841 improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 | 842 DRM_COLOR_FORMAT_YCRCB444 | 843 DRM_COLOR_FORMAT_YCRCB422; 844 value = malidp_read32(reg, BLK_INFO); 845 if (value & IPS_INFO_CHD420) 846 improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420; 847 848 improc->supports_csc = true; 849 improc->supports_gamma = true; 850 851 return 0; 852 } 853 854 static void d71_timing_ctrlr_disable(struct komeda_component *c) 855 { 856 malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0); 857 } 858 859 static void d71_timing_ctrlr_update(struct komeda_component *c, 860 struct komeda_component_state *state) 861 { 862 struct drm_crtc_state *crtc_st = state->crtc->state; 863 u32 __iomem *reg = c->reg; 864 struct videomode vm; 865 u32 value; 866 867 drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm); 868 869 malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive)); 870 malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch, 871 vm.hback_porch)); 872 malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch, 873 vm.vback_porch)); 874 875 value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len); 876 value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0; 877 value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0; 878 malidp_write32(reg, BS_SYNC, value); 879 880 malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1); 881 malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE); 882 883 /* configure bs control register */ 884 value = BS_CTRL_EN | BS_CTRL_VM; 885 886 malidp_write32(reg, BLK_CONTROL, value); 887 } 888 889 static void d71_timing_ctrlr_dump(struct komeda_component *c, 890 struct seq_file *sf) 891 { 892 u32 v[8], i; 893 894 dump_block_header(sf, c->reg); 895 896 get_values_from_reg(c->reg, 0xC0, 1, v); 897 seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]); 898 899 get_values_from_reg(c->reg, 0xD0, 8, v); 900 seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]); 901 seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]); 902 seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]); 903 seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]); 904 seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]); 905 seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]); 906 seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]); 907 seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]); 908 909 get_values_from_reg(c->reg, 0x100, 3, v); 910 seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]); 911 seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]); 912 seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]); 913 914 get_values_from_reg(c->reg, 0x110, 3, v); 915 for (i = 0; i < 3; i++) 916 seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]); 917 918 get_values_from_reg(c->reg, 0x120, 5, v); 919 for (i = 0; i < 2; i++) { 920 seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]); 921 seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]); 922 } 923 seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]); 924 } 925 926 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = { 927 .update = d71_timing_ctrlr_update, 928 .disable = d71_timing_ctrlr_disable, 929 .dump_register = d71_timing_ctrlr_dump, 930 }; 931 932 static int d71_timing_ctrlr_init(struct d71_dev *d71, 933 struct block_header *blk, u32 __iomem *reg) 934 { 935 struct komeda_component *c; 936 struct komeda_timing_ctrlr *ctrlr; 937 u32 pipe_id, comp_id; 938 939 get_resources_id(blk->block_info, &pipe_id, &comp_id); 940 941 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr), 942 KOMEDA_COMPONENT_TIMING_CTRLR, 943 BLOCK_INFO_INPUT_ID(blk->block_info), 944 &d71_timing_ctrlr_funcs, 945 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id), 946 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id); 947 if (IS_ERR(c)) { 948 DRM_ERROR("Failed to add display_ctrl component\n"); 949 return PTR_ERR(c); 950 } 951 952 ctrlr = to_ctrlr(c); 953 954 ctrlr->supports_dual_link = true; 955 956 return 0; 957 } 958 959 int d71_probe_block(struct d71_dev *d71, 960 struct block_header *blk, u32 __iomem *reg) 961 { 962 struct d71_pipeline *pipe; 963 int blk_id = BLOCK_INFO_BLK_ID(blk->block_info); 964 965 int err = 0; 966 967 switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) { 968 case D71_BLK_TYPE_GCU: 969 break; 970 971 case D71_BLK_TYPE_LPU: 972 pipe = d71->pipes[blk_id]; 973 pipe->lpu_addr = reg; 974 break; 975 976 case D71_BLK_TYPE_LPU_LAYER: 977 err = d71_layer_init(d71, blk, reg); 978 break; 979 980 case D71_BLK_TYPE_LPU_WB_LAYER: 981 err = d71_wb_layer_init(d71, blk, reg); 982 break; 983 984 case D71_BLK_TYPE_CU: 985 pipe = d71->pipes[blk_id]; 986 pipe->cu_addr = reg; 987 err = d71_compiz_init(d71, blk, reg); 988 break; 989 990 case D71_BLK_TYPE_CU_SCALER: 991 err = d71_scaler_init(d71, blk, reg); 992 break; 993 994 case D71_BLK_TYPE_CU_SPLITTER: 995 case D71_BLK_TYPE_CU_MERGER: 996 break; 997 998 case D71_BLK_TYPE_DOU: 999 pipe = d71->pipes[blk_id]; 1000 pipe->dou_addr = reg; 1001 break; 1002 1003 case D71_BLK_TYPE_DOU_IPS: 1004 err = d71_improc_init(d71, blk, reg); 1005 break; 1006 1007 case D71_BLK_TYPE_DOU_FT_COEFF: 1008 pipe = d71->pipes[blk_id]; 1009 pipe->dou_ft_coeff_addr = reg; 1010 break; 1011 1012 case D71_BLK_TYPE_DOU_BS: 1013 err = d71_timing_ctrlr_init(d71, blk, reg); 1014 break; 1015 1016 case D71_BLK_TYPE_GLB_LT_COEFF: 1017 break; 1018 1019 case D71_BLK_TYPE_GLB_SCL_COEFF: 1020 d71->glb_scl_coeff_addr[blk_id] = reg; 1021 break; 1022 1023 default: 1024 DRM_ERROR("Unknown block (block_info: 0x%x) is found\n", 1025 blk->block_info); 1026 err = -EINVAL; 1027 break; 1028 } 1029 1030 return err; 1031 } 1032 1033 const struct komeda_pipeline_funcs d71_pipeline_funcs = { 1034 .downscaling_clk_check = d71_downscaling_clk_check, 1035 }; 1036