diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 64cb1a350812..68b21a5471ff 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -297,6 +297,7 @@ enum { enum { DSC_OFF, DSC_LEN, + DSC_PAIR_MASK, DSC_PROP_MAX, }; @@ -684,6 +685,7 @@ static struct sde_prop_type pp_prop[] = { static struct sde_prop_type dsc_prop[] = { {DSC_OFF, "qcom,sde-dsc-off", false, PROP_TYPE_U32_ARRAY}, {DSC_LEN, "qcom,sde-dsc-size", false, PROP_TYPE_U32}, + {DSC_PAIR_MASK, "qcom,sde-dsc-pair-mask", false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type cdm_prop[] = { @@ -2559,7 +2561,7 @@ static int sde_dsc_parse_dt(struct device_node *np, int rc, prop_count[MAX_BLOCKS], i; struct sde_prop_value *prop_value = NULL; bool prop_exists[DSC_PROP_MAX]; - u32 off_count; + u32 off_count, dsc_pair_mask; struct sde_dsc_cfg *dsc; if (!sde_cfg) { @@ -2600,6 +2602,11 @@ static int sde_dsc_parse_dt(struct device_node *np, if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) set_bit(SDE_DSC_OUTPUT_CTRL, &dsc->features); + + dsc_pair_mask = PROP_VALUE_ACCESS(prop_value, + DSC_PAIR_MASK, i); + if (dsc_pair_mask) + set_bit(dsc_pair_mask, dsc->dsc_pair_mask); } end: diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 7c87f9e14182..6900aa234311 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -13,6 +13,7 @@ #include #include #include +#include "sde_hw_mdss.h" /** * Max hardware block count: For ex: max 12 SSPP pipes or @@ -915,9 +916,11 @@ struct sde_pingpong_cfg { * @base register offset of this block * @len: length of hardware block * @features bit mask identifying sub-blocks/features + * @dsc_pair_mask: Bitmask of DSCs that can be controlled by same CTL */ struct sde_dsc_cfg { SDE_HW_BLK_INFO; + DECLARE_BITMAP(dsc_pair_mask, DSC_MAX); }; /** diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index 240311aada22..3a267387c8b8 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -1201,44 +1201,111 @@ static int _sde_rm_reserve_ctls( return 0; } +static bool _sde_rm_check_dsc(struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_hw_blk *dsc, + struct sde_rm_hw_blk *paired_dsc) +{ + const struct sde_dsc_cfg *dsc_cfg = to_sde_hw_dsc(dsc->hw)->caps; + + /* Already reserved? */ + if (RESERVED_BY_OTHER(dsc, rsvp)) { + SDE_DEBUG("dsc %d already reserved\n", dsc_cfg->id); + return false; + } + + /* Check if this dsc is a peer of the proposed paired DSC */ + if (paired_dsc) { + const struct sde_dsc_cfg *paired_dsc_cfg = + to_sde_hw_dsc(paired_dsc->hw)->caps; + + if (!test_bit(dsc_cfg->id, paired_dsc_cfg->dsc_pair_mask)) { + SDE_DEBUG("dsc %d not peer of dsc %d\n", dsc_cfg->id, + paired_dsc_cfg->id); + return false; + } + } + + return true; +} + static int _sde_rm_reserve_dsc( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, const struct sde_rm_topology_def *top, u8 *_dsc_ids) { - struct sde_rm_hw_iter iter; + struct sde_rm_hw_iter iter_i, iter_j; + struct sde_rm_hw_blk *dsc[MAX_BLOCKS]; int alloc_count = 0; - int num_dsc_enc = top->num_lm; + int num_dsc_enc = top->num_comp_enc; + int i; if (!top->num_comp_enc) return 0; - sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DSC); + sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_DSC); - while (_sde_rm_get_hw_locked(rm, &iter)) { - if (RESERVED_BY_OTHER(iter.blk, rsvp)) + /* Find a first DSC */ + while (alloc_count != num_dsc_enc && + _sde_rm_get_hw_locked(rm, &iter_i)) { + memset(&dsc, 0, sizeof(dsc)); + alloc_count = 0; + + if (_dsc_ids && (iter_i.blk->id != _dsc_ids[alloc_count])) + continue; + + if (!_sde_rm_check_dsc(rm, rsvp, iter_i.blk, NULL)) continue; SDE_DEBUG("blk id = %d, _dsc_ids[%d] = %d\n", - iter.blk->id, + iter_i.blk->id, alloc_count, _dsc_ids ? _dsc_ids[alloc_count] : -1); - if (_dsc_ids && (iter.blk->id != _dsc_ids[alloc_count])) - continue; + dsc[alloc_count++] = iter_i.blk; - iter.blk->rsvp_nxt = rsvp; - SDE_EVT32(iter.blk->type, rsvp->enc_id, iter.blk->id); + /* Valid first dsc found, find matching peers */ + sde_rm_init_hw_iter(&iter_j, 0, SDE_HW_BLK_DSC); - if (++alloc_count == num_dsc_enc) - return 0; + while (alloc_count != num_dsc_enc && + _sde_rm_get_hw_locked(rm, &iter_j)) { + if (iter_i.blk == iter_j.blk) + continue; + + if (_dsc_ids && (iter_j.blk->id != + _dsc_ids[alloc_count])) + continue; + + if (!_sde_rm_check_dsc(rm, rsvp, + iter_j.blk, iter_i.blk)) + continue; + + SDE_DEBUG("blk id = %d, _dsc_ids[%d] = %d\n", + iter_j.blk->id, + alloc_count, + _dsc_ids ? _dsc_ids[alloc_count] : -1); + + dsc[alloc_count++] = iter_j.blk; + } } - SDE_ERROR("couldn't reserve %d dsc blocks for enc id %d\n", - num_dsc_enc, rsvp->enc_id); + if (alloc_count != num_dsc_enc) { + SDE_ERROR("couldn't reserve %d dsc blocks for enc id %d\n", + num_dsc_enc, rsvp->enc_id); + return -EINVAL; + } - return -ENAVAIL; + for (i = 0; i < ARRAY_SIZE(dsc); i++) { + if (!dsc[i]) + break; + + dsc[i]->rsvp_nxt = rsvp; + + SDE_EVT32(dsc[i]->type, rsvp->enc_id, dsc[i]->id); + } + + return 0; } static int _sde_rm_reserve_qdss(