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