Loading drivers/gpu/drm/msm/sde/sde_crtc.c +62 −11 Original line number Diff line number Diff line Loading @@ -1341,8 +1341,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, struct drm_display_mode *mode; int cnt = 0, rc = 0, mixer_width, i, z_pos; int left_crtc_zpos_cnt[SDE_STAGE_MAX] = {0}; int right_crtc_zpos_cnt[SDE_STAGE_MAX] = {0}; int left_zpos_cnt = 0, right_zpos_cnt = 0; if (!crtc) { SDE_ERROR("invalid crtc\n"); Loading Loading @@ -1396,11 +1395,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, } } /* assign mixer stages based on sorted zpos property */ sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); if (!sde_is_custom_client()) { int stage_old = pstates[0].stage; /* assign mixer stages based on sorted zpos property */ sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); z_pos = 0; for (i = 0; i < cnt; i++) { if (stage_old != pstates[i].stage) Loading @@ -1410,8 +1410,14 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, } } z_pos = -1; for (i = 0; i < cnt; i++) { /* reset counts at every new blend stage */ if (pstates[i].stage != z_pos) { left_zpos_cnt = 0; right_zpos_cnt = 0; z_pos = pstates[i].stage; } /* verify z_pos setting before using it */ if (z_pos >= SDE_STAGE_MAX - SDE_STAGE_0) { Loading @@ -1420,22 +1426,24 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, rc = -EINVAL; goto end; } else if (pstates[i].drm_pstate->crtc_x < mixer_width) { if (left_crtc_zpos_cnt[z_pos] == 2) { SDE_ERROR("> 2 plane @ stage%d on left\n", if (left_zpos_cnt == 2) { SDE_ERROR("> 2 planes @ stage %d on left\n", z_pos); rc = -EINVAL; goto end; } left_crtc_zpos_cnt[z_pos]++; left_zpos_cnt++; } else { if (right_crtc_zpos_cnt[z_pos] == 2) { SDE_ERROR("> 2 plane @ stage%d on right\n", if (right_zpos_cnt == 2) { SDE_ERROR("> 2 planes @ stage %d on right\n", z_pos); rc = -EINVAL; goto end; } right_crtc_zpos_cnt[z_pos]++; right_zpos_cnt++; } pstates[i].sde_pstate->stage = z_pos + SDE_STAGE_0; SDE_DEBUG("%s: zpos %d", sde_crtc->name, z_pos); } Loading @@ -1447,6 +1455,49 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, goto end; } /* * enforce pipe priority restrictions * use pstates sorted by stage to check planes on same stage * we assume that all pipes are in source split so its valid to compare * without taking into account left/right mixer placement */ for (i = 1; i < cnt; i++) { struct plane_state *prv_pstate, *cur_pstate; int32_t prv_x, cur_x, prv_id, cur_id; prv_pstate = &pstates[i - 1]; cur_pstate = &pstates[i]; if (prv_pstate->stage != cur_pstate->stage) continue; prv_x = prv_pstate->drm_pstate->crtc_x; cur_x = cur_pstate->drm_pstate->crtc_x; prv_id = prv_pstate->sde_pstate->base.plane->base.id; cur_id = cur_pstate->sde_pstate->base.plane->base.id; /* * Planes are enumerated in pipe-priority order such that planes * with lower drm_id must be left-most in a shared blend-stage * when using source split. */ if (cur_x > prv_x && cur_id < prv_id) { SDE_ERROR( "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n", cur_pstate->stage, cur_id, cur_x, prv_id, prv_x); rc = -EINVAL; goto end; } else if (cur_x < prv_x && cur_id > prv_id) { SDE_ERROR( "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n", cur_pstate->stage, prv_id, prv_x, cur_id, cur_x); rc = -EINVAL; goto end; } } end: return rc; } Loading drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +21 −4 Original line number Diff line number Diff line Loading @@ -281,23 +281,40 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) { struct sde_encoder_phys_vid *vid_enc = arg; struct sde_encoder_phys *phys_enc; struct sde_hw_ctl *hw_ctl; unsigned long lock_flags; int new_cnt; u32 flush_register = 0; int new_cnt = -1, old_cnt = -1; if (!vid_enc) return; phys_enc = &vid_enc->base; hw_ctl = phys_enc->hw_ctl; if (phys_enc->parent_ops.handle_vblank_virt) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, phys_enc); old_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); /* * only decrement the pending flush count if we've actually flushed * hardware. due to sw irq latency, vblank may have already happened * so we need to double-check with hw that it accepted the flush bits */ spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0, new_cnt); if (hw_ctl && hw_ctl->ops.get_flush_register) flush_register = hw_ctl->ops.get_flush_register(hw_ctl); if (flush_register == 0) new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0, old_cnt, new_cnt, flush_register); /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); } Loading drivers/gpu/drm/msm/sde/sde_hw_ctl.c +7 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,12 @@ static inline void sde_hw_ctl_trigger_flush(struct sde_hw_ctl *ctx) SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); } static inline u32 sde_hw_ctl_get_flush_register(struct sde_hw_ctl *ctx) { struct sde_hw_blk_reg_map *c = &ctx->hw; return SDE_REG_READ(c, CTL_FLUSH); } static inline uint32_t sde_hw_ctl_get_bitmask_sspp(struct sde_hw_ctl *ctx, enum sde_sspp sspp) Loading Loading @@ -459,6 +465,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, ops->update_pending_flush = sde_hw_ctl_update_pending_flush; ops->get_pending_flush = sde_hw_ctl_get_pending_flush; ops->trigger_flush = sde_hw_ctl_trigger_flush; ops->get_flush_register = sde_hw_ctl_get_flush_register; ops->trigger_start = sde_hw_ctl_trigger_start; ops->setup_intf_cfg = sde_hw_ctl_intf_cfg; ops->reset = sde_hw_ctl_reset_control; Loading drivers/gpu/drm/msm/sde/sde_hw_ctl.h +8 −1 Original line number Diff line number Diff line /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -93,6 +93,13 @@ struct sde_hw_ctl_ops { */ void (*trigger_flush)(struct sde_hw_ctl *ctx); /** * Read the value of the flush register * @ctx : ctl path ctx pointer * @Return: value of the ctl flush register. */ u32 (*get_flush_register)(struct sde_hw_ctl *ctx); /** * Setup ctl_path interface config * @ctx Loading drivers/gpu/drm/msm/sde/sde_kms.h +43 −0 Original line number Diff line number Diff line Loading @@ -370,6 +370,49 @@ void sde_kms_info_append_format(struct sde_kms_info *info, */ void sde_kms_info_stop(struct sde_kms_info *info); /** * sde_kms_rect_intersect - intersect two rectangles * @r1: first rectangle * @r2: scissor rectangle * @result: result rectangle, all 0's on no intersection found */ void sde_kms_rect_intersect(const struct sde_rect *r1, const struct sde_rect *r2, struct sde_rect *result); /** * sde_kms_rect_is_equal - compares two rects * @r1: rect value to compare * @r2: rect value to compare * * Returns 1 if the rects are same, 0 otherwise. */ static inline bool sde_kms_rect_is_equal(struct sde_rect *r1, struct sde_rect *r2) { if ((!r1 && r2) || (r1 && !r2)) return false; if (!r1 && !r2) return true; return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w && r1->h == r2->h; } /** * sde_kms_rect_is_null - returns true if the width or height of a rect is 0 * @rect: rectangle to check for zero size * @Return: True if width or height of rectangle is 0 */ static inline bool sde_kms_rect_is_null(const struct sde_rect *r) { if (!r) return true; return (!r->w || !r->h); } /** * Vblank enable/disable functions */ Loading Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +62 −11 Original line number Diff line number Diff line Loading @@ -1341,8 +1341,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, struct drm_display_mode *mode; int cnt = 0, rc = 0, mixer_width, i, z_pos; int left_crtc_zpos_cnt[SDE_STAGE_MAX] = {0}; int right_crtc_zpos_cnt[SDE_STAGE_MAX] = {0}; int left_zpos_cnt = 0, right_zpos_cnt = 0; if (!crtc) { SDE_ERROR("invalid crtc\n"); Loading Loading @@ -1396,11 +1395,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, } } /* assign mixer stages based on sorted zpos property */ sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); if (!sde_is_custom_client()) { int stage_old = pstates[0].stage; /* assign mixer stages based on sorted zpos property */ sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); z_pos = 0; for (i = 0; i < cnt; i++) { if (stage_old != pstates[i].stage) Loading @@ -1410,8 +1410,14 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, } } z_pos = -1; for (i = 0; i < cnt; i++) { /* reset counts at every new blend stage */ if (pstates[i].stage != z_pos) { left_zpos_cnt = 0; right_zpos_cnt = 0; z_pos = pstates[i].stage; } /* verify z_pos setting before using it */ if (z_pos >= SDE_STAGE_MAX - SDE_STAGE_0) { Loading @@ -1420,22 +1426,24 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, rc = -EINVAL; goto end; } else if (pstates[i].drm_pstate->crtc_x < mixer_width) { if (left_crtc_zpos_cnt[z_pos] == 2) { SDE_ERROR("> 2 plane @ stage%d on left\n", if (left_zpos_cnt == 2) { SDE_ERROR("> 2 planes @ stage %d on left\n", z_pos); rc = -EINVAL; goto end; } left_crtc_zpos_cnt[z_pos]++; left_zpos_cnt++; } else { if (right_crtc_zpos_cnt[z_pos] == 2) { SDE_ERROR("> 2 plane @ stage%d on right\n", if (right_zpos_cnt == 2) { SDE_ERROR("> 2 planes @ stage %d on right\n", z_pos); rc = -EINVAL; goto end; } right_crtc_zpos_cnt[z_pos]++; right_zpos_cnt++; } pstates[i].sde_pstate->stage = z_pos + SDE_STAGE_0; SDE_DEBUG("%s: zpos %d", sde_crtc->name, z_pos); } Loading @@ -1447,6 +1455,49 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, goto end; } /* * enforce pipe priority restrictions * use pstates sorted by stage to check planes on same stage * we assume that all pipes are in source split so its valid to compare * without taking into account left/right mixer placement */ for (i = 1; i < cnt; i++) { struct plane_state *prv_pstate, *cur_pstate; int32_t prv_x, cur_x, prv_id, cur_id; prv_pstate = &pstates[i - 1]; cur_pstate = &pstates[i]; if (prv_pstate->stage != cur_pstate->stage) continue; prv_x = prv_pstate->drm_pstate->crtc_x; cur_x = cur_pstate->drm_pstate->crtc_x; prv_id = prv_pstate->sde_pstate->base.plane->base.id; cur_id = cur_pstate->sde_pstate->base.plane->base.id; /* * Planes are enumerated in pipe-priority order such that planes * with lower drm_id must be left-most in a shared blend-stage * when using source split. */ if (cur_x > prv_x && cur_id < prv_id) { SDE_ERROR( "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n", cur_pstate->stage, cur_id, cur_x, prv_id, prv_x); rc = -EINVAL; goto end; } else if (cur_x < prv_x && cur_id > prv_id) { SDE_ERROR( "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n", cur_pstate->stage, prv_id, prv_x, cur_id, cur_x); rc = -EINVAL; goto end; } } end: return rc; } Loading
drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +21 −4 Original line number Diff line number Diff line Loading @@ -281,23 +281,40 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) { struct sde_encoder_phys_vid *vid_enc = arg; struct sde_encoder_phys *phys_enc; struct sde_hw_ctl *hw_ctl; unsigned long lock_flags; int new_cnt; u32 flush_register = 0; int new_cnt = -1, old_cnt = -1; if (!vid_enc) return; phys_enc = &vid_enc->base; hw_ctl = phys_enc->hw_ctl; if (phys_enc->parent_ops.handle_vblank_virt) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, phys_enc); old_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); /* * only decrement the pending flush count if we've actually flushed * hardware. due to sw irq latency, vblank may have already happened * so we need to double-check with hw that it accepted the flush bits */ spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0, new_cnt); if (hw_ctl && hw_ctl->ops.get_flush_register) flush_register = hw_ctl->ops.get_flush_register(hw_ctl); if (flush_register == 0) new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0, old_cnt, new_cnt, flush_register); /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); } Loading
drivers/gpu/drm/msm/sde/sde_hw_ctl.c +7 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,12 @@ static inline void sde_hw_ctl_trigger_flush(struct sde_hw_ctl *ctx) SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); } static inline u32 sde_hw_ctl_get_flush_register(struct sde_hw_ctl *ctx) { struct sde_hw_blk_reg_map *c = &ctx->hw; return SDE_REG_READ(c, CTL_FLUSH); } static inline uint32_t sde_hw_ctl_get_bitmask_sspp(struct sde_hw_ctl *ctx, enum sde_sspp sspp) Loading Loading @@ -459,6 +465,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, ops->update_pending_flush = sde_hw_ctl_update_pending_flush; ops->get_pending_flush = sde_hw_ctl_get_pending_flush; ops->trigger_flush = sde_hw_ctl_trigger_flush; ops->get_flush_register = sde_hw_ctl_get_flush_register; ops->trigger_start = sde_hw_ctl_trigger_start; ops->setup_intf_cfg = sde_hw_ctl_intf_cfg; ops->reset = sde_hw_ctl_reset_control; Loading
drivers/gpu/drm/msm/sde/sde_hw_ctl.h +8 −1 Original line number Diff line number Diff line /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -93,6 +93,13 @@ struct sde_hw_ctl_ops { */ void (*trigger_flush)(struct sde_hw_ctl *ctx); /** * Read the value of the flush register * @ctx : ctl path ctx pointer * @Return: value of the ctl flush register. */ u32 (*get_flush_register)(struct sde_hw_ctl *ctx); /** * Setup ctl_path interface config * @ctx Loading
drivers/gpu/drm/msm/sde/sde_kms.h +43 −0 Original line number Diff line number Diff line Loading @@ -370,6 +370,49 @@ void sde_kms_info_append_format(struct sde_kms_info *info, */ void sde_kms_info_stop(struct sde_kms_info *info); /** * sde_kms_rect_intersect - intersect two rectangles * @r1: first rectangle * @r2: scissor rectangle * @result: result rectangle, all 0's on no intersection found */ void sde_kms_rect_intersect(const struct sde_rect *r1, const struct sde_rect *r2, struct sde_rect *result); /** * sde_kms_rect_is_equal - compares two rects * @r1: rect value to compare * @r2: rect value to compare * * Returns 1 if the rects are same, 0 otherwise. */ static inline bool sde_kms_rect_is_equal(struct sde_rect *r1, struct sde_rect *r2) { if ((!r1 && r2) || (r1 && !r2)) return false; if (!r1 && !r2) return true; return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w && r1->h == r2->h; } /** * sde_kms_rect_is_null - returns true if the width or height of a rect is 0 * @rect: rectangle to check for zero size * @Return: True if width or height of rectangle is 0 */ static inline bool sde_kms_rect_is_null(const struct sde_rect *r) { if (!r) return true; return (!r->w || !r->h); } /** * Vblank enable/disable functions */ Loading