1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 5 */ 6 7 #define pr_fmt(fmt) "[drm:%s] " fmt, __func__ 8 #include "dpu_kms.h" 9 #include "dpu_hw_lm.h" 10 #include "dpu_hw_ctl.h" 11 #include "dpu_hw_cdm.h" 12 #include "dpu_hw_pingpong.h" 13 #include "dpu_hw_sspp.h" 14 #include "dpu_hw_intf.h" 15 #include "dpu_hw_wb.h" 16 #include "dpu_hw_dspp.h" 17 #include "dpu_hw_merge3d.h" 18 #include "dpu_hw_dsc.h" 19 #include "dpu_encoder.h" 20 #include "dpu_trace.h" 21 22 23 static inline bool reserved_by_other(uint32_t *res_map, int idx, 24 uint32_t enc_id) 25 { 26 return res_map[idx] && res_map[idx] != enc_id; 27 } 28 29 /** 30 * struct dpu_rm_requirements - Reservation requirements parameter bundle 31 * @topology: selected topology for the display 32 */ 33 struct dpu_rm_requirements { 34 struct msm_display_topology topology; 35 }; 36 37 int dpu_rm_init(struct drm_device *dev, 38 struct dpu_rm *rm, 39 const struct dpu_mdss_cfg *cat, 40 const struct msm_mdss_data *mdss_data, 41 void __iomem *mmio) 42 { 43 int rc, i; 44 45 if (!rm || !cat || !mmio) { 46 DPU_ERROR("invalid kms\n"); 47 return -EINVAL; 48 } 49 50 /* Clear, setup lists */ 51 memset(rm, 0, sizeof(*rm)); 52 53 /* Interrogate HW catalog and create tracking items for hw blocks */ 54 for (i = 0; i < cat->mixer_count; i++) { 55 struct dpu_hw_mixer *hw; 56 const struct dpu_lm_cfg *lm = &cat->mixer[i]; 57 58 hw = dpu_hw_lm_init(dev, lm, mmio); 59 if (IS_ERR(hw)) { 60 rc = PTR_ERR(hw); 61 DPU_ERROR("failed lm object creation: err %d\n", rc); 62 goto fail; 63 } 64 rm->mixer_blks[lm->id - LM_0] = &hw->base; 65 } 66 67 for (i = 0; i < cat->merge_3d_count; i++) { 68 struct dpu_hw_merge_3d *hw; 69 const struct dpu_merge_3d_cfg *merge_3d = &cat->merge_3d[i]; 70 71 hw = dpu_hw_merge_3d_init(dev, merge_3d, mmio); 72 if (IS_ERR(hw)) { 73 rc = PTR_ERR(hw); 74 DPU_ERROR("failed merge_3d object creation: err %d\n", 75 rc); 76 goto fail; 77 } 78 rm->merge_3d_blks[merge_3d->id - MERGE_3D_0] = &hw->base; 79 } 80 81 for (i = 0; i < cat->pingpong_count; i++) { 82 struct dpu_hw_pingpong *hw; 83 const struct dpu_pingpong_cfg *pp = &cat->pingpong[i]; 84 85 hw = dpu_hw_pingpong_init(dev, pp, mmio, cat->mdss_ver); 86 if (IS_ERR(hw)) { 87 rc = PTR_ERR(hw); 88 DPU_ERROR("failed pingpong object creation: err %d\n", 89 rc); 90 goto fail; 91 } 92 if (pp->merge_3d && pp->merge_3d < MERGE_3D_MAX) 93 hw->merge_3d = to_dpu_hw_merge_3d(rm->merge_3d_blks[pp->merge_3d - MERGE_3D_0]); 94 rm->pingpong_blks[pp->id - PINGPONG_0] = &hw->base; 95 } 96 97 for (i = 0; i < cat->intf_count; i++) { 98 struct dpu_hw_intf *hw; 99 const struct dpu_intf_cfg *intf = &cat->intf[i]; 100 101 hw = dpu_hw_intf_init(dev, intf, mmio, cat->mdss_ver); 102 if (IS_ERR(hw)) { 103 rc = PTR_ERR(hw); 104 DPU_ERROR("failed intf object creation: err %d\n", rc); 105 goto fail; 106 } 107 rm->hw_intf[intf->id - INTF_0] = hw; 108 } 109 110 for (i = 0; i < cat->wb_count; i++) { 111 struct dpu_hw_wb *hw; 112 const struct dpu_wb_cfg *wb = &cat->wb[i]; 113 114 hw = dpu_hw_wb_init(dev, wb, mmio, cat->mdss_ver); 115 if (IS_ERR(hw)) { 116 rc = PTR_ERR(hw); 117 DPU_ERROR("failed wb object creation: err %d\n", rc); 118 goto fail; 119 } 120 rm->hw_wb[wb->id - WB_0] = hw; 121 } 122 123 for (i = 0; i < cat->ctl_count; i++) { 124 struct dpu_hw_ctl *hw; 125 const struct dpu_ctl_cfg *ctl = &cat->ctl[i]; 126 127 hw = dpu_hw_ctl_init(dev, ctl, mmio, cat->mixer_count, cat->mixer); 128 if (IS_ERR(hw)) { 129 rc = PTR_ERR(hw); 130 DPU_ERROR("failed ctl object creation: err %d\n", rc); 131 goto fail; 132 } 133 rm->ctl_blks[ctl->id - CTL_0] = &hw->base; 134 } 135 136 for (i = 0; i < cat->dspp_count; i++) { 137 struct dpu_hw_dspp *hw; 138 const struct dpu_dspp_cfg *dspp = &cat->dspp[i]; 139 140 hw = dpu_hw_dspp_init(dev, dspp, mmio); 141 if (IS_ERR(hw)) { 142 rc = PTR_ERR(hw); 143 DPU_ERROR("failed dspp object creation: err %d\n", rc); 144 goto fail; 145 } 146 rm->dspp_blks[dspp->id - DSPP_0] = &hw->base; 147 } 148 149 for (i = 0; i < cat->dsc_count; i++) { 150 struct dpu_hw_dsc *hw; 151 const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; 152 153 if (test_bit(DPU_DSC_HW_REV_1_2, &dsc->features)) 154 hw = dpu_hw_dsc_init_1_2(dev, dsc, mmio); 155 else 156 hw = dpu_hw_dsc_init(dev, dsc, mmio); 157 158 if (IS_ERR(hw)) { 159 rc = PTR_ERR(hw); 160 DPU_ERROR("failed dsc object creation: err %d\n", rc); 161 goto fail; 162 } 163 rm->dsc_blks[dsc->id - DSC_0] = &hw->base; 164 } 165 166 for (i = 0; i < cat->sspp_count; i++) { 167 struct dpu_hw_sspp *hw; 168 const struct dpu_sspp_cfg *sspp = &cat->sspp[i]; 169 170 hw = dpu_hw_sspp_init(dev, sspp, mmio, mdss_data, cat->mdss_ver); 171 if (IS_ERR(hw)) { 172 rc = PTR_ERR(hw); 173 DPU_ERROR("failed sspp object creation: err %d\n", rc); 174 goto fail; 175 } 176 rm->hw_sspp[sspp->id - SSPP_NONE] = hw; 177 } 178 179 if (cat->cdm) { 180 struct dpu_hw_cdm *hw; 181 182 hw = dpu_hw_cdm_init(dev, cat->cdm, mmio, cat->mdss_ver); 183 if (IS_ERR(hw)) { 184 rc = PTR_ERR(hw); 185 DPU_ERROR("failed cdm object creation: err %d\n", rc); 186 goto fail; 187 } 188 rm->cdm_blk = &hw->base; 189 } 190 191 return 0; 192 193 fail: 194 return rc ? rc : -EFAULT; 195 } 196 197 static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) 198 { 199 return top->num_intf > 1; 200 } 201 202 /** 203 * _dpu_rm_get_lm_peer - get the id of a mixer which is a peer of the primary 204 * @rm: dpu resource manager handle 205 * @primary_idx: index of primary mixer in rm->mixer_blks[] 206 * 207 * Returns: lm peer mixed id on success or %-EINVAL on error 208 */ 209 static int _dpu_rm_get_lm_peer(struct dpu_rm *rm, int primary_idx) 210 { 211 const struct dpu_lm_cfg *prim_lm_cfg; 212 213 prim_lm_cfg = to_dpu_hw_mixer(rm->mixer_blks[primary_idx])->cap; 214 215 if (prim_lm_cfg->lm_pair >= LM_0 && prim_lm_cfg->lm_pair < LM_MAX) 216 return prim_lm_cfg->lm_pair - LM_0; 217 return -EINVAL; 218 } 219 220 /** 221 * _dpu_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets 222 * proposed use case requirements, incl. hardwired dependent blocks like 223 * pingpong 224 * @rm: dpu resource manager handle 225 * @global_state: resources shared across multiple kms objects 226 * @enc_id: encoder id requesting for allocation 227 * @lm_idx: index of proposed layer mixer in rm->mixer_blks[], function checks 228 * if lm, and all other hardwired blocks connected to the lm (pp) is 229 * available and appropriate 230 * @pp_idx: output parameter, index of pingpong block attached to the layer 231 * mixer in rm->pingpong_blks[]. 232 * @dspp_idx: output parameter, index of dspp block attached to the layer 233 * mixer in rm->dspp_blks[]. 234 * @reqs: input parameter, rm requirements for HW blocks needed in the 235 * datapath. 236 * Return: true if lm matches all requirements, false otherwise 237 */ 238 static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, 239 struct dpu_global_state *global_state, 240 uint32_t enc_id, int lm_idx, int *pp_idx, int *dspp_idx, 241 struct dpu_rm_requirements *reqs) 242 { 243 const struct dpu_lm_cfg *lm_cfg; 244 int idx; 245 246 /* Already reserved? */ 247 if (reserved_by_other(global_state->mixer_to_enc_id, lm_idx, enc_id)) { 248 DPU_DEBUG("lm %d already reserved\n", lm_idx + LM_0); 249 return false; 250 } 251 252 lm_cfg = to_dpu_hw_mixer(rm->mixer_blks[lm_idx])->cap; 253 idx = lm_cfg->pingpong - PINGPONG_0; 254 if (idx < 0 || idx >= ARRAY_SIZE(rm->pingpong_blks)) { 255 DPU_ERROR("failed to get pp on lm %d\n", lm_cfg->pingpong); 256 return false; 257 } 258 259 if (reserved_by_other(global_state->pingpong_to_enc_id, idx, enc_id)) { 260 DPU_DEBUG("lm %d pp %d already reserved\n", lm_cfg->id, 261 lm_cfg->pingpong); 262 return false; 263 } 264 *pp_idx = idx; 265 266 if (!reqs->topology.num_dspp) 267 return true; 268 269 idx = lm_cfg->dspp - DSPP_0; 270 if (idx < 0 || idx >= ARRAY_SIZE(rm->dspp_blks)) { 271 DPU_ERROR("failed to get dspp on lm %d\n", lm_cfg->dspp); 272 return false; 273 } 274 275 if (reserved_by_other(global_state->dspp_to_enc_id, idx, enc_id)) { 276 DPU_DEBUG("lm %d dspp %d already reserved\n", lm_cfg->id, 277 lm_cfg->dspp); 278 return false; 279 } 280 *dspp_idx = idx; 281 282 return true; 283 } 284 285 static int _dpu_rm_reserve_lms(struct dpu_rm *rm, 286 struct dpu_global_state *global_state, 287 uint32_t enc_id, 288 struct dpu_rm_requirements *reqs) 289 290 { 291 int lm_idx[MAX_BLOCKS]; 292 int pp_idx[MAX_BLOCKS]; 293 int dspp_idx[MAX_BLOCKS] = {0}; 294 int i, lm_count = 0; 295 296 if (!reqs->topology.num_lm) { 297 DPU_ERROR("invalid number of lm: %d\n", reqs->topology.num_lm); 298 return -EINVAL; 299 } 300 301 /* Find a primary mixer */ 302 for (i = 0; i < ARRAY_SIZE(rm->mixer_blks) && 303 lm_count < reqs->topology.num_lm; i++) { 304 if (!rm->mixer_blks[i]) 305 continue; 306 307 lm_count = 0; 308 lm_idx[lm_count] = i; 309 310 if (!_dpu_rm_check_lm_and_get_connected_blks(rm, global_state, 311 enc_id, i, &pp_idx[lm_count], 312 &dspp_idx[lm_count], reqs)) { 313 continue; 314 } 315 316 ++lm_count; 317 318 /* Valid primary mixer found, find matching peers */ 319 if (lm_count < reqs->topology.num_lm) { 320 int j = _dpu_rm_get_lm_peer(rm, i); 321 322 /* ignore the peer if there is an error or if the peer was already processed */ 323 if (j < 0 || j < i) 324 continue; 325 326 if (!rm->mixer_blks[j]) 327 continue; 328 329 if (!_dpu_rm_check_lm_and_get_connected_blks(rm, 330 global_state, enc_id, j, 331 &pp_idx[lm_count], &dspp_idx[lm_count], 332 reqs)) { 333 continue; 334 } 335 336 lm_idx[lm_count] = j; 337 ++lm_count; 338 } 339 } 340 341 if (lm_count != reqs->topology.num_lm) { 342 DPU_DEBUG("unable to find appropriate mixers\n"); 343 return -ENAVAIL; 344 } 345 346 for (i = 0; i < lm_count; i++) { 347 global_state->mixer_to_enc_id[lm_idx[i]] = enc_id; 348 global_state->pingpong_to_enc_id[pp_idx[i]] = enc_id; 349 global_state->dspp_to_enc_id[dspp_idx[i]] = 350 reqs->topology.num_dspp ? enc_id : 0; 351 352 trace_dpu_rm_reserve_lms(lm_idx[i] + LM_0, enc_id, 353 pp_idx[i] + PINGPONG_0); 354 } 355 356 return 0; 357 } 358 359 static int _dpu_rm_reserve_ctls( 360 struct dpu_rm *rm, 361 struct dpu_global_state *global_state, 362 uint32_t enc_id, 363 const struct msm_display_topology *top) 364 { 365 int ctl_idx[MAX_BLOCKS]; 366 int i = 0, j, num_ctls; 367 bool needs_split_display; 368 369 /* each hw_intf needs its own hw_ctrl to program its control path */ 370 num_ctls = top->num_intf; 371 372 needs_split_display = _dpu_rm_needs_split_display(top); 373 374 for (j = 0; j < ARRAY_SIZE(rm->ctl_blks); j++) { 375 const struct dpu_hw_ctl *ctl; 376 unsigned long features; 377 bool has_split_display; 378 379 if (!rm->ctl_blks[j]) 380 continue; 381 if (reserved_by_other(global_state->ctl_to_enc_id, j, enc_id)) 382 continue; 383 384 ctl = to_dpu_hw_ctl(rm->ctl_blks[j]); 385 features = ctl->caps->features; 386 has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features; 387 388 DPU_DEBUG("ctl %d caps 0x%lX\n", j + CTL_0, features); 389 390 if (needs_split_display != has_split_display) 391 continue; 392 393 ctl_idx[i] = j; 394 DPU_DEBUG("ctl %d match\n", j + CTL_0); 395 396 if (++i == num_ctls) 397 break; 398 399 } 400 401 if (i != num_ctls) 402 return -ENAVAIL; 403 404 for (i = 0; i < ARRAY_SIZE(ctl_idx) && i < num_ctls; i++) { 405 global_state->ctl_to_enc_id[ctl_idx[i]] = enc_id; 406 trace_dpu_rm_reserve_ctls(i + CTL_0, enc_id); 407 } 408 409 return 0; 410 } 411 412 static int _dpu_rm_reserve_dsc(struct dpu_rm *rm, 413 struct dpu_global_state *global_state, 414 struct drm_encoder *enc, 415 const struct msm_display_topology *top) 416 { 417 int num_dsc = top->num_dsc; 418 int i; 419 420 /* check if DSC required are allocated or not */ 421 for (i = 0; i < num_dsc; i++) { 422 if (!rm->dsc_blks[i]) { 423 DPU_ERROR("DSC %d does not exist\n", i); 424 return -EIO; 425 } 426 427 if (global_state->dsc_to_enc_id[i]) { 428 DPU_ERROR("DSC %d is already allocated\n", i); 429 return -EIO; 430 } 431 } 432 433 for (i = 0; i < num_dsc; i++) 434 global_state->dsc_to_enc_id[i] = enc->base.id; 435 436 return 0; 437 } 438 439 static int _dpu_rm_reserve_cdm(struct dpu_rm *rm, 440 struct dpu_global_state *global_state, 441 struct drm_encoder *enc) 442 { 443 /* try allocating only one CDM block */ 444 if (!rm->cdm_blk) { 445 DPU_ERROR("CDM block does not exist\n"); 446 return -EIO; 447 } 448 449 if (global_state->cdm_to_enc_id) { 450 DPU_ERROR("CDM_0 is already allocated\n"); 451 return -EIO; 452 } 453 454 global_state->cdm_to_enc_id = enc->base.id; 455 456 return 0; 457 } 458 459 static int _dpu_rm_make_reservation( 460 struct dpu_rm *rm, 461 struct dpu_global_state *global_state, 462 struct drm_encoder *enc, 463 struct dpu_rm_requirements *reqs) 464 { 465 int ret; 466 467 ret = _dpu_rm_reserve_lms(rm, global_state, enc->base.id, reqs); 468 if (ret) { 469 DPU_ERROR("unable to find appropriate mixers\n"); 470 return ret; 471 } 472 473 ret = _dpu_rm_reserve_ctls(rm, global_state, enc->base.id, 474 &reqs->topology); 475 if (ret) { 476 DPU_ERROR("unable to find appropriate CTL\n"); 477 return ret; 478 } 479 480 ret = _dpu_rm_reserve_dsc(rm, global_state, enc, &reqs->topology); 481 if (ret) 482 return ret; 483 484 if (reqs->topology.needs_cdm) { 485 ret = _dpu_rm_reserve_cdm(rm, global_state, enc); 486 if (ret) { 487 DPU_ERROR("unable to find CDM blk\n"); 488 return ret; 489 } 490 } 491 492 return ret; 493 } 494 495 static int _dpu_rm_populate_requirements( 496 struct drm_encoder *enc, 497 struct dpu_rm_requirements *reqs, 498 struct msm_display_topology req_topology) 499 { 500 reqs->topology = req_topology; 501 502 DRM_DEBUG_KMS("num_lm: %d num_dsc: %d num_intf: %d cdm: %d\n", 503 reqs->topology.num_lm, reqs->topology.num_dsc, 504 reqs->topology.num_intf, reqs->topology.needs_cdm); 505 506 return 0; 507 } 508 509 static void _dpu_rm_clear_mapping(uint32_t *res_mapping, int cnt, 510 uint32_t enc_id) 511 { 512 int i; 513 514 for (i = 0; i < cnt; i++) { 515 if (res_mapping[i] == enc_id) 516 res_mapping[i] = 0; 517 } 518 } 519 520 void dpu_rm_release(struct dpu_global_state *global_state, 521 struct drm_encoder *enc) 522 { 523 _dpu_rm_clear_mapping(global_state->pingpong_to_enc_id, 524 ARRAY_SIZE(global_state->pingpong_to_enc_id), enc->base.id); 525 _dpu_rm_clear_mapping(global_state->mixer_to_enc_id, 526 ARRAY_SIZE(global_state->mixer_to_enc_id), enc->base.id); 527 _dpu_rm_clear_mapping(global_state->ctl_to_enc_id, 528 ARRAY_SIZE(global_state->ctl_to_enc_id), enc->base.id); 529 _dpu_rm_clear_mapping(global_state->dsc_to_enc_id, 530 ARRAY_SIZE(global_state->dsc_to_enc_id), enc->base.id); 531 _dpu_rm_clear_mapping(global_state->dspp_to_enc_id, 532 ARRAY_SIZE(global_state->dspp_to_enc_id), enc->base.id); 533 _dpu_rm_clear_mapping(&global_state->cdm_to_enc_id, 1, enc->base.id); 534 } 535 536 int dpu_rm_reserve( 537 struct dpu_rm *rm, 538 struct dpu_global_state *global_state, 539 struct drm_encoder *enc, 540 struct drm_crtc_state *crtc_state, 541 struct msm_display_topology topology) 542 { 543 struct dpu_rm_requirements reqs; 544 int ret; 545 546 /* Check if this is just a page-flip */ 547 if (!drm_atomic_crtc_needs_modeset(crtc_state)) 548 return 0; 549 550 if (IS_ERR(global_state)) { 551 DPU_ERROR("failed to global state\n"); 552 return PTR_ERR(global_state); 553 } 554 555 DRM_DEBUG_KMS("reserving hw for enc %d crtc %d\n", 556 enc->base.id, crtc_state->crtc->base.id); 557 558 ret = _dpu_rm_populate_requirements(enc, &reqs, topology); 559 if (ret) { 560 DPU_ERROR("failed to populate hw requirements\n"); 561 return ret; 562 } 563 564 ret = _dpu_rm_make_reservation(rm, global_state, enc, &reqs); 565 if (ret) 566 DPU_ERROR("failed to reserve hw resources: %d\n", ret); 567 568 569 570 return ret; 571 } 572 573 int dpu_rm_get_assigned_resources(struct dpu_rm *rm, 574 struct dpu_global_state *global_state, uint32_t enc_id, 575 enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size) 576 { 577 struct dpu_hw_blk **hw_blks; 578 uint32_t *hw_to_enc_id; 579 int i, num_blks, max_blks; 580 581 switch (type) { 582 case DPU_HW_BLK_PINGPONG: 583 hw_blks = rm->pingpong_blks; 584 hw_to_enc_id = global_state->pingpong_to_enc_id; 585 max_blks = ARRAY_SIZE(rm->pingpong_blks); 586 break; 587 case DPU_HW_BLK_LM: 588 hw_blks = rm->mixer_blks; 589 hw_to_enc_id = global_state->mixer_to_enc_id; 590 max_blks = ARRAY_SIZE(rm->mixer_blks); 591 break; 592 case DPU_HW_BLK_CTL: 593 hw_blks = rm->ctl_blks; 594 hw_to_enc_id = global_state->ctl_to_enc_id; 595 max_blks = ARRAY_SIZE(rm->ctl_blks); 596 break; 597 case DPU_HW_BLK_DSPP: 598 hw_blks = rm->dspp_blks; 599 hw_to_enc_id = global_state->dspp_to_enc_id; 600 max_blks = ARRAY_SIZE(rm->dspp_blks); 601 break; 602 case DPU_HW_BLK_DSC: 603 hw_blks = rm->dsc_blks; 604 hw_to_enc_id = global_state->dsc_to_enc_id; 605 max_blks = ARRAY_SIZE(rm->dsc_blks); 606 break; 607 case DPU_HW_BLK_CDM: 608 hw_blks = &rm->cdm_blk; 609 hw_to_enc_id = &global_state->cdm_to_enc_id; 610 max_blks = 1; 611 break; 612 default: 613 DPU_ERROR("blk type %d not managed by rm\n", type); 614 return 0; 615 } 616 617 num_blks = 0; 618 for (i = 0; i < max_blks; i++) { 619 if (hw_to_enc_id[i] != enc_id) 620 continue; 621 622 if (num_blks == blks_size) { 623 DPU_ERROR("More than %d resources assigned to enc %d\n", 624 blks_size, enc_id); 625 break; 626 } 627 if (!hw_blks[i]) { 628 DPU_ERROR("Allocated resource %d unavailable to assign to enc %d\n", 629 type, enc_id); 630 break; 631 } 632 blks[num_blks++] = hw_blks[i]; 633 } 634 635 return num_blks; 636 } 637