From 30b933f50c9c234fc59d83d5253fab24a74e7cbd Mon Sep 17 00:00:00 2001 From: Nilesh Laad Date: Fri, 28 Apr 2023 15:27:44 +0530 Subject: [PATCH 1/5] disp: msm: dp: add eDP panel notifier support If panel notifier support is set, get panel phandle and add panel to drm_panel. Notifier for this panel will be called on dpms update. Change-Id: I6346eb09a551a993ec9050797d1ba9383491e612 Signed-off-by: Nilesh Laad --- msm/dp/dp_display.c | 2 ++ msm/dp/dp_panel.c | 27 +++++++++++++++++++++++++++ msm/dp/dp_panel.h | 4 ++++ msm/dp/dp_parser.c | 4 ++++ msm/dp/dp_parser.h | 1 + 5 files changed, 38 insertions(+) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index afa73fa3e013..89301247b79d 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -2095,6 +2095,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp) panel_in.connector = dp->dp_display.base_connector; panel_in.base_panel = NULL; panel_in.parser = dp->parser; + panel_in.is_edp = dp->dp_display.is_edp; + panel_in.panel_notifier_support = dp->parser->panel_notifier_support; dp->panel = dp_panel_get(&panel_in); if (IS_ERR(dp->panel)) { diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 5369ab30bdb4..6c24c52b0004 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ @@ -3015,6 +3016,8 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) struct dp_panel_private *panel; struct dp_panel *dp_panel; struct sde_connector *sde_conn; + struct device *dev; + struct device_node *of_node = NULL; if (!in->dev || !in->catalog || !in->aux || !in->link || !in->connector) { @@ -3029,6 +3032,13 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) goto error; } + dev = devm_kzalloc(in->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) { + DP_ERR("failed to allocate dev\n"); + rc = -ENOMEM; + goto error; + } + panel->dev = in->dev; panel->aux = in->aux; panel->catalog = in->catalog; @@ -3088,6 +3098,23 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) dp_panel_edid_register(panel); + if (in->is_edp && in->panel_notifier_support) { + of_node = of_parse_phandle(in->dev->of_node, "qcom,edp-default-panel", 0); + if (!of_node) { + DP_ERR("phandle for default panel not found\n"); + } else { + drm_panel_init(&dp_panel->drm_panel); + dp_panel->drm_panel.dev = dev; + dev->of_node = of_node; + + rc = drm_panel_add(&dp_panel->drm_panel); + if (rc) + DP_ERR("Failed to add drm_panel\n"); + + dp_panel->connector->panel = &dp_panel->drm_panel; + } + } + return dp_panel; error: return ERR_PTR(rc); diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h index f388f2d94063..822393143ab8 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ @@ -74,6 +75,8 @@ struct dp_panel_in { struct drm_connector *connector; struct dp_panel *base_panel; struct dp_parser *parser; + bool is_edp; + bool panel_notifier_support; }; struct dp_dsc_caps { @@ -95,6 +98,7 @@ struct dp_panel { u8 fec_dpcd; u8 fec_sts_dpcd[DP_RECEIVER_FEC_STATUS_SIZE + 1]; + struct drm_panel drm_panel; struct drm_dp_link link_info; struct sde_edid_ctrl *edid_ctrl; struct dp_panel_info pinfo; diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index 1a18d69ed070..7f5501a136bf 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -177,6 +177,10 @@ static int dp_parser_misc(struct dp_parser *parser) if (!parser->display_type) parser->display_type = "unknown"; + parser->panel_notifier_support = of_property_read_bool(of_node, + "qcom,panel-notifier-support"); + DP_DEBUG("panel-notifier-support = %d\n", parser->panel_notifier_support); + return 0; } diff --git a/msm/dp/dp_parser.h b/msm/dp/dp_parser.h index 4404930d255a..5c6c0bf0410b 100644 --- a/msm/dp/dp_parser.h +++ b/msm/dp/dp_parser.h @@ -264,6 +264,7 @@ struct dp_parser { bool has_widebus; bool gpio_aux_switch; bool lphw_hpd; + bool panel_notifier_support; u32 mst_fixed_port[MAX_DP_MST_STREAMS]; u32 pixel_base_off[MAX_DP_MST_STREAMS]; const char *mst_fixed_display_type[MAX_DP_MST_STREAMS]; From 228e520fb4e7a8ee321edad60c39f6d261938144 Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Tue, 13 Jun 2023 12:42:28 +0530 Subject: [PATCH 2/5] disp: msm: dp: add backlight for edp Register backlight and cooling devices for eDP interface and reuse connector backlight update functions. Parse and use backlight properties from devicetree. Change-Id: I5d96a8d588d8f7266aa5bffad310718942e7dfe6 Signed-off-by: Venkata Prahlad Valluru --- msm/dp/dp_display.c | 44 +++++++++++++ msm/dp/dp_display.h | 2 + msm/dp/dp_drm.c | 21 ++++++ msm/dp/dp_drm.h | 9 +++ msm/dp/dp_panel.c | 105 ++++++++++++++++++++++++++++++ msm/dp/dp_panel.h | 21 ++++++ msm/dp/dp_parser.c | 42 ++++++++++++ msm/dp/dp_parser.h | 10 ++- msm/sde/sde_connector.c | 140 +++++++++++++++++++++++++++------------- msm/sde/sde_kms.c | 1 + 10 files changed, 350 insertions(+), 45 deletions(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 11349989c449..f99fd658ec26 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -2581,6 +2581,9 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) { struct dp_display_private *dp; struct dp_panel *dp_panel; + struct drm_connector *connector; + struct sde_connector *sde_conn; + struct backlight_device *bl_device; int rc = 0; if (!dp_display || !panel) { @@ -2626,6 +2629,15 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) DP_ERR("Cannot turn edp backlight power on"); goto end; } + connector = dp_display->base_connector; + sde_conn = to_sde_connector(connector); + + sde_conn->allow_bl_update = true; + if (sde_conn->bl_device) { + bl_device = sde_conn->bl_device; + bl_device->props.power = FB_BLANK_UNBLANK; + bl_device->props.state &= ~BL_CORE_FBBLANK; + } } cancel_delayed_work_sync(&dp->hdcp_cb_work); @@ -3283,6 +3295,37 @@ static int dp_display_config_hdr(struct dp_display *dp_display, void *panel, core_clk_rate, flush_hdr); } +static int dp_display_set_backlight(struct dp_display *dp_display, + void *panel, u32 bl_lvl) +{ + struct dp_panel *dp_panel; + struct dp_display_private *dp; + u32 bl_scale, bl_scale_sv; + u64 bl_temp; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + dp_panel = panel; + + dp_panel->bl_config.bl_level = bl_lvl; + + /* scale backlight */ + bl_scale = dp_panel->bl_config.bl_scale; + bl_temp = bl_lvl * bl_scale / MAX_BL_SCALE_LEVEL; + + bl_scale_sv = dp_panel->bl_config.bl_scale_sv; + bl_temp = (u32)bl_temp * bl_scale_sv / MAX_SV_BL_SCALE_LEVEL; + + DP_DEBUG("bl_scale = %u, bl_scale_sv = %u, bl_lvl = %u\n", + bl_scale, bl_scale_sv, (u32)bl_temp); + + return dp_panel->set_backlight(dp_panel, (u32)bl_temp); +} + static int dp_display_setup_colospace(struct dp_display *dp_display, void *panel, u32 colorspace) @@ -3944,6 +3987,7 @@ static int dp_display_probe(struct platform_device *pdev) dp_display->wakeup_phy_layer = dp_display_wakeup_phy_layer; dp_display->set_colorspace = dp_display_setup_colospace; + dp_display->set_backlight = dp_display_set_backlight; dp_display->get_available_dp_resources = dp_display_get_available_dp_resources; dp_display->get_display_type = dp_display_get_display_type; diff --git a/msm/dp/dp_display.h b/msm/dp/dp_display.h index 892322fa2fc2..a49ef045d702 100644 --- a/msm/dp/dp_display.h +++ b/msm/dp/dp_display.h @@ -110,6 +110,8 @@ struct dp_display { bool dhdr_update); int (*set_colorspace)(struct dp_display *dp_display, void *panel, u32 colorspace); + int (*set_backlight)(struct dp_display *dp_display, void *panel, + u32 bl_lvl); int (*post_init)(struct dp_display *dp_display); int (*mst_install)(struct dp_display *dp_display, struct dp_mst_drm_install_info *mst_install_info); diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index 6e054af5dc3d..d936aecd7c8c 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -326,6 +326,27 @@ int dp_connector_config_hdr(struct drm_connector *connector, void *display, c_state->dyn_hdr_meta.dynamic_hdr_update); } +int dp_connector_set_backlight(struct drm_connector *connector, + void *display, u32 bl_lvl) +{ + struct dp_display *dp_display = display; + struct sde_connector *sde_conn; + + if (!dp_display || !connector) { + DP_ERR("invalid dp display\n"); + return -EINVAL; + } + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid dp panel\n"); + return -EINVAL; + } + + return dp_display->set_backlight(dp_display, + sde_conn->drv_panel, bl_lvl); +} + int dp_connector_set_colorspace(struct drm_connector *connector, void *display) { diff --git a/msm/dp/dp_drm.h b/msm/dp/dp_drm.h index 647705c2706d..a99ab9c86f9d 100644 --- a/msm/dp/dp_drm.h +++ b/msm/dp/dp_drm.h @@ -49,6 +49,15 @@ int dp_connector_atomic_check(struct drm_connector *connector, void *display, struct drm_atomic_state *state); +/** + * dp_connector_set_backlight - callback to set backlight + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success + */ +int dp_connector_set_backlight(struct drm_connector *connector, + void *display, u32 bl_lvl); + /** * dp_connector_set_colorspace - callback to set new colorspace * @connector: Pointer to drm connector structure diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 6c24c52b0004..8fc1b13c3e32 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -6,6 +6,7 @@ #include "dp_panel.h" #include +#include #include #include "dp_debug.h" #include @@ -2295,6 +2296,91 @@ static int dp_panel_set_stream_info(struct dp_panel *dp_panel, return 0; } +static int dp_panel_pwm_register(struct dp_panel *dp_panel) +{ + int rc = 0; + struct dp_backlight_config *bl = &dp_panel->bl_config; + struct platform_device *pdev; + struct device *dev; + struct dp_panel_private *panel; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + pdev = panel->parser->pdev; + dev = &pdev->dev; + + bl->pwm_bl = devm_of_pwm_get(dev, dev->of_node, NULL); + if (IS_ERR_OR_NULL(bl->pwm_bl)) { + rc = PTR_ERR(bl->pwm_bl); + DP_ERR("failed to request pwm, rc=%d\n", rc); + return rc; + } + + return 0; +} + +static void dp_panel_pwm_unregister(struct dp_panel *dp_panel) +{ + struct dp_backlight_config *bl = &dp_panel->bl_config; + struct platform_device *pdev; + struct dp_panel_private *panel; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + pdev = panel->parser->pdev; + + if (bl->pwm_bl) + devm_pwm_put(&pdev->dev, bl->pwm_bl); +} + +static int dp_panel_set_backlight(struct dp_panel *panel, u32 bl_lvl) +{ + int rc = 0; + u32 duty = 0; + u32 period_ns = 0; + struct dp_backlight_config *bl; + + if (!panel) { + DP_ERR("Invalid Params\n"); + return -EINVAL; + } + + bl = &panel->bl_config; + if (!bl->pwm_bl) { + DP_ERR("pwm device not found\n"); + return -EINVAL; + } + + DP_DEBUG("backlight lvl:%d\n", bl_lvl); + + period_ns = bl->pwm_period_usecs * NSEC_PER_USEC; + duty = bl_lvl * period_ns; + duty /= bl->bl_max_level; + + rc = pwm_config(bl->pwm_bl, duty, period_ns); + if (rc) { + DP_ERR("failed to change pwm config, rc=\n", rc); + goto error; + } + + if (bl_lvl == 0 && bl->pwm_enabled) { + pwm_disable(bl->pwm_bl); + bl->pwm_enabled = false; + return 0; + } + + if (bl_lvl != 0 && !bl->pwm_enabled) { + rc = pwm_enable(bl->pwm_bl); + if (rc) { + DP_ERR("failed to enable pwm, rc=\n", rc); + goto error; + } + + bl->pwm_enabled = true; + } + +error: + return rc; +} + static int dp_panel_init_panel_info(struct dp_panel *dp_panel) { int rc = 0; @@ -3058,6 +3144,15 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) dp_panel->fec_feature_enable = panel->parser->fec_feature_enable; dp_panel->dsc_continuous_pps = panel->parser->dsc_continuous_pps; + /* backlight config for edp */ + dp_panel->bl_config.bl_min_level = panel->parser->bl_min_level; + dp_panel->bl_config.bl_max_level = panel->parser->bl_max_level; + dp_panel->bl_config.brightness_max_level = panel->parser->brightness_max_level; + dp_panel->bl_config.pwm_period_usecs = panel->parser->pwm_period_usecs; + dp_panel->bl_config.bl_scale = MAX_BL_SCALE_LEVEL; + dp_panel->bl_config.bl_scale_sv = MAX_SV_BL_SCALE_LEVEL; + + if (in->base_panel) { memcpy(dp_panel->dpcd, in->base_panel->dpcd, DP_RECEIVER_CAP_SIZE + 1); @@ -3085,6 +3180,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) dp_panel->spd_config = dp_panel_spd_config; dp_panel->setup_hdr = dp_panel_setup_hdr; dp_panel->set_colorspace = dp_panel_set_colorspace; + dp_panel->set_backlight = dp_panel_set_backlight; dp_panel->hdr_supported = dp_panel_hdr_supported; dp_panel->set_stream_info = dp_panel_set_stream_info; dp_panel->read_sink_status = dp_panel_read_sink_sts; @@ -3115,6 +3211,12 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) } } + if (in->is_edp) { + rc = dp_panel_pwm_register(dp_panel); + if (rc) + DP_ERR("Failed to register pwm\n"); + } + return dp_panel; error: return ERR_PTR(rc); @@ -3132,6 +3234,9 @@ void dp_panel_put(struct dp_panel *dp_panel) dp_panel_edid_deregister(panel); sde_conn = to_sde_connector(dp_panel->connector); + + dp_panel_pwm_unregister(dp_panel); + if (sde_conn) sde_conn->drv_panel = NULL; diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h index 822393143ab8..3abb41297584 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -18,6 +18,9 @@ #define DP_RECEIVER_DSC_CAP_SIZE 15 #define DP_RECEIVER_FEC_STATUS_SIZE 3 #define DP_RECEIVER_EXT_CAP_SIZE 4 +#define MAX_BL_LEVEL 4096 +#define MAX_BL_SCALE_LEVEL 1024 +#define MAX_SV_BL_SCALE_LEVEL 65535 /* * A source initiated power down flag is set * when the DP is powered off while physical @@ -86,6 +89,22 @@ struct dp_dsc_caps { u8 color_depth; }; +struct dp_backlight_config { + u32 bl_min_level; + u32 bl_max_level; + u32 brightness_max_level; + u32 bl_level; + u32 bl_scale; + u32 bl_scale_sv; + + int en_gpio; + /* PWM params */ + struct pwm_device *pwm_bl; + bool pwm_enabled; + u32 pwm_period_usecs; +}; + + struct dp_audio; #define DP_PANEL_CAPS_DSC BIT(0) @@ -102,6 +121,7 @@ struct dp_panel { struct drm_dp_link link_info; struct sde_edid_ctrl *edid_ctrl; struct dp_panel_info pinfo; + struct dp_backlight_config bl_config; bool video_test; bool spd_enabled; @@ -159,6 +179,7 @@ struct dp_panel { bool dhdr_update, u64 core_clk_rate, bool flush); int (*set_colorspace)(struct dp_panel *dp_panel, u32 colorspace); + int (*set_backlight)(struct dp_panel *dp_panel, u32 bl_lvl); void (*tpg_config)(struct dp_panel *dp_panel, bool enable); int (*spd_config)(struct dp_panel *dp_panel); bool (*hdr_supported)(struct dp_panel *dp_panel); diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index 7f5501a136bf..4503df56a81d 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -256,6 +256,47 @@ error: return rc; } +static void dp_parser_bl_config(struct dp_parser *parser) +{ + int rc = 0; + u32 val = 0; + struct device_node *of_node = parser->pdev->dev.of_node; + + rc = of_property_read_u32(of_node, "qcom,edp-bl-min-level", &val); + if (rc) { + DP_DEBUG("bl-min-level unspecified, defaulting to zero\n"); + parser->bl_min_level = 0; + } else { + parser->bl_min_level = val; + } + + rc = of_property_read_u32(of_node, "qcom,edp-bl-max-level", &val); + if (rc) { + DP_DEBUG("bl-max-level unspecified, defaulting to 4096\n"); + parser->bl_max_level = 4096; + } else { + parser->bl_max_level = val; + } + + rc = of_property_read_u32(of_node, "qcom,edp-brightness-max-level", + &val); + if (rc) { + DP_DEBUG("brigheness-max-level unspecified, defaulting to 255\n"); + parser->brightness_max_level = 255; + } else { + parser->brightness_max_level = val; + } + + rc = of_property_read_u32(of_node, "qcom,bl-pmic-pwm-period-usecs", + &val); + if (rc) { + DP_DEBUG("bl-pmic-pwm-period-usecs unspecified, default 100\n"); + parser->pwm_period_usecs = 100; + } else { + parser->pwm_period_usecs = val; + } +} + static int dp_parser_gpio(struct dp_parser *parser) { int i = 0; @@ -854,6 +895,7 @@ static int dp_parser_parse(struct dp_parser *parser) if (rc) goto err; + dp_parser_bl_config(parser); dp_parser_dsc(parser); dp_parser_fec(parser); dp_parser_widebus(parser); diff --git a/msm/dp/dp_parser.h b/msm/dp/dp_parser.h index 5444ee9e7050..da70b5674d51 100644 --- a/msm/dp/dp_parser.h +++ b/msm/dp/dp_parser.h @@ -235,7 +235,11 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) * @fec_feature_enable: FEC feature enable status * @dsc_continuous_pps: PPS sent every frame by HW * @has_widebus: widebus (2PPC) feature eanble status - *@mst_fixed_port: mst port_num reserved for fixed topology + * @bl_min_level: minimum brightness value for backlight + * @bl_max_level: maximum brightness value for backlight + * @brightness_max_level: maximum brightness level for backlight + * @pwm_period_usecs: pwm period in usecs for backlight pwm + * @mst_fixed_port: mst port_num reserved for fixed topology * @parse: function to be called by client to parse device tree. * @get_io: function to be called by client to get io data. * @get_io_buf: function to be called by client to get io buffers. @@ -267,6 +271,10 @@ struct dp_parser { bool gpio_aux_switch; bool lphw_hpd; bool panel_notifier_support; + u32 bl_min_level; + u32 bl_max_level; + u32 brightness_max_level; + u32 pwm_period_usecs; u32 mst_fixed_port[MAX_DP_MST_STREAMS]; u32 pixel_base_off[MAX_DP_MST_STREAMS]; const char *mst_fixed_display_type[MAX_DP_MST_STREAMS]; diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 404e8af8c80f..8c23f622a97b 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -16,6 +16,7 @@ #include #include "dsi_drm.h" #include "dsi_display.h" +#include "dp_panel.h" #include "sde_crtc.h" #include "sde_rm.h" #include "sde_vm.h" @@ -23,6 +24,7 @@ #define BL_NODE_NAME_SIZE 32 #define HDR10_PLUS_VSIF_TYPE_CODE 0x81 +#define MAX_BRIGHTNESS_LEVEL 255 /* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */ #define AUTOREFRESH_MAX_FRAME_CNT 6 @@ -93,13 +95,16 @@ static inline struct sde_kms *_sde_connector_get_kms(struct drm_connector *conn) static int sde_backlight_device_update_status(struct backlight_device *bd) { int brightness; - struct dsi_display *display; + struct dsi_display *dsi_display; + struct dp_panel *dp_panel; struct sde_connector *c_conn = bl_get_data(bd); int bl_lvl; struct drm_event event; int rc = 0; struct sde_kms *sde_kms; struct sde_vm_ops *vm_ops; + u32 bl_max_level = 0; + u32 brightness_max_level = 0; sde_kms = _sde_connector_get_kms(&c_conn->base); if (!sde_kms) { @@ -114,15 +119,27 @@ static int sde_backlight_device_update_status(struct backlight_device *bd) (bd->props.state & BL_CORE_SUSPENDED)) brightness = 0; - display = (struct dsi_display *) c_conn->display; - if (brightness > display->panel->bl_config.bl_max_level) - brightness = display->panel->bl_config.bl_max_level; + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) { + dsi_display = (struct dsi_display *) c_conn->display; + bl_max_level = dsi_display->panel->bl_config.bl_max_level; + brightness_max_level = + dsi_display->panel->bl_config.brightness_max_level; + } else if (c_conn->connector_type == DRM_MODE_CONNECTOR_eDP) { + dp_panel = (struct dp_panel *) c_conn->drv_panel; + if (dp_panel) { + bl_max_level = dp_panel->bl_config.bl_max_level; + brightness_max_level = + dp_panel->bl_config.brightness_max_level; + } + } + + if (brightness > bl_max_level) + brightness = bl_max_level; if (brightness > c_conn->thermal_max_brightness) brightness = c_conn->thermal_max_brightness; /* map UI brightness into driver backlight level with rounding */ - bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level, - display->panel->bl_config.brightness_max_level); + bl_lvl = mult_frac(brightness, bl_max_level, brightness_max_level); if (!bl_lvl && brightness) bl_lvl = 1; @@ -188,31 +205,46 @@ static int sde_backlight_setup(struct sde_connector *c_conn, { struct backlight_properties props; struct dsi_display *display; - struct dsi_backlight_config *bl_config; + struct dp_panel *dp_panel; + struct dsi_backlight_config *dsi_bl_config; struct sde_kms *sde_kms; static int display_count; char bl_node_name[BL_NODE_NAME_SIZE]; + u32 brightness_max_level = 0; sde_kms = _sde_connector_get_kms(&c_conn->base); if (!sde_kms) { SDE_ERROR("invalid kms\n"); return -EINVAL; - } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) { + } + + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) { + display = (struct dsi_display *) c_conn->display; + dsi_bl_config = &display->panel->bl_config; + brightness_max_level = dsi_bl_config->brightness_max_level; + if (dsi_bl_config->type != DSI_BACKLIGHT_DCS && + sde_in_trusted_vm(sde_kms)) + return 0; + } else if (c_conn->connector_type == DRM_MODE_CONNECTOR_eDP) { + dp_panel = (struct dp_panel *) c_conn->drv_panel; + if (dp_panel) + brightness_max_level = + dp_panel->bl_config.brightness_max_level; + else { + brightness_max_level = MAX_BRIGHTNESS_LEVEL; + } + } else { + SDE_DEBUG("invalid connector type %d\n", + c_conn->connector_type); return 0; } - display = (struct dsi_display *) c_conn->display; - bl_config = &display->panel->bl_config; - - if (bl_config->type != DSI_BACKLIGHT_DCS && - sde_in_trusted_vm(sde_kms)) - return 0; memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.power = FB_BLANK_UNBLANK; - props.max_brightness = bl_config->brightness_max_level; - props.brightness = bl_config->brightness_max_level; + props.max_brightness = brightness_max_level; + props.brightness = brightness_max_level; snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight", display_count); c_conn->bl_device = backlight_device_register(bl_node_name, dev->dev, @@ -223,7 +255,7 @@ static int sde_backlight_setup(struct sde_connector *c_conn, c_conn->bl_device = NULL; return -ENODEV; } - c_conn->thermal_max_brightness = bl_config->brightness_max_level; + c_conn->thermal_max_brightness = brightness_max_level; /** * In TVM, thermal cooling device is not enabled. Registering with dummy @@ -639,42 +671,62 @@ static int _sde_connector_update_power_locked(struct sde_connector *c_conn) static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) { struct dsi_display *dsi_display; - struct dsi_backlight_config *bl_config; + struct dp_display *dp_display; + struct dsi_backlight_config *dsi_bl_config; + struct dp_backlight_config *dp_bl_config; + struct dp_panel *dp_panel; int rc = 0; + u32 bl_scale, bl_scale_sv; if (!c_conn) { SDE_ERROR("Invalid params sde_connector null\n"); return -EINVAL; } - dsi_display = c_conn->display; - if (!dsi_display || !dsi_display->panel) { - SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n", - dsi_display, - ((dsi_display) ? dsi_display->panel : NULL)); - return -EINVAL; - } - - bl_config = &dsi_display->panel->bl_config; - - if (!c_conn->allow_bl_update) { - c_conn->unset_bl_level = bl_config->bl_level; - return 0; - } - - if (c_conn->unset_bl_level) - bl_config->bl_level = c_conn->unset_bl_level; - - bl_config->bl_scale = c_conn->bl_scale > MAX_BL_SCALE_LEVEL ? + bl_scale = c_conn->bl_scale > MAX_BL_SCALE_LEVEL ? MAX_BL_SCALE_LEVEL : c_conn->bl_scale; - bl_config->bl_scale_sv = c_conn->bl_scale_sv > MAX_SV_BL_SCALE_LEVEL ? + bl_scale_sv = c_conn->bl_scale_sv > MAX_SV_BL_SCALE_LEVEL ? MAX_SV_BL_SCALE_LEVEL : c_conn->bl_scale_sv; - SDE_DEBUG("bl_scale = %u, bl_scale_sv = %u, bl_level = %u\n", - bl_config->bl_scale, bl_config->bl_scale_sv, - bl_config->bl_level); - rc = c_conn->ops.set_backlight(&c_conn->base, - dsi_display, bl_config->bl_level); + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) { + dsi_display = c_conn->display; + if (!dsi_display || !dsi_display->panel) { + SDE_ERROR("Invalid params dsi_display %pK, panel %pK\n", + dsi_display, + ((dsi_display) ? dsi_display->panel : NULL)); + return -EINVAL; + } + dsi_bl_config = &dsi_display->panel->bl_config; + if (!c_conn->allow_bl_update) { + c_conn->unset_bl_level = dsi_bl_config->bl_level; + return 0; + } + dsi_bl_config->bl_scale = bl_scale; + dsi_bl_config->bl_scale_sv = bl_scale_sv; + if (c_conn->unset_bl_level) + dsi_bl_config->bl_level = c_conn->unset_bl_level; + + rc = c_conn->ops.set_backlight(&c_conn->base, + dsi_display, dsi_bl_config->bl_level); + } else if (c_conn->connector_type == DRM_MODE_CONNECTOR_eDP) { + dp_display = c_conn->display; + dp_panel = (struct dp_panel *) c_conn->drv_panel; + if (dp_panel) { + dp_bl_config = &dp_panel->bl_config; + if (!c_conn->allow_bl_update) { + c_conn->unset_bl_level = dp_bl_config->bl_level; + return 0; + } + dp_bl_config->bl_scale = bl_scale; + dp_bl_config->bl_scale_sv = bl_scale_sv; + if (c_conn->unset_bl_level) + dp_bl_config->bl_level = c_conn->unset_bl_level; + rc = c_conn->ops.set_backlight(&c_conn->base, + dp_display, dp_bl_config->bl_level); + } else + SDE_ERROR("Invalid dp_panel null\n"); + } + c_conn->unset_bl_level = 0; return rc; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 308200bd8579..00f3d28619ec 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1785,6 +1785,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .get_info = dp_connector_get_info, .get_mode_info = dp_connector_get_mode_info, .post_open = dp_connector_post_open, + .set_backlight = dp_connector_set_backlight, .check_status = NULL, .set_colorspace = dp_connector_set_colorspace, .config_hdr = dp_connector_config_hdr, From 126db6aa9e593d75ca4489f88cb9d27b047ee9f0 Mon Sep 17 00:00:00 2001 From: Sai Srujana Oruganti Date: Mon, 22 May 2023 21:34:58 +0530 Subject: [PATCH 3/5] disp: msm: eDP continuous splash implementation For continuous splash use case bootloader already takes care of eDP hardware states including clocks and regulators. This change avoid touching eDP hardware blocks during eDP initialization sequence. Change-Id: I23635b43ce2a41078383bbcc89aa3f60564599dd Signed-off-by: Sai Srujana Oruganti --- msm/dp/dp_aux.c | 9 +++- msm/dp/dp_aux.h | 3 +- msm/dp/dp_ctrl.c | 68 +++++++++++++++++++----------- msm/dp/dp_ctrl.h | 10 ++--- msm/dp/dp_display.c | 99 +++++++++++++++++++++++++++++++++++++++----- msm/dp/dp_display.h | 17 +++++++- msm/dp/dp_drm.c | 1 + msm/dp/dp_pll.h | 2 +- msm/dp/edp_pll_7nm.c | 10 +++++ msm/sde/sde_kms.c | 3 +- 10 files changed, 177 insertions(+), 45 deletions(-) diff --git a/msm/dp/dp_aux.c b/msm/dp/dp_aux.c index ae00856bb3da..7c4fbc2fbb50 100644 --- a/msm/dp/dp_aux.c +++ b/msm/dp/dp_aux.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ @@ -631,7 +632,7 @@ static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg) aux_cfg[i].current_index = 0; } -static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg) +static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg, bool skip_op) { struct dp_aux_private *aux; @@ -645,10 +646,16 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg) if (aux->enabled) return; + /*skip aux init when cont. splash is enabled*/ + if (skip_op) + goto skip_init; + dp_aux_reset_phy_config_indices(aux_cfg); aux->catalog->setup(aux->catalog, aux_cfg); aux->catalog->reset(aux->catalog); aux->catalog->enable(aux->catalog, true); + +skip_init: atomic_set(&aux->aborted, 0); aux->retry_cnt = 0; aux->enabled = true; diff --git a/msm/dp/dp_aux.h b/msm/dp/dp_aux.h index 850941b1e53d..aa762e91acf7 100644 --- a/msm/dp/dp_aux.h +++ b/msm/dp/dp_aux.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ @@ -47,7 +48,7 @@ struct dp_aux { int (*drm_aux_register)(struct dp_aux *aux); void (*drm_aux_deregister)(struct dp_aux *aux); void (*isr)(struct dp_aux *aux); - void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg); + void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg, bool skip_op); void (*deinit)(struct dp_aux *aux); void (*reconfig)(struct dp_aux *aux); void (*abort)(struct dp_aux *aux, bool abort); diff --git a/msm/dp/dp_ctrl.c b/msm/dp/dp_ctrl.c index 395d5a7e1cc9..4f935764cc21 100644 --- a/msm/dp/dp_ctrl.c +++ b/msm/dp/dp_ctrl.c @@ -165,8 +165,13 @@ trigger_idle: * configuration, output format and sink/panel timing information. */ static void dp_ctrl_configure_source_link_params(struct dp_ctrl_private *ctrl, - bool enable) + bool enable, bool skip_op) { + if (skip_op) { + DP_DEBUG("configuring source link params skipped\n"); + return; + } + if (enable) { ctrl->catalog->lane_mapping(ctrl->catalog, ctrl->orientation, ctrl->parser->l_map); @@ -533,7 +538,7 @@ skip_training: return ret; } -static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) +static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, bool skip_op) { int ret = 0; u8 const encoding = 0x1, downspread = 0x00; @@ -547,6 +552,11 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) ctrl->link->link_params.bw_code); link_info.capabilities = ctrl->panel->link_info.capabilities; + if (skip_op) { + DP_DEBUG("link training skipped\n"); + return 0; + } + ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info); if (ret) goto end; @@ -592,7 +602,7 @@ end: return ret; } -static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl) +static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool skip_op) { int ret = 0; @@ -604,13 +614,15 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl) * transitioned to PUSH_IDLE. In order to start transmitting a link * training pattern, we have to first to a DP software reset. */ - ctrl->catalog->reset(ctrl->catalog); + + if (!skip_op) + ctrl->catalog->reset(ctrl->catalog); if (ctrl->fec_mode) drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_FEC_CONFIGURATION, 0x01); - ret = dp_ctrl_link_train(ctrl); + ret = dp_ctrl_link_train(ctrl, skip_op); end: return ret; @@ -720,7 +732,7 @@ end: ctrl->training_2_pattern = pattern; } -static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow) +static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow, bool skip_op) { int rc = -EINVAL; bool downgrade = false; @@ -746,7 +758,7 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow) ctrl->link->link_params.lane_count, ctrl->orientation); - dp_ctrl_configure_source_link_params(ctrl, true); + dp_ctrl_configure_source_link_params(ctrl, true, skip_op); if (!(--link_train_max_retries % 10)) { struct dp_link_params *link = &ctrl->link->link_params; @@ -758,7 +770,7 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow) dp_ctrl_select_training_pattern(ctrl, downgrade); - rc = dp_ctrl_setup_main_link(ctrl); + rc = dp_ctrl_setup_main_link(ctrl, skip_op); if (!rc) break; @@ -782,7 +794,7 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow) if (rc != -EAGAIN) dp_ctrl_link_rate_down_shift(ctrl); - dp_ctrl_configure_source_link_params(ctrl, false); + dp_ctrl_configure_source_link_params(ctrl, false, skip_op); dp_ctrl_disable_link_clock(ctrl); /* hw recommended delays before retrying link training */ @@ -852,7 +864,7 @@ static int dp_ctrl_disable_stream_clocks(struct dp_ctrl_private *ctrl, } return ret; } -static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset) +static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset, bool skip_op) { struct dp_ctrl_private *ctrl; struct dp_catalog_ctrl *catalog; @@ -867,7 +879,7 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset) ctrl->orientation = flip; catalog = ctrl->catalog; - if (reset) { + if (reset && !skip_op) { catalog->usb_reset(ctrl->catalog, flip); catalog->phy_reset(ctrl->catalog); } @@ -906,7 +918,7 @@ static void dp_ctrl_send_video(struct dp_ctrl_private *ctrl) ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO); } -static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) +static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl, bool skip_op) { int ret = 0; struct dp_ctrl_private *ctrl; @@ -931,7 +943,7 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) goto end; ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED; - ret = dp_ctrl_setup_main_link(ctrl); + ret = dp_ctrl_setup_main_link(ctrl, skip_op); ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED; if (ret) { @@ -949,7 +961,7 @@ end: return ret; } -static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl) +static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl, bool skip_op) { int ret = 0; struct dp_ctrl_private *ctrl; @@ -978,14 +990,14 @@ static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl) ctrl->dp_ctrl.stream_off(&ctrl->dp_ctrl, ctrl->panel); ctrl->dp_ctrl.off(&ctrl->dp_ctrl); - ctrl->aux->init(ctrl->aux, ctrl->parser->aux_cfg); + ctrl->aux->init(ctrl->aux, ctrl->parser->aux_cfg, skip_op); ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl, ctrl->mst_mode, - ctrl->fec_mode, ctrl->dsc_mode, false); + ctrl->fec_mode, ctrl->dsc_mode, false, skip_op); if (ret) DP_ERR("failed to enable DP controller\n"); - ctrl->dp_ctrl.stream_on(&ctrl->dp_ctrl, ctrl->panel); + ctrl->dp_ctrl.stream_on(&ctrl->dp_ctrl, ctrl->panel, skip_op); DP_DEBUG("end\n"); } @@ -1228,7 +1240,7 @@ static void dp_ctrl_fec_dsc_setup(struct dp_ctrl_private *ctrl) DP_WARN("failed to enable sink dsc\n"); } -static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) +static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel, bool skip_op) { int rc = 0; bool link_ready = false; @@ -1250,9 +1262,12 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) return rc; } - rc = panel->hw_cfg(panel, true); - if (rc) - return rc; + /*Skip panel config when cont. splash is enabled*/ + if (!skip_op) { + rc = panel->hw_cfg(panel, true); + if (rc) + return rc; + } if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { dp_ctrl_send_phy_test_pattern(ctrl); @@ -1343,7 +1358,7 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) } static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode, - bool fec_mode, bool dsc_mode, bool shallow) + bool fec_mode, bool dsc_mode, bool shallow, bool skip_op) { int rc = 0; struct dp_ctrl_private *ctrl; @@ -1389,9 +1404,13 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode, ctrl->initial_lane_count = ctrl->link->link_params.lane_count; ctrl->initial_bw_code = ctrl->link->link_params.bw_code; - rc = dp_ctrl_link_setup(ctrl, shallow); + rc = dp_ctrl_link_setup(ctrl, shallow, skip_op); if (!rc) ctrl->power_on = true; + + /*enable stream clocks when cont. splash is enabled*/ + if (skip_op) + dp_ctrl_enable_stream_clocks(ctrl, ctrl->panel); end: return rc; } @@ -1399,6 +1418,7 @@ end: static void dp_ctrl_off(struct dp_ctrl *dp_ctrl) { struct dp_ctrl_private *ctrl; + bool skip_op = false; if (!dp_ctrl) return; @@ -1409,7 +1429,7 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl) return; ctrl->catalog->fec_config(ctrl->catalog, false); - dp_ctrl_configure_source_link_params(ctrl, false); + dp_ctrl_configure_source_link_params(ctrl, false, skip_op); ctrl->catalog->reset(ctrl->catalog); /* Make sure DP is disabled before clk disable */ diff --git a/msm/dp/dp_ctrl.h b/msm/dp/dp_ctrl.h index 225a4bf54daf..0f506d7294d8 100644 --- a/msm/dp/dp_ctrl.h +++ b/msm/dp/dp_ctrl.h @@ -16,17 +16,17 @@ #include "dp_debug.h" struct dp_ctrl { - int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset); + int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset, bool skip_op); void (*deinit)(struct dp_ctrl *dp_ctrl); int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool fec_en, - bool dsc_en, bool shallow); + bool dsc_en, bool shallow, bool skip_op); void (*off)(struct dp_ctrl *dp_ctrl); void (*abort)(struct dp_ctrl *dp_ctrl, bool abort); void (*isr)(struct dp_ctrl *dp_ctrl); bool (*handle_sink_request)(struct dp_ctrl *dp_ctrl); - void (*process_phy_test_request)(struct dp_ctrl *dp_ctrl); - int (*link_maintenance)(struct dp_ctrl *dp_ctrl); - int (*stream_on)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel); + void (*process_phy_test_request)(struct dp_ctrl *dp_ctrl, bool skip_op); + int (*link_maintenance)(struct dp_ctrl *dp_ctrl, bool skip_op); + int (*stream_on)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel, bool skip_op); void (*stream_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel); void (*stream_pre_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel); void (*set_mst_channel_info)(struct dp_ctrl *dp_ctrl, diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 11349989c449..292c6cef76a2 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -136,6 +136,12 @@ static char *dp_display_state_name(enum dp_display_states state) static struct dp_display *g_dp_display[MAX_DP_ACTIVE_DISPLAY]; #define HPD_STRING_SIZE 30 +static char edp_display_primary[MAX_CMDLINE_PARAM_LEN]; + +static struct dp_display_boot_param boot_displays[MAX_DP_ACTIVE_BOOT_DISPLAY] = { + {.boot_param = edp_display_primary}, +}; + struct dp_hdcp_dev { void *fd; struct sde_hdcp_ops *ops; @@ -229,6 +235,13 @@ static const struct of_device_id dp_dt_match[] = { {} }; +bool is_skip_required(struct dp_display *display) +{ + if (!display) + return false; + return display->cont_splash_enabled; +} + static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp) { return dp->link->hdcp_status.hdcp_version && dp->hdcp.ops; @@ -304,6 +317,35 @@ static void dp_audio_enable(struct dp_display_private *dp, bool enable) } } +static int dp_display_parse_boot_display_selection(void) +{ + char *pos = NULL; + char disp_buf[MAX_CMDLINE_PARAM_LEN] = {'\0'}; + int i, j; + + for (i = 0; i < MAX_DP_ACTIVE_BOOT_DISPLAY; i++) { + strlcpy(disp_buf, boot_displays[i].boot_param, + MAX_CMDLINE_PARAM_LEN); + + pos = strnstr(disp_buf, ":", strlen(disp_buf)); + + /* Use ':' as a delimiter to retrieve the display name */ + if (!pos) { + DP_DEBUG("display name[%s]is not valid\n", disp_buf); + continue; + } + + for (j = 0; (disp_buf + j) < pos; j++) + boot_displays[i].name[j] = *(disp_buf + j); + + boot_displays[i].name[j] = '\0'; + + boot_displays[i].boot_disp_en = true; + } + + return 0; +} + static void dp_display_update_hdcp_status(struct dp_display_private *dp, bool reset) { @@ -1060,6 +1102,8 @@ static int dp_display_host_init(struct dp_display_private *dp) bool flip = false; bool reset; int rc = 0; + bool skip_op = is_skip_required(&dp->dp_display); + if (dp_display_state_is(DP_STATE_INITIALIZED)) { dp_display_state_log("[already initialized]"); @@ -1079,7 +1123,7 @@ static int dp_display_host_init(struct dp_display_private *dp) } dp->hpd->host_init(dp->hpd, &dp->catalog->hpd); - rc = dp->ctrl->init(dp->ctrl, flip, reset); + rc = dp->ctrl->init(dp->ctrl, flip, reset, skip_op); if (rc) { DP_WARN("Ctrl init Failed.\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_CASE2, dp->state); @@ -1122,7 +1166,8 @@ static int dp_display_panel_ready(struct dp_display_private *dp) return -ETIMEDOUT; } } - dp->panel->init(dp->panel); + if (!dp->dp_display.cont_splash_enabled) + dp->panel->init(dp->panel); return 0; } @@ -1130,6 +1175,7 @@ static int dp_display_panel_ready(struct dp_display_private *dp) static int dp_display_host_ready(struct dp_display_private *dp) { int rc = 0; + bool skip_op; if (!dp_display_state_is(DP_STATE_INITIALIZED)) { rc = dp_display_host_init(dp); @@ -1160,11 +1206,11 @@ static int dp_display_host_ready(struct dp_display_private *dp) * the connect/disconnect notifications do not currently have any * sessions IDs. */ + skip_op = dp->dp_display.cont_splash_enabled; dp->aux->abort(dp->aux, false); dp->ctrl->abort(dp->ctrl, false); - dp->aux->init(dp->aux, dp->parser->aux_cfg); - + dp->aux->init(dp->aux, dp->parser->aux_cfg, skip_op); dp_display_state_add(DP_STATE_READY); /* log this as it results from user action of cable connection */ DP_INFO("[OK]\n"); @@ -1220,6 +1266,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) int rc = -EINVAL; unsigned long wait_timeout_ms; unsigned long t; + bool skip_op = is_skip_required(&dp->dp_display); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); @@ -1302,7 +1349,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp_display_mst_init(dp); rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, - dp->panel->fec_en, dp->panel->dsc_en, false); + dp->panel->fec_en, dp->panel->dsc_en, false, skip_op); if (rc) { dp_display_state_remove(DP_STATE_CONNECTED); goto end; @@ -1702,8 +1749,9 @@ static int dp_display_stream_enable(struct dp_display_private *dp, struct dp_panel *dp_panel) { int rc = 0; + bool skip_op = is_skip_required(&dp->dp_display); - rc = dp->ctrl->stream_on(dp->ctrl, dp_panel); + rc = dp->ctrl->stream_on(dp->ctrl, dp_panel, skip_op); if (dp->debug->tpg_state) dp_panel->tpg_config(dp_panel, true); @@ -1742,6 +1790,7 @@ static void dp_display_attention_work(struct work_struct *work) struct dp_display_private *dp = container_of(work, struct dp_display_private, attention_work); int rc = 0; + bool skip_op = is_skip_required(&dp->dp_display); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); mutex_lock(&dp->session_lock); @@ -1805,18 +1854,18 @@ static void dp_display_attention_work(struct work_struct *work) if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { SDE_EVT32_EXTERNAL(dp->state, DP_TEST_LINK_PHY_TEST_PATTERN); - dp->ctrl->process_phy_test_request(dp->ctrl); + dp->ctrl->process_phy_test_request(dp->ctrl, skip_op); } if (dp->link->sink_request & DP_TEST_LINK_TRAINING) { SDE_EVT32_EXTERNAL(dp->state, DP_TEST_LINK_TRAINING); dp->link->send_test_response(dp->link); - rc = dp->ctrl->link_maintenance(dp->ctrl); + rc = dp->ctrl->link_maintenance(dp->ctrl, skip_op); } if (dp->link->sink_request & DP_LINK_STATUS_UPDATED) { SDE_EVT32_EXTERNAL(dp->state, DP_LINK_STATUS_UPDATED); - rc = dp->ctrl->link_maintenance(dp->ctrl); + rc = dp->ctrl->link_maintenance(dp->ctrl, skip_op); } if (!rc) @@ -2066,6 +2115,9 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_pll; } + if (dp->dp_display.cont_splash_enabled) + dp->pll->cont_splash_enabled = 1; + dp->power = dp_power_get(dp->parser, dp->pll); if (IS_ERR(dp->power)) { rc = PTR_ERR(dp->power); @@ -2283,6 +2335,7 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel) struct dp_panel *dp_panel; int rc = 0; bool shallow_mode = true; + bool skip_op = is_skip_required(dp_display); if (!dp_display || !panel) { DP_ERR("invalid input\n"); @@ -2385,7 +2438,7 @@ static int dp_display_prepare(struct dp_display *dp_display, void *panel) * and required things. */ rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp_panel->fec_en, - dp_panel->dsc_en, shallow_mode); + dp_panel->dsc_en, shallow_mode, skip_op); if (rc) goto end; @@ -2573,6 +2626,11 @@ end: static void dp_display_stream_post_enable(struct dp_display_private *dp, struct dp_panel *dp_panel) { + + if (dp->dp_display.cont_splash_enabled) { + dp->dp_display.cont_splash_enabled = false; + dp->pll->cont_splash_enabled = false; + } dp_panel->spd_config(dp_panel); dp_panel->setup_hdr(dp_panel, NULL, false, 0, true); } @@ -3953,6 +4011,10 @@ static int dp_display_probe(struct platform_device *pdev) dp_display->is_edp = (info->display_type == DRM_MODE_CONNECTOR_eDP) ? true : false; dp_display->edp_detect = dp_display_edp_detect; + if (dp_display->is_edp) { + if (dp_display_get_num_of_boot_displays()) + dp_display->cont_splash_enabled = 1; + } rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { DP_ERR("component add failed, rc=%d\n", rc); @@ -3985,6 +4047,17 @@ int dp_display_get_displays(void **displays, int count) return i; } +int dp_display_get_num_of_boot_displays(void) +{ + int i; + int count = 0; + + for (i = 0; i < MAX_DP_ACTIVE_BOOT_DISPLAY; i++) { + if (boot_displays[i].boot_disp_en == true) + count++; + } + return count; +} int dp_display_get_num_of_displays(void) { int i; @@ -4151,7 +4224,7 @@ static struct platform_driver dp_display_driver = { void __init dp_display_register(void) { - + dp_display_parse_boot_display_selection(); platform_driver_register(&dp_display_driver); } @@ -4159,3 +4232,7 @@ void __exit dp_display_unregister(void) { platform_driver_unregister(&dp_display_driver); } +module_param_string(edp_display0, edp_display_primary, MAX_CMDLINE_PARAM_LEN, + 0600); +MODULE_PARM_DESC(edp_display0, + "msm_drm.edp_display0=: where is 'primary dp display node name' "); diff --git a/msm/dp/dp_display.h b/msm/dp/dp_display.h index 892322fa2fc2..13181732cf32 100644 --- a/msm/dp/dp_display.h +++ b/msm/dp/dp_display.h @@ -16,6 +16,9 @@ #define DP_MST_SIM_MAX_PORTS 8 #define MAX_DP_ACTIVE_DISPLAY 8 +#define MAX_DP_ACTIVE_BOOT_DISPLAY 1 + +#define MAX_CMDLINE_PARAM_LEN 512 enum dp_drv_state { PM_DEFAULT, @@ -39,6 +42,13 @@ struct dp_display_info { u32 stream_cnt; }; +struct dp_display_boot_param { + char name[MAX_CMDLINE_PARAM_LEN]; + char *boot_param; + bool boot_disp_en; + void *disp; +}; + struct dp_mst_drm_cbs { void (*hpd)(void *display, bool hpd_status); void (*hpd_irq)(void *display, struct dp_mst_hpd_info *info); @@ -86,6 +96,7 @@ struct dp_display { void *dp_mst_prv_info; u32 max_mixer_count; u32 max_dsc_count; + bool cont_splash_enabled; int (*enable)(struct dp_display *dp_display, void *panel); int (*post_enable)(struct dp_display *dp_display, void *panel); @@ -149,9 +160,9 @@ struct dp_display { u32 strm_id, const char **display_type); int (*edp_detect)(struct dp_display *dp_display); }; - #if IS_ENABLED(CONFIG_DRM_MSM_DP) int dp_display_get_num_of_displays(void); +int dp_display_get_num_of_boot_displays(void); int dp_display_get_displays(void **displays, int count); int dp_display_get_num_of_streams(void); int dp_display_get_info(void *dp_display, struct dp_display_info *dp_info); @@ -160,6 +171,10 @@ static inline int dp_display_get_num_of_displays(void) { return 0; } +static inline int dp_display_get_num_of_boot_displays(void) +{ + return 0; +} static inline int dp_display_get_displays(void **displays, int count) { return 0; diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index 6e054af5dc3d..1342726043e8 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -463,6 +463,7 @@ int dp_connector_get_info(struct drm_connector *connector, if (display && display->is_edp) { info->intf_type = DRM_MODE_CONNECTOR_eDP; info->display_type = SDE_CONNECTOR_PRIMARY; + info->is_connected = true; } else { info->capabilities |= MSM_DISPLAY_CAP_HOT_PLUG; } diff --git a/msm/dp/dp_pll.h b/msm/dp/dp_pll.h index fa56964ab533..780a00c6dbfa 100644 --- a/msm/dp/dp_pll.h +++ b/msm/dp/dp_pll.h @@ -127,7 +127,7 @@ struct dp_pll { bool ssc_en; bool bonding_en; - + bool cont_splash_enabled; void *priv; struct dp_pll_db pll_db; struct dp_pll_vco_clk pll_clks[DP_PLL_NUM_CLKS]; diff --git a/msm/dp/edp_pll_7nm.c b/msm/dp/edp_pll_7nm.c index da26cb657884..1f3b60a1f325 100644 --- a/msm/dp/edp_pll_7nm.c +++ b/msm/dp/edp_pll_7nm.c @@ -277,6 +277,8 @@ static int edp_config_vco_rate_7nm(struct dp_pll *pll, DP_ERR("VCO Init DB failed\n"); return rc; } + if (pll->cont_splash_enabled) + return 0; dp_pll_write(dp_phy, DP_PHY_PD_CTL, 0x7d); /* Make sure the PLL register writes are done */ @@ -460,6 +462,11 @@ static int edp_pll_enable_7nm(struct dp_pll *pll) pll->aux->state &= ~DP_STATE_PLL_LOCKED; + if (pll->cont_splash_enabled) { + pll->aux->state |= DP_STATE_PLL_LOCKED; + return rc; + } + dp_pll_write(dp_phy, DP_PHY_CFG, 0x01); dp_pll_write(dp_phy, DP_PHY_CFG, 0x05); dp_pll_write(dp_phy, DP_PHY_CFG, 0x01); @@ -790,6 +797,9 @@ static int edp_pll_vco_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, pll_link = to_dp_vco_hw(hw); pll = pll_link->priv; + if (pll->cont_splash_enabled) + return rc; + if (rate != edp_pll_vco_div_clk_get_rate(pll)) { DP_ERR("unsupported rate %lu failed\n", rate); return rc; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 308200bd8579..b416840b5f7c 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -4426,7 +4426,8 @@ static int _sde_kms_get_splash_data(struct sde_kms *sde_kms, * cont_splash_region should be collection of all memory regions * Ex: */ - num_displays = dsi_display_get_num_of_displays(); + num_displays = dsi_display_get_num_of_displays() + + dp_display_get_num_of_boot_displays(); num_regions = of_property_count_u64_elems(node, "reg") / 2; data->num_splash_displays = num_displays; From ea245e7982147e234773528e78f64db2135fb846 Mon Sep 17 00:00:00 2001 From: Sai Srujana Oruganti Date: Sun, 18 Jun 2023 21:35:42 +0530 Subject: [PATCH 4/5] disp: msm: sde: Remove pm vote at time of handoff Additional pm vote is added when cont splash is enabled for eDP. This vote has to be removed at the time of handoff. Change-Id: Ib1c0cc58f0be1031d405ca8941d3e7984b1e9f46 Signed-off-by: Sai Srujana Oruganti --- msm/sde/sde_kms.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index b416840b5f7c..c7c4b224ee73 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1255,6 +1255,16 @@ static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms, SDE_EVT32(DRMID(crtc), crtc->state->active, sde_kms->splash_data.num_splash_displays); + /*remove all votes if eDP displays are done with splash*/ + if (dp_display_get_num_of_boot_displays()) { + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_set_quota(phandle, i, + SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, + phandle->ib_quota[i]); + pm_runtime_put_sync(sde_kms->dev->dev); + sde_kms->splash_data.num_splash_displays--; + } + for (i = 0; i < MAX_DSI_DISPLAYS; i++) { splash_display = &sde_kms->splash_data.splash_display[i]; if (splash_display->encoder && From 452e643352bd41612f5634d8b38d7be9cbc9a875 Mon Sep 17 00:00:00 2001 From: Nilesh Laad Date: Fri, 23 Jun 2023 17:42:52 +0530 Subject: [PATCH 5/5] disp: msm: dp: wait for resources init in case of cont splash Driver probe has to wait for dp resource initialization, in case of continuous splash to avoid any resource resets. Change-Id: Idaa506b14132d22b9bfe558c88ab6d33171b4f3b Signed-off-by: Nilesh Laad --- msm/dp/dp_display.c | 41 ++++++++++++++++++++++++++++++++++ msm/dp/dp_display.h | 5 +++++ msm/sde/sde_kms.c | 54 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index b33930a7e5fb..bcb6f8f57ff4 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -177,6 +177,7 @@ struct dp_display_private { struct dentry *root; struct completion notification_comp; struct completion attention_comp; + struct completion res_init_comp; struct dp_hpd *hpd; struct dp_parser *parser; @@ -317,6 +318,42 @@ static void dp_audio_enable(struct dp_display_private *dp, bool enable) } } +/** + * dp_display_cont_splash_config() - Initialize resources for continuous splash + * @dp_display: Pointer to dp display + * Returns: Zero on success + */ +int dp_display_cont_splash_config(void *display) +{ + struct dp_display *dp_display = display; + struct dp_display_private *dp; + int rc = 0; + + /* Vote for gdsc required to read register address space */ + if (!dp_display) { + DP_ERR("invalid input display param\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + if (!dp_display->is_edp) { + DP_ERR("splash handoff for dp not supported\n"); + return -EOPNOTSUPP; + } + + /* wait for the all the resource initialization and voting to + * complete, before we exit driver probe + */ + if (!wait_for_completion_timeout(&dp->res_init_comp, HZ * 10)) { + DP_WARN("timeout waiting for splash_res_init\n"); + rc = -ETIMEDOUT; + } + + return rc; +} + + static int dp_display_parse_boot_display_selection(void) { char *pos = NULL; @@ -1358,6 +1395,9 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->process_hpd_connect = false; dp_display_set_mst_mgr_state(dp, true); + + /* all dp resource init are complete */ + complete_all(&dp->res_init_comp); end: mutex_unlock(&dp->session_lock); @@ -3990,6 +4030,7 @@ static int dp_display_probe(struct platform_device *pdev) init_completion(&dp->notification_comp); init_completion(&dp->attention_comp); + init_completion(&dp->res_init_comp); dp->pdev = pdev; dp->name = "drm_dp"; diff --git a/msm/dp/dp_display.h b/msm/dp/dp_display.h index 9d4cea9810d2..f7088a4aa93b 100644 --- a/msm/dp/dp_display.h +++ b/msm/dp/dp_display.h @@ -168,6 +168,7 @@ int dp_display_get_num_of_boot_displays(void); int dp_display_get_displays(void **displays, int count); int dp_display_get_num_of_streams(void); int dp_display_get_info(void *dp_display, struct dp_display_info *dp_info); +int dp_display_cont_splash_config(void *display); #else static inline int dp_display_get_num_of_displays(void) { @@ -194,5 +195,9 @@ static inline int dp_connector_update_pps(struct drm_connector *connector, { return 0; } +static inline int dp_display_cont_splash_config(void *display) +{ + return 0; +} #endif /* CONFIG_DRM_MSM_DP */ #endif /* _DP_DISPLAY_H_ */ diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 5bdcdd018157..e0df3cc96fd8 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1800,7 +1800,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev, .set_colorspace = dp_connector_set_colorspace, .config_hdr = dp_connector_config_hdr, .cmd_transfer = NULL, - .cont_splash_config = NULL, + .cont_splash_config = dp_display_cont_splash_config, .cont_splash_res_disable = NULL, .get_panel_vfp = NULL, .update_pps = dp_connector_update_pps, @@ -3381,6 +3381,7 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms, { void *display; struct dsi_display *dsi_display; + struct dp_display *dp_display; struct msm_display_info info; struct drm_encoder *encoder = NULL; struct drm_crtc *crtc = NULL; @@ -3531,6 +3532,57 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms, } } + /* dp */ + for (i = 0; i < sde_kms->dp_display_count; ++i) { + display = sde_kms->dp_displays[i]; + dp_display = (struct dp_display *)display; + + if (!dp_display->cont_splash_enabled) { + SDE_DEBUG("DP-%d splash not enabled\n", i); + continue; + } + + if (dp_display->bridge->base.encoder) { + encoder = dp_display->bridge->base.encoder; + SDE_DEBUG("encoder name = %s\n", encoder->name); + } else { + SDE_DEBUG("Invalid encoder\n"); + break; + } + + mutex_lock(&dev->mode_config.mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + /** + * SDE_KMS doesn't attach more than one encoder to + * a DSI connector. So it is safe to check only with + * the first encoder entry. Revisit this logic if we + * ever have to support continuous splash for + * external displays in MST configuration. + */ + if (connector->encoder_ids[0] == encoder->base.id) + break; + } + + drm_connector_list_iter_end(&conn_iter); + if (!connector) { + SDE_ERROR("connector not initialized\n"); + mutex_unlock(&dev->mode_config.mutex); + return -EINVAL; + } + mutex_unlock(&dev->mode_config.mutex); + + /* Enable all irqs */ + sde_irq_update(kms, true); + + sde_conn = to_sde_connector(connector); + if (sde_conn && sde_conn->ops.cont_splash_config) + sde_conn->ops.cont_splash_config(sde_conn->display); + + /* Disable irqs */ + sde_irq_update(kms, false); + } + return rc; }