Loading drivers/gpu/drm/msm/sde/sde_crtc.c +75 −28 Original line number Diff line number Diff line Loading @@ -864,56 +864,83 @@ static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc, lm_bounds = &crtc_state->lm_bounds[lm_idx]; lm_roi = &crtc_state->lm_roi[lm_idx]; if (!sde_kms_rect_is_null(crtc_roi)) { sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi); if (sde_kms_rect_is_null(lm_roi)) { SDE_ERROR("unsupported R/L only partial update\n"); return -EINVAL; } } else { if (sde_kms_rect_is_null(crtc_roi)) memcpy(lm_roi, lm_bounds, sizeof(*lm_roi)); } else sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi); SDE_DEBUG("%s: lm%d roi (%d,%d,%d,%d)\n", sde_crtc->name, lm_idx, lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h); /* if any dimension is zero, clear all dimensions for clarity */ if (sde_kms_rect_is_null(lm_roi)) memset(lm_roi, 0, sizeof(*lm_roi)); return 0; } static u32 _sde_crtc_get_displays_affected(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct sde_crtc *sde_crtc; struct sde_crtc_state *crtc_state; u32 disp_bitmask = 0; int i; sde_crtc = to_sde_crtc(crtc); crtc_state = to_sde_crtc_state(state); for (i = 0; i < sde_crtc->num_mixers; i++) { if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i])) disp_bitmask |= BIT(i); } SDE_DEBUG("affected displays 0x%x\n", disp_bitmask); return disp_bitmask; } static int _sde_crtc_check_rois_centered_and_symmetric(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct sde_crtc *sde_crtc; struct sde_crtc_state *crtc_state; const struct sde_rect *roi_prv, *roi_cur; int lm_idx; const struct sde_rect *roi[CRTC_DUAL_MIXERS]; if (!crtc || !state) return -EINVAL; sde_crtc = to_sde_crtc(crtc); crtc_state = to_sde_crtc_state(state); if (sde_crtc->num_mixers == 1) return 0; if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("%s: unsupported number of mixers: %d\n", sde_crtc->name, sde_crtc->num_mixers); return -EINVAL; } /* * On certain HW, ROIs must be centered on the split between LMs, * and be of equal width. */ roi[0] = &crtc_state->lm_roi[0]; roi[1] = &crtc_state->lm_roi[1]; sde_crtc = to_sde_crtc(crtc); crtc_state = to_sde_crtc_state(state); roi_prv = &crtc_state->lm_roi[0]; for (lm_idx = 1; lm_idx < sde_crtc->num_mixers; lm_idx++) { roi_cur = &crtc_state->lm_roi[lm_idx]; /* if one of the roi is null it's a left/right-only update */ if (sde_kms_rect_is_null(roi[0]) || sde_kms_rect_is_null(roi[1])) return 0; /* check lm rois are equal width & first roi ends at 2nd roi */ if (((roi_prv->x + roi_prv->w) != roi_cur->x) || (roi_prv->w != roi_cur->w)) { SDE_ERROR("%s: roi lm%d x %d w %d lm%d x %d w %d\n", sde_crtc->name, lm_idx-1, roi_prv->x, roi_prv->w, lm_idx, roi_cur->x, roi_cur->w); if (roi[0]->x + roi[0]->w != roi[1]->x || roi[0]->w != roi[1]->w) { SDE_ERROR( "%s: rois not centered and symmetric: roi0 x %d w %d roi1 x %d w %d\n", sde_crtc->name, roi[0]->x, roi[0]->w, roi[1]->x, roi[1]->w); return -EINVAL; } roi_prv = roi_cur; } return 0; } Loading Loading @@ -1188,13 +1215,21 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, */ static void _sde_crtc_blend_setup(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct sde_crtc_mixer *mixer = sde_crtc->mixers; struct sde_crtc *sde_crtc; struct sde_crtc_state *sde_crtc_state; struct sde_crtc_mixer *mixer; struct sde_hw_ctl *ctl; struct sde_hw_mixer *lm; int i; if (!crtc) return; sde_crtc = to_sde_crtc(crtc); sde_crtc_state = to_sde_crtc_state(crtc->state); mixer = sde_crtc->mixers; SDE_DEBUG("%s\n", sde_crtc->name); if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { Loading Loading @@ -1225,9 +1260,19 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc) _sde_crtc_blend_setup_mixer(crtc, sde_crtc, mixer); for (i = 0; i < sde_crtc->num_mixers; i++) { const struct sde_rect *lm_roi = &sde_crtc_state->lm_roi[i]; ctl = mixer[i].hw_ctl; lm = mixer[i].hw_lm; if (sde_kms_rect_is_null(lm_roi)) { SDE_DEBUG( "%s: lm%d leave ctl%d mask 0 since null roi\n", sde_crtc->name, lm->idx - LM_0, ctl->idx - CTL_0); continue; } lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); mixer[i].flush_mask |= ctl->ops.get_bitmask_mixer(ctl, Loading Loading @@ -1912,6 +1957,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc) * If so, it may delay and flush at an irq event (e.g. ppdone) */ params.inline_rotate_prefill = cstate->sbuf_prefill_line; params.affected_displays = _sde_crtc_get_displays_affected(crtc, crtc->state); sde_encoder_prepare_for_kickoff(encoder, ¶ms); } Loading drivers/gpu/drm/msm/sde/sde_crtc.h +3 −3 Original line number Diff line number Diff line Loading @@ -248,10 +248,10 @@ struct sde_crtc_respool { * @num_connectors: Number of associated drm connectors * @intf_mode : Interface mode of the primary connector * @rsc_client : sde rsc client when mode is valid * @lm_bounds : LM boundaries based on current mode full resolution, no ROI. * Origin top left of CRTC. * @crtc_roi : Current CRTC ROI. Possibly sub-rectangle of mode. * Origin top left of CRTC. * @lm_bounds : LM boundaries based on current mode full resolution, no ROI. * Origin top left of CRTC. * @lm_roi : Current LM ROI, possibly sub-rectangle of mode. * Origin top left of CRTC. * @user_roi_list : List of user's requested ROIs as from set property Loading @@ -274,8 +274,8 @@ struct sde_crtc_state { struct sde_rsc_client *rsc_client; bool rsc_update; struct sde_rect lm_bounds[CRTC_DUAL_MIXERS]; struct sde_rect crtc_roi; struct sde_rect lm_bounds[CRTC_DUAL_MIXERS]; struct sde_rect lm_roi[CRTC_DUAL_MIXERS]; struct msm_roi_list user_roi_list; Loading drivers/gpu/drm/msm/sde/sde_encoder.c +82 −4 Original line number Diff line number Diff line Loading @@ -1463,6 +1463,14 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc, return; } if (phys->split_role == ENC_ROLE_SKIP) { SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent), "skip flush pp%d ctl%d\n", phys->hw_pp->idx - PINGPONG_0, ctl->idx - CTL_0); return; } pending_kickoff_cnt = sde_encoder_phys_inc_pending(phys); if (extra_flush_bits && ctl->ops.update_pending_flush) Loading @@ -1484,11 +1492,21 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc, */ static inline void _sde_encoder_trigger_start(struct sde_encoder_phys *phys) { struct sde_hw_ctl *ctl; if (!phys) { SDE_ERROR("invalid encoder\n"); return; } ctl = phys->hw_ctl; if (phys->split_role == ENC_ROLE_SKIP) { SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent), "skip start pp%d ctl%d\n", phys->hw_pp->idx - PINGPONG_0, ctl->idx - CTL_0); return; } if (phys->ops.trigger_start && phys->enable_state != SDE_ENC_DISABLED) phys->ops.trigger_start(phys); } Loading Loading @@ -1620,9 +1638,13 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) topology = sde_connector_get_topology_name( phys->connector); /* don't wait on ppsplit slaves, they dont register irqs */ /* * don't wait on ppsplit slaves or skipped encoders because * they dont receive irqs */ if (!(topology == SDE_RM_TOPOLOGY_PPSPLIT && phys->split_role == ENC_ROLE_SLAVE)) phys->split_role == ENC_ROLE_SLAVE) && phys->split_role != ENC_ROLE_SKIP) set_bit(i, sde_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || Loading @@ -1645,6 +1667,60 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); } static void _sde_encoder_update_master(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys; int i, num_active_phys; bool master_assigned = false; if (!drm_enc || !params) return; sde_enc = to_sde_encoder_virt(drm_enc); if (sde_enc->num_phys_encs <= 1) return; /* count bits set */ num_active_phys = hweight_long(params->affected_displays); SDE_DEBUG_ENC(sde_enc, "affected_displays 0x%lx num_active_phys %d\n", params->affected_displays, num_active_phys); for (i = 0; i < sde_enc->num_phys_encs; i++) { enum sde_enc_split_role prv_role, new_role; bool active; phys = sde_enc->phys_encs[i]; if (!phys || !phys->ops.update_split_role) continue; active = test_bit(i, ¶ms->affected_displays); prv_role = phys->split_role; if (active && num_active_phys == 1) new_role = ENC_ROLE_SOLO; else if (active && !master_assigned) new_role = ENC_ROLE_MASTER; else if (active) new_role = ENC_ROLE_SLAVE; else new_role = ENC_ROLE_SKIP; phys->ops.update_split_role(phys, new_role); if (new_role == ENC_ROLE_SOLO || new_role == ENC_ROLE_MASTER) { sde_enc->cur_master = phys; master_assigned = true; } SDE_DEBUG_ENC(sde_enc, "pp %d role prv %d new %d active %d\n", phys->hw_pp->idx - PINGPONG_0, prv_role, phys->split_role, active); } } void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { Loading @@ -1654,8 +1730,8 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, unsigned int i; int rc; if (!drm_enc) { SDE_ERROR("invalid encoder\n"); if (!drm_enc || !params) { SDE_ERROR("invalid args\n"); return; } sde_enc = to_sde_encoder_virt(drm_enc); Loading Loading @@ -1685,6 +1761,8 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, } } _sde_encoder_update_master(drm_enc, params); if (sde_enc->cur_master && sde_enc->cur_master->connector) { rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector); if (rc) Loading drivers/gpu/drm/msm/sde/sde_encoder.h +3 −0 Original line number Diff line number Diff line Loading @@ -47,9 +47,12 @@ struct sde_encoder_hw_resources { /** * sde_encoder_kickoff_params - info encoder requires at kickoff * @inline_rotate_prefill: number of lines to prefill for inline rotation * @affected_displays: bitmask, bit set means the ROI of the commit lies within * the bounds of the physical display at the bit index */ struct sde_encoder_kickoff_params { u32 inline_rotate_prefill; unsigned long affected_displays; }; /** Loading drivers/gpu/drm/msm/sde/sde_encoder_phys.h +6 −2 Original line number Diff line number Diff line Loading @@ -41,11 +41,13 @@ * @ENC_ROLE_SOLO: This is the one and only panel. This encoder is master. * @ENC_ROLE_MASTER: This encoder is the master of a split panel config. * @ENC_ROLE_SLAVE: This encoder is not the master of a split panel config. * @ENC_ROLE_SKIP: This encoder is not participating in kickoffs */ enum sde_enc_split_role { ENC_ROLE_SOLO, ENC_ROLE_MASTER, ENC_ROLE_SLAVE ENC_ROLE_SLAVE, ENC_ROLE_SKIP }; /** Loading Loading @@ -118,6 +120,7 @@ struct sde_encoder_virt_ops { * @hw_reset: Issue HW recovery such as CTL reset and clear * SDE_ENC_ERR_NEEDS_HW_RESET state * @irq_control: Handler to enable/disable all the encoder IRQs * @update_split_role: Update the split role of the phys enc */ struct sde_encoder_phys_ops { Loading Loading @@ -152,6 +155,8 @@ struct sde_encoder_phys_ops { u32 (*collect_misr)(struct sde_encoder_phys *phys_enc); void (*hw_reset)(struct sde_encoder_phys *phys_enc); void (*irq_control)(struct sde_encoder_phys *phys, bool enable); void (*update_split_role)(struct sde_encoder_phys *phys_enc, enum sde_enc_split_role role); }; /** Loading Loading @@ -265,7 +270,6 @@ struct sde_encoder_phys_vid { */ struct sde_encoder_phys_cmd { struct sde_encoder_phys base; int intf_idx; int stream_sel; int irq_idx[INTR_IDX_MAX]; struct sde_irq_callback irq_cb[INTR_IDX_MAX]; Loading Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +75 −28 Original line number Diff line number Diff line Loading @@ -864,56 +864,83 @@ static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc, lm_bounds = &crtc_state->lm_bounds[lm_idx]; lm_roi = &crtc_state->lm_roi[lm_idx]; if (!sde_kms_rect_is_null(crtc_roi)) { sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi); if (sde_kms_rect_is_null(lm_roi)) { SDE_ERROR("unsupported R/L only partial update\n"); return -EINVAL; } } else { if (sde_kms_rect_is_null(crtc_roi)) memcpy(lm_roi, lm_bounds, sizeof(*lm_roi)); } else sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi); SDE_DEBUG("%s: lm%d roi (%d,%d,%d,%d)\n", sde_crtc->name, lm_idx, lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h); /* if any dimension is zero, clear all dimensions for clarity */ if (sde_kms_rect_is_null(lm_roi)) memset(lm_roi, 0, sizeof(*lm_roi)); return 0; } static u32 _sde_crtc_get_displays_affected(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct sde_crtc *sde_crtc; struct sde_crtc_state *crtc_state; u32 disp_bitmask = 0; int i; sde_crtc = to_sde_crtc(crtc); crtc_state = to_sde_crtc_state(state); for (i = 0; i < sde_crtc->num_mixers; i++) { if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i])) disp_bitmask |= BIT(i); } SDE_DEBUG("affected displays 0x%x\n", disp_bitmask); return disp_bitmask; } static int _sde_crtc_check_rois_centered_and_symmetric(struct drm_crtc *crtc, struct drm_crtc_state *state) { struct sde_crtc *sde_crtc; struct sde_crtc_state *crtc_state; const struct sde_rect *roi_prv, *roi_cur; int lm_idx; const struct sde_rect *roi[CRTC_DUAL_MIXERS]; if (!crtc || !state) return -EINVAL; sde_crtc = to_sde_crtc(crtc); crtc_state = to_sde_crtc_state(state); if (sde_crtc->num_mixers == 1) return 0; if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { SDE_ERROR("%s: unsupported number of mixers: %d\n", sde_crtc->name, sde_crtc->num_mixers); return -EINVAL; } /* * On certain HW, ROIs must be centered on the split between LMs, * and be of equal width. */ roi[0] = &crtc_state->lm_roi[0]; roi[1] = &crtc_state->lm_roi[1]; sde_crtc = to_sde_crtc(crtc); crtc_state = to_sde_crtc_state(state); roi_prv = &crtc_state->lm_roi[0]; for (lm_idx = 1; lm_idx < sde_crtc->num_mixers; lm_idx++) { roi_cur = &crtc_state->lm_roi[lm_idx]; /* if one of the roi is null it's a left/right-only update */ if (sde_kms_rect_is_null(roi[0]) || sde_kms_rect_is_null(roi[1])) return 0; /* check lm rois are equal width & first roi ends at 2nd roi */ if (((roi_prv->x + roi_prv->w) != roi_cur->x) || (roi_prv->w != roi_cur->w)) { SDE_ERROR("%s: roi lm%d x %d w %d lm%d x %d w %d\n", sde_crtc->name, lm_idx-1, roi_prv->x, roi_prv->w, lm_idx, roi_cur->x, roi_cur->w); if (roi[0]->x + roi[0]->w != roi[1]->x || roi[0]->w != roi[1]->w) { SDE_ERROR( "%s: rois not centered and symmetric: roi0 x %d w %d roi1 x %d w %d\n", sde_crtc->name, roi[0]->x, roi[0]->w, roi[1]->x, roi[1]->w); return -EINVAL; } roi_prv = roi_cur; } return 0; } Loading Loading @@ -1188,13 +1215,21 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, */ static void _sde_crtc_blend_setup(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); struct sde_crtc_mixer *mixer = sde_crtc->mixers; struct sde_crtc *sde_crtc; struct sde_crtc_state *sde_crtc_state; struct sde_crtc_mixer *mixer; struct sde_hw_ctl *ctl; struct sde_hw_mixer *lm; int i; if (!crtc) return; sde_crtc = to_sde_crtc(crtc); sde_crtc_state = to_sde_crtc_state(crtc->state); mixer = sde_crtc->mixers; SDE_DEBUG("%s\n", sde_crtc->name); if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { Loading Loading @@ -1225,9 +1260,19 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc) _sde_crtc_blend_setup_mixer(crtc, sde_crtc, mixer); for (i = 0; i < sde_crtc->num_mixers; i++) { const struct sde_rect *lm_roi = &sde_crtc_state->lm_roi[i]; ctl = mixer[i].hw_ctl; lm = mixer[i].hw_lm; if (sde_kms_rect_is_null(lm_roi)) { SDE_DEBUG( "%s: lm%d leave ctl%d mask 0 since null roi\n", sde_crtc->name, lm->idx - LM_0, ctl->idx - CTL_0); continue; } lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); mixer[i].flush_mask |= ctl->ops.get_bitmask_mixer(ctl, Loading Loading @@ -1912,6 +1957,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc) * If so, it may delay and flush at an irq event (e.g. ppdone) */ params.inline_rotate_prefill = cstate->sbuf_prefill_line; params.affected_displays = _sde_crtc_get_displays_affected(crtc, crtc->state); sde_encoder_prepare_for_kickoff(encoder, ¶ms); } Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +3 −3 Original line number Diff line number Diff line Loading @@ -248,10 +248,10 @@ struct sde_crtc_respool { * @num_connectors: Number of associated drm connectors * @intf_mode : Interface mode of the primary connector * @rsc_client : sde rsc client when mode is valid * @lm_bounds : LM boundaries based on current mode full resolution, no ROI. * Origin top left of CRTC. * @crtc_roi : Current CRTC ROI. Possibly sub-rectangle of mode. * Origin top left of CRTC. * @lm_bounds : LM boundaries based on current mode full resolution, no ROI. * Origin top left of CRTC. * @lm_roi : Current LM ROI, possibly sub-rectangle of mode. * Origin top left of CRTC. * @user_roi_list : List of user's requested ROIs as from set property Loading @@ -274,8 +274,8 @@ struct sde_crtc_state { struct sde_rsc_client *rsc_client; bool rsc_update; struct sde_rect lm_bounds[CRTC_DUAL_MIXERS]; struct sde_rect crtc_roi; struct sde_rect lm_bounds[CRTC_DUAL_MIXERS]; struct sde_rect lm_roi[CRTC_DUAL_MIXERS]; struct msm_roi_list user_roi_list; Loading
drivers/gpu/drm/msm/sde/sde_encoder.c +82 −4 Original line number Diff line number Diff line Loading @@ -1463,6 +1463,14 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc, return; } if (phys->split_role == ENC_ROLE_SKIP) { SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent), "skip flush pp%d ctl%d\n", phys->hw_pp->idx - PINGPONG_0, ctl->idx - CTL_0); return; } pending_kickoff_cnt = sde_encoder_phys_inc_pending(phys); if (extra_flush_bits && ctl->ops.update_pending_flush) Loading @@ -1484,11 +1492,21 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc, */ static inline void _sde_encoder_trigger_start(struct sde_encoder_phys *phys) { struct sde_hw_ctl *ctl; if (!phys) { SDE_ERROR("invalid encoder\n"); return; } ctl = phys->hw_ctl; if (phys->split_role == ENC_ROLE_SKIP) { SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent), "skip start pp%d ctl%d\n", phys->hw_pp->idx - PINGPONG_0, ctl->idx - CTL_0); return; } if (phys->ops.trigger_start && phys->enable_state != SDE_ENC_DISABLED) phys->ops.trigger_start(phys); } Loading Loading @@ -1620,9 +1638,13 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) topology = sde_connector_get_topology_name( phys->connector); /* don't wait on ppsplit slaves, they dont register irqs */ /* * don't wait on ppsplit slaves or skipped encoders because * they dont receive irqs */ if (!(topology == SDE_RM_TOPOLOGY_PPSPLIT && phys->split_role == ENC_ROLE_SLAVE)) phys->split_role == ENC_ROLE_SLAVE) && phys->split_role != ENC_ROLE_SKIP) set_bit(i, sde_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || Loading @@ -1645,6 +1667,60 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); } static void _sde_encoder_update_master(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { struct sde_encoder_virt *sde_enc; struct sde_encoder_phys *phys; int i, num_active_phys; bool master_assigned = false; if (!drm_enc || !params) return; sde_enc = to_sde_encoder_virt(drm_enc); if (sde_enc->num_phys_encs <= 1) return; /* count bits set */ num_active_phys = hweight_long(params->affected_displays); SDE_DEBUG_ENC(sde_enc, "affected_displays 0x%lx num_active_phys %d\n", params->affected_displays, num_active_phys); for (i = 0; i < sde_enc->num_phys_encs; i++) { enum sde_enc_split_role prv_role, new_role; bool active; phys = sde_enc->phys_encs[i]; if (!phys || !phys->ops.update_split_role) continue; active = test_bit(i, ¶ms->affected_displays); prv_role = phys->split_role; if (active && num_active_phys == 1) new_role = ENC_ROLE_SOLO; else if (active && !master_assigned) new_role = ENC_ROLE_MASTER; else if (active) new_role = ENC_ROLE_SLAVE; else new_role = ENC_ROLE_SKIP; phys->ops.update_split_role(phys, new_role); if (new_role == ENC_ROLE_SOLO || new_role == ENC_ROLE_MASTER) { sde_enc->cur_master = phys; master_assigned = true; } SDE_DEBUG_ENC(sde_enc, "pp %d role prv %d new %d active %d\n", phys->hw_pp->idx - PINGPONG_0, prv_role, phys->split_role, active); } } void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { Loading @@ -1654,8 +1730,8 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, unsigned int i; int rc; if (!drm_enc) { SDE_ERROR("invalid encoder\n"); if (!drm_enc || !params) { SDE_ERROR("invalid args\n"); return; } sde_enc = to_sde_encoder_virt(drm_enc); Loading Loading @@ -1685,6 +1761,8 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, } } _sde_encoder_update_master(drm_enc, params); if (sde_enc->cur_master && sde_enc->cur_master->connector) { rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector); if (rc) Loading
drivers/gpu/drm/msm/sde/sde_encoder.h +3 −0 Original line number Diff line number Diff line Loading @@ -47,9 +47,12 @@ struct sde_encoder_hw_resources { /** * sde_encoder_kickoff_params - info encoder requires at kickoff * @inline_rotate_prefill: number of lines to prefill for inline rotation * @affected_displays: bitmask, bit set means the ROI of the commit lies within * the bounds of the physical display at the bit index */ struct sde_encoder_kickoff_params { u32 inline_rotate_prefill; unsigned long affected_displays; }; /** Loading
drivers/gpu/drm/msm/sde/sde_encoder_phys.h +6 −2 Original line number Diff line number Diff line Loading @@ -41,11 +41,13 @@ * @ENC_ROLE_SOLO: This is the one and only panel. This encoder is master. * @ENC_ROLE_MASTER: This encoder is the master of a split panel config. * @ENC_ROLE_SLAVE: This encoder is not the master of a split panel config. * @ENC_ROLE_SKIP: This encoder is not participating in kickoffs */ enum sde_enc_split_role { ENC_ROLE_SOLO, ENC_ROLE_MASTER, ENC_ROLE_SLAVE ENC_ROLE_SLAVE, ENC_ROLE_SKIP }; /** Loading Loading @@ -118,6 +120,7 @@ struct sde_encoder_virt_ops { * @hw_reset: Issue HW recovery such as CTL reset and clear * SDE_ENC_ERR_NEEDS_HW_RESET state * @irq_control: Handler to enable/disable all the encoder IRQs * @update_split_role: Update the split role of the phys enc */ struct sde_encoder_phys_ops { Loading Loading @@ -152,6 +155,8 @@ struct sde_encoder_phys_ops { u32 (*collect_misr)(struct sde_encoder_phys *phys_enc); void (*hw_reset)(struct sde_encoder_phys *phys_enc); void (*irq_control)(struct sde_encoder_phys *phys, bool enable); void (*update_split_role)(struct sde_encoder_phys *phys_enc, enum sde_enc_split_role role); }; /** Loading Loading @@ -265,7 +270,6 @@ struct sde_encoder_phys_vid { */ struct sde_encoder_phys_cmd { struct sde_encoder_phys base; int intf_idx; int stream_sel; int irq_idx[INTR_IDX_MAX]; struct sde_irq_callback irq_cb[INTR_IDX_MAX]; Loading