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_state *st, int idx) 160 { 161 struct komeda_component_output *input = &st->inputs[idx]; 162 163 /* if input is not active, set hw input_id(0) to disable it */ 164 if (has_bit(idx, st->active_inputs)) 165 return input->component->hw_id + input->output_port; 166 else 167 return 0; 168 } 169 170 static void d71_layer_update_fb(struct komeda_component *c, 171 struct komeda_fb *kfb, 172 dma_addr_t *addr) 173 { 174 struct drm_framebuffer *fb = &kfb->base; 175 const struct drm_format_info *info = fb->format; 176 u32 __iomem *reg = c->reg; 177 int block_h; 178 179 if (info->num_planes > 2) 180 malidp_write64(reg, BLK_P2_PTR_LOW, addr[2]); 181 182 if (info->num_planes > 1) { 183 block_h = drm_format_info_block_height(info, 1); 184 malidp_write32(reg, BLK_P1_STRIDE, fb->pitches[1] * block_h); 185 malidp_write64(reg, BLK_P1_PTR_LOW, addr[1]); 186 } 187 188 block_h = drm_format_info_block_height(info, 0); 189 malidp_write32(reg, BLK_P0_STRIDE, fb->pitches[0] * block_h); 190 malidp_write64(reg, BLK_P0_PTR_LOW, addr[0]); 191 malidp_write32(reg, LAYER_FMT, kfb->format_caps->hw_id); 192 } 193 194 static void d71_layer_disable(struct komeda_component *c) 195 { 196 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0); 197 } 198 199 static void d71_layer_update(struct komeda_component *c, 200 struct komeda_component_state *state) 201 { 202 struct komeda_layer_state *st = to_layer_st(state); 203 struct drm_plane_state *plane_st = state->plane->state; 204 struct drm_framebuffer *fb = plane_st->fb; 205 struct komeda_fb *kfb = to_kfb(fb); 206 u32 __iomem *reg = c->reg; 207 u32 ctrl_mask = L_EN | L_ROT(L_ROT_R270) | L_HFLIP | L_VFLIP | L_TBU_EN; 208 u32 ctrl = L_EN | to_rot_ctrl(st->rot); 209 210 d71_layer_update_fb(c, kfb, st->addr); 211 212 malidp_write32(reg, AD_CONTROL, to_ad_ctrl(fb->modifier)); 213 if (fb->modifier) { 214 u64 addr; 215 216 malidp_write32(reg, LAYER_AD_H_CROP, HV_CROP(st->afbc_crop_l, 217 st->afbc_crop_r)); 218 malidp_write32(reg, LAYER_AD_V_CROP, HV_CROP(st->afbc_crop_t, 219 st->afbc_crop_b)); 220 /* afbc 1.2 wants payload, afbc 1.0/1.1 wants end_addr */ 221 if (fb->modifier & AFBC_FORMAT_MOD_TILED) 222 addr = st->addr[0] + kfb->offset_payload; 223 else 224 addr = st->addr[0] + kfb->afbc_size - 1; 225 226 malidp_write32(reg, BLK_P1_PTR_LOW, lower_32_bits(addr)); 227 malidp_write32(reg, BLK_P1_PTR_HIGH, upper_32_bits(addr)); 228 } 229 230 if (fb->format->is_yuv) { 231 u32 upsampling = 0; 232 233 switch (kfb->format_caps->fourcc) { 234 case DRM_FORMAT_YUYV: 235 upsampling = fb->modifier ? LR_CHI422_BILINEAR : 236 LR_CHI422_REPLICATION; 237 break; 238 case DRM_FORMAT_UYVY: 239 upsampling = LR_CHI422_REPLICATION; 240 break; 241 case DRM_FORMAT_NV12: 242 case DRM_FORMAT_YUV420_8BIT: 243 case DRM_FORMAT_YUV420_10BIT: 244 case DRM_FORMAT_YUV420: 245 case DRM_FORMAT_P010: 246 /* these fmt support MPGE/JPEG both, here perfer JPEG*/ 247 upsampling = LR_CHI420_JPEG; 248 break; 249 case DRM_FORMAT_X0L2: 250 upsampling = LR_CHI420_JPEG; 251 break; 252 default: 253 break; 254 } 255 256 malidp_write32(reg, LAYER_R_CONTROL, upsampling); 257 malidp_write_group(reg, LAYER_YUV_RGB_COEFF0, 258 KOMEDA_N_YUV2RGB_COEFFS, 259 komeda_select_yuv2rgb_coeffs( 260 plane_st->color_encoding, 261 plane_st->color_range)); 262 } 263 264 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize)); 265 266 if (kfb->is_va) 267 ctrl |= L_TBU_EN; 268 malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl); 269 } 270 271 static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf) 272 { 273 u32 v[15], i; 274 bool rich, rgb2rgb; 275 char *prefix; 276 277 get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]); 278 if (v[14] & 0x1) { 279 rich = true; 280 prefix = "LR_"; 281 } else { 282 rich = false; 283 prefix = "LS_"; 284 } 285 286 rgb2rgb = !!(v[14] & L_INFO_CM); 287 288 dump_block_header(sf, c->reg); 289 290 seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]); 291 292 get_values_from_reg(c->reg, 0xD0, 1, v); 293 seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]); 294 if (rich) { 295 get_values_from_reg(c->reg, 0xD4, 1, v); 296 seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]); 297 } 298 get_values_from_reg(c->reg, 0xD8, 4, v); 299 seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]); 300 seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]); 301 seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]); 302 seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]); 303 304 get_values_from_reg(c->reg, 0x100, 3, v); 305 seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]); 306 seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]); 307 seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]); 308 309 get_values_from_reg(c->reg, 0x110, 2, v); 310 seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]); 311 seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]); 312 if (rich) { 313 get_values_from_reg(c->reg, 0x118, 1, v); 314 seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]); 315 316 get_values_from_reg(c->reg, 0x120, 2, v); 317 seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]); 318 seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]); 319 320 get_values_from_reg(c->reg, 0x130, 12, v); 321 for (i = 0; i < 12; i++) 322 seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]); 323 } 324 325 if (rgb2rgb) { 326 get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v); 327 for (i = 0; i < 12; i++) 328 seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]); 329 } 330 331 get_values_from_reg(c->reg, 0x160, 3, v); 332 seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]); 333 seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]); 334 seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]); 335 } 336 337 static const struct komeda_component_funcs d71_layer_funcs = { 338 .update = d71_layer_update, 339 .disable = d71_layer_disable, 340 .dump_register = d71_layer_dump, 341 }; 342 343 static int d71_layer_init(struct d71_dev *d71, 344 struct block_header *blk, u32 __iomem *reg) 345 { 346 struct komeda_component *c; 347 struct komeda_layer *layer; 348 u32 pipe_id, layer_id, layer_info; 349 350 get_resources_id(blk->block_info, &pipe_id, &layer_id); 351 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*layer), 352 layer_id, 353 BLOCK_INFO_INPUT_ID(blk->block_info), 354 &d71_layer_funcs, 0, 355 get_valid_inputs(blk), 356 1, reg, "LPU%d_LAYER%d", pipe_id, layer_id); 357 if (IS_ERR(c)) { 358 DRM_ERROR("Failed to add layer component\n"); 359 return PTR_ERR(c); 360 } 361 362 layer = to_layer(c); 363 layer_info = malidp_read32(reg, LAYER_INFO); 364 365 if (layer_info & L_INFO_RF) 366 layer->layer_type = KOMEDA_FMT_RICH_LAYER; 367 else 368 layer->layer_type = KOMEDA_FMT_SIMPLE_LAYER; 369 370 set_range(&layer->hsize_in, 4, d71->max_line_size); 371 set_range(&layer->vsize_in, 4, d71->max_vsize); 372 373 malidp_write32(reg, LAYER_PALPHA, D71_PALPHA_DEF_MAP); 374 375 layer->supported_rots = DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK; 376 377 return 0; 378 } 379 380 static void d71_wb_layer_update(struct komeda_component *c, 381 struct komeda_component_state *state) 382 { 383 struct komeda_layer_state *st = to_layer_st(state); 384 struct drm_connector_state *conn_st = state->wb_conn->state; 385 struct komeda_fb *kfb = to_kfb(conn_st->writeback_job->fb); 386 u32 ctrl = L_EN | LW_OFM, mask = L_EN | LW_OFM | LW_TBU_EN; 387 u32 __iomem *reg = c->reg; 388 389 d71_layer_update_fb(c, kfb, st->addr); 390 391 if (kfb->is_va) 392 ctrl |= LW_TBU_EN; 393 394 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize, st->vsize)); 395 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0)); 396 malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); 397 } 398 399 static void d71_wb_layer_dump(struct komeda_component *c, struct seq_file *sf) 400 { 401 u32 v[12], i; 402 403 dump_block_header(sf, c->reg); 404 405 get_values_from_reg(c->reg, 0x80, 1, v); 406 seq_printf(sf, "LW_INPUT_ID0:\t\t0x%X\n", v[0]); 407 408 get_values_from_reg(c->reg, 0xD0, 3, v); 409 seq_printf(sf, "LW_CONTROL:\t\t0x%X\n", v[0]); 410 seq_printf(sf, "LW_PROG_LINE:\t\t0x%X\n", v[1]); 411 seq_printf(sf, "LW_FORMAT:\t\t0x%X\n", v[2]); 412 413 get_values_from_reg(c->reg, 0xE0, 1, v); 414 seq_printf(sf, "LW_IN_SIZE:\t\t0x%X\n", v[0]); 415 416 for (i = 0; i < 2; i++) { 417 get_values_from_reg(c->reg, 0x100 + i * 0x10, 3, v); 418 seq_printf(sf, "LW_P%u_PTR_LOW:\t\t0x%X\n", i, v[0]); 419 seq_printf(sf, "LW_P%u_PTR_HIGH:\t\t0x%X\n", i, v[1]); 420 seq_printf(sf, "LW_P%u_STRIDE:\t\t0x%X\n", i, v[2]); 421 } 422 423 get_values_from_reg(c->reg, 0x130, 12, v); 424 for (i = 0; i < 12; i++) 425 seq_printf(sf, "LW_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]); 426 } 427 428 static void d71_wb_layer_disable(struct komeda_component *c) 429 { 430 malidp_write32(c->reg, BLK_INPUT_ID0, 0); 431 malidp_write32_mask(c->reg, BLK_CONTROL, L_EN, 0); 432 } 433 434 static const struct komeda_component_funcs d71_wb_layer_funcs = { 435 .update = d71_wb_layer_update, 436 .disable = d71_wb_layer_disable, 437 .dump_register = d71_wb_layer_dump, 438 }; 439 440 static int d71_wb_layer_init(struct d71_dev *d71, 441 struct block_header *blk, u32 __iomem *reg) 442 { 443 struct komeda_component *c; 444 struct komeda_layer *wb_layer; 445 u32 pipe_id, layer_id; 446 447 get_resources_id(blk->block_info, &pipe_id, &layer_id); 448 449 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*wb_layer), 450 layer_id, BLOCK_INFO_INPUT_ID(blk->block_info), 451 &d71_wb_layer_funcs, 452 1, get_valid_inputs(blk), 0, reg, 453 "LPU%d_LAYER_WR", pipe_id); 454 if (IS_ERR(c)) { 455 DRM_ERROR("Failed to add wb_layer component\n"); 456 return PTR_ERR(c); 457 } 458 459 wb_layer = to_layer(c); 460 wb_layer->layer_type = KOMEDA_FMT_WB_LAYER; 461 462 set_range(&wb_layer->hsize_in, D71_MIN_LINE_SIZE, d71->max_line_size); 463 set_range(&wb_layer->vsize_in, D71_MIN_VERTICAL_SIZE, d71->max_vsize); 464 465 return 0; 466 } 467 468 static void d71_component_disable(struct komeda_component *c) 469 { 470 u32 __iomem *reg = c->reg; 471 u32 i; 472 473 malidp_write32(reg, BLK_CONTROL, 0); 474 475 for (i = 0; i < c->max_active_inputs; i++) { 476 malidp_write32(reg, BLK_INPUT_ID0 + (i << 2), 0); 477 478 /* Besides clearing the input ID to zero, D71 compiz also has 479 * input enable bit in CU_INPUTx_CONTROL which need to be 480 * cleared. 481 */ 482 if (has_bit(c->id, KOMEDA_PIPELINE_COMPIZS)) 483 malidp_write32(reg, CU_INPUT0_CONTROL + 484 i * CU_PER_INPUT_REGS * 4, 485 CU_INPUT_CTRL_ALPHA(0xFF)); 486 } 487 } 488 489 static void compiz_enable_input(u32 __iomem *id_reg, 490 u32 __iomem *cfg_reg, 491 u32 input_hw_id, 492 struct komeda_compiz_input_cfg *cin) 493 { 494 u32 ctrl = CU_INPUT_CTRL_EN; 495 u8 blend = cin->pixel_blend_mode; 496 497 if (blend == DRM_MODE_BLEND_PIXEL_NONE) 498 ctrl |= CU_INPUT_CTRL_PAD; 499 else if (blend == DRM_MODE_BLEND_PREMULTI) 500 ctrl |= CU_INPUT_CTRL_PMUL; 501 502 ctrl |= CU_INPUT_CTRL_ALPHA(cin->layer_alpha); 503 504 malidp_write32(id_reg, BLK_INPUT_ID0, input_hw_id); 505 506 malidp_write32(cfg_reg, CU_INPUT0_SIZE, 507 HV_SIZE(cin->hsize, cin->vsize)); 508 malidp_write32(cfg_reg, CU_INPUT0_OFFSET, 509 HV_OFFSET(cin->hoffset, cin->voffset)); 510 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, ctrl); 511 } 512 513 static void d71_compiz_update(struct komeda_component *c, 514 struct komeda_component_state *state) 515 { 516 struct komeda_compiz_state *st = to_compiz_st(state); 517 u32 __iomem *reg = c->reg; 518 u32 __iomem *id_reg, *cfg_reg; 519 u32 index; 520 521 for_each_changed_input(state, index) { 522 id_reg = reg + index; 523 cfg_reg = reg + index * CU_PER_INPUT_REGS; 524 if (state->active_inputs & BIT(index)) { 525 compiz_enable_input(id_reg, cfg_reg, 526 to_d71_input_id(state, index), 527 &st->cins[index]); 528 } else { 529 malidp_write32(id_reg, BLK_INPUT_ID0, 0); 530 malidp_write32(cfg_reg, CU_INPUT0_CONTROL, 0); 531 } 532 } 533 534 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); 535 } 536 537 static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf) 538 { 539 u32 v[8], i; 540 541 dump_block_header(sf, c->reg); 542 543 get_values_from_reg(c->reg, 0x80, 5, v); 544 for (i = 0; i < 5; i++) 545 seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]); 546 547 get_values_from_reg(c->reg, 0xA0, 5, v); 548 seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]); 549 seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]); 550 seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]); 551 seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]); 552 seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]); 553 554 get_values_from_reg(c->reg, 0xD0, 2, v); 555 seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]); 556 seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]); 557 558 get_values_from_reg(c->reg, 0xDC, 1, v); 559 seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]); 560 561 for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) { 562 get_values_from_reg(c->reg, v[4], 3, v); 563 seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]); 564 seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]); 565 seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]); 566 } 567 568 get_values_from_reg(c->reg, 0x130, 2, v); 569 seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]); 570 seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]); 571 } 572 573 static const struct komeda_component_funcs d71_compiz_funcs = { 574 .update = d71_compiz_update, 575 .disable = d71_component_disable, 576 .dump_register = d71_compiz_dump, 577 }; 578 579 static int d71_compiz_init(struct d71_dev *d71, 580 struct block_header *blk, u32 __iomem *reg) 581 { 582 struct komeda_component *c; 583 struct komeda_compiz *compiz; 584 u32 pipe_id, comp_id; 585 586 get_resources_id(blk->block_info, &pipe_id, &comp_id); 587 588 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*compiz), 589 comp_id, 590 BLOCK_INFO_INPUT_ID(blk->block_info), 591 &d71_compiz_funcs, 592 CU_NUM_INPUT_IDS, get_valid_inputs(blk), 593 CU_NUM_OUTPUT_IDS, reg, 594 "CU%d", pipe_id); 595 if (IS_ERR(c)) 596 return PTR_ERR(c); 597 598 compiz = to_compiz(c); 599 600 set_range(&compiz->hsize, D71_MIN_LINE_SIZE, d71->max_line_size); 601 set_range(&compiz->vsize, D71_MIN_VERTICAL_SIZE, d71->max_vsize); 602 603 return 0; 604 } 605 606 static void d71_scaler_update_filter_lut(u32 __iomem *reg, u32 hsize_in, 607 u32 vsize_in, u32 hsize_out, 608 u32 vsize_out) 609 { 610 u32 val = 0; 611 612 if (hsize_in <= hsize_out) 613 val |= 0x62; 614 else if (hsize_in <= (hsize_out + hsize_out / 2)) 615 val |= 0x63; 616 else if (hsize_in <= hsize_out * 2) 617 val |= 0x64; 618 else if (hsize_in <= hsize_out * 2 + (hsize_out * 3) / 4) 619 val |= 0x65; 620 else 621 val |= 0x66; 622 623 if (vsize_in <= vsize_out) 624 val |= SC_VTSEL(0x6A); 625 else if (vsize_in <= (vsize_out + vsize_out / 2)) 626 val |= SC_VTSEL(0x6B); 627 else if (vsize_in <= vsize_out * 2) 628 val |= SC_VTSEL(0x6C); 629 else if (vsize_in <= vsize_out * 2 + vsize_out * 3 / 4) 630 val |= SC_VTSEL(0x6D); 631 else 632 val |= SC_VTSEL(0x6E); 633 634 malidp_write32(reg, SC_COEFFTAB, val); 635 } 636 637 static void d71_scaler_update(struct komeda_component *c, 638 struct komeda_component_state *state) 639 { 640 struct komeda_scaler_state *st = to_scaler_st(state); 641 u32 __iomem *reg = c->reg; 642 u32 init_ph, delta_ph, ctrl; 643 644 d71_scaler_update_filter_lut(reg, st->hsize_in, st->vsize_in, 645 st->hsize_out, st->vsize_out); 646 647 malidp_write32(reg, BLK_IN_SIZE, HV_SIZE(st->hsize_in, st->vsize_in)); 648 malidp_write32(reg, SC_OUT_SIZE, HV_SIZE(st->hsize_out, st->vsize_out)); 649 malidp_write32(reg, SC_H_CROP, HV_CROP(st->left_crop, st->right_crop)); 650 651 /* for right part, HW only sample the valid pixel which means the pixels 652 * in left_crop will be jumpped, and the first sample pixel is: 653 * 654 * dst_a = st->total_hsize_out - st->hsize_out + st->left_crop + 0.5; 655 * 656 * Then the corresponding texel in src is: 657 * 658 * h_delta_phase = st->total_hsize_in / st->total_hsize_out; 659 * src_a = dst_A * h_delta_phase; 660 * 661 * and h_init_phase is src_a deduct the real source start src_S; 662 * 663 * src_S = st->total_hsize_in - st->hsize_in; 664 * h_init_phase = src_a - src_S; 665 * 666 * And HW precision for the initial/delta_phase is 16:16 fixed point, 667 * the following is the simplified formula 668 */ 669 if (st->right_part) { 670 u32 dst_a = st->total_hsize_out - st->hsize_out + st->left_crop; 671 672 if (st->en_img_enhancement) 673 dst_a -= 1; 674 675 init_ph = ((st->total_hsize_in * (2 * dst_a + 1) - 676 2 * st->total_hsize_out * (st->total_hsize_in - 677 st->hsize_in)) << 15) / st->total_hsize_out; 678 } else { 679 init_ph = (st->total_hsize_in << 15) / st->total_hsize_out; 680 } 681 682 malidp_write32(reg, SC_H_INIT_PH, init_ph); 683 684 delta_ph = (st->total_hsize_in << 16) / st->total_hsize_out; 685 malidp_write32(reg, SC_H_DELTA_PH, delta_ph); 686 687 init_ph = (st->total_vsize_in << 15) / st->vsize_out; 688 malidp_write32(reg, SC_V_INIT_PH, init_ph); 689 690 delta_ph = (st->total_vsize_in << 16) / st->vsize_out; 691 malidp_write32(reg, SC_V_DELTA_PH, delta_ph); 692 693 ctrl = 0; 694 ctrl |= st->en_scaling ? SC_CTRL_SCL : 0; 695 ctrl |= st->en_alpha ? SC_CTRL_AP : 0; 696 ctrl |= st->en_img_enhancement ? SC_CTRL_IENH : 0; 697 /* If we use the hardware splitter we shouldn't set SC_CTRL_LS */ 698 if (st->en_split && 699 state->inputs[0].component->id != KOMEDA_COMPONENT_SPLITTER) 700 ctrl |= SC_CTRL_LS; 701 702 malidp_write32(reg, BLK_CONTROL, ctrl); 703 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0)); 704 } 705 706 static void d71_scaler_dump(struct komeda_component *c, struct seq_file *sf) 707 { 708 u32 v[9]; 709 710 dump_block_header(sf, c->reg); 711 712 get_values_from_reg(c->reg, 0x80, 1, v); 713 seq_printf(sf, "SC_INPUT_ID0:\t\t0x%X\n", v[0]); 714 715 get_values_from_reg(c->reg, 0xD0, 1, v); 716 seq_printf(sf, "SC_CONTROL:\t\t0x%X\n", v[0]); 717 718 get_values_from_reg(c->reg, 0xDC, 9, v); 719 seq_printf(sf, "SC_COEFFTAB:\t\t0x%X\n", v[0]); 720 seq_printf(sf, "SC_IN_SIZE:\t\t0x%X\n", v[1]); 721 seq_printf(sf, "SC_OUT_SIZE:\t\t0x%X\n", v[2]); 722 seq_printf(sf, "SC_H_CROP:\t\t0x%X\n", v[3]); 723 seq_printf(sf, "SC_V_CROP:\t\t0x%X\n", v[4]); 724 seq_printf(sf, "SC_H_INIT_PH:\t\t0x%X\n", v[5]); 725 seq_printf(sf, "SC_H_DELTA_PH:\t\t0x%X\n", v[6]); 726 seq_printf(sf, "SC_V_INIT_PH:\t\t0x%X\n", v[7]); 727 seq_printf(sf, "SC_V_DELTA_PH:\t\t0x%X\n", v[8]); 728 } 729 730 static const struct komeda_component_funcs d71_scaler_funcs = { 731 .update = d71_scaler_update, 732 .disable = d71_component_disable, 733 .dump_register = d71_scaler_dump, 734 }; 735 736 static int d71_scaler_init(struct d71_dev *d71, 737 struct block_header *blk, u32 __iomem *reg) 738 { 739 struct komeda_component *c; 740 struct komeda_scaler *scaler; 741 u32 pipe_id, comp_id; 742 743 get_resources_id(blk->block_info, &pipe_id, &comp_id); 744 745 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*scaler), 746 comp_id, BLOCK_INFO_INPUT_ID(blk->block_info), 747 &d71_scaler_funcs, 748 1, get_valid_inputs(blk), 1, reg, 749 "CU%d_SCALER%d", 750 pipe_id, BLOCK_INFO_BLK_ID(blk->block_info)); 751 752 if (IS_ERR(c)) { 753 DRM_ERROR("Failed to initialize scaler"); 754 return PTR_ERR(c); 755 } 756 757 scaler = to_scaler(c); 758 set_range(&scaler->hsize, 4, 2048); 759 set_range(&scaler->vsize, 4, 4096); 760 scaler->max_downscaling = 6; 761 scaler->max_upscaling = 64; 762 scaler->scaling_split_overlap = 8; 763 scaler->enh_split_overlap = 1; 764 765 malidp_write32(c->reg, BLK_CONTROL, 0); 766 767 return 0; 768 } 769 770 static int d71_downscaling_clk_check(struct komeda_pipeline *pipe, 771 struct drm_display_mode *mode, 772 unsigned long aclk_rate, 773 struct komeda_data_flow_cfg *dflow) 774 { 775 u32 h_in = dflow->in_w; 776 u32 v_in = dflow->in_h; 777 u32 v_out = dflow->out_h; 778 u64 fraction, denominator; 779 780 /* D71 downscaling must satisfy the following equation 781 * 782 * ACLK h_in * v_in 783 * ------- >= --------------------------------------------- 784 * PXLCLK (h_total - (1 + 2 * v_in / v_out)) * v_out 785 * 786 * In only horizontal downscaling situation, the right side should be 787 * multiplied by (h_total - 3) / (h_active - 3), then equation becomes 788 * 789 * ACLK h_in 790 * ------- >= ---------------- 791 * PXLCLK (h_active - 3) 792 * 793 * To avoid precision lost the equation 1 will be convert to: 794 * 795 * ACLK h_in * v_in 796 * ------- >= ----------------------------------- 797 * PXLCLK (h_total -1 ) * v_out - 2 * v_in 798 */ 799 if (v_in == v_out) { 800 fraction = h_in; 801 denominator = mode->hdisplay - 3; 802 } else { 803 fraction = h_in * v_in; 804 denominator = (mode->htotal - 1) * v_out - 2 * v_in; 805 } 806 807 return aclk_rate * denominator >= mode->clock * 1000 * fraction ? 808 0 : -EINVAL; 809 } 810 811 static void d71_splitter_update(struct komeda_component *c, 812 struct komeda_component_state *state) 813 { 814 struct komeda_splitter_state *st = to_splitter_st(state); 815 u32 __iomem *reg = c->reg; 816 817 malidp_write32(reg, BLK_INPUT_ID0, to_d71_input_id(state, 0)); 818 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); 819 malidp_write32(reg, SP_OVERLAP_SIZE, st->overlap & 0x1FFF); 820 malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN); 821 } 822 823 static void d71_splitter_dump(struct komeda_component *c, struct seq_file *sf) 824 { 825 u32 v[3]; 826 827 dump_block_header(sf, c->reg); 828 829 get_values_from_reg(c->reg, BLK_INPUT_ID0, 1, v); 830 seq_printf(sf, "SP_INPUT_ID0:\t\t0x%X\n", v[0]); 831 832 get_values_from_reg(c->reg, BLK_CONTROL, 3, v); 833 seq_printf(sf, "SP_CONTROL:\t\t0x%X\n", v[0]); 834 seq_printf(sf, "SP_SIZE:\t\t0x%X\n", v[1]); 835 seq_printf(sf, "SP_OVERLAP_SIZE:\t0x%X\n", v[2]); 836 } 837 838 static const struct komeda_component_funcs d71_splitter_funcs = { 839 .update = d71_splitter_update, 840 .disable = d71_component_disable, 841 .dump_register = d71_splitter_dump, 842 }; 843 844 static int d71_splitter_init(struct d71_dev *d71, 845 struct block_header *blk, u32 __iomem *reg) 846 { 847 struct komeda_component *c; 848 struct komeda_splitter *splitter; 849 u32 pipe_id, comp_id; 850 851 get_resources_id(blk->block_info, &pipe_id, &comp_id); 852 853 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*splitter), 854 comp_id, 855 BLOCK_INFO_INPUT_ID(blk->block_info), 856 &d71_splitter_funcs, 857 1, get_valid_inputs(blk), 2, reg, 858 "CU%d_SPLITTER", pipe_id); 859 860 if (IS_ERR(c)) { 861 DRM_ERROR("Failed to initialize splitter"); 862 return -1; 863 } 864 865 splitter = to_splitter(c); 866 867 set_range(&splitter->hsize, 4, d71->max_line_size); 868 set_range(&splitter->vsize, 4, d71->max_vsize); 869 870 return 0; 871 } 872 873 static void d71_merger_update(struct komeda_component *c, 874 struct komeda_component_state *state) 875 { 876 struct komeda_merger_state *st = to_merger_st(state); 877 u32 __iomem *reg = c->reg; 878 u32 index; 879 880 for_each_changed_input(state, index) 881 malidp_write32(reg, MG_INPUT_ID0 + index * 4, 882 to_d71_input_id(state, index)); 883 884 malidp_write32(reg, MG_SIZE, HV_SIZE(st->hsize_merged, 885 st->vsize_merged)); 886 malidp_write32(reg, BLK_CONTROL, BLK_CTRL_EN); 887 } 888 889 static void d71_merger_dump(struct komeda_component *c, struct seq_file *sf) 890 { 891 u32 v; 892 893 dump_block_header(sf, c->reg); 894 895 get_values_from_reg(c->reg, MG_INPUT_ID0, 1, &v); 896 seq_printf(sf, "MG_INPUT_ID0:\t\t0x%X\n", v); 897 898 get_values_from_reg(c->reg, MG_INPUT_ID1, 1, &v); 899 seq_printf(sf, "MG_INPUT_ID1:\t\t0x%X\n", v); 900 901 get_values_from_reg(c->reg, BLK_CONTROL, 1, &v); 902 seq_printf(sf, "MG_CONTROL:\t\t0x%X\n", v); 903 904 get_values_from_reg(c->reg, MG_SIZE, 1, &v); 905 seq_printf(sf, "MG_SIZE:\t\t0x%X\n", v); 906 } 907 908 static const struct komeda_component_funcs d71_merger_funcs = { 909 .update = d71_merger_update, 910 .disable = d71_component_disable, 911 .dump_register = d71_merger_dump, 912 }; 913 914 static int d71_merger_init(struct d71_dev *d71, 915 struct block_header *blk, u32 __iomem *reg) 916 { 917 struct komeda_component *c; 918 struct komeda_merger *merger; 919 u32 pipe_id, comp_id; 920 921 get_resources_id(blk->block_info, &pipe_id, &comp_id); 922 923 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*merger), 924 comp_id, 925 BLOCK_INFO_INPUT_ID(blk->block_info), 926 &d71_merger_funcs, 927 MG_NUM_INPUTS_IDS, get_valid_inputs(blk), 928 MG_NUM_OUTPUTS_IDS, reg, 929 "CU%d_MERGER", pipe_id); 930 931 if (IS_ERR(c)) { 932 DRM_ERROR("Failed to initialize merger.\n"); 933 return PTR_ERR(c); 934 } 935 936 merger = to_merger(c); 937 938 set_range(&merger->hsize_merged, 4, 4032); 939 set_range(&merger->vsize_merged, 4, 4096); 940 941 return 0; 942 } 943 944 static void d71_improc_update(struct komeda_component *c, 945 struct komeda_component_state *state) 946 { 947 struct komeda_improc_state *st = to_improc_st(state); 948 u32 __iomem *reg = c->reg; 949 u32 index; 950 951 for_each_changed_input(state, index) 952 malidp_write32(reg, BLK_INPUT_ID0 + index * 4, 953 to_d71_input_id(state, index)); 954 955 malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize)); 956 } 957 958 static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf) 959 { 960 u32 v[12], i; 961 962 dump_block_header(sf, c->reg); 963 964 get_values_from_reg(c->reg, 0x80, 2, v); 965 seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]); 966 seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]); 967 968 get_values_from_reg(c->reg, 0xC0, 1, v); 969 seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]); 970 971 get_values_from_reg(c->reg, 0xD0, 3, v); 972 seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]); 973 seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]); 974 seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]); 975 976 get_values_from_reg(c->reg, 0x130, 12, v); 977 for (i = 0; i < 12; i++) 978 seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]); 979 980 get_values_from_reg(c->reg, 0x170, 12, v); 981 for (i = 0; i < 12; i++) 982 seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]); 983 } 984 985 static const struct komeda_component_funcs d71_improc_funcs = { 986 .update = d71_improc_update, 987 .disable = d71_component_disable, 988 .dump_register = d71_improc_dump, 989 }; 990 991 static int d71_improc_init(struct d71_dev *d71, 992 struct block_header *blk, u32 __iomem *reg) 993 { 994 struct komeda_component *c; 995 struct komeda_improc *improc; 996 u32 pipe_id, comp_id, value; 997 998 get_resources_id(blk->block_info, &pipe_id, &comp_id); 999 1000 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*improc), 1001 comp_id, 1002 BLOCK_INFO_INPUT_ID(blk->block_info), 1003 &d71_improc_funcs, IPS_NUM_INPUT_IDS, 1004 get_valid_inputs(blk), 1005 IPS_NUM_OUTPUT_IDS, reg, "DOU%d_IPS", pipe_id); 1006 if (IS_ERR(c)) { 1007 DRM_ERROR("Failed to add improc component\n"); 1008 return PTR_ERR(c); 1009 } 1010 1011 improc = to_improc(c); 1012 improc->supported_color_depths = BIT(8) | BIT(10); 1013 improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 | 1014 DRM_COLOR_FORMAT_YCRCB444 | 1015 DRM_COLOR_FORMAT_YCRCB422; 1016 value = malidp_read32(reg, BLK_INFO); 1017 if (value & IPS_INFO_CHD420) 1018 improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420; 1019 1020 improc->supports_csc = true; 1021 improc->supports_gamma = true; 1022 1023 return 0; 1024 } 1025 1026 static void d71_timing_ctrlr_disable(struct komeda_component *c) 1027 { 1028 malidp_write32_mask(c->reg, BLK_CONTROL, BS_CTRL_EN, 0); 1029 } 1030 1031 static void d71_timing_ctrlr_update(struct komeda_component *c, 1032 struct komeda_component_state *state) 1033 { 1034 struct drm_crtc_state *crtc_st = state->crtc->state; 1035 u32 __iomem *reg = c->reg; 1036 struct videomode vm; 1037 u32 value; 1038 1039 drm_display_mode_to_videomode(&crtc_st->adjusted_mode, &vm); 1040 1041 malidp_write32(reg, BS_ACTIVESIZE, HV_SIZE(vm.hactive, vm.vactive)); 1042 malidp_write32(reg, BS_HINTERVALS, BS_H_INTVALS(vm.hfront_porch, 1043 vm.hback_porch)); 1044 malidp_write32(reg, BS_VINTERVALS, BS_V_INTVALS(vm.vfront_porch, 1045 vm.vback_porch)); 1046 1047 value = BS_SYNC_VSW(vm.vsync_len) | BS_SYNC_HSW(vm.hsync_len); 1048 value |= vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? BS_SYNC_VSP : 0; 1049 value |= vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? BS_SYNC_HSP : 0; 1050 malidp_write32(reg, BS_SYNC, value); 1051 1052 malidp_write32(reg, BS_PROG_LINE, D71_DEFAULT_PREPRETCH_LINE - 1); 1053 malidp_write32(reg, BS_PREFETCH_LINE, D71_DEFAULT_PREPRETCH_LINE); 1054 1055 /* configure bs control register */ 1056 value = BS_CTRL_EN | BS_CTRL_VM; 1057 1058 malidp_write32(reg, BLK_CONTROL, value); 1059 } 1060 1061 static void d71_timing_ctrlr_dump(struct komeda_component *c, 1062 struct seq_file *sf) 1063 { 1064 u32 v[8], i; 1065 1066 dump_block_header(sf, c->reg); 1067 1068 get_values_from_reg(c->reg, 0xC0, 1, v); 1069 seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]); 1070 1071 get_values_from_reg(c->reg, 0xD0, 8, v); 1072 seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]); 1073 seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]); 1074 seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]); 1075 seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]); 1076 seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]); 1077 seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]); 1078 seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]); 1079 seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]); 1080 1081 get_values_from_reg(c->reg, 0x100, 3, v); 1082 seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]); 1083 seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]); 1084 seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]); 1085 1086 get_values_from_reg(c->reg, 0x110, 3, v); 1087 for (i = 0; i < 3; i++) 1088 seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]); 1089 1090 get_values_from_reg(c->reg, 0x120, 5, v); 1091 for (i = 0; i < 2; i++) { 1092 seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]); 1093 seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]); 1094 } 1095 seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]); 1096 } 1097 1098 static const struct komeda_component_funcs d71_timing_ctrlr_funcs = { 1099 .update = d71_timing_ctrlr_update, 1100 .disable = d71_timing_ctrlr_disable, 1101 .dump_register = d71_timing_ctrlr_dump, 1102 }; 1103 1104 static int d71_timing_ctrlr_init(struct d71_dev *d71, 1105 struct block_header *blk, u32 __iomem *reg) 1106 { 1107 struct komeda_component *c; 1108 struct komeda_timing_ctrlr *ctrlr; 1109 u32 pipe_id, comp_id; 1110 1111 get_resources_id(blk->block_info, &pipe_id, &comp_id); 1112 1113 c = komeda_component_add(&d71->pipes[pipe_id]->base, sizeof(*ctrlr), 1114 KOMEDA_COMPONENT_TIMING_CTRLR, 1115 BLOCK_INFO_INPUT_ID(blk->block_info), 1116 &d71_timing_ctrlr_funcs, 1117 1, BIT(KOMEDA_COMPONENT_IPS0 + pipe_id), 1118 BS_NUM_OUTPUT_IDS, reg, "DOU%d_BS", pipe_id); 1119 if (IS_ERR(c)) { 1120 DRM_ERROR("Failed to add display_ctrl component\n"); 1121 return PTR_ERR(c); 1122 } 1123 1124 ctrlr = to_ctrlr(c); 1125 1126 ctrlr->supports_dual_link = true; 1127 1128 return 0; 1129 } 1130 1131 int d71_probe_block(struct d71_dev *d71, 1132 struct block_header *blk, u32 __iomem *reg) 1133 { 1134 struct d71_pipeline *pipe; 1135 int blk_id = BLOCK_INFO_BLK_ID(blk->block_info); 1136 1137 int err = 0; 1138 1139 switch (BLOCK_INFO_BLK_TYPE(blk->block_info)) { 1140 case D71_BLK_TYPE_GCU: 1141 break; 1142 1143 case D71_BLK_TYPE_LPU: 1144 pipe = d71->pipes[blk_id]; 1145 pipe->lpu_addr = reg; 1146 break; 1147 1148 case D71_BLK_TYPE_LPU_LAYER: 1149 err = d71_layer_init(d71, blk, reg); 1150 break; 1151 1152 case D71_BLK_TYPE_LPU_WB_LAYER: 1153 err = d71_wb_layer_init(d71, blk, reg); 1154 break; 1155 1156 case D71_BLK_TYPE_CU: 1157 pipe = d71->pipes[blk_id]; 1158 pipe->cu_addr = reg; 1159 err = d71_compiz_init(d71, blk, reg); 1160 break; 1161 1162 case D71_BLK_TYPE_CU_SCALER: 1163 err = d71_scaler_init(d71, blk, reg); 1164 break; 1165 1166 case D71_BLK_TYPE_CU_SPLITTER: 1167 err = d71_splitter_init(d71, blk, reg); 1168 break; 1169 1170 case D71_BLK_TYPE_CU_MERGER: 1171 err = d71_merger_init(d71, blk, reg); 1172 break; 1173 1174 case D71_BLK_TYPE_DOU: 1175 pipe = d71->pipes[blk_id]; 1176 pipe->dou_addr = reg; 1177 break; 1178 1179 case D71_BLK_TYPE_DOU_IPS: 1180 err = d71_improc_init(d71, blk, reg); 1181 break; 1182 1183 case D71_BLK_TYPE_DOU_FT_COEFF: 1184 pipe = d71->pipes[blk_id]; 1185 pipe->dou_ft_coeff_addr = reg; 1186 break; 1187 1188 case D71_BLK_TYPE_DOU_BS: 1189 err = d71_timing_ctrlr_init(d71, blk, reg); 1190 break; 1191 1192 case D71_BLK_TYPE_GLB_LT_COEFF: 1193 break; 1194 1195 case D71_BLK_TYPE_GLB_SCL_COEFF: 1196 d71->glb_scl_coeff_addr[blk_id] = reg; 1197 break; 1198 1199 default: 1200 DRM_ERROR("Unknown block (block_info: 0x%x) is found\n", 1201 blk->block_info); 1202 err = -EINVAL; 1203 break; 1204 } 1205 1206 return err; 1207 } 1208 1209 const struct komeda_pipeline_funcs d71_pipeline_funcs = { 1210 .downscaling_clk_check = d71_downscaling_clk_check, 1211 }; 1212