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