Loading drivers/gpu/drm/msm/sde/sde_crtc.c +3 −0 Original line number Diff line number Diff line Loading @@ -532,6 +532,9 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) ktime_to_ns(fevent->ts), atomic_read(&sde_crtc->frame_pending)); SDE_EVT32(DRMID(crtc), fevent->event, 0); /* don't propagate unexpected frame done events */ return; } else if (atomic_dec_return(&sde_crtc->frame_pending) == 0) { /* release bandwidth and other resources */ SDE_DEBUG("crtc%d ts:%lld last pending\n", Loading drivers/gpu/drm/msm/sde/sde_encoder.c +65 −0 Original line number Diff line number Diff line Loading @@ -1263,6 +1263,71 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc) } } int sde_encoder_helper_hw_release(struct sde_encoder_phys *phys_enc, struct drm_framebuffer *fb) { struct drm_encoder *drm_enc; struct sde_hw_mixer_cfg mixer; struct sde_rm_hw_iter lm_iter; bool lm_valid = false; if (!phys_enc || !phys_enc->parent) { SDE_ERROR("invalid encoder\n"); return -EINVAL; } drm_enc = phys_enc->parent; memset(&mixer, 0, sizeof(mixer)); /* reset associated CTL/LMs */ if (phys_enc->hw_ctl->ops.clear_pending_flush) phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); if (phys_enc->hw_ctl->ops.clear_all_blendstages) phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl); sde_rm_init_hw_iter(&lm_iter, drm_enc->base.id, SDE_HW_BLK_LM); while (sde_rm_get_hw(&phys_enc->sde_kms->rm, &lm_iter)) { struct sde_hw_mixer *hw_lm = (struct sde_hw_mixer *)lm_iter.hw; if (!hw_lm) continue; /* need to flush LM to remove it */ if (phys_enc->hw_ctl->ops.get_bitmask_mixer && phys_enc->hw_ctl->ops.update_pending_flush) phys_enc->hw_ctl->ops.update_pending_flush( phys_enc->hw_ctl, phys_enc->hw_ctl->ops.get_bitmask_mixer( phys_enc->hw_ctl, hw_lm->idx)); if (fb) { /* assume a single LM if targeting a frame buffer */ if (lm_valid) continue; mixer.out_height = fb->height; mixer.out_width = fb->width; if (hw_lm->ops.setup_mixer_out) hw_lm->ops.setup_mixer_out(hw_lm, &mixer); } lm_valid = true; /* only enable border color on LM */ if (phys_enc->hw_ctl->ops.setup_blendstage) phys_enc->hw_ctl->ops.setup_blendstage( phys_enc->hw_ctl, hw_lm->idx, 0, 0); } if (!lm_valid) { SDE_DEBUG_ENC(to_sde_encoder_virt(drm_enc), "lm not found\n"); return -EFAULT; } return 0; } static int _sde_encoder_status_show(struct seq_file *s, void *data) { struct sde_encoder_virt *sde_enc; Loading drivers/gpu/drm/msm/sde/sde_encoder_phys.h +19 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ enum sde_enc_split_role { /** * enum sde_enc_enable_state - current enabled state of the physical encoder * @SDE_ENC_DISABLING: Encoder transitioning to disable state * Events bounding transition are encoder type specific * @SDE_ENC_DISABLED: Encoder is disabled * @SDE_ENC_ENABLING: Encoder transitioning to enabled * Events bounding transition are encoder type specific Loading @@ -59,6 +61,7 @@ enum sde_enc_split_role { * to recover from a previous error */ enum sde_enc_enable_state { SDE_ENC_DISABLING, SDE_ENC_DISABLED, SDE_ENC_ENABLING, SDE_ENC_ENABLED, Loading Loading @@ -286,6 +289,8 @@ struct sde_encoder_phys_cmd { * @wb_dev: Pointer to writeback device * @start_time: Start time of writeback latest request * @end_time: End time of writeback latest request * @bo_disable: Buffer object(s) to use during the disabling state * @fb_disable: Frame buffer to use during the disabling state */ struct sde_encoder_phys_wb { struct sde_encoder_phys base; Loading @@ -305,6 +310,8 @@ struct sde_encoder_phys_wb { struct sde_wb_device *wb_dev; ktime_t start_time; ktime_t end_time; struct drm_gem_object *bo_disable[SDE_MAX_PLANES]; struct drm_framebuffer *fb_disable; }; /** Loading Loading @@ -406,6 +413,9 @@ static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode( { enum sde_rm_topology_name topology; if (!phys_enc || phys_enc->enable_state == SDE_ENC_DISABLING) return BLEND_3D_NONE; topology = sde_connector_get_topology_name(phys_enc->connector); if (phys_enc->split_role == ENC_ROLE_SOLO && topology == SDE_RM_TOPOLOGY_DUALPIPEMERGE && Loading @@ -426,4 +436,13 @@ void sde_encoder_helper_split_config( struct sde_encoder_phys *phys_enc, enum sde_intf interface); /** * sde_encoder_helper_hw_release - prepare for h/w reset during disable * @phys_enc: Pointer to physical encoder structure * @fb: Optional fb for specifying new mixer output resolution, may be NULL * Return: Zero on success */ int sde_encoder_helper_hw_release(struct sde_encoder_phys *phys_enc, struct drm_framebuffer *fb); #endif /* __sde_encoder_phys_H__ */ drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +160 −10 Original line number Diff line number Diff line Loading @@ -434,10 +434,10 @@ static int sde_encoder_phys_wb_atomic_check( } /** * sde_encoder_phys_wb_flush - flush hardware update * _sde_encoder_phys_wb_update_flush - flush hardware update * @phys_enc: Pointer to physical encoder */ static void sde_encoder_phys_wb_flush(struct sde_encoder_phys *phys_enc) static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc) { struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); struct sde_hw_wb *hw_wb = wb_enc->hw_wb; Loading @@ -461,7 +461,10 @@ static void sde_encoder_phys_wb_flush(struct sde_encoder_phys *phys_enc) if (hw_ctl->ops.update_pending_flush) hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask); SDE_DEBUG("Flushing CTL_ID %d, flush_mask %x, WB %d\n", if (hw_ctl->ops.get_pending_flush) flush_mask = hw_ctl->ops.get_pending_flush(hw_ctl); SDE_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n", hw_ctl->idx - CTL_0, flush_mask, hw_wb->idx - WB_0); } Loading @@ -484,7 +487,15 @@ static void sde_encoder_phys_wb_setup( memset(wb_roi, 0, sizeof(struct sde_rect)); if (phys_enc->enable_state == SDE_ENC_DISABLING) { fb = wb_enc->fb_disable; wb_roi->w = 0; wb_roi->h = 0; } else { fb = sde_wb_get_output_fb(wb_enc->wb_dev); sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi); } if (!fb) { SDE_DEBUG("no output framebuffer\n"); return; Loading @@ -493,7 +504,6 @@ static void sde_encoder_phys_wb_setup( SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id, fb->width, fb->height); sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi); if (wb_roi->w == 0 || wb_roi->h == 0) { wb_roi->x = 0; wb_roi->y = 0; Loading Loading @@ -564,6 +574,10 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count); /* don't notify upper layer for internal commit */ if (phys_enc->enable_state == SDE_ENC_DISABLING) goto complete; if (phys_enc->parent_ops.handle_frame_done) phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, SDE_ENCODER_FRAME_EVENT_DONE); Loading @@ -571,6 +585,7 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, phys_enc); complete: complete_all(&wb_enc->wbdone_complete); } Loading Loading @@ -700,8 +715,10 @@ static int sde_encoder_phys_wb_wait_for_commit_done( u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS); /* Return EWOULDBLOCK since we know the wait isn't necessary */ if (WARN_ON(phys_enc->enable_state != SDE_ENC_ENABLED)) if (phys_enc->enable_state == SDE_ENC_DISABLED) { SDE_ERROR("encoder already disabled\n"); return -EWOULDBLOCK; } SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count); Loading Loading @@ -784,7 +801,7 @@ static void sde_encoder_phys_wb_prepare_for_kickoff( /* set OT limit & enable traffic shaper */ sde_encoder_phys_wb_setup(phys_enc); sde_encoder_phys_wb_flush(phys_enc); _sde_encoder_phys_wb_update_flush(phys_enc); /* vote for iommu/clk/bus */ wb_enc->start_time = ktime_get(); Loading @@ -806,6 +823,111 @@ static void sde_encoder_phys_wb_handle_post_kickoff( SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc)); } /** * _sde_encoder_phys_wb_init_internal_fb - create fb for internal commit * @wb_enc: Pointer to writeback encoder * @pixel_format: DRM pixel format * @width: Desired fb width * @height: Desired fb height */ static int _sde_encoder_phys_wb_init_internal_fb( struct sde_encoder_phys_wb *wb_enc, uint32_t pixel_format, uint32_t width, uint32_t height) { struct drm_device *dev; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; uint32_t size; int nplanes, i, ret; if (!wb_enc || !wb_enc->base.parent || !wb_enc->base.sde_kms) { SDE_ERROR("invalid params\n"); return -EINVAL; } dev = wb_enc->base.sde_kms->dev; if (!dev) { SDE_ERROR("invalid dev\n"); return -EINVAL; } memset(&mode_cmd, 0, sizeof(mode_cmd)); mode_cmd.pixel_format = pixel_format; mode_cmd.width = width; mode_cmd.height = height; size = sde_format_get_framebuffer_size(pixel_format, mode_cmd.width, mode_cmd.height, 0, 0); if (!size) { SDE_DEBUG("not creating zero size buffer\n"); return -EINVAL; } /* allocate gem tracking object */ nplanes = drm_format_num_planes(pixel_format); if (nplanes > SDE_MAX_PLANES) { SDE_ERROR("requested format has too many planes\n"); return -EINVAL; } mutex_lock(&dev->struct_mutex); wb_enc->bo_disable[0] = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC); mutex_unlock(&dev->struct_mutex); if (IS_ERR_OR_NULL(wb_enc->bo_disable[0])) { ret = PTR_ERR(wb_enc->bo_disable[0]); wb_enc->bo_disable[0] = NULL; SDE_ERROR("failed to create bo, %d\n", ret); return ret; } for (i = 0; i < nplanes; ++i) { wb_enc->bo_disable[i] = wb_enc->bo_disable[0]; mode_cmd.pitches[i] = width * drm_format_plane_cpp(pixel_format, i); } fb = msm_framebuffer_init(dev, &mode_cmd, wb_enc->bo_disable); if (IS_ERR_OR_NULL(fb)) { ret = PTR_ERR(fb); drm_gem_object_unreference(wb_enc->bo_disable[0]); wb_enc->bo_disable[0] = NULL; SDE_ERROR("failed to init fb, %d\n", ret); return ret; } /* prepare the backing buffer now so that it's available later */ ret = msm_framebuffer_prepare(fb, wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE]); if (!ret) wb_enc->fb_disable = fb; return ret; } /** * _sde_encoder_phys_wb_destroy_internal_fb - deconstruct internal fb * @wb_enc: Pointer to writeback encoder */ static void _sde_encoder_phys_wb_destroy_internal_fb( struct sde_encoder_phys_wb *wb_enc) { if (!wb_enc) return; if (wb_enc->fb_disable) { drm_framebuffer_unregister_private(wb_enc->fb_disable); drm_framebuffer_remove(wb_enc->fb_disable); wb_enc->fb_disable = NULL; } if (wb_enc->bo_disable[0]) { drm_gem_object_unreference(wb_enc->bo_disable[0]); wb_enc->bo_disable[0] = NULL; } } /** * sde_encoder_phys_wb_enable - enable writeback encoder * @phys_enc: Pointer to physical encoder Loading Loading @@ -865,11 +987,23 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc) sde_encoder_phys_wb_wait_for_commit_done(phys_enc); } if (phys_enc->hw_cdm && phys_enc->hw_cdm->ops.disable) { SDE_DEBUG_DRIVER("[cdm_disable]\n"); phys_enc->hw_cdm->ops.disable(phys_enc->hw_cdm); if (!phys_enc->hw_ctl || !phys_enc->parent || !phys_enc->sde_kms || !wb_enc->fb_disable) { SDE_DEBUG("invalid enc, skipping extra commit\n"); goto exit; } /* reset h/w before final flush */ if (sde_encoder_helper_hw_release(phys_enc, wb_enc->fb_disable)) goto exit; phys_enc->enable_state = SDE_ENC_DISABLING; sde_encoder_phys_wb_prepare_for_kickoff(phys_enc); if (phys_enc->hw_ctl->ops.trigger_flush) phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl); sde_encoder_helper_trigger_start(phys_enc); sde_encoder_phys_wb_wait_for_commit_done(phys_enc); exit: phys_enc->enable_state = SDE_ENC_DISABLED; } Loading Loading @@ -971,6 +1105,8 @@ static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc) if (!phys_enc) return; _sde_encoder_phys_wb_destroy_internal_fb(wb_enc); kfree(wb_enc); } Loading Loading @@ -1009,8 +1145,15 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( SDE_DEBUG("\n"); if (!p || !p->parent) { SDE_ERROR("invalid params\n"); ret = -EINVAL; goto fail_alloc; } wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL); if (!wb_enc) { SDE_ERROR("failed to allocate wb enc\n"); ret = -ENOMEM; goto fail_alloc; } Loading Loading @@ -1078,6 +1221,13 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( phys_enc->enc_spinlock = p->enc_spinlock; INIT_LIST_HEAD(&wb_enc->irq_cb.list); /* create internal buffer for disable logic */ if (_sde_encoder_phys_wb_init_internal_fb(wb_enc, DRM_FORMAT_RGB888, 2, 1)) { SDE_ERROR("failed to init internal fb\n"); goto fail_wb_init; } SDE_DEBUG("Created sde_encoder_phys_wb for wb %d\n", wb_enc->hw_wb->idx - WB_0); Loading drivers/gpu/drm/msm/sde/sde_formats.c +20 −0 Original line number Diff line number Diff line Loading @@ -689,6 +689,26 @@ static int _sde_format_get_plane_sizes( return _sde_format_get_plane_sizes_linear(fmt, w, h, layout); } uint32_t sde_format_get_framebuffer_size( const uint32_t format, const uint32_t width, const uint32_t height, const uint64_t *modifiers, const uint32_t modifiers_len) { const struct sde_format *fmt; struct sde_hw_fmt_layout layout; fmt = sde_get_sde_format_ext(format, modifiers, modifiers_len); if (!fmt) return 0; if (_sde_format_get_plane_sizes(fmt, width, height, &layout)) layout.total_size = 0; return layout.total_size; } static int _sde_format_populate_addrs_ubwc( int mmu_id, struct drm_framebuffer *fb, Loading Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +3 −0 Original line number Diff line number Diff line Loading @@ -532,6 +532,9 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) ktime_to_ns(fevent->ts), atomic_read(&sde_crtc->frame_pending)); SDE_EVT32(DRMID(crtc), fevent->event, 0); /* don't propagate unexpected frame done events */ return; } else if (atomic_dec_return(&sde_crtc->frame_pending) == 0) { /* release bandwidth and other resources */ SDE_DEBUG("crtc%d ts:%lld last pending\n", Loading
drivers/gpu/drm/msm/sde/sde_encoder.c +65 −0 Original line number Diff line number Diff line Loading @@ -1263,6 +1263,71 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc) } } int sde_encoder_helper_hw_release(struct sde_encoder_phys *phys_enc, struct drm_framebuffer *fb) { struct drm_encoder *drm_enc; struct sde_hw_mixer_cfg mixer; struct sde_rm_hw_iter lm_iter; bool lm_valid = false; if (!phys_enc || !phys_enc->parent) { SDE_ERROR("invalid encoder\n"); return -EINVAL; } drm_enc = phys_enc->parent; memset(&mixer, 0, sizeof(mixer)); /* reset associated CTL/LMs */ if (phys_enc->hw_ctl->ops.clear_pending_flush) phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); if (phys_enc->hw_ctl->ops.clear_all_blendstages) phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl); sde_rm_init_hw_iter(&lm_iter, drm_enc->base.id, SDE_HW_BLK_LM); while (sde_rm_get_hw(&phys_enc->sde_kms->rm, &lm_iter)) { struct sde_hw_mixer *hw_lm = (struct sde_hw_mixer *)lm_iter.hw; if (!hw_lm) continue; /* need to flush LM to remove it */ if (phys_enc->hw_ctl->ops.get_bitmask_mixer && phys_enc->hw_ctl->ops.update_pending_flush) phys_enc->hw_ctl->ops.update_pending_flush( phys_enc->hw_ctl, phys_enc->hw_ctl->ops.get_bitmask_mixer( phys_enc->hw_ctl, hw_lm->idx)); if (fb) { /* assume a single LM if targeting a frame buffer */ if (lm_valid) continue; mixer.out_height = fb->height; mixer.out_width = fb->width; if (hw_lm->ops.setup_mixer_out) hw_lm->ops.setup_mixer_out(hw_lm, &mixer); } lm_valid = true; /* only enable border color on LM */ if (phys_enc->hw_ctl->ops.setup_blendstage) phys_enc->hw_ctl->ops.setup_blendstage( phys_enc->hw_ctl, hw_lm->idx, 0, 0); } if (!lm_valid) { SDE_DEBUG_ENC(to_sde_encoder_virt(drm_enc), "lm not found\n"); return -EFAULT; } return 0; } static int _sde_encoder_status_show(struct seq_file *s, void *data) { struct sde_encoder_virt *sde_enc; Loading
drivers/gpu/drm/msm/sde/sde_encoder_phys.h +19 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ enum sde_enc_split_role { /** * enum sde_enc_enable_state - current enabled state of the physical encoder * @SDE_ENC_DISABLING: Encoder transitioning to disable state * Events bounding transition are encoder type specific * @SDE_ENC_DISABLED: Encoder is disabled * @SDE_ENC_ENABLING: Encoder transitioning to enabled * Events bounding transition are encoder type specific Loading @@ -59,6 +61,7 @@ enum sde_enc_split_role { * to recover from a previous error */ enum sde_enc_enable_state { SDE_ENC_DISABLING, SDE_ENC_DISABLED, SDE_ENC_ENABLING, SDE_ENC_ENABLED, Loading Loading @@ -286,6 +289,8 @@ struct sde_encoder_phys_cmd { * @wb_dev: Pointer to writeback device * @start_time: Start time of writeback latest request * @end_time: End time of writeback latest request * @bo_disable: Buffer object(s) to use during the disabling state * @fb_disable: Frame buffer to use during the disabling state */ struct sde_encoder_phys_wb { struct sde_encoder_phys base; Loading @@ -305,6 +310,8 @@ struct sde_encoder_phys_wb { struct sde_wb_device *wb_dev; ktime_t start_time; ktime_t end_time; struct drm_gem_object *bo_disable[SDE_MAX_PLANES]; struct drm_framebuffer *fb_disable; }; /** Loading Loading @@ -406,6 +413,9 @@ static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode( { enum sde_rm_topology_name topology; if (!phys_enc || phys_enc->enable_state == SDE_ENC_DISABLING) return BLEND_3D_NONE; topology = sde_connector_get_topology_name(phys_enc->connector); if (phys_enc->split_role == ENC_ROLE_SOLO && topology == SDE_RM_TOPOLOGY_DUALPIPEMERGE && Loading @@ -426,4 +436,13 @@ void sde_encoder_helper_split_config( struct sde_encoder_phys *phys_enc, enum sde_intf interface); /** * sde_encoder_helper_hw_release - prepare for h/w reset during disable * @phys_enc: Pointer to physical encoder structure * @fb: Optional fb for specifying new mixer output resolution, may be NULL * Return: Zero on success */ int sde_encoder_helper_hw_release(struct sde_encoder_phys *phys_enc, struct drm_framebuffer *fb); #endif /* __sde_encoder_phys_H__ */
drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +160 −10 Original line number Diff line number Diff line Loading @@ -434,10 +434,10 @@ static int sde_encoder_phys_wb_atomic_check( } /** * sde_encoder_phys_wb_flush - flush hardware update * _sde_encoder_phys_wb_update_flush - flush hardware update * @phys_enc: Pointer to physical encoder */ static void sde_encoder_phys_wb_flush(struct sde_encoder_phys *phys_enc) static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc) { struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); struct sde_hw_wb *hw_wb = wb_enc->hw_wb; Loading @@ -461,7 +461,10 @@ static void sde_encoder_phys_wb_flush(struct sde_encoder_phys *phys_enc) if (hw_ctl->ops.update_pending_flush) hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask); SDE_DEBUG("Flushing CTL_ID %d, flush_mask %x, WB %d\n", if (hw_ctl->ops.get_pending_flush) flush_mask = hw_ctl->ops.get_pending_flush(hw_ctl); SDE_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n", hw_ctl->idx - CTL_0, flush_mask, hw_wb->idx - WB_0); } Loading @@ -484,7 +487,15 @@ static void sde_encoder_phys_wb_setup( memset(wb_roi, 0, sizeof(struct sde_rect)); if (phys_enc->enable_state == SDE_ENC_DISABLING) { fb = wb_enc->fb_disable; wb_roi->w = 0; wb_roi->h = 0; } else { fb = sde_wb_get_output_fb(wb_enc->wb_dev); sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi); } if (!fb) { SDE_DEBUG("no output framebuffer\n"); return; Loading @@ -493,7 +504,6 @@ static void sde_encoder_phys_wb_setup( SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id, fb->width, fb->height); sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi); if (wb_roi->w == 0 || wb_roi->h == 0) { wb_roi->x = 0; wb_roi->y = 0; Loading Loading @@ -564,6 +574,10 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count); /* don't notify upper layer for internal commit */ if (phys_enc->enable_state == SDE_ENC_DISABLING) goto complete; if (phys_enc->parent_ops.handle_frame_done) phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, SDE_ENCODER_FRAME_EVENT_DONE); Loading @@ -571,6 +585,7 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, phys_enc); complete: complete_all(&wb_enc->wbdone_complete); } Loading Loading @@ -700,8 +715,10 @@ static int sde_encoder_phys_wb_wait_for_commit_done( u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS); /* Return EWOULDBLOCK since we know the wait isn't necessary */ if (WARN_ON(phys_enc->enable_state != SDE_ENC_ENABLED)) if (phys_enc->enable_state == SDE_ENC_DISABLED) { SDE_ERROR("encoder already disabled\n"); return -EWOULDBLOCK; } SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count); Loading Loading @@ -784,7 +801,7 @@ static void sde_encoder_phys_wb_prepare_for_kickoff( /* set OT limit & enable traffic shaper */ sde_encoder_phys_wb_setup(phys_enc); sde_encoder_phys_wb_flush(phys_enc); _sde_encoder_phys_wb_update_flush(phys_enc); /* vote for iommu/clk/bus */ wb_enc->start_time = ktime_get(); Loading @@ -806,6 +823,111 @@ static void sde_encoder_phys_wb_handle_post_kickoff( SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc)); } /** * _sde_encoder_phys_wb_init_internal_fb - create fb for internal commit * @wb_enc: Pointer to writeback encoder * @pixel_format: DRM pixel format * @width: Desired fb width * @height: Desired fb height */ static int _sde_encoder_phys_wb_init_internal_fb( struct sde_encoder_phys_wb *wb_enc, uint32_t pixel_format, uint32_t width, uint32_t height) { struct drm_device *dev; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; uint32_t size; int nplanes, i, ret; if (!wb_enc || !wb_enc->base.parent || !wb_enc->base.sde_kms) { SDE_ERROR("invalid params\n"); return -EINVAL; } dev = wb_enc->base.sde_kms->dev; if (!dev) { SDE_ERROR("invalid dev\n"); return -EINVAL; } memset(&mode_cmd, 0, sizeof(mode_cmd)); mode_cmd.pixel_format = pixel_format; mode_cmd.width = width; mode_cmd.height = height; size = sde_format_get_framebuffer_size(pixel_format, mode_cmd.width, mode_cmd.height, 0, 0); if (!size) { SDE_DEBUG("not creating zero size buffer\n"); return -EINVAL; } /* allocate gem tracking object */ nplanes = drm_format_num_planes(pixel_format); if (nplanes > SDE_MAX_PLANES) { SDE_ERROR("requested format has too many planes\n"); return -EINVAL; } mutex_lock(&dev->struct_mutex); wb_enc->bo_disable[0] = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC); mutex_unlock(&dev->struct_mutex); if (IS_ERR_OR_NULL(wb_enc->bo_disable[0])) { ret = PTR_ERR(wb_enc->bo_disable[0]); wb_enc->bo_disable[0] = NULL; SDE_ERROR("failed to create bo, %d\n", ret); return ret; } for (i = 0; i < nplanes; ++i) { wb_enc->bo_disable[i] = wb_enc->bo_disable[0]; mode_cmd.pitches[i] = width * drm_format_plane_cpp(pixel_format, i); } fb = msm_framebuffer_init(dev, &mode_cmd, wb_enc->bo_disable); if (IS_ERR_OR_NULL(fb)) { ret = PTR_ERR(fb); drm_gem_object_unreference(wb_enc->bo_disable[0]); wb_enc->bo_disable[0] = NULL; SDE_ERROR("failed to init fb, %d\n", ret); return ret; } /* prepare the backing buffer now so that it's available later */ ret = msm_framebuffer_prepare(fb, wb_enc->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE]); if (!ret) wb_enc->fb_disable = fb; return ret; } /** * _sde_encoder_phys_wb_destroy_internal_fb - deconstruct internal fb * @wb_enc: Pointer to writeback encoder */ static void _sde_encoder_phys_wb_destroy_internal_fb( struct sde_encoder_phys_wb *wb_enc) { if (!wb_enc) return; if (wb_enc->fb_disable) { drm_framebuffer_unregister_private(wb_enc->fb_disable); drm_framebuffer_remove(wb_enc->fb_disable); wb_enc->fb_disable = NULL; } if (wb_enc->bo_disable[0]) { drm_gem_object_unreference(wb_enc->bo_disable[0]); wb_enc->bo_disable[0] = NULL; } } /** * sde_encoder_phys_wb_enable - enable writeback encoder * @phys_enc: Pointer to physical encoder Loading Loading @@ -865,11 +987,23 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc) sde_encoder_phys_wb_wait_for_commit_done(phys_enc); } if (phys_enc->hw_cdm && phys_enc->hw_cdm->ops.disable) { SDE_DEBUG_DRIVER("[cdm_disable]\n"); phys_enc->hw_cdm->ops.disable(phys_enc->hw_cdm); if (!phys_enc->hw_ctl || !phys_enc->parent || !phys_enc->sde_kms || !wb_enc->fb_disable) { SDE_DEBUG("invalid enc, skipping extra commit\n"); goto exit; } /* reset h/w before final flush */ if (sde_encoder_helper_hw_release(phys_enc, wb_enc->fb_disable)) goto exit; phys_enc->enable_state = SDE_ENC_DISABLING; sde_encoder_phys_wb_prepare_for_kickoff(phys_enc); if (phys_enc->hw_ctl->ops.trigger_flush) phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl); sde_encoder_helper_trigger_start(phys_enc); sde_encoder_phys_wb_wait_for_commit_done(phys_enc); exit: phys_enc->enable_state = SDE_ENC_DISABLED; } Loading Loading @@ -971,6 +1105,8 @@ static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc) if (!phys_enc) return; _sde_encoder_phys_wb_destroy_internal_fb(wb_enc); kfree(wb_enc); } Loading Loading @@ -1009,8 +1145,15 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( SDE_DEBUG("\n"); if (!p || !p->parent) { SDE_ERROR("invalid params\n"); ret = -EINVAL; goto fail_alloc; } wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL); if (!wb_enc) { SDE_ERROR("failed to allocate wb enc\n"); ret = -ENOMEM; goto fail_alloc; } Loading Loading @@ -1078,6 +1221,13 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( phys_enc->enc_spinlock = p->enc_spinlock; INIT_LIST_HEAD(&wb_enc->irq_cb.list); /* create internal buffer for disable logic */ if (_sde_encoder_phys_wb_init_internal_fb(wb_enc, DRM_FORMAT_RGB888, 2, 1)) { SDE_ERROR("failed to init internal fb\n"); goto fail_wb_init; } SDE_DEBUG("Created sde_encoder_phys_wb for wb %d\n", wb_enc->hw_wb->idx - WB_0); Loading
drivers/gpu/drm/msm/sde/sde_formats.c +20 −0 Original line number Diff line number Diff line Loading @@ -689,6 +689,26 @@ static int _sde_format_get_plane_sizes( return _sde_format_get_plane_sizes_linear(fmt, w, h, layout); } uint32_t sde_format_get_framebuffer_size( const uint32_t format, const uint32_t width, const uint32_t height, const uint64_t *modifiers, const uint32_t modifiers_len) { const struct sde_format *fmt; struct sde_hw_fmt_layout layout; fmt = sde_get_sde_format_ext(format, modifiers, modifiers_len); if (!fmt) return 0; if (_sde_format_get_plane_sizes(fmt, width, height, &layout)) layout.total_size = 0; return layout.total_size; } static int _sde_format_populate_addrs_ubwc( int mmu_id, struct drm_framebuffer *fb, Loading