OSDN Git Service

Merge tag 'drm-msm-next-2019-09-06' of https://gitlab.freedesktop.org/drm/msm into...
authorDave Airlie <airlied@redhat.com>
Thu, 12 Sep 2019 13:56:12 +0000 (23:56 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 17 Sep 2019 05:19:40 +0000 (15:19 +1000)
+ move msm8998 (snapdragon 835) display support
+ dpu fixes/cleanup
+ better async commit support for cursor updates
   (for dpu for now, I'll add mdp5 and possibly
   mdp4 once the movers deliver boxes full of my
   older hardware, so for v5.5)

Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Rob Clark <robdclark@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CAF6AEGuKVayu9bCuVe1RhzS6N6sHTrv4SVAh=qyCrmubX24Xag@mail.gmail.com
66 files changed:
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a5xx_debugfs.c
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.c
drivers/gpu/drm/msm/disp/dpu1/dpu_io_util.h
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h
drivers/gpu/drm/msm/disp/dpu1/dpu_mdss.c
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_irq.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_irq.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c
drivers/gpu/drm/msm/disp/mdp_format.c
drivers/gpu/drm/msm/dsi/dsi_host.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy_14nm.c
drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c
drivers/gpu/drm/msm/dsi/pll/dsi_pll.h
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi.h
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8x60.c
drivers/gpu/drm/msm/hdmi/hdmi_pll_8960.c
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_atomic_trace.h [new file with mode: 0644]
drivers/gpu/drm/msm/msm_atomic_tracepoints.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_debugfs.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_fb.c
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem_prime.c
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu_trace.h
drivers/gpu/drm/msm/msm_gpummu.c
drivers/gpu/drm/msm/msm_kms.h
drivers/gpu/drm/msm/msm_perf.c
drivers/gpu/drm/msm/msm_rd.c
drivers/gpu/drm/msm/msm_submitqueue.c

index 9c37e4d..e9160ce 100644 (file)
@@ -14,11 +14,11 @@ config DRM_MSM
        select SHMEM
        select TMPFS
        select QCOM_SCM if ARCH_QCOM
+       select QCOM_COMMAND_DB if ARCH_QCOM
        select WANT_DEV_COREDUMP
        select SND_SOC_HDMI_CODEC if SND_SOC
        select SYNC_FILE
        select PM_OPP
-       default y
        help
          DRM/KMS driver for MSM/snapdragon.
 
index 7a05cbf..1579cf0 100644 (file)
@@ -75,6 +75,7 @@ msm-y := \
        disp/dpu1/dpu_rm.o \
        disp/dpu1/dpu_vbif.o \
        msm_atomic.o \
+       msm_atomic_tracepoints.o \
        msm_debugfs.o \
        msm_drv.o \
        msm_fb.o \
index 9f2dd76..075ecce 100644 (file)
@@ -2,9 +2,11 @@
 /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
  */
 
-
 #include <linux/types.h>
 #include <linux/debugfs.h>
+
+#include <drm/drm_debugfs.h>
+#include <drm/drm_file.h>
 #include <drm/drm_print.h>
 
 #include "a5xx_gpu.h"
index 2ca470e..85f14fe 100644 (file)
@@ -1172,7 +1172,7 @@ static int a6xx_gmu_pwrlevels_probe(struct a6xx_gmu *gmu)
 
 static int a6xx_gmu_clocks_probe(struct a6xx_gmu *gmu)
 {
-       int ret = msm_clk_bulk_get(gmu->dev, &gmu->clocks);
+       int ret = devm_clk_bulk_get_all(gmu->dev, &gmu->clocks);
 
        if (ret < 1)
                return ret;
index 40133a4..0888e0d 100644 (file)
@@ -181,6 +181,7 @@ MODULE_FIRMWARE("qcom/a530_zap.b01");
 MODULE_FIRMWARE("qcom/a530_zap.b02");
 MODULE_FIRMWARE("qcom/a630_sqe.fw");
 MODULE_FIRMWARE("qcom/a630_gmu.bin");
+MODULE_FIRMWARE("qcom/a630_zap.mbn");
 
 static inline bool _rev_match(uint8_t entry, uint8_t id)
 {
index 5cda968..09a49b5 100644 (file)
@@ -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);
index b3417d5..ce59adf 100644 (file)
@@ -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",
index 5181f07..5174e86 100644 (file)
@@ -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
index 0aa8a12..d82ea99 100644 (file)
@@ -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,
index a8bf114..b491346 100644 (file)
@@ -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
index 1b3ab90..2923b63 100644 (file)
@@ -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
index 5055a5e..b9c84fb 100644 (file)
@@ -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;
index 90f4398..ec76b86 100644 (file)
@@ -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
index b2f7b0e..179e8d5 100644 (file)
@@ -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;
 }
 
index 71b6987..27fbeb5 100644 (file)
@@ -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>
 
index 09083e9..e6b5c77 100644 (file)
@@ -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>
 
 #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;
 };
index bb9d44e..58b0485 100644 (file)
@@ -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);
index 9e40f55..4c889aa 100644 (file)
@@ -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 {
index 986915b..29705e7 100644 (file)
@@ -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:
index 8cf0b8a..58d5acb 100644 (file)
@@ -10,8 +10,9 @@
 #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"
@@ -1036,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);
@@ -1518,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 */
index 7654844..eecfe9b 100644 (file)
@@ -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)
index 8bc3aea..8d24b79 100644 (file)
@@ -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) {
index 668c419..f34dca5 100644 (file)
@@ -8,6 +8,7 @@
 #include <drm/drm_flip_work.h>
 #include <drm/drm_mode.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
 
 #include "mdp4_kms.h"
 
index 62fbca3..4d49f3b 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <drm/drm_print.h>
+#include <drm/drm_vblank.h>
 
 #include "msm_drv.h"
 #include "mdp4_kms.h"
index 7a9ab55..50711cc 100644 (file)
@@ -4,6 +4,9 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <linux/delay.h>
+
+#include <drm/drm_vblank.h>
 
 #include "msm_drv.h"
 #include "msm_gem.h"
@@ -93,40 +96,51 @@ out:
        return ret;
 }
 
-static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+static void mdp4_enable_commit(struct msm_kms *kms)
+{
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_enable(mdp4_kms);
+}
+
+static void mdp4_disable_commit(struct msm_kms *kms)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_disable(mdp4_kms);
+}
+
+static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
        int i;
        struct drm_crtc *crtc;
        struct drm_crtc_state *crtc_state;
 
-       mdp4_enable(mdp4_kms);
-
        /* see 119ecb7fd */
        for_each_new_crtc_in_state(state, crtc, crtc_state, i)
                drm_crtc_vblank_get(crtc);
 }
 
-static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+static void mdp4_flush_commit(struct msm_kms *kms, unsigned crtc_mask)
+{
+       /* TODO */
+}
+
+static void mdp4_wait_flush(struct msm_kms *kms, unsigned crtc_mask)
 {
        struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
-       int i;
        struct drm_crtc *crtc;
-       struct drm_crtc_state *crtc_state;
 
-       drm_atomic_helper_wait_for_vblanks(mdp4_kms->dev, state);
-
-       /* see 119ecb7fd */
-       for_each_new_crtc_in_state(state, crtc, crtc_state, i)
-               drm_crtc_vblank_put(crtc);
-
-       mdp4_disable(mdp4_kms);
+       for_each_crtc_mask(mdp4_kms->dev, crtc, crtc_mask)
+               mdp4_crtc_wait_for_commit_done(crtc);
 }
 
-static void mdp4_wait_for_crtc_commit_done(struct msm_kms *kms,
-                                               struct drm_crtc *crtc)
+static void mdp4_complete_commit(struct msm_kms *kms, unsigned crtc_mask)
 {
-       mdp4_crtc_wait_for_commit_done(crtc);
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       struct drm_crtc *crtc;
+
+       /* see 119ecb7fd */
+       for_each_crtc_mask(mdp4_kms->dev, crtc, crtc_mask)
+               drm_crtc_vblank_put(crtc);
 }
 
 static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
@@ -178,9 +192,12 @@ static const struct mdp_kms_funcs kms_funcs = {
                .irq             = mdp4_irq,
                .enable_vblank   = mdp4_enable_vblank,
                .disable_vblank  = mdp4_disable_vblank,
+               .enable_commit   = mdp4_enable_commit,
+               .disable_commit  = mdp4_disable_commit,
                .prepare_commit  = mdp4_prepare_commit,
+               .flush_commit    = mdp4_flush_commit,
+               .wait_flush      = mdp4_wait_flush,
                .complete_commit = mdp4_complete_commit,
-               .wait_for_crtc_commit_done = mdp4_wait_for_crtc_commit_done,
                .get_format      = mdp_get_format,
                .round_pixclk    = mdp4_round_pixclk,
                .destroy         = mdp4_destroy,
index 62e2ebe..871f351 100644 (file)
@@ -5,6 +5,8 @@
  * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
  */
 
+#include <linux/delay.h>
+
 #include <drm/drm_crtc.h>
 #include <drm/drm_probe_helper.h>
 
index ecef4f5..9262ed2 100644 (file)
@@ -5,8 +5,6 @@
  * Author: Vinay Simha <vinaysimha@inforcecomputing.com>
  */
 
-#include <linux/gpio.h>
-
 #include "mdp4_kms.h"
 
 struct mdp4_lvds_connector {
index e3010f0..da3cc1d 100644 (file)
@@ -5,6 +5,8 @@
  */
 
 #include <drm/drm_damage_helper.h>
+#include <drm/drm_fourcc.h>
+
 #include "mdp4_kms.h"
 
 #define DOWN_SCALE_MAX 8
index dd1daf0..f6e71ff 100644 (file)
@@ -630,7 +630,115 @@ const struct mdp5_cfg_hw msm8917_config = {
        .max_clk = 320000000,
 };
 
-static const struct mdp5_cfg_handler cfg_handlers[] = {
+const struct mdp5_cfg_hw msm8998_config = {
+       .name = "msm8998",
+       .mdp = {
+               .count = 1,
+               .caps = MDP_CAP_DSC |
+                       MDP_CAP_CDM |
+                       MDP_CAP_SRC_SPLIT |
+                       0,
+       },
+       .ctl = {
+               .count = 5,
+               .base = { 0x01000, 0x01200, 0x01400, 0x01600, 0x01800 },
+               .flush_hw_mask = 0xf7ffffff,
+       },
+       .pipe_vig = {
+               .count = 4,
+               .base = { 0x04000, 0x06000, 0x08000, 0x0a000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_SCALE      |
+                       MDP_PIPE_CAP_CSC        |
+                       MDP_PIPE_CAP_DECIMATION |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       0,
+       },
+       .pipe_rgb = {
+               .count = 4,
+               .base = { 0x14000, 0x16000, 0x18000, 0x1a000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_SCALE      |
+                       MDP_PIPE_CAP_DECIMATION |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       0,
+       },
+       .pipe_dma = {
+               .count = 2, /* driver supports max of 2 currently */
+               .base = { 0x24000, 0x26000, 0x28000, 0x2a000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       0,
+       },
+       .pipe_cursor = {
+               .count = 2,
+               .base = { 0x34000, 0x36000 },
+               .caps = MDP_PIPE_CAP_HFLIP      |
+                       MDP_PIPE_CAP_VFLIP      |
+                       MDP_PIPE_CAP_SW_PIX_EXT |
+                       MDP_PIPE_CAP_CURSOR     |
+                       0,
+       },
+
+       .lm = {
+               .count = 6,
+               .base = { 0x44000, 0x45000, 0x46000, 0x47000, 0x48000, 0x49000 },
+               .instances = {
+                               { .id = 0, .pp = 0, .dspp = 0,
+                                 .caps = MDP_LM_CAP_DISPLAY |
+                                         MDP_LM_CAP_PAIR, },
+                               { .id = 1, .pp = 1, .dspp = 1,
+                                 .caps = MDP_LM_CAP_DISPLAY, },
+                               { .id = 2, .pp = 2, .dspp = -1,
+                                 .caps = MDP_LM_CAP_DISPLAY |
+                                         MDP_LM_CAP_PAIR, },
+                               { .id = 3, .pp = -1, .dspp = -1,
+                                 .caps = MDP_LM_CAP_WB, },
+                               { .id = 4, .pp = -1, .dspp = -1,
+                                 .caps = MDP_LM_CAP_WB, },
+                               { .id = 5, .pp = 3, .dspp = -1,
+                                 .caps = MDP_LM_CAP_DISPLAY, },
+                            },
+               .nb_stages = 8,
+               .max_width = 2560,
+               .max_height = 0xFFFF,
+       },
+       .dspp = {
+               .count = 2,
+               .base = { 0x54000, 0x56000 },
+       },
+       .ad = {
+               .count = 3,
+               .base = { 0x78000, 0x78800, 0x79000 },
+       },
+       .pp = {
+               .count = 4,
+               .base = { 0x70000, 0x70800, 0x71000, 0x71800 },
+       },
+       .cdm = {
+               .count = 1,
+               .base = { 0x79200 },
+       },
+       .dsc = {
+               .count = 2,
+               .base = { 0x80000, 0x80400 },
+       },
+       .intf = {
+               .base = { 0x6a000, 0x6a800, 0x6b000, 0x6b800, 0x6c000 },
+               .connect = {
+                       [0] = INTF_eDP,
+                       [1] = INTF_DSI,
+                       [2] = INTF_DSI,
+                       [3] = INTF_HDMI,
+               },
+       },
+       .max_clk = 412500000,
+};
+
+static const struct mdp5_cfg_handler cfg_handlers_v1[] = {
        { .revision = 0, .config = { .hw = &msm8x74v1_config } },
        { .revision = 2, .config = { .hw = &msm8x74v2_config } },
        { .revision = 3, .config = { .hw = &apq8084_config } },
@@ -640,6 +748,10 @@ static const struct mdp5_cfg_handler cfg_handlers[] = {
        { .revision = 15, .config = { .hw = &msm8917_config } },
 };
 
+static const struct mdp5_cfg_handler cfg_handlers_v3[] = {
+       { .revision = 0, .config = { .hw = &msm8998_config } },
+};
+
 static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev);
 
 const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_handler)
@@ -668,8 +780,9 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
        struct drm_device *dev = mdp5_kms->dev;
        struct platform_device *pdev = to_platform_device(dev->dev);
        struct mdp5_cfg_handler *cfg_handler;
+       const struct mdp5_cfg_handler *cfg_handlers;
        struct mdp5_cfg_platform *pconfig;
-       int i, ret = 0;
+       int i, ret = 0, num_handlers;
 
        cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL);
        if (unlikely(!cfg_handler)) {
@@ -677,15 +790,24 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
                goto fail;
        }
 
-       if (major != 1) {
+       switch (major) {
+       case 1:
+               cfg_handlers = cfg_handlers_v1;
+               num_handlers = ARRAY_SIZE(cfg_handlers_v1);
+               break;
+       case 3:
+               cfg_handlers = cfg_handlers_v3;
+               num_handlers = ARRAY_SIZE(cfg_handlers_v3);
+               break;
+       default:
                DRM_DEV_ERROR(dev->dev, "unexpected MDP major version: v%d.%d\n",
                                major, minor);
                ret = -ENXIO;
                goto fail;
-       }
+       };
 
        /* only after mdp5_cfg global pointer's init can we access the hw */
-       for (i = 0; i < ARRAY_SIZE(cfg_handlers); i++) {
+       for (i = 0; i < num_handlers; i++) {
                if (cfg_handlers[i].revision != minor)
                        continue;
                mdp5_cfg = cfg_handlers[i].config.hw;
index 78d5fa2..eb0b4b7 100644 (file)
@@ -6,10 +6,13 @@
  */
 
 #include <linux/sort.h>
+
 #include <drm/drm_mode.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_flip_work.h>
+#include <drm/drm_fourcc.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
 
 #include "mdp5_kms.h"
 
index 4804cf4..030279d 100644 (file)
@@ -253,7 +253,7 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline,
        u32 blend_cfg;
        struct mdp5_hw_mixer *mixer = pipeline->mixer;
 
-       if (unlikely(WARN_ON(!mixer))) {
+       if (WARN_ON(!mixer)) {
                DRM_DEV_ERROR(ctl_mgr->dev->dev, "CTL %d cannot find LM",
                        ctl->id);
                return -EINVAL;
@@ -695,7 +695,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
                goto fail;
        }
 
-       if (unlikely(WARN_ON(ctl_cfg->count > MAX_CTL))) {
+       if (WARN_ON(ctl_cfg->count > MAX_CTL)) {
                DRM_DEV_ERROR(dev->dev, "Increase static pool size to at least %d\n",
                                ctl_cfg->count);
                ret = -ENOSPC;
index 58db08a..9b4c8d9 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/irq.h>
 
 #include <drm/drm_print.h>
+#include <drm/drm_vblank.h>
 
 #include "msm_drv.h"
 #include "mdp5_kms.h"
index fec6ef1..91cd76a 100644 (file)
@@ -5,9 +5,15 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <linux/delay.h>
 #include <linux/interconnect.h>
 #include <linux/of_irq.h>
 
+#include <drm/drm_debugfs.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_vblank.h>
+
 #include "msm_drv.h"
 #include "msm_gem.h"
 #include "msm_mmu.h"
@@ -140,40 +146,52 @@ static int mdp5_global_obj_init(struct mdp5_kms *mdp5_kms)
        return 0;
 }
 
+static void mdp5_enable_commit(struct msm_kms *kms)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       pm_runtime_get_sync(&mdp5_kms->pdev->dev);
+}
+
+static void mdp5_disable_commit(struct msm_kms *kms)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       pm_runtime_put_sync(&mdp5_kms->pdev->dev);
+}
+
 static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-       struct device *dev = &mdp5_kms->pdev->dev;
        struct mdp5_global_state *global_state;
 
        global_state = mdp5_get_existing_global_state(mdp5_kms);
 
-       pm_runtime_get_sync(dev);
-
        if (mdp5_kms->smp)
                mdp5_smp_prepare_commit(mdp5_kms->smp, &global_state->smp);
 }
 
-static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+static void mdp5_flush_commit(struct msm_kms *kms, unsigned crtc_mask)
+{
+       /* TODO */
+}
+
+static void mdp5_wait_flush(struct msm_kms *kms, unsigned crtc_mask)
 {
        struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
-       struct device *dev = &mdp5_kms->pdev->dev;
-       struct mdp5_global_state *global_state;
+       struct drm_crtc *crtc;
 
-       drm_atomic_helper_wait_for_vblanks(mdp5_kms->dev, state);
+       for_each_crtc_mask(mdp5_kms->dev, crtc, crtc_mask)
+               mdp5_crtc_wait_for_commit_done(crtc);
+}
+
+static void mdp5_complete_commit(struct msm_kms *kms, unsigned crtc_mask)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       struct mdp5_global_state *global_state;
 
        global_state = mdp5_get_existing_global_state(mdp5_kms);
 
        if (mdp5_kms->smp)
                mdp5_smp_complete_commit(mdp5_kms->smp, &global_state->smp);
-
-       pm_runtime_put_sync(dev);
-}
-
-static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms,
-                                               struct drm_crtc *crtc)
-{
-       mdp5_crtc_wait_for_commit_done(crtc);
 }
 
 static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
@@ -271,9 +289,12 @@ static const struct mdp_kms_funcs kms_funcs = {
                .irq             = mdp5_irq,
                .enable_vblank   = mdp5_enable_vblank,
                .disable_vblank  = mdp5_disable_vblank,
+               .flush_commit    = mdp5_flush_commit,
+               .enable_commit   = mdp5_enable_commit,
+               .disable_commit  = mdp5_disable_commit,
                .prepare_commit  = mdp5_prepare_commit,
+               .wait_flush      = mdp5_wait_flush,
                .complete_commit = mdp5_complete_commit,
-               .wait_for_crtc_commit_done = mdp5_wait_for_crtc_commit_done,
                .get_format      = mdp_get_format,
                .round_pixclk    = mdp5_round_pixclk,
                .set_split_display = mdp5_set_split_display,
@@ -663,6 +684,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
        struct msm_kms *kms;
        struct msm_gem_address_space *aspace;
        int irq, i, ret;
+       struct device *iommu_dev;
 
        /* priv->kms would have been populated by the MDP5 driver */
        kms = priv->kms;
@@ -702,7 +724,11 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
        mdelay(16);
 
        if (config->platform.iommu) {
-               aspace = msm_gem_address_space_create(&pdev->dev,
+               iommu_dev = &pdev->dev;
+               if (!iommu_dev->iommu_fwspec)
+                       iommu_dev = iommu_dev->parent;
+
+               aspace = msm_gem_address_space_create(iommu_dev,
                                config->platform.iommu, "mdp5");
                if (IS_ERR(aspace)) {
                        ret = PTR_ERR(aspace);
index c7e6725..8342309 100644 (file)
@@ -6,7 +6,9 @@
  */
 
 #include <drm/drm_damage_helper.h>
+#include <drm/drm_fourcc.h>
 #include <drm/drm_print.h>
+
 #include "mdp5_kms.h"
 
 struct mdp5_plane {
index 776337f..b31cfb5 100644 (file)
@@ -5,6 +5,7 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <drm/drm_fourcc.h>
 #include <drm/drm_util.h>
 
 #include "mdp5_kms.h"
index 8afb0f9..5495d8b 100644 (file)
@@ -174,7 +174,7 @@ const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format,
 
 struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type type)
 {
-       if (unlikely(WARN_ON(type >= CSC_MAX)))
+       if (WARN_ON(type >= CSC_MAX))
                return NULL;
 
        return &csc_convert[type];
index aa35d18..663ff9f 100644 (file)
@@ -5,19 +5,19 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
 #include <linux/of_irq.h>
 #include <linux/pinctrl/consumer.h>
-#include <linux/of_graph.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spinlock.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
+
 #include <video/mipi_display.h>
 
 #include "dsi.h"
@@ -421,15 +421,15 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host)
        }
 
        msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk);
-       if (!msm_host->byte_clk_src) {
-               ret = -ENODEV;
+       if (IS_ERR(msm_host->byte_clk_src)) {
+               ret = PTR_ERR(msm_host->byte_clk_src);
                pr_err("%s: can't find byte_clk clock. ret=%d\n", __func__, ret);
                goto exit;
        }
 
        msm_host->pixel_clk_src = clk_get_parent(msm_host->pixel_clk);
-       if (!msm_host->pixel_clk_src) {
-               ret = -ENODEV;
+       if (IS_ERR(msm_host->pixel_clk_src)) {
+               ret = PTR_ERR(msm_host->pixel_clk_src);
                pr_err("%s: can't find pixel_clk clock. ret=%d\n", __func__, ret);
                goto exit;
        }
index 4097eca..3522863 100644 (file)
@@ -396,8 +396,12 @@ static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
 
        ret = devm_regulator_bulk_get(dev, num, s);
        if (ret < 0) {
-               DRM_DEV_ERROR(dev, "%s: failed to init regulator, ret=%d\n",
-                                               __func__, ret);
+               if (ret != -EPROBE_DEFER) {
+                       DRM_DEV_ERROR(dev,
+                                     "%s: failed to init regulator, ret=%d\n",
+                                     __func__, ret);
+               }
+
                return ret;
        }
 
@@ -584,10 +588,8 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)
        }
 
        ret = dsi_phy_regulator_init(phy);
-       if (ret) {
-               DRM_DEV_ERROR(dev, "%s: failed to init regulator\n", __func__);
+       if (ret)
                goto fail;
-       }
 
        phy->ahb_clk = msm_clk_get(pdev, "iface");
        if (IS_ERR(phy->ahb_clk)) {
index c3a6187..1594f14 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (c) 2016, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/delay.h>
+
 #include "dsi_phy.h"
 #include "dsi.xml.h"
 
index a198f51..f225833 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
  */
 
+#include <linux/delay.h>
+
 #include "dsi_phy.h"
 #include "dsi.xml.h"
 
index 118bebe..c6a3623 100644 (file)
@@ -6,8 +6,8 @@
 #ifndef __DSI_PLL_H__
 #define __DSI_PLL_H__
 
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/delay.h>
 
 #include "dsi.h"
 
index 0e4217b..355afb9 100644 (file)
@@ -425,38 +425,6 @@ static const struct {
        { "qcom,hdmi-tx-mux-lpm", true, 1, "HDMI_MUX_LPM" },
 };
 
-static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name)
-{
-       int gpio;
-
-       /* try with the gpio names as in the table (downstream bindings) */
-       gpio = of_get_named_gpio(of_node, name, 0);
-       if (gpio < 0) {
-               char name2[32];
-
-               /* try with the gpio names as in the upstream bindings */
-               snprintf(name2, sizeof(name2), "%s-gpios", name);
-               gpio = of_get_named_gpio(of_node, name2, 0);
-               if (gpio < 0) {
-                       char name3[32];
-
-                       /*
-                        * try again after stripping out the "qcom,hdmi-tx"
-                        * prefix. This is mainly to match "hpd-gpios" used
-                        * in the upstream bindings
-                        */
-                       if (sscanf(name2, "qcom,hdmi-tx-%s", name3))
-                               gpio = of_get_named_gpio(of_node, name3, 0);
-               }
-
-               if (gpio < 0) {
-                       DBG("failed to get gpio: %s (%d)", name, gpio);
-                       gpio = -1;
-               }
-       }
-       return gpio;
-}
-
 /*
  * HDMI audio codec callbacks
  */
@@ -582,11 +550,39 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data)
        hdmi_cfg->qfprom_mmio_name = "qfprom_physical";
 
        for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
-               hdmi_cfg->gpios[i].num = msm_hdmi_get_gpio(of_node,
-                                               msm_hdmi_gpio_pdata[i].name);
+               const char *name = msm_hdmi_gpio_pdata[i].name;
+               struct gpio_desc *gpiod;
+
+               /*
+                * We are fetching the GPIO lines "as is" since the connector
+                * code is enabling and disabling the lines. Until that point
+                * the power-on default value will be kept.
+                */
+               gpiod = devm_gpiod_get_optional(dev, name, GPIOD_ASIS);
+               /* This will catch e.g. -PROBE_DEFER */
+               if (IS_ERR(gpiod))
+                       return PTR_ERR(gpiod);
+               if (!gpiod) {
+                       /* Try a second time, stripping down the name */
+                       char name3[32];
+
+                       /*
+                        * Try again after stripping out the "qcom,hdmi-tx"
+                        * prefix. This is mainly to match "hpd-gpios" used
+                        * in the upstream bindings.
+                        */
+                       if (sscanf(name, "qcom,hdmi-tx-%s", name3))
+                               gpiod = devm_gpiod_get_optional(dev, name3, GPIOD_ASIS);
+                       if (IS_ERR(gpiod))
+                               return PTR_ERR(gpiod);
+                       if (!gpiod)
+                               DBG("failed to get gpio: %s", name);
+               }
+               hdmi_cfg->gpios[i].gpiod = gpiod;
+               if (gpiod)
+                       gpiod_set_consumer_name(gpiod, msm_hdmi_gpio_pdata[i].label);
                hdmi_cfg->gpios[i].output = msm_hdmi_gpio_pdata[i].output;
                hdmi_cfg->gpios[i].value = msm_hdmi_gpio_pdata[i].value;
-               hdmi_cfg->gpios[i].label = msm_hdmi_gpio_pdata[i].label;
        }
 
        dev->platform_data = hdmi_cfg;
index 9828658..bdac452 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/hdmi.h>
 
 #include "msm_drv.h"
@@ -22,10 +23,9 @@ struct hdmi_phy;
 struct hdmi_platform_config;
 
 struct hdmi_gpio_data {
-       int num;
+       struct gpio_desc *gpiod;
        bool output;
        int value;
-       const char *label;
 };
 
 struct hdmi_audio {
index c8dbd82..ba81338 100644 (file)
@@ -4,6 +4,8 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <linux/delay.h>
+
 #include "hdmi.h"
 
 struct hdmi_bridge {
index 07b4cb8..839822d 100644 (file)
@@ -4,7 +4,8 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
-#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/pinctrl/consumer.h>
 
 #include "msm_kms.h"
@@ -68,30 +69,21 @@ static void msm_hdmi_phy_reset(struct hdmi *hdmi)
 
 static int gpio_config(struct hdmi *hdmi, bool on)
 {
-       struct device *dev = &hdmi->pdev->dev;
        const struct hdmi_platform_config *config = hdmi->config;
-       int ret, i;
+       int i;
 
        if (on) {
                for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
                        struct hdmi_gpio_data gpio = config->gpios[i];
 
-                       if (gpio.num != -1) {
-                               ret = gpio_request(gpio.num, gpio.label);
-                               if (ret) {
-                                       DRM_DEV_ERROR(dev,
-                                               "'%s'(%d) gpio_request failed: %d\n",
-                                               gpio.label, gpio.num, ret);
-                                       goto err;
-                               }
-
+                       if (gpio.gpiod) {
                                if (gpio.output) {
-                                       gpio_direction_output(gpio.num,
-                                                             gpio.value);
+                                       gpiod_direction_output(gpio.gpiod,
+                                                              gpio.value);
                                } else {
-                                       gpio_direction_input(gpio.num);
-                                       gpio_set_value_cansleep(gpio.num,
-                                                               gpio.value);
+                                       gpiod_direction_input(gpio.gpiod);
+                                       gpiod_set_value_cansleep(gpio.gpiod,
+                                                                gpio.value);
                                }
                        }
                }
@@ -101,29 +93,20 @@ static int gpio_config(struct hdmi *hdmi, bool on)
                for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) {
                        struct hdmi_gpio_data gpio = config->gpios[i];
 
-                       if (gpio.num == -1)
+                       if (!gpio.gpiod)
                                continue;
 
                        if (gpio.output) {
                                int value = gpio.value ? 0 : 1;
 
-                               gpio_set_value_cansleep(gpio.num, value);
+                               gpiod_set_value_cansleep(gpio.gpiod, value);
                        }
-
-                       gpio_free(gpio.num);
                };
 
                DBG("gpio off");
        }
 
        return 0;
-err:
-       while (i--) {
-               if (config->gpios[i].num != -1)
-                       gpio_free(config->gpios[i].num);
-       }
-
-       return ret;
 }
 
 static void enable_hpd_clocks(struct hdmi *hdmi, bool enable)
@@ -311,7 +294,7 @@ static enum drm_connector_status detect_gpio(struct hdmi *hdmi)
        const struct hdmi_platform_config *config = hdmi->config;
        struct hdmi_gpio_data hpd_gpio = config->gpios[HPD_GPIO_INDEX];
 
-       return gpio_get_value(hpd_gpio.num) ?
+       return gpiod_get_value(hpd_gpio.gpiod) ?
                        connector_status_connected :
                        connector_status_disconnected;
 }
@@ -330,7 +313,7 @@ static enum drm_connector_status hdmi_connector_detect(
         * some platforms may not have hpd gpio. Rely only on the status
         * provided by REG_HDMI_HPD_INT_STATUS in this case.
         */
-       if (hpd_gpio.num == -1)
+       if (!hpd_gpio.gpiod)
                return detect_reg(hdmi);
 
        do {
index fe82ad3..a8f3b2c 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/delay.h>
 
 #include "hdmi.h"
 
index 1acc33c..95f2928 100644 (file)
@@ -4,6 +4,8 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <linux/delay.h>
+
 #include "hdmi.h"
 
 static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy,
index e24a11d..562dfac 100644 (file)
@@ -6,6 +6,8 @@
  */
 
 #include <linux/clk-provider.h>
+#include <linux/delay.h>
+
 #include "hdmi.h"
 
 struct hdmi_pll_8960 {
index 169d5f9..5ccfad7 100644 (file)
 
 #include <drm/drm_atomic_uapi.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_vblank.h>
 
+#include "msm_atomic_trace.h"
 #include "msm_drv.h"
 #include "msm_gem.h"
 #include "msm_kms.h"
 
-static void msm_atomic_wait_for_commit_done(struct drm_device *dev,
-               struct drm_atomic_state *old_state)
+int msm_atomic_prepare_fb(struct drm_plane *plane,
+                         struct drm_plane_state *new_state)
 {
-       struct drm_crtc *crtc;
-       struct drm_crtc_state *new_crtc_state;
-       struct msm_drm_private *priv = old_state->dev->dev_private;
+       struct msm_drm_private *priv = plane->dev->dev_private;
        struct msm_kms *kms = priv->kms;
-       int i;
 
-       for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
-               if (!new_crtc_state->active)
-                       continue;
+       if (!new_state->fb)
+               return 0;
 
-               if (drm_crtc_vblank_get(crtc))
-                       continue;
+       drm_gem_fb_prepare_fb(plane, new_state);
 
-               kms->funcs->wait_for_crtc_commit_done(kms, crtc);
+       return msm_framebuffer_prepare(new_state->fb, kms->aspace);
+}
 
-               drm_crtc_vblank_put(crtc);
+static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx)
+{
+       unsigned crtc_mask = BIT(crtc_idx);
+
+       trace_msm_atomic_async_commit_start(crtc_mask);
+
+       mutex_lock(&kms->commit_lock);
+
+       if (!(kms->pending_crtc_mask & crtc_mask)) {
+               mutex_unlock(&kms->commit_lock);
+               goto out;
        }
+
+       kms->pending_crtc_mask &= ~crtc_mask;
+
+       kms->funcs->enable_commit(kms);
+
+       /*
+        * Flush hardware updates:
+        */
+       trace_msm_atomic_flush_commit(crtc_mask);
+       kms->funcs->flush_commit(kms, crtc_mask);
+       mutex_unlock(&kms->commit_lock);
+
+       /*
+        * Wait for flush to complete:
+        */
+       trace_msm_atomic_wait_flush_start(crtc_mask);
+       kms->funcs->wait_flush(kms, crtc_mask);
+       trace_msm_atomic_wait_flush_finish(crtc_mask);
+
+       mutex_lock(&kms->commit_lock);
+       kms->funcs->complete_commit(kms, crtc_mask);
+       mutex_unlock(&kms->commit_lock);
+       kms->funcs->disable_commit(kms);
+
+out:
+       trace_msm_atomic_async_commit_finish(crtc_mask);
 }
 
-int msm_atomic_prepare_fb(struct drm_plane *plane,
-                         struct drm_plane_state *new_state)
+static enum hrtimer_restart msm_atomic_pending_timer(struct hrtimer *t)
 {
-       struct msm_drm_private *priv = plane->dev->dev_private;
-       struct msm_kms *kms = priv->kms;
+       struct msm_pending_timer *timer = container_of(t,
+                       struct msm_pending_timer, timer);
+       struct msm_drm_private *priv = timer->kms->dev->dev_private;
 
-       if (!new_state->fb)
-               return 0;
+       queue_work(priv->wq, &timer->work);
 
-       drm_gem_fb_prepare_fb(plane, new_state);
+       return HRTIMER_NORESTART;
+}
 
-       return msm_framebuffer_prepare(new_state->fb, kms->aspace);
+static void msm_atomic_pending_work(struct work_struct *work)
+{
+       struct msm_pending_timer *timer = container_of(work,
+                       struct msm_pending_timer, work);
+
+       msm_atomic_async_commit(timer->kms, timer->crtc_idx);
+}
+
+void msm_atomic_init_pending_timer(struct msm_pending_timer *timer,
+               struct msm_kms *kms, int crtc_idx)
+{
+       timer->kms = kms;
+       timer->crtc_idx = crtc_idx;
+       hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       timer->timer.function = msm_atomic_pending_timer;
+       INIT_WORK(&timer->work, msm_atomic_pending_work);
+}
+
+static bool can_do_async(struct drm_atomic_state *state,
+               struct drm_crtc **async_crtc)
+{
+       struct drm_connector_state *connector_state;
+       struct drm_connector *connector;
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       int i, num_crtcs = 0;
+
+       if (!(state->legacy_cursor_update || state->async_update))
+               return false;
+
+       /* any connector change, means slow path: */
+       for_each_new_connector_in_state(state, connector, connector_state, i)
+               return false;
+
+       for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+               if (drm_atomic_crtc_needs_modeset(crtc_state))
+                       return false;
+               if (++num_crtcs > 1)
+                       return false;
+               *async_crtc = crtc;
+       }
+
+       return true;
+}
+
+/* Get bitmask of crtcs that will need to be flushed.  The bitmask
+ * can be used with for_each_crtc_mask() iterator, to iterate
+ * effected crtcs without needing to preserve the atomic state.
+ */
+static unsigned get_crtc_mask(struct drm_atomic_state *state)
+{
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       unsigned i, mask = 0;
+
+       for_each_new_crtc_in_state(state, crtc, crtc_state, i)
+               mask |= drm_crtc_mask(crtc);
+
+       return mask;
 }
 
 void msm_atomic_commit_tail(struct drm_atomic_state *state)
@@ -52,26 +144,104 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state)
        struct drm_device *dev = state->dev;
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_kms *kms = priv->kms;
+       struct drm_crtc *async_crtc = NULL;
+       unsigned crtc_mask = get_crtc_mask(state);
+       bool async = kms->funcs->vsync_time &&
+                       can_do_async(state, &async_crtc);
+
+       trace_msm_atomic_commit_tail_start(async, crtc_mask);
+
+       kms->funcs->enable_commit(kms);
 
+       /*
+        * Ensure any previous (potentially async) commit has
+        * completed:
+        */
+       trace_msm_atomic_wait_flush_start(crtc_mask);
+       kms->funcs->wait_flush(kms, crtc_mask);
+       trace_msm_atomic_wait_flush_finish(crtc_mask);
+
+       mutex_lock(&kms->commit_lock);
+
+       /*
+        * Now that there is no in-progress flush, prepare the
+        * current update:
+        */
        kms->funcs->prepare_commit(kms, state);
 
+       /*
+        * Push atomic updates down to hardware:
+        */
        drm_atomic_helper_commit_modeset_disables(dev, state);
-
        drm_atomic_helper_commit_planes(dev, state, 0);
-
        drm_atomic_helper_commit_modeset_enables(dev, state);
 
-       if (kms->funcs->commit) {
-               DRM_DEBUG_ATOMIC("triggering commit\n");
-               kms->funcs->commit(kms, state);
-       }
+       if (async) {
+               struct msm_pending_timer *timer =
+                       &kms->pending_timers[drm_crtc_index(async_crtc)];
 
-       if (!state->legacy_cursor_update)
-               msm_atomic_wait_for_commit_done(dev, state);
+               /* async updates are limited to single-crtc updates: */
+               WARN_ON(crtc_mask != drm_crtc_mask(async_crtc));
 
-       kms->funcs->complete_commit(kms, state);
+               /*
+                * Start timer if we don't already have an update pending
+                * on this crtc:
+                */
+               if (!(kms->pending_crtc_mask & crtc_mask)) {
+                       ktime_t vsync_time, wakeup_time;
 
-       drm_atomic_helper_commit_hw_done(state);
+                       kms->pending_crtc_mask |= crtc_mask;
+
+                       vsync_time = kms->funcs->vsync_time(kms, async_crtc);
+                       wakeup_time = ktime_sub(vsync_time, ms_to_ktime(1));
+
+                       hrtimer_start(&timer->timer, wakeup_time,
+                                       HRTIMER_MODE_ABS);
+               }
 
+               kms->funcs->disable_commit(kms);
+               mutex_unlock(&kms->commit_lock);
+
+               /*
+                * At this point, from drm core's perspective, we
+                * are done with the atomic update, so we can just
+                * go ahead and signal that it is done:
+                */
+               drm_atomic_helper_commit_hw_done(state);
+               drm_atomic_helper_cleanup_planes(dev, state);
+
+               trace_msm_atomic_commit_tail_finish(async, crtc_mask);
+
+               return;
+       }
+
+       /*
+        * If there is any async flush pending on updated crtcs, fold
+        * them into the current flush.
+        */
+       kms->pending_crtc_mask &= ~crtc_mask;
+
+       /*
+        * Flush hardware updates:
+        */
+       trace_msm_atomic_flush_commit(crtc_mask);
+       kms->funcs->flush_commit(kms, crtc_mask);
+       mutex_unlock(&kms->commit_lock);
+
+       /*
+        * Wait for flush to complete:
+        */
+       trace_msm_atomic_wait_flush_start(crtc_mask);
+       kms->funcs->wait_flush(kms, crtc_mask);
+       trace_msm_atomic_wait_flush_finish(crtc_mask);
+
+       mutex_lock(&kms->commit_lock);
+       kms->funcs->complete_commit(kms, crtc_mask);
+       mutex_unlock(&kms->commit_lock);
+       kms->funcs->disable_commit(kms);
+
+       drm_atomic_helper_commit_hw_done(state);
        drm_atomic_helper_cleanup_planes(dev, state);
+
+       trace_msm_atomic_commit_tail_finish(async, crtc_mask);
 }
diff --git a/drivers/gpu/drm/msm/msm_atomic_trace.h b/drivers/gpu/drm/msm/msm_atomic_trace.h
new file mode 100644 (file)
index 0000000..b4ca0ed
--- /dev/null
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_MSM_GPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _MSM_GPU_TRACE_H_
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM drm_msm_atomic
+#define TRACE_INCLUDE_FILE msm_atomic_trace
+
+TRACE_EVENT(msm_atomic_commit_tail_start,
+           TP_PROTO(bool async, unsigned crtc_mask),
+           TP_ARGS(async, crtc_mask),
+           TP_STRUCT__entry(
+                   __field(bool, async)
+                   __field(u32, crtc_mask)
+                   ),
+           TP_fast_assign(
+                   __entry->async = async;
+                   __entry->crtc_mask = crtc_mask;
+                   ),
+           TP_printk("async=%d crtc_mask=%x",
+                   __entry->async, __entry->crtc_mask)
+);
+
+TRACE_EVENT(msm_atomic_commit_tail_finish,
+           TP_PROTO(bool async, unsigned crtc_mask),
+           TP_ARGS(async, crtc_mask),
+           TP_STRUCT__entry(
+                   __field(bool, async)
+                   __field(u32, crtc_mask)
+                   ),
+           TP_fast_assign(
+                   __entry->async = async;
+                   __entry->crtc_mask = crtc_mask;
+                   ),
+           TP_printk("async=%d crtc_mask=%x",
+                   __entry->async, __entry->crtc_mask)
+);
+
+TRACE_EVENT(msm_atomic_async_commit_start,
+           TP_PROTO(unsigned crtc_mask),
+           TP_ARGS(crtc_mask),
+           TP_STRUCT__entry(
+                   __field(u32, crtc_mask)
+                   ),
+           TP_fast_assign(
+                   __entry->crtc_mask = crtc_mask;
+                   ),
+           TP_printk("crtc_mask=%x",
+                   __entry->crtc_mask)
+);
+
+TRACE_EVENT(msm_atomic_async_commit_finish,
+           TP_PROTO(unsigned crtc_mask),
+           TP_ARGS(crtc_mask),
+           TP_STRUCT__entry(
+                   __field(u32, crtc_mask)
+                   ),
+           TP_fast_assign(
+                   __entry->crtc_mask = crtc_mask;
+                   ),
+           TP_printk("crtc_mask=%x",
+                   __entry->crtc_mask)
+);
+
+TRACE_EVENT(msm_atomic_wait_flush_start,
+           TP_PROTO(unsigned crtc_mask),
+           TP_ARGS(crtc_mask),
+           TP_STRUCT__entry(
+                   __field(u32, crtc_mask)
+                   ),
+           TP_fast_assign(
+                   __entry->crtc_mask = crtc_mask;
+                   ),
+           TP_printk("crtc_mask=%x",
+                   __entry->crtc_mask)
+);
+
+TRACE_EVENT(msm_atomic_wait_flush_finish,
+           TP_PROTO(unsigned crtc_mask),
+           TP_ARGS(crtc_mask),
+           TP_STRUCT__entry(
+                   __field(u32, crtc_mask)
+                   ),
+           TP_fast_assign(
+                   __entry->crtc_mask = crtc_mask;
+                   ),
+           TP_printk("crtc_mask=%x",
+                   __entry->crtc_mask)
+);
+
+TRACE_EVENT(msm_atomic_flush_commit,
+           TP_PROTO(unsigned crtc_mask),
+           TP_ARGS(crtc_mask),
+           TP_STRUCT__entry(
+                   __field(u32, crtc_mask)
+                   ),
+           TP_fast_assign(
+                   __entry->crtc_mask = crtc_mask;
+                   ),
+           TP_printk("crtc_mask=%x",
+                   __entry->crtc_mask)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/msm
+#include <trace/define_trace.h>
diff --git a/drivers/gpu/drm/msm/msm_atomic_tracepoints.c b/drivers/gpu/drm/msm/msm_atomic_tracepoints.c
new file mode 100644 (file)
index 0000000..011dc88
--- /dev/null
@@ -0,0 +1,3 @@
+// SPDX-License-Identifier: GPL-2.0
+#define CREATE_TRACE_POINTS
+#include "msm_atomic_trace.h"
index a0a8df5..6be8795 100644 (file)
@@ -5,7 +5,12 @@
  */
 
 #ifdef CONFIG_DEBUG_FS
+
 #include <linux/debugfs.h>
+
+#include <drm/drm_debugfs.h>
+#include <drm/drm_file.h>
+
 #include "msm_drv.h"
 #include "msm_gpu.h"
 #include "msm_kms.h"
index ee031c0..c84f0a8 100644 (file)
@@ -5,9 +5,18 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/kthread.h>
+#include <linux/uaccess.h>
 #include <uapi/linux/sched/types.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_irq.h>
+#include <drm/drm_prime.h>
 #include <drm/drm_of.h>
+#include <drm/drm_vblank.h>
 
 #include "msm_drv.h"
 #include "msm_debugfs.h"
@@ -17,7 +26,6 @@
 #include "msm_kms.h"
 #include "adreno/adreno_gpu.h"
 
-
 /*
  * MSM driver version:
  * - 1.0.0 - initial interface
@@ -75,46 +83,6 @@ module_param(modeset, bool, 0600);
  * Util/helpers:
  */
 
-int msm_clk_bulk_get(struct device *dev, struct clk_bulk_data **bulk)
-{
-       struct property *prop;
-       const char *name;
-       struct clk_bulk_data *local;
-       int i = 0, ret, count;
-
-       count = of_property_count_strings(dev->of_node, "clock-names");
-       if (count < 1)
-               return 0;
-
-       local = devm_kcalloc(dev, sizeof(struct clk_bulk_data *),
-               count, GFP_KERNEL);
-       if (!local)
-               return -ENOMEM;
-
-       of_property_for_each_string(dev->of_node, "clock-names", prop, name) {
-               local[i].id = devm_kstrdup(dev, name, GFP_KERNEL);
-               if (!local[i].id) {
-                       devm_kfree(dev, local);
-                       return -ENOMEM;
-               }
-
-               i++;
-       }
-
-       ret = devm_clk_bulk_get(dev, count, local);
-
-       if (ret) {
-               for (i = 0; i < count; i++)
-                       devm_kfree(dev, (void *) local[i].id);
-               devm_kfree(dev, local);
-
-               return ret;
-       }
-
-       *bulk = local;
-       return count;
-}
-
 struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count,
                const char *name)
 {
@@ -505,6 +473,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)
        ddev->mode_config.normalize_zpos = true;
 
        if (kms) {
+               kms->dev = ddev;
                ret = kms->funcs->hw_init(kms);
                if (ret) {
                        DRM_DEV_ERROR(dev, "kms hw init failed: %d\n", ret);
index ee7b512..71547e7 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/sizes.h>
 #include <linux/kthread.h>
 
-#include <drm/drmP.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
@@ -222,8 +221,12 @@ struct msm_format {
        uint32_t pixel_format;
 };
 
+struct msm_pending_timer;
+
 int msm_atomic_prepare_fb(struct drm_plane *plane,
                          struct drm_plane_state *new_state);
+void msm_atomic_init_pending_timer(struct msm_pending_timer *timer,
+               struct msm_kms *kms, int crtc_idx);
 void msm_atomic_commit_tail(struct drm_atomic_state *state);
 struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev);
 void msm_atomic_state_clear(struct drm_atomic_state *state);
@@ -399,7 +402,6 @@ static inline void msm_perf_debugfs_cleanup(struct msm_drm_private *priv) {}
 #endif
 
 struct clk *msm_clk_get(struct platform_device *pdev, const char *name);
-int msm_clk_bulk_get(struct device *dev, struct clk_bulk_data **bulk);
 
 struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count,
        const char *name);
index 5bcd5e5..37674e8 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <drm/drm_crtc.h>
 #include <drm/drm_damage_helper.h>
+#include <drm/drm_file.h>
+#include <drm/drm_fourcc.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_probe_helper.h>
 
index 2429d5e..cff198b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <drm/drm_crtc.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
 
 #include "msm_drv.h"
 #include "msm_kms.h"
@@ -169,6 +170,9 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
        if (ret)
                goto fini;
 
+       /* the fw fb could be anywhere in memory */
+       drm_fb_helper_remove_conflicting_framebuffers(NULL, "msm", false);
+
        ret = drm_fb_helper_initial_config(helper, 32);
        if (ret)
                goto fini;
index 0c2a125..5a6a79f 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/dma-buf.h>
 #include <linux/pfn_t.h>
 
+#include <drm/drm_prime.h>
+
 #include "msm_drv.h"
 #include "msm_fence.h"
 #include "msm_gem.h"
@@ -50,7 +52,7 @@ static void sync_for_device(struct msm_gem_object *msm_obj)
 {
        struct device *dev = msm_obj->base.dev->dev;
 
-       if (get_dma_ops(dev)) {
+       if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {
                dma_sync_sg_for_device(dev, msm_obj->sgt->sgl,
                        msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
        } else {
@@ -63,7 +65,7 @@ static void sync_for_cpu(struct msm_gem_object *msm_obj)
 {
        struct device *dev = msm_obj->base.dev->dev;
 
-       if (get_dma_ops(dev)) {
+       if (get_dma_ops(dev) && IS_ENABLED(CONFIG_ARM64)) {
                dma_sync_sg_for_cpu(dev, msm_obj->sgt->sgl,
                        msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
        } else {
index 5d64e06..d7c8948 100644 (file)
@@ -4,11 +4,13 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <linux/dma-buf.h>
+
+#include <drm/drm_prime.h>
+
 #include "msm_drv.h"
 #include "msm_gem.h"
 
-#include <linux/dma-buf.h>
-
 struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
 {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
index 2e1556b..be5327a 100644 (file)
@@ -4,7 +4,11 @@
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
+#include <linux/file.h>
 #include <linux/sync_file.h>
+#include <linux/uaccess.h>
+
+#include <drm/drm_file.h>
 
 #include "msm_drv.h"
 #include "msm_gpu.h"
@@ -26,8 +30,8 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
                uint32_t nr_cmds)
 {
        struct msm_gem_submit *submit;
-       uint64_t sz = sizeof(*submit) + ((u64)nr_bos * sizeof(submit->bos[0])) +
-               ((u64)nr_cmds * sizeof(submit->cmd[0]));
+       uint64_t sz = struct_size(submit, bos, nr_bos) +
+                                 ((u64)nr_cmds * sizeof(submit->cmd[0]));
 
        if (sz > SIZE_MAX)
                return NULL;
index f7308d6..a052364 100644 (file)
@@ -784,7 +784,7 @@ static irqreturn_t irq_handler(int irq, void *data)
 
 static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu)
 {
-       int ret = msm_clk_bulk_get(&pdev->dev, &gpu->grp_clks);
+       int ret = devm_clk_bulk_get_all(&pdev->dev, &gpu->grp_clks);
 
        if (ret < 1) {
                gpu->nr_clocks = 0;
index 1155118..122b847 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/tracepoint.h>
 
 #undef TRACE_SYSTEM
-#define TRACE_SYSTEM drm_msm
+#define TRACE_SYSTEM drm_msm_gpu
 #define TRACE_INCLUDE_FILE msm_gpu_trace
 
 TRACE_EVENT(msm_gpu_submit,
index 27312b5..34f643a 100644 (file)
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2018 The Linux Foundation. All rights reserved. */
 
+#include <linux/dma-mapping.h>
+
 #include "msm_drv.h"
 #include "msm_mmu.h"
 #include "adreno/adreno_gpu.h"
index c7588a4..1cbef6b 100644 (file)
@@ -30,13 +30,76 @@ struct msm_kms_funcs {
        irqreturn_t (*irq)(struct msm_kms *kms);
        int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
        void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
-       /* modeset, bracketing atomic_commit(): */
+
+       /*
+        * Atomic commit handling:
+        *
+        * Note that in the case of async commits, the funcs which take
+        * a crtc_mask (ie. ->flush_commit(), and ->complete_commit())
+        * might not be evenly balanced with ->prepare_commit(), however
+        * each crtc that effected by a ->prepare_commit() (potentially
+        * multiple times) will eventually (at end of vsync period) be
+        * flushed and completed.
+        *
+        * This has some implications about tracking of cleanup state,
+        * for example SMP blocks to release after commit completes.  Ie.
+        * cleanup state should be also duplicated in the various
+        * duplicate_state() methods, as the current cleanup state at
+        * ->complete_commit() time may have accumulated cleanup work
+        * from multiple commits.
+        */
+
+       /**
+        * Enable/disable power/clks needed for hw access done in other
+        * commit related methods.
+        *
+        * If mdp4 is migrated to runpm, we could probably drop these
+        * and use runpm directly.
+        */
+       void (*enable_commit)(struct msm_kms *kms);
+       void (*disable_commit)(struct msm_kms *kms);
+
+       /**
+        * If the kms backend supports async commit, it should implement
+        * this method to return the time of the next vsync.  This is
+        * used to determine a time slightly before vsync, for the async
+        * commit timer to run and complete an async commit.
+        */
+       ktime_t (*vsync_time)(struct msm_kms *kms, struct drm_crtc *crtc);
+
+       /**
+        * Prepare for atomic commit.  This is called after any previous
+        * (async or otherwise) commit has completed.
+        */
        void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state);
-       void (*commit)(struct msm_kms *kms, struct drm_atomic_state *state);
-       void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state);
-       /* functions to wait for atomic commit completed on each CRTC */
-       void (*wait_for_crtc_commit_done)(struct msm_kms *kms,
-                                       struct drm_crtc *crtc);
+
+       /**
+        * Flush an atomic commit.  This is called after the hardware
+        * updates have already been pushed down to effected planes/
+        * crtcs/encoders/connectors.
+        */
+       void (*flush_commit)(struct msm_kms *kms, unsigned crtc_mask);
+
+       /**
+        * Wait for any in-progress flush to complete on the specified
+        * crtcs.  This should not block if there is no in-progress
+        * commit (ie. don't just wait for a vblank), as it will also
+        * be called before ->prepare_commit() to ensure any potential
+        * "async" commit has completed.
+        */
+       void (*wait_flush)(struct msm_kms *kms, unsigned crtc_mask);
+
+       /**
+        * Clean up after commit is completed.  This is called after
+        * ->wait_flush(), to give the backend a chance to do any
+        * post-commit cleanup.
+        */
+       void (*complete_commit)(struct msm_kms *kms, unsigned crtc_mask);
+
+       /*
+        * Format handling:
+        */
+
        /* get msm_format w/ optional format modifiers from drm_mode_fb_cmd2 */
        const struct msm_format *(*get_format)(struct msm_kms *kms,
                                        const uint32_t format,
@@ -46,6 +109,7 @@ struct msm_kms_funcs {
                        const struct msm_format *msm_fmt,
                        const struct drm_mode_fb_cmd2 *cmd,
                        struct drm_gem_object **bos);
+
        /* misc: */
        long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
                        struct drm_encoder *encoder);
@@ -64,20 +128,48 @@ struct msm_kms_funcs {
 #endif
 };
 
+struct msm_kms;
+
+/*
+ * A per-crtc timer for pending async atomic flushes.  Scheduled to expire
+ * shortly before vblank to flush pending async updates.
+ */
+struct msm_pending_timer {
+       struct hrtimer timer;
+       struct work_struct work;
+       struct msm_kms *kms;
+       unsigned crtc_idx;
+};
+
 struct msm_kms {
        const struct msm_kms_funcs *funcs;
+       struct drm_device *dev;
 
        /* irq number to be passed on to drm_irq_install */
        int irq;
 
        /* mapper-id used to request GEM buffer mapped for scanout: */
        struct msm_gem_address_space *aspace;
+
+       /*
+        * For async commit, where ->flush_commit() and later happens
+        * from the crtc's pending_timer close to end of the frame:
+        */
+       struct mutex commit_lock;
+       unsigned pending_crtc_mask;
+       struct msm_pending_timer pending_timers[MAX_CRTCS];
 };
 
 static inline void msm_kms_init(struct msm_kms *kms,
                const struct msm_kms_funcs *funcs)
 {
+       unsigned i;
+
+       mutex_init(&kms->commit_lock);
        kms->funcs = funcs;
+
+       for (i = 0; i < ARRAY_SIZE(kms->pending_timers); i++)
+               msm_atomic_init_pending_timer(&kms->pending_timers[i], kms, i);
 }
 
 struct msm_kms *mdp4_kms_init(struct drm_device *dev);
@@ -98,4 +190,8 @@ struct msm_mdss {
 int mdp5_mdss_init(struct drm_device *dev);
 int dpu_mdss_init(struct drm_device *dev);
 
+#define for_each_crtc_mask(dev, crtc, crtc_mask) \
+       drm_for_each_crtc(crtc, dev) \
+               for_each_if (drm_crtc_mask(crtc) & (crtc_mask))
+
 #endif /* __MSM_KMS_H__ */
index 490cadd..3a27153 100644 (file)
@@ -15,6 +15,9 @@
 #ifdef CONFIG_DEBUG_FS
 
 #include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <drm/drm_file.h>
 
 #include "msm_drv.h"
 #include "msm_gpu.h"
index 76d3fdd..c7832a9 100644 (file)
 
 #ifdef CONFIG_DEBUG_FS
 
-#include <linux/kfifo.h>
-#include <linux/debugfs.h>
 #include <linux/circ_buf.h>
+#include <linux/debugfs.h>
+#include <linux/kfifo.h>
+#include <linux/uaccess.h>
 #include <linux/wait.h>
 
+#include <drm/drm_file.h>
+
 #include "msm_drv.h"
 #include "msm_gpu.h"
 #include "msm_gem.h"
index c70e00e..001fbf5 100644 (file)
@@ -3,6 +3,8 @@
  */
 
 #include <linux/kref.h>
+#include <linux/uaccess.h>
+
 #include "msm_gpu.h"
 
 void msm_submitqueue_destroy(struct kref *kref)