summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLloyd Atkinson <latkinso@codeaurora.org>2016-07-05 12:23:29 -0400
committerDhaval Patel <pdhaval@codeaurora.org>2016-08-01 11:58:08 -0700
commitad84d148e1219ff4d6299847ec29d7ab70616e9f (patch)
tree521d04a5f9254250fbb0e74c14602df6ce1ad7f4
parent0527ae787b14f5e9ccd1737b5f998fc6f22742bd (diff)
drm/msm/sde: set encoder role at display probe time
Base the encoder's master/slave role on display probe. Move interface select programming fully to the mdp_top block. Fix vblank_en race condition in CRTC. Change-Id: I4a26509a0ac28e0926b8bea90c5aaa5707a37e21 Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.c41
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.h4
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c167
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys.h104
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c220
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_intf.c40
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c1
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.h13
8 files changed, 352 insertions, 238 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index e8d27cfe8b82..786dd63a7a22 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -197,8 +197,8 @@ static void sde_crtc_mode_set_nofb(struct drm_crtc *crtc)
static void sde_crtc_get_blend_cfg(struct sde_hw_blend_cfg *cfg,
struct sde_plane_state *pstate)
{
- const struct mdp_format *format;
struct drm_plane *plane;
+ const struct mdp_format *format;
format = to_mdp_format(
msm_framebuffer_format(pstate->base.fb));
@@ -241,6 +241,16 @@ static void sde_crtc_get_blend_cfg(struct sde_hw_blend_cfg *cfg,
cfg->fg.const_alpha = 0xFF;
cfg->bg.const_alpha = 0x00;
}
+
+ DBG("format 0x%x, alpha_enable %u premultiplied %llu",
+ format->base.pixel_format, format->alpha_enable,
+ pstate->property_values[PLANE_PROP_PREMULTIPLIED]);
+ DBG("fg alpha config %d %d %d %d %d",
+ cfg->fg.alpha_sel, cfg->fg.const_alpha, cfg->fg.mod_alpha,
+ cfg->fg.inv_alpha_sel, cfg->fg.inv_mode_alpha);
+ DBG("bg alpha config %d %d %d %d %d",
+ cfg->bg.alpha_sel, cfg->bg.const_alpha, cfg->bg.mod_alpha,
+ cfg->bg.inv_alpha_sel, cfg->bg.inv_mode_alpha);
}
static void blend_setup(struct drm_crtc *crtc)
@@ -312,10 +322,9 @@ static void blend_setup(struct drm_crtc *crtc)
* If there is no base layer, enable border color.
* currently border color is always black
*/
- if ((stage_cfg.stage[SDE_STAGE_BASE][0] == SSPP_NONE) &&
- plane_cnt) {
+ if ((stage_cfg.stage[SDE_STAGE_BASE][0] == SSPP_NONE) && plane_cnt) {
stage_cfg.border_enable = 1;
- DBG("Border Color is enabled\n");
+ DBG("Border Color is enabled");
}
/* Program ctl_paths */
@@ -371,7 +380,7 @@ static void sde_crtc_vblank_cb(void *data)
if (pending & PENDING_FLIP)
complete_flip(crtc, NULL);
- if (sde_crtc->vblank_enable) {
+ if (sde_crtc->drm_requested_vblank) {
drm_handle_vblank(dev, sde_crtc->id);
DBG_IRQ("");
}
@@ -381,9 +390,13 @@ static bool frame_flushed(struct sde_crtc *sde_crtc)
{
struct vsync_info vsync;
- /* encoder get vsync_info */
- /* if frame_count does not match frame is flushed */
- sde_encoder_get_vsync_info(sde_crtc->encoder, &vsync);
+ /*
+ * encoder get vsync_info
+ * if frame_count does not match
+ * frame is flushed
+ */
+ sde_encoder_get_vblank_status(sde_crtc->encoder, &vsync);
+
return (vsync.frame_count != sde_crtc->vsync_count) ? true : false;
}
@@ -422,7 +435,7 @@ static void request_pending(struct drm_crtc *crtc, u32 pending)
struct vsync_info vsync;
/* request vsync info, cache the current frame count */
- sde_encoder_get_vsync_info(sde_crtc->encoder, &vsync);
+ sde_encoder_get_vblank_status(sde_crtc->encoder, &vsync);
sde_crtc->vsync_count = vsync.frame_count;
atomic_or(pending, &sde_crtc->pending);
@@ -634,6 +647,15 @@ int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
DBG("%d", en);
+
+ /*
+ * Mark that framework requested vblank,
+ * as opposed to enabling vblank only for our internal purposes
+ * Currently this variable isn't required, but may be useful for future
+ * features
+ */
+ sde_crtc->drm_requested_vblank = en;
+
if (en)
sde_encoder_register_vblank_callback(sde_crtc->encoder,
sde_crtc_vblank_cb, (void *)crtc);
@@ -641,7 +663,6 @@ int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
sde_encoder_register_vblank_callback(sde_crtc->encoder,
NULL, NULL);
- sde_crtc->vblank_enable = en;
return 0;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index fa54d805ddf2..bf4bbc104f88 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -52,7 +52,7 @@ struct sde_crtc_mixer {
* @event : Pointer to last received drm vblank event
* @pending : Whether or not an update is pending
* @vsync_count : Running count of received vsync events
- * @vblank_enable : Whether vblanks have been enabled in the encoder
+ * @drm_requested_vblank : Whether vblanks have been enabled in the encoder
*/
struct sde_crtc {
struct drm_crtc base;
@@ -71,7 +71,7 @@ struct sde_crtc {
struct drm_pending_vblank_event *event;
atomic_t pending;
u32 vsync_count;
- bool vblank_enable;
+ bool drm_requested_vblank;
};
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 642c668fc01e..bea9a30cb1dd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -24,6 +24,40 @@
#include "sde_encoder_phys.h"
#include "display_manager.h"
+#define NUM_PHYS_ENCODER_TYPES 2
+#define MAX_PHYS_ENCODERS_PER_VIRTUAL \
+ (MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES)
+
+/**
+ * struct sde_encoder_virt - virtual encoder. Container of one or more physical
+ * encoders. Virtual encoder manages one "logical" display. Physical
+ * encoders manage one intf block, tied to a specific panel/sub-panel.
+ * Virtual encoder defers as much as possible to the physical encoders.
+ * Virtual encoder registers itself with the DRM Framework as the encoder.
+ * @base: drm_encoder base class for registration with DRM
+ * @spin_lock: Lock for IRQ purposes
+ * @bus_scaling_client: Client handle to the bus scaling interface
+ * @num_phys_encs: Actual number of physical encoders contained.
+ * @phys_encs: Container of physical encoders managed.
+ * @cur_master: Pointer to the current master in this mode. Optimization
+ * Only valid after enable. Cleared as disable.
+ * @kms_vblank_callback: Callback into the upper layer / CRTC for
+ * notification of the VBLANK
+ * @kms_vblank_callback_data: Data from upper layer for VBLANK notification
+ */
+struct sde_encoder_virt {
+ struct drm_encoder base;
+ spinlock_t spin_lock;
+ uint32_t bus_scaling_client;
+
+ int num_phys_encs;
+ struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
+ struct sde_encoder_phys *cur_master;
+
+ void (*kms_vblank_callback)(void *);
+ void *kms_vblank_callback_data;
+};
+
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
#ifdef CONFIG_QCOM_BUS_SCALING
@@ -117,8 +151,8 @@ void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys && phys->phys_ops.get_hw_resources)
- phys->phys_ops.get_hw_resources(phys, hw_res);
+ if (phys && phys->ops.get_hw_resources)
+ phys->ops.get_hw_resources(phys, hw_res);
}
}
@@ -139,8 +173,8 @@ static void sde_encoder_destroy(struct drm_encoder *drm_enc)
for (i = 0; i < ARRAY_SIZE(sde_enc->phys_encs); i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys && phys->phys_ops.destroy) {
- phys->phys_ops.destroy(phys);
+ if (phys && phys->ops.destroy) {
+ phys->ops.destroy(phys);
--sde_enc->num_phys_encs;
sde_enc->phys_encs[i] = NULL;
}
@@ -176,12 +210,11 @@ static bool sde_encoder_virt_mode_fixup(struct drm_encoder *drm_enc,
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys && phys->phys_ops.mode_fixup) {
- ret =
- phys->phys_ops.mode_fixup(phys, mode,
- adjusted_mode);
+ if (phys && phys->ops.mode_fixup) {
+ ret = phys->ops.mode_fixup(phys, mode,
+ adjusted_mode);
if (!ret) {
- DBG("Mode unsupported by phys_enc %d", i);
+ DRM_ERROR("Mode unsupported, phys_enc %d\n", i);
break;
}
@@ -201,7 +234,6 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
{
struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
- bool splitmode = false;
DBG("");
@@ -212,23 +244,10 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
sde_enc = to_sde_encoder_virt(drm_enc);
- /*
- * Panel is driven by two interfaces ,each interface drives half of
- * the horizontal
- */
- if (sde_enc->num_phys_encs == 2)
- splitmode = true;
-
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys) {
- phys->phys_ops.mode_set(phys,
- mode,
- adjusted_mode,
- splitmode);
- if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0)
- DRM_ERROR("adjusted modes not supported\n");
- }
+ if (phys && phys->ops.mode_set)
+ phys->ops.mode_set(phys, mode, adjusted_mode);
}
}
@@ -236,7 +255,6 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
- bool splitmode = false;
DBG("");
@@ -249,21 +267,22 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
bs_set(sde_enc, 1);
- if (sde_enc->num_phys_encs == 2)
- splitmode = true;
-
-
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys && phys->phys_ops.enable) {
- /* enable/disable dual interface top config */
- if (phys->phys_ops.enable_split_config)
- phys->phys_ops.enable_split_config(phys,
- splitmode);
+
+ if (phys) {
+ if (phys->ops.enable)
+ phys->ops.enable(phys);
+
/*
- * enable interrupts on master only
+ * Master can switch at enable time.
+ * It is based on the current mode (CMD/VID) and
+ * the encoder role found at panel probe time
*/
- phys->phys_ops.enable(phys, (i == 0) ? true : false);
+ if (phys->ops.is_master && phys->ops.is_master(phys)) {
+ DBG("phys enc master is now idx %d", i);
+ sde_enc->cur_master = phys;
+ }
}
}
}
@@ -285,10 +304,13 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys && phys->phys_ops.disable)
- phys->phys_ops.disable(phys);
+ if (phys && phys->ops.disable)
+ phys->ops.disable(phys);
}
+ sde_enc->cur_master = NULL;
+ DBG("clear phys enc master");
+
bs_set(sde_enc, 0);
}
@@ -338,10 +360,12 @@ static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc)
spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags);
}
-static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder_virt *sde_enc,
- struct sde_kms *sde_kms,
- enum sde_intf intf_idx,
- enum sde_ctl ctl_idx)
+static int sde_encoder_virt_add_phys_vid_enc(
+ struct sde_encoder_virt *sde_enc,
+ struct sde_kms *sde_kms,
+ enum sde_intf intf_idx,
+ enum sde_ctl ctl_idx,
+ enum sde_enc_split_role split_role)
{
int ret = 0;
@@ -357,12 +381,12 @@ static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder_virt *sde_enc,
};
struct sde_encoder_phys *enc =
sde_encoder_phys_vid_init(sde_kms, intf_idx, ctl_idx,
- &sde_enc->base,
- parent_ops);
- if (IS_ERR(enc))
- ret = PTR_ERR(enc);
-
- if (!ret) {
+ split_role, &sde_enc->base, parent_ops);
+ if (IS_ERR_OR_NULL(enc)) {
+ DRM_ERROR("Failed to initialize phys enc: %ld\n",
+ PTR_ERR(enc));
+ ret = enc == 0 ? -EINVAL : PTR_ERR(enc);
+ } else {
sde_enc->phys_encs[sde_enc->num_phys_encs] = enc;
++sde_enc->num_phys_encs;
}
@@ -407,26 +431,36 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc,
enum sde_intf intf_idx = INTF_MAX;
enum sde_ctl ctl_idx = CTL_MAX;
u32 controller_id = disp_info->h_tile_instance[i];
+ enum sde_enc_split_role split_role = ENC_ROLE_SOLO;
+
+ if (disp_info->num_of_h_tiles > 1) {
+ if (i == 0)
+ split_role = ENC_ROLE_MASTER;
+ else
+ split_role = ENC_ROLE_SLAVE;
+ }
- DBG("h_tile_instance %d = %d", i, controller_id);
+ DBG("h_tile_instance %d = %d, split_role %d",
+ i, controller_id, split_role);
intf_idx = sde_encoder_get_intf(sde_kms->catalog,
intf_type, controller_id);
if (intf_idx == INTF_MAX) {
- DBG("Error: could not get the interface id");
+ DRM_ERROR("Error: could not get the interface id\n");
ret = -EINVAL;
}
hw_res_map = sde_rm_get_res_map(sde_kms, intf_idx);
- if (IS_ERR_OR_NULL(hw_res_map))
+ if (IS_ERR_OR_NULL(hw_res_map)) {
ret = -EINVAL;
- else
+ } else {
ctl_idx = hw_res_map->ctl;
-
- /* Create both VID and CMD Phys Encoders here */
- if (!ret)
ret = sde_encoder_virt_add_phys_vid_enc(
- sde_enc, sde_kms, intf_idx, ctl_idx);
+ sde_enc, sde_kms, intf_idx, ctl_idx,
+ split_role);
+ if (ret)
+ DRM_ERROR("Failed to add phys enc\n");
+ }
}
@@ -456,6 +490,7 @@ static struct drm_encoder *sde_encoder_virt_init(
if (ret)
goto fail;
+ sde_enc->cur_master = NULL;
spin_lock_init(&sde_enc->spin_lock);
drm_enc = &sde_enc->base;
drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode);
@@ -488,23 +523,25 @@ void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc,
spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags);
}
-void sde_encoder_get_vsync_info(struct drm_encoder *drm_enc,
+void sde_encoder_get_vblank_status(struct drm_encoder *drm_enc,
struct vsync_info *vsync)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
- struct sde_encoder_phys *phys;
+ struct sde_encoder_virt *sde_enc = NULL;
+ struct sde_encoder_phys *master = NULL;
DBG("");
- if (!vsync) {
+ if (!vsync || !drm_enc) {
DRM_ERROR("Invalid pointer");
return;
}
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
+ memset(vsync, 0, sizeof(*vsync));
- /* we get the vsync info from the intf at index 0: master index */
- phys = sde_enc->phys_encs[0];
- if (phys)
- phys->phys_ops.get_vsync_info(phys, vsync);
+ master = sde_enc->cur_master;
+ if (master && master->ops.get_vblank_status)
+ master->ops.get_vblank_status(master, vsync);
}
/* encoders init,
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 45935bb858bd..e6ee7284fcf1 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -19,42 +19,95 @@
#include "sde_hw_intf.h"
#include "sde_hw_mdp_ctl.h"
-#define MAX_PHYS_ENCODERS_PER_VIRTUAL 4
+/**
+ * enum sde_enc_split_role - Role this physical encoder will play in a
+ * split-panel configuration, where one panel is master, and others slaves.
+ * Masters have extra responsibilities, like managing the VBLANK IRQ.
+ * @ENC_ROLE_SOLO: This is the one and only panel. This encoder is master.
+ * @ENC_ROLE_MASTER: This encoder is the master of a split panel config.
+ * @ENC_ROLE_SLAVE: This encoder is not the master of a split panel config.
+ */
+enum sde_enc_split_role {
+ ENC_ROLE_SOLO,
+ ENC_ROLE_MASTER,
+ ENC_ROLE_SLAVE
+};
struct sde_encoder_phys;
+/**
+ * struct sde_encoder_virt_ops - Interface the containing virtual encoder
+ * provides for the physical encoders to use to callback.
+ * @handle_vblank_virt: Notify virtual encoder of vblank IRQ reception
+ * Note: This is called from IRQ handler context.
+ */
struct sde_encoder_virt_ops {
void (*handle_vblank_virt)(struct drm_encoder *);
};
+/**
+ * struct sde_encoder_phys_ops - Interface the physical encoders provide to
+ * the containing virtual encoder.
+ * @is_master: Whether this phys_enc is the current master
+ * encoder. Can be switched at enable time. Based
+ * on split_role and current mode (CMD/VID).
+ * @mode_fixup: DRM Call. Fixup a DRM mode.
+ * @mode_set: DRM Call. Set a DRM mode.
+ * This likely caches the mode, for use at enable.
+ * @enable: DRM Call. Enable a DRM mode.
+ * @disable: DRM Call. Disable mode.
+ * @destroy: DRM Call. Destroy and release resources.
+ * @get_hw_resources: Populate the structure with the hardware
+ * resources that this phys_enc is using.
+ * Expect no overlap between phys_encs.
+ * @get_vblank_status: Query hardware for the vblank info
+ * appropriate for this phys_enc (vsync/pprdptr).
+ * Only appropriate for master phys_enc.
+ */
struct sde_encoder_phys_ops {
- void (*mode_set)(struct sde_encoder_phys *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- bool splitmode);
+ bool (*is_master)(struct sde_encoder_phys *encoder);
bool (*mode_fixup)(struct sde_encoder_phys *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
- void (*enable)(struct sde_encoder_phys *encoder, bool intr_en);
+ void (*mode_set)(struct sde_encoder_phys *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+ void (*enable)(struct sde_encoder_phys *encoder);
void (*disable)(struct sde_encoder_phys *encoder);
void (*destroy)(struct sde_encoder_phys *encoder);
void (*get_hw_resources)(struct sde_encoder_phys *encoder,
struct sde_encoder_hw_resources *hw_res);
- void (*get_vsync_info)(struct sde_encoder_phys *enc,
+ void (*get_vblank_status)(struct sde_encoder_phys *enc,
struct vsync_info *vsync);
- void (*enable_split_config)(struct sde_encoder_phys *enc,
- bool enable);
};
+/**
+ * struct sde_encoder_phys - physical encoder that drives a single INTF block
+ * tied to a specific panel / sub-panel. Abstract type, sub-classed by
+ * phys_vid or phys_cmd for video mode or command mode encs respectively.
+ * @parent: Pointer to the containing virtual encoder
+ * @ops: Operations exposed to the virtual encoder
+ * @parent_ops: Callbacks exposed by the parent to the phys_enc
+ * @hw_mdptop: Hardware interface to the top registers
+ * @hw_intf: Hardware interface to the intf registers
+ * @hw_ctl: Hardware interface to the ctl registers
+ * @sde_kms: Pointer to the sde_kms top level
+ * @cached_mode: DRM mode cached at mode_set time, acted on in enable
+ * @enabled: Whether the encoder has enabled and running a mode
+ * @split_role: Role to play in a split-panel configuration
+ * @spin_lock: Lock for IRQ purposes
+ */
struct sde_encoder_phys {
struct drm_encoder *parent;
+ struct sde_encoder_phys_ops ops;
struct sde_encoder_virt_ops parent_ops;
- struct sde_encoder_phys_ops phys_ops;
+ struct sde_hw_mdp *hw_mdptop;
struct sde_hw_intf *hw_intf;
struct sde_hw_ctl *hw_ctl;
struct sde_kms *sde_kms;
struct drm_display_mode cached_mode;
bool enabled;
+ enum sde_enc_split_role split_role;
spinlock_t spin_lock;
};
@@ -69,26 +122,25 @@ struct sde_encoder_phys_vid {
struct sde_encoder_phys base;
int irq_idx;
struct completion vblank_complete;
- bool intr_en;
};
-struct sde_encoder_virt {
- struct drm_encoder base;
- spinlock_t spin_lock;
- uint32_t bus_scaling_client;
-
- int num_phys_encs;
- struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
-
- void (*kms_vblank_callback)(void *);
- void *kms_vblank_callback_data;
-};
-
-struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
+/**
+ * sde_encoder_phys_vid_init - Construct a new video mode physical encoder
+ * @sde_kms: Pointer to the sde_kms top level
+ * @intf_idx: Interface index this phys_enc will control
+ * @ctl_idx: Control index this phys_enc requires
+ * @split_role: Role to play in a split-panel configuration
+ * @parent: Pointer to the containing virtual encoder
+ * @parent_ops: Callbacks exposed by the parent to the phys_enc
+ *
+ * Return: Error code or newly allocated encoder
+ */
+struct sde_encoder_phys *sde_encoder_phys_vid_init(
+ struct sde_kms *sde_kms,
enum sde_intf intf_idx,
enum sde_ctl ctl_idx,
+ enum sde_enc_split_role split_role,
struct drm_encoder *parent,
- struct sde_encoder_virt_ops
- parent_ops);
+ struct sde_encoder_virt_ops parent_ops);
#endif /* __sde_encoder_phys_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 4d38fd326b6e..8c220b99ceb4 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -27,7 +27,10 @@
static bool sde_encoder_phys_vid_is_master(
struct sde_encoder_phys *phys_enc)
{
- bool ret = true;
+ bool ret = false;
+
+ if (phys_enc->split_role != ENC_ROLE_SLAVE)
+ ret = true;
return ret;
}
@@ -145,7 +148,7 @@ static u32 programmable_fetch_get_num_lines(
} else if (timing->v_front_porch < needed_vfp_lines) {
/* Warn fetch needed, but not enough porch in panel config */
pr_warn_once
- ("low vbp+vfp may lead to perf issues in some cases\n");
+ ("low vbp+vfp may lead to perf issues in some cases\n");
DBG("Less vfp than fetch requires, using entire vfp");
actual_vfp_lines = timing->v_front_porch;
} else {
@@ -216,49 +219,23 @@ static bool sde_encoder_phys_vid_mode_fixup(
return true;
}
-static void sde_encoder_phys_vid_flush_intf(struct sde_encoder_phys *phys_enc)
-{
- struct sde_hw_intf *intf = phys_enc->hw_intf;
- struct sde_hw_ctl *ctl = phys_enc->hw_ctl;
- u32 flush_mask = 0;
-
- DBG("");
-
- ctl->ops.get_bitmask_intf(ctl, &flush_mask, intf->idx);
- ctl->ops.setup_flush(ctl, flush_mask);
-
- DBG("Flushing CTL_ID %d, flush_mask %x, INTF %d",
- ctl->idx, flush_mask, intf->idx);
-}
-
-static void sde_encoder_phys_vid_mode_set(struct sde_encoder_phys *phys_enc,
- struct drm_display_mode *mode,
- struct drm_display_mode
- *adjusted_mode,
- bool splitmode)
+static void sde_encoder_phys_vid_mode_set(
+ struct sde_encoder_phys *phys_enc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
mode = adjusted_mode;
phys_enc->cached_mode = *adjusted_mode;
- if (splitmode) {
- phys_enc->cached_mode.hdisplay >>= 1;
- phys_enc->cached_mode.htotal >>= 1;
- phys_enc->cached_mode.hsync_start >>= 1;
- phys_enc->cached_mode.hsync_end >>= 1;
- }
-
- DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
- mode->base.id, mode->name, mode->vrefresh, mode->clock,
- mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
- mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
- mode->type, mode->flags);
+ DBG("intf %d, caching mode:", phys_enc->hw_intf->idx);
+ drm_mode_debug_printmodeline(mode);
}
static void sde_encoder_phys_vid_setup_timing_engine(
struct sde_encoder_phys *phys_enc)
{
struct drm_display_mode *mode = &phys_enc->cached_mode;
- struct intf_timing_params p = { 0 };
- struct sde_mdp_format_params *sde_fmt_params = NULL;
+ struct intf_timing_params timing_params = { 0 };
+ struct sde_mdp_format_params *fmt_params = NULL;
u32 fmt_fourcc = DRM_FORMAT_RGB888;
u32 fmt_mod = 0;
unsigned long lock_flags;
@@ -270,26 +247,37 @@ static void sde_encoder_phys_vid_setup_timing_engine(
if (WARN_ON(!phys_enc->hw_ctl->ops.setup_intf_cfg))
return;
- DBG("enable mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
- mode->base.id, mode->name, mode->vrefresh, mode->clock,
- mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
- mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
- mode->type, mode->flags);
- drm_mode_to_intf_timing_params(phys_enc, mode, &p);
+ DBG("intf %d, enabling mode:", phys_enc->hw_intf->idx);
+ drm_mode_debug_printmodeline(mode);
+
+ if (phys_enc->split_role != ENC_ROLE_SOLO) {
+ mode->hdisplay >>= 1;
+ mode->htotal >>= 1;
+ mode->hsync_start >>= 1;
+ mode->hsync_end >>= 1;
+
+ DBG("split_role %d, halve horizontal: %d %d %d %d",
+ phys_enc->split_role,
+ mode->hdisplay, mode->htotal,
+ mode->hsync_start, mode->hsync_end);
+ }
+
+ drm_mode_to_intf_timing_params(phys_enc, mode, &timing_params);
- sde_fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod);
+ fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod);
+ DBG("fmt_fourcc %d, fmt_mod %d", fmt_fourcc, fmt_mod);
intf_cfg.intf = phys_enc->hw_intf->idx;
intf_cfg.wb = SDE_NONE;
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
- phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &p,
- sde_fmt_params);
+ phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf,
+ &timing_params, fmt_params);
phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
- programmable_fetch_config(phys_enc, &p);
+ programmable_fetch_config(phys_enc, &timing_params);
}
static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
@@ -306,7 +294,7 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
static int sde_encoder_phys_vid_register_irq(struct sde_encoder_phys *phys_enc)
{
struct sde_encoder_phys_vid *vid_enc =
- to_sde_encoder_phys_vid(phys_enc);
+ to_sde_encoder_phys_vid(phys_enc);
struct sde_irq_callback irq_cb;
int ret = 0;
@@ -365,11 +353,31 @@ static int sde_encoder_phys_vid_unregister_irq(
return 0;
}
-static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc,
- bool intr_en)
+static void sde_encoder_phys_vid_split_config(
+ struct sde_encoder_phys *phys_enc, bool enable)
+{
+ struct sde_hw_mdp *hw_mdptop = phys_enc->hw_mdptop;
+ struct split_pipe_cfg cfg = { 0 };
+
+ DBG("enable %d", enable);
+
+ cfg.en = enable;
+ cfg.mode = INTF_MODE_VIDEO;
+ cfg.intf = phys_enc->hw_intf->idx;
+ cfg.pp_split = false;
+ cfg.split_flush_en = enable;
+
+ if (hw_mdptop && hw_mdptop->ops.setup_split_pipe) {
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
+ hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
+ spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
+ }
+}
+
+static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc)
{
- struct sde_encoder_phys_vid *vid_enc =
- to_sde_encoder_phys_vid(phys_enc);
int ret = 0;
DBG("");
@@ -377,18 +385,18 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc,
if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing))
return;
- sde_encoder_phys_vid_setup_timing_engine(phys_enc);
+ if (phys_enc->split_role == ENC_ROLE_MASTER)
+ sde_encoder_phys_vid_split_config(phys_enc, true);
+ else if (phys_enc->split_role == ENC_ROLE_SOLO)
+ sde_encoder_phys_vid_split_config(phys_enc, false);
- sde_encoder_phys_vid_flush_intf(phys_enc);
+ sde_encoder_phys_vid_setup_timing_engine(phys_enc);
/* Register for interrupt unless we're the slave encoder */
- if (sde_encoder_phys_vid_is_master(phys_enc) && intr_en) {
+ if (phys_enc->split_role != ENC_ROLE_SLAVE)
ret = sde_encoder_phys_vid_register_irq(phys_enc);
- if (!ret)
- vid_enc->intr_en = true;
- }
- if (!ret && !phys_enc->enabled) {
+ if (!ret) {
unsigned long lock_flags = 0;
/* Now enable timing engine */
@@ -428,8 +436,7 @@ static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
* scanout buffer) don't latch properly..
*/
sde_encoder_phys_vid_wait_for_vblank(vid_enc);
- if (vid_enc->intr_en)
- sde_encoder_phys_vid_unregister_irq(phys_enc);
+ sde_encoder_phys_vid_unregister_irq(phys_enc);
phys_enc->enabled = false;
}
@@ -438,7 +445,9 @@ static void sde_encoder_phys_vid_destroy(struct sde_encoder_phys *phys_enc)
struct sde_encoder_phys_vid *vid_enc =
to_sde_encoder_phys_vid(phys_enc);
DBG("");
- kfree(phys_enc->hw_intf);
+ sde_rm_release_ctl_path(phys_enc->sde_kms, phys_enc->hw_ctl->idx);
+ sde_hw_intf_deinit(phys_enc->hw_intf);
+ sde_hw_mdp_destroy(phys_enc->hw_mdptop);
kfree(vid_enc);
}
@@ -446,8 +455,6 @@ static void sde_encoder_phys_vid_get_hw_resources(
struct sde_encoder_phys *phys_enc,
struct sde_encoder_hw_resources *hw_res)
{
- struct msm_drm_private *priv = phys_enc->parent->dev->dev_private;
- struct sde_kms *sde_kms = to_sde_kms(priv->kms);
const struct sde_hw_res_map *hw_res_map;
DBG("Intf %d\n", phys_enc->hw_intf->idx);
@@ -457,12 +464,22 @@ static void sde_encoder_phys_vid_get_hw_resources(
* defaults should not be in use,
* otherwise signal/return failure
*/
- hw_res_map = sde_rm_get_res_map(sde_kms, phys_enc->hw_intf->idx);
+ hw_res_map = sde_rm_get_res_map(phys_enc->sde_kms,
+ phys_enc->hw_intf->idx);
+ if (IS_ERR_OR_NULL(hw_res_map)) {
+ DRM_ERROR("Failed to get hw_res_map: %ld\n",
+ PTR_ERR(hw_res_map));
+ return;
+ }
- /* This is video mode panel so PINGPONG will be in by-pass mode
+ /*
+ * This is video mode panel so PINGPONG will be in by-pass mode
* only assign ctl path.For cmd panel check if pp_split is
* enabled, override default map
*/
+ /*
+ * phys_enc->hw_ctl->idx
+ */
hw_res->ctls[hw_res_map->ctl] = true;
}
@@ -471,54 +488,54 @@ static void sde_encoder_phys_vid_get_hw_resources(
* cmd mode will use the pingpong (get_vsync_info)
* to get this information
*/
-static void sde_encoder_intf_get_vsync_info(struct sde_encoder_phys *phys_enc,
+static void sde_encoder_intf_get_vblank_status(
+ struct sde_encoder_phys *phys_enc,
struct vsync_info *vsync)
{
- struct intf_status status;
-
DBG("");
- phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &status);
- vsync->frame_count = status.frame_count;
- vsync->line_count = status.line_count;
- DBG(" sde_encoder_intf_get_vsync_info, count %d", vsync->frame_count);
-}
-static void sde_encoder_intf_split_config(struct sde_encoder_phys *phys_enc,
- bool enable)
-{
- struct msm_drm_private *priv = phys_enc->parent->dev->dev_private;
- struct sde_kms *sde_kms = to_sde_kms(priv->kms);
- struct sde_hw_mdp *mdp = sde_hw_mdptop_init(MDP_TOP, sde_kms->mmio,
- sde_kms->catalog);
- struct split_pipe_cfg cfg;
+ /* Slave encoders don't drive VBLANK interrupts, so don't respond */
+ if (phys_enc->split_role == ENC_ROLE_SLAVE)
+ return;
- cfg.en = enable;
+ /*
+ * Report VBlank Status as the VSYNC Frame/Line Counts from hardware
+ * Video encoders report from the VSYNC INTF (get_status)
+ * CMD Encoders report from the PingPong block (get_vsync_info)
+ */
+ if (phys_enc->hw_intf->ops.get_status) {
+ unsigned long lock_flags = 0;
+ struct intf_status status;
- cfg.mode = INTF_MODE_VIDEO;
- cfg.intf = INTF_1;
- cfg.pp_split = false;
- cfg.split_flush_en = true;
+ spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
+ phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &status);
+ spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
- if (!IS_ERR_OR_NULL(mdp))
- mdp->ops.setup_split_pipe(mdp, &cfg);
+ vsync->frame_count = status.frame_count;
+ vsync->line_count = status.line_count;
+ }
+
+ DBG("frame_count %d line_count %d", vsync->frame_count,
+ vsync->line_count);
}
-static void sde_encoder_phys_vid_init_cbs(struct sde_encoder_phys_ops *ops)
+static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
{
+ ops->is_master = sde_encoder_phys_vid_is_master;
ops->mode_set = sde_encoder_phys_vid_mode_set;
ops->mode_fixup = sde_encoder_phys_vid_mode_fixup;
ops->enable = sde_encoder_phys_vid_enable;
ops->disable = sde_encoder_phys_vid_disable;
ops->destroy = sde_encoder_phys_vid_destroy;
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
- ops->get_vsync_info = sde_encoder_intf_get_vsync_info;
- ops->enable_split_config = sde_encoder_intf_split_config;
+ ops->get_vblank_status = sde_encoder_intf_get_vblank_status;
}
struct sde_encoder_phys *sde_encoder_phys_vid_init(
struct sde_kms *sde_kms,
enum sde_intf intf_idx,
enum sde_ctl ctl_idx,
+ enum sde_enc_split_role split_role,
struct drm_encoder *parent,
struct sde_encoder_virt_ops parent_ops)
{
@@ -538,23 +555,34 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init(
phys_enc = &vid_enc->base;
+ phys_enc->hw_mdptop = sde_hw_mdptop_init(MDP_TOP, sde_kms->mmio,
+ sde_kms->catalog);
+ if (IS_ERR_OR_NULL(phys_enc->hw_mdptop)) {
+ ret = PTR_ERR(phys_enc->hw_mdptop);
+ DRM_ERROR("Failed init hw_top: %d\n", ret);
+ goto fail;
+ }
+
phys_enc->hw_intf =
sde_hw_intf_init(intf_idx, sde_kms->mmio, sde_kms->catalog);
- if (!phys_enc->hw_intf) {
- ret = -ENOMEM;
+ if (IS_ERR_OR_NULL(phys_enc->hw_intf)) {
+ ret = PTR_ERR(phys_enc->hw_intf);
+ DRM_ERROR("Failed init hw_intf: %d\n", ret);
goto fail;
}
phys_enc->hw_ctl = sde_rm_acquire_ctl_path(sde_kms, ctl_idx);
- if (!phys_enc->hw_ctl) {
- ret = -ENOMEM;
+ if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) {
+ ret = PTR_ERR(phys_enc->hw_ctl);
+ DRM_ERROR("Failed init hw_ctl: %d\n", ret);
goto fail;
}
- sde_encoder_phys_vid_init_cbs(&phys_enc->phys_ops);
+ sde_encoder_phys_vid_init_ops(&phys_enc->ops);
phys_enc->parent = parent;
phys_enc->parent_ops = parent_ops;
phys_enc->sde_kms = sde_kms;
+ phys_enc->split_role = split_role;
spin_lock_init(&phys_enc->spin_lock);
DBG("Created sde_encoder_phys_vid for intf %d", phys_enc->hw_intf->idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index a9cd20122275..101e3248c08a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -13,7 +13,6 @@
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_intf.h"
-#include "sde_hw_mdp_top.h"
#define INTF_TIMING_ENGINE_EN 0x000
#define INTF_CONFIG 0x004
@@ -173,24 +172,17 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx,
(0x21 << 8));
SDE_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
- SDE_REG_WRITE(c, INTF_VSYNC_PERIOD_F0,
- vsync_period * hsync_period);
+ SDE_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period);
SDE_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
p->vsync_pulse_width * hsync_period);
SDE_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl);
- SDE_REG_WRITE(c, INTF_DISPLAY_V_START_F0,
- display_v_start);
- SDE_REG_WRITE(c, INTF_DISPLAY_V_END_F0,
- display_v_end);
+ SDE_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start);
+ SDE_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end);
SDE_REG_WRITE(c, INTF_ACTIVE_HCTL, active_hctl);
- SDE_REG_WRITE(c, INTF_ACTIVE_V_START_F0,
- active_v_start);
- SDE_REG_WRITE(c, INTF_ACTIVE_V_END_F0,
- active_v_end);
-
+ SDE_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start);
+ SDE_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end);
SDE_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr);
- SDE_REG_WRITE(c, INTF_UNDERFLOW_COLOR,
- p->underflow_clr);
+ SDE_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr);
SDE_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew);
SDE_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl);
SDE_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
@@ -203,24 +195,8 @@ static void sde_hw_intf_enable_timing_engine(
u8 enable)
{
struct sde_hw_blk_reg_map *c = &intf->hw;
- u32 intf_sel;
-
- /* Display interface select */
- if (enable) {
- /* top block */
- struct sde_hw_mdp *mdp = sde_hw_mdptop_init(MDP_TOP,
- c->base_off,
- intf->mdss);
- struct sde_hw_blk_reg_map *top = &mdp->hw;
-
- intf_sel = SDE_REG_READ(top, DISP_INTF_SEL);
-
- intf_sel |= (intf->cap->type << ((intf->idx - INTF_0) * 8));
- SDE_REG_WRITE(top, DISP_INTF_SEL, intf_sel);
- }
-
- SDE_REG_WRITE(c, INTF_TIMING_ENGINE_EN,
- enable & 0x1);
+ /* Note: Display interface select is handled in top block hw layer */
+ SDE_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0);
}
static void sde_hw_intf_setup_prg_fetch(
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c
index 9b1d0d5f309e..9c9731215c3a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdp_top.c
@@ -126,5 +126,6 @@ struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp)
{
+ kfree(mdp);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index bb043dfb46b9..51e6e538305b 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -46,8 +46,8 @@ struct sde_irq {
/**
* struct sde_hw_res_map : Default resource table identifying default
* hw resource map. Primarily used for forcing DSI to use CTL_0/1
- * and Pingpong 0/1, if the field is set to SDE_NONE means any HW
- * intstance for that tpye is allowed as long as it is unused.
+ * and PingPong 0/1, if the field is set to SDE_NONE means any HW
+ * instance for that type is allowed as long as it is unused.
*/
struct sde_hw_res_map {
enum sde_intf intf;
@@ -56,7 +56,7 @@ struct sde_hw_res_map {
enum sde_ctl ctl;
};
-/* struct sde_hw_resource_manager : Resource mananger maintains the current
+/* struct sde_hw_resource_manager : Resource manager maintains the current
* default platform config and manages shared
* hw resources ex:ctl_path hw driver context
* is needed by CRTCs/PLANEs/ENCODERs
@@ -65,7 +65,7 @@ struct sde_hw_res_map {
* @intr : pointer to hw interrupt context
* @res_table : pointer to default hw_res table for this platform
* @feature_map :BIT map for default enabled features ex:specifies if PP_SPLIT
- * is enabled/disabled by defalt for this platform
+ * is enabled/disabled by default for this platform
*/
struct sde_hw_resource_manager {
struct sde_hw_ctl *ctl[CTL_MAX];
@@ -374,10 +374,9 @@ void sde_encoder_get_hw_resources(struct drm_encoder *encoder,
struct sde_encoder_hw_resources *hw_res);
void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc,
void (*cb)(void *), void *data);
-void sde_encoders_init(struct drm_device *dev);
-void sde_encoder_get_vsync_info(struct drm_encoder *encoder,
+void sde_encoder_get_vblank_status(struct drm_encoder *encoder,
struct vsync_info *vsync);
-
+void sde_encoders_init(struct drm_device *dev);
#endif /* __sde_kms_H__ */