diff options
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1')
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 95 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 78 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 112 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c | 11 |
17 files changed, 203 insertions, 240 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index 5cda96875e03..09a49b59bb5b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -214,7 +214,6 @@ static int _dpu_core_perf_crtc_update_bus(struct dpu_kms *kms, */ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc) { - struct drm_crtc *tmp_crtc; struct dpu_crtc *dpu_crtc; struct dpu_crtc_state *dpu_cstate; struct dpu_kms *kms; @@ -233,22 +232,9 @@ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc) dpu_crtc = to_dpu_crtc(crtc); dpu_cstate = to_dpu_crtc_state(crtc->state); - /* only do this for command mode rt client */ - if (dpu_crtc_get_intf_mode(crtc) != INTF_MODE_CMD) + if (atomic_dec_return(&kms->bandwidth_ref) > 0) return; - /* - * If video interface present, cmd panel bandwidth cannot be - * released. - */ - if (dpu_crtc_get_intf_mode(crtc) == INTF_MODE_CMD) - drm_for_each_crtc(tmp_crtc, crtc->dev) { - if (tmp_crtc->enabled && - dpu_crtc_get_intf_mode(tmp_crtc) == - INTF_MODE_VIDEO) - return; - } - /* Release the bandwidth */ if (kms->perf.enable_bw_release) { trace_dpu_cmd_release_bw(crtc->base.id); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index b3417d56032d..ce59adff06aa 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -9,11 +9,13 @@ #include <linux/sort.h> #include <linux/debugfs.h> #include <linux/ktime.h> + #include <drm/drm_crtc.h> #include <drm/drm_flip_work.h> #include <drm/drm_mode.h> #include <drm/drm_probe_helper.h> #include <drm/drm_rect.h> +#include <drm/drm_vblank.h> #include "dpu_kms.h" #include "dpu_hw_lm.h" @@ -292,19 +294,6 @@ void dpu_crtc_vblank_callback(struct drm_crtc *crtc) trace_dpu_crtc_vblank_cb(DRMID(crtc)); } -static void dpu_crtc_release_bw_unlocked(struct drm_crtc *crtc) -{ - int ret = 0; - struct drm_modeset_acquire_ctx ctx; - - DRM_MODESET_LOCK_ALL_BEGIN(crtc->dev, ctx, 0, ret); - dpu_core_perf_crtc_release_bw(crtc); - DRM_MODESET_LOCK_ALL_END(ctx, ret); - if (ret) - DRM_ERROR("Failed to acquire modeset locks to release bw, %d\n", - ret); -} - static void dpu_crtc_frame_event_work(struct kthread_work *work) { struct dpu_crtc_frame_event *fevent = container_of(work, @@ -324,17 +313,12 @@ static void dpu_crtc_frame_event_work(struct kthread_work *work) | DPU_ENCODER_FRAME_EVENT_PANEL_DEAD)) { if (atomic_read(&dpu_crtc->frame_pending) < 1) { - /* this should not happen */ - DRM_ERROR("crtc%d ev:%u ts:%lld frame_pending:%d\n", - crtc->base.id, - fevent->event, - ktime_to_ns(fevent->ts), - atomic_read(&dpu_crtc->frame_pending)); + /* ignore vblank when not pending */ } else if (atomic_dec_return(&dpu_crtc->frame_pending) == 0) { /* release bandwidth and other resources */ trace_dpu_crtc_frame_event_done(DRMID(crtc), fevent->event); - dpu_crtc_release_bw_unlocked(crtc); + dpu_core_perf_crtc_release_bw(crtc); } else { trace_dpu_crtc_frame_event_more_pending(DRMID(crtc), fevent->event); @@ -407,13 +391,8 @@ static void dpu_crtc_frame_event_cb(void *data, u32 event) kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); } -void dpu_crtc_complete_commit(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) +void dpu_crtc_complete_commit(struct drm_crtc *crtc) { - if (!crtc || !crtc->state) { - DPU_ERROR("invalid crtc\n"); - return; - } trace_dpu_crtc_complete_commit(DRMID(crtc)); } @@ -623,13 +602,12 @@ static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) return rc; } -void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async) +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) { struct drm_encoder *encoder; struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); struct dpu_crtc_state *cstate = to_dpu_crtc_state(crtc->state); - int ret; /* * If no mixers has been allocated in dpu_crtc_atomic_check(), @@ -647,37 +625,22 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async) */ drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) - dpu_encoder_prepare_for_kickoff(encoder, async); - - if (!async) { - /* wait for frame_event_done completion */ - DPU_ATRACE_BEGIN("wait_for_frame_done_event"); - ret = _dpu_crtc_wait_for_frame_done(crtc); - DPU_ATRACE_END("wait_for_frame_done_event"); - if (ret) { - DPU_ERROR("crtc%d wait for frame done failed;frame_pending%d\n", - crtc->base.id, - atomic_read(&dpu_crtc->frame_pending)); - goto end; - } + dpu_encoder_prepare_for_kickoff(encoder); - if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { - /* acquire bandwidth and other resources */ - DPU_DEBUG("crtc%d first commit\n", crtc->base.id); - } else - DPU_DEBUG("crtc%d commit\n", crtc->base.id); + if (atomic_inc_return(&dpu_crtc->frame_pending) == 1) { + /* acquire bandwidth and other resources */ + DPU_DEBUG("crtc%d first commit\n", crtc->base.id); + } else + DPU_DEBUG("crtc%d commit\n", crtc->base.id); - dpu_crtc->play_count++; - } + dpu_crtc->play_count++; dpu_vbif_clear_errors(dpu_kms); drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) - dpu_encoder_kickoff(encoder, async); + dpu_encoder_kickoff(encoder); -end: - if (!async) - reinit_completion(&dpu_crtc->frame_done_comp); + reinit_completion(&dpu_crtc->frame_done_comp); DPU_ATRACE_END("crtc_commit"); } @@ -729,6 +692,7 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, struct drm_encoder *encoder; struct msm_drm_private *priv; unsigned long flags; + bool release_bandwidth = false; if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { DPU_ERROR("invalid crtc\n"); @@ -745,8 +709,15 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, drm_crtc_vblank_off(crtc); drm_for_each_encoder_mask(encoder, crtc->dev, - old_crtc_state->encoder_mask) + old_crtc_state->encoder_mask) { + /* in video mode, we hold an extra bandwidth reference + * as we cannot drop bandwidth at frame-done if any + * crtc is being used in video mode. + */ + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) + release_bandwidth = true; dpu_encoder_assign_crtc(encoder, NULL); + } /* wait for frame_event_done completion */ if (_dpu_crtc_wait_for_frame_done(crtc)) @@ -760,7 +731,8 @@ static void dpu_crtc_disable(struct drm_crtc *crtc, if (atomic_read(&dpu_crtc->frame_pending)) { trace_dpu_crtc_disable_frame_pending(DRMID(crtc), atomic_read(&dpu_crtc->frame_pending)); - dpu_core_perf_crtc_release_bw(crtc); + if (release_bandwidth) + dpu_core_perf_crtc_release_bw(crtc); atomic_set(&dpu_crtc->frame_pending, 0); } @@ -792,6 +764,7 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, struct dpu_crtc *dpu_crtc; struct drm_encoder *encoder; struct msm_drm_private *priv; + bool request_bandwidth; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { DPU_ERROR("invalid crtc\n"); @@ -804,9 +777,19 @@ static void dpu_crtc_enable(struct drm_crtc *crtc, DRM_DEBUG_KMS("crtc%d\n", crtc->base.id); dpu_crtc = to_dpu_crtc(crtc); - drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { + /* in video mode, we hold an extra bandwidth reference + * as we cannot drop bandwidth at frame-done if any + * crtc is being used in video mode. + */ + if (dpu_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) + request_bandwidth = true; dpu_encoder_register_frame_event_callback(encoder, dpu_crtc_frame_event_cb, (void *)crtc); + } + + if (request_bandwidth) + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); trace_dpu_crtc_enable(DRMID(crtc), true, dpu_crtc); dpu_crtc->enabled = true; @@ -981,6 +964,8 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, } } + atomic_inc(&_dpu_crtc_get_kms(crtc)->bandwidth_ref); + rc = dpu_core_perf_crtc_check(crtc, state); if (rc) { DPU_ERROR("crtc%d failed performance check %d\n", diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 5181f079a6a1..5174e86124cc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -238,17 +238,14 @@ void dpu_crtc_vblank_callback(struct drm_crtc *crtc); /** * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc * @crtc: Pointer to drm crtc object - * @async: true if the commit is asynchronous, false otherwise */ -void dpu_crtc_commit_kickoff(struct drm_crtc *crtc, bool async); +void dpu_crtc_commit_kickoff(struct drm_crtc *crtc); /** * dpu_crtc_complete_commit - callback signalling completion of current commit * @crtc: Pointer to drm crtc object - * @old_state: Pointer to drm crtc old state object */ -void dpu_crtc_complete_commit(struct drm_crtc *crtc, - struct drm_crtc_state *old_state); +void dpu_crtc_complete_commit(struct drm_crtc *crtc); /** * dpu_crtc_init - create a new crtc object diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 0e2f74163a16..d82ea994063f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -6,14 +6,16 @@ */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ -#include <linux/kthread.h> #include <linux/debugfs.h> +#include <linux/kthread.h> #include <linux/seq_file.h> -#include "msm_drv.h" -#include "dpu_kms.h" #include <drm/drm_crtc.h> +#include <drm/drm_file.h> #include <drm/drm_probe_helper.h> + +#include "msm_drv.h" +#include "dpu_kms.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_intf.h" @@ -1421,19 +1423,12 @@ static void dpu_encoder_off_work(struct work_struct *work) * extra_flush_bits: Additional bit mask to include in flush trigger */ static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc, - struct dpu_encoder_phys *phys, uint32_t extra_flush_bits, - bool async) + struct dpu_encoder_phys *phys, uint32_t extra_flush_bits) { struct dpu_hw_ctl *ctl; int pending_kickoff_cnt; u32 ret = UINT_MAX; - if (!drm_enc || !phys) { - DPU_ERROR("invalid argument(s), drm_enc %d, phys_enc %d\n", - drm_enc != 0, phys != 0); - return; - } - if (!phys->hw_pp) { DPU_ERROR("invalid pingpong hw\n"); return; @@ -1445,10 +1440,7 @@ static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc, return; } - if (!async) - pending_kickoff_cnt = dpu_encoder_phys_inc_pending(phys); - else - pending_kickoff_cnt = atomic_read(&phys->pending_kickoff_cnt); + pending_kickoff_cnt = dpu_encoder_phys_inc_pending(phys); if (extra_flush_bits && ctl->ops.update_pending_flush) ctl->ops.update_pending_flush(ctl, extra_flush_bits); @@ -1559,18 +1551,12 @@ static void dpu_encoder_helper_hw_reset(struct dpu_encoder_phys *phys_enc) * a time. * dpu_enc: Pointer to virtual encoder structure */ -static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc, - bool async) +static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc) { struct dpu_hw_ctl *ctl; uint32_t i, pending_flush; unsigned long lock_flags; - if (!dpu_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - pending_flush = 0x0; /* update pending counts and trigger kickoff ctl flush atomically */ @@ -1592,13 +1578,12 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc, * for async commits. So don't set this for async, since it'll * roll over to the next commit. */ - if (!async && phys->split_role != ENC_ROLE_SLAVE) + if (phys->split_role != ENC_ROLE_SLAVE) set_bit(i, dpu_enc->frame_busy_mask); if (!phys->ops.needs_single_flush || !phys->ops.needs_single_flush(phys)) - _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0, - async); + _dpu_encoder_trigger_flush(&dpu_enc->base, phys, 0x0); else if (ctl->ops.get_pending_flush) pending_flush |= ctl->ops.get_pending_flush(ctl); } @@ -1608,7 +1593,7 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc, _dpu_encoder_trigger_flush( &dpu_enc->base, dpu_enc->cur_master, - pending_flush, async); + pending_flush); } _dpu_encoder_trigger_start(dpu_enc->cur_master); @@ -1695,8 +1680,7 @@ static u32 _dpu_encoder_calculate_linetime(struct dpu_encoder_virt *dpu_enc, return line_time; } -static int _dpu_encoder_wakeup_time(struct drm_encoder *drm_enc, - ktime_t *wakeup_time) +int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time) { struct drm_display_mode *mode; struct dpu_encoder_virt *dpu_enc; @@ -1783,7 +1767,7 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) return; } - if (_dpu_encoder_wakeup_time(&dpu_enc->base, &wakeup_time)) + if (dpu_encoder_vsync_time(&dpu_enc->base, &wakeup_time)) return; trace_dpu_enc_vsync_event_work(DRMID(&dpu_enc->base), wakeup_time); @@ -1791,17 +1775,13 @@ static void dpu_encoder_vsync_event_work_handler(struct kthread_work *work) nsecs_to_jiffies(ktime_to_ns(wakeup_time))); } -void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async) +void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; struct dpu_encoder_phys *phys; bool needs_hw_reset = false; unsigned int i; - if (!drm_enc) { - DPU_ERROR("invalid args\n"); - return; - } dpu_enc = to_dpu_encoder_virt(drm_enc); trace_dpu_enc_prepare_kickoff(DRMID(drm_enc)); @@ -1830,39 +1810,28 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, bool async) } } -void dpu_encoder_kickoff(struct drm_encoder *drm_enc, bool async) +void dpu_encoder_kickoff(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; struct dpu_encoder_phys *phys; ktime_t wakeup_time; + unsigned long timeout_ms; unsigned int i; - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } DPU_ATRACE_BEGIN("encoder_kickoff"); dpu_enc = to_dpu_encoder_virt(drm_enc); trace_dpu_enc_kickoff(DRMID(drm_enc)); - /* - * Asynchronous frames don't handle FRAME_DONE events. As such, they - * shouldn't enable the frame_done watchdog since it will always time - * out. - */ - if (!async) { - unsigned long timeout_ms; - timeout_ms = DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES * 1000 / + timeout_ms = DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES * 1000 / drm_mode_vrefresh(&drm_enc->crtc->state->adjusted_mode); - atomic_set(&dpu_enc->frame_done_timeout_ms, timeout_ms); - mod_timer(&dpu_enc->frame_done_timer, - jiffies + msecs_to_jiffies(timeout_ms)); - } + atomic_set(&dpu_enc->frame_done_timeout_ms, timeout_ms); + mod_timer(&dpu_enc->frame_done_timer, + jiffies + msecs_to_jiffies(timeout_ms)); /* All phys encs are ready to go, trigger the kickoff */ - _dpu_encoder_kickoff_phys(dpu_enc, async); + _dpu_encoder_kickoff_phys(dpu_enc); /* allow phys encs to handle any post-kickoff business */ for (i = 0; i < dpu_enc->num_phys_encs; i++) { @@ -1872,7 +1841,7 @@ void dpu_encoder_kickoff(struct drm_encoder *drm_enc, bool async) } if (dpu_enc->disp_info.intf_type == DRM_MODE_ENCODER_DSI && - !_dpu_encoder_wakeup_time(drm_enc, &wakeup_time)) { + !dpu_encoder_vsync_time(drm_enc, &wakeup_time)) { trace_dpu_enc_early_kickoff(DRMID(drm_enc), ktime_to_ms(wakeup_time)); mod_timer(&dpu_enc->vsync_event_timer, @@ -2221,8 +2190,6 @@ int dpu_encoder_setup(struct drm_device *dev, struct drm_encoder *enc, if (ret) goto fail; - spin_lock_init(&dpu_enc->enc_spinlock); - atomic_set(&dpu_enc->frame_done_timeout_ms, 0); timer_setup(&dpu_enc->frame_done_timer, dpu_encoder_frame_done_timeout, 0); @@ -2276,6 +2243,7 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs); + spin_lock_init(&dpu_enc->enc_spinlock); dpu_enc->enabled = false; return &dpu_enc->base; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index a8bf1147fc56..b4913465e602 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -68,9 +68,8 @@ void dpu_encoder_register_frame_event_callback(struct drm_encoder *encoder, * Immediately: if no previous commit is outstanding. * Delayed: Block until next trigger can be issued. * @encoder: encoder pointer - * @async: true if this is an asynchronous commit */ -void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder, bool async); +void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder); /** * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous @@ -83,9 +82,13 @@ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *encoder); * dpu_encoder_kickoff - trigger a double buffer flip of the ctl path * (i.e. ctl flush and start) immediately. * @encoder: encoder pointer - * @async: true if this is an asynchronous commit */ -void dpu_encoder_kickoff(struct drm_encoder *encoder, bool async); +void dpu_encoder_kickoff(struct drm_encoder *encoder); + +/** + * dpu_encoder_wakeup_time - get the time of the next vsync + */ +int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time); /** * dpu_encoder_wait_for_event - Waits for encoder events diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index 1b3ab909f367..2923b63d95fe 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -720,9 +720,6 @@ static int dpu_encoder_phys_cmd_wait_for_vblank( static void dpu_encoder_phys_cmd_handle_post_kickoff( struct dpu_encoder_phys *phys_enc) { - if (!phys_enc) - return; - /** * re-enable external TE, either for the first time after enabling * or if disabled for Autorefresh diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index 5055a5eec869..b9c84fb4d4a1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -324,6 +324,10 @@ static void dpu_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); + + phys_enc->parent_ops->handle_frame_done(phys_enc->parent, phys_enc, + DPU_ENCODER_FRAME_EVENT_DONE); + DPU_ATRACE_END("vblank_irq"); } @@ -483,8 +487,8 @@ static void dpu_encoder_phys_vid_get_hw_resources( hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_VIDEO; } -static int _dpu_encoder_phys_vid_wait_for_vblank( - struct dpu_encoder_phys *phys_enc, bool notify) +static int dpu_encoder_phys_vid_wait_for_vblank( + struct dpu_encoder_phys *phys_enc) { struct dpu_encoder_wait_info wait_info; int ret; @@ -499,10 +503,6 @@ static int _dpu_encoder_phys_vid_wait_for_vblank( wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; if (!dpu_encoder_phys_vid_is_master(phys_enc)) { - if (notify && phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done( - phys_enc->parent, phys_enc, - DPU_ENCODER_FRAME_EVENT_DONE); return 0; } @@ -512,18 +512,29 @@ static int _dpu_encoder_phys_vid_wait_for_vblank( if (ret == -ETIMEDOUT) { dpu_encoder_helper_report_irq_timeout(phys_enc, INTR_IDX_VSYNC); - } else if (!ret && notify && phys_enc->parent_ops->handle_frame_done) - phys_enc->parent_ops->handle_frame_done( - phys_enc->parent, phys_enc, - DPU_ENCODER_FRAME_EVENT_DONE); + } return ret; } -static int dpu_encoder_phys_vid_wait_for_vblank( +static int dpu_encoder_phys_vid_wait_for_commit_done( struct dpu_encoder_phys *phys_enc) { - return _dpu_encoder_phys_vid_wait_for_vblank(phys_enc, true); + struct dpu_hw_ctl *hw_ctl = phys_enc->hw_ctl; + int ret; + + if (!hw_ctl) + return 0; + + ret = wait_event_timeout(phys_enc->pending_kickoff_wq, + (hw_ctl->ops.get_flush_register(hw_ctl) == 0), + msecs_to_jiffies(50)); + if (ret <= 0) { + DPU_ERROR("vblank timeout\n"); + return -ETIMEDOUT; + } + + return 0; } static void dpu_encoder_phys_vid_prepare_for_kickoff( @@ -595,7 +606,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) * scanout buffer) don't latch properly.. */ if (dpu_encoder_phys_vid_is_master(phys_enc)) { - ret = _dpu_encoder_phys_vid_wait_for_vblank(phys_enc, false); + ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); if (ret) { atomic_set(&phys_enc->pending_kickoff_cnt, 0); DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", @@ -612,11 +623,6 @@ static void dpu_encoder_phys_vid_handle_post_kickoff( { unsigned long lock_flags; - if (!phys_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - /* * Video mode must flush CTL before enabling timing engine * Video encoders need to turn on their interfaces now @@ -681,7 +687,7 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->destroy = dpu_encoder_phys_vid_destroy; ops->get_hw_resources = dpu_encoder_phys_vid_get_hw_resources; ops->control_vblank_irq = dpu_encoder_phys_vid_control_vblank_irq; - ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_vblank; + ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_commit_done; ops->wait_for_vblank = dpu_encoder_phys_vid_wait_for_vblank; ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_vblank; ops->irq_control = dpu_encoder_phys_vid_irq_control; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 90f439812088..ec76b8687a98 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -9,7 +9,6 @@ #include <linux/bug.h> #include <linux/bitmap.h> #include <linux/err.h> -#include <drm/drmP.h> /** * Max hardware block count: For ex: max 12 SSPP pipes or diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index b2f7b0e886b5..179e8d52cadb 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -102,9 +102,6 @@ static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx, static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) { - if (!ctx) - return 0x0; - return ctx->pending_flush_mask; } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c index 71b6987bff1e..27fbeb504362 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c @@ -7,6 +7,7 @@ #include <linux/clk/clk-conf.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/of.h> #include <drm/drm_print.h> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h index 09083e9f06bb..e6b5c772fa3b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h @@ -5,7 +5,6 @@ #ifndef __DPU_IO_UTIL_H__ #define __DPU_IO_UTIL_H__ -#include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/types.h> @@ -14,12 +13,6 @@ #define DEV_WARN(fmt, args...) pr_warn(fmt, ##args) #define DEV_ERR(fmt, args...) pr_err(fmt, ##args) -struct dss_gpio { - unsigned int gpio; - unsigned int value; - char gpio_name[32]; -}; - enum dss_clk_type { DSS_CLK_AHB, /* no set rate. rate controlled through rpm */ DSS_CLK_PCLK, @@ -34,8 +27,6 @@ struct dss_clk { }; struct dss_module_power { - unsigned int num_gpio; - struct dss_gpio *gpio_config; unsigned int num_clk; struct dss_clk *clk_config; }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index bb9d44e7bd26..58b0485dc375 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -7,10 +7,12 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ -#include <drm/drm_crtc.h> #include <linux/debugfs.h> -#include <linux/of_irq.h> #include <linux/dma-buf.h> +#include <linux/of_irq.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_file.h> #include "msm_drv.h" #include "msm_mmu.h" @@ -248,6 +250,32 @@ static void dpu_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) dpu_crtc_vblank(crtc, false); } +static void dpu_kms_enable_commit(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + pm_runtime_get_sync(&dpu_kms->pdev->dev); +} + +static void dpu_kms_disable_commit(struct msm_kms *kms) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + pm_runtime_put_sync(&dpu_kms->pdev->dev); +} + +static ktime_t dpu_kms_vsync_time(struct msm_kms *kms, struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + + drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask) { + ktime_t vsync_time; + + if (dpu_encoder_vsync_time(encoder, &vsync_time) == 0) + return vsync_time; + } + + return ktime_get(); +} + static void dpu_kms_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) { @@ -267,7 +295,6 @@ static void dpu_kms_prepare_commit(struct msm_kms *kms, if (!dev || !dev->dev_private) return; priv = dev->dev_private; - pm_runtime_get_sync(&dpu_kms->pdev->dev); /* Call prepare_commit for all affected encoders */ for_each_new_crtc_in_state(state, crtc, crtc_state, i) { @@ -278,6 +305,20 @@ static void dpu_kms_prepare_commit(struct msm_kms *kms, } } +static void dpu_kms_flush_commit(struct msm_kms *kms, unsigned crtc_mask) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + struct drm_crtc *crtc; + + for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask) { + if (!crtc->state->active) + continue; + + trace_dpu_kms_commit(DRMID(crtc)); + dpu_crtc_commit_kickoff(crtc); + } +} + /* * Override the encoder enable since we need to setup the inline rotator and do * some crtc magic before enabling any bridge that might be present. @@ -298,52 +339,18 @@ void dpu_kms_encoder_enable(struct drm_encoder *encoder) continue; trace_dpu_kms_enc_enable(DRMID(crtc)); - dpu_crtc_commit_kickoff(crtc, false); - } -} - -static void dpu_kms_commit(struct msm_kms *kms, struct drm_atomic_state *state) -{ - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int i; - - for_each_new_crtc_in_state(state, crtc, crtc_state, i) { - /* If modeset is required, kickoff is run in encoder_enable */ - if (drm_atomic_crtc_needs_modeset(crtc_state)) - continue; - - if (crtc->state->active) { - trace_dpu_kms_commit(DRMID(crtc)); - dpu_crtc_commit_kickoff(crtc, - state->legacy_cursor_update); - } } } -static void dpu_kms_complete_commit(struct msm_kms *kms, - struct drm_atomic_state *old_state) +static void dpu_kms_complete_commit(struct msm_kms *kms, unsigned crtc_mask) { - struct dpu_kms *dpu_kms; - struct msm_drm_private *priv; + struct dpu_kms *dpu_kms = to_dpu_kms(kms); struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state; - int i; - - if (!kms || !old_state) - return; - dpu_kms = to_dpu_kms(kms); - - if (!dpu_kms->dev || !dpu_kms->dev->dev_private) - return; - priv = dpu_kms->dev->dev_private; DPU_ATRACE_BEGIN("kms_complete_commit"); - for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) - dpu_crtc_complete_commit(crtc, old_crtc_state); - - pm_runtime_put_sync(&dpu_kms->pdev->dev); + for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask) + dpu_crtc_complete_commit(crtc); DPU_ATRACE_END("kms_complete_commit"); } @@ -389,6 +396,15 @@ static void dpu_kms_wait_for_commit_done(struct msm_kms *kms, } } +static void dpu_kms_wait_flush(struct msm_kms *kms, unsigned crtc_mask) +{ + struct dpu_kms *dpu_kms = to_dpu_kms(kms); + struct drm_crtc *crtc; + + for_each_crtc_mask(dpu_kms->dev, crtc, crtc_mask) + dpu_kms_wait_for_commit_done(kms, crtc); +} + static int _dpu_kms_initialize_dsi(struct drm_device *dev, struct msm_drm_private *priv, struct dpu_kms *dpu_kms) @@ -490,11 +506,6 @@ static int _dpu_kms_drm_obj_init(struct dpu_kms *dpu_kms) int primary_planes_idx = 0, cursor_planes_idx = 0, i, ret; int max_crtc_count; - if (!dpu_kms || !dpu_kms->dev || !dpu_kms->dev->dev) { - DPU_ERROR("invalid dpu_kms\n"); - return -EINVAL; - } - dev = dpu_kms->dev; priv = dev->dev_private; catalog = dpu_kms->catalog; @@ -686,10 +697,13 @@ static const struct msm_kms_funcs kms_funcs = { .irq_preinstall = dpu_irq_preinstall, .irq_uninstall = dpu_irq_uninstall, .irq = dpu_irq, + .enable_commit = dpu_kms_enable_commit, + .disable_commit = dpu_kms_disable_commit, + .vsync_time = dpu_kms_vsync_time, .prepare_commit = dpu_kms_prepare_commit, - .commit = dpu_kms_commit, + .flush_commit = dpu_kms_flush_commit, + .wait_flush = dpu_kms_wait_flush, .complete_commit = dpu_kms_complete_commit, - .wait_for_crtc_commit_done = dpu_kms_wait_for_commit_done, .enable_vblank = dpu_kms_enable_vblank, .disable_vblank = dpu_kms_disable_vblank, .check_modified_format = dpu_format_check_modified_format, @@ -800,6 +814,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) return rc; } + atomic_set(&dpu_kms->bandwidth_ref, 0); + dpu_kms->mmio = msm_ioremap(dpu_kms->pdev, "mdp", "mdp"); if (IS_ERR(dpu_kms->mmio)) { rc = PTR_ERR(dpu_kms->mmio); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 9e40f559c51f..4c889aabdaf9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -8,6 +8,8 @@ #ifndef __DPU_KMS_H__ #define __DPU_KMS_H__ +#include <drm/drm_drv.h> + #include "msm_drv.h" #include "msm_kms.h" #include "msm_mmu.h" @@ -120,6 +122,14 @@ struct dpu_kms { struct platform_device *pdev; bool rpm_enabled; struct dss_module_power mp; + + /* reference count bandwidth requests, so we know when we can + * release bandwidth. Each atomic update increments, and frame- + * done event decrements. Additionally, for video mode, the + * reference is incremented when crtc is enabled, and decremented + * when disabled. + */ + atomic_t bandwidth_ref; }; struct vsync_info { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c index 986915bbbc02..29705e773a4b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c @@ -3,6 +3,10 @@ * Copyright (c) 2018, The Linux Foundation */ +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqdesc.h> +#include <linux/irqchip/chained_irq.h> #include "dpu_kms.h" #include <linux/interconnect.h> @@ -22,7 +26,6 @@ struct dpu_mdss { struct msm_mdss base; void __iomem *mmio; unsigned long mmio_len; - u32 hwversion; struct dss_module_power mp; struct dpu_irq_controller irq_controller; struct icc_path *path[2]; @@ -287,10 +290,6 @@ int dpu_mdss_init(struct drm_device *dev) dpu_mdss_icc_request_bw(priv->mdss); - pm_runtime_get_sync(dev->dev); - dpu_mdss->hwversion = readl_relaxed(dpu_mdss->mmio); - pm_runtime_put_sync(dev->dev); - return ret; irq_error: diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 45bfac9e3af7..58d5acbcfc5c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -10,8 +10,10 @@ #include <linux/debugfs.h> #include <linux/dma-buf.h> -#include <drm/drm_damage_helper.h> #include <drm/drm_atomic_uapi.h> +#include <drm/drm_damage_helper.h> +#include <drm/drm_file.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "msm_drv.h" #include "dpu_kms.h" @@ -764,8 +766,6 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane, struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_state); struct dpu_hw_fmt_layout layout; - struct drm_gem_object *obj; - struct dma_fence *fence; struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); int ret; @@ -782,10 +782,7 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane, * we can use msm_atomic_prepare_fb() instead of doing the * implicit fence and fb prepare by hand here. */ - obj = msm_framebuffer_bo(new_state->fb, 0); - fence = reservation_object_get_excl_rcu(obj->resv); - if (fence) - drm_atomic_set_fence_for_plane(new_state, fence); + drm_gem_fb_prepare_fb(plane, new_state); if (pstate->aspace) { ret = msm_framebuffer_prepare(new_state->fb, @@ -1040,8 +1037,21 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) pstate->multirect_mode); if (pdpu->pipe_hw->ops.setup_format) { + unsigned int rotation; + src_flags = 0x0; + rotation = drm_rotation_simplify(state->rotation, + DRM_MODE_ROTATE_0 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y); + + if (rotation & DRM_MODE_REFLECT_X) + src_flags |= DPU_SSPP_FLIP_LR; + + if (rotation & DRM_MODE_REFLECT_Y) + src_flags |= DPU_SSPP_FLIP_UD; + /* update format */ pdpu->pipe_hw->ops.setup_format(pdpu->pipe_hw, fmt, src_flags, pstate->multirect_index); @@ -1522,6 +1532,13 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, if (ret) DPU_ERROR("failed to install zpos property, rc = %d\n", ret); + drm_plane_create_rotation_property(plane, + DRM_MODE_ROTATE_0, + DRM_MODE_ROTATE_0 | + DRM_MODE_ROTATE_180 | + DRM_MODE_REFLECT_X | + DRM_MODE_REFLECT_Y); + drm_plane_enable_fb_damage_clips(plane); /* success! finalize initialization */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h index 765484437d11..eecfe9b3199e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h @@ -392,7 +392,7 @@ TRACE_EVENT(dpu_enc_rc, __entry->rc_state = rc_state; __assign_str(stage_str, stage); ), - TP_printk("%s: id:%u, sw_event:%d, idle_pc_supported:%s, rc_state:%d\n", + TP_printk("%s: id:%u, sw_event:%d, idle_pc_supported:%s, rc_state:%d", __get_str(stage_str), __entry->drm_id, __entry->sw_event, __entry->idle_pc_supported ? "true" : "false", __entry->rc_state) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c index 8bc3aea7cd86..8d24b79fd400 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c @@ -5,6 +5,7 @@ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ #include <linux/debugfs.h> +#include <linux/delay.h> #include "dpu_vbif.h" #include "dpu_hw_vbif.h" @@ -264,11 +265,6 @@ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) struct dpu_hw_vbif *vbif; u32 i, pnd, src; - if (!dpu_kms) { - DPU_ERROR("invalid argument\n"); - return; - } - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { vbif = dpu_kms->hw_vbif[i]; if (vbif && vbif->ops.clear_errors) { @@ -286,11 +282,6 @@ void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms) struct dpu_hw_vbif *vbif; int i, j; - if (!dpu_kms) { - DPU_ERROR("invalid argument\n"); - return; - } - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { vbif = dpu_kms->hw_vbif[i]; if (vbif && vbif->cap && vbif->ops.set_mem_type) { |