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 127 for (i = 0; i < cat->merge_3d_count; i++) { 128 struct dpu_hw_merge_3d *hw; 129 const struct dpu_merge_3d_cfg *merge_3d = &cat->merge_3d[i]; 130 131 if (merge_3d->id < MERGE_3D_0 || merge_3d->id >= MERGE_3D_MAX) { 132 DPU_ERROR("skip merge_3d %d with invalid id\n", merge_3d->id); 133 continue; 134 } 135 hw = dpu_hw_merge_3d_init(merge_3d->id, mmio, cat); 136 if (IS_ERR_OR_NULL(hw)) { 137 rc = PTR_ERR(hw); 138 DPU_ERROR("failed merge_3d object creation: err %d\n", 139 rc); 140 goto fail; 141 } 142 rm->merge_3d_blks[merge_3d->id - MERGE_3D_0] = &hw->base; 143 } 144 145 for (i = 0; i < cat->pingpong_count; i++) { 146 struct dpu_hw_pingpong *hw; 147 const struct dpu_pingpong_cfg *pp = &cat->pingpong[i]; 148 149 if (pp->id < PINGPONG_0 || pp->id >= PINGPONG_MAX) { 150 DPU_ERROR("skip pingpong %d with invalid id\n", pp->id); 151 continue; 152 } 153 hw = dpu_hw_pingpong_init(pp->id, mmio, cat); 154 if (IS_ERR_OR_NULL(hw)) { 155 rc = PTR_ERR(hw); 156 DPU_ERROR("failed pingpong object creation: err %d\n", 157 rc); 158 goto fail; 159 } 160 if (pp->merge_3d && pp->merge_3d < MERGE_3D_MAX) 161 hw->merge_3d = to_dpu_hw_merge_3d(rm->merge_3d_blks[pp->merge_3d - MERGE_3D_0]); 162 rm->pingpong_blks[pp->id - PINGPONG_0] = &hw->base; 163 } 164 165 for (i = 0; i < cat->intf_count; i++) { 166 struct dpu_hw_intf *hw; 167 const struct dpu_intf_cfg *intf = &cat->intf[i]; 168 169 if (intf->type == INTF_NONE) { 170 DPU_DEBUG("skip intf %d with type none\n", i); 171 continue; 172 } 173 if (intf->id < INTF_0 || intf->id >= INTF_MAX) { 174 DPU_ERROR("skip intf %d with invalid id\n", intf->id); 175 continue; 176 } 177 hw = dpu_hw_intf_init(intf->id, mmio, cat); 178 if (IS_ERR_OR_NULL(hw)) { 179 rc = PTR_ERR(hw); 180 DPU_ERROR("failed intf object creation: err %d\n", rc); 181 goto fail; 182 } 183 rm->intf_blks[intf->id - INTF_0] = &hw->base; 184 } 185 186 for (i = 0; i < cat->ctl_count; i++) { 187 struct dpu_hw_ctl *hw; 188 const struct dpu_ctl_cfg *ctl = &cat->ctl[i]; 189 190 if (ctl->id < CTL_0 || ctl->id >= CTL_MAX) { 191 DPU_ERROR("skip ctl %d with invalid id\n", ctl->id); 192 continue; 193 } 194 hw = dpu_hw_ctl_init(ctl->id, mmio, cat); 195 if (IS_ERR_OR_NULL(hw)) { 196 rc = PTR_ERR(hw); 197 DPU_ERROR("failed ctl object creation: err %d\n", rc); 198 goto fail; 199 } 200 rm->ctl_blks[ctl->id - CTL_0] = &hw->base; 201 } 202 203 for (i = 0; i < cat->dspp_count; i++) { 204 struct dpu_hw_dspp *hw; 205 const struct dpu_dspp_cfg *dspp = &cat->dspp[i]; 206 207 if (dspp->id < DSPP_0 || dspp->id >= DSPP_MAX) { 208 DPU_ERROR("skip dspp %d with invalid id\n", dspp->id); 209 continue; 210 } 211 hw = dpu_hw_dspp_init(dspp->id, mmio, cat); 212 if (IS_ERR_OR_NULL(hw)) { 213 rc = PTR_ERR(hw); 214 DPU_ERROR("failed dspp object creation: err %d\n", rc); 215 goto fail; 216 } 217 rm->dspp_blks[dspp->id - DSPP_0] = &hw->base; 218 } 219 220 return 0; 221 222 fail: 223 dpu_rm_destroy(rm); 224 225 return rc ? rc : -EFAULT; 226 } 227 228 static bool _dpu_rm_needs_split_display(const struct msm_display_topology *top) 229 { 230 return top->num_intf > 1; 231 } 232 233 /** 234 * _dpu_rm_check_lm_peer - check if a mixer is a peer of the primary 235 * @rm: dpu resource manager handle 236 * @primary_idx: index of primary mixer in rm->mixer_blks[] 237 * @peer_idx: index of other mixer in rm->mixer_blks[] 238 * Return: true if rm->mixer_blks[peer_idx] is a peer of 239 * rm->mixer_blks[primary_idx] 240 */ 241 static bool _dpu_rm_check_lm_peer(struct dpu_rm *rm, int primary_idx, 242 int peer_idx) 243 { 244 const struct dpu_lm_cfg *prim_lm_cfg; 245 const struct dpu_lm_cfg *peer_cfg; 246 247 prim_lm_cfg = to_dpu_hw_mixer(rm->mixer_blks[primary_idx])->cap; 248 peer_cfg = to_dpu_hw_mixer(rm->mixer_blks[peer_idx])->cap; 249 250 if (!test_bit(peer_cfg->id, &prim_lm_cfg->lm_pair_mask)) { 251 DPU_DEBUG("lm %d not peer of lm %d\n", peer_cfg->id, 252 peer_cfg->id); 253 return false; 254 } 255 return true; 256 } 257 258 /** 259 * _dpu_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets 260 * proposed use case requirements, incl. hardwired dependent blocks like 261 * pingpong 262 * @rm: dpu resource manager handle 263 * @global_state: resources shared across multiple kms objects 264 * @enc_id: encoder id requesting for allocation 265 * @lm_idx: index of proposed layer mixer in rm->mixer_blks[], function checks 266 * if lm, and all other hardwired blocks connected to the lm (pp) is 267 * available and appropriate 268 * @pp_idx: output parameter, index of pingpong block attached to the layer 269 * mixer in rm->pingpong_blks[]. 270 * @dspp_idx: output parameter, index of dspp block attached to the layer 271 * mixer in rm->dspp_blks[]. 272 * @reqs: input parameter, rm requirements for HW blocks needed in the 273 * datapath. 274 * Return: true if lm matches all requirements, false otherwise 275 */ 276 static bool _dpu_rm_check_lm_and_get_connected_blks(struct dpu_rm *rm, 277 struct dpu_global_state *global_state, 278 uint32_t enc_id, int lm_idx, int *pp_idx, int *dspp_idx, 279 struct dpu_rm_requirements *reqs) 280 { 281 const struct dpu_lm_cfg *lm_cfg; 282 int idx; 283 284 /* Already reserved? */ 285 if (reserved_by_other(global_state->mixer_to_enc_id, lm_idx, enc_id)) { 286 DPU_DEBUG("lm %d already reserved\n", lm_idx + LM_0); 287 return false; 288 } 289 290 lm_cfg = to_dpu_hw_mixer(rm->mixer_blks[lm_idx])->cap; 291 idx = lm_cfg->pingpong - PINGPONG_0; 292 if (idx < 0 || idx >= ARRAY_SIZE(rm->pingpong_blks)) { 293 DPU_ERROR("failed to get pp on lm %d\n", lm_cfg->pingpong); 294 return false; 295 } 296 297 if (reserved_by_other(global_state->pingpong_to_enc_id, idx, enc_id)) { 298 DPU_DEBUG("lm %d pp %d already reserved\n", lm_cfg->id, 299 lm_cfg->pingpong); 300 return false; 301 } 302 *pp_idx = idx; 303 304 if (!reqs->topology.num_dspp) 305 return true; 306 307 idx = lm_cfg->dspp - DSPP_0; 308 if (idx < 0 || idx >= ARRAY_SIZE(rm->dspp_blks)) { 309 DPU_ERROR("failed to get dspp on lm %d\n", lm_cfg->dspp); 310 return false; 311 } 312 313 if (reserved_by_other(global_state->dspp_to_enc_id, idx, enc_id)) { 314 DPU_DEBUG("lm %d dspp %d already reserved\n", lm_cfg->id, 315 lm_cfg->dspp); 316 return false; 317 } 318 *dspp_idx = idx; 319 320 return true; 321 } 322 323 static int _dpu_rm_reserve_lms(struct dpu_rm *rm, 324 struct dpu_global_state *global_state, 325 uint32_t enc_id, 326 struct dpu_rm_requirements *reqs) 327 328 { 329 int lm_idx[MAX_BLOCKS]; 330 int pp_idx[MAX_BLOCKS]; 331 int dspp_idx[MAX_BLOCKS] = {0}; 332 int i, j, lm_count = 0; 333 334 if (!reqs->topology.num_lm) { 335 DPU_ERROR("invalid number of lm: %d\n", reqs->topology.num_lm); 336 return -EINVAL; 337 } 338 339 /* Find a primary mixer */ 340 for (i = 0; i < ARRAY_SIZE(rm->mixer_blks) && 341 lm_count < reqs->topology.num_lm; i++) { 342 if (!rm->mixer_blks[i]) 343 continue; 344 345 lm_count = 0; 346 lm_idx[lm_count] = i; 347 348 if (!_dpu_rm_check_lm_and_get_connected_blks(rm, global_state, 349 enc_id, i, &pp_idx[lm_count], 350 &dspp_idx[lm_count], reqs)) { 351 continue; 352 } 353 354 ++lm_count; 355 356 /* Valid primary mixer found, find matching peers */ 357 for (j = i + 1; j < ARRAY_SIZE(rm->mixer_blks) && 358 lm_count < reqs->topology.num_lm; j++) { 359 if (!rm->mixer_blks[j]) 360 continue; 361 362 if (!_dpu_rm_check_lm_peer(rm, i, j)) { 363 DPU_DEBUG("lm %d not peer of lm %d\n", LM_0 + j, 364 LM_0 + i); 365 continue; 366 } 367 368 if (!_dpu_rm_check_lm_and_get_connected_blks(rm, 369 global_state, enc_id, j, 370 &pp_idx[lm_count], &dspp_idx[lm_count], 371 reqs)) { 372 continue; 373 } 374 375 lm_idx[lm_count] = j; 376 ++lm_count; 377 } 378 } 379 380 if (lm_count != reqs->topology.num_lm) { 381 DPU_DEBUG("unable to find appropriate mixers\n"); 382 return -ENAVAIL; 383 } 384 385 for (i = 0; i < lm_count; i++) { 386 global_state->mixer_to_enc_id[lm_idx[i]] = enc_id; 387 global_state->pingpong_to_enc_id[pp_idx[i]] = enc_id; 388 global_state->dspp_to_enc_id[dspp_idx[i]] = 389 reqs->topology.num_dspp ? enc_id : 0; 390 391 trace_dpu_rm_reserve_lms(lm_idx[i] + LM_0, enc_id, 392 pp_idx[i] + PINGPONG_0); 393 } 394 395 return 0; 396 } 397 398 static int _dpu_rm_reserve_ctls( 399 struct dpu_rm *rm, 400 struct dpu_global_state *global_state, 401 uint32_t enc_id, 402 const struct msm_display_topology *top) 403 { 404 int ctl_idx[MAX_BLOCKS]; 405 int i = 0, j, num_ctls; 406 bool needs_split_display; 407 408 /* each hw_intf needs its own hw_ctrl to program its control path */ 409 num_ctls = top->num_intf; 410 411 needs_split_display = _dpu_rm_needs_split_display(top); 412 413 for (j = 0; j < ARRAY_SIZE(rm->ctl_blks); j++) { 414 const struct dpu_hw_ctl *ctl; 415 unsigned long features; 416 bool has_split_display; 417 418 if (!rm->ctl_blks[j]) 419 continue; 420 if (reserved_by_other(global_state->ctl_to_enc_id, j, enc_id)) 421 continue; 422 423 ctl = to_dpu_hw_ctl(rm->ctl_blks[j]); 424 features = ctl->caps->features; 425 has_split_display = BIT(DPU_CTL_SPLIT_DISPLAY) & features; 426 427 DPU_DEBUG("ctl %d caps 0x%lX\n", j + CTL_0, features); 428 429 if (needs_split_display != has_split_display) 430 continue; 431 432 ctl_idx[i] = j; 433 DPU_DEBUG("ctl %d match\n", j + CTL_0); 434 435 if (++i == num_ctls) 436 break; 437 438 } 439 440 if (i != num_ctls) 441 return -ENAVAIL; 442 443 for (i = 0; i < ARRAY_SIZE(ctl_idx) && i < num_ctls; i++) { 444 global_state->ctl_to_enc_id[ctl_idx[i]] = enc_id; 445 trace_dpu_rm_reserve_ctls(i + CTL_0, enc_id); 446 } 447 448 return 0; 449 } 450 451 static int _dpu_rm_reserve_intf( 452 struct dpu_rm *rm, 453 struct dpu_global_state *global_state, 454 uint32_t enc_id, 455 uint32_t id) 456 { 457 int idx = id - INTF_0; 458 459 if (idx < 0 || idx >= ARRAY_SIZE(rm->intf_blks)) { 460 DPU_ERROR("invalid intf id: %d", id); 461 return -EINVAL; 462 } 463 464 if (!rm->intf_blks[idx]) { 465 DPU_ERROR("couldn't find intf id %d\n", id); 466 return -EINVAL; 467 } 468 469 if (reserved_by_other(global_state->intf_to_enc_id, idx, enc_id)) { 470 DPU_ERROR("intf id %d already reserved\n", id); 471 return -ENAVAIL; 472 } 473 474 global_state->intf_to_enc_id[idx] = enc_id; 475 return 0; 476 } 477 478 static int _dpu_rm_reserve_intf_related_hw( 479 struct dpu_rm *rm, 480 struct dpu_global_state *global_state, 481 uint32_t enc_id, 482 struct dpu_encoder_hw_resources *hw_res) 483 { 484 int i, ret = 0; 485 u32 id; 486 487 for (i = 0; i < ARRAY_SIZE(hw_res->intfs); i++) { 488 if (hw_res->intfs[i] == INTF_MODE_NONE) 489 continue; 490 id = i + INTF_0; 491 ret = _dpu_rm_reserve_intf(rm, global_state, enc_id, id); 492 if (ret) 493 return ret; 494 } 495 496 return ret; 497 } 498 499 static int _dpu_rm_make_reservation( 500 struct dpu_rm *rm, 501 struct dpu_global_state *global_state, 502 struct drm_encoder *enc, 503 struct dpu_rm_requirements *reqs) 504 { 505 int ret; 506 507 ret = _dpu_rm_reserve_lms(rm, global_state, enc->base.id, reqs); 508 if (ret) { 509 DPU_ERROR("unable to find appropriate mixers\n"); 510 return ret; 511 } 512 513 ret = _dpu_rm_reserve_ctls(rm, global_state, enc->base.id, 514 &reqs->topology); 515 if (ret) { 516 DPU_ERROR("unable to find appropriate CTL\n"); 517 return ret; 518 } 519 520 ret = _dpu_rm_reserve_intf_related_hw(rm, global_state, enc->base.id, 521 &reqs->hw_res); 522 if (ret) 523 return ret; 524 525 return ret; 526 } 527 528 static int _dpu_rm_populate_requirements( 529 struct drm_encoder *enc, 530 struct dpu_rm_requirements *reqs, 531 struct msm_display_topology req_topology) 532 { 533 dpu_encoder_get_hw_resources(enc, &reqs->hw_res); 534 535 reqs->topology = req_topology; 536 537 DRM_DEBUG_KMS("num_lm: %d num_enc: %d num_intf: %d\n", 538 reqs->topology.num_lm, reqs->topology.num_enc, 539 reqs->topology.num_intf); 540 541 return 0; 542 } 543 544 static void _dpu_rm_clear_mapping(uint32_t *res_mapping, int cnt, 545 uint32_t enc_id) 546 { 547 int i; 548 549 for (i = 0; i < cnt; i++) { 550 if (res_mapping[i] == enc_id) 551 res_mapping[i] = 0; 552 } 553 } 554 555 void dpu_rm_release(struct dpu_global_state *global_state, 556 struct drm_encoder *enc) 557 { 558 _dpu_rm_clear_mapping(global_state->pingpong_to_enc_id, 559 ARRAY_SIZE(global_state->pingpong_to_enc_id), enc->base.id); 560 _dpu_rm_clear_mapping(global_state->mixer_to_enc_id, 561 ARRAY_SIZE(global_state->mixer_to_enc_id), enc->base.id); 562 _dpu_rm_clear_mapping(global_state->ctl_to_enc_id, 563 ARRAY_SIZE(global_state->ctl_to_enc_id), enc->base.id); 564 _dpu_rm_clear_mapping(global_state->intf_to_enc_id, 565 ARRAY_SIZE(global_state->intf_to_enc_id), enc->base.id); 566 } 567 568 int dpu_rm_reserve( 569 struct dpu_rm *rm, 570 struct dpu_global_state *global_state, 571 struct drm_encoder *enc, 572 struct drm_crtc_state *crtc_state, 573 struct msm_display_topology topology) 574 { 575 struct dpu_rm_requirements reqs; 576 int ret; 577 578 /* Check if this is just a page-flip */ 579 if (!drm_atomic_crtc_needs_modeset(crtc_state)) 580 return 0; 581 582 if (IS_ERR(global_state)) { 583 DPU_ERROR("failed to global state\n"); 584 return PTR_ERR(global_state); 585 } 586 587 DRM_DEBUG_KMS("reserving hw for enc %d crtc %d\n", 588 enc->base.id, crtc_state->crtc->base.id); 589 590 ret = _dpu_rm_populate_requirements(enc, &reqs, topology); 591 if (ret) { 592 DPU_ERROR("failed to populate hw requirements\n"); 593 return ret; 594 } 595 596 ret = _dpu_rm_make_reservation(rm, global_state, enc, &reqs); 597 if (ret) 598 DPU_ERROR("failed to reserve hw resources: %d\n", ret); 599 600 601 602 return ret; 603 } 604 605 int dpu_rm_get_assigned_resources(struct dpu_rm *rm, 606 struct dpu_global_state *global_state, uint32_t enc_id, 607 enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size) 608 { 609 struct dpu_hw_blk **hw_blks; 610 uint32_t *hw_to_enc_id; 611 int i, num_blks, max_blks; 612 613 switch (type) { 614 case DPU_HW_BLK_PINGPONG: 615 hw_blks = rm->pingpong_blks; 616 hw_to_enc_id = global_state->pingpong_to_enc_id; 617 max_blks = ARRAY_SIZE(rm->pingpong_blks); 618 break; 619 case DPU_HW_BLK_LM: 620 hw_blks = rm->mixer_blks; 621 hw_to_enc_id = global_state->mixer_to_enc_id; 622 max_blks = ARRAY_SIZE(rm->mixer_blks); 623 break; 624 case DPU_HW_BLK_CTL: 625 hw_blks = rm->ctl_blks; 626 hw_to_enc_id = global_state->ctl_to_enc_id; 627 max_blks = ARRAY_SIZE(rm->ctl_blks); 628 break; 629 case DPU_HW_BLK_INTF: 630 hw_blks = rm->intf_blks; 631 hw_to_enc_id = global_state->intf_to_enc_id; 632 max_blks = ARRAY_SIZE(rm->intf_blks); 633 break; 634 case DPU_HW_BLK_DSPP: 635 hw_blks = rm->dspp_blks; 636 hw_to_enc_id = global_state->dspp_to_enc_id; 637 max_blks = ARRAY_SIZE(rm->dspp_blks); 638 break; 639 default: 640 DPU_ERROR("blk type %d not managed by rm\n", type); 641 return 0; 642 } 643 644 num_blks = 0; 645 for (i = 0; i < max_blks; i++) { 646 if (hw_to_enc_id[i] != enc_id) 647 continue; 648 649 if (num_blks == blks_size) { 650 DPU_ERROR("More than %d resources assigned to enc %d\n", 651 blks_size, enc_id); 652 break; 653 } 654 blks[num_blks++] = hw_blks[i]; 655 } 656 657 return num_blks; 658 } 659