summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c7
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.xml.h18
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.c45
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.c123
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.h32
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c75
-rw-r--r--drivers/gpu/drm/msm/sde/sde_plane.c1257
-rw-r--r--drivers/gpu/drm/msm/sde/sde_plane.h6
-rw-r--r--drivers/gpu/drm/msm/sde/sde_rm.c42
-rw-r--r--drivers/gpu/drm/msm/sde/sde_rm.h14
10 files changed, 1072 insertions, 547 deletions
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index c377f3759e67..020b1d84ae7a 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -48,6 +48,9 @@ static LIST_HEAD(sde_hdmi_list);
#define HDMI_SCDC_ERR_DET_2_H 0x55
#define HDMI_SCDC_ERR_DET_CHECKSUM 0x56
+#define HDMI_DISPLAY_MAX_WIDTH 4096
+#define HDMI_DISPLAY_MAX_HEIGHT 2160
+
static const struct of_device_id sde_hdmi_dt_match[] = {
{.compatible = "qcom,hdmi-display"},
{}
@@ -1428,8 +1431,8 @@ int sde_hdmi_get_info(struct msm_display_info *info,
MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_VID_MODE;
}
info->is_connected = hdmi_display->connected;
- info->max_width = 4096;
- info->max_height = 2160;
+ info->max_width = HDMI_DISPLAY_MAX_WIDTH;
+ info->max_height = HDMI_DISPLAY_MAX_HEIGHT;
info->compression = MSM_DISPLAY_COMPRESS_NONE;
mutex_unlock(&hdmi_display->display_lock);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
index 0956617442af..ea485a2ec2cd 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
@@ -466,13 +466,13 @@ static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val)
#define REG_HDMI_CEC_RD_FILTER 0x000002b0
#define REG_HDMI_ACTIVE_HSYNC 0x000002b4
-#define HDMI_ACTIVE_HSYNC_START__MASK 0x00000fff
+#define HDMI_ACTIVE_HSYNC_START__MASK 0x00001fff
#define HDMI_ACTIVE_HSYNC_START__SHIFT 0
static inline uint32_t HDMI_ACTIVE_HSYNC_START(uint32_t val)
{
return ((val) << HDMI_ACTIVE_HSYNC_START__SHIFT) & HDMI_ACTIVE_HSYNC_START__MASK;
}
-#define HDMI_ACTIVE_HSYNC_END__MASK 0x0fff0000
+#define HDMI_ACTIVE_HSYNC_END__MASK 0x1fff0000
#define HDMI_ACTIVE_HSYNC_END__SHIFT 16
static inline uint32_t HDMI_ACTIVE_HSYNC_END(uint32_t val)
{
@@ -480,13 +480,13 @@ static inline uint32_t HDMI_ACTIVE_HSYNC_END(uint32_t val)
}
#define REG_HDMI_ACTIVE_VSYNC 0x000002b8
-#define HDMI_ACTIVE_VSYNC_START__MASK 0x00000fff
+#define HDMI_ACTIVE_VSYNC_START__MASK 0x00001fff
#define HDMI_ACTIVE_VSYNC_START__SHIFT 0
static inline uint32_t HDMI_ACTIVE_VSYNC_START(uint32_t val)
{
return ((val) << HDMI_ACTIVE_VSYNC_START__SHIFT) & HDMI_ACTIVE_VSYNC_START__MASK;
}
-#define HDMI_ACTIVE_VSYNC_END__MASK 0x0fff0000
+#define HDMI_ACTIVE_VSYNC_END__MASK 0x1fff0000
#define HDMI_ACTIVE_VSYNC_END__SHIFT 16
static inline uint32_t HDMI_ACTIVE_VSYNC_END(uint32_t val)
{
@@ -494,13 +494,13 @@ static inline uint32_t HDMI_ACTIVE_VSYNC_END(uint32_t val)
}
#define REG_HDMI_VSYNC_ACTIVE_F2 0x000002bc
-#define HDMI_VSYNC_ACTIVE_F2_START__MASK 0x00000fff
+#define HDMI_VSYNC_ACTIVE_F2_START__MASK 0x00001fff
#define HDMI_VSYNC_ACTIVE_F2_START__SHIFT 0
static inline uint32_t HDMI_VSYNC_ACTIVE_F2_START(uint32_t val)
{
return ((val) << HDMI_VSYNC_ACTIVE_F2_START__SHIFT) & HDMI_VSYNC_ACTIVE_F2_START__MASK;
}
-#define HDMI_VSYNC_ACTIVE_F2_END__MASK 0x0fff0000
+#define HDMI_VSYNC_ACTIVE_F2_END__MASK 0x1fff0000
#define HDMI_VSYNC_ACTIVE_F2_END__SHIFT 16
static inline uint32_t HDMI_VSYNC_ACTIVE_F2_END(uint32_t val)
{
@@ -508,13 +508,13 @@ static inline uint32_t HDMI_VSYNC_ACTIVE_F2_END(uint32_t val)
}
#define REG_HDMI_TOTAL 0x000002c0
-#define HDMI_TOTAL_H_TOTAL__MASK 0x00000fff
+#define HDMI_TOTAL_H_TOTAL__MASK 0x00001fff
#define HDMI_TOTAL_H_TOTAL__SHIFT 0
static inline uint32_t HDMI_TOTAL_H_TOTAL(uint32_t val)
{
return ((val) << HDMI_TOTAL_H_TOTAL__SHIFT) & HDMI_TOTAL_H_TOTAL__MASK;
}
-#define HDMI_TOTAL_V_TOTAL__MASK 0x0fff0000
+#define HDMI_TOTAL_V_TOTAL__MASK 0x1fff0000
#define HDMI_TOTAL_V_TOTAL__SHIFT 16
static inline uint32_t HDMI_TOTAL_V_TOTAL(uint32_t val)
{
@@ -522,7 +522,7 @@ static inline uint32_t HDMI_TOTAL_V_TOTAL(uint32_t val)
}
#define REG_HDMI_VSYNC_TOTAL_F2 0x000002c4
-#define HDMI_VSYNC_TOTAL_F2_V_TOTAL__MASK 0x00000fff
+#define HDMI_VSYNC_TOTAL_F2_V_TOTAL__MASK 0x00001fff
#define HDMI_VSYNC_TOTAL_F2_V_TOTAL__SHIFT 0
static inline uint32_t HDMI_VSYNC_TOTAL_F2_V_TOTAL(uint32_t val)
{
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index adfe9e54e6f4..4fd20f5c2d94 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -57,6 +57,7 @@
static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
{
struct msm_drm_private *priv = crtc->dev->dev_private;
+
return to_sde_kms(priv->kms);
}
@@ -183,9 +184,6 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
pstate = to_sde_plane_state(plane->state);
- flush_mask = ctl->ops.get_bitmask_sspp(ctl,
- sde_plane_pipe(plane));
-
/* always stage plane on either left or right lm */
if (plane->state->crtc_x >= crtc_split_width) {
lm_idx = RIGHT_MIXER;
@@ -195,20 +193,36 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
idx = left_crtc_zpos_cnt[pstate->stage]++;
}
+ /*
+ * program each mixer with two hw pipes in dual mixer mode,
+ */
+ if (sde_crtc->num_mixers == CRTC_DUAL_MIXERS) {
+ stage_cfg->stage[LEFT_MIXER][pstate->stage][1] =
+ sde_plane_pipe(plane, 1);
+
+ flush_mask = ctl->ops.get_bitmask_sspp(ctl,
+ sde_plane_pipe(plane, 1));
+ }
+
+ flush_mask |= ctl->ops.get_bitmask_sspp(ctl,
+ sde_plane_pipe(plane, lm_idx ? 1 : 0));
+
/* stage plane on right LM if it crosses the boundary */
lm_right = (lm_idx == LEFT_MIXER) &&
(plane->state->crtc_x + plane->state->crtc_w >
crtc_split_width);
stage_cfg->stage[lm_idx][pstate->stage][idx] =
- sde_plane_pipe(plane);
+ sde_plane_pipe(plane, lm_idx ? 1 : 0);
+
mixer[lm_idx].flush_mask |= flush_mask;
SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
crtc->base.id,
pstate->stage,
plane->base.id,
- sde_plane_pipe(plane) - SSPP_VIG0,
+ sde_plane_pipe(plane,
+ lm_idx ? 1 : 0) - SSPP_VIG0,
plane->state->fb ?
plane->state->fb->base.id : -1);
@@ -230,8 +244,19 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
if (lm_right) {
idx = right_crtc_zpos_cnt[pstate->stage]++;
- stage_cfg->stage[RIGHT_MIXER][pstate->stage][idx] =
- sde_plane_pipe(plane);
+
+ /*
+ * program each mixer with two hw pipes
+ in dual mixer mode,
+ */
+ if (sde_crtc->num_mixers == CRTC_DUAL_MIXERS) {
+ stage_cfg->stage[RIGHT_MIXER][pstate->stage][1]
+ = sde_plane_pipe(plane, 0);
+ }
+
+ stage_cfg->stage[RIGHT_MIXER][pstate->stage][idx]
+ = sde_plane_pipe(plane, 1);
+
mixer[RIGHT_MIXER].flush_mask |= flush_mask;
/* blend config update */
@@ -1256,7 +1281,8 @@ int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
return 0;
}
-void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
+void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc,
+ struct drm_file *file)
{
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
@@ -1665,7 +1691,8 @@ static void _sde_crtc_init_debugfs(struct sde_crtc *sde_crtc,
#endif
/* initialize crtc */
-struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
+struct drm_crtc *sde_crtc_init(struct drm_device *dev,
+ struct drm_plane *plane)
{
struct drm_crtc *crtc = NULL;
struct sde_crtc *sde_crtc = NULL;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 519288f0dda2..17b678cfca46 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
#include "sde_hw_mdss.h"
#include "sde_hw_catalog.h"
#include "sde_hw_catalog_format.h"
@@ -715,6 +717,7 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
sblk->pcc_blk.len = 0;
set_bit(SDE_SSPP_PCC, &sspp->features);
}
+ snprintf(sspp->name, sizeof(sspp->name), "vig%d", *vig_count-1);
}
static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
@@ -753,6 +756,7 @@ static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
sblk->pcc_blk.len = 0;
set_bit(SDE_SSPP_PCC, &sspp->features);
}
+ snprintf(sspp->name, sizeof(sspp->name), "rgb%d", *rgb_count-1);
}
static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg,
@@ -766,6 +770,7 @@ static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg,
sspp->clk_ctrl = SDE_CLK_CTRL_CURSOR0 + *cursor_count;
sblk->format_list = plane_formats;
(*cursor_count)++;
+ snprintf(sspp->name, sizeof(sspp->name), "cursor%d", *cursor_count-1);
}
static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg,
@@ -779,6 +784,7 @@ static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg,
sblk->format_list = plane_formats;
set_bit(SDE_SSPP_QOS, &sspp->features);
(*dma_count)++;
+ snprintf(sspp->name, sizeof(sspp->name), "dma%d", *dma_count-1);
}
static int sde_sspp_parse_dt(struct device_node *np,
@@ -1200,7 +1206,8 @@ end:
return rc;
}
-static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
+static int sde_wb_parse_dt(struct device_node *np,
+ struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[WB_PROP_MAX], i, j;
struct sde_prop_value *prop_value = NULL;
@@ -1686,7 +1693,8 @@ end:
return rc;
}
-static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
+static int sde_pp_parse_dt(struct device_node *np,
+ struct sde_mdss_cfg *sde_cfg)
{
int rc, prop_count[PP_PROP_MAX], i;
struct sde_prop_value *prop_value = NULL;
@@ -1760,6 +1768,94 @@ end:
return rc;
}
+static inline u32 _sde_parse_sspp_id(struct sde_mdss_cfg *cfg,
+ const char *name)
+{
+ int i;
+
+ for (i = 0; i < cfg->sspp_count; i++) {
+ if (!strcmp(cfg->sspp[i].name, name))
+ return cfg->sspp[i].id;
+ }
+
+ return SSPP_NONE;
+}
+
+static int _sde_vp_parse_dt(struct device_node *np,
+ struct sde_mdss_cfg *cfg)
+{
+ int rc = 0, i = 0;
+ struct device_node *node = NULL;
+ struct device_node *root_node = NULL;
+ struct sde_vp_cfg *vp;
+ struct sde_vp_sub_blks *vp_sub, *vp_sub_next;
+ struct property *prop;
+ const char *cname;
+
+ root_node = of_get_child_by_name(np, "qcom,sde-plane-id-map");
+ if (!root_node) {
+ root_node = of_parse_phandle(np, "qcom,sde-plane-id-map", 0);
+ if (!root_node) {
+ SDE_ERROR("No entry present for qcom,sde-plane-id-map");
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+
+ for_each_child_of_node(root_node, node) {
+ if (i >= MAX_BLOCKS) {
+ SDE_ERROR("num of nodes(%d) is bigger than max(%d)\n",
+ i, MAX_BLOCKS);
+ rc = -EINVAL;
+ goto end;
+ }
+ cfg->vp_count++;
+ vp = &(cfg->vp[i]);
+ vp->id = i;
+ rc = of_property_read_string(node, "qcom,display-type",
+ &(vp->display_type));
+ if (rc) {
+ SDE_ERROR("failed to read display-type, rc = %d\n", rc);
+ goto end;
+ }
+
+ rc = of_property_read_string(node, "qcom,plane-type",
+ &(vp->plane_type));
+ if (rc) {
+ SDE_ERROR("failed to read plane-type, rc = %d\n", rc);
+ goto end;
+ }
+
+ INIT_LIST_HEAD(&vp->sub_blks);
+ of_property_for_each_string(node, "qcom,plane-name",
+ prop, cname) {
+ vp_sub = kzalloc(sizeof(*vp_sub), GFP_KERNEL);
+ if (!vp_sub) {
+ rc = -ENOMEM;
+ goto end;
+ }
+ vp_sub->sspp_id = _sde_parse_sspp_id(cfg, cname);
+ list_add_tail(&vp_sub->pipeid_list, &vp->sub_blks);
+ }
+ i++;
+ }
+
+end:
+ if (rc && cfg->vp_count) {
+ vp = &(cfg->vp[i]);
+ for (i = 0; i < cfg->vp_count; i++) {
+ list_for_each_entry_safe(vp_sub, vp_sub_next,
+ &vp->sub_blks, pipeid_list) {
+ list_del(&vp_sub->pipeid_list);
+ kfree(vp_sub);
+ }
+ }
+ memset(&(cfg->vp[0]), 0, sizeof(cfg->vp));
+ cfg->vp_count = 0;
+ }
+ return rc;
+}
+
static int sde_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
{
int rc, len, prop_count[SDE_PROP_MAX];
@@ -1851,7 +1947,8 @@ end:
return rc;
}
-static int sde_perf_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
+static int sde_perf_parse_dt(struct device_node *np,
+ struct sde_mdss_cfg *cfg)
{
int rc, len, prop_count[PERF_PROP_MAX];
struct sde_prop_value *prop_value = NULL;
@@ -1891,7 +1988,8 @@ end:
return rc;
}
-static void sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
+static void sde_hardware_caps(struct sde_mdss_cfg *sde_cfg,
+ uint32_t hw_rev)
{
switch (hw_rev) {
case SDE_HW_VER_170:
@@ -1909,6 +2007,7 @@ static void sde_hardware_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
{
int i;
+ struct sde_vp_sub_blks *vp_sub, *vp_sub_next;
if (!sde_cfg)
return;
@@ -1932,13 +2031,23 @@ void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg)
kfree(sde_cfg->vbif[i].dynamic_ot_rd_tbl.cfg);
kfree(sde_cfg->vbif[i].dynamic_ot_wr_tbl.cfg);
}
+
+ for (i = 0; i < sde_cfg->vp_count; i++) {
+ list_for_each_entry_safe(vp_sub, vp_sub_next,
+ &sde_cfg->vp[i].sub_blks, pipeid_list) {
+ list_del(&vp_sub->pipeid_list);
+ kfree(vp_sub);
+ }
+ }
+
kfree(sde_cfg);
}
/*************************************************************
* hardware catalog init
*************************************************************/
-struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 hw_rev)
+struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev,
+ u32 hw_rev)
{
int rc;
struct sde_mdss_cfg *sde_cfg;
@@ -1996,6 +2105,10 @@ struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 hw_rev)
if (rc)
goto end;
+ rc = _sde_vp_parse_dt(np, sde_cfg);
+ if (rc)
+ SDE_DEBUG("virtual plane is not supported.\n");
+
sde_hardware_caps(sde_cfg, hw_rev);
return sde_cfg;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index a8f9169aaf35..bca221d2a959 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -57,6 +57,8 @@
#define SDE_COLOR_PROCESS_MAJOR(version) (((version) & 0xFFFF0000) >> 16)
#define SDE_COLOR_PROCESS_MINOR(version) ((version) & 0xFFFF)
+#define SSPP_NAME_SIZE 12
+
/**
* MDP TOP BLOCK features
* @SDE_MDP_PANIC_PER_PIPE Panic configuration needs to be be done per pipe
@@ -455,12 +457,14 @@ struct sde_ctl_cfg {
* @sblk: SSPP sub-blocks information
* @xin_id: bus client identifier
* @clk_ctrl clock control identifier
+ *@name source pipe name
*/
struct sde_sspp_cfg {
SDE_HW_BLK_INFO;
const struct sde_sspp_sub_blks *sblk;
u32 xin_id;
enum sde_clk_ctrl_type clk_ctrl;
+ char name[SSPP_NAME_SIZE];
};
/**
@@ -608,6 +612,31 @@ struct sde_perf_cfg {
};
/**
+* struct sde_vp_sub_blks - Virtual Plane sub-blocks
+* @pipeid_list list for hw pipe id
+* @sspp_id SSPP ID, refer to enum sde_sspp.
+*/
+struct sde_vp_sub_blks {
+ struct list_head pipeid_list;
+ u32 sspp_id;
+};
+
+/**
+* struct sde_vp_cfg - information of Virtual Plane SW blocks
+* @id enum identifying this block
+* @sub_blks list head for virtual plane sub blocks
+* @plane_type plane type, such as primary, overlay or cursor
+* @display_type which display the plane bound to, such as primary,
+* secondary or tertiary
+*/
+struct sde_vp_cfg {
+ u32 id;
+ struct list_head sub_blks;
+ const char *plane_type;
+ const char *display_type;
+};
+
+/**
* struct sde_mdss_cfg - information of MDSS HW
* This is the main catalog data structure representing
* this HW version. Contains number of instances,
@@ -672,6 +701,9 @@ struct sde_mdss_cfg {
/* Add additional block data structures here */
struct sde_perf_cfg perf;
+
+ u32 vp_count;
+ struct sde_vp_cfg vp[MAX_BLOCKS];
};
struct sde_mdss_hw_cfg_handler {
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 709c9970b357..45a87456e5ec 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -797,6 +797,16 @@ static void _sde_kms_drm_obj_destroy(struct sde_kms *sde_kms)
_sde_kms_release_displays(sde_kms);
}
+static inline int sde_get_crtc_id(const char *display_type)
+{
+ if (!strcmp(display_type, "primary"))
+ return 0;
+ else if (!strcmp(display_type, "secondary"))
+ return 1;
+ else
+ return 2;
+}
+
static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms)
{
struct drm_device *dev;
@@ -829,28 +839,57 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms)
(void)_sde_kms_setup_displays(dev, priv, sde_kms);
max_crtc_count = min(catalog->mixer_count, priv->num_encoders);
- max_plane_count = min_t(u32, catalog->sspp_count, MAX_PLANES);
/* Create the planes */
primary_planes_idx = 0;
- for (i = 0; i < max_plane_count; i++) {
- bool primary = true;
-
- if (catalog->sspp[i].features & BIT(SDE_SSPP_CURSOR)
- || primary_planes_idx >= max_crtc_count)
- primary = false;
-
- plane = sde_plane_init(dev, catalog->sspp[i].id, primary,
- (1UL << max_crtc_count) - 1);
- if (IS_ERR(plane)) {
- SDE_ERROR("sde_plane_init failed\n");
- ret = PTR_ERR(plane);
- goto fail;
+ if (catalog->vp_count) {
+ max_plane_count = min_t(u32, catalog->vp_count, MAX_PLANES);
+
+ for (i = 0; i < max_plane_count; i++) {
+ bool primary = true;
+ int crtc_id =
+ sde_get_crtc_id(catalog->vp[i].display_type);
+
+ if (strcmp(catalog->vp[i].plane_type, "primary"))
+ primary = false;
+
+ plane = sde_plane_init(dev, catalog->vp[i].id,
+ primary, 1UL << crtc_id, true);
+ if (IS_ERR(plane)) {
+ SDE_ERROR("sde_plane_init failed\n");
+ ret = PTR_ERR(plane);
+ goto fail;
+ }
+ priv->planes[priv->num_planes++] = plane;
+
+ if (primary) {
+ primary_planes[crtc_id] = plane;
+ primary_planes_idx++;
+ }
+ }
+ } else {
+ max_plane_count = min_t(u32, catalog->sspp_count, MAX_PLANES);
+
+ for (i = 0; i < max_plane_count; i++) {
+ bool primary = true;
+
+ if (catalog->sspp[i].features & BIT(SDE_SSPP_CURSOR)
+ || primary_planes_idx >= max_crtc_count)
+ primary = false;
+
+ plane = sde_plane_init(dev, catalog->sspp[i].id,
+ primary, (1UL << max_crtc_count) - 1,
+ false);
+ if (IS_ERR(plane)) {
+ SDE_ERROR("sde_plane_init failed\n");
+ ret = PTR_ERR(plane);
+ goto fail;
+ }
+ priv->planes[priv->num_planes++] = plane;
+
+ if (primary)
+ primary_planes[primary_planes_idx++] = plane;
}
- priv->planes[priv->num_planes++] = plane;
-
- if (primary)
- primary_planes[primary_planes_idx++] = plane;
}
max_crtc_count = min(max_crtc_count, primary_planes_idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 114acfd7a173..5c84025243a3 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -78,20 +78,22 @@ enum sde_plane_qos {
};
/*
- * struct sde_plane - local sde plane structure
+ * struct sde_phy_plane - physical plane structure
+ * @sde_plane: Points to virtual plane
+ * @phy_plane_list: list of hw pipe(physical plane)
+ * @index: index of physical plane (starts from 0, order from left to right)
+ * @features: capabilities from catalog
* @csc_cfg: Decoded user configuration for csc
* @csc_usr_ptr: Points to csc_cfg if valid user config available
* @csc_ptr: Points to sde_csc_cfg structure to use for current
*/
-struct sde_plane {
- struct drm_plane base;
-
- struct msm_gem_address_space *aspace;
-
- struct mutex lock;
-
+struct sde_phy_plane {
+ struct sde_plane *sde_plane;
+ struct list_head phy_plane_list;
enum sde_sspp pipe;
- uint32_t features; /* capabilities from catalog */
+ uint32_t index;
+
+ uint32_t features;
uint32_t nformats;
uint32_t formats[64];
@@ -101,7 +103,6 @@ struct sde_plane {
struct sde_hw_scaler3_cfg *scaler3_cfg;
struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
uint32_t color_fill;
- bool is_error;
bool is_rt_pipe;
struct sde_hw_pixel_ext pixel_ext;
@@ -112,9 +113,22 @@ struct sde_plane {
struct sde_csc_cfg *csc_ptr;
const struct sde_sspp_sub_blks *pipe_sblk;
+};
+/*
+ * struct sde_plane - local sde plane structure
+ */
+struct sde_plane {
+ struct drm_plane base;
+
+ struct msm_gem_address_space *aspace;
+ struct mutex lock;
+ bool is_error;
char pipe_name[SDE_NAME_SIZE];
+ struct list_head phy_plane_head;
+ u32 num_of_phy_planes;
+
struct msm_property_info property_info;
struct msm_property_data property_data[PLANE_PROP_COUNT];
struct drm_property_blob *blob_info;
@@ -140,20 +154,20 @@ static bool sde_plane_enabled(struct drm_plane_state *state)
* @src_wdith: width of source buffer
* Return: fill level corresponding to the source buffer/format or 0 if error
*/
-static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
+static inline int _sde_plane_calc_fill_level(struct sde_phy_plane *pp,
const struct sde_format *fmt, u32 src_width)
{
struct sde_plane *psde;
u32 fixed_buff_size;
u32 total_fl;
- if (!plane || !fmt) {
+ if (!pp || !fmt) {
SDE_ERROR("invalid arguments\n");
return 0;
}
- psde = to_sde_plane(plane);
- fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
+ psde = pp->sde_plane;
+ fixed_buff_size = pp->pipe_sblk->pixel_ram_size;
if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
if (fmt->chroma_sample == SDE_CHROMA_420) {
@@ -171,7 +185,7 @@ static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
}
SDE_DEBUG("plane%u: pnum:%d fmt:%x w:%u fl:%u\n",
- plane->base.id, psde->pipe - SSPP_VIG0,
+ psde->base.base.id, pp->pipe - SSPP_VIG0,
fmt->base.pixel_format, src_width, total_fl);
return total_fl;
@@ -236,7 +250,7 @@ static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
* @plane: Pointer to drm plane
* @fb: Pointer to framebuffer associated with the given plane
*/
-static void _sde_plane_set_qos_lut(struct drm_plane *plane,
+static void _sde_plane_set_qos_lut(struct sde_phy_plane *pp,
struct drm_framebuffer *fb)
{
struct sde_plane *psde;
@@ -244,30 +258,30 @@ static void _sde_plane_set_qos_lut(struct drm_plane *plane,
u32 qos_lut;
u32 total_fl = 0;
- if (!plane || !fb) {
- SDE_ERROR("invalid arguments plane %d fb %d\n",
- plane != 0, fb != 0);
+ if (!pp || !fb) {
+ SDE_ERROR("invalid arguments phy_plane %d fb %d\n",
+ pp != NULL, fb != NULL);
return;
}
- psde = to_sde_plane(plane);
+ psde = pp->sde_plane;
- if (!psde->pipe_hw || !psde->pipe_sblk) {
+ if (!pp->pipe_hw || !pp->pipe_sblk) {
SDE_ERROR("invalid arguments\n");
return;
- } else if (!psde->pipe_hw->ops.setup_creq_lut) {
+ } else if (!pp->pipe_hw->ops.setup_creq_lut) {
return;
}
- if (!psde->is_rt_pipe) {
- qos_lut = psde->pipe_sblk->creq_lut_nrt;
+ if (!pp->is_rt_pipe) {
+ qos_lut = pp->pipe_sblk->creq_lut_nrt;
} else {
fmt = sde_get_sde_format_ext(
fb->pixel_format,
fb->modifier,
drm_format_num_planes(fb->pixel_format));
- total_fl = _sde_plane_calc_fill_level(plane, fmt,
- psde->pipe_cfg.src_rect.w);
+ total_fl = _sde_plane_calc_fill_level(pp, fmt,
+ pp->pipe_cfg.src_rect.w);
if (SDE_FORMAT_IS_LINEAR(fmt))
qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
@@ -275,20 +289,20 @@ static void _sde_plane_set_qos_lut(struct drm_plane *plane,
qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
}
- psde->pipe_qos_cfg.creq_lut = qos_lut;
+ pp->pipe_qos_cfg.creq_lut = qos_lut;
- trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
+ trace_sde_perf_set_qos_luts(pp->pipe - SSPP_VIG0,
(fmt) ? fmt->base.pixel_format : 0,
- psde->is_rt_pipe, total_fl, qos_lut,
+ pp->is_rt_pipe, total_fl, qos_lut,
(fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
SDE_DEBUG("plane%u: pnum:%d fmt:%x rt:%d fl:%u lut:0x%x\n",
- plane->base.id,
- psde->pipe - SSPP_VIG0,
+ psde->base.base.id,
+ pp->pipe - SSPP_VIG0,
(fmt) ? fmt->base.pixel_format : 0,
- psde->is_rt_pipe, total_fl, qos_lut);
+ pp->is_rt_pipe, total_fl, qos_lut);
- psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
+ pp->pipe_hw->ops.setup_creq_lut(pp->pipe_hw, &pp->pipe_qos_cfg);
}
/**
@@ -296,30 +310,30 @@ static void _sde_plane_set_qos_lut(struct drm_plane *plane,
* @plane: Pointer to drm plane
* @fb: Pointer to framebuffer associated with the given plane
*/
-static void _sde_plane_set_danger_lut(struct drm_plane *plane,
+static void _sde_plane_set_danger_lut(struct sde_phy_plane *pp,
struct drm_framebuffer *fb)
{
struct sde_plane *psde;
const struct sde_format *fmt = NULL;
u32 danger_lut, safe_lut;
- if (!plane || !fb) {
+ if (!pp || !fb) {
SDE_ERROR("invalid arguments\n");
return;
}
- psde = to_sde_plane(plane);
+ psde = pp->sde_plane;
- if (!psde->pipe_hw || !psde->pipe_sblk) {
+ if (!pp->pipe_hw || !pp->pipe_sblk) {
SDE_ERROR("invalid arguments\n");
return;
- } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
+ } else if (!pp->pipe_hw->ops.setup_danger_safe_lut) {
return;
}
- if (!psde->is_rt_pipe) {
- danger_lut = psde->pipe_sblk->danger_lut_nrt;
- safe_lut = psde->pipe_sblk->safe_lut_nrt;
+ if (!pp->is_rt_pipe) {
+ danger_lut = pp->pipe_sblk->danger_lut_nrt;
+ safe_lut = pp->pipe_sblk->safe_lut_nrt;
} else {
fmt = sde_get_sde_format_ext(
fb->pixel_format,
@@ -327,33 +341,33 @@ static void _sde_plane_set_danger_lut(struct drm_plane *plane,
drm_format_num_planes(fb->pixel_format));
if (SDE_FORMAT_IS_LINEAR(fmt)) {
- danger_lut = psde->pipe_sblk->danger_lut_linear;
- safe_lut = psde->pipe_sblk->safe_lut_linear;
+ danger_lut = pp->pipe_sblk->danger_lut_linear;
+ safe_lut = pp->pipe_sblk->safe_lut_linear;
} else {
- danger_lut = psde->pipe_sblk->danger_lut_tile;
- safe_lut = psde->pipe_sblk->safe_lut_tile;
+ danger_lut = pp->pipe_sblk->danger_lut_tile;
+ safe_lut = pp->pipe_sblk->safe_lut_tile;
}
}
- psde->pipe_qos_cfg.danger_lut = danger_lut;
- psde->pipe_qos_cfg.safe_lut = safe_lut;
+ pp->pipe_qos_cfg.danger_lut = danger_lut;
+ pp->pipe_qos_cfg.safe_lut = safe_lut;
- trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
+ trace_sde_perf_set_danger_luts(pp->pipe - SSPP_VIG0,
(fmt) ? fmt->base.pixel_format : 0,
(fmt) ? fmt->fetch_mode : 0,
- psde->pipe_qos_cfg.danger_lut,
- psde->pipe_qos_cfg.safe_lut);
+ pp->pipe_qos_cfg.danger_lut,
+ pp->pipe_qos_cfg.safe_lut);
SDE_DEBUG("plane%u: pnum:%d fmt:%x mode:%d luts[0x%x, 0x%x]\n",
- plane->base.id,
- psde->pipe - SSPP_VIG0,
+ psde->base.base.id,
+ pp->pipe - SSPP_VIG0,
fmt ? fmt->base.pixel_format : 0,
fmt ? fmt->fetch_mode : -1,
- psde->pipe_qos_cfg.danger_lut,
- psde->pipe_qos_cfg.safe_lut);
+ pp->pipe_qos_cfg.danger_lut,
+ pp->pipe_qos_cfg.safe_lut);
- psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
- &psde->pipe_qos_cfg);
+ pp->pipe_hw->ops.setup_danger_safe_lut(pp->pipe_hw,
+ &pp->pipe_qos_cfg);
}
/**
@@ -362,85 +376,90 @@ static void _sde_plane_set_danger_lut(struct drm_plane *plane,
* @enable: true to enable QoS control
* @flags: QoS control mode (enum sde_plane_qos)
*/
-static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
+static void _sde_plane_set_qos_ctrl(struct sde_phy_plane *pp,
bool enable, u32 flags)
{
struct sde_plane *psde;
- if (!plane) {
+ if (!pp) {
SDE_ERROR("invalid arguments\n");
return;
}
- psde = to_sde_plane(plane);
+ psde = pp->sde_plane;
- if (!psde->pipe_hw || !psde->pipe_sblk) {
+ if (!pp->pipe_hw || !pp->pipe_sblk) {
SDE_ERROR("invalid arguments\n");
return;
- } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
+ } else if (!pp->pipe_hw->ops.setup_qos_ctrl) {
return;
}
if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
- psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
- psde->pipe_qos_cfg.danger_vblank =
- psde->pipe_sblk->danger_vblank;
- psde->pipe_qos_cfg.vblank_en = enable;
+ pp->pipe_qos_cfg.creq_vblank = pp->pipe_sblk->creq_vblank;
+ pp->pipe_qos_cfg.danger_vblank =
+ pp->pipe_sblk->danger_vblank;
+ pp->pipe_qos_cfg.vblank_en = enable;
}
if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
/* this feature overrules previous VBLANK_CTRL */
- psde->pipe_qos_cfg.vblank_en = false;
- psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
+ pp->pipe_qos_cfg.vblank_en = false;
+ pp->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
}
if (flags & SDE_PLANE_QOS_PANIC_CTRL)
- psde->pipe_qos_cfg.danger_safe_en = enable;
+ pp->pipe_qos_cfg.danger_safe_en = enable;
- if (!psde->is_rt_pipe) {
- psde->pipe_qos_cfg.vblank_en = false;
- psde->pipe_qos_cfg.danger_safe_en = false;
+ if (!pp->is_rt_pipe) {
+ pp->pipe_qos_cfg.vblank_en = false;
+ pp->pipe_qos_cfg.danger_safe_en = false;
}
SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n",
- plane->base.id,
- psde->pipe - SSPP_VIG0,
- psde->pipe_qos_cfg.danger_safe_en,
- psde->pipe_qos_cfg.vblank_en,
- psde->pipe_qos_cfg.creq_vblank,
- psde->pipe_qos_cfg.danger_vblank,
- psde->is_rt_pipe);
-
- psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
- &psde->pipe_qos_cfg);
+ psde->base.base.id,
+ pp->pipe - SSPP_VIG0,
+ pp->pipe_qos_cfg.danger_safe_en,
+ pp->pipe_qos_cfg.vblank_en,
+ pp->pipe_qos_cfg.creq_vblank,
+ pp->pipe_qos_cfg.danger_vblank,
+ pp->is_rt_pipe);
+
+ pp->pipe_hw->ops.setup_qos_ctrl(pp->pipe_hw,
+ &pp->pipe_qos_cfg);
}
-int sde_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
+static int sde_plane_danger_signal_ctrl(struct sde_phy_plane *pp, bool enable)
{
struct sde_plane *psde;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
- if (!plane || !plane->dev) {
+ if (!pp) {
+ SDE_ERROR("invalid arguments\n");
+ return -EINVAL;
+ }
+ psde = pp->sde_plane;
+
+ if (!psde->base.dev) {
SDE_ERROR("invalid arguments\n");
return -EINVAL;
}
- priv = plane->dev->dev_private;
+ priv = psde->base.dev->dev_private;
if (!priv || !priv->kms) {
SDE_ERROR("invalid KMS reference\n");
return -EINVAL;
}
sde_kms = to_sde_kms(priv->kms);
- psde = to_sde_plane(plane);
- if (!psde->is_rt_pipe)
+ if (!pp->is_rt_pipe)
goto end;
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
- _sde_plane_set_qos_ctrl(plane, enable, SDE_PLANE_QOS_PANIC_CTRL);
+ _sde_plane_set_qos_ctrl(pp, enable, SDE_PLANE_QOS_PANIC_CTRL);
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
@@ -453,7 +472,7 @@ end:
* @plane: Pointer to drm plane
* @crtc: Pointer to drm crtc
*/
-static void _sde_plane_set_ot_limit(struct drm_plane *plane,
+static void _sde_plane_set_ot_limit(struct sde_phy_plane *pp,
struct drm_crtc *crtc)
{
struct sde_plane *psde;
@@ -461,34 +480,38 @@ static void _sde_plane_set_ot_limit(struct drm_plane *plane,
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
- if (!plane || !plane->dev || !crtc) {
- SDE_ERROR("invalid arguments plane %d crtc %d\n",
- plane != 0, crtc != 0);
+ if (!pp || !crtc) {
+ SDE_ERROR("invalid arguments phy_plane %d crtc %d\n",
+ pp != NULL, crtc != NULL);
+ return;
+ }
+ psde = pp->sde_plane;
+ if (!psde->base.dev) {
+ SDE_ERROR("invalid DRM device\n");
return;
}
- priv = plane->dev->dev_private;
+ priv = psde->base.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) {
+ if (!pp->pipe_hw) {
SDE_ERROR("invalid pipe reference\n");
return;
}
memset(&ot_params, 0, sizeof(ot_params));
- ot_params.xin_id = psde->pipe_hw->cap->xin_id;
- ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
- ot_params.width = psde->pipe_cfg.src_rect.w;
- ot_params.height = psde->pipe_cfg.src_rect.h;
- ot_params.is_wfd = !psde->is_rt_pipe;
+ ot_params.xin_id = pp->pipe_hw->cap->xin_id;
+ ot_params.num = pp->pipe_hw->idx - SSPP_NONE;
+ ot_params.width = pp->pipe_cfg.src_rect.w;
+ ot_params.height = pp->pipe_cfg.src_rect.h;
+ ot_params.is_wfd = !pp->is_rt_pipe;
ot_params.frame_rate = crtc->mode.vrefresh;
ot_params.vbif_idx = VBIF_RT;
- ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
+ ot_params.clk_ctrl = pp->pipe_hw->cap->clk_ctrl;
ot_params.rd = true;
sde_vbif_set_ot_limit(sde_kms, &ot_params);
@@ -559,7 +582,7 @@ int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
return ret;
}
-static inline void _sde_plane_set_scanout(struct drm_plane *plane,
+static inline void _sde_plane_set_scanout(struct sde_phy_plane *pp,
struct sde_plane_state *pstate,
struct sde_hw_pipe_cfg *pipe_cfg,
struct drm_framebuffer *fb)
@@ -567,15 +590,15 @@ static inline void _sde_plane_set_scanout(struct drm_plane *plane,
struct sde_plane *psde;
int ret;
- if (!plane || !pstate || !pipe_cfg || !fb) {
+ if (!pp || !pstate || !pipe_cfg || !fb) {
SDE_ERROR(
- "invalid arg(s), plane %d state %d cfg %d fb %d\n",
- plane != 0, pstate != 0, pipe_cfg != 0, fb != 0);
+ "invalid arg(s), phy_plane %d state %d cfg %d fb %d\n",
+ pp != 0, pstate != 0, pipe_cfg != 0, fb != 0);
return;
}
- psde = to_sde_plane(plane);
- if (!psde->pipe_hw) {
+ psde = pp->sde_plane;
+ if (!pp->pipe_hw) {
SDE_ERROR_PLANE(psde, "invalid pipe_hw\n");
return;
}
@@ -585,14 +608,15 @@ static inline void _sde_plane_set_scanout(struct drm_plane *plane,
SDE_DEBUG_PLANE(psde, "not updating same src addrs\n");
else if (ret)
SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret);
- else if (psde->pipe_hw->ops.setup_sourceaddress)
- psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
+ else if (pp->pipe_hw && pp->pipe_hw->ops.setup_sourceaddress)
+ pp->pipe_hw->ops.setup_sourceaddress(pp->pipe_hw, pipe_cfg);
}
-static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde,
+static int _sde_plane_setup_scaler3_lut(struct sde_phy_plane *pp,
struct sde_plane_state *pstate)
{
- struct sde_hw_scaler3_cfg *cfg = psde->scaler3_cfg;
+ struct sde_plane *psde = pp->sde_plane;
+ struct sde_hw_scaler3_cfg *cfg = pp->scaler3_cfg;
int ret = 0;
cfg->dir_lut = msm_property_get_blob(
@@ -612,7 +636,7 @@ static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde,
return ret;
}
-static void _sde_plane_setup_scaler3(struct sde_plane *psde,
+static void _sde_plane_setup_scaler3(struct sde_phy_plane *pp,
uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
struct sde_hw_scaler3_cfg *scale_cfg,
const struct sde_format *fmt,
@@ -620,10 +644,10 @@ static void _sde_plane_setup_scaler3(struct sde_plane *psde,
{
uint32_t decimated, i;
- if (!psde || !scale_cfg || !fmt || !chroma_subsmpl_h ||
+ if (!pp || !scale_cfg || !fmt || !chroma_subsmpl_h ||
!chroma_subsmpl_v) {
SDE_ERROR("psde %pK scale_cfg %pK fmt %pK smp_h %d smp_v %d\n"
- , psde, scale_cfg, fmt, chroma_subsmpl_h,
+ , pp, scale_cfg, fmt, chroma_subsmpl_h,
chroma_subsmpl_v);
return;
}
@@ -631,11 +655,11 @@ static void _sde_plane_setup_scaler3(struct sde_plane *psde,
memset(scale_cfg, 0, sizeof(*scale_cfg));
decimated = DECIMATED_DIMENSION(src_w,
- psde->pipe_cfg.horz_decimation);
+ pp->pipe_cfg.horz_decimation);
scale_cfg->phase_step_x[SDE_SSPP_COMP_0] =
mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_w);
decimated = DECIMATED_DIMENSION(src_h,
- psde->pipe_cfg.vert_decimation);
+ pp->pipe_cfg.vert_decimation);
scale_cfg->phase_step_y[SDE_SSPP_COMP_0] =
mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_h);
@@ -657,9 +681,9 @@ static void _sde_plane_setup_scaler3(struct sde_plane *psde,
for (i = 0; i < SDE_MAX_PLANES; i++) {
scale_cfg->src_width[i] = DECIMATED_DIMENSION(src_w,
- psde->pipe_cfg.horz_decimation);
+ pp->pipe_cfg.horz_decimation);
scale_cfg->src_height[i] = DECIMATED_DIMENSION(src_h,
- psde->pipe_cfg.vert_decimation);
+ pp->pipe_cfg.vert_decimation);
if (SDE_FORMAT_IS_YUV(fmt))
scale_cfg->src_width[i] &= ~0x1;
if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) {
@@ -668,9 +692,9 @@ static void _sde_plane_setup_scaler3(struct sde_plane *psde,
}
scale_cfg->preload_x[i] = SDE_QSEED3_DEFAULT_PRELOAD_H;
scale_cfg->preload_y[i] = SDE_QSEED3_DEFAULT_PRELOAD_V;
- psde->pixel_ext.num_ext_pxls_top[i] =
+ pp->pixel_ext.num_ext_pxls_top[i] =
scale_cfg->src_height[i];
- psde->pixel_ext.num_ext_pxls_left[i] =
+ pp->pixel_ext.num_ext_pxls_left[i] =
scale_cfg->src_width[i];
}
if (!(SDE_FORMAT_IS_YUV(fmt)) && (src_h == dst_h)
@@ -835,7 +859,7 @@ static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
}
}
-static inline void _sde_plane_setup_csc(struct sde_plane *psde)
+static inline void _sde_plane_setup_csc(struct sde_phy_plane *pp)
{
static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
{
@@ -866,26 +890,30 @@ static inline void _sde_plane_setup_csc(struct sde_plane *psde)
{ 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
};
- if (!psde) {
+ struct sde_plane *psde;
+
+ if (!pp) {
SDE_ERROR("invalid plane\n");
return;
}
+ psde = pp->sde_plane;
/* revert to kernel default if override not available */
- if (psde->csc_usr_ptr)
- psde->csc_ptr = psde->csc_usr_ptr;
- else if (BIT(SDE_SSPP_CSC_10BIT) & psde->features)
- psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc10_YUV2RGB_601L;
+ if (pp->csc_usr_ptr)
+ pp->csc_ptr = pp->csc_usr_ptr;
+ else if (BIT(SDE_SSPP_CSC_10BIT) & pp->features)
+ pp->csc_ptr = (struct sde_csc_cfg *)&sde_csc10_YUV2RGB_601L;
else
- psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
+ pp->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
SDE_DEBUG_PLANE(psde, "using 0x%X 0x%X 0x%X...\n",
- psde->csc_ptr->csc_mv[0],
- psde->csc_ptr->csc_mv[1],
- psde->csc_ptr->csc_mv[2]);
+ pp->csc_ptr->csc_mv[0],
+ pp->csc_ptr->csc_mv[1],
+ pp->csc_ptr->csc_mv[2]);
}
-static void sde_color_process_plane_setup(struct drm_plane *plane)
+static void sde_color_process_plane_setup(struct drm_plane *plane,
+ struct sde_phy_plane *pp)
{
struct sde_plane *psde;
struct sde_plane_state *pstate;
@@ -893,32 +921,32 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
struct drm_msm_memcol *memcol = NULL;
size_t memcol_sz = 0;
- psde = to_sde_plane(plane);
+ psde = pp->sde_plane;
pstate = to_sde_plane_state(plane->state);
hue = (uint32_t) sde_plane_get_property(pstate, PLANE_PROP_HUE_ADJUST);
- if (psde->pipe_hw->ops.setup_pa_hue)
- psde->pipe_hw->ops.setup_pa_hue(psde->pipe_hw, &hue);
+ if (pp->pipe_hw->ops.setup_pa_hue)
+ pp->pipe_hw->ops.setup_pa_hue(pp->pipe_hw, &hue);
saturation = (uint32_t) sde_plane_get_property(pstate,
PLANE_PROP_SATURATION_ADJUST);
- if (psde->pipe_hw->ops.setup_pa_sat)
- psde->pipe_hw->ops.setup_pa_sat(psde->pipe_hw, &saturation);
+ if (pp->pipe_hw->ops.setup_pa_sat)
+ pp->pipe_hw->ops.setup_pa_sat(pp->pipe_hw, &saturation);
value = (uint32_t) sde_plane_get_property(pstate,
PLANE_PROP_VALUE_ADJUST);
- if (psde->pipe_hw->ops.setup_pa_val)
- psde->pipe_hw->ops.setup_pa_val(psde->pipe_hw, &value);
+ if (pp->pipe_hw->ops.setup_pa_val)
+ pp->pipe_hw->ops.setup_pa_val(pp->pipe_hw, &value);
contrast = (uint32_t) sde_plane_get_property(pstate,
PLANE_PROP_CONTRAST_ADJUST);
- if (psde->pipe_hw->ops.setup_pa_cont)
- psde->pipe_hw->ops.setup_pa_cont(psde->pipe_hw, &contrast);
+ if (pp->pipe_hw->ops.setup_pa_cont)
+ pp->pipe_hw->ops.setup_pa_cont(pp->pipe_hw, &contrast);
- if (psde->pipe_hw->ops.setup_pa_memcolor) {
+ if (pp->pipe_hw->ops.setup_pa_memcolor) {
/* Skin memory color setup */
memcol = msm_property_get_blob(&psde->property_info,
pstate->property_blobs,
&memcol_sz,
PLANE_PROP_SKIN_COLOR);
- psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
+ pp->pipe_hw->ops.setup_pa_memcolor(pp->pipe_hw,
MEMCOLOR_SKIN, memcol);
/* Sky memory color setup */
@@ -926,7 +954,7 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
pstate->property_blobs,
&memcol_sz,
PLANE_PROP_SKY_COLOR);
- psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
+ pp->pipe_hw->ops.setup_pa_memcolor(pp->pipe_hw,
MEMCOLOR_SKY, memcol);
/* Foliage memory color setup */
@@ -934,87 +962,89 @@ static void sde_color_process_plane_setup(struct drm_plane *plane)
pstate->property_blobs,
&memcol_sz,
PLANE_PROP_FOLIAGE_COLOR);
- psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
+ pp->pipe_hw->ops.setup_pa_memcolor(pp->pipe_hw,
MEMCOLOR_FOLIAGE, memcol);
}
}
-static void _sde_plane_setup_scaler(struct sde_plane *psde,
+static void _sde_plane_setup_scaler(struct sde_phy_plane *pp,
const struct sde_format *fmt,
struct sde_plane_state *pstate)
{
struct sde_hw_pixel_ext *pe;
uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
+ struct sde_plane *psde;
- if (!psde || !fmt) {
- SDE_ERROR("invalid arg(s), plane %d fmt %d state %d\n",
- psde != 0, fmt != 0, pstate != 0);
+ if (!pp || !fmt || !pstate || !pp->sde_plane) {
+ SDE_ERROR("invalid arg(s), phy_plane %d fmt %d\n",
+ pp != NULL, fmt != NULL);
return;
}
+ psde = pp->sde_plane;
- pe = &(psde->pixel_ext);
+ pe = &(pp->pixel_ext);
- psde->pipe_cfg.horz_decimation =
+ pp->pipe_cfg.horz_decimation =
sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
- psde->pipe_cfg.vert_decimation =
+ pp->pipe_cfg.vert_decimation =
sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
/* don't chroma subsample if decimating */
- chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
+ chroma_subsmpl_h = pp->pipe_cfg.horz_decimation ? 1 :
drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
- chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
+ chroma_subsmpl_v = pp->pipe_cfg.vert_decimation ? 1 :
drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
/* update scaler */
- if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
+ if (pp->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
int error;
- error = _sde_plane_setup_scaler3_lut(psde, pstate);
- if (error || !psde->pixel_ext_usr) {
+ error = _sde_plane_setup_scaler3_lut(pp, pstate);
+ if (error || !pp->pixel_ext_usr) {
memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
/* calculate default config for QSEED3 */
- _sde_plane_setup_scaler3(psde,
- psde->pipe_cfg.src_rect.w,
- psde->pipe_cfg.src_rect.h,
- psde->pipe_cfg.dst_rect.w,
- psde->pipe_cfg.dst_rect.h,
- psde->scaler3_cfg, fmt,
+ _sde_plane_setup_scaler3(pp,
+ pp->pipe_cfg.src_rect.w,
+ pp->pipe_cfg.src_rect.h,
+ pp->pipe_cfg.dst_rect.w,
+ pp->pipe_cfg.dst_rect.h,
+ pp->scaler3_cfg, fmt,
chroma_subsmpl_h, chroma_subsmpl_v);
}
- } else if (!psde->pixel_ext_usr) {
+ } else if (!pp->pixel_ext_usr) {
uint32_t deci_dim, i;
/* calculate default configuration for QSEED2 */
memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
SDE_DEBUG_PLANE(psde, "default config\n");
- deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
- psde->pipe_cfg.horz_decimation);
+ deci_dim = DECIMATED_DIMENSION(pp->pipe_cfg.src_rect.w,
+ pp->pipe_cfg.horz_decimation);
_sde_plane_setup_scaler2(psde,
deci_dim,
- psde->pipe_cfg.dst_rect.w,
+ pp->pipe_cfg.dst_rect.w,
pe->phase_step_x,
pe->horz_filter, fmt, chroma_subsmpl_h);
if (SDE_FORMAT_IS_YUV(fmt))
deci_dim &= ~0x1;
- _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
- psde->pipe_cfg.dst_rect.w, deci_dim,
+ _sde_plane_setup_pixel_ext(psde, pp->pipe_cfg.src_rect.w,
+ pp->pipe_cfg.dst_rect.w, deci_dim,
pe->phase_step_x,
pe->roi_w,
pe->num_ext_pxls_left,
pe->num_ext_pxls_right, pe->horz_filter, fmt,
chroma_subsmpl_h, 0);
- deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
- psde->pipe_cfg.vert_decimation);
+ deci_dim = DECIMATED_DIMENSION(pp->pipe_cfg.src_rect.h,
+ pp->pipe_cfg.vert_decimation);
_sde_plane_setup_scaler2(psde,
deci_dim,
- psde->pipe_cfg.dst_rect.h,
+ pp->pipe_cfg.dst_rect.h,
pe->phase_step_y,
pe->vert_filter, fmt, chroma_subsmpl_v);
- _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
- psde->pipe_cfg.dst_rect.h, deci_dim,
+ _sde_plane_setup_pixel_ext(psde, pp->pipe_cfg.src_rect.h,
+ pp->pipe_cfg.dst_rect.h, deci_dim,
pe->phase_step_y,
pe->roi_h,
pe->num_ext_pxls_top,
@@ -1052,22 +1082,22 @@ static void _sde_plane_setup_scaler(struct sde_plane *psde,
* @alpha: 8-bit fill alpha value, 255 selects 100% alpha
* Returns: 0 on success
*/
-static int _sde_plane_color_fill(struct sde_plane *psde,
+static int _sde_plane_color_fill(struct sde_phy_plane *pp,
uint32_t color, uint32_t alpha)
{
const struct sde_format *fmt;
- if (!psde) {
+ if (!pp) {
SDE_ERROR("invalid plane\n");
return -EINVAL;
}
- if (!psde->pipe_hw) {
- SDE_ERROR_PLANE(psde, "invalid plane h/w pointer\n");
+ if (!pp->pipe_hw) {
+ SDE_ERROR_PLANE(pp->sde_plane, "invalid plane h/w pointer\n");
return -EINVAL;
}
- SDE_DEBUG_PLANE(psde, "\n");
+ SDE_DEBUG_PLANE(pp->sde_plane, "\n");
/*
* select fill format to match user property expectation,
@@ -1076,26 +1106,26 @@ static int _sde_plane_color_fill(struct sde_plane *psde,
fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
/* update sspp */
- if (fmt && psde->pipe_hw->ops.setup_solidfill) {
- psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
+ if (fmt && pp->pipe_hw->ops.setup_solidfill) {
+ pp->pipe_hw->ops.setup_solidfill(pp->pipe_hw,
(color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
/* override scaler/decimation if solid fill */
- psde->pipe_cfg.src_rect.x = 0;
- psde->pipe_cfg.src_rect.y = 0;
- psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
- psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
+ pp->pipe_cfg.src_rect.x = 0;
+ pp->pipe_cfg.src_rect.y = 0;
+ pp->pipe_cfg.src_rect.w = pp->pipe_cfg.dst_rect.w;
+ pp->pipe_cfg.src_rect.h = pp->pipe_cfg.dst_rect.h;
- _sde_plane_setup_scaler(psde, fmt, 0);
+ _sde_plane_setup_scaler(pp, fmt, NULL);
- if (psde->pipe_hw->ops.setup_format)
- psde->pipe_hw->ops.setup_format(psde->pipe_hw,
+ if (pp->pipe_hw->ops.setup_format)
+ pp->pipe_hw->ops.setup_format(pp->pipe_hw,
fmt, SDE_SSPP_SOLID_FILL);
- if (psde->pipe_hw->ops.setup_rects)
- psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
- &psde->pipe_cfg, &psde->pixel_ext,
- psde->scaler3_cfg);
+ if (pp->pipe_hw->ops.setup_rects)
+ pp->pipe_hw->ops.setup_rects(pp->pipe_hw,
+ &pp->pipe_cfg, &pp->pixel_ext,
+ pp->scaler3_cfg);
}
return 0;
@@ -1113,6 +1143,8 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
struct sde_rect src, dst;
bool q16_data = true;
int idx;
+ struct sde_phy_plane *pp;
+ uint32_t num_of_phy_planes = 0, maxlinewidth = 0xFFFF;
if (!plane) {
SDE_ERROR("invalid plane\n");
@@ -1170,19 +1202,24 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
}
}
- if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
- memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
+ memset(&(pp->pipe_cfg), 0,
+ sizeof(struct sde_hw_pipe_cfg));
+
+ _sde_plane_set_scanout(pp, pstate, &pp->pipe_cfg, fb);
- _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
+ pstate->pending = true;
+
+ pp->is_rt_pipe = sde_crtc_is_rt(crtc);
+ _sde_plane_set_qos_ctrl(pp, false, SDE_PLANE_QOS_PANIC_CTRL);
+ }
/* early out if nothing dirty */
if (!pstate->dirty)
return 0;
- pstate->pending = true;
-
- psde->is_rt_pipe = sde_crtc_is_rt(crtc);
- _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
+ memset(&src, 0, sizeof(struct sde_rect));
/* update roi config */
if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) {
POPULATE_RECT(&src, state->src_x, state->src_y,
@@ -1201,72 +1238,99 @@ static int _sde_plane_mode_set(struct drm_plane *plane,
BIT(SDE_DRM_DEINTERLACE)) {
SDE_DEBUG_PLANE(psde, "deinterlace\n");
for (idx = 0; idx < SDE_MAX_PLANES; ++idx)
- psde->pipe_cfg.layout.plane_pitch[idx] <<= 1;
+ pp->pipe_cfg.layout.plane_pitch[idx] <<= 1;
src.h /= 2;
src.y = DIV_ROUND_UP(src.y, 2);
src.y &= ~0x1;
}
+ }
+
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ if (maxlinewidth > pp->pipe_sblk->maxlinewidth)
+ maxlinewidth = pp->pipe_sblk->maxlinewidth;
+ num_of_phy_planes++;
+ }
+
+ /*
+ * Only need to use one physical plane if plane width is still within
+ * the limitation.
+ */
+ if (maxlinewidth >= (src.x + src.w))
+ num_of_phy_planes = 1;
+
+ if (num_of_phy_planes > 1) {
+ /* Adjust width for multi-pipe */
+ src.w /= num_of_phy_planes;
+ dst.w /= num_of_phy_planes;
+ }
- psde->pipe_cfg.src_rect = src;
- psde->pipe_cfg.dst_rect = dst;
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ /* Adjust offset for multi-pipe */
+ src.x += src.w * pp->index;
+ dst.x += dst.w * pp->index;
+
+ pp->pipe_cfg.src_rect = src;
+ pp->pipe_cfg.dst_rect = dst;
/* check for color fill */
- psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
+ pp->color_fill = (uint32_t)sde_plane_get_property(pstate,
PLANE_PROP_COLOR_FILL);
- if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG) {
+ if (pp->color_fill & SDE_PLANE_COLOR_FILL_FLAG) {
/* skip remaining processing on color fill */
pstate->dirty = 0x0;
- } else if (psde->pipe_hw->ops.setup_rects) {
- _sde_plane_setup_scaler(psde, fmt, pstate);
+ } else if (pp->pipe_hw->ops.setup_rects) {
+ _sde_plane_setup_scaler(pp, fmt, pstate);
- psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
- &psde->pipe_cfg, &psde->pixel_ext,
- psde->scaler3_cfg);
+ pp->pipe_hw->ops.setup_rects(pp->pipe_hw,
+ &pp->pipe_cfg, &pp->pixel_ext,
+ pp->scaler3_cfg);
}
- }
- if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) &&
- psde->pipe_hw->ops.setup_format) {
- src_flags = 0x0;
- SDE_DEBUG_PLANE(psde, "rotation 0x%llX\n",
+ if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) &&
+ pp->pipe_hw->ops.setup_format) {
+ src_flags = 0x0;
+ SDE_DEBUG_PLANE(psde, "rotation 0x%llX\n",
sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
- if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
- BIT(DRM_REFLECT_X))
- src_flags |= SDE_SSPP_FLIP_LR;
- if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
- BIT(DRM_REFLECT_Y))
- src_flags |= SDE_SSPP_FLIP_UD;
-
- /* update format */
- psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt, src_flags);
-
- /* update csc */
- if (SDE_FORMAT_IS_YUV(fmt))
- _sde_plane_setup_csc(psde);
- else
- psde->csc_ptr = 0;
- }
+ if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION)
+ & BIT(DRM_REFLECT_X))
+ src_flags |= SDE_SSPP_FLIP_LR;
+ if (sde_plane_get_property(pstate,
+ PLANE_PROP_ROTATION) & BIT(DRM_REFLECT_Y))
+ src_flags |= SDE_SSPP_FLIP_UD;
+
+ /* update format */
+ pp->pipe_hw->ops.setup_format(pp->pipe_hw,
+ fmt, src_flags);
+
+ /* update csc */
+ if (SDE_FORMAT_IS_YUV(fmt))
+ _sde_plane_setup_csc(pp);
+ else
+ pp->csc_ptr = NULL;
+ }
- sde_color_process_plane_setup(plane);
+ sde_color_process_plane_setup(plane, pp);
- /* update sharpening */
- if ((pstate->dirty & SDE_PLANE_DIRTY_SHARPEN) &&
- psde->pipe_hw->ops.setup_sharpening) {
- psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
- psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
- psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
- psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
+ /* update sharpening */
+ if ((pstate->dirty & SDE_PLANE_DIRTY_SHARPEN) &&
+ pp->pipe_hw->ops.setup_sharpening) {
+ pp->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
+ pp->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
+ pp->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
+ pp->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
- psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
- &psde->sharp_cfg);
- }
+ pp->pipe_hw->ops.setup_sharpening(pp->pipe_hw,
+ &pp->sharp_cfg);
+ }
- _sde_plane_set_qos_lut(plane, fb);
- _sde_plane_set_danger_lut(plane, fb);
+ _sde_plane_set_qos_lut(pp, fb);
+ _sde_plane_set_danger_lut(pp, fb);
- 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 (plane->type != DRM_PLANE_TYPE_CURSOR) {
+ _sde_plane_set_qos_ctrl(pp, true,
+ SDE_PLANE_QOS_PANIC_CTRL);
+ _sde_plane_set_ot_limit(pp, crtc);
+ }
}
/* clear dirty */
@@ -1393,10 +1457,12 @@ static int sde_plane_atomic_check(struct drm_plane *plane,
uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
bool q16_data = true;
+ struct sde_phy_plane *pp;
+ uint32_t num_of_phy_planes = 0;
if (!plane || !state) {
- SDE_ERROR("invalid arg(s), plane %d state %d\n",
- plane != 0, state != 0);
+ SDE_ERROR("invalid arg(s), plane %d state %d.\n",
+ plane != NULL, state != NULL);
ret = -EINVAL;
goto exit;
}
@@ -1404,11 +1470,8 @@ static int sde_plane_atomic_check(struct drm_plane *plane,
psde = to_sde_plane(plane);
pstate = to_sde_plane_state(state);
- if (!psde->pipe_sblk) {
- SDE_ERROR_PLANE(psde, "invalid catalog\n");
- ret = -EINVAL;
- goto exit;
- }
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list)
+ num_of_phy_planes++;
deci_w = sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
deci_h = sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
@@ -1422,10 +1485,6 @@ static int sde_plane_atomic_check(struct drm_plane *plane,
src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
- max_upscale = psde->pipe_sblk->maxupscale;
- max_downscale = psde->pipe_sblk->maxdwnscale;
- max_linewidth = psde->pipe_sblk->maxlinewidth;
-
SDE_DEBUG_PLANE(psde, "check %d -> %d\n",
sde_plane_enabled(plane->state), sde_plane_enabled(state));
@@ -1436,73 +1495,87 @@ static int sde_plane_atomic_check(struct drm_plane *plane,
min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
- if (SDE_FORMAT_IS_YUV(fmt) &&
- (!(psde->features & SDE_SSPP_SCALER) ||
- !(psde->features & (BIT(SDE_SSPP_CSC)
- | BIT(SDE_SSPP_CSC_10BIT))))) {
- SDE_ERROR_PLANE(psde,
- "plane doesn't have scaler/csc for yuv\n");
- ret = -EINVAL;
-
- /* check src bounds */
- } else if (state->fb->width > MAX_IMG_WIDTH ||
- state->fb->height > MAX_IMG_HEIGHT ||
- src.w < min_src_size || src.h < min_src_size ||
- CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
- CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
- SDE_ERROR_PLANE(psde, "invalid source %u, %u, %ux%u\n",
- src.x, src.y, src.w, src.h);
- ret = -E2BIG;
-
- /* valid yuv image */
- } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
- (src.w & 0x1) || (src.h & 0x1))) {
- SDE_ERROR_PLANE(psde, "invalid yuv source %u, %u, %ux%u\n",
- src.x, src.y, src.w, src.h);
- ret = -EINVAL;
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ if (!pp->pipe_sblk) {
+ SDE_ERROR("invalid plane catalog\n");
+ ret = -EINVAL;
+ goto exit;
+ }
- /* min dst support */
- } else if (dst.w < 0x1 || dst.h < 0x1) {
- SDE_ERROR_PLANE(psde, "invalid dest rect %u, %u, %ux%u\n",
- dst.x, dst.y, dst.w, dst.h);
- ret = -EINVAL;
+ max_upscale = pp->pipe_sblk->maxupscale;
+ max_downscale = pp->pipe_sblk->maxdwnscale;
+ max_linewidth = pp->pipe_sblk->maxlinewidth;
- /* decimation validation */
- } else if (deci_w || deci_h) {
- if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
- (deci_h > psde->pipe_sblk->maxvdeciexp)) {
+ if (SDE_FORMAT_IS_YUV(fmt) &&
+ (!(pp->features & SDE_SSPP_SCALER) ||
+ !(pp->features & (BIT(SDE_SSPP_CSC)
+ | BIT(SDE_SSPP_CSC_10BIT))))) {
SDE_ERROR_PLANE(psde,
- "too much decimation requested\n");
+ "plane doesn't have scaler/csc for yuv\n");
ret = -EINVAL;
- } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
- SDE_ERROR_PLANE(psde,
- "decimation requires linear fetch\n");
+
+ /* check src bounds */
+ } else if (state->fb->width > MAX_IMG_WIDTH ||
+ state->fb->height > MAX_IMG_HEIGHT ||
+ src.w < min_src_size || src.h < min_src_size ||
+ CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
+ CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
+ SDE_ERROR_PLANE(psde, "invalid source %u, %u, %ux%u\n",
+ src.x, src.y, src.w, src.h);
+ ret = -E2BIG;
+
+ /* valid yuv image */
+ } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1)
+ || (src.y & 0x1) || (src.w & 0x1)
+ || (src.h & 0x1))) {
+ SDE_ERROR_PLANE(psde, "invalid yuv source %u, %u,\"\
+ %ux%u\n", src.x, src.y, src.w, src.h);
ret = -EINVAL;
- }
- } else if (!(psde->features & SDE_SSPP_SCALER) &&
- ((src.w != dst.w) || (src.h != dst.h))) {
- SDE_ERROR_PLANE(psde,
- "pipe doesn't support scaling %ux%u->%ux%u\n",
- src.w, src.h, dst.w, dst.h);
- ret = -EINVAL;
+ /* min dst support */
+ } else if (dst.w < 0x1 || dst.h < 0x1) {
+ SDE_ERROR_PLANE(psde, "invalid dest rect %u, %u,\"\
+ %ux%u\n", dst.x, dst.y, dst.w, dst.h);
+ ret = -EINVAL;
- /* check decimated source width */
- } else if (src_deci_w > max_linewidth) {
- SDE_ERROR_PLANE(psde,
- "invalid src w:%u, deci w:%u, line w:%u\n",
- src.w, src_deci_w, max_linewidth);
- ret = -E2BIG;
+ /* decimation validation */
+ } else if (deci_w || deci_h) {
+ if ((deci_w > pp->pipe_sblk->maxhdeciexp) ||
+ (deci_h > pp->pipe_sblk->maxvdeciexp)) {
+ SDE_ERROR_PLANE(psde,
+ "too much decimation requested\n");
+ ret = -EINVAL;
+ } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
+ SDE_ERROR_PLANE(psde,
+ "decimation requires linear fetch\n");
+ ret = -EINVAL;
+ }
- /* check max scaler capability */
- } else if (((src_deci_w * max_upscale) < dst.w) ||
- ((src_deci_h * max_upscale) < dst.h) ||
- ((dst.w * max_downscale) < src_deci_w) ||
- ((dst.h * max_downscale) < src_deci_h)) {
- SDE_ERROR_PLANE(psde,
- "too much scaling requested %ux%u->%ux%u\n",
- src_deci_w, src_deci_h, dst.w, dst.h);
- ret = -E2BIG;
+ } else if (!(pp->features & SDE_SSPP_SCALER) &&
+ ((src.w != dst.w) || (src.h != dst.h))) {
+ SDE_ERROR_PLANE(psde,
+ "pipe doesn't support scaling %ux%u->%ux%u\n",
+ src.w, src.h, dst.w, dst.h);
+ ret = -EINVAL;
+
+ /* check decimated source width */
+ } else if (src_deci_w > max_linewidth * num_of_phy_planes) {
+ SDE_ERROR_PLANE(psde,
+ "invalid src w:%u, deci w:%u, line w:%u, num_phy_planes:%u\n",
+ src.w, src_deci_w, max_linewidth,
+ num_of_phy_planes);
+ ret = -E2BIG;
+
+ /* check max scaler capability */
+ } else if (((src_deci_w * max_upscale) < dst.w) ||
+ ((src_deci_h * max_upscale) < dst.h) ||
+ ((dst.w * max_downscale) < src_deci_w) ||
+ ((dst.h * max_downscale) < src_deci_h)) {
+ SDE_ERROR_PLANE(psde,
+ "too much scaling requested %ux%u->%ux%u\n",
+ src_deci_w, src_deci_h, dst.w, dst.h);
+ ret = -E2BIG;
+ }
}
modeset_update:
@@ -1519,6 +1592,7 @@ exit:
void sde_plane_flush(struct drm_plane *plane)
{
struct sde_plane *psde;
+ struct sde_phy_plane *pp;
if (!plane) {
SDE_ERROR("invalid plane\n");
@@ -1531,14 +1605,17 @@ void sde_plane_flush(struct drm_plane *plane)
* These updates have to be done immediately before the plane flush
* timing, and may not be moved to the atomic_update/mode_set functions.
*/
- if (psde->is_error)
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ if (psde->is_error)
/* force white frame with 0% alpha pipe output on error */
- _sde_plane_color_fill(psde, 0xFFFFFF, 0x0);
- else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
- /* force 100% alpha */
- _sde_plane_color_fill(psde, psde->color_fill, 0xFF);
- else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
- psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
+ _sde_plane_color_fill(pp, 0xFFFFFF, 0x0);
+ else if (pp->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
+ /* force 100% alpha */
+ _sde_plane_color_fill(pp, pp->color_fill, 0xFF);
+ else if (pp->pipe_hw && pp->csc_ptr &&
+ pp->pipe_hw->ops.setup_csc)
+ pp->pipe_hw->ops.setup_csc(pp->pipe_hw, pp->csc_ptr);
+ }
/* flag h/w flush complete */
if (plane->state)
@@ -1598,19 +1675,48 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
int zpos_max = 255;
int zpos_def = 0;
char feature_name[256];
+ struct sde_phy_plane *pp;
+ uint32_t features = 0xFFFFFFFF, nformats = 64;
+ u32 maxlinewidth = -1, maxupscale = -1, maxdwnscale = -1;
+ u32 maxhdeciexp = -1, maxvdeciexp = -1;
if (!plane || !psde) {
SDE_ERROR("invalid plane\n");
return;
- } else if (!psde->pipe_hw || !psde->pipe_sblk) {
- SDE_ERROR("invalid plane, pipe_hw %d pipe_sblk %d\n",
- psde->pipe_hw != 0, psde->pipe_sblk != 0);
- return;
- } else if (!catalog) {
+ }
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ if (!pp->pipe_hw || !pp->pipe_sblk) {
+ SDE_ERROR("invalid phy_plane, pipe_hw %d\"\
+ pipe_sblk %d\n", pp->pipe_hw != NULL,
+ pp->pipe_sblk != NULL);
+ return;
+ }
+ }
+ if (!catalog) {
SDE_ERROR("invalid catalog\n");
return;
}
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ /* Get common features for all pipes */
+ features &= pp->features;
+ if (nformats > pp->nformats) {
+ nformats = pp->nformats;
+ format_list = pp->pipe_sblk->format_list;
+ }
+ if (maxlinewidth < pp->pipe_sblk->maxlinewidth)
+ maxlinewidth = pp->pipe_sblk->maxlinewidth;
+ if (maxupscale < pp->pipe_sblk->maxupscale)
+ maxupscale = pp->pipe_sblk->maxupscale;
+ if (maxdwnscale < pp->pipe_sblk->maxdwnscale)
+ maxdwnscale = pp->pipe_sblk->maxdwnscale;
+ if (maxhdeciexp < pp->pipe_sblk->maxhdeciexp)
+ maxhdeciexp = pp->pipe_sblk->maxhdeciexp;
+ if (maxvdeciexp < pp->pipe_sblk->maxvdeciexp)
+ maxvdeciexp = pp->pipe_sblk->maxvdeciexp;
+ break;
+ }
+
if (sde_is_custom_client()) {
if (catalog->mixer_count && catalog->mixer &&
catalog->mixer[0].sblk->maxblendstages) {
@@ -1633,19 +1739,24 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
msm_property_install_range(&psde->property_info, "input_fence",
0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
- if (psde->pipe_sblk->maxhdeciexp) {
- msm_property_install_range(&psde->property_info, "h_decimate",
- 0x0, 0, psde->pipe_sblk->maxhdeciexp, 0,
- PLANE_PROP_H_DECIMATE);
- }
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ if (pp->pipe_sblk->maxhdeciexp) {
+ msm_property_install_range(&psde->property_info,
+ "h_decimate", 0x0, 0,
+ pp->pipe_sblk->maxhdeciexp, 0,
+ PLANE_PROP_H_DECIMATE);
+ }
- if (psde->pipe_sblk->maxvdeciexp) {
- msm_property_install_range(&psde->property_info, "v_decimate",
- 0x0, 0, psde->pipe_sblk->maxvdeciexp, 0,
+ if (pp->pipe_sblk->maxvdeciexp) {
+ msm_property_install_range(&psde->property_info,
+ "v_decimate", 0x0, 0,
+ pp->pipe_sblk->maxvdeciexp, 0,
PLANE_PROP_V_DECIMATE);
+ }
+ break;
}
- if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
+ if (features & BIT(SDE_SSPP_SCALER_QSEED3)) {
msm_property_install_volatile_range(&psde->property_info,
"scaler_v2", 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V2);
msm_property_install_blob(&psde->property_info, "lut_ed", 0,
@@ -1654,38 +1765,38 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
PLANE_PROP_SCALER_LUT_CIR);
msm_property_install_blob(&psde->property_info, "lut_sep", 0,
PLANE_PROP_SCALER_LUT_SEP);
- } else if (psde->features & SDE_SSPP_SCALER) {
+ } else if (features & SDE_SSPP_SCALER) {
msm_property_install_volatile_range(&psde->property_info,
"scaler_v1", 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V1);
}
- if (psde->features & BIT(SDE_SSPP_CSC)) {
+ if (features & BIT(SDE_SSPP_CSC)) {
msm_property_install_volatile_range(&psde->property_info,
"csc_v1", 0x0, 0, ~0, 0, PLANE_PROP_CSC_V1);
}
- if (psde->features & BIT(SDE_SSPP_HSIC)) {
+ if (features & BIT(SDE_SSPP_HSIC)) {
snprintf(feature_name, sizeof(feature_name), "%s%d",
"SDE_SSPP_HUE_V",
- psde->pipe_sblk->hsic_blk.version >> 16);
+ pp->pipe_sblk->hsic_blk.version >> 16);
msm_property_install_range(&psde->property_info,
feature_name, 0, 0, 0xFFFFFFFF, 0,
PLANE_PROP_HUE_ADJUST);
snprintf(feature_name, sizeof(feature_name), "%s%d",
"SDE_SSPP_SATURATION_V",
- psde->pipe_sblk->hsic_blk.version >> 16);
+ pp->pipe_sblk->hsic_blk.version >> 16);
msm_property_install_range(&psde->property_info,
feature_name, 0, 0, 0xFFFFFFFF, 0,
PLANE_PROP_SATURATION_ADJUST);
snprintf(feature_name, sizeof(feature_name), "%s%d",
"SDE_SSPP_VALUE_V",
- psde->pipe_sblk->hsic_blk.version >> 16);
+ pp->pipe_sblk->hsic_blk.version >> 16);
msm_property_install_range(&psde->property_info,
feature_name, 0, 0, 0xFFFFFFFF, 0,
PLANE_PROP_VALUE_ADJUST);
snprintf(feature_name, sizeof(feature_name), "%s%d",
"SDE_SSPP_CONTRAST_V",
- psde->pipe_sblk->hsic_blk.version >> 16);
+ pp->pipe_sblk->hsic_blk.version >> 16);
msm_property_install_range(&psde->property_info,
feature_name, 0, 0, 0xFFFFFFFF, 0,
PLANE_PROP_CONTRAST_ADJUST);
@@ -1701,9 +1812,13 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
- if (psde->pipe_hw->ops.setup_solidfill)
- msm_property_install_range(&psde->property_info, "color_fill",
- 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ if (pp->pipe_hw->ops.setup_solidfill)
+ msm_property_install_range(&psde->property_info,
+ "color_fill", 0, 0, 0xFFFFFFFF, 0,
+ PLANE_PROP_COLOR_FILL);
+ break;
+ }
info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
if (!info) {
@@ -1715,7 +1830,6 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
sde_kms_info_reset(info);
- format_list = psde->pipe_sblk->format_list;
if (format_list) {
sde_kms_info_start(info, "pixel_formats");
while (format_list->fourcc_format) {
@@ -1727,51 +1841,49 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
sde_kms_info_stop(info);
}
- sde_kms_info_add_keyint(info, "max_linewidth",
- psde->pipe_sblk->maxlinewidth);
- sde_kms_info_add_keyint(info, "max_upscale",
- psde->pipe_sblk->maxupscale);
- sde_kms_info_add_keyint(info, "max_downscale",
- psde->pipe_sblk->maxdwnscale);
- sde_kms_info_add_keyint(info, "max_horizontal_deci",
- psde->pipe_sblk->maxhdeciexp);
- sde_kms_info_add_keyint(info, "max_vertical_deci",
- psde->pipe_sblk->maxvdeciexp);
+ sde_kms_info_add_keyint(info, "max_linewidth", maxlinewidth);
+ sde_kms_info_add_keyint(info, "max_upscale", maxupscale);
+ sde_kms_info_add_keyint(info, "max_downscale", maxdwnscale);
+ sde_kms_info_add_keyint(info, "max_horizontal_deci", maxhdeciexp);
+ sde_kms_info_add_keyint(info, "max_vertical_deci", maxvdeciexp);
msm_property_set_blob(&psde->property_info, &psde->blob_info,
info->data, info->len, PLANE_PROP_INFO);
kfree(info);
- if (psde->features & BIT(SDE_SSPP_MEMCOLOR)) {
+ if (features & BIT(SDE_SSPP_MEMCOLOR)) {
snprintf(feature_name, sizeof(feature_name), "%s%d",
"SDE_SSPP_SKIN_COLOR_V",
- psde->pipe_sblk->memcolor_blk.version >> 16);
+ pp->pipe_sblk->memcolor_blk.version >> 16);
msm_property_install_blob(&psde->property_info, feature_name, 0,
PLANE_PROP_SKIN_COLOR);
snprintf(feature_name, sizeof(feature_name), "%s%d",
"SDE_SSPP_SKY_COLOR_V",
- psde->pipe_sblk->memcolor_blk.version >> 16);
+ pp->pipe_sblk->memcolor_blk.version >> 16);
msm_property_install_blob(&psde->property_info, feature_name, 0,
PLANE_PROP_SKY_COLOR);
snprintf(feature_name, sizeof(feature_name), "%s%d",
"SDE_SSPP_FOLIAGE_COLOR_V",
- psde->pipe_sblk->memcolor_blk.version >> 16);
+ pp->pipe_sblk->memcolor_blk.version >> 16);
msm_property_install_blob(&psde->property_info, feature_name, 0,
PLANE_PROP_FOLIAGE_COLOR);
}
}
-static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, void *usr_ptr)
+static inline void _sde_plane_set_csc_v1(struct sde_phy_plane *pp,
+ void *usr_ptr)
{
struct sde_drm_csc_v1 csc_v1;
+ struct sde_plane *psde;
int i;
- if (!psde) {
- SDE_ERROR("invalid plane\n");
+ if (!pp) {
+ SDE_ERROR("invalid phy_plane\n");
return;
}
+ psde = pp->sde_plane;
- psde->csc_usr_ptr = NULL;
+ pp->csc_usr_ptr = NULL;
if (!usr_ptr) {
SDE_DEBUG_PLANE(psde, "csc data removed\n");
return;
@@ -1784,30 +1896,33 @@ static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, void *usr_ptr)
/* populate from user space */
for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
- psde->csc_cfg.csc_mv[i] = csc_v1.ctm_coeff[i] >> 16;
+ pp->csc_cfg.csc_mv[i] = csc_v1.ctm_coeff[i] >> 16;
for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
- psde->csc_cfg.csc_pre_bv[i] = csc_v1.pre_bias[i];
- psde->csc_cfg.csc_post_bv[i] = csc_v1.post_bias[i];
+ pp->csc_cfg.csc_pre_bv[i] = csc_v1.pre_bias[i];
+ pp->csc_cfg.csc_post_bv[i] = csc_v1.post_bias[i];
}
for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
- psde->csc_cfg.csc_pre_lv[i] = csc_v1.pre_clamp[i];
- psde->csc_cfg.csc_post_lv[i] = csc_v1.post_clamp[i];
+ pp->csc_cfg.csc_pre_lv[i] = csc_v1.pre_clamp[i];
+ pp->csc_cfg.csc_post_lv[i] = csc_v1.post_clamp[i];
}
- psde->csc_usr_ptr = &psde->csc_cfg;
+ pp->csc_usr_ptr = &pp->csc_cfg;
}
-static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, void *usr)
+static inline void _sde_plane_set_scaler_v1(struct sde_phy_plane *pp,
+ void *usr)
{
struct sde_drm_scaler_v1 scale_v1;
struct sde_hw_pixel_ext *pe;
+ struct sde_plane *psde;
int i;
- if (!psde) {
- SDE_ERROR("invalid plane\n");
+ if (!pp) {
+ SDE_ERROR("invalid phy_plane\n");
return;
}
+ psde = pp->sde_plane;
- psde->pixel_ext_usr = false;
+ pp->pixel_ext_usr = false;
if (!usr) {
SDE_DEBUG_PLANE(psde, "scale data removed\n");
return;
@@ -1819,7 +1934,7 @@ static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, void *usr)
}
/* populate from user space */
- pe = &(psde->pixel_ext);
+ pe = &(pp->pixel_ext);
memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
for (i = 0; i < SDE_MAX_PLANES; i++) {
pe->init_phase_x[i] = scale_v1.init_phase_x[i];
@@ -1844,26 +1959,28 @@ static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, void *usr)
pe->roi_h[i] = scale_v1.pe.num_ext_pxls_tb[i];
}
- psde->pixel_ext_usr = true;
+ pp->pixel_ext_usr = true;
SDE_DEBUG_PLANE(psde, "user property data copied\n");
}
-static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
+static inline void _sde_plane_set_scaler_v2(struct sde_phy_plane *pp,
struct sde_plane_state *pstate, void *usr)
{
struct sde_drm_scaler_v2 scale_v2;
struct sde_hw_pixel_ext *pe;
int i;
struct sde_hw_scaler3_cfg *cfg;
+ struct sde_plane *psde;
- if (!psde) {
- SDE_ERROR("invalid plane\n");
+ if (!pp) {
+ SDE_ERROR("invalid phy_plane\n");
return;
}
+ psde = pp->sde_plane;
- cfg = psde->scaler3_cfg;
- psde->pixel_ext_usr = false;
+ cfg = pp->scaler3_cfg;
+ pp->pixel_ext_usr = false;
if (!usr) {
SDE_DEBUG_PLANE(psde, "scale data removed\n");
return;
@@ -1875,7 +1992,7 @@ static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
}
/* populate from user space */
- pe = &(psde->pixel_ext);
+ pe = &(pp->pixel_ext);
memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
cfg->enable = scale_v2.enable;
cfg->dir_en = scale_v2.dir_en;
@@ -1933,7 +2050,7 @@ static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
pe->btm_rpt[i] = scale_v2.pe.btm_rpt[i];
pe->roi_h[i] = scale_v2.pe.num_ext_pxls_tb[i];
}
- psde->pixel_ext_usr = true;
+ pp->pixel_ext_usr = true;
SDE_DEBUG_PLANE(psde, "user property data copied\n");
}
@@ -1945,6 +2062,7 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane,
struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
struct sde_plane_state *pstate;
int idx, ret = -EINVAL;
+ struct sde_phy_plane *pp;
SDE_DEBUG_PLANE(psde, "\n");
@@ -1965,14 +2083,24 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane,
_sde_plane_set_input_fence(psde, pstate, val);
break;
case PLANE_PROP_CSC_V1:
- _sde_plane_set_csc_v1(psde, (void *)val);
+ list_for_each_entry(pp, &psde->phy_plane_head,
+ phy_plane_list) {
+ _sde_plane_set_csc_v1(pp, (void *)val);
+ }
break;
case PLANE_PROP_SCALER_V1:
- _sde_plane_set_scaler_v1(psde, (void *)val);
+ list_for_each_entry(pp, &psde->phy_plane_head,
+ phy_plane_list) {
+ _sde_plane_set_scaler_v1(pp,
+ (void *)val);
+ }
break;
case PLANE_PROP_SCALER_V2:
- _sde_plane_set_scaler_v2(psde, pstate,
- (void *)val);
+ list_for_each_entry(pp, &psde->phy_plane_head,
+ phy_plane_list) {
+ _sde_plane_set_scaler_v2(pp, pstate,
+ (void *)val);
+ }
break;
default:
/* nothing to do */
@@ -2019,12 +2147,15 @@ static int sde_plane_atomic_get_property(struct drm_plane *plane,
static void sde_plane_destroy(struct drm_plane *plane)
{
struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
+ struct sde_phy_plane *pp, *n;
SDE_DEBUG_PLANE(psde, "\n");
if (psde) {
- _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
-
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ _sde_plane_set_qos_ctrl(pp,
+ false, SDE_PLANE_QOS_PANIC_CTRL);
+ }
debugfs_remove_recursive(psde->debugfs_root);
if (psde->blob_info)
@@ -2037,8 +2168,13 @@ static void sde_plane_destroy(struct drm_plane *plane)
/* this will destroy the states as well */
drm_plane_cleanup(plane);
- if (psde->pipe_hw)
- sde_hw_sspp_destroy(psde->pipe_hw);
+ list_for_each_entry_safe(pp, n,
+ &psde->phy_plane_head, phy_plane_list) {
+ if (pp->pipe_hw)
+ sde_hw_sspp_destroy(pp->pipe_hw);
+ list_del(&pp->phy_plane_list);
+ kfree(pp);
+ }
kfree(psde);
}
@@ -2174,9 +2310,22 @@ static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
.atomic_update = sde_plane_atomic_update,
};
-enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
+enum sde_sspp sde_plane_pipe(struct drm_plane *plane, uint32_t index)
{
- return plane ? to_sde_plane(plane)->pipe : SSPP_NONE;
+ struct sde_plane *sde_plane = to_sde_plane(plane);
+ struct sde_phy_plane *pp;
+ int i = 0;
+ enum sde_sspp default_sspp = SSPP_NONE;
+
+ list_for_each_entry(pp, &sde_plane->phy_plane_head, phy_plane_list) {
+ if (i == 0)
+ default_sspp = pp->pipe;
+ if (i == index)
+ return pp->pipe;
+ i++;
+ }
+
+ return default_sspp;
}
static ssize_t _sde_plane_danger_read(struct file *file,
@@ -2208,10 +2357,16 @@ static ssize_t _sde_plane_danger_read(struct file *file,
static void _sde_plane_set_danger_state(struct sde_kms *kms, bool enable)
{
struct drm_plane *plane;
+ struct sde_plane *psde;
+ struct sde_phy_plane *pp;
drm_for_each_plane(plane, kms->dev) {
if (plane->fb && plane->state) {
- sde_plane_danger_signal_ctrl(plane, enable);
+ psde = to_sde_plane(plane);
+ list_for_each_entry(pp, &psde->phy_plane_head,
+ phy_plane_list) {
+ sde_plane_danger_signal_ctrl(pp, enable);
+ }
SDE_DEBUG("plane:%d img:%dx%d ",
plane->base.id, plane->fb->width,
plane->fb->height);
@@ -2229,7 +2384,7 @@ static void _sde_plane_set_danger_state(struct sde_kms *kms, bool enable)
}
static ssize_t _sde_plane_danger_write(struct file *file,
- const char __user *user_buf, size_t count, loff_t *ppos)
+ const char __user *user_buf, size_t count, loff_t *ppos)
{
struct sde_kms *kms = file->private_data;
struct sde_mdss_cfg *cfg = kms->catalog;
@@ -2271,85 +2426,166 @@ static const struct file_operations sde_plane_danger_enable = {
.write = _sde_plane_danger_write,
};
-static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
+static void _sde_plane_init_debugfs(struct sde_plane *psde,
+ struct sde_kms *kms)
{
const struct sde_sspp_sub_blks *sblk = 0;
const struct sde_sspp_cfg *cfg = 0;
+ struct sde_phy_plane *pp;
+
+ if (!psde || !kms) {
+ SDE_ERROR("invalid arg(s), psde %d kms %d\n",
+ psde != NULL, kms != NULL);
+ return;
+ }
- if (psde && psde->pipe_hw)
- cfg = psde->pipe_hw->cap;
- if (cfg)
+ /* create overall sub-directory for the pipe */
+ psde->debugfs_root = debugfs_create_dir(psde->pipe_name,
+ sde_debugfs_get_root(kms));
+ if (!psde->debugfs_root)
+ return;
+
+ list_for_each_entry(pp, &psde->phy_plane_head, phy_plane_list) {
+ debugfs_create_u32("pipe", S_IRUGO | S_IWUSR,
+ psde->debugfs_root, &pp->pipe);
+
+ if (!pp->pipe_hw || !pp->pipe_hw->cap ||
+ !pp->pipe_hw->cap->sblk)
+ continue;
+ cfg = pp->pipe_hw->cap;
sblk = cfg->sblk;
- if (kms && sblk) {
- /* create overall sub-directory for the pipe */
- psde->debugfs_root =
- debugfs_create_dir(psde->pipe_name,
- sde_debugfs_get_root(kms));
- if (psde->debugfs_root) {
- /* don't error check these */
- debugfs_create_x32("features", S_IRUGO | S_IWUSR,
- psde->debugfs_root, &psde->features);
-
- /* add register dump support */
- sde_debugfs_setup_regset32(&psde->debugfs_src,
- sblk->src_blk.base + cfg->base,
- sblk->src_blk.len,
- kms);
- sde_debugfs_create_regset32("src_blk", S_IRUGO,
- psde->debugfs_root, &psde->debugfs_src);
-
- sde_debugfs_setup_regset32(&psde->debugfs_scaler,
- sblk->scaler_blk.base + cfg->base,
- sblk->scaler_blk.len,
- kms);
- sde_debugfs_create_regset32("scaler_blk", S_IRUGO,
- psde->debugfs_root,
- &psde->debugfs_scaler);
-
- sde_debugfs_setup_regset32(&psde->debugfs_csc,
- sblk->csc_blk.base + cfg->base,
- sblk->csc_blk.len,
- kms);
- sde_debugfs_create_regset32("csc_blk", S_IRUGO,
- psde->debugfs_root, &psde->debugfs_csc);
-
- debugfs_create_u32("xin_id",
- S_IRUGO,
- psde->debugfs_root,
- (u32 *) &cfg->xin_id);
- debugfs_create_u32("clk_ctrl",
- S_IRUGO,
- psde->debugfs_root,
- (u32 *) &cfg->clk_ctrl);
- debugfs_create_x32("creq_vblank",
- S_IRUGO | S_IWUSR,
- psde->debugfs_root,
- (u32 *) &sblk->creq_vblank);
- debugfs_create_x32("danger_vblank",
- S_IRUGO | S_IWUSR,
- psde->debugfs_root,
- (u32 *) &sblk->danger_vblank);
-
- debugfs_create_file("disable_danger",
- S_IRUGO | S_IWUSR,
- psde->debugfs_root,
- kms, &sde_plane_danger_enable);
+ /* don't error check these */
+ debugfs_create_x32("features", S_IRUGO | S_IWUSR,
+ psde->debugfs_root, &pp->features);
+
+ /* add register dump support */
+ sde_debugfs_setup_regset32(&psde->debugfs_src,
+ sblk->src_blk.base + cfg->base,
+ sblk->src_blk.len,
+ kms);
+ sde_debugfs_create_regset32("src_blk", S_IRUGO,
+ psde->debugfs_root, &psde->debugfs_src);
+
+ sde_debugfs_setup_regset32(&psde->debugfs_scaler,
+ sblk->scaler_blk.base + cfg->base,
+ sblk->scaler_blk.len,
+ kms);
+ sde_debugfs_create_regset32("scaler_blk", S_IRUGO,
+ psde->debugfs_root,
+ &psde->debugfs_scaler);
+
+ sde_debugfs_setup_regset32(&psde->debugfs_csc,
+ sblk->csc_blk.base + cfg->base,
+ sblk->csc_blk.len,
+ kms);
+ sde_debugfs_create_regset32("csc_blk", S_IRUGO,
+ psde->debugfs_root, &psde->debugfs_csc);
+
+ debugfs_create_u32("xin_id",
+ S_IRUGO,
+ psde->debugfs_root,
+ (u32 *) &cfg->xin_id);
+ debugfs_create_u32("clk_ctrl",
+ S_IRUGO,
+ psde->debugfs_root,
+ (u32 *) &cfg->clk_ctrl);
+ debugfs_create_x32("creq_vblank",
+ S_IRUGO | S_IWUSR,
+ psde->debugfs_root,
+ (u32 *) &sblk->creq_vblank);
+ debugfs_create_x32("danger_vblank",
+ S_IRUGO | S_IWUSR,
+ psde->debugfs_root,
+ (u32 *) &sblk->danger_vblank);
+
+ debugfs_create_file("disable_danger",
+ S_IRUGO | S_IWUSR,
+ psde->debugfs_root,
+ kms, &sde_plane_danger_enable);
+
+ break;
+ }
+}
+
+static int _sde_init_phy_plane(struct sde_kms *sde_kms,
+ struct sde_plane *psde, uint32_t pipe, uint32_t index,
+ struct sde_phy_plane *pp)
+{
+ int rc = 0;
+
+ pp->pipe_hw = sde_rm_get_hw_by_id(&sde_kms->rm,
+ SDE_HW_BLK_SSPP, pipe);
+ if (!pp->pipe_hw) {
+ SDE_ERROR("Not found resource for id=%d\n", pipe);
+ rc = -EINVAL;
+ goto end;
+ } else if (!pp->pipe_hw->cap || !pp->pipe_hw->cap->sblk) {
+ SDE_ERROR("[%u]SSPP returned invalid cfg\n", pipe);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ /* cache features mask for later */
+ pp->features = pp->pipe_hw->cap->features;
+ pp->pipe_sblk = pp->pipe_hw->cap->sblk;
+ if (!pp->pipe_sblk) {
+ SDE_ERROR("invalid sblk on pipe %d\n", pipe);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (pp->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
+ pp->scaler3_cfg = kzalloc(sizeof(struct sde_hw_scaler3_cfg),
+ GFP_KERNEL);
+ if (!pp->scaler3_cfg) {
+ SDE_ERROR("[%u]failed to allocate scale struct\n",
+ pipe);
+ rc = -ENOMEM;
+ goto end;
}
}
+
+ /* add plane to DRM framework */
+ pp->nformats = sde_populate_formats(
+ pp->pipe_sblk->format_list,
+ pp->formats,
+ NULL,
+ ARRAY_SIZE(pp->formats));
+
+ if (!pp->nformats) {
+ SDE_ERROR("[%u]no valid formats for plane\n", pipe);
+ if (pp->scaler3_cfg)
+ kzfree(pp->scaler3_cfg);
+
+ rc = -EINVAL;
+ goto end;
+ }
+
+ pp->sde_plane = psde;
+ pp->pipe = pipe;
+ pp->index = index;
+
+end:
+ return rc;
}
/* initialize plane */
struct drm_plane *sde_plane_init(struct drm_device *dev,
uint32_t pipe, bool primary_plane,
- unsigned long possible_crtcs)
+ unsigned long possible_crtcs, bool vp_enabled)
{
struct drm_plane *plane = NULL;
struct sde_plane *psde;
+ struct sde_phy_plane *pp, *n;
struct msm_drm_private *priv;
struct sde_kms *kms;
enum drm_plane_type type;
int ret = -EINVAL;
+ struct sde_vp_cfg *vp;
+ struct sde_vp_sub_blks *vp_sub;
+ uint32_t features = 0xFFFFFFFF, nformats = 64, formats[64];
+ uint32_t index = 0;
if (!dev) {
SDE_ERROR("[%u]device is NULL\n", pipe);
@@ -2383,60 +2619,77 @@ struct drm_plane *sde_plane_init(struct drm_device *dev,
/* cache local stuff for later */
plane = &psde->base;
- psde->pipe = pipe;
psde->aspace = kms->aspace[MSM_SMMU_DOMAIN_UNSECURE];
- /* initialize underlying h/w driver */
- psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
- if (IS_ERR(psde->pipe_hw)) {
- SDE_ERROR("[%u]SSPP init failed\n", pipe);
- ret = PTR_ERR(psde->pipe_hw);
- goto clean_plane;
- } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
- SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
- goto clean_sspp;
- }
+ INIT_LIST_HEAD(&psde->phy_plane_head);
- /* cache features mask for later */
- psde->features = psde->pipe_hw->cap->features;
- psde->pipe_sblk = psde->pipe_hw->cap->sblk;
- if (!psde->pipe_sblk) {
- SDE_ERROR("[%u]invalid sblk\n", pipe);
- goto clean_sspp;
- }
+ /* initialize underlying h/w driver */
+ if (vp_enabled) {
+ vp = &(kms->catalog->vp[pipe]);
+ list_for_each_entry(vp_sub, &vp->sub_blks, pipeid_list) {
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp) {
+ SDE_ERROR("out of memory\n");
+ ret = -ENOMEM;
+ goto clean_plane;
+ }
- if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
- psde->scaler3_cfg = kzalloc(sizeof(struct sde_hw_scaler3_cfg),
- GFP_KERNEL);
- if (!psde->scaler3_cfg) {
- SDE_ERROR("[%u]failed to allocate scale struct\n",
- pipe);
+ ret = _sde_init_phy_plane(kms, psde, vp_sub->sspp_id,
+ index, pp);
+ if (ret) {
+ SDE_ERROR("_sde_init_phy_plane error vp=%d\n",
+ pipe);
+ kfree(pp);
+ ret = -EINVAL;
+ goto clean_plane;
+ }
+ /* Get common features for all pipes */
+ features &= pp->features;
+ if (nformats > pp->nformats) {
+ nformats = pp->nformats;
+ memcpy(formats, pp->formats,
+ sizeof(formats));
+ }
+ list_add_tail(&pp->phy_plane_list,
+ &psde->phy_plane_head);
+ index++;
+ psde->num_of_phy_planes++;
+ }
+ } else {
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp) {
+ SDE_ERROR("out of memory\n");
ret = -ENOMEM;
- goto clean_sspp;
+ goto clean_plane;
}
- }
-
- /* add plane to DRM framework */
- psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
- psde->formats,
- 0,
- ARRAY_SIZE(psde->formats));
- if (!psde->nformats) {
- SDE_ERROR("[%u]no valid formats for plane\n", pipe);
- goto clean_sspp;
+ ret = _sde_init_phy_plane(kms, psde, pipe, index, pp);
+ if (ret) {
+ SDE_ERROR("_sde_init_phy_plane error id=%d\n",
+ pipe);
+ kfree(pp);
+ ret = -EINVAL;
+ goto clean_plane;
+ }
+ features = pp->features;
+ nformats = pp->nformats;
+ memcpy(formats, pp->formats,
+ sizeof(uint32_t) * 64);
+ list_add_tail(&pp->phy_plane_list,
+ &psde->phy_plane_head);
+ psde->num_of_phy_planes++;
}
- if (psde->features & BIT(SDE_SSPP_CURSOR))
+ if (features & BIT(SDE_SSPP_CURSOR))
type = DRM_PLANE_TYPE_CURSOR;
else if (primary_plane)
type = DRM_PLANE_TYPE_PRIMARY;
else
type = DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(dev, plane, possible_crtcs,
- &sde_plane_funcs, psde->formats, psde->nformats, type);
+ &sde_plane_funcs, formats, nformats, type);
if (ret)
- goto clean_sspp;
+ goto clean_plane;
/* success! finalize initialization */
drm_plane_helper_add(plane, &sde_plane_helper_funcs);
@@ -2458,14 +2711,20 @@ struct drm_plane *sde_plane_init(struct drm_device *dev,
DRM_INFO("%s created for pipe %u\n", psde->pipe_name, pipe);
return plane;
-clean_sspp:
- if (psde && psde->pipe_hw)
- sde_hw_sspp_destroy(psde->pipe_hw);
-
- if (psde && psde->scaler3_cfg)
- kfree(psde->scaler3_cfg);
clean_plane:
- kfree(psde);
+ if (psde) {
+ list_for_each_entry_safe(pp, n,
+ &psde->phy_plane_head, phy_plane_list) {
+ if (pp->pipe_hw)
+ sde_hw_sspp_destroy(pp->pipe_hw);
+
+ kfree(pp->scaler3_cfg);
+ list_del(&pp->phy_plane_list);
+ kfree(pp);
+ }
+ kfree(psde);
+ }
+
exit:
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index 1514f633c61e..7b91822d4cde 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -59,9 +59,10 @@ struct sde_plane_state {
/**
* sde_plane_pipe - return sspp identifier for the given plane
* @plane: Pointer to DRM plane object
+ * @index: Plane index
* Returns: sspp identifier of the given plane
*/
-enum sde_sspp sde_plane_pipe(struct drm_plane *plane);
+enum sde_sspp sde_plane_pipe(struct drm_plane *plane, uint32_t index);
/**
* sde_plane_flush - final plane operations before commit flush
@@ -75,10 +76,11 @@ void sde_plane_flush(struct drm_plane *plane);
* @pipe: sde hardware pipe identifier
* @primary_plane: true if this pipe is primary plane for crtc
* @possible_crtcs: bitmask of crtc that can be attached to the given pipe
+ * @vp_enabled: Flag indicating if virtual planes enabled
*/
struct drm_plane *sde_plane_init(struct drm_device *dev,
uint32_t pipe, bool primary_plane,
- unsigned long possible_crtcs);
+ unsigned long possible_crtcs, bool vp_enabled);
/**
* sde_plane_wait_input_fence - wait for input fence object
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index fca0768e2734..fe4b73b4ffea 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -23,6 +23,7 @@
#include "sde_hw_wb.h"
#include "sde_encoder.h"
#include "sde_connector.h"
+#include "sde_hw_sspp.h"
#define RESERVED_BY_OTHER(h, r) \
((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id))
@@ -197,6 +198,33 @@ bool sde_rm_get_hw(struct sde_rm *rm, struct sde_rm_hw_iter *i)
return false;
}
+void *sde_rm_get_hw_by_id(struct sde_rm *rm, enum sde_hw_blk_type type, int id)
+{
+ struct list_head *blk_list;
+ struct sde_rm_hw_blk *blk;
+ void *hw = NULL;
+
+ if (!rm || type >= SDE_HW_BLK_MAX) {
+ SDE_ERROR("invalid rm\n");
+ return hw;
+ }
+
+ blk_list = &rm->hw_blks[type];
+
+ list_for_each_entry(blk, blk_list, list) {
+ if (blk->id == id) {
+ hw = blk->hw;
+ SDE_DEBUG("found type %d %s id %d\n",
+ type, blk->type_name, blk->id);
+ return hw;
+ }
+ }
+
+ SDE_DEBUG("no match, type %d id=%d\n", type, id);
+
+ return hw;
+}
+
static void _sde_rm_hw_destroy(enum sde_hw_blk_type type, void *hw)
{
switch (type) {
@@ -222,7 +250,8 @@ static void _sde_rm_hw_destroy(enum sde_hw_blk_type type, void *hw)
sde_hw_wb_destroy(hw);
break;
case SDE_HW_BLK_SSPP:
- /* SSPPs are not managed by the resource manager */
+ sde_hw_sspp_destroy(hw);
+ break;
case SDE_HW_BLK_TOP:
/* Top is a singleton, not managed in hw_blks list */
case SDE_HW_BLK_MAX:
@@ -310,7 +339,9 @@ static int _sde_rm_hw_blk_create(
name = "wb";
break;
case SDE_HW_BLK_SSPP:
- /* SSPPs are not managed by the resource manager */
+ hw = sde_hw_sspp_init(id, (void __iomem *)mmio, cat);
+ name = "sspp";
+ break;
case SDE_HW_BLK_TOP:
/* Top is a singleton, not managed in hw_blks list */
case SDE_HW_BLK_MAX:
@@ -369,6 +400,13 @@ int sde_rm_init(struct sde_rm *rm,
goto fail;
}
+ for (i = 0; i < cat->sspp_count; i++) {
+ rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_SSPP,
+ cat->sspp[i].id, &cat->sspp[i]);
+ if (rc)
+ goto fail;
+ }
+
/* Interrogate HW catalog and create tracking items for hw blocks */
for (i = 0; i < cat->mixer_count; i++) {
struct sde_lm_cfg *lm = &cat->mixer[i];
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.h b/drivers/gpu/drm/msm/sde/sde_rm.h
index 855b12ce8150..1cc22c5fbbf4 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.h
+++ b/drivers/gpu/drm/msm/sde/sde_rm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-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
@@ -185,6 +185,18 @@ void sde_rm_init_hw_iter(
bool sde_rm_get_hw(struct sde_rm *rm, struct sde_rm_hw_iter *iter);
/**
+ * sde_rm_get_hw_by_id - retrieve hw object given hw type and hw id
+ * Meant to do a single pass through the hardware list to iteratively
+ * retrieve hardware blocks of a given type and id.
+ * Function returns the hw resource pointer.
+ * @rm: SDE Resource Manager handle
+ * @type: hw type
+ * @id: hw id
+ * @Return: hw resource pointer on match found, NULL on no match found
+ */
+void *sde_rm_get_hw_by_id(struct sde_rm *rm, enum sde_hw_blk_type type, int id);
+
+/**
* sde_rm_check_property_topctl - validate property bitmask before it is set
* @val: user's proposed topology control bitmask
* @Return: 0 on success or error