diff options
| -rw-r--r-- | Documentation/devicetree/bindings/drm/msm/hdmi-display.txt | 3 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/drm/msm/mdp.txt | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 20 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_display.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_drm.c | 23 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_drm.h | 12 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c | 44 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h | 19 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_connector.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_connector.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_encoder.c | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_kms.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_rm.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/sde/sde_rm.h | 2 |
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, }; /** |
