Loading drivers/gpu/drm/msm/sde/sde_rm.c +241 −155 Original line number Diff line number Diff line Loading @@ -391,72 +391,11 @@ static int _sde_rm_hw_blk_create( return 0; } int sde_rm_init(struct sde_rm *rm, static int _sde_rm_hw_blk_create_new(struct sde_rm *rm, struct sde_mdss_cfg *cat, void __iomem *mmio, struct drm_device *dev) void __iomem *mmio) { int i, rc = 0; enum sde_hw_blk_type type; if (!rm || !cat || !mmio || !dev) { SDE_ERROR("invalid kms\n"); return -EINVAL; } /* Clear, setup lists */ memset(rm, 0, sizeof(*rm)); mutex_init(&rm->rm_lock); INIT_LIST_HEAD(&rm->rsvps); for (type = 0; type < SDE_HW_BLK_MAX; type++) INIT_LIST_HEAD(&rm->hw_blks[type]); rm->dev = dev; if (IS_SDE_CTL_REV_100(cat->ctl_rev)) rm->topology_tbl = g_ctl_ver_1_top_table; else rm->topology_tbl = g_top_table; /* Some of the sub-blocks require an mdptop to be created */ rm->hw_mdp = sde_hw_mdptop_init(MDP_TOP, mmio, cat); if (IS_ERR_OR_NULL(rm->hw_mdp)) { rc = PTR_ERR(rm->hw_mdp); rm->hw_mdp = NULL; SDE_ERROR("failed: mdp hw not available\n"); goto fail; } /* Interrogate HW catalog and create tracking items for hw blocks */ for (i = 0; i < cat->mixer_count; i++) { struct sde_lm_cfg *lm = &cat->mixer[i]; if (lm->pingpong == PINGPONG_MAX) { SDE_ERROR("mixer %d without pingpong\n", lm->id); goto fail; } rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_LM, cat->mixer[i].id, &cat->mixer[i]); if (rc) { SDE_ERROR("failed: lm hw not available\n"); goto fail; } if (!rm->lm_max_width) { rm->lm_max_width = lm->sblk->maxwidth; } else if (rm->lm_max_width != lm->sblk->maxwidth) { /* * Don't expect to have hw where lm max widths differ. * If found, take the min. */ SDE_ERROR("unsupported: lm maxwidth differs\n"); if (rm->lm_max_width > lm->sblk->maxwidth) rm->lm_max_width = lm->sblk->maxwidth; } } for (i = 0; i < cat->dspp_count; i++) { rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DSPP, Loading Loading @@ -538,6 +477,80 @@ int sde_rm_init(struct sde_rm *rm, } return 0; fail: return rc; } int sde_rm_init(struct sde_rm *rm, struct sde_mdss_cfg *cat, void __iomem *mmio, struct drm_device *dev) { int i, rc = 0; enum sde_hw_blk_type type; if (!rm || !cat || !mmio || !dev) { SDE_ERROR("invalid kms\n"); return -EINVAL; } /* Clear, setup lists */ memset(rm, 0, sizeof(*rm)); mutex_init(&rm->rm_lock); INIT_LIST_HEAD(&rm->rsvps); for (type = 0; type < SDE_HW_BLK_MAX; type++) INIT_LIST_HEAD(&rm->hw_blks[type]); rm->dev = dev; if (IS_SDE_CTL_REV_100(cat->ctl_rev)) rm->topology_tbl = g_ctl_ver_1_top_table; else rm->topology_tbl = g_top_table; /* Some of the sub-blocks require an mdptop to be created */ rm->hw_mdp = sde_hw_mdptop_init(MDP_TOP, mmio, cat); if (IS_ERR_OR_NULL(rm->hw_mdp)) { rc = PTR_ERR(rm->hw_mdp); rm->hw_mdp = NULL; SDE_ERROR("failed: mdp hw not available\n"); goto fail; } /* Interrogate HW catalog and create tracking items for hw blocks */ for (i = 0; i < cat->mixer_count; i++) { struct sde_lm_cfg *lm = &cat->mixer[i]; if (lm->pingpong == PINGPONG_MAX) { SDE_ERROR("mixer %d without pingpong\n", lm->id); goto fail; } rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_LM, cat->mixer[i].id, &cat->mixer[i]); if (rc) { SDE_ERROR("failed: lm hw not available\n"); goto fail; } if (!rm->lm_max_width) { rm->lm_max_width = lm->sblk->maxwidth; } else if (rm->lm_max_width != lm->sblk->maxwidth) { /* * Don't expect to have hw where lm max widths differ. * If found, take the min. */ SDE_ERROR("unsupported: lm maxwidth differs\n"); if (rm->lm_max_width > lm->sblk->maxwidth) rm->lm_max_width = lm->sblk->maxwidth; } } rc = _sde_rm_hw_blk_create_new(rm, cat, mmio); if (!rc) return 0; fail: sde_rm_destroy(rm); Loading @@ -545,63 +558,18 @@ int sde_rm_init(struct sde_rm *rm, return rc; } /** * _sde_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets * proposed use case requirements, incl. hardwired dependent blocks like * pingpong, and dspp. * @rm: sde resource manager handle * @rsvp: reservation currently being created * @reqs: proposed use case requirements * @lm: proposed layer mixer, function checks if lm, and all other hardwired * blocks connected to the lm (pp, dspp) are available and appropriate * @dspp: output parameter, dspp block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @pp: output parameter, pingpong block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @primary_lm: if non-null, this function check if lm is compatible primary_lm * as well as satisfying all other requirements * @Return: true if lm matches all requirements, false otherwise */ static bool _sde_rm_check_lm_and_get_connected_blks( static bool _sde_rm_check_lm( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, struct sde_rm_requirements *reqs, const struct sde_lm_cfg *lm_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp, struct sde_rm_hw_blk *primary_lm) struct sde_rm_hw_blk **pp) { const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap; const struct sde_pingpong_cfg *pp_cfg; struct sde_rm_hw_iter iter; bool is_valid_dspp, is_valid_ds, ret; u32 display_pref, cwb_pref; *dspp = NULL; *ds = NULL; *pp = NULL; display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF); cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF); SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n", lm_cfg->id, lm_cfg->dspp, lm_cfg->ds, lm_cfg->pingpong, display_pref, cwb_pref); /* Check if this layer mixer is a peer of the proposed primary LM */ if (primary_lm) { const struct sde_lm_cfg *prim_lm_cfg = to_sde_hw_mixer(primary_lm->hw)->cap; if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) { SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id, prim_lm_cfg->id); return false; } } /* bypass rest of the checks if LM for primary display is found */ if (!display_pref) { is_valid_dspp = (lm_cfg->dspp != DSPP_MAX) ? true : false; is_valid_ds = (lm_cfg->ds != DS_MAX) ? true : false; Loading @@ -626,30 +594,20 @@ static bool _sde_rm_check_lm_and_get_connected_blks( lm_cfg->id, (bool)(RM_RQ_DSPP(reqs)), lm_cfg->dspp, (bool)(RM_RQ_DS(reqs)), lm_cfg->ds); return ret; } /** * If CWB is enabled and LM is not CWB supported * then return false. */ if (RM_RQ_CWB(reqs) && !cwb_pref) { SDE_DEBUG("fail: cwb supported lm not allocated\n"); return false; return ret; } } else if (!(reqs->hw_res.is_primary && display_pref)) { SDE_DEBUG( "display preference is not met. is_primary: %d display_pref: %d\n", (int)reqs->hw_res.is_primary, (int)display_pref); return false; return true; } /* Already reserved? */ if (RESERVED_BY_OTHER(lm, rsvp)) { SDE_DEBUG("lm %d already reserved\n", lm_cfg->id); return false; } static bool _sde_rm_reserve_dspp( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, const struct sde_lm_cfg *lm_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp) { struct sde_rm_hw_iter iter; if (lm_cfg->dspp != DSPP_MAX) { sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DSPP); Loading @@ -672,6 +630,18 @@ static bool _sde_rm_check_lm_and_get_connected_blks( return false; } } return true; } static bool _sde_rm_reserve_ds( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, const struct sde_lm_cfg *lm_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **ds) { struct sde_rm_hw_iter iter; if (lm_cfg->ds != DS_MAX) { sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DS); Loading @@ -694,6 +664,21 @@ static bool _sde_rm_check_lm_and_get_connected_blks( return false; } } return true; } static bool _sde_rm_reserve_pp( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, struct sde_rm_requirements *reqs, const struct sde_lm_cfg *lm_cfg, const struct sde_pingpong_cfg *pp_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp) { struct sde_rm_hw_iter iter; sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_PINGPONG); while (_sde_rm_get_hw_locked(rm, &iter)) { Loading Loading @@ -724,6 +709,107 @@ static bool _sde_rm_check_lm_and_get_connected_blks( *ds = NULL; return false; } return true; } /** * _sde_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets * proposed use case requirements, incl. hardwired dependent blocks like * pingpong, and dspp. * @rm: sde resource manager handle * @rsvp: reservation currently being created * @reqs: proposed use case requirements * @lm: proposed layer mixer, function checks if lm, and all other hardwired * blocks connected to the lm (pp, dspp) are available and appropriate * @dspp: output parameter, dspp block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @pp: output parameter, pingpong block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @primary_lm: if non-null, this function check if lm is compatible primary_lm * as well as satisfying all other requirements * @Return: true if lm matches all requirements, false otherwise */ static bool _sde_rm_check_lm_and_get_connected_blks( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, struct sde_rm_requirements *reqs, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp, struct sde_rm_hw_blk *primary_lm) { const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap; const struct sde_pingpong_cfg *pp_cfg; bool ret; u32 display_pref, cwb_pref; *dspp = NULL; *ds = NULL; *pp = NULL; display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF); cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF); SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n", lm_cfg->id, lm_cfg->dspp, lm_cfg->ds, lm_cfg->pingpong, display_pref, cwb_pref); /* Check if this layer mixer is a peer of the proposed primary LM */ if (primary_lm) { const struct sde_lm_cfg *prim_lm_cfg = to_sde_hw_mixer(primary_lm->hw)->cap; if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) { SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id, prim_lm_cfg->id); return false; } } /* bypass rest of the checks if LM for primary display is found */ if (!display_pref) { /* Check lm for valid requirements */ ret = _sde_rm_check_lm(rm, rsvp, reqs, lm_cfg, lm, dspp, ds, pp); if (!ret) return ret; /** * If CWB is enabled and LM is not CWB supported * then return false. */ if (RM_RQ_CWB(reqs) && !cwb_pref) { SDE_DEBUG("fail: cwb supported lm not allocated\n"); return false; } } else if (!(reqs->hw_res.is_primary && display_pref)) { SDE_DEBUG( "display preference is not met. is_primary: %d display_pref: %d\n", (int)reqs->hw_res.is_primary, (int)display_pref); return false; } /* Already reserved? */ if (RESERVED_BY_OTHER(lm, rsvp)) { SDE_DEBUG("lm %d already reserved\n", lm_cfg->id); return false; } /* Reserve dspp */ ret = _sde_rm_reserve_dspp(rm, rsvp, lm_cfg, lm, dspp); if (!ret) return ret; /* Reserve ds */ ret = _sde_rm_reserve_ds(rm, rsvp, lm_cfg, lm, ds); if (!ret) return ret; /* Reserve pp */ ret = _sde_rm_reserve_pp(rm, rsvp, reqs, lm_cfg, pp_cfg, lm, dspp, ds, pp); if (!ret) return ret; return true; } Loading Loading
drivers/gpu/drm/msm/sde/sde_rm.c +241 −155 Original line number Diff line number Diff line Loading @@ -391,72 +391,11 @@ static int _sde_rm_hw_blk_create( return 0; } int sde_rm_init(struct sde_rm *rm, static int _sde_rm_hw_blk_create_new(struct sde_rm *rm, struct sde_mdss_cfg *cat, void __iomem *mmio, struct drm_device *dev) void __iomem *mmio) { int i, rc = 0; enum sde_hw_blk_type type; if (!rm || !cat || !mmio || !dev) { SDE_ERROR("invalid kms\n"); return -EINVAL; } /* Clear, setup lists */ memset(rm, 0, sizeof(*rm)); mutex_init(&rm->rm_lock); INIT_LIST_HEAD(&rm->rsvps); for (type = 0; type < SDE_HW_BLK_MAX; type++) INIT_LIST_HEAD(&rm->hw_blks[type]); rm->dev = dev; if (IS_SDE_CTL_REV_100(cat->ctl_rev)) rm->topology_tbl = g_ctl_ver_1_top_table; else rm->topology_tbl = g_top_table; /* Some of the sub-blocks require an mdptop to be created */ rm->hw_mdp = sde_hw_mdptop_init(MDP_TOP, mmio, cat); if (IS_ERR_OR_NULL(rm->hw_mdp)) { rc = PTR_ERR(rm->hw_mdp); rm->hw_mdp = NULL; SDE_ERROR("failed: mdp hw not available\n"); goto fail; } /* Interrogate HW catalog and create tracking items for hw blocks */ for (i = 0; i < cat->mixer_count; i++) { struct sde_lm_cfg *lm = &cat->mixer[i]; if (lm->pingpong == PINGPONG_MAX) { SDE_ERROR("mixer %d without pingpong\n", lm->id); goto fail; } rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_LM, cat->mixer[i].id, &cat->mixer[i]); if (rc) { SDE_ERROR("failed: lm hw not available\n"); goto fail; } if (!rm->lm_max_width) { rm->lm_max_width = lm->sblk->maxwidth; } else if (rm->lm_max_width != lm->sblk->maxwidth) { /* * Don't expect to have hw where lm max widths differ. * If found, take the min. */ SDE_ERROR("unsupported: lm maxwidth differs\n"); if (rm->lm_max_width > lm->sblk->maxwidth) rm->lm_max_width = lm->sblk->maxwidth; } } for (i = 0; i < cat->dspp_count; i++) { rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DSPP, Loading Loading @@ -538,6 +477,80 @@ int sde_rm_init(struct sde_rm *rm, } return 0; fail: return rc; } int sde_rm_init(struct sde_rm *rm, struct sde_mdss_cfg *cat, void __iomem *mmio, struct drm_device *dev) { int i, rc = 0; enum sde_hw_blk_type type; if (!rm || !cat || !mmio || !dev) { SDE_ERROR("invalid kms\n"); return -EINVAL; } /* Clear, setup lists */ memset(rm, 0, sizeof(*rm)); mutex_init(&rm->rm_lock); INIT_LIST_HEAD(&rm->rsvps); for (type = 0; type < SDE_HW_BLK_MAX; type++) INIT_LIST_HEAD(&rm->hw_blks[type]); rm->dev = dev; if (IS_SDE_CTL_REV_100(cat->ctl_rev)) rm->topology_tbl = g_ctl_ver_1_top_table; else rm->topology_tbl = g_top_table; /* Some of the sub-blocks require an mdptop to be created */ rm->hw_mdp = sde_hw_mdptop_init(MDP_TOP, mmio, cat); if (IS_ERR_OR_NULL(rm->hw_mdp)) { rc = PTR_ERR(rm->hw_mdp); rm->hw_mdp = NULL; SDE_ERROR("failed: mdp hw not available\n"); goto fail; } /* Interrogate HW catalog and create tracking items for hw blocks */ for (i = 0; i < cat->mixer_count; i++) { struct sde_lm_cfg *lm = &cat->mixer[i]; if (lm->pingpong == PINGPONG_MAX) { SDE_ERROR("mixer %d without pingpong\n", lm->id); goto fail; } rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_LM, cat->mixer[i].id, &cat->mixer[i]); if (rc) { SDE_ERROR("failed: lm hw not available\n"); goto fail; } if (!rm->lm_max_width) { rm->lm_max_width = lm->sblk->maxwidth; } else if (rm->lm_max_width != lm->sblk->maxwidth) { /* * Don't expect to have hw where lm max widths differ. * If found, take the min. */ SDE_ERROR("unsupported: lm maxwidth differs\n"); if (rm->lm_max_width > lm->sblk->maxwidth) rm->lm_max_width = lm->sblk->maxwidth; } } rc = _sde_rm_hw_blk_create_new(rm, cat, mmio); if (!rc) return 0; fail: sde_rm_destroy(rm); Loading @@ -545,63 +558,18 @@ int sde_rm_init(struct sde_rm *rm, return rc; } /** * _sde_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets * proposed use case requirements, incl. hardwired dependent blocks like * pingpong, and dspp. * @rm: sde resource manager handle * @rsvp: reservation currently being created * @reqs: proposed use case requirements * @lm: proposed layer mixer, function checks if lm, and all other hardwired * blocks connected to the lm (pp, dspp) are available and appropriate * @dspp: output parameter, dspp block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @pp: output parameter, pingpong block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @primary_lm: if non-null, this function check if lm is compatible primary_lm * as well as satisfying all other requirements * @Return: true if lm matches all requirements, false otherwise */ static bool _sde_rm_check_lm_and_get_connected_blks( static bool _sde_rm_check_lm( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, struct sde_rm_requirements *reqs, const struct sde_lm_cfg *lm_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp, struct sde_rm_hw_blk *primary_lm) struct sde_rm_hw_blk **pp) { const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap; const struct sde_pingpong_cfg *pp_cfg; struct sde_rm_hw_iter iter; bool is_valid_dspp, is_valid_ds, ret; u32 display_pref, cwb_pref; *dspp = NULL; *ds = NULL; *pp = NULL; display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF); cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF); SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n", lm_cfg->id, lm_cfg->dspp, lm_cfg->ds, lm_cfg->pingpong, display_pref, cwb_pref); /* Check if this layer mixer is a peer of the proposed primary LM */ if (primary_lm) { const struct sde_lm_cfg *prim_lm_cfg = to_sde_hw_mixer(primary_lm->hw)->cap; if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) { SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id, prim_lm_cfg->id); return false; } } /* bypass rest of the checks if LM for primary display is found */ if (!display_pref) { is_valid_dspp = (lm_cfg->dspp != DSPP_MAX) ? true : false; is_valid_ds = (lm_cfg->ds != DS_MAX) ? true : false; Loading @@ -626,30 +594,20 @@ static bool _sde_rm_check_lm_and_get_connected_blks( lm_cfg->id, (bool)(RM_RQ_DSPP(reqs)), lm_cfg->dspp, (bool)(RM_RQ_DS(reqs)), lm_cfg->ds); return ret; } /** * If CWB is enabled and LM is not CWB supported * then return false. */ if (RM_RQ_CWB(reqs) && !cwb_pref) { SDE_DEBUG("fail: cwb supported lm not allocated\n"); return false; return ret; } } else if (!(reqs->hw_res.is_primary && display_pref)) { SDE_DEBUG( "display preference is not met. is_primary: %d display_pref: %d\n", (int)reqs->hw_res.is_primary, (int)display_pref); return false; return true; } /* Already reserved? */ if (RESERVED_BY_OTHER(lm, rsvp)) { SDE_DEBUG("lm %d already reserved\n", lm_cfg->id); return false; } static bool _sde_rm_reserve_dspp( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, const struct sde_lm_cfg *lm_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp) { struct sde_rm_hw_iter iter; if (lm_cfg->dspp != DSPP_MAX) { sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DSPP); Loading @@ -672,6 +630,18 @@ static bool _sde_rm_check_lm_and_get_connected_blks( return false; } } return true; } static bool _sde_rm_reserve_ds( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, const struct sde_lm_cfg *lm_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **ds) { struct sde_rm_hw_iter iter; if (lm_cfg->ds != DS_MAX) { sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DS); Loading @@ -694,6 +664,21 @@ static bool _sde_rm_check_lm_and_get_connected_blks( return false; } } return true; } static bool _sde_rm_reserve_pp( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, struct sde_rm_requirements *reqs, const struct sde_lm_cfg *lm_cfg, const struct sde_pingpong_cfg *pp_cfg, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp) { struct sde_rm_hw_iter iter; sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_PINGPONG); while (_sde_rm_get_hw_locked(rm, &iter)) { Loading Loading @@ -724,6 +709,107 @@ static bool _sde_rm_check_lm_and_get_connected_blks( *ds = NULL; return false; } return true; } /** * _sde_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets * proposed use case requirements, incl. hardwired dependent blocks like * pingpong, and dspp. * @rm: sde resource manager handle * @rsvp: reservation currently being created * @reqs: proposed use case requirements * @lm: proposed layer mixer, function checks if lm, and all other hardwired * blocks connected to the lm (pp, dspp) are available and appropriate * @dspp: output parameter, dspp block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @pp: output parameter, pingpong block attached to the layer mixer. * NULL if dspp was not available, or not matching requirements. * @primary_lm: if non-null, this function check if lm is compatible primary_lm * as well as satisfying all other requirements * @Return: true if lm matches all requirements, false otherwise */ static bool _sde_rm_check_lm_and_get_connected_blks( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, struct sde_rm_requirements *reqs, struct sde_rm_hw_blk *lm, struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp, struct sde_rm_hw_blk *primary_lm) { const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap; const struct sde_pingpong_cfg *pp_cfg; bool ret; u32 display_pref, cwb_pref; *dspp = NULL; *ds = NULL; *pp = NULL; display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF); cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF); SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n", lm_cfg->id, lm_cfg->dspp, lm_cfg->ds, lm_cfg->pingpong, display_pref, cwb_pref); /* Check if this layer mixer is a peer of the proposed primary LM */ if (primary_lm) { const struct sde_lm_cfg *prim_lm_cfg = to_sde_hw_mixer(primary_lm->hw)->cap; if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) { SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id, prim_lm_cfg->id); return false; } } /* bypass rest of the checks if LM for primary display is found */ if (!display_pref) { /* Check lm for valid requirements */ ret = _sde_rm_check_lm(rm, rsvp, reqs, lm_cfg, lm, dspp, ds, pp); if (!ret) return ret; /** * If CWB is enabled and LM is not CWB supported * then return false. */ if (RM_RQ_CWB(reqs) && !cwb_pref) { SDE_DEBUG("fail: cwb supported lm not allocated\n"); return false; } } else if (!(reqs->hw_res.is_primary && display_pref)) { SDE_DEBUG( "display preference is not met. is_primary: %d display_pref: %d\n", (int)reqs->hw_res.is_primary, (int)display_pref); return false; } /* Already reserved? */ if (RESERVED_BY_OTHER(lm, rsvp)) { SDE_DEBUG("lm %d already reserved\n", lm_cfg->id); return false; } /* Reserve dspp */ ret = _sde_rm_reserve_dspp(rm, rsvp, lm_cfg, lm, dspp); if (!ret) return ret; /* Reserve ds */ ret = _sde_rm_reserve_ds(rm, rsvp, lm_cfg, lm, ds); if (!ret) return ret; /* Reserve pp */ ret = _sde_rm_reserve_pp(rm, rsvp, reqs, lm_cfg, pp_cfg, lm, dspp, ds, pp); if (!ret) return ret; return true; } Loading