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