summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/drm/msm/hdmi-display.txt3
-rw-r--r--Documentation/devicetree/bindings/drm/msm/mdp.txt2
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_display.c20
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_display.h2
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_drm.c23
-rw-r--r--drivers/gpu/drm/msm/dsi-staging/dsi_drm.h12
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c44
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h19
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.c3
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.h10
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c16
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c6
-rw-r--r--drivers/gpu/drm/msm/sde/sde_rm.c10
-rw-r--r--drivers/gpu/drm/msm/sde/sde_rm.h2
14 files changed, 167 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt b/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt
index 762103277593..597469611f11 100644
--- a/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt
+++ b/Documentation/devicetree/bindings/drm/msm/hdmi-display.txt
@@ -7,6 +7,8 @@ Required properties:
Optional properties:
- qcom,display-type: display type of this manager. It could be "primary",
"secondary", "tertiary", etc.
+- qcom,display-topology-control: display topology control. It could be
+ "force-mixer", "force-tiling"
- qcom,non-pluggable: Boolean to indicate if display is non pluggable.
- qcom,skip_ddc: Boolean to indicate if display skips ddc function.
- qcom,customize-modes: Customized modes when it's non pluggable display.
@@ -37,6 +39,7 @@ Example:
compatible = "qcom,hdmi-display";
label = "hdmi_display";
qcom,display-type = "secondary";
+ qcom,display-topology-control = "force-mixer";
qcom,non-pluggable;
qcom,customize-modes {
qcom,customize-mode-id@0 {
diff --git a/Documentation/devicetree/bindings/drm/msm/mdp.txt b/Documentation/devicetree/bindings/drm/msm/mdp.txt
index a76b604445bd..b8920a4e8d88 100644
--- a/Documentation/devicetree/bindings/drm/msm/mdp.txt
+++ b/Documentation/devicetree/bindings/drm/msm/mdp.txt
@@ -9,6 +9,8 @@ Optional properties:
- reg: reg property.
- qcom,display-type: display type this plane is mapped to. It could be
"primary", "secondary" and "tertiary".
+- qcom,display-topology-control: display topology control. It could be
+ "force-mixer", "force-tiling"
- qcom,plane-name: plane name array for this virtual plane. It could be
"rgb0", "rgb1", "rgb2", "rgb3", "vig0", "vig1", "vig2", "vig3", "dma0", "dma1",
"dma2", "dma3", "cursor0", "cursor1".
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 175603b85d49..742760cc791c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -1142,6 +1142,8 @@ static int dsi_display_parse_dt(struct dsi_display *display)
int i, size;
u32 phy_count = 0;
struct device_node *of_node;
+ const char *name;
+ u32 top = 0;
/* Parse controllers */
for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) {
@@ -1189,6 +1191,24 @@ static int dsi_display_parse_dt(struct dsi_display *display)
"qcom,dsi-split-swap");
}
+ rc = of_property_read_string(display->pdev->dev.of_node,
+ "qcom,display-topology-control",
+ &name);
+ if (rc) {
+ SDE_ERROR("unable to get qcom,display-topology-control,rc=%d\n",
+ rc);
+ } else {
+ SDE_DEBUG("%s qcom,display-topology-control = %s\n",
+ __func__, name);
+
+ if (!strcmp(name, "force-mixer"))
+ top = BIT(SDE_RM_TOPCTL_FORCE_MIXER);
+ else if (!strcmp(name, "force-tiling"))
+ top = BIT(SDE_RM_TOPCTL_FORCE_TILING);
+
+ display->display_topology = top;
+ }
+
if (of_get_property(display->pdev->dev.of_node, "qcom,dsi-panel",
&size)) {
display->panel_count = size / sizeof(int);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 25b2d0c1ec53..d285779e07c3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -123,6 +123,7 @@ struct dsi_display_clk_info {
* @root: Debugfs root directory
* @cont_splash_enabled: Early splash status.
* @dsi_split_swap: Swap dsi output in split mode.
+ * @display_topology: user requested display topology
*/
struct dsi_display {
struct platform_device *pdev;
@@ -163,6 +164,7 @@ struct dsi_display {
bool cont_splash_enabled;
bool dsi_split_swap;
+ u32 display_topology;
};
int dsi_display_dev_probe(struct platform_device *pdev);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index 35000d7eb12a..ad9e553785b6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -288,6 +288,29 @@ static const struct drm_bridge_funcs dsi_bridge_ops = {
.mode_set = dsi_bridge_mode_set,
};
+int dsi_display_set_top_ctl(struct drm_connector *connector,
+ struct drm_display_mode *adj_mode, void *display)
+{
+ int rc = 0;
+ struct dsi_display *dsi_display = (struct dsi_display *)display;
+
+ if (!dsi_display) {
+ SDE_ERROR("dsi_display is NULL\n");
+ return -EINVAL;
+ }
+
+ if (dsi_display->display_topology) {
+ SDE_DEBUG("%s, set display topology %d\n",
+ __func__, dsi_display->display_topology);
+
+ msm_property_set_property(sde_connector_get_propinfo(connector),
+ sde_connector_get_property_values(connector->state),
+ CONNECTOR_PROP_TOPOLOGY_CONTROL,
+ dsi_display->display_topology);
+ }
+ return rc;
+}
+
int dsi_conn_post_init(struct drm_connector *connector,
void *info,
void *display)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index 934899bd2068..89ad0da21946 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -33,6 +33,16 @@ struct dsi_bridge {
};
/**
+ * dsi_display_set_top_ctl - callback to set display topology property
+ * @connector: Pointer to drm connector structure
+ * @adj_mode: adjusted mode
+ * @display: Pointer to private display handle
+ * Returns: Zero on success
+ */
+int dsi_display_set_top_ctl(struct drm_connector *connector,
+ struct drm_display_mode *adj_mode, void *display);
+
+/**
* dsi_conn_post_init - callback to perform additional initialization steps
* @connector: Pointer to drm connector structure
* @info: Pointer to sde connector info structure
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index ca60c869d613..ac9c81c5eda1 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -2520,6 +2520,30 @@ end:
return rc;
}
+int sde_hdmi_set_top_ctl(struct drm_connector *connector,
+ struct drm_display_mode *adj_mode, void *display)
+{
+ int rc = 0;
+ struct sde_hdmi *sde_hdmi = (struct sde_hdmi *)display;
+
+ if (!sde_hdmi) {
+ SDE_ERROR("sde_hdmi is NULL\n");
+ return -EINVAL;
+ }
+
+ if (sde_hdmi->display_topology) {
+ SDE_DEBUG("%s, set display topology %d\n",
+ __func__, sde_hdmi->display_topology);
+
+ msm_property_set_property(sde_connector_get_propinfo(connector),
+ sde_connector_get_property_values(connector->state),
+ CONNECTOR_PROP_TOPOLOGY_CONTROL,
+ sde_hdmi->display_topology);
+ }
+
+ return rc;
+}
+
int sde_hdmi_connector_post_init(struct drm_connector *connector,
void *info,
void *display)
@@ -3120,6 +3144,9 @@ static int _sde_hdmi_parse_dt(struct device_node *node,
{
int rc = 0;
+ const char *name;
+ u32 top = 0;
+
display->name = of_get_property(node, "label", NULL);
display->display_type = of_get_property(node,
@@ -3130,6 +3157,23 @@ static int _sde_hdmi_parse_dt(struct device_node *node,
display->non_pluggable = of_property_read_bool(node,
"qcom,non-pluggable");
+ rc = of_property_read_string(node, "qcom,display-topology-control",
+ &name);
+ if (rc) {
+ SDE_ERROR("unable to get qcom,display-topology-control,rc=%d\n",
+ rc);
+ } else {
+ SDE_DEBUG("%s qcom,display-topology-control = %s\n",
+ __func__, name);
+
+ if (!strcmp(name, "force-mixer"))
+ top = BIT(SDE_RM_TOPCTL_FORCE_MIXER);
+ else if (!strcmp(name, "force-tiling"))
+ top = BIT(SDE_RM_TOPCTL_FORCE_TILING);
+
+ display->display_topology = top;
+ }
+
display->skip_ddc = of_property_read_bool(node,
"qcom,skip_ddc");
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 9a15f40bb32c..082b3328a40d 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -103,6 +103,7 @@ enum hdmi_tx_feature_type {
* @display_lock: Mutex for sde_hdmi interface.
* @ctrl: Controller information for HDMI display.
* @non_pluggable: If HDMI display is non pluggable
+ * @display_topology: user requested display topology
* @num_of_modes: Number of modes supported by display if non pluggable.
* @mode_list: Mode list if non pluggable.
* @mode: Current display mode.
@@ -154,6 +155,7 @@ struct sde_hdmi {
struct sde_edid_ctrl *edid_ctrl;
bool non_pluggable;
+ u32 display_topology;
bool skip_ddc;
u32 num_of_modes;
struct list_head mode_list;
@@ -280,6 +282,17 @@ int sde_hdmi_connector_pre_deinit(struct drm_connector *connector,
void *display);
/**
+ * sde_hdmi_set_top_ctl()- set display topology control property
+ * @connector: Pointer to drm connector structure
+ * @adj_mode: adjusted mode
+ * @display: Pointer to private display handle
+ *
+ * Return: error code
+ */
+int sde_hdmi_set_top_ctl(struct drm_connector *connector,
+ struct drm_display_mode *adj_mode, void *display);
+
+/**
* sde_hdmi_connector_post_init()- perform additional initialization steps
* @connector: Pointer to drm connector structure
* @info: Pointer to sde connector info structure
@@ -570,6 +583,12 @@ static inline int sde_hdmi_connector_pre_deinit(struct drm_connector *connector,
return 0;
}
+static inline int sde_hdmi_set_top_ctl(struct drm_connector *connector,
+ struct drm_display_mode *adj_mode, void *display)
+{
+ return 0;
+}
+
static inline int sde_hdmi_connector_post_init(struct drm_connector *connector,
void *info,
void *display)
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 5f6b93931c35..a067086a3143 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -40,7 +40,8 @@ static const struct drm_prop_enum_list e_topology_control[] = {
{SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"},
{SDE_RM_TOPCTL_DSPP, "dspp"},
{SDE_RM_TOPCTL_FORCE_TILING, "force_tiling"},
- {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"}
+ {SDE_RM_TOPCTL_PPSPLIT, "ppsplit"},
+ {SDE_RM_TOPCTL_FORCE_MIXER, "force_mixer"}
};
static const struct drm_prop_enum_list e_power_mode[] = {
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 6433d3f3bca4..3bf5a6fe3ce3 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -124,6 +124,16 @@ struct sde_connector_ops {
*/
int (*get_info)(struct msm_display_info *info, void *display);
+ /**
+ * set_topology_ctl - set sde display topology property
+ * @connector: Pointer to drm connector structure
+ * @adj_mode: adjusted mode
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+ int (*set_topology_ctl)(struct drm_connector *connector,
+ struct drm_display_mode *adj_mode, void *display);
+
int (*set_backlight)(void *display, u32 bl_lvl);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index dde742014125..4f3fd02da5a4 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -326,6 +326,7 @@ static int sde_encoder_virt_atomic_check(
struct sde_kms *sde_kms;
const struct drm_display_mode *mode;
struct drm_display_mode *adj_mode;
+ struct sde_connector *sde_conn = NULL;
int i = 0;
int ret = 0;
@@ -362,6 +363,13 @@ static int sde_encoder_virt_atomic_check(
}
}
+ sde_conn = to_sde_connector(conn_state->connector);
+ if (sde_conn) {
+ if (sde_conn->ops.set_topology_ctl)
+ sde_conn->ops.set_topology_ctl(conn_state->connector,
+ adj_mode, sde_conn->display);
+ }
+
/* Reserve dynamic resources now. Indicating AtomicTest phase */
if (!ret)
ret = sde_rm_reserve(&sde_kms->rm, drm_enc, crtc_state,
@@ -384,6 +392,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
struct sde_kms *sde_kms;
struct list_head *connector_list;
struct drm_connector *conn = NULL, *conn_iter;
+ struct sde_connector *sde_conn = NULL;
struct sde_rm_hw_iter pp_iter;
int i = 0, ret;
@@ -413,6 +422,13 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
return;
}
+ sde_conn = to_sde_connector(conn);
+ if (sde_conn) {
+ if (sde_conn->ops.set_topology_ctl)
+ sde_conn->ops.set_topology_ctl(conn,
+ adj_mode, sde_conn->display);
+ }
+
/* Reserve dynamic resources now. Indicating non-AtomicTest phase */
ret = sde_rm_reserve(&sde_kms->rm, drm_enc, drm_enc->crtc->state,
conn->state, false);
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index a53b345071a6..c0481ae3311c 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -593,7 +593,8 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.get_modes = dsi_connector_get_modes,
.mode_valid = dsi_conn_mode_valid,
.get_info = dsi_display_get_info,
- .set_backlight = dsi_display_set_backlight
+ .set_backlight = dsi_display_set_backlight,
+ .set_topology_ctl = dsi_display_set_top_ctl,
};
static const struct sde_connector_ops wb_ops = {
.post_init = sde_wb_connector_post_init,
@@ -613,7 +614,8 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.get_property = sde_hdmi_get_property,
.pre_kickoff = sde_hdmi_pre_kickoff,
.mode_needs_full_range = sde_hdmi_mode_needs_full_range,
- .get_csc_type = sde_hdmi_get_csc_type
+ .get_csc_type = sde_hdmi_get_csc_type,
+ .set_topology_ctl = sde_hdmi_set_top_ctl,
};
struct msm_display_info info = {0};
struct drm_encoder *encoder;
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index 384b6f50979c..07700c64dac3 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -36,6 +36,7 @@
#define RM_RQ_DSPP(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_DSPP))
#define RM_RQ_PPSPLIT(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_PPSPLIT))
#define RM_RQ_FORCE_TILING(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_FORCE_TILING))
+#define RM_RQ_FORCE_MIXER(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_FORCE_MIXER))
/**
* struct sde_rm_requirements - Reservation requirements parameter bundle
@@ -1192,6 +1193,8 @@ static int _sde_rm_populate_requirements(
reqs->top_ctrl = sde_connector_get_property(conn_state,
CONNECTOR_PROP_TOPOLOGY_CONTROL);
+ SDE_DEBUG("%s reqs->top_ctrl = %llu\n", __func__, reqs->top_ctrl);
+
sde_encoder_get_hw_resources(enc, &reqs->hw_res, conn_state);
/* Base assumption is LMs = h_tiles, conditions below may override */
@@ -1212,7 +1215,12 @@ static int _sde_rm_populate_requirements(
}
} else if (reqs->num_lm == 1) {
- if (mode->hdisplay > rm->lm_max_width) {
+ if (RM_RQ_FORCE_MIXER(reqs)) {
+ /* user request serving wide display with 1 lm */
+ reqs->top_name = SDE_RM_TOPOLOGY_SINGLEPIPE;
+ reqs->num_ctl = 1;
+ reqs->needs_split_display = false;
+ } else if (mode->hdisplay > rm->lm_max_width) {
/* wide display, must split across 2 lm and merge */
reqs->top_name = SDE_RM_TOPOLOGY_DUALPIPEMERGE;
reqs->num_lm = 2;
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.h b/drivers/gpu/drm/msm/sde/sde_rm.h
index bec398a3b996..4116fb78b28c 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.h
+++ b/drivers/gpu/drm/msm/sde/sde_rm.h
@@ -52,6 +52,7 @@ enum sde_rm_topology_name {
* of a single layer mixer.
* @SDE_RM_TOPCTL_PPSPLIT: Require kernel to use pingpong split pipe
* configuration instead of dual pipe.
+ * @SDE_RM_TOPCTL_FORCE_MIXER: Require kernel to force single mixer usage
*/
enum sde_rm_topology_control {
SDE_RM_TOPCTL_RESERVE_LOCK,
@@ -59,6 +60,7 @@ enum sde_rm_topology_control {
SDE_RM_TOPCTL_DSPP,
SDE_RM_TOPCTL_FORCE_TILING,
SDE_RM_TOPCTL_PPSPLIT,
+ SDE_RM_TOPCTL_FORCE_MIXER,
};
/**