summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h26
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.h2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c3
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_mdss.h12
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_sspp.c2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_sspp.h4
-rw-r--r--drivers/gpu/drm/msm/sde/sde_plane.c471
7 files changed, 448 insertions, 72 deletions
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 21bd43607d69..b0b6bd01f775 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -71,20 +71,28 @@ struct msm_file_private {
};
enum msm_mdp_plane_property {
+ /* blob properties, always put these first */
+ PLANE_PROP_SCALER,
+ PLANE_PROP_CSC,
+
+ /* # of blob properties */
+ PLANE_PROP_BLOBCOUNT,
+
/* range properties */
- PLANE_PROP_ZPOS,
+ PLANE_PROP_ZPOS = PLANE_PROP_BLOBCOUNT,
PLANE_PROP_ALPHA,
PLANE_PROP_PREMULTIPLIED,
+ PLANE_PROP_H_DECIMATE,
+ PLANE_PROP_V_DECIMATE,
+ PLANE_PROP_SYNC_FENCE,
- /* enum properties */
-
- /* blob properties */
- PLANE_PROP_PIXEXT,
+ /* enum/bitmask properties */
+ PLANE_PROP_ROTATION,
+ PLANE_PROP_BLEND_OP,
+ PLANE_PROP_SRC_CONFIG,
- /* property counts */
- PLANE_PROP_COUNT,
- PLANE_PROP_FIRSTBLOB = PLANE_PROP_PIXEXT,
- PLANE_PROP_BLOBCOUNT = PLANE_PROP_COUNT - PLANE_PROP_FIRSTBLOB
+ /* total # of properties */
+ PLANE_PROP_COUNT
};
struct msm_vblank_ctrl {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index da610049fcba..f25bcf76dcdd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -242,6 +242,8 @@ struct sde_sspp_sub_blks {
u32 safe_lut;
u32 maxdwnscale;
u32 maxupscale;
+ u32 maxhdeciexp; /* max decimation is 2^value */
+ u32 maxvdeciexp; /* max decimation is 2^value */
struct sde_src_blk src_blk;
struct sde_scaler_blk scaler_blk;
struct sde_pp_blk csc_blk;
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 6ee17d8e0968..6e425ceb0b6f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_8996.c
@@ -70,6 +70,7 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.danger_lut = 0xFFFF,
.safe_lut = 0xFF00,
.maxdwnscale = 4, .maxupscale = 20,
+ .maxhdeciexp = 4, .maxvdeciexp = 4,
.src_blk = {.id = SDE_SSPP_SRC,
.base = 0x00, .len = 0x150,},
.scaler_blk = {.id = SDE_SSPP_SCALER_QSEED2,
@@ -89,6 +90,7 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.danger_lut = 0xFFFF,
.safe_lut = 0xFF00,
.maxdwnscale = 0, .maxupscale = 0,
+ .maxhdeciexp = 4, .maxvdeciexp = 4,
.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,},
.scaler_blk = {.id = 0, .base = 0x00, .len = 0x0,},
.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
@@ -102,6 +104,7 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
.danger_lut = 0xFFFF,
.safe_lut = 0xFF00,
.maxdwnscale = 0, .maxupscale = 0,
+ .maxhdeciexp = 4, .maxvdeciexp = 4,
.src_blk = {.id = SDE_SSPP_SRC, .base = 0x00, .len = 0x0,},
.scaler_blk = {.id = 0, .base = 0x00, .len = 0x0,},
.csc_blk = {.id = 0, .base = 0x00, .len = 0x0,},
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 56627fece9a3..2c1dffc61526 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -17,11 +17,23 @@
#include <linux/err.h>
#define SDE_NONE 0
+
+#ifndef SDE_CSC_MATRIX_COEFF_SIZE
#define SDE_CSC_MATRIX_COEFF_SIZE 9
+#endif
+
+#ifndef SDE_CSC_CLAMP_SIZE
#define SDE_CSC_CLAMP_SIZE 6
+#endif
+
+#ifndef SDE_CSC_BIAS_SIZE
#define SDE_CSC_BIAS_SIZE 3
+#endif
+#ifndef SDE_MAX_PLANES
#define SDE_MAX_PLANES 4
+#endif
+
#define PIPES_PER_STAGE 2
#define VALID_ROT_WB_FORMAT BIT(0)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index 59ee3b962dee..f998225e4595 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -176,6 +176,8 @@ static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx,
c = &ctx->hw;
opmode = SDE_REG_READ(c, SSPP_SRC_OP_MODE + idx);
+ opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD |
+ MDSS_MDP_OP_BWC_EN | MDSS_MDP_OP_PE_OVERRIDE);
/* format info */
fmt = cfg->src.format;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
index 768201c0bf72..23503be6653d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.h
@@ -117,6 +117,10 @@ struct sde_hw_pixel_ext {
};
+struct sde_hw_scaler3_cfg {
+ uint32_t filter_mode;
+};
+
/**
* struct sde_hw_pipe_cfg : Pipe description
* @src: source surface information
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 395967eb92b1..042343b00f4b 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
#include <linux/debugfs.h>
+#include <uapi/drm/sde_drm.h>
#include "sde_kms.h"
#include "sde_hwio.h"
#include "sde_hw_mdp_ctl.h"
@@ -26,11 +27,10 @@
#define SHARP_SMOOTH_THR_DEFAULT 8
#define SHARP_NOISE_THR_DEFAULT 2
-#define SDE_PIPE_NAME_SIZE 8
+#define SDE_NAME_SIZE 12
struct sde_plane {
struct drm_plane base;
- const char *name;
int mmu_id;
@@ -43,8 +43,9 @@ struct sde_plane {
struct sde_hw_pipe_cfg pipe_cfg;
struct sde_hw_pixel_ext pixel_ext;
struct sde_hw_sharp_cfg sharp_cfg;
+ struct sde_hw_scaler3_cfg scaler3_cfg;
- char pipe_name[SDE_PIPE_NAME_SIZE];
+ char pipe_name[SDE_NAME_SIZE];
/* debugfs related stuff */
struct dentry *debugfs_root;
@@ -54,23 +55,37 @@ struct sde_plane {
};
#define to_sde_plane(x) container_of(x, struct sde_plane, base)
+/* macro to obtain int/enum value from plane state, no error checking */
+#define SDE_PLANE_GETINT(S, X) ((S)->property_values[(X)])
+
+/* macro to obtain blob ptr from plane state, no error checking */
+#define SDE_PLANE_GETBLOB(S, X) ((S)->property_blobs[(X)])
+
static bool sde_plane_enabled(struct drm_plane_state *state)
{
return state->fb && state->crtc;
}
static void _sde_plane_set_scanout(struct drm_plane *plane,
+ struct sde_plane_state *pstate,
struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
{
struct sde_plane *psde = to_sde_plane(plane);
+ unsigned int shift;
int i;
if (pipe_cfg && fb && psde->pipe_hw->ops.setup_sourceaddress) {
/* stride */
+ if (SDE_PLANE_GETINT(pstate, PLANE_PROP_SRC_CONFIG) &
+ BIT(SDE_DRM_DEINTERLACE))
+ shift = 1;
+ else
+ shift = 0;
+
i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
while (i) {
--i;
- pipe_cfg->src.ystride[i] = fb->pitches[i];
+ pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
}
/* address */
@@ -83,7 +98,15 @@ static void _sde_plane_set_scanout(struct drm_plane *plane,
}
}
-static void _sde_plane_setup_scaler(struct drm_plane *plane,
+static void _sde_plane_setup_scaler3(struct drm_plane *plane,
+ uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
+ struct sde_hw_scaler3_cfg *scale_cfg,
+ struct sde_mdp_format_params *fmt,
+ uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
+{
+}
+
+static void _sde_plane_setup_scaler2(struct drm_plane *plane,
uint32_t src, uint32_t dst, uint32_t *phase_steps,
enum sde_hw_filter *filter, struct sde_mdp_format_params *fmt,
uint32_t chroma_subsampling)
@@ -196,6 +219,68 @@ static void _sde_plane_setup_pixel_ext(struct drm_plane *plane,
}
}
+static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
+ enum msm_mdp_plane_property property, size_t *byte_len)
+{
+ struct drm_property_blob *blob;
+ size_t len = 0;
+ void *ret = 0;
+
+ if (pstate && (property < PLANE_PROP_BLOBCOUNT)) {
+ blob = SDE_PLANE_GETBLOB(pstate, property);
+ if (blob) {
+ len = blob->length;
+ ret = &blob->data;
+ }
+ }
+
+ if (byte_len)
+ *byte_len = len;
+
+ return ret;
+}
+
+/**
+ * _sde_plane_verify_blob - verify incoming blob is big enough to contain
+ * sub-structure
+ * @blob_ptr: Pointer to start of incoming blob data
+ * @blob_size: Size of incoming blob data, in bytes
+ * @sub_ptr: Pointer to start of desired sub-structure
+ * @sub_size: Required size of sub-structure, in bytes
+ */
+static int _sde_plane_verify_blob(void *blob_ptr,
+ size_t blob_size,
+ void *sub_ptr,
+ size_t sub_size)
+{
+ /*
+ * Use the blob size provided by drm to check if there are enough
+ * bytes from the start of versioned sub-structures to the end of
+ * blob data:
+ *
+ * e.g.,
+ * blob_ptr --> struct blob_data {
+ * uint32_t version;
+ * sub_ptr --> struct blob_data_v1 v1;
+ * sub_ptr + sub_size --> struct blob_stuff more_stuff;
+ * blob_ptr + blob_size --> };
+ *
+ * It's important to check the actual number of bytes from the start
+ * of the sub-structure to the end of the blob data, and not just rely
+ * on something like,
+ *
+ * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
+ *
+ * This is because the start of the sub-structure can vary based on
+ * how the compiler pads the overall structure.
+ */
+ if (blob_ptr && sub_ptr)
+ /* return zero if end of blob >= end of sub-struct */
+ return ((unsigned char *)blob_ptr + blob_size) <
+ ((unsigned char *)sub_ptr + sub_size);
+ return -EINVAL;
+}
+
static void _sde_plane_setup_csc(struct sde_plane *psde,
struct sde_plane_state *pstate,
struct sde_mdp_format_params *fmt)
@@ -223,16 +308,66 @@ static void _sde_plane_setup_csc(struct sde_plane *psde,
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
};
+ struct sde_drm_csc *csc = NULL;
+ size_t csc_size = 0;
+ bool user_blob = false;
if (!psde->pipe_hw->ops.setup_csc)
return;
- if (fmt->is_yuv)
+ /* check for user space override */
+ csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
+ if (csc) {
+ struct sde_csc_cfg cfg;
+ int i;
+
+ /* user space override */
+ memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
+ switch (csc->version) {
+ case SDE_DRM_CSC_V1:
+ if (!_sde_plane_verify_blob(csc,
+ csc_size,
+ &csc->v1,
+ sizeof(struct sde_drm_csc_v1))) {
+ for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
+ cfg.csc_mv[i] =
+ csc->v1.ctm_coeff[i] >> 23;
+ for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
+ cfg.csc_pre_bv[i] =
+ csc->v1.pre_bias[i];
+ cfg.csc_post_bv[i] =
+ csc->v1.post_bias[i];
+ }
+ for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
+ cfg.csc_pre_lv[i] =
+ csc->v1.pre_clamp[i];
+ cfg.csc_post_lv[i] =
+ csc->v1.post_clamp[i];
+ }
+ user_blob = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!user_blob)
+ DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
+ else
+ psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
+ (struct sde_csc_cfg *)&cfg);
+ }
+
+ if (user_blob) {
+ DBG("User blobs override for CSC");
+ /* revert to kernel default */
+ } else if (fmt->is_yuv) {
psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
(struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L);
- else
+ } else {
psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
(struct sde_csc_cfg *)&sde_csc_NOP);
+ }
}
static int _sde_plane_mode_set(struct drm_plane *plane,
@@ -242,19 +377,32 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
- struct sde_plane *psde = to_sde_plane(plane);
+ struct sde_plane *psde;
struct sde_plane_state *pstate;
const struct mdp_format *format;
uint32_t nplanes, pix_format, tmp;
+ uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
+ uint32_t src_fmt_flags;
int i;
struct sde_mdp_format_params *fmt;
struct sde_hw_pixel_ext *pe;
- int ret = 0;
+ size_t sc_u_size = 0;
+ struct sde_drm_scaler *sc_u = NULL;
+ struct sde_drm_scaler_v1 *sc_u1 = NULL;
DBG("");
- nplanes = drm_format_num_planes(fb->pixel_format);
+ if (!plane || !plane->state) {
+ DRM_ERROR("Invalid plane/state\n");
+ return -EINVAL;
+ }
+ if (!crtc || !fb) {
+ DRM_ERROR("Invalid crtc/fb\n");
+ return -EINVAL;
+ }
+ psde = to_sde_plane(plane);
pstate = to_sde_plane_state(plane->state);
+ nplanes = drm_format_num_planes(fb->pixel_format);
format = to_mdp_format(msm_framebuffer_format(fb));
pix_format = format->base.pixel_format;
@@ -271,6 +419,7 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
/* update format configuration */
memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
+ src_fmt_flags = 0;
psde->pipe_cfg.src.format = sde_mdp_get_format_params(pix_format,
fb->modifier[0]);
@@ -278,7 +427,30 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
psde->pipe_cfg.src.height = fb->height;
psde->pipe_cfg.src.num_planes = nplanes;
- _sde_plane_set_scanout(plane, &psde->pipe_cfg, fb);
+ _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
+
+ /* decimation */
+ psde->pipe_cfg.horz_decimation =
+ SDE_PLANE_GETINT(pstate, PLANE_PROP_H_DECIMATE);
+ psde->pipe_cfg.vert_decimation =
+ SDE_PLANE_GETINT(pstate, PLANE_PROP_V_DECIMATE);
+
+ /* flags */
+ DBG("Flags 0x%llX, rotation 0x%llX",
+ SDE_PLANE_GETINT(pstate, PLANE_PROP_SRC_CONFIG),
+ SDE_PLANE_GETINT(pstate, PLANE_PROP_ROTATION));
+ if (SDE_PLANE_GETINT(pstate, PLANE_PROP_ROTATION) &
+ BIT(DRM_REFLECT_X))
+ src_fmt_flags |= SDE_SSPP_FLIP_LR;
+ if (SDE_PLANE_GETINT(pstate, PLANE_PROP_ROTATION) &
+ BIT(DRM_REFLECT_Y))
+ src_fmt_flags |= SDE_SSPP_FLIP_UD;
+ if (SDE_PLANE_GETINT(pstate, PLANE_PROP_SRC_CONFIG) &
+ BIT(SDE_DRM_DEINTERLACE)) {
+ src_h /= 2;
+ src_y = DIV_ROUND_UP(src_y, 2);
+ src_y &= ~0x1;
+ }
psde->pipe_cfg.src_rect.x = src_x;
psde->pipe_cfg.src_rect.y = src_y;
@@ -290,33 +462,89 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
psde->pipe_cfg.dst_rect.w = crtc_w;
psde->pipe_cfg.dst_rect.h = crtc_h;
- psde->pipe_cfg.horz_decimation = 0;
- psde->pipe_cfg.vert_decimation = 0;
-
/* get sde pixel format definition */
fmt = psde->pipe_cfg.src.format;
- /* update pixel extensions */
- pe = &(psde->pixel_ext);
- if (!pe->enable_pxl_ext) {
- uint32_t chroma_subsample_h, chroma_subsample_v;
-
- chroma_subsample_h = psde->pipe_cfg.horz_decimation ? 1 :
- drm_format_horz_chroma_subsampling(pix_format);
- chroma_subsample_v = psde->pipe_cfg.vert_decimation ? 1 :
- drm_format_vert_chroma_subsampling(pix_format);
+ /* don't chroma subsample if decimating */
+ chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
+ drm_format_horz_chroma_subsampling(pix_format);
+ chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
+ drm_format_vert_chroma_subsampling(pix_format);
- memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
+ pe = &(psde->pixel_ext);
+ memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
+
+ /* get scaler config from user space */
+ sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
+ if (sc_u) {
+ switch (sc_u->version) {
+ case SDE_DRM_SCALER_V1:
+ if (!_sde_plane_verify_blob(sc_u,
+ sc_u_size,
+ &sc_u->v1,
+ sizeof(*sc_u1)))
+ sc_u1 = &sc_u->v1;
+ break;
+ default:
+ DBG("Unrecognized scaler blob v%lld", sc_u->version);
+ break;
+ }
+ }
- /* calculate phase steps */
- _sde_plane_setup_scaler(plane, src_w, crtc_w,
- pe->phase_step_x,
- pe->horz_filter, fmt, chroma_subsample_h);
- _sde_plane_setup_scaler(plane, src_h, crtc_h,
- pe->phase_step_y,
- pe->vert_filter, fmt, chroma_subsample_v);
+ /* update scaler */
+ if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
+ if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
+ DBG("QSEED3 blob detected");
+ else
+ _sde_plane_setup_scaler3(plane, src_w, src_h, crtc_w,
+ crtc_h, &psde->scaler3_cfg, fmt,
+ chroma_subsmpl_h, chroma_subsmpl_v);
+ } else {
+ /* always calculate basic scaler config */
+ if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
+ /* populate from user space */
+ for (i = 0; i < SDE_MAX_PLANES; i++) {
+ pe->init_phase_x[i] = sc_u1->init_phase_x[i];
+ pe->phase_step_x[i] = sc_u1->phase_step_x[i];
+ pe->init_phase_y[i] = sc_u1->init_phase_y[i];
+ pe->phase_step_y[i] = sc_u1->phase_step_y[i];
+
+ pe->horz_filter[i] = sc_u1->horz_filter[i];
+ pe->vert_filter[i] = sc_u1->vert_filter[i];
+ }
+ } else {
+ /* calculate phase steps */
+ _sde_plane_setup_scaler2(plane, src_w, crtc_w,
+ pe->phase_step_x,
+ pe->horz_filter, fmt, chroma_subsmpl_h);
+ _sde_plane_setup_scaler2(plane, src_h, crtc_h,
+ pe->phase_step_y,
+ pe->vert_filter, fmt, chroma_subsmpl_v);
+ }
+ }
- /* calculate left/right/top/bottom pixel extentions */
+ /* update pixel extensions */
+ if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
+ /* populate from user space */
+ for (i = 0; i < SDE_MAX_PLANES; i++) {
+ pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
+ pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
+ pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
+ pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
+ pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
+ pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
+ pe->roi_w[i] = sc_u1->lr.roi[i];
+
+ pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
+ pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
+ pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
+ pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
+ pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
+ pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
+ pe->roi_h[i] = sc_u1->tb.roi[i];
+ }
+ } else {
+ /* calculate left/right/top/bottom pixel extensions */
tmp = DECIMATED_DIMENSION(src_w,
psde->pipe_cfg.horz_decimation);
if (fmt->is_yuv)
@@ -326,7 +554,7 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
pe->roi_w,
pe->num_ext_pxls_left,
pe->num_ext_pxls_right, pe->horz_filter, fmt,
- chroma_subsample_h, 0);
+ chroma_subsmpl_h, 0);
tmp = DECIMATED_DIMENSION(src_h,
psde->pipe_cfg.vert_decimation);
@@ -335,7 +563,7 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
pe->roi_h,
pe->num_ext_pxls_top,
pe->num_ext_pxls_btm, pe->vert_filter, fmt,
- chroma_subsample_v, 1);
+ chroma_subsmpl_v, 1);
for (i = 0; i < SDE_MAX_PLANES; i++) {
if (pe->num_ext_pxls_left[i] >= 0)
@@ -370,7 +598,7 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
if (psde->pipe_hw->ops.setup_sourceformat)
psde->pipe_hw->ops.setup_sourceformat(psde->pipe_hw,
- &psde->pipe_cfg, 0);
+ &psde->pipe_cfg, src_fmt_flags);
if (psde->pipe_hw->ops.setup_rects)
psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
&psde->pipe_cfg, &psde->pixel_ext);
@@ -389,7 +617,7 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
if (fmt->is_yuv)
_sde_plane_setup_csc(psde, pstate, fmt);
- return ret;
+ return 0;
}
static int sde_plane_prepare_fb(struct drm_plane *plane,
@@ -484,17 +712,27 @@ static int sde_plane_atomic_check(struct drm_plane *plane,
static void sde_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
- struct sde_plane *sde_plane = to_sde_plane(plane);
- struct drm_plane_state *state = plane->state;
+ struct sde_plane *sde_plane;
+ struct drm_plane_state *state;
+ struct sde_plane_state *pstate;
DBG("%s: update", sde_plane->pipe_name);
+ if (!plane || !plane->state) {
+ DRM_ERROR("Invalid plane/state\n");
+ return;
+ }
+
+ sde_plane = to_sde_plane(plane);
+ state = plane->state;
+ pstate = to_sde_plane_state(state);
+
if (!sde_plane_enabled(state)) {
- to_sde_plane_state(state)->pending = true;
- } else if (to_sde_plane_state(state)->mode_changed) {
+ pstate->pending = true;
+ } else if (pstate->mode_changed) {
int ret;
- to_sde_plane_state(state)->pending = true;
+ pstate->pending = true;
ret = _sde_plane_mode_set(plane,
state->crtc, state->fb,
state->crtc_x, state->crtc_y,
@@ -504,7 +742,8 @@ static void sde_plane_atomic_update(struct drm_plane *plane,
/* atomic_check should have ensured that this doesn't fail */
WARN_ON(ret < 0);
} else {
- _sde_plane_set_scanout(plane, &sde_plane->pipe_cfg, state->fb);
+ _sde_plane_set_scanout(plane, pstate,
+ &sde_plane->pipe_cfg, state->fb);
}
}
@@ -519,7 +758,7 @@ static void _sde_plane_install_range_property(struct drm_plane *plane,
*prop = drm_property_create_range(dev,
0 /* flags */, name, min, max);
if (*prop == 0)
- DRM_ERROR("Create property %s failed\n", name);
+ DRM_ERROR("Create %s property failed\n", name);
}
/* always attach property, if created */
@@ -528,28 +767,137 @@ static void _sde_plane_install_range_property(struct drm_plane *plane,
}
}
+static void _sde_plane_install_rotation_property(struct drm_plane *plane,
+ struct drm_device *dev, struct drm_property **prop)
+{
+ if (plane && dev && prop) {
+ /* only create the property once */
+ if (*prop == 0) {
+ *prop = drm_mode_create_rotation_property(dev,
+ BIT(DRM_REFLECT_X) |
+ BIT(DRM_REFLECT_Y));
+ if (*prop == 0)
+ DRM_ERROR("Create rotation property failed\n");
+ }
+
+ /* always attach property, if created */
+ if (*prop)
+ drm_object_attach_property(&plane->base, *prop, 0);
+ }
+}
+
+static void _sde_plane_install_enum_property(struct drm_plane *plane,
+ struct drm_device *dev, const char *name, int is_bitmask,
+ const struct drm_prop_enum_list *values, int num_values,
+ struct drm_property **prop)
+{
+ if (plane && dev && name && prop && values && num_values) {
+ /* only create the property once */
+ if (*prop == 0) {
+ /* 'bitmask' is a special type of 'enum' */
+ if (is_bitmask)
+ *prop = drm_property_create_bitmask(dev,
+ DRM_MODE_PROP_BITMASK, name,
+ values, num_values, -1);
+ else
+ *prop = drm_property_create_enum(dev,
+ DRM_MODE_PROP_ENUM, name,
+ values, num_values);
+ if (*prop == 0)
+ DRM_ERROR("Create %s property failed\n", name);
+ }
+
+ /* always attach property, if created */
+ if (*prop)
+ drm_object_attach_property(&plane->base, *prop, 0);
+ }
+}
+
static void _sde_plane_install_blob_property(struct drm_plane *plane,
struct drm_device *dev, const char *name,
struct drm_property **prop)
{
+ if (plane && dev && name && prop) {
+ /* only create the property once */
+ if (*prop == 0) {
+ /* use 'create' for blob property place holder */
+ *prop = drm_property_create(dev,
+ DRM_MODE_PROP_BLOB, name, 0);
+ if (*prop == 0)
+ DRM_ERROR("Create %s property failed\n", name);
+ }
+
+ /* always attach property, if created */
+ if (*prop)
+ drm_object_attach_property(&plane->base, *prop, 0);
+ }
}
/* helper to install properties which are common to planes and crtcs */
static void _sde_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj)
{
+ static const struct drm_prop_enum_list e_blend_op[] = {
+ {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
+ {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
+ {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
+ {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
+ };
+ static const struct drm_prop_enum_list e_src_config[] = {
+ {SDE_DRM_DEINTERLACE, "deinterlace"}
+ };
+ struct sde_plane *psde = to_sde_plane(plane);
struct drm_device *dev = plane->dev;
struct msm_drm_private *dev_priv = dev->dev_private;
+ const struct sde_sspp_sub_blks *sblk = 0;
+ const struct sde_sspp_cfg *cfg = 0;
DBG("");
- /* range/enum properties */
+ if (psde && psde->pipe_hw)
+ cfg = psde->pipe_hw->cap;
+ if (cfg)
+ sblk = cfg->sblk;
+ if (!sblk) {
+ DRM_ERROR("Failed to identify catalog definition\n");
+ return;
+ }
+
+ /* range properties */
_sde_plane_install_range_property(plane, dev, "zpos", 1, 255, 1,
&(dev_priv->plane_property[PLANE_PROP_ZPOS]));
+ _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
+ &(dev_priv->plane_property[PLANE_PROP_ALPHA]));
+
+ _sde_plane_install_range_property(plane, dev, "h_decimate",
+ 0, sblk->maxhdeciexp, 0,
+ &(dev_priv->plane_property[PLANE_PROP_H_DECIMATE]));
+
+ _sde_plane_install_range_property(plane, dev, "v_decimate",
+ 0, sblk->maxvdeciexp, 0,
+ &(dev_priv->plane_property[PLANE_PROP_V_DECIMATE]));
+
+ _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, 0,
+ &(dev_priv->plane_property[PLANE_PROP_SYNC_FENCE]));
+
+ /* standard properties */
+ _sde_plane_install_rotation_property(plane, dev,
+ &(dev_priv->plane_property[PLANE_PROP_ROTATION]));
+
+ /* enum/bitmask properties */
+ _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
+ e_blend_op, ARRAY_SIZE(e_blend_op),
+ &(dev_priv->plane_property[PLANE_PROP_BLEND_OP]));
+ _sde_plane_install_enum_property(plane, dev, "src_config", 1,
+ e_src_config, ARRAY_SIZE(e_src_config),
+ &(dev_priv->plane_property[PLANE_PROP_SRC_CONFIG]));
+
/* blob properties */
- _sde_plane_install_blob_property(plane, dev, "pixext",
- &(dev_priv->plane_property[PLANE_PROP_PIXEXT]));
+ _sde_plane_install_blob_property(plane, dev, "scaler",
+ &(dev_priv->plane_property[PLANE_PROP_SCALER]));
+ _sde_plane_install_blob_property(plane, dev, "csc",
+ &(dev_priv->plane_property[PLANE_PROP_CSC]));
}
static int sde_plane_atomic_set_property(struct drm_plane *plane,
@@ -558,7 +906,7 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane,
{
struct drm_device *dev = plane->dev;
struct sde_plane_state *pstate;
- struct drm_property_blob *blob, **prop_blob;
+ struct drm_property_blob *blob, **prp_blob;
struct msm_drm_private *dev_priv = dev->dev_private;
int idx, ret = -EINVAL;
@@ -570,25 +918,26 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane,
if (dev_priv->plane_property[idx] == property) {
DBG("Set property %d <= %d", idx, (int)val);
- /* FUTURE: Add special handling here */
- if (property->flags & DRM_MODE_PROP_BLOB) {
+ /* extra handling for incoming blob properties */
+ if ((property->flags & DRM_MODE_PROP_BLOB) &&
+ (idx < PLANE_PROP_BLOBCOUNT)) {
+ /* DRM lookup also takes a reference */
blob = drm_property_lookup_blob(dev,
(uint32_t)val);
if (!blob) {
DRM_ERROR("Blob not found\n");
val = 0;
} else {
+ DBG("Blob %u saved", blob->base.id);
val = blob->base.id;
/* save blobs for later */
- prop_blob =
- &pstate->property_blobs[idx -
- PLANE_PROP_FIRSTBLOB];
+ prp_blob = &pstate->property_blobs[idx];
/* need to clear previous reference */
- if (*prop_blob)
+ if (*prp_blob)
drm_property_unreference_blob(
- *prop_blob);
- *prop_blob = blob;
+ *prp_blob);
+ *prp_blob = blob;
}
}
pstate->property_values[idx] = val;
@@ -608,8 +957,7 @@ static int sde_plane_set_property(struct drm_plane *plane,
int rc;
DBG("");
- rc = sde_plane_atomic_set_property(plane, plane->state, property,
- val);
+ rc = sde_plane_atomic_set_property(plane, plane->state, property, val);
return rc;
}
@@ -623,7 +971,6 @@ static int sde_plane_atomic_get_property(struct drm_plane *plane,
int idx, ret = -EINVAL;
DBG("");
-
pstate = to_sde_plane_state(state);
for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
@@ -728,8 +1075,6 @@ static void sde_plane_reset(struct drm_plane *plane)
kfree(to_sde_plane_state(plane->state));
pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
- memset(pstate, 0, sizeof(struct sde_plane_state));
-
/* assign default blend parameters */
pstate->property_values[PLANE_PROP_ALPHA] = 255;
pstate->property_values[PLANE_PROP_PREMULTIPLIED] = 0;
@@ -875,8 +1220,6 @@ struct drm_plane *sde_plane_init(struct drm_device *dev,
drm_plane_helper_add(plane, &sde_plane_helper_funcs);
- _sde_plane_install_properties(plane, &plane->base);
-
psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, sde_cat);
if (IS_ERR(psde->pipe_hw)) {
ret = PTR_ERR(psde->pipe_hw);
@@ -884,8 +1227,10 @@ struct drm_plane *sde_plane_init(struct drm_device *dev,
goto fail;
}
+ _sde_plane_install_properties(plane, &plane->base);
+
/* save user friendly pipe name for later */
- snprintf(psde->pipe_name, SDE_PIPE_NAME_SIZE, "pipe%u", pipe);
+ snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
_sde_plane_init_debugfs(psde, kms);