Merge "drm/msm/sde: add inline rotation prefill for video mode" into msm-4.9
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index a01383b..b51187d 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -134,6 +134,7 @@
CRTC_PROP_CORE_CLK,
CRTC_PROP_CORE_AB,
CRTC_PROP_CORE_IB,
+ CRTC_PROP_ROT_PREFILL_BW,
/* total # of properties */
CRTC_PROP_COUNT
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 44f6169..b6a37b7 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -365,9 +365,11 @@
if (!sbuf_mode) {
cstate->sbuf_cfg.rot_op_mode =
SDE_CTL_ROT_OP_MODE_OFFLINE;
+ cstate->sbuf_prefill_line = 0;
} else {
cstate->sbuf_cfg.rot_op_mode =
SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
+ cstate->sbuf_prefill_line = prefill;
}
ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
@@ -1024,6 +1026,7 @@
struct sde_crtc *sde_crtc;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
+ struct sde_crtc_state *cstate;
if (!crtc) {
SDE_ERROR("invalid argument\n");
@@ -1033,8 +1036,11 @@
sde_crtc = to_sde_crtc(crtc);
sde_kms = _sde_crtc_get_kms(crtc);
priv = sde_kms->dev->dev_private;
+ cstate = to_sde_crtc_state(crtc->state);
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct sde_encoder_kickoff_params params = { 0 };
+
if (encoder->crtc != crtc)
continue;
@@ -1042,7 +1048,8 @@
* Encoder will flush/start now, unless it has a tx pending.
* If so, it may delay and flush at an irq event (e.g. ppdone)
*/
- sde_encoder_prepare_for_kickoff(encoder);
+ params.inline_rotate_prefill = cstate->sbuf_prefill_line;
+ sde_encoder_prepare_for_kickoff(encoder, ¶ms);
}
if (atomic_read(&sde_crtc->frame_pending) > 2) {
@@ -1715,6 +1722,10 @@
"core_ib", 0x0, 0, U64_MAX,
SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA,
CRTC_PROP_CORE_IB);
+ msm_property_install_range(&sde_crtc->property_info,
+ "rot_prefill_bw", 0, 0, U64_MAX,
+ catalog->perf.max_bw_high * 1000ULL,
+ CRTC_PROP_ROT_PREFILL_BW);
msm_property_install_blob(&sde_crtc->property_info, "capabilities",
DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index d288752..f389196 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -202,6 +202,7 @@
* @cur_perf: current performance state
* @new_perf: new performance state
* @sbuf_cfg: stream buffer configuration
+ * @sbuf_prefill_line: number of line for inline rotator prefetch
*/
struct sde_crtc_state {
struct drm_crtc_state base;
@@ -221,6 +222,7 @@
struct sde_core_perf_params cur_perf;
struct sde_core_perf_params new_perf;
struct sde_ctl_sbuf_cfg sbuf_cfg;
+ u64 sbuf_prefill_line;
};
#define to_sde_crtc_state(x) \
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 7db44d3..69d21fb 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1203,7 +1203,8 @@
spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
}
-void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
+void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
+ struct sde_encoder_kickoff_params *params)
{
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *phys;
@@ -1224,7 +1225,7 @@
phys = sde_enc->phys_encs[i];
if (phys) {
if (phys->ops.prepare_for_kickoff)
- phys->ops.prepare_for_kickoff(phys);
+ phys->ops.prepare_for_kickoff(phys, params);
if (phys->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET)
needs_hw_reset = true;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index bd7ef69..cdecd08 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -45,6 +45,14 @@
};
/**
+ * sde_encoder_kickoff_params - info encoder requires at kickoff
+ * @inline_rotate_prefill: number of lines to prefill for inline rotation
+ */
+struct sde_encoder_kickoff_params {
+ u32 inline_rotate_prefill;
+};
+
+/**
* sde_encoder_get_hw_resources - Populate table of required hardware resources
* @encoder: encoder pointer
* @hw_res: resource table to populate with encoder required resources
@@ -89,8 +97,10 @@
* Immediately: if no previous commit is outstanding.
* Delayed: Block until next trigger can be issued.
* @encoder: encoder pointer
+ * @params: kickoff time parameters
*/
-void sde_encoder_prepare_for_kickoff(struct drm_encoder *encoder);
+void sde_encoder_prepare_for_kickoff(struct drm_encoder *encoder,
+ struct sde_encoder_kickoff_params *params);
/**
* sde_encoder_kickoff - trigger a double buffer flip of the ctl path
@@ -116,6 +126,24 @@
enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder);
/**
+ * enum sde_encoder_property - property tags for sde enoder
+ * @SDE_ENCODER_PROPERTY_INLINE_ROTATE_REFILL: # of prefill line, 0 to disable
+ */
+enum sde_encoder_property {
+ SDE_ENCODER_PROPERTY_INLINE_ROTATE_PREFILL,
+ SDE_ENCODER_PROPERTY_MAX,
+};
+
+/*
+ * sde_encoder_set_property - set the property tag to the given value
+ * @encoder: Pointer to drm encoder object
+ * @tag: property tag
+ * @val: property value
+ * return: 0 if success; errror code otherwise
+ */
+int sde_encoder_set_property(struct drm_encoder *encoder, u32 tag, u64 val);
+
+/**
* sde_encoder_init - initialize virtual encoder object
* @dev: Pointer to drm device structure
* @disp_info: Pointer to display information structure
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 6d50c53..7aa9a29 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -141,7 +141,8 @@
struct drm_connector_state *conn_state);
int (*control_vblank_irq)(struct sde_encoder_phys *enc, bool enable);
int (*wait_for_commit_done)(struct sde_encoder_phys *phys_enc);
- void (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc);
+ void (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc,
+ struct sde_encoder_kickoff_params *params);
void (*handle_post_kickoff)(struct sde_encoder_phys *phys_enc);
void (*trigger_start)(struct sde_encoder_phys *phys_enc);
bool (*needs_single_flush)(struct sde_encoder_phys *phys_enc);
@@ -238,12 +239,16 @@
* @irq_idx: IRQ interface lookup index
* @irq_cb: interrupt callback
* @hw_intf: Hardware interface to the intf registers
+ * @timing_params: Current timing parameter
+ * @rot_prefill_line: number of line to prefill for inline rotation; 0 disable
*/
struct sde_encoder_phys_vid {
struct sde_encoder_phys base;
int irq_idx[INTR_IDX_MAX];
struct sde_irq_callback irq_cb[INTR_IDX_MAX];
struct sde_hw_intf *hw_intf;
+ struct intf_timing_params timing_params;
+ u64 rot_prefill_line;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index afc21ed..86e292f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -653,7 +653,8 @@
}
static void sde_encoder_phys_cmd_prepare_for_kickoff(
- struct sde_encoder_phys *phys_enc)
+ struct sde_encoder_phys *phys_enc,
+ struct sde_encoder_kickoff_params *params)
{
struct sde_encoder_phys_cmd *cmd_enc =
to_sde_encoder_phys_cmd(phys_enc);
@@ -687,7 +688,7 @@
to_sde_encoder_phys_cmd(phys_enc);
if (cmd_enc->serialize_wait4pp)
- sde_encoder_phys_cmd_prepare_for_kickoff(phys_enc);
+ sde_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL);
/*
* following statement is true serialize_wait4pp is false.
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 01dd982..82d32dc 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -211,6 +211,54 @@
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
}
+/*
+ * programmable_rot_fetch_config: Programs ROT 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.
+ * @phys_enc: Pointer to physical encoder
+ * @rot_fetch_lines: number of line to prefill, or 0 to disable
+ */
+static void programmable_rot_fetch_config(struct sde_encoder_phys *phys_enc,
+ u64 rot_fetch_lines)
+{
+ struct sde_encoder_phys_vid *vid_enc =
+ to_sde_encoder_phys_vid(phys_enc);
+ struct intf_prog_fetch f = { 0 };
+ struct intf_timing_params *timing = &vid_enc->timing_params;
+ u32 vfp_fetch_lines = 0;
+ u32 horiz_total = 0;
+ u32 vert_total = 0;
+ u32 rot_fetch_start_vsync_counter = 0;
+ unsigned long lock_flags;
+
+ if (WARN_ON_ONCE(!vid_enc->hw_intf->ops.setup_rot_start))
+ return;
+
+ vfp_fetch_lines = programmable_fetch_get_num_lines(vid_enc, timing);
+ if (vfp_fetch_lines && rot_fetch_lines) {
+ vert_total = get_vertical_total(timing);
+ horiz_total = get_horizontal_total(timing);
+ if (vert_total >= (vfp_fetch_lines + rot_fetch_lines)) {
+ rot_fetch_start_vsync_counter =
+ (vert_total - vfp_fetch_lines - rot_fetch_lines) *
+ horiz_total + 1;
+ f.enable = 1;
+ f.fetch_start = rot_fetch_start_vsync_counter;
+ }
+ }
+
+ SDE_DEBUG_VIDENC(vid_enc,
+ "rot_fetch_lines %llu rot_fetch_start_vsync_counter %u\n",
+ rot_fetch_lines, rot_fetch_start_vsync_counter);
+
+ spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+ vid_enc->hw_intf->ops.setup_rot_start(vid_enc->hw_intf, &f);
+ spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+}
+
static bool sde_encoder_phys_vid_mode_fixup(
struct sde_encoder_phys *phys_enc,
const struct drm_display_mode *mode,
@@ -281,6 +329,8 @@
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
programmable_fetch_config(phys_enc, &timing_params);
+
+ vid_enc->timing_params = timing_params;
}
static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
@@ -655,14 +705,15 @@
}
static void sde_encoder_phys_vid_prepare_for_kickoff(
- struct sde_encoder_phys *phys_enc)
+ struct sde_encoder_phys *phys_enc,
+ struct sde_encoder_kickoff_params *params)
{
struct sde_encoder_phys_vid *vid_enc;
struct sde_hw_ctl *ctl;
int rc;
- if (!phys_enc) {
- SDE_ERROR("invalid encoder\n");
+ if (!phys_enc || !params) {
+ SDE_ERROR("invalid encoder/parameters\n");
return;
}
vid_enc = to_sde_encoder_phys_vid(phys_enc);
@@ -681,6 +732,8 @@
ctl->idx, rc);
SDE_DBG_DUMP("panic");
}
+
+ programmable_rot_fetch_config(phys_enc, params->inline_rotate_prefill);
}
static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 5187627..28a2b16 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -777,9 +777,11 @@
/**
* sde_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing
* @phys_enc: Pointer to physical encoder
+ * @params: kickoff parameters
*/
static void sde_encoder_phys_wb_prepare_for_kickoff(
- struct sde_encoder_phys *phys_enc)
+ struct sde_encoder_phys *phys_enc,
+ struct sde_encoder_kickoff_params *params)
{
struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
int ret;
@@ -992,7 +994,7 @@
goto exit;
phys_enc->enable_state = SDE_ENC_DISABLING;
- sde_encoder_phys_wb_prepare_for_kickoff(phys_enc);
+ sde_encoder_phys_wb_prepare_for_kickoff(phys_enc, NULL);
if (phys_enc->hw_ctl->ops.trigger_flush)
phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl);
sde_encoder_helper_trigger_start(phys_enc);
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 2adb4cb..00b6c85 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -779,6 +779,24 @@
return _sde_format_get_plane_sizes_linear(fmt, w, h, layout);
}
+int sde_format_get_block_size(const struct sde_format *fmt,
+ uint32_t *w, uint32_t *h)
+{
+ if (!fmt || !w || !h) {
+ DRM_ERROR("invalid pointer\n");
+ return -EINVAL;
+ }
+
+ /* TP10 is 96x96 and all others are 128x128 */
+ if (SDE_FORMAT_IS_YUV(fmt) && SDE_FORMAT_IS_DX(fmt) &&
+ (fmt->num_planes == 2) && fmt->unpack_tight)
+ *w = *h = 96;
+ else
+ *w = *h = 128;
+
+ return 0;
+}
+
uint32_t sde_format_get_framebuffer_size(
const uint32_t format,
const uint32_t width,
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.h b/drivers/gpu/drm/msm/sde/sde_formats.h
index 544f436..40aab22 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.h
+++ b/drivers/gpu/drm/msm/sde/sde_formats.h
@@ -73,6 +73,18 @@
struct sde_hw_fmt_layout *layout);
/**
+ * sde_format_get_block_size - get block size of given format when
+ * operating in block mode
+ * @fmt: pointer to sde_format
+ * @w: pointer to width of the block
+ * @h: pointer to height of the block
+ *
+ * Return: 0 if success; error oode otherwise
+ */
+int sde_format_get_block_size(const struct sde_format *fmt,
+ uint32_t *w, uint32_t *h);
+
+/**
* sde_format_check_modified_format - validate format and buffers for
* sde non-standard, i.e. modified format
* @kms: kms driver
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 25222c3..9285487 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1378,6 +1378,9 @@
intf->controller_id = none_count;
none_count++;
}
+
+ if (sde_cfg->has_sbuf)
+ set_bit(SDE_INTF_ROT_START, &intf->features);
}
end:
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 962cd0d..97da08f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -212,6 +212,16 @@
};
/**
+ * INTF sub-blocks
+ * @SDE_INTF_ROT_START INTF supports rotator start trigger
+ * @SDE_INTF_MAX
+ */
+enum {
+ SDE_INTF_ROT_START = 0x1,
+ SDE_INTF_MAX
+};
+
+/**
* WB sub-blocks and features
* @SDE_WB_LINE_MODE Writeback module supports line/linear mode
* @SDE_WB_BLOCK_MODE Writeback module supports block mode read
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index c17844d..d96e49a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -58,6 +58,7 @@
#define INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118
#define INTF_TPG_RGB_MAPPING 0x11C
#define INTF_PROG_FETCH_START 0x170
+#define INTF_PROG_ROT_START 0x174
#define INTF_FRAME_LINE_COUNT_EN 0x0A8
#define INTF_FRAME_COUNT 0x0AC
@@ -234,6 +235,25 @@
SDE_REG_WRITE(c, INTF_CONFIG, fetch_enable);
}
+static void sde_hw_intf_setup_rot_start(
+ struct sde_hw_intf *intf,
+ const struct intf_prog_fetch *fetch)
+{
+ struct sde_hw_blk_reg_map *c = &intf->hw;
+ int fetch_enable;
+
+ fetch_enable = SDE_REG_READ(c, INTF_CONFIG);
+ if (fetch->enable) {
+ fetch_enable |= BIT(19);
+ SDE_REG_WRITE(c, INTF_PROG_ROT_START,
+ fetch->fetch_start);
+ } else {
+ fetch_enable &= ~BIT(19);
+ }
+
+ SDE_REG_WRITE(c, INTF_CONFIG, fetch_enable);
+}
+
static void sde_hw_intf_get_status(
struct sde_hw_intf *intf,
struct intf_status *s)
@@ -303,6 +323,8 @@
ops->enable_timing = sde_hw_intf_enable_timing_engine;
ops->setup_misr = sde_hw_intf_set_misr;
ops->collect_misr = sde_hw_intf_collect_misr;
+ if (cap & BIT(SDE_INTF_ROT_START))
+ ops->setup_rot_start = sde_hw_intf_setup_rot_start;
}
struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
index f4a01cb..c6428ca 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -74,6 +74,7 @@
* Assumption is these functions will be called after clocks are enabled
* @ setup_timing_gen : programs the timing engine
* @ setup_prog_fetch : enables/disables the programmable fetch logic
+ * @ setup_rot_start : enables/disables the rotator start trigger
* @ enable_timing: enable/disable timing engine
* @ get_status: returns if timing engine is enabled or not
* @ setup_misr: enables/disables MISR in HW register
@@ -87,6 +88,9 @@
void (*setup_prg_fetch)(struct sde_hw_intf *intf,
const struct intf_prog_fetch *fetch);
+ void (*setup_rot_start)(struct sde_hw_intf *intf,
+ const struct intf_prog_fetch *fetch);
+
void (*enable_timing)(struct sde_hw_intf *intf,
u8 enable);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.c b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
index 049d877..ffb1b67 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.c
@@ -557,6 +557,8 @@
rot_cmd.vflip = data->vflip;
rot_cmd.secure = data->secure;
rot_cmd.clkrate = data->clkrate;
+ rot_cmd.data_bw = 0;
+ rot_cmd.prefill_bw = data->prefill_bw;
rot_cmd.src_width = data->src_width;
rot_cmd.src_height = data->src_height;
rot_cmd.src_rect_x = data->src_rect_x;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_rot.h b/drivers/gpu/drm/msm/sde/sde_hw_rot.h
index 37215bb..949f9bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_rot.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_rot.h
@@ -49,6 +49,7 @@
* @secure: true if image content is in secure domain
* @video_mode: true if rotator is feeding into video interface
* @clkrate : clock rate in Hz
+ * @prefill_bw: prefill bandwidth in Bps (video mode only)
* @src_iova: source i/o virtual address
* @src_len: source i/o buffer length
* @src_planes: source plane number
@@ -84,6 +85,7 @@
bool secure;
bool video_mode;
u64 clkrate;
+ u64 prefill_bw;
dma_addr_t src_iova[4];
u32 src_len[4];
u32 src_planes;
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index fc0bce6..f9c55ec 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -165,6 +165,27 @@
return to_sde_kms(priv->kms);
}
+/**
+ * _sde_plane_get_crtc_state - obtain crtc state attached to given plane state
+ * @pstate: Pointer to drm plane state
+ * return: Pointer to crtc state if success; pointer error, otherwise
+ */
+static struct drm_crtc_state *_sde_plane_get_crtc_state(
+ struct drm_plane_state *pstate)
+{
+ struct drm_crtc_state *cstate;
+
+ if (!pstate || !pstate->crtc)
+ return NULL;
+
+ if (pstate->state)
+ cstate = drm_atomic_get_crtc_state(pstate->state, pstate->crtc);
+ else
+ cstate = pstate->crtc->state;
+
+ return cstate;
+}
+
static bool sde_plane_enabled(struct drm_plane_state *state)
{
return state && state->fb && state->crtc;
@@ -1193,7 +1214,7 @@
}
/**
- * sde_plane_rot_calc_perfill - calculate rotator start prefill
+ * sde_plane_rot_calc_prefill - calculate rotator start prefill
* @plane: Pointer to drm plane
* return: prefill time in line
*/
@@ -1225,8 +1246,8 @@
return 0;
}
- /* if rstate->out_fb_format is TP10, then block size is 96 */
-
+ sde_format_get_block_size(rstate->out_fb_format, &blocksize,
+ &blocksize);
prefill_line = blocksize + sde_kms->catalog->sbuf_headroom;
SDE_DEBUG("plane%d prefill:%u\n", plane->base.id, prefill_line);
@@ -1442,6 +1463,8 @@
struct sde_plane_state *pstate = to_sde_plane_state(state);
struct sde_plane_rot_state *rstate = &pstate->rot;
struct sde_hw_rot_cmd *rot_cmd;
+ struct drm_crtc_state *cstate;
+ struct sde_crtc_state *sde_cstate;
int ret, i;
if (!plane || !state || !state->fb || !rstate->rot_hw) {
@@ -1449,6 +1472,13 @@
return -EINVAL;
}
+ cstate = _sde_plane_get_crtc_state(state);
+ if (IS_ERR_OR_NULL(cstate)) {
+ SDE_ERROR("invalid crtc state %ld\n", PTR_ERR(cstate));
+ return -EINVAL;
+ }
+ sde_cstate = to_sde_crtc_state(cstate);
+
rot_cmd = &rstate->rot_cmd;
rot_cmd->master = (rstate->out_xpos == 0);
@@ -1460,6 +1490,8 @@
rot_cmd->hflip = rstate->hflip;
rot_cmd->vflip = rstate->vflip;
rot_cmd->secure = state->fb->flags & DRM_MODE_FB_SECURE ? true : false;
+ rot_cmd->prefill_bw = sde_crtc_get_property(sde_cstate,
+ CRTC_PROP_ROT_PREFILL_BW);
rot_cmd->dst_writeback = psde->sbuf_writeback;
if (sde_crtc_get_intf_mode(state->crtc) == INTF_MODE_VIDEO)