drm/msm/sde: add ts prefill support to sde plane
Prefill with traffic shaper is used to amortize prefill
requests until the layer is active. Add ts prefill support
to sde plane.
CRs-Fixed: 2037879
Change-Id: I7bfbaed4a82d11d9bdf8de48633f3cdde4bfd53f
Signed-off-by: Alan Kwong <akwong@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index f596989..2cd9aa1 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -110,6 +110,8 @@
PLANE_PROP_ROT_DST_Y,
PLANE_PROP_ROT_DST_W,
PLANE_PROP_ROT_DST_H,
+ PLANE_PROP_PREFILL_SIZE,
+ PLANE_PROP_PREFILL_TIME,
/* enum/bitmask properties */
PLANE_PROP_ROTATION,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 6e39a59..30e63da 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1055,6 +1055,13 @@
set_bit(SDE_SSPP_SRC, &sspp->features);
+ if (sde_cfg->ts_prefill_rev == 1) {
+ set_bit(SDE_SSPP_TS_PREFILL, &sspp->features);
+ } else if (sde_cfg->ts_prefill_rev == 2) {
+ set_bit(SDE_SSPP_TS_PREFILL, &sspp->features);
+ set_bit(SDE_SSPP_TS_PREFILL_REC1, &sspp->features);
+ }
+
sblk->smart_dma_priority =
PROP_VALUE_ACCESS(prop_value, SSPP_SMART_DMA, i);
@@ -2584,12 +2591,16 @@
sde_cfg->has_wb_ubwc = true;
sde_cfg->perf.min_prefill_lines = 25;
sde_cfg->vbif_qos_nlvl = 4;
+ sde_cfg->ts_prefill_rev = 1;
+ sde_cfg->perf.min_prefill_lines = 25;
break;
case SDE_HW_VER_400:
/* update sdm845 target here */
sde_cfg->has_wb_ubwc = true;
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
+ sde_cfg->ts_prefill_rev = 2;
+ sde_cfg->perf.min_prefill_lines = 24;
break;
default:
sde_cfg->perf.min_prefill_lines = 0xffff;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 9df3711..e24192b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -111,6 +111,8 @@
* @SDE_SSPP_SMART_DMA_V1, SmartDMA 1.0 support
* @SDE_SSPP_SMART_DMA_V2, SmartDMA 2.0 support
* @SDE_SSPP_SBUF, SSPP support inline stream buffer
+ * @SDE_SSPP_TS_PREFILL Supports prefill with traffic shaper
+ * @SDE_SSPP_TS_PREFILL_REC1 Supports prefill with traffic shaper multirec
* @SDE_SSPP_MAX maximum value
*/
enum {
@@ -130,6 +132,8 @@
SDE_SSPP_SMART_DMA_V1,
SDE_SSPP_SMART_DMA_V2,
SDE_SSPP_SBUF,
+ SDE_SSPP_TS_PREFILL,
+ SDE_SSPP_TS_PREFILL_REC1,
SDE_SSPP_MAX
};
@@ -763,6 +767,7 @@
* @vig_formats Supported formats for vig pipe
* @wb_formats Supported formats for wb
* @vbif_qos_nlvl number of vbif QoS priority level
+ * @ts_prefill_rev prefill traffic shaper feature revision
*/
struct sde_mdss_cfg {
u32 hwversion;
@@ -783,6 +788,7 @@
u32 sbuf_headroom;
bool has_idle_pc;
u32 vbif_qos_nlvl;
+ u32 ts_prefill_rev;
u32 mdss_count;
struct sde_mdss_base_cfg mdss[MAX_BLOCKS];
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index a1f5cee..694d267 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -79,11 +79,16 @@
#define SSPP_SW_PIX_EXT_C3_LR 0x120
#define SSPP_SW_PIX_EXT_C3_TB 0x124
#define SSPP_SW_PIX_EXT_C3_REQ_PIXELS 0x128
+#define SSPP_TRAFFIC_SHAPER 0x130
#define SSPP_UBWC_ERROR_STATUS 0x138
+#define SSPP_TRAFFIC_SHAPER_PREFILL 0x150
+#define SSPP_TRAFFIC_SHAPER_REC1_PREFILL 0x154
+#define SSPP_TRAFFIC_SHAPER_REC1 0x158
#define SSPP_EXCL_REC_SIZE 0x1B4
#define SSPP_EXCL_REC_XY 0x1B8
#define SSPP_VIG_OP_MODE 0x0
#define SSPP_VIG_CSC_10_OP_MODE 0x0
+#define SSPP_TRAFFIC_SHAPER_BPC_MAX 0xFF
/* SSPP_QOS_CTRL */
#define SSPP_QOS_CTRL_VBLANK_EN BIT(16)
@@ -186,6 +191,9 @@
#define VIG_CSC_10_EN BIT(0)
#define CSC_10BIT_OFFSET 4
+/* traffic shaper clock in Hz */
+#define TS_CLK 19200000
+
static inline int _sspp_subblk_offset(struct sde_hw_pipe *ctx,
int s_id,
u32 *idx)
@@ -1041,6 +1049,51 @@
status->rd_ptr[1] = val & 0xffff;
}
+static void sde_hw_sspp_setup_ts_prefill(struct sde_hw_pipe *ctx,
+ struct sde_hw_pipe_ts_cfg *cfg,
+ enum sde_sspp_multirect_index index)
+{
+ u32 idx;
+ u32 ts_offset, ts_prefill_offset;
+ u32 ts_count = 0, ts_bytes = 0;
+ const struct sde_sspp_cfg *cap;
+
+ if (!ctx || !cfg || !ctx->cap)
+ return;
+
+ if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx))
+ return;
+
+ cap = ctx->cap;
+
+ if (index == SDE_SSPP_RECT_0 &&
+ test_bit(SDE_SSPP_TS_PREFILL, &cap->features)) {
+ ts_offset = SSPP_TRAFFIC_SHAPER;
+ ts_prefill_offset = SSPP_TRAFFIC_SHAPER_PREFILL;
+ } else if (index == SDE_SSPP_RECT_1 &&
+ test_bit(SDE_SSPP_TS_PREFILL_REC1, &cap->features)) {
+ ts_offset = SSPP_TRAFFIC_SHAPER_REC1;
+ ts_prefill_offset = SSPP_TRAFFIC_SHAPER_REC1_PREFILL;
+ } else {
+ return;
+ }
+
+ if (cfg->time) {
+ ts_bytes = mult_frac(TS_CLK * 1000000ULL, cfg->size,
+ cfg->time);
+ if (ts_bytes > SSPP_TRAFFIC_SHAPER_BPC_MAX)
+ ts_bytes = SSPP_TRAFFIC_SHAPER_BPC_MAX;
+ }
+
+ if (ts_bytes) {
+ ts_count = DIV_ROUND_UP_ULL(cfg->size, ts_bytes);
+ ts_bytes |= BIT(31) | BIT(27);
+ }
+
+ SDE_REG_WRITE(&ctx->hw, ts_offset, ts_bytes);
+ SDE_REG_WRITE(&ctx->hw, ts_prefill_offset, ts_count);
+}
+
static void _setup_layer_ops(struct sde_hw_pipe *c,
unsigned long features)
{
@@ -1062,6 +1115,9 @@
c->ops.setup_qos_ctrl = sde_hw_sspp_setup_qos_ctrl;
}
+ if (test_bit(SDE_SSPP_TS_PREFILL, &features))
+ c->ops.setup_ts_prefill = sde_hw_sspp_setup_ts_prefill;
+
if (test_bit(SDE_SSPP_CSC, &features) ||
test_bit(SDE_SSPP_CSC_10BIT, &features))
c->ops.setup_csc = sde_hw_sspp_setup_csc;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 1b81e54..010b363 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -343,6 +343,16 @@
};
/**
+ * struct sde_hw_pipe_ts_cfg - traffic shaper configuration
+ * @size: size to prefill in bytes, or zero to disable
+ * @time: time to prefill in usec, or zero to disable
+ */
+struct sde_hw_pipe_ts_cfg {
+ u64 size;
+ u64 time;
+};
+
+/**
* Maximum number of stream buffer plane
*/
#define SDE_PIPE_SBUF_PLANE_NUM 2
@@ -554,6 +564,16 @@
*/
void (*get_sbuf_status)(struct sde_hw_pipe *ctx,
struct sde_hw_pipe_sbuf_status *status);
+
+ /**
+ * setup_ts_prefill - setup prefill traffic shaper
+ * @ctx: Pointer to pipe context
+ * @cfg: Pointer to traffic shaper configuration
+ * @index: rectangle index in multirect
+ */
+ void (*setup_ts_prefill)(struct sde_hw_pipe *ctx,
+ struct sde_hw_pipe_ts_cfg *cfg,
+ enum sde_sspp_multirect_index index);
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index f2ea15f..36764ba 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -629,6 +629,55 @@
sde_vbif_set_qos_remap(sde_kms, &qos_params);
}
+/**
+ * _sde_plane_set_ts_prefill - set prefill with traffic shaper
+ * @plane: Pointer to drm plane
+ * @pstate: Pointer to sde plane state
+ */
+static void _sde_plane_set_ts_prefill(struct drm_plane *plane,
+ struct sde_plane_state *pstate)
+{
+ struct sde_plane *psde;
+ struct sde_hw_pipe_ts_cfg cfg;
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+
+ if (!plane || !plane->dev) {
+ SDE_ERROR("invalid arguments");
+ return;
+ }
+
+ priv = plane->dev->dev_private;
+ if (!priv || !priv->kms) {
+ SDE_ERROR("invalid KMS reference\n");
+ return;
+ }
+
+ sde_kms = to_sde_kms(priv->kms);
+ psde = to_sde_plane(plane);
+ if (!psde->pipe_hw) {
+ SDE_ERROR("invalid pipe reference\n");
+ return;
+ }
+
+ if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_ts_prefill)
+ return;
+
+ _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_VBLANK_AMORTIZE);
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.size = sde_plane_get_property(pstate,
+ PLANE_PROP_PREFILL_SIZE);
+ cfg.time = sde_plane_get_property(pstate,
+ PLANE_PROP_PREFILL_TIME);
+
+ SDE_DEBUG("plane%d size:%llu time:%llu\n",
+ plane->base.id, cfg.size, cfg.time);
+ SDE_EVT32(DRMID(plane), cfg.size, cfg.time);
+ psde->pipe_hw->ops.setup_ts_prefill(psde->pipe_hw, &cfg,
+ pstate->multirect_index);
+}
+
/* helper to update a state's input fence pointer from the property */
static void _sde_plane_set_input_fence(struct sde_plane *psde,
struct sde_plane_state *pstate, uint64_t fd)
@@ -2899,6 +2948,10 @@
case PLANE_PROP_BLEND_OP:
/* no special action required */
break;
+ case PLANE_PROP_PREFILL_SIZE:
+ case PLANE_PROP_PREFILL_TIME:
+ pstate->dirty |= SDE_PLANE_DIRTY_PERF;
+ break;
case PLANE_PROP_ROT_DST_X:
case PLANE_PROP_ROT_DST_Y:
case PLANE_PROP_ROT_DST_W:
@@ -3090,6 +3143,8 @@
if (plane->type != DRM_PLANE_TYPE_CURSOR) {
_sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
_sde_plane_set_ot_limit(plane, crtc);
+ if (pstate->dirty & SDE_PLANE_DIRTY_PERF)
+ _sde_plane_set_ts_prefill(plane, pstate);
}
_sde_plane_set_qos_remap(plane);
@@ -3278,6 +3333,13 @@
msm_property_install_range(&psde->property_info, "color_fill",
0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
+ msm_property_install_range(&psde->property_info,
+ "prefill_size", 0x0, 0, ~0, 0,
+ PLANE_PROP_PREFILL_SIZE);
+ msm_property_install_range(&psde->property_info,
+ "prefill_time", 0x0, 0, ~0, 0,
+ PLANE_PROP_PREFILL_TIME);
+
info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
if (!info) {
SDE_ERROR("failed to allocate info memory\n");
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 2056a70..47611d1 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -95,6 +95,7 @@
#define SDE_PLANE_DIRTY_RECTS 0x1
#define SDE_PLANE_DIRTY_FORMAT 0x2
#define SDE_PLANE_DIRTY_SHARPEN 0x4
+#define SDE_PLANE_DIRTY_PERF 0x8
#define SDE_PLANE_DIRTY_ALL 0xFFFFFFFF
/**