summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLloyd Atkinson <latkinso@codeaurora.org>2016-06-26 10:08:25 -0400
committerKrishna Srinivas Kundurthi <kskund@codeaurora.org>2017-01-12 11:10:33 -0800
commitfe03524bee6ad1f1c108e6bcfc49212ba08f1b64 (patch)
treee654679d4ab5174c3e5a50ffe94a5121df0c0474
parenta142ec80cac01872b3f281e46e46e3e0730e86d9 (diff)
drm/msm/sde: programmable pre-fetch support for video encoders
Add support in encoder for programming early fetch in the vertical front porch. Change-Id: I60fcf4a4e6aea80292b590ee14506579123f372d Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org> Signed-off-by: Krishna Srinivas Kundurthi <kskund@codeaurora.org>
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c117
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c280
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.h2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c12
4 files changed, 303 insertions, 108 deletions
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 08abe700844b..f4bb230df98b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -101,37 +101,46 @@ static void bs_set(struct sde_encoder_virt *sde_enc, int idx)
void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
struct sde_encoder_hw_resources *hw_res)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
DBG("");
- if (!hw_res) {
+ if (!hw_res || !drm_enc) {
DRM_ERROR("Invalid pointer");
return;
}
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
/* Query resources used by phys encs, expected to be without overlap */
memset(hw_res, 0, sizeof(*hw_res));
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys)
+ if (phys && phys->phys_ops.get_hw_resources)
phys->phys_ops.get_hw_resources(phys, hw_res);
}
}
static void sde_encoder_destroy(struct drm_encoder *drm_enc)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
DBG("");
+ if (!drm_enc) {
+ DRM_ERROR("Invalid pointer");
+ return;
+ }
+
+ sde_enc = to_sde_encoder_virt(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) {
+ if (phys && phys->phys_ops.destroy) {
phys->phys_ops.destroy(phys);
--sde_enc->num_phys_encs;
sde_enc->phys_encs[i] = NULL;
@@ -152,70 +161,103 @@ static bool sde_encoder_virt_mode_fixup(struct drm_encoder *drm_enc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
+ bool ret = true;
DBG("");
+ if (!drm_enc) {
+ DRM_ERROR("Invalid pointer");
+ return false;
+ }
+
+ sde_enc = to_sde_encoder_virt(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(phys, mode, adjusted_mode);
- if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0) {
- DRM_ERROR("adjusted modes not supported\n");
- return false;
+ if (phys && phys->phys_ops.mode_fixup) {
+ ret =
+ phys->phys_ops.mode_fixup(phys, mode,
+ adjusted_mode);
+ if (!ret) {
+ DBG("Mode unsupported by phys_enc %d", i);
+ break;
+ }
+
+ if (sde_enc->num_phys_encs > 1) {
+ DBG("ModeFix only checking 1 phys_enc");
+ break;
}
}
}
- return true;
+ return ret;
}
static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
DBG("");
+ if (!drm_enc) {
+ DRM_ERROR("Invalid pointer");
+ return;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys) {
+ if (phys && phys->phys_ops.mode_set)
phys->phys_ops.mode_set(phys, mode, adjusted_mode);
- if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0)
- DRM_ERROR("adjusted modes not supported\n");
- }
}
}
static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
DBG("");
+ if (!drm_enc) {
+ DRM_ERROR("Invalid pointer");
+ return;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
bs_set(sde_enc, 1);
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (phys)
+ if (phys && phys->phys_ops.enable)
phys->phys_ops.enable(phys);
}
}
static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_virt *sde_enc = NULL;
int i = 0;
DBG("");
+ if (!drm_enc) {
+ DRM_ERROR("Invalid pointer");
+ return;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
@@ -256,11 +298,18 @@ static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc)
{
- struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ struct sde_encoder_virt *sde_enc = NULL;
unsigned long lock_flags;
DBG("");
+ if (!drm_enc) {
+ DRM_ERROR("Invalid pointer");
+ return;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
spin_lock_irqsave(&sde_enc->spin_lock, lock_flags);
if (sde_enc->kms_vblank_callback)
sde_enc->kms_vblank_callback(sde_enc->kms_vblank_callback_data);
@@ -286,7 +335,8 @@ 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);
+ &sde_enc->base,
+ parent_ops);
if (IS_ERR(enc))
ret = PTR_ERR(enc);
@@ -304,6 +354,7 @@ static int sde_encoder_setup_hdmi(struct sde_encoder_virt *sde_enc,
{
int ret = 0;
enum sde_intf intf_idx = INTF_MAX;
+ enum sde_ctl ctl_idx = CTL_2;
DBG("");
@@ -314,8 +365,7 @@ static int sde_encoder_setup_hdmi(struct sde_encoder_virt *sde_enc,
if (!ret)
ret =
sde_encoder_virt_add_phys_vid_enc(sde_enc, sde_kms,
- intf_idx,
- CTL_2);
+ intf_idx, ctl_idx);
return ret;
}
@@ -343,13 +393,14 @@ static int sde_encoder_setup_dsi(struct sde_encoder_virt *sde_enc,
enum sde_ctl ctl_idx = CTL_0;
intf_idx = sde_encoder_get_intf(sde_kms->catalog,
- INTF_DSI, dsi_info->h_tile_ids[i]);
+ INTF_DSI,
+ dsi_info->h_tile_ids[i]);
if (intf_idx == INTF_MAX) {
DBG("Error: could not get the interface id");
ret = -EINVAL;
}
- /* Create both VID and CMD Phys Encoders here */
+ /* Create both VID and CMD Phys Encoders here */
if (!ret)
ret =
sde_encoder_virt_add_phys_vid_enc(sde_enc, sde_kms,
@@ -511,12 +562,22 @@ void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc,
*/
void sde_encoders_init(struct drm_device *dev)
{
- struct msm_drm_private *priv = dev->dev_private;
+ struct msm_drm_private *priv = NULL;
int ret = 0;
DBG("");
- /* Start num_encoders at 0, probe functions will increment */
+ if (!dev || !dev->dev_private) {
+ DRM_ERROR("Invalid pointer");
+ return;
+ }
+
+ priv = dev->dev_private;
+ if (!priv->kms) {
+ DRM_ERROR("Invalid pointer");
+ return;
+ }
+ /* Start num_encoders at 0, probe functions will increment */
priv->num_encoders = 0;
ret = sde_encoder_probe_dsi(dev);
if (ret)
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 55fad67cbf12..0528c3d1ff8d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -20,23 +20,185 @@
#include "sde_encoder_phys.h"
#include "sde_mdp_formats.h"
-
#define to_sde_encoder_phys_vid(x) \
container_of(x, struct sde_encoder_phys_vid, base)
-static bool sde_encoder_phys_vid_mode_fixup(struct sde_encoder_phys *drm_enc,
- const struct drm_display_mode *mode,
- struct drm_display_mode
- *adjusted_mode)
+static void drm_mode_to_intf_timing_params(
+ const struct sde_encoder_phys *phys_enc,
+ const struct drm_display_mode *mode,
+ struct intf_timing_params *timing)
+{
+ memset(timing, 0, sizeof(*timing));
+ /*
+ * https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
+ * Active Region Front Porch Sync Back Porch
+ * <-----------------><------------><-----><----------->
+ * <- [hv]display --->
+ * <--------- [hv]sync_start ------>
+ * <----------------- [hv]sync_end ------->
+ * <---------------------------- [hv]total ------------->
+ */
+ timing->width = mode->hdisplay; /* active width */
+ timing->height = mode->vdisplay; /* active height */
+ timing->xres = timing->width;
+ timing->yres = timing->height;
+ timing->h_back_porch = mode->htotal - mode->hsync_end;
+ timing->h_front_porch = mode->hsync_start - mode->hdisplay;
+ timing->v_back_porch = mode->vtotal - mode->vsync_end;
+ timing->v_front_porch = mode->vsync_start - mode->vdisplay;
+ timing->hsync_pulse_width = mode->hsync_end - mode->hsync_start;
+ timing->vsync_pulse_width = mode->vsync_end - mode->vsync_start;
+ timing->hsync_polarity = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0;
+ timing->vsync_polarity = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
+ timing->border_clr = 0;
+ timing->underflow_clr = 0xff;
+ timing->hsync_skew = mode->hskew;
+
+ /* DSI controller cannot handle active-low sync signals. */
+ if (phys_enc->hw_intf->cap->type == INTF_DSI) {
+ timing->hsync_polarity = 0;
+ timing->vsync_polarity = 0;
+ }
+
+ /*
+ * For edp only:
+ * DISPLAY_V_START = (VBP * HCYCLE) + HBP
+ * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
+ */
+ /*
+ * if (vid_enc->hw->cap->type == INTF_EDP) {
+ * display_v_start += mode->htotal - mode->hsync_start;
+ * display_v_end -= mode->hsync_start - mode->hdisplay;
+ * }
+ */
+}
+
+static inline u32 get_horizontal_total(const struct intf_timing_params *timing)
+{
+ u32 active = timing->xres;
+ u32 inactive =
+ timing->h_back_porch + timing->h_front_porch +
+ timing->hsync_pulse_width;
+ return active + inactive;
+}
+
+static inline u32 get_vertical_total(const struct intf_timing_params *timing)
+{
+ u32 active = timing->yres;
+ u32 inactive =
+ timing->v_back_porch + timing->v_front_porch +
+ timing->vsync_pulse_width;
+ return active + inactive;
+}
+
+/*
+ * programmable_fetch_get_num_lines:
+ * Number of fetch lines in vertical front porch
+ * @timing: Pointer to the intf timing information for the requested mode
+ *
+ * Returns the number of fetch lines in vertical front porch at which mdp
+ * can start fetching the next frame.
+ *
+ * Number of needed prefetch lines is anything that cannot be absorbed in the
+ * start of frame time (back porch + vsync pulse width).
+ *
+ * Some panels have very large VFP, however we only need a total number of
+ * lines based on the chip worst case latencies.
+ */
+static u32 programmable_fetch_get_num_lines(
+ struct sde_encoder_phys *phys_enc,
+ const struct intf_timing_params *timing)
+{
+ u32 worst_case_needed_lines =
+ phys_enc->hw_intf->cap->prog_fetch_lines_worst_case;
+ u32 start_of_frame_lines =
+ timing->v_back_porch + timing->vsync_pulse_width;
+ u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines;
+ u32 actual_vfp_lines = 0;
+
+ /* Fetch must be outside active lines, otherwise undefined. */
+
+ if (start_of_frame_lines >= worst_case_needed_lines) {
+ DBG("Programmable fetch is not needed due to large vbp+vsw");
+ actual_vfp_lines = 0;
+ } 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");
+ DBG("Less vfp than fetch requires, using entire vfp");
+ actual_vfp_lines = timing->v_front_porch;
+ } else {
+ DBG("Room in vfp for needed prefetch");
+ actual_vfp_lines = needed_vfp_lines;
+ }
+
+ DBG("v_front_porch %u v_back_porch %u vsync_pulse_width %u",
+ timing->v_front_porch, timing->v_back_porch,
+ timing->vsync_pulse_width);
+ DBG("wc_lines %u needed_vfp_lines %u actual_vfp_lines %u",
+ worst_case_needed_lines, needed_vfp_lines, actual_vfp_lines);
+
+ return actual_vfp_lines;
+}
+
+/*
+ * programmable_fetch_config: Programs HW to prefetch lines by offsetting
+ * the start of fetch into the vertical front porch for cases where the
+ * vsync pulse width and vertical back porch time is insufficient
+ *
+ * Gets # of lines to pre-fetch, then calculate VSYNC counter value.
+ * HW layer requires VSYNC counter of first pixel of tgt VFP line.
+ *
+ * @timing: Pointer to the intf timing information for the requested mode
+ */
+static void programmable_fetch_config(struct sde_encoder_phys *phys_enc,
+ const struct intf_timing_params *timing)
+{
+ struct intf_prog_fetch f = { 0 };
+ u32 vfp_fetch_lines = 0;
+ u32 horiz_total = 0;
+ u32 vert_total = 0;
+ u32 vfp_fetch_start_vsync_counter = 0;
+ unsigned long lock_flags;
+
+ if (WARN_ON_ONCE(!phys_enc->hw_intf->ops.setup_prg_fetch))
+ return;
+
+ vfp_fetch_lines = programmable_fetch_get_num_lines(phys_enc, timing);
+ if (vfp_fetch_lines) {
+ vert_total = get_vertical_total(timing);
+ horiz_total = get_horizontal_total(timing);
+ vfp_fetch_start_vsync_counter =
+ (vert_total - vfp_fetch_lines) * horiz_total + 1;
+ f.enable = 1;
+ f.fetch_start = vfp_fetch_start_vsync_counter;
+ }
+
+ DBG("vfp_fetch_lines %u vfp_fetch_start_vsync_counter %u",
+ vfp_fetch_lines, vfp_fetch_start_vsync_counter);
+
+ spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
+ phys_enc->hw_intf->ops.setup_prg_fetch(phys_enc->hw_intf, &f);
+ spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
+}
+
+static bool sde_encoder_phys_vid_mode_fixup(
+ struct sde_encoder_phys *phys_enc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
{
DBG("");
+
+ /*
+ * Modifying mode has consequences when the mode comes back to us
+ */
return true;
}
-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)
+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;
@@ -48,18 +210,22 @@ static void sde_encoder_phys_vid_mode_set(struct sde_encoder_phys *phys_enc,
mode->type, mode->flags);
}
-static void sde_encoder_phys_vid_setup_timing_engine(struct sde_encoder_phys
- *phys_enc)
+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 };
- uint32_t hsync_polarity = 0;
- uint32_t vsync_polarity = 0;
struct sde_mdp_format_params *sde_fmt_params = NULL;
u32 fmt_fourcc = DRM_FORMAT_RGB888;
u32 fmt_mod = 0;
unsigned long lock_flags;
- struct sde_hw_intf_cfg intf_cfg = {0};
+ struct sde_hw_intf_cfg intf_cfg = { 0 };
+
+ if (WARN_ON(!phys_enc->hw_intf->ops.setup_timing_gen))
+ return;
+
+ 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,
@@ -67,66 +233,24 @@ static void sde_encoder_phys_vid_setup_timing_engine(struct sde_encoder_phys
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
mode->type, mode->flags);
- /* DSI controller cannot handle active-low sync signals. */
- if (phys_enc->hw_intf->cap->type != INTF_DSI) {
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- hsync_polarity = 1;
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- vsync_polarity = 1;
- }
-
- /*
- * For edp only:
- * DISPLAY_V_START = (VBP * HCYCLE) + HBP
- * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
- */
- /*
- * if (vid_enc->hw->cap->type == INTF_EDP) {
- * display_v_start += mode->htotal - mode->hsync_start;
- * display_v_end -= mode->hsync_start - mode->hdisplay;
- * }
- */
-
- /*
- * https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
- * Active Region Front Porch Sync Back Porch
- * <---------------------><----------------><---------><-------------->
- * <--- [hv]display ----->
- * <----------- [hv]sync_start ------------>
- * <------------------- [hv]sync_end ----------------->
- * <------------------------------ [hv]total ------------------------->
- */
+ drm_mode_to_intf_timing_params(phys_enc, mode, &p);
sde_fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod);
- p.width = mode->hdisplay; /* active width */
- p.height = mode->vdisplay; /* active height */
- p.xres = p.width; /* Display panel width */
- p.yres = p.height; /* Display panel height */
- p.h_back_porch = mode->htotal - mode->hsync_end;
- p.h_front_porch = mode->hsync_start - mode->hdisplay;
- p.v_back_porch = mode->vtotal - mode->vsync_end;
- p.v_front_porch = mode->vsync_start - mode->vdisplay;
- p.hsync_pulse_width = mode->hsync_end - mode->hsync_start;
- p.vsync_pulse_width = mode->vsync_end - mode->vsync_start;
- p.hsync_polarity = hsync_polarity;
- p.vsync_polarity = vsync_polarity;
- p.border_clr = 0;
- p.underflow_clr = 0xff;
- p.hsync_skew = mode->hskew;
-
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);
+ sde_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);
}
-static void sde_encoder_phys_vid_wait_for_vblank(struct sde_encoder_phys_vid
- *vid_enc)
+static void sde_encoder_phys_vid_wait_for_vblank(
+ struct sde_encoder_phys_vid *vid_enc)
{
DBG("");
mdp_irq_wait(vid_enc->base.mdp_kms, vid_enc->vblank_irq.irqmask);
@@ -139,9 +263,7 @@ static void sde_encoder_phys_vid_vblank_irq(struct mdp_irq *irq,
container_of(irq, struct sde_encoder_phys_vid,
vblank_irq);
struct sde_encoder_phys *phys_enc = &vid_enc->base;
- struct intf_status status = { 0 };
- phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &status);
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent);
}
@@ -156,6 +278,9 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc)
if (WARN_ON(phys_enc->enabled))
return;
+ if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing))
+ return;
+
sde_encoder_phys_vid_setup_timing_engine(phys_enc);
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
@@ -180,6 +305,9 @@ static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
if (WARN_ON(!phys_enc->enabled))
return;
+ if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing))
+ return;
+
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 0);
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
@@ -206,10 +334,9 @@ static void sde_encoder_phys_vid_destroy(struct sde_encoder_phys *phys_enc)
kfree(vid_enc);
}
-static void sde_encoder_phys_vid_get_hw_resources(struct sde_encoder_phys
- *phys_enc, struct
- sde_encoder_hw_resources
- *hw_res)
+static void sde_encoder_phys_vid_get_hw_resources(
+ struct sde_encoder_phys *phys_enc,
+ struct sde_encoder_hw_resources *hw_res)
{
DBG("");
hw_res->intfs[phys_enc->hw_intf->idx] = true;
@@ -225,15 +352,16 @@ static void sde_encoder_phys_vid_init_cbs(struct sde_encoder_phys_ops *ops)
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
}
-struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
- enum sde_intf intf_idx,
- enum sde_ctl ctl_idx,
- struct drm_encoder *parent,
- struct sde_encoder_virt_ops
- parent_ops)
+struct sde_encoder_phys *sde_encoder_phys_vid_init(
+ struct sde_kms *sde_kms,
+ enum sde_intf intf_idx,
+ enum sde_ctl ctl_idx,
+ struct drm_encoder *parent,
+ struct sde_encoder_virt_ops parent_ops)
{
struct sde_encoder_phys *phys_enc = NULL;
struct sde_encoder_phys_vid *vid_enc = NULL;
+ u32 irq_mask = 0x8000000;
int ret = 0;
DBG("");
@@ -253,7 +381,7 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
}
phys_enc->hw_ctl = sde_hw_ctl_init(ctl_idx, sde_kms->mmio,
- sde_kms->catalog);
+ sde_kms->catalog);
if (!phys_enc->hw_ctl) {
ret = -ENOMEM;
goto fail;
@@ -264,7 +392,7 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
phys_enc->parent_ops = parent_ops;
phys_enc->mdp_kms = &sde_kms->base;
vid_enc->vblank_irq.irq = sde_encoder_phys_vid_vblank_irq;
- vid_enc->vblank_irq.irqmask = 0x8000000;
+ vid_enc->vblank_irq.irqmask = irq_mask;
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_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 1d1788bcef62..5273dd69410f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -372,11 +372,13 @@ struct sde_cdm_cfg {
* @features bit mask identifying sub-blocks/features
* @type: Interface type(DSI, DP, HDMI)
* @controller_id: Controller Instance ID in case of multiple of intf type
+ * @prog_fetch_lines_worst_case Worst case latency num lines needed to prefetch
*/
struct sde_intf_cfg {
SDE_HW_BLK_INFO;
u32 type; /* interface type*/
u32 controller_id;
+ u32 prog_fetch_lines_worst_case;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
index a958cc46ee4a..68736bece06b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
@@ -244,13 +244,17 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.intf_count = 4,
.intf = {
{.id = INTF_0, .base = 0x0006B000,
- .type = INTF_NONE, .controller_id = 0},
+ .type = INTF_NONE, .controller_id = 0,
+ .prog_fetch_lines_worst_case = 21},
{.id = INTF_1, .base = 0x0006B800,
- .type = INTF_DSI, .controller_id = 0},
+ .type = INTF_DSI, .controller_id = 0,
+ .prog_fetch_lines_worst_case = 21},
{.id = INTF_2, .base = 0x0006C000,
- .type = INTF_DSI, .controller_id = 1},
+ .type = INTF_DSI, .controller_id = 1,
+ .prog_fetch_lines_worst_case = 21},
{.id = INTF_3, .base = 0x0006C800,
- .type = INTF_HDMI, .controller_id = 0},
+ .type = INTF_HDMI, .controller_id = 0,
+ .prog_fetch_lines_worst_case = 21},
},
.wb_count = 3,
.wb = {