From f6d96209a5510d52caaf380ae3938697cbd9330b Mon Sep 17 00:00:00 2001 From: Srihitha Tangudu Date: Wed, 8 Sep 2021 15:21:00 +0530 Subject: [PATCH 01/51] disp: msm: dsi: Fix deadlock issue in debugfs_esd_trigger_check function In debugfs_esd_trigger_check, display mutex is not unlocked in error scenario which may lead to deadlock. This change adds fix to handle this. Change-Id: I44d78959630a49bd1e9dcf871cfc108ac43232db Signed-off-by: Srihitha Tangudu --- msm/dsi/dsi_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 9cf97c164e70..361bb5528bae 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -1562,7 +1562,7 @@ static ssize_t debugfs_esd_trigger_check(struct file *file, display->trusted_vm_env); if (rc) { DSI_ERR("Failed to trigger ESD attack\n"); - goto error; + goto unlock; } } From ad3b81ed30d3578ca9f69028fdbbc6b60541666a Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Thu, 9 Sep 2021 14:18:15 +0800 Subject: [PATCH 02/51] disp: msm: qpic: fix kw issues in QPIC display driver This change is updated to address use after free and null checks in QPIC display driver. Change-Id: I97f1d941de69aad3d49cbf0c9782022b8f7db840 Signed-off-by: Lei Chen --- tinydrm/qpic_display.c | 18 +++++++++++++----- tinydrm/qpic_display.h | 2 +- tinydrm/qpic_panel_ili9341.c | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tinydrm/qpic_display.c b/tinydrm/qpic_display.c index d000751bdd76..d32241db2b2c 100644 --- a/tinydrm/qpic_display.c +++ b/tinydrm/qpic_display.c @@ -918,14 +918,22 @@ static const struct drm_mode_config_funcs qpic_mode_config_funcs = { static void qpic_display_fb_mark_dirty(struct drm_framebuffer *fb, struct drm_rect *rect) { u32 size; - struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - struct dma_buf_attachment *import_attach = cma_obj->base.import_attach; + struct drm_gem_cma_object *cma_obj = NULL; + struct dma_buf_attachment *import_attach = NULL; struct qpic_display_data *qpic_display = fb->dev->dev_private; if (!qpic_display->is_qpic_on || !qpic_display->is_panel_on) { pr_info("%s: qpic or panel is not enabled\n", __func__); return; } + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + pr_err("failed to get gem obj\n"); + return; + } + import_attach = cma_obj->base.import_attach; + /* currently QPIC display SW can't support partial updates */ rect->x1 = 0; rect->x2 = fb->width; @@ -1194,7 +1202,7 @@ int qpic_display_get_resource(struct qpic_display_data *qpic_display) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qpic_base"); if (!res) { pr_err("unable to get QPIC reg base address\n"); - rc = -ENOMEM; + return -ENOMEM; } qpic_display->qpic_reg_size = resource_size(res); @@ -1202,7 +1210,7 @@ int qpic_display_get_resource(struct qpic_display_data *qpic_display) qpic_display->qpic_reg_size); if (unlikely(!qpic_display->qpic_base)) { pr_err("unable to map MDSS QPIC base\n"); - rc = -ENOMEM; + return -ENOMEM; } qpic_display->qpic_phys = res->start; pr_info("MDSS QPIC HW Base phy_Address=0x%x virt=0x%x\n", @@ -1212,7 +1220,7 @@ int qpic_display_get_resource(struct qpic_display_data *qpic_display) res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { pr_err("unable to get QPIC irq\n"); - rc = -ENODEV; + return -ENODEV; } qpic_display->qpic_clk = devm_clk_get(&pdev->dev, "core_clk"); diff --git a/tinydrm/qpic_display.h b/tinydrm/qpic_display.h index 7e5af6e3a885..a91a99ba77b1 100644 --- a/tinydrm/qpic_display.h +++ b/tinydrm/qpic_display.h @@ -132,6 +132,6 @@ struct qpic_display_data { }; -int get_ili_qvga_panel_config(struct qpic_display_data *qpic_display); +void get_ili_qvga_panel_config(struct qpic_display_data *qpic_display); #endif diff --git a/tinydrm/qpic_panel_ili9341.c b/tinydrm/qpic_panel_ili9341.c index 757dfd2a7371..db47abbf8172 100644 --- a/tinydrm/qpic_panel_ili9341.c +++ b/tinydrm/qpic_panel_ili9341.c @@ -76,7 +76,7 @@ static struct qpic_panel_config ili_qvga_panel = { .bpp = 16, }; -int get_ili_qvga_panel_config(struct qpic_display_data *qpic_display) +void get_ili_qvga_panel_config(struct qpic_display_data *qpic_display) { qpic_display->panel_config = &ili_qvga_panel; qpic_display->panel_on = ili9341_on; From d57c2eee4797f014b658a3455a3422b4fc43f05a Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Tue, 10 Nov 2020 13:01:11 +0530 Subject: [PATCH 03/51] drm: msm: dsi: Update DSI parser util to skip disabled child nodes Currently, disabled timing child nodes or power supply nodes are not skipped because of which status = "disabled" entry does not work for child nodes. Use of_get_next_available_child to skip disabled child nodes. Change-Id: Ib6e4b655f83dd0ee3ffddd496976c34030fa3dc0 Signed-off-by: Ritesh Kumar --- msm/dsi/dsi_parser.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/msm/dsi/dsi_parser.h b/msm/dsi/dsi_parser.h index 949de1b4b02e..0ba6aa3a3b67 100644 --- a/msm/dsi/dsi_parser.h +++ b/msm/dsi/dsi_parser.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #ifndef _DSI_PARSER_H_ @@ -204,7 +204,7 @@ static inline struct dsi_parser_utils *dsi_parser_get_of_utils(void) .get_child_count = of_get_child_count, .get_available_child_count = of_get_available_child_count, .find_property = of_find_property, - .get_next_child = of_get_next_child, + .get_next_child = of_get_next_available_child, .count_u32_elems = of_property_count_u32_elems, .get_named_gpio = of_get_named_gpio, }; From 92359a8a2e68001f07c6d1aa2a1818de5ec7b637 Mon Sep 17 00:00:00 2001 From: Andhavarapu Karthik Date: Tue, 21 Sep 2021 10:00:57 +0530 Subject: [PATCH 04/51] disp: msm: sde: add checks to avoid null pointer dereference This change adds required checks to avoid accessing null pointer where debug bus is not initialised and dumping the debug bus points. Change-Id: Ia46a4b95706f05e37be660f006c04b1e2e9f6848 Signed-off-by: Andhavarapu Karthik --- msm/sde_dbg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/msm/sde_dbg.c b/msm/sde_dbg.c index a065ef45a98c..23855af9c9f0 100644 --- a/msm/sde_dbg.c +++ b/msm/sde_dbg.c @@ -959,6 +959,9 @@ static void _sde_dbg_dump_sde_dbg_bus(struct sde_dbg_sde_debug_bus *bus) u32 bus_size; char name[20]; + if (!bus || !bus->cmn.entries_size) + return; + reg_base = _sde_dump_get_blk_addr(bus->cmn.name); if (!reg_base || !reg_base->base) { pr_err("unable to find mem_base for %s\n", bus->cmn.name); From ae98505aae5c777a7397d08098f7d6c309eaecc6 Mon Sep 17 00:00:00 2001 From: Mahadevan Date: Fri, 13 Aug 2021 20:18:01 +0530 Subject: [PATCH 05/51] disp: msm: sde: switch rsc state before CTL_PREPARE in dual display In dual display usecase when both displays comes out of idle following scenario will cause wr_ptr timeout. 1. Both displays goes to idle and RSCC enters Mode-2. 2. Primary display exit idle upon DRM commit N RSC enters Solver State. 3. Secondary display exits idle upon DRM commit M and waits on input fence after CTL_1_PREPARE is set. RSC is still in CMD state. 4. Primary Commit N frame transfer got successful and commit N+1 is queued in primary display when RSC in solver state which leads to timeout in primary. This is because RSCC will not generate a wakeup in sync with primary timelines leading to timeout. This is because RSCC still sees idle low thinking frame transfer is taking long time. This change will switch the rsc state to AMC mode before CTL_PREPARE is set which resolves such issue. Change-Id: Ic32e48b4febbbcc54d94876194d38fe6ef3d0981 Signed-off-by: Mahadevan --- msm/sde/sde_crtc.c | 1 + msm/sde/sde_encoder.c | 40 ++++++++++++++++++++++++++++++++++++++++ msm/sde/sde_encoder.h | 6 ++++++ 3 files changed, 47 insertions(+) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 260e713c34d2..2c08ab9b2e5e 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3298,6 +3298,7 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, if (encoder->crtc != crtc) continue; + sde_encoder_trigger_rsc_state_change(encoder); /* encoder will trigger pending mask now */ sde_encoder_trigger_kickoff_pending(encoder); } diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index cb5990cd52bb..7f1a99b5f53b 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -3797,6 +3797,46 @@ bool sde_encoder_check_curr_mode(struct drm_encoder *drm_enc, u32 mode) return (disp_info->curr_panel_mode == mode); } +void sde_encoder_trigger_rsc_state_change(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + int ret = 0; + + sde_enc = to_sde_encoder_virt(drm_enc); + + if (!sde_enc) + return; + + mutex_lock(&sde_enc->rc_lock); + /* + * In dual display case when secondary comes out of + * idle make sure RSC solver mode is disabled before + * setting CTL_PREPARE. + */ + if (!sde_enc->cur_master || + !sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE) || + sde_enc->disp_info.display_type == SDE_CONNECTOR_PRIMARY || + sde_enc->rc_state != SDE_ENC_RC_STATE_IDLE) + goto end; + + /* enable all the clks and resources */ + ret = _sde_encoder_resource_control_helper(drm_enc, true); + if (ret) { + SDE_ERROR_ENC(sde_enc, "rc in state %d\n", sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sde_enc->rc_state, SDE_EVTLOG_ERROR); + goto end; + } + + _sde_encoder_update_rsc_client(drm_enc, true); + + SDE_EVT32(DRMID(drm_enc), sde_enc->rc_state, SDE_ENC_RC_STATE_ON); + sde_enc->rc_state = SDE_ENC_RC_STATE_ON; + +end: + mutex_unlock(&sde_enc->rc_lock); +} + + void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc; diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 8e90c1408483..27116034c11b 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -275,6 +275,12 @@ void sde_encoder_get_hw_resources(struct drm_encoder *encoder, struct sde_encoder_hw_resources *hw_res, struct drm_connector_state *conn_state); +/** + * sde_encoder_trigger_rsc_state_change - rsc state change. + * @encoder: encoder pointer + */ +void sde_encoder_trigger_rsc_state_change(struct drm_encoder *drm_enc); + /** * sde_encoder_early_wakeup - early wake up display * @encoder: encoder pointer From 5599d64b443ae8e9ab5d489615a1031482ab8085 Mon Sep 17 00:00:00 2001 From: osaisruj Date: Wed, 22 Sep 2021 10:43:04 +0530 Subject: [PATCH 06/51] disp: msm: dsi: add support for ultra low power state During lp2 state the load on the panel and controller regulators can be reduced. Configure ldos in optimum mode during this state. Change-Id: I75c180f28f636ebb23ecbe9679ba89c00977fe0f Signed-off-by: osaisruj --- msm/dsi/dsi_display.c | 39 +++++++++++++++++++++++++++++++++++++++ msm/dsi/dsi_display.h | 2 +- msm/dsi/dsi_pwr.c | 34 +++++++++++++++++++++++++++++++++- msm/dsi/dsi_pwr.h | 13 ++++++++++++- 4 files changed, 85 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 361bb5528bae..74c556be67e6 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -1247,12 +1247,22 @@ int dsi_display_set_power(struct drm_connector *connector, switch (power_mode) { case SDE_MODE_DPMS_LP1: + if (display->panel->power_mode == SDE_MODE_DPMS_LP2) { + if (dsi_display_set_ulp_load(display, false) < 0) + DSI_WARN("failed to set load for lp1 state\n"); + } rc = dsi_panel_set_lp1(display->panel); break; case SDE_MODE_DPMS_LP2: rc = dsi_panel_set_lp2(display->panel); + if (dsi_display_set_ulp_load(display, true) < 0) + DSI_WARN("failed to set load for lp2 state\n"); break; case SDE_MODE_DPMS_ON: + if (display->panel->power_mode == SDE_MODE_DPMS_LP2) { + if (dsi_display_set_ulp_load(display, false) < 0) + DSI_WARN("failed to set load for on state\n"); + } if ((display->panel->power_mode == SDE_MODE_DPMS_LP1) || (display->panel->power_mode == SDE_MODE_DPMS_LP2)) rc = dsi_panel_set_nolp(display->panel); @@ -3904,6 +3914,35 @@ int dsi_pre_clkon_cb(void *priv, return rc; } +int dsi_display_set_ulp_load(struct dsi_display *display, bool enable) +{ + int i, rc = 0; + struct dsi_display_ctrl *display_ctrl; + struct dsi_ctrl *ctrl; + struct dsi_panel *panel; + + display_for_each_ctrl(i, display) { + display_ctrl = &display->ctrl[i]; + if (!display_ctrl->ctrl) + continue; + ctrl = display_ctrl->ctrl; + + rc = dsi_pwr_config_vreg_opt_mode(&ctrl->pwr_info.host_pwr, enable); + if (rc) { + DSI_ERR("failed to set ctrl load\n"); + return rc; + } + } + + panel = display->panel; + rc = dsi_pwr_config_vreg_opt_mode(&panel->power_info, enable); + if (rc) { + DSI_ERR("failed to set panel load\n"); + return rc; + } + return rc; +} + static void __set_lane_map_v2(u8 *lane_map_v2, enum dsi_phy_data_lanes lane0, enum dsi_phy_data_lanes lane1, diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index 7ac0c8ba8feb..2dc7bc7dd137 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -628,7 +628,7 @@ int dsi_pre_clkon_cb(void *priv, enum dsi_clk_type clk_type, * Return: error code. */ int dsi_display_unprepare(struct dsi_display *display); - +int dsi_display_set_ulp_load(struct dsi_display *display, bool enable); int dsi_display_set_tpg_state(struct dsi_display *display, bool enable); int dsi_display_clock_gate(struct dsi_display *display, bool enable); diff --git a/msm/dsi/dsi_pwr.c b/msm/dsi/dsi_pwr.c index 7b3f9e2c8541..44bb745ad275 100644 --- a/msm/dsi/dsi_pwr.c +++ b/msm/dsi/dsi_pwr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020,2021 The Linux Foundation. All rights reserved. */ #include @@ -65,6 +65,14 @@ static int dsi_pwr_parse_supply_node(struct dsi_parser_utils *utils, regs->vregs[i].disable_load = tmp; /* Optional values */ + rc = utils->read_u32(node, "qcom,supply-ulp-load", &tmp); + if (rc) { + DSI_DEBUG("ulp-load not specified\n"); + rc = 0; + } + regs->vregs[i].ulp_load = (!rc ? tmp : + regs->vregs[i].enable_load); + rc = utils->read_u32(node, "qcom,supply-off-min-voltage", &tmp); if (rc) { DSI_DEBUG("off-min-voltage not specified\n"); @@ -118,6 +126,30 @@ error: return rc; } +int dsi_pwr_config_vreg_opt_mode(struct dsi_regulator_info *regs, + bool enable) +{ + int i = 0, rc = 0; + struct dsi_vreg *vreg; + u32 mode; + + for (i = 0; i < regs->count; i++) { + vreg = ®s->vregs[i]; + mode = enable ? vreg->ulp_load : vreg->enable_load; + + DSI_DEBUG(" Setting optimum mode for %s load = %d\n", + vreg->vreg_name, mode); + + rc = regulator_set_load(vreg->vreg, mode); + if (rc < 0) { + DSI_ERR("Set opt mode failed for %s", + vreg->vreg_name); + return rc; + } + } + return rc; +} + /** * dsi_pwr_enable_vregs() - enable/disable regulators */ diff --git a/msm/dsi/dsi_pwr.h b/msm/dsi/dsi_pwr.h index fd9ef2c18d8b..8e808b63a2f8 100644 --- a/msm/dsi/dsi_pwr.h +++ b/msm/dsi/dsi_pwr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2019,2021 The Linux Foundation. All rights reserved. */ #ifndef _DSI_PWR_H_ @@ -21,6 +21,7 @@ struct dsi_parser_utils; * @max_voltage: Maximum voltage in uV. * @enable_load: Load, in uA, when enabled. * @disable_load: Load, in uA, when disabled. + * @ulp_load: Load, in uA, when ulp is enabled. * @off_min_voltage: Minimum voltage in uV when regulator is disabled. * @pre_on_sleep: Sleep, in ms, before enabling the regulator. * @post_on_sleep: Sleep, in ms, after enabling the regulator. @@ -34,6 +35,7 @@ struct dsi_vreg { u32 max_voltage; u32 enable_load; u32 disable_load; + u32 ulp_load; u32 off_min_voltage; u32 pre_on_sleep; u32 post_on_sleep; @@ -103,4 +105,13 @@ int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable); int dsi_pwr_panel_regulator_mode_set(struct dsi_regulator_info *regs, const char *reg_name, int regulator_mode); + +/** + * dsi_pwr_config_vreg_opt_mode() + * set regulator load + * @regs: Pointer to set of regulators to enable or disable. + * @enable: enable ulp_load or disable + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_config_vreg_opt_mode(struct dsi_regulator_info *regs, bool enable); #endif /* _DSI_PWR_H_ */ From 070934308cd58693ee33f782facf69e5be0e0f02 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Fri, 8 Oct 2021 10:25:24 +0530 Subject: [PATCH 07/51] disp: msm: sde: protect file private structure with mutex lock Access file private data structures inside the mutex lock only to avoid use-after-free issues. Change-Id: If70731f517bcb47d4515f131fecafe702064cb45 Signed-off-by: Krishna Manikandan --- msm/msm_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 5597b8d72da1..5eb8363e2198 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1488,7 +1488,7 @@ void msm_mode_object_event_notify(struct drm_mode_object *obj, static int msm_release(struct inode *inode, struct file *filp) { - struct drm_file *file_priv = filp->private_data; + struct drm_file *file_priv; struct drm_minor *minor; struct drm_device *dev; struct msm_drm_private *priv; @@ -1500,6 +1500,7 @@ static int msm_release(struct inode *inode, struct file *filp) mutex_lock(&msm_release_lock); + file_priv = filp->private_data; if (!file_priv) { ret = -EINVAL; goto end; From 018e528ec314842739f9a1887b6ea43b83f25ecc Mon Sep 17 00:00:00 2001 From: Mahadevan Date: Mon, 18 Oct 2021 12:10:34 +0530 Subject: [PATCH 08/51] disp: rotator: remove warning log from spin_lock On rotator commit failure resync timeline will happen which gives continuous warning logs in console leads to cpu throttling. To resolve this the warning message is removed from spin_lock. Change-Id: I5ce66413556518668769cad3bc6a900f9bdada4b Signed-off-by: Mahadevan --- rotator/sde_rotator_sync.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rotator/sde_rotator_sync.c b/rotator/sde_rotator_sync.c index 4f7f54aa62f5..75a205791609 100644 --- a/rotator/sde_rotator_sync.c +++ b/rotator/sde_rotator_sync.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -249,11 +249,13 @@ void sde_rotator_resync_timeline(struct sde_rot_timeline *tl) spin_lock_irqsave(&tl->lock, flags); val = tl->next_value - tl->curr_value; - if (val > 0) { - SDEROT_WARN("flush %s:%d\n", tl->name, val); + if (val > 0) sde_rotator_inc_timeline_locked(tl, val); - } spin_unlock_irqrestore(&tl->lock, flags); + + if (val > 0) + SDEROT_WARN("flush %s:%d\n", tl->name, val); + } /* From c667c77f1f80b9a401174011459a255a7a3dfb52 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Mon, 18 Oct 2021 16:40:40 +0530 Subject: [PATCH 09/51] disp: msm: sde: disable CWB crop after cwb session is ended Add changes to disable CWB crop params as part of writeback disable. Change-Id: I18582ceb502e759ec4b67568562ac95ff3f0d359 Signed-off-by: Krishna Manikandan --- msm/sde/sde_encoder_phys_wb.c | 3 +++ msm/sde/sde_hw_wb.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index 58ba064f73ec..43c03e87fb0e 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -1727,6 +1727,9 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc) } if (phys_enc->in_clone_mode) { + if (hw_wb->ops.setup_crop) + hw_wb->ops.setup_crop(hw_wb, NULL, false); + _sde_encoder_phys_wb_setup_cwb(phys_enc, false); _sde_encoder_phys_wb_update_cwb_flush(phys_enc, false); phys_enc->enable_state = SDE_ENC_DISABLING; diff --git a/msm/sde/sde_hw_wb.c b/msm/sde/sde_hw_wb.c index e6c61e68dd27..608d0ea492d7 100644 --- a/msm/sde/sde_hw_wb.c +++ b/msm/sde/sde_hw_wb.c @@ -215,9 +215,8 @@ static void sde_hw_wb_crop(struct sde_hw_wb *ctx, struct sde_hw_wb_cfg *wb, bool struct sde_hw_blk_reg_map *c = &ctx->hw; u32 crop_xy; - crop_xy = (wb->crop.y << 16) | wb->crop.x; - if (crop) { + crop_xy = (wb->crop.y << 16) | wb->crop.x; SDE_REG_WRITE(c, WB_CROP_CTRL, 0x1); SDE_REG_WRITE(c, WB_CROP_OFFSET, crop_xy); } else { From c0783f528e4b851aeafad4d7023bb9bf06b12b6b Mon Sep 17 00:00:00 2001 From: Rajeev Nandan Date: Wed, 6 Oct 2021 20:59:56 +0530 Subject: [PATCH 10/51] disp: msm: dsi: Do not call devm_clk_put() with invalid clk Do not call devm_clk_put() if devm_clk_get() was failed for a given clk. The devm_clk_put() does not check for the validity of the input clk argumnet, and can cause NULL pointer dereference or some other errors if called with invalid clk argument. Change-Id: Ie626a5afed52a146ebd1a2092c7d9db9226dbfe0 Signed-off-by: Rajeev Nandan --- msm/dsi/dsi_ctrl.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 506181bc8776..89092690a678 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -657,34 +657,34 @@ static int dsi_ctrl_clocks_deinit(struct dsi_ctrl *ctrl) struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks; struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks; - if (core->mdp_core_clk) + if (!IS_ERR_OR_NULL(core->mdp_core_clk)) devm_clk_put(&ctrl->pdev->dev, core->mdp_core_clk); - if (core->iface_clk) + if (!IS_ERR_OR_NULL(core->iface_clk)) devm_clk_put(&ctrl->pdev->dev, core->iface_clk); - if (core->core_mmss_clk) + if (!IS_ERR_OR_NULL(core->core_mmss_clk)) devm_clk_put(&ctrl->pdev->dev, core->core_mmss_clk); - if (core->bus_clk) + if (!IS_ERR_OR_NULL(core->bus_clk)) devm_clk_put(&ctrl->pdev->dev, core->bus_clk); - if (core->mnoc_clk) + if (!IS_ERR_OR_NULL(core->mnoc_clk)) devm_clk_put(&ctrl->pdev->dev, core->mnoc_clk); memset(core, 0x0, sizeof(*core)); - if (hs_link->byte_clk) + if (!IS_ERR_OR_NULL(hs_link->byte_clk)) devm_clk_put(&ctrl->pdev->dev, hs_link->byte_clk); - if (hs_link->pixel_clk) + if (!IS_ERR_OR_NULL(hs_link->pixel_clk)) devm_clk_put(&ctrl->pdev->dev, hs_link->pixel_clk); - if (lp_link->esc_clk) + if (!IS_ERR_OR_NULL(lp_link->esc_clk)) devm_clk_put(&ctrl->pdev->dev, lp_link->esc_clk); - if (hs_link->byte_intf_clk) + if (!IS_ERR_OR_NULL(hs_link->byte_intf_clk)) devm_clk_put(&ctrl->pdev->dev, hs_link->byte_intf_clk); memset(hs_link, 0x0, sizeof(*hs_link)); memset(lp_link, 0x0, sizeof(*lp_link)); - if (rcg->byte_clk) + if (!IS_ERR_OR_NULL(rcg->byte_clk)) devm_clk_put(&ctrl->pdev->dev, rcg->byte_clk); - if (rcg->pixel_clk) + if (!IS_ERR_OR_NULL(rcg->pixel_clk)) devm_clk_put(&ctrl->pdev->dev, rcg->pixel_clk); memset(rcg, 0x0, sizeof(*rcg)); From 1cbd7ae15233d7712e57028be43c62ccaf4bbb5d Mon Sep 17 00:00:00 2001 From: Soutrik Mukhopadhyay Date: Tue, 19 Oct 2021 19:02:58 +0530 Subject: [PATCH 11/51] disp: msm: dp: replace pr_err with DP_ERR This change replaces pr_err with DP_ERR in dp_display driver source code. Change-Id: I5c621ead001c5b9364511495fceba1aa7f41488d Signed-off-by: Soutrik Mukhopadhyay --- msm/dp/dp_display.c | 2 +- msm/dp/dp_drm.c | 4 ++-- msm/dp/dp_panel.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 62544f4d6f73..3e0fdbd26fce 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -3051,7 +3051,7 @@ static int dp_display_setup_colospace(struct dp_display *dp_display, struct dp_display_private *dp; if (!dp_display || !panel) { - pr_err("invalid input\n"); + DP_ERR("invalid input\n"); return -EINVAL; } diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index f1e870af0811..3c29801249c3 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ #include @@ -336,7 +336,7 @@ int dp_connector_set_colorspace(struct drm_connector *connector, sde_conn = to_sde_connector(connector); if (!sde_conn->drv_panel) { - pr_err("invalid dp panel\n"); + DP_ERR("invalid dp panel\n"); return -EINVAL; } diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 0d63f3aa230a..5369ab30bdb4 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ #include "dp_panel.h" @@ -2571,7 +2571,7 @@ static int dp_panel_set_colorspace(struct dp_panel *dp_panel, struct dp_panel_private *panel; if (!dp_panel) { - pr_err("invalid input\n"); + DP_ERR("invalid input\n"); rc = -EINVAL; goto end; } From c03772f2f2d19c5b17c224819ef8958ea3bd5ba5 Mon Sep 17 00:00:00 2001 From: Kalyan Thota Date: Tue, 19 Oct 2021 23:28:30 -0700 Subject: [PATCH 12/51] msm: disp: rotator: add ROT macros for logs Avoid pr_err and use SDEROT macros for console logging. Change-Id: I4c0c6cf1d482a55f82c73572b1327695b85c5501 Signed-off-by: Kalyan Thota --- rotator/sde_rotator_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rotator/sde_rotator_base.c b/rotator/sde_rotator_base.c index 76681b967761..f17905a9b057 100644 --- a/rotator/sde_rotator_base.c +++ b/rotator/sde_rotator_base.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012, 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2012, 2015-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -79,7 +79,7 @@ u32 sde_apply_comp_ratio_factor(u32 quota, return quota; } -#define RES_1080p (1088*1920) +#define RES_1080p (1088*1920) #define RES_UHD (3840*2160) #define RES_WQXGA (2560*1600) #define XIN_HALT_TIMEOUT_US 0x4000 @@ -507,10 +507,10 @@ int sde_update_reg_bus_vote(struct reg_bus_client *bus_client, u32 usecase_ndx) } if (ret) { - pr_err("rotator: reg_bus_hdl set failed ab=%llu, ib=%llu\n", + SDEROT_ERR("rotator: reg_bus_hdl set failed ab=%llu, ib=%llu\n", reg_bus_value->ab, reg_bus_value->ib); if (sde_res->reg_bus_usecase_ndx == VOTE_INDEX_DISABLE) - pr_err("rotator: reg_bus_hdl was disabled\n"); + SDEROT_ERR("rotator: reg_bus_hdl was disabled\n"); } else { sde_res->reg_bus_usecase_ndx = max_usecase_ndx; } @@ -841,7 +841,7 @@ static int sde_mdp_bus_scale_register(struct sde_rot_data_type *mdata) mdata->reg_bus_hdl = of_icc_get(&mdata->pdev->dev, "qcom,sde-reg-bus"); if (mdata->reg_bus_hdl == NULL) { - pr_err("rotator: reg bus dt node missing\n"); + SDEROT_ERR("rotator: reg bus dt node missing\n"); return 0; } else if (IS_ERR(mdata->reg_bus_hdl)) { SDEROT_ERR("reg bus handle parsing failed\n"); From cf6ecb421493de16684a0a2ae4b89cb13c544dd0 Mon Sep 17 00:00:00 2001 From: Andhavarapu Karthik Date: Wed, 20 Oct 2021 12:55:53 +0530 Subject: [PATCH 13/51] disp: msm: sde: add evt log in rsc timer calculation This change adds required log in rsc timer calculation. Change-Id: If16487ae8783651b3a2ac4839928a15131b678ee Signed-off-by: Andhavarapu Karthik --- msm/sde_rsc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index 75dcb932a77d..4b4c13bca0a5 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -352,6 +352,8 @@ static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc, line_time_ns, prefill_time_ns); pr_debug("static wakeup time:%lld cxo:%u\n", total, cxo_period_ns); + SDE_EVT32(rsc->cmd_config.fps, rsc->cmd_config.vtotal, total); + pdc_backoff_time_ns = rsc_backoff_time_ns; rsc_backoff_time_ns = div_u64(rsc_backoff_time_ns, cxo_period_ns); rsc->timer_config.rsc_backoff_time_ns = (u32) rsc_backoff_time_ns; From a245be26e4170d71593f5bda62664b14c168a620 Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Thu, 30 Sep 2021 20:41:20 +0530 Subject: [PATCH 14/51] disp: msm: sde: add changes to allocate compatible cwb mixers in RM This change parses new dt property CWB_MIXER_MASK, which signifies the compatible mixer_mask for the corresponding CWB block. During mixer allocation for CWB usecase, we use this cwb_mixer_mask to decide compatible mixers for built-in primary and secondary displays. In the current issue case, mixer allocation is as below in multi display usecase: primary: LM0 secondary: LM1 external: LM2 RM loops through available mixers and tries to allocate LM3 when CWB is triggered on primary display. But from HW perspective, LM0 is not muxed to LM3 causing wb timeouts. With current change LM3 gets skipped and LM4 gets allocated. Change-Id: I95ce16a083c9b9976a9dff309d7754085ee08958 Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_connector.c | 2 +- msm/sde/sde_connector.h | 1 + msm/sde/sde_encoder.c | 6 +-- msm/sde/sde_encoder.h | 8 ++-- msm/sde/sde_hw_catalog.c | 13 +++++- msm/sde/sde_hw_catalog.h | 6 ++- msm/sde/sde_rm.c | 90 ++++++++++++++++++++++++++++------------ 7 files changed, 87 insertions(+), 39 deletions(-) diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index a6de23aab43b..013ebf81887f 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1833,7 +1833,7 @@ static int _sde_connector_lm_preference(struct sde_connector *sde_conn, return -EINVAL; } - sde_hw_mixer_set_preference(sde_kms->catalog, num_lm, disp_type); + sde_conn->lm_mask = sde_hw_mixer_set_preference(sde_kms->catalog, num_lm, disp_type); return ret; } diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 94f868ccff29..2407b7efed42 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -547,6 +547,7 @@ struct sde_connector { bool hdr_supported; u32 color_enc_fmt; + u32 lm_mask; u8 hdr_plus_app_ver; u32 qsync_mode; diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index dd3b2cc033da..c334b11ae77c 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -267,13 +267,11 @@ static int _sde_encoder_wait_timeout(int32_t drm_id, int32_t hw_id, return rc; } -bool sde_encoder_is_primary_display(struct drm_encoder *drm_enc) +u32 sde_encoder_get_display_type(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); - return sde_enc && - (sde_enc->disp_info.display_type == - SDE_CONNECTOR_PRIMARY); + return sde_enc ? sde_enc->disp_info.display_type : 0; } bool sde_encoder_is_dsi_display(struct drm_encoder *drm_enc) diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 27116034c11b..3bd432072c8b 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -523,12 +523,12 @@ bool sde_encoder_is_cwb_disabling(struct drm_encoder *drm_enc, struct drm_crtc *drm_crtc); /** - * sde_encoder_is_primary_display - checks if underlying display is primary - * display or not. + * sde_encoder_get_display_type - returns the display_type of underlying + * display * @drm_enc: Pointer to drm encoder structure - * @Return: true if it is primary display. false if secondary display + * @Return: display_type */ -bool sde_encoder_is_primary_display(struct drm_encoder *enc); +u32 sde_encoder_get_display_type(struct drm_encoder *enc); /** * sde_encoder_is_dsi_display - checks if underlying display is DSI diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 51875f9cd02f..f19c495ed440 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -425,6 +425,7 @@ enum { MIXER_BLOCKS, MIXER_DISP, MIXER_CWB, + MIXER_CWB_MASK, MIXER_PROP_MAX, }; @@ -710,6 +711,7 @@ static struct sde_prop_type mixer_prop[] = { PROP_TYPE_STRING_ARRAY}, {MIXER_CWB, "qcom,sde-mixer-cwb-pref", false, PROP_TYPE_STRING_ARRAY}, + {MIXER_CWB_MASK, "qcom,sde-mixer-cwb-mask", false, PROP_TYPE_U32_ARRAY}, }; static struct sde_prop_type mixer_blocks_prop[] = { @@ -1976,10 +1978,10 @@ void sde_hw_ctl_set_preference(struct sde_mdss_cfg *sde_cfg, } } -void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, +u32 sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, uint32_t disp_type) { - u32 i, cnt = 0, sec_cnt = 0; + u32 i, cnt = 0, sec_cnt = 0, lm_mask = 0; if (disp_type == SDE_CONNECTOR_PRIMARY) { for (i = 0; i < sde_cfg->mixer_count; i++) { @@ -1998,6 +2000,7 @@ void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, if (cnt < num_lm) { set_bit(SDE_DISP_PRIMARY_PREF, &sde_cfg->mixer[i].features); + lm_mask |= BIT(sde_cfg->mixer[i].id - 1); cnt++; } @@ -2036,10 +2039,13 @@ void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, BIT(SDE_DISP_PRIMARY_PREF))) { set_bit(SDE_DISP_SECONDARY_PREF, &sde_cfg->mixer[i].features); + lm_mask |= BIT(sde_cfg->mixer[i].id - 1); cnt++; } } } + + return lm_mask; } static int sde_mixer_parse_dt(struct device_node *np, @@ -2151,6 +2157,9 @@ static int sde_mixer_parse_dt(struct device_node *np, if (BIT(mixer->id - LM_0) & sde_cfg->cwb_virtual_mixers_mask) set_bit(SDE_MIXER_IS_VIRTUAL, &mixer->features); + mixer->cwb_mask = !props->exists[MIXER_CWB_MASK] ? 0x0 : + PROP_VALUE_ACCESS(props->values, MIXER_CWB_MASK, i); + mixer->pingpong = pp_count > 0 ? pp_idx + PINGPONG_0 : PINGPONG_MAX; mixer->dspp = dspp_count > 0 ? dspp_idx + DSPP_0 diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 4ba0764ac7b3..3e7ab2ad90d2 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -977,6 +977,7 @@ struct sde_sspp_cfg { * @pingpong: ID of connected PingPong, PINGPONG_MAX if unsupported * @ds: ID of connected DS, DS_MAX if unsupported * @lm_pair_mask: Bitmask of LMs that can be controlled by same CTL + * @cwb_mask: Bitmask of LMs connected to cwb mux from this LM id */ struct sde_lm_cfg { SDE_HW_BLK_INFO; @@ -985,6 +986,7 @@ struct sde_lm_cfg { u32 pingpong; u32 ds; unsigned long lm_pair_mask; + u32 cwb_mask; }; /** @@ -1641,8 +1643,10 @@ struct sde_mdss_hw_cfg_handler { * @sde_cfg: pointer to sspp cfg * @num_lm: num lms to set preference * @disp_type: is the given display primary/secondary + * + * Return: layer mixer mask allocated for the disp_type */ -void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, +u32 sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, uint32_t disp_type); /** diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index dafddd66f6ec..4367cf9d2055 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -111,6 +111,8 @@ struct sde_rm_requirements { uint64_t top_ctrl; const struct sde_rm_topology_def *topology; struct sde_encoder_hw_resources hw_res; + u32 cwb_requested_disp_type; + u32 conn_lm_mask; }; /** @@ -981,7 +983,8 @@ static bool _sde_rm_check_lm_and_get_connected_blks( struct sde_rm_hw_blk **dspp, struct sde_rm_hw_blk **ds, struct sde_rm_hw_blk **pp, - struct sde_rm_hw_blk *primary_lm) + struct sde_rm_hw_blk *primary_lm, + u32 conn_lm_mask) { const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap; const struct sde_pingpong_cfg *pp_cfg; @@ -1038,6 +1041,13 @@ static bool _sde_rm_check_lm_and_get_connected_blks( SDE_DEBUG("fail: cwb supported lm not allocated\n"); return false; } + + if (lm_cfg->cwb_mask && RM_RQ_CWB(reqs) && + !(BIT(ffs(conn_lm_mask) - 1) & lm_cfg->cwb_mask)) { + SDE_DEBUG("cwb mixer not compatible id:%d cwb_mask:0x%x lm_mask:0x%x\n", + lm_cfg->id, lm_cfg->cwb_mask, conn_lm_mask); + return false; + } } else if ((!is_conn_primary && lm_primary_pref) || (!is_conn_secondary && lm_secondary_pref)) { SDE_DEBUG( @@ -1083,7 +1093,7 @@ static int _sde_rm_reserve_lms( struct sde_rm_hw_blk *ds[MAX_BLOCKS]; struct sde_rm_hw_blk *pp[MAX_BLOCKS]; struct sde_rm_hw_iter iter_i, iter_j; - u32 lm_mask = 0; + u32 lm_mask = 0, conn_lm_mask = 0; int lm_count = 0; int i, rc = 0; @@ -1092,6 +1102,9 @@ static int _sde_rm_reserve_lms( return 0; } + if (RM_RQ_CWB(reqs)) + conn_lm_mask = reqs->conn_lm_mask; + /* Find a primary mixer */ sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_LM); while (lm_count != reqs->topology->num_lm && @@ -1115,12 +1128,15 @@ static int _sde_rm_reserve_lms( if (!_sde_rm_check_lm_and_get_connected_blks( rm, rsvp, reqs, lm[lm_count], &dspp[lm_count], &ds[lm_count], - &pp[lm_count], NULL)) + &pp[lm_count], NULL, conn_lm_mask)) continue; lm_mask |= (1 << iter_i.blk->id); ++lm_count; + if (RM_RQ_CWB(reqs)) + conn_lm_mask = conn_lm_mask & ~BIT(ffs(conn_lm_mask) - 1); + /* Return if peer is not needed */ if (lm_count == reqs->topology->num_lm) break; @@ -1140,7 +1156,7 @@ static int _sde_rm_reserve_lms( if (!_sde_rm_check_lm_and_get_connected_blks( rm, rsvp, reqs, iter_j.blk, &dspp[lm_count], &ds[lm_count], - &pp[lm_count], iter_i.blk)) + &pp[lm_count], iter_i.blk, conn_lm_mask)) continue; SDE_DEBUG("blk id = %d, _lm_ids[%d] = %d\n", @@ -1153,6 +1169,10 @@ static int _sde_rm_reserve_lms( lm_mask |= (1 << iter_j.blk->id); ++lm_count; + + if (RM_RQ_CWB(reqs)) + conn_lm_mask = conn_lm_mask & ~BIT(ffs(conn_lm_mask) - 1); + break; } @@ -2005,6 +2025,26 @@ int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, return 0; } +static struct drm_connector *_sde_rm_get_connector( + struct drm_encoder *enc) +{ + struct drm_connector *conn = NULL, *conn_search; + struct sde_connector *c_conn = NULL; + struct drm_connector_list_iter conn_iter; + + drm_connector_list_iter_begin(enc->dev, &conn_iter); + drm_for_each_connector_iter(conn_search, &conn_iter) { + c_conn = to_sde_connector(conn_search); + if (c_conn->encoder == enc) { + conn = conn_search; + break; + } + } + drm_connector_list_iter_end(&conn_iter); + + return conn; +} + static int _sde_rm_populate_requirements( struct sde_rm *rm, struct drm_encoder *enc, @@ -2013,6 +2053,8 @@ static int _sde_rm_populate_requirements( struct sde_rm_requirements *reqs) { const struct drm_display_mode *mode = &crtc_state->mode; + struct drm_encoder *encoder_iter; + struct drm_connector *conn; int i, num_lm; reqs->top_ctrl = sde_connector_get_property(conn_state, @@ -2041,7 +2083,7 @@ static int _sde_rm_populate_requirements( reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DSPP); if (!RM_RQ_DS(reqs) && rm->hw_mdp->caps->has_dest_scaler && - sde_encoder_is_primary_display(enc)) + (sde_encoder_get_display_type(enc) == SDE_CONNECTOR_PRIMARY)) reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DS); } @@ -2075,8 +2117,22 @@ static int _sde_rm_populate_requirements( reqs->topology->top_name, reqs->topology->num_ctl); } - SDE_DEBUG("top_ctrl: 0x%llX num_h_tiles: %d\n", reqs->top_ctrl, - reqs->hw_res.display_num_of_h_tiles); + if (RM_RQ_CWB(reqs)) { + drm_for_each_encoder_mask(encoder_iter, enc->dev, + crtc_state->encoder_mask) { + if (drm_encoder_mask(encoder_iter) == drm_encoder_mask(enc)) + continue; + + reqs->cwb_requested_disp_type = sde_encoder_get_display_type(encoder_iter); + conn = _sde_rm_get_connector(encoder_iter); + if (conn) + reqs->conn_lm_mask = to_sde_connector(conn)->lm_mask; + break; + } + } + + SDE_DEBUG("top_ctrl: 0x%llX num_h_tiles: %d cwb_req_disp_type:%d\n", reqs->top_ctrl, + reqs->hw_res.display_num_of_h_tiles, reqs->cwb_requested_disp_type); SDE_DEBUG("num_lm: %d num_ctl: %d topology: %d split_display: %d\n", reqs->topology->num_lm, reqs->topology->num_ctl, reqs->topology->top_name, @@ -2120,26 +2176,6 @@ static struct sde_rm_rsvp *_sde_rm_get_rsvp_cur(struct sde_rm *rm, return _sde_rm_get_rsvp(rm, enc, false); } -static struct drm_connector *_sde_rm_get_connector( - struct drm_encoder *enc) -{ - struct drm_connector *conn = NULL, *conn_search; - struct sde_connector *c_conn = NULL; - struct drm_connector_list_iter conn_iter; - - drm_connector_list_iter_begin(enc->dev, &conn_iter); - drm_for_each_connector_iter(conn_search, &conn_iter) { - c_conn = to_sde_connector(conn_search); - if (c_conn->encoder == enc) { - conn = conn_search; - break; - } - } - drm_connector_list_iter_end(&conn_iter); - - return conn; -} - int sde_rm_update_topology(struct sde_rm *rm, struct drm_connector_state *conn_state, struct msm_display_topology *topology) From d7a8169269ce8b4a29d09e4cc3ae22be665efb2d Mon Sep 17 00:00:00 2001 From: Mahadevan Date: Tue, 26 Oct 2021 16:58:24 +0530 Subject: [PATCH 15/51] disp: rotator: remove ubwc format support for rotator This change removes ubwc formats from input and output for the holi and blair target which do not support ubwc for offline roation. Change-Id: I34f8f3e6db5e7f8f63bb3948c69f810342b7c0ea Signed-off-by: Mahadevan --- rotator/sde_rotator_r3.c | 170 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 166 insertions(+), 4 deletions(-) diff --git a/rotator/sde_rotator_r3.c b/rotator/sde_rotator_r3.c index 19100a5bcd49..b1e2f15a4b84 100644 --- a/rotator/sde_rotator_r3.c +++ b/rotator/sde_rotator_r3.c @@ -406,6 +406,168 @@ static const u32 sde_hw_rotator_v4_outpixfmts[] = { SDE_PIX_FMT_XBGR_2101010_TILE, }; +static const u32 sde_hw_rotator_v5_inpixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + SDE_PIX_FMT_Y_CB_CR_H2V2, + SDE_PIX_FMT_Y_CR_CB_H2V2, + SDE_PIX_FMT_Y_CR_CB_GH2V2, + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + SDE_PIX_FMT_YCBYCR_H2V1, + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + /* SDE_PIX_FMT_RGBA_8888_UBWC */ + /* SDE_PIX_FMT_RGBX_8888_UBWC */ + /* SDE_PIX_FMT_RGB_565_UBWC */ + /* SDE_PIX_FMT_Y_CBCR_H2V2_UBWC */ + SDE_PIX_FMT_RGBA_1010102, + SDE_PIX_FMT_RGBX_1010102, + SDE_PIX_FMT_ARGB_2101010, + SDE_PIX_FMT_XRGB_2101010, + SDE_PIX_FMT_BGRA_1010102, + SDE_PIX_FMT_BGRX_1010102, + SDE_PIX_FMT_ABGR_2101010, + SDE_PIX_FMT_XBGR_2101010, + /* SDE_PIX_FMT_RGBA_1010102_UBWC */ + /* SDE_PIX_FMT_RGBX_1010102_UBWC */ + SDE_PIX_FMT_Y_CBCR_H2V2_P010, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + /* SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC */ + /* SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC */ + SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE, + SDE_PIX_FMT_Y_CBCR_H2V2_TILE, + SDE_PIX_FMT_Y_CRCB_H2V2_TILE, + SDE_PIX_FMT_XRGB_8888_TILE, + SDE_PIX_FMT_ARGB_8888_TILE, + SDE_PIX_FMT_ABGR_8888_TILE, + SDE_PIX_FMT_XBGR_8888_TILE, + SDE_PIX_FMT_RGBA_8888_TILE, + SDE_PIX_FMT_BGRA_8888_TILE, + SDE_PIX_FMT_RGBX_8888_TILE, + SDE_PIX_FMT_BGRX_8888_TILE, + SDE_PIX_FMT_RGBA_1010102_TILE, + SDE_PIX_FMT_RGBX_1010102_TILE, + SDE_PIX_FMT_ARGB_2101010_TILE, + SDE_PIX_FMT_XRGB_2101010_TILE, + SDE_PIX_FMT_BGRA_1010102_TILE, + SDE_PIX_FMT_BGRX_1010102_TILE, + SDE_PIX_FMT_ABGR_2101010_TILE, + SDE_PIX_FMT_XBGR_2101010_TILE, +}; + +static const u32 sde_hw_rotator_v5_outpixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + /* SDE_PIX_FMT_Y_CB_CR_H2V2 */ + /* SDE_PIX_FMT_Y_CR_CB_H2V2 */ + /* SDE_PIX_FMT_Y_CR_CB_GH2V2 */ + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + /* SDE_PIX_FMT_YCBYCR_H2V1 */ + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + /* SDE_PIX_FMT_RGBA_8888_UBWC */ + /* SDE_PIX_FMT_RGBX_8888_UBWC */ + /* SDE_PIX_FMT_RGB_565_UBWC */ + /* SDE_PIX_FMT_Y_CBCR_H2V2_UBWC */ + SDE_PIX_FMT_RGBA_1010102, + SDE_PIX_FMT_RGBX_1010102, + SDE_PIX_FMT_ARGB_2101010, + SDE_PIX_FMT_XRGB_2101010, + SDE_PIX_FMT_BGRA_1010102, + SDE_PIX_FMT_BGRX_1010102, + SDE_PIX_FMT_ABGR_2101010, + SDE_PIX_FMT_XBGR_2101010, + /* SDE_PIX_FMT_RGBA_1010102_UBWC */ + /* SDE_PIX_FMT_RGBX_1010102_UBWC */ + SDE_PIX_FMT_Y_CBCR_H2V2_P010, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + /* SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC */ + /* SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC */ + SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE, + SDE_PIX_FMT_Y_CBCR_H2V2_TILE, + SDE_PIX_FMT_Y_CRCB_H2V2_TILE, + SDE_PIX_FMT_XRGB_8888_TILE, + SDE_PIX_FMT_ARGB_8888_TILE, + SDE_PIX_FMT_ABGR_8888_TILE, + SDE_PIX_FMT_XBGR_8888_TILE, + SDE_PIX_FMT_RGBA_8888_TILE, + SDE_PIX_FMT_BGRA_8888_TILE, + SDE_PIX_FMT_RGBX_8888_TILE, + SDE_PIX_FMT_BGRX_8888_TILE, + SDE_PIX_FMT_RGBA_1010102_TILE, + SDE_PIX_FMT_RGBX_1010102_TILE, + SDE_PIX_FMT_ARGB_2101010_TILE, + SDE_PIX_FMT_XRGB_2101010_TILE, + SDE_PIX_FMT_BGRA_1010102_TILE, + SDE_PIX_FMT_BGRX_1010102_TILE, + SDE_PIX_FMT_ABGR_2101010_TILE, + SDE_PIX_FMT_XBGR_2101010_TILE, +}; + static const u32 sde_hw_rotator_v4_inpixfmts_sbuf[] = { SDE_PIX_FMT_Y_CBCR_H2V2_P010, SDE_PIX_FMT_Y_CBCR_H2V2, @@ -3507,13 +3669,13 @@ static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot) set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map); set_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map); rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = - sde_hw_rotator_v4_inpixfmts; + sde_hw_rotator_v5_inpixfmts; rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = - ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts); + ARRAY_SIZE(sde_hw_rotator_v5_inpixfmts); rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = - sde_hw_rotator_v4_outpixfmts; + sde_hw_rotator_v5_outpixfmts; rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = - ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts); + ARRAY_SIZE(sde_hw_rotator_v5_outpixfmts); rot->downscale_caps = "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; } else { From b71e9dc15f5a0ed1e427eddfb4acc7d651eb586e Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Mon, 1 Nov 2021 15:01:42 +0530 Subject: [PATCH 16/51] disp: msm: sde: avoid rsvp_nxt allocation for suspend commit During suspend commit, crtc_commit thread is blocked waiting for touch response in drm_panel_notifier_call_chain and rsvp_nxt pointer clear in drm_atomic_state_put is pending (>100ms wait) which was allocated in atomic_check. When resume commit is triggered early, RM poll timeouts are seen due to rsvp_nxt pointer is not cleared and thus causing power on commit failures. This change avoids RM reserve during atomic_check of suspend commit as msm_crtc_set_mode returns early and rsvp_nxt is not used elsewhere in commit path. Change-Id: I4e7bb41d38f5b88ee75f63007dc4403b6b903265 Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_encoder.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c334b11ae77c..9cb8fc2c9229 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -918,9 +918,10 @@ static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc, } /* Skip RM allocation for Primary during CWB usecase */ - if (!crtc_state->mode_changed && !crtc_state->active_changed && + if ((!crtc_state->mode_changed && !crtc_state->active_changed && crtc_state->connectors_changed && (conn_state->crtc == - conn_state->connector->state->crtc)) + conn_state->connector->state->crtc)) || + (crtc_state->active_changed && !crtc_state->active)) goto skip_reserve; /* Reserve dynamic resources, indicating atomic_check phase */ From c56edb2f47142582b616621bb7e2577e023f2131 Mon Sep 17 00:00:00 2001 From: Rajeev Nandan Date: Thu, 7 Oct 2021 23:11:32 +0530 Subject: [PATCH 17/51] disp: msm: dsi: Support uncompressed rgb101010 format Add support for uncompressed rgb101010 format. Change-Id: I60c2f7817eb2ea3e462c4692b1beb7f523836326 Signed-off-by: Rajeev Nandan Signed-off-by: Ritesh Kumar --- msm/dsi/dsi_ctrl.c | 3 +++ msm/dsi/dsi_ctrl_hw_cmn.c | 13 ++++++++----- msm/dsi/dsi_defs.h | 4 ++++ msm/dsi/dsi_panel.c | 3 +++ msm/dsi/dsi_phy_timing_calc.c | 4 ++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 89092690a678..1040b4f5fb0c 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -933,6 +933,9 @@ int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format) case DSI_PIXEL_FORMAT_RGB888: bpp = 24; break; + case DSI_PIXEL_FORMAT_RGB101010: + bpp = 30; + break; default: bpp = 24; break; diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index 59281c045075..dceee163c15e 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -41,9 +41,9 @@ static bool dsi_compression_enabled(struct dsi_mode_info *mode) /* Unsupported formats default to RGB888 */ static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { - 0x6, 0x7, 0x8, 0x8, 0x0, 0x3, 0x4 }; + 0x6, 0x7, 0x8, 0x8, 0x0, 0x3, 0x4, 0x9 }; static const u8 video_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { - 0x0, 0x1, 0x2, 0x3, 0x3, 0x3, 0x3 }; + 0x0, 0x1, 0x2, 0x3, 0x3, 0x3, 0x3, 0x4 }; /** * dsi_split_link_setup() - setup dsi split link configurations @@ -421,10 +421,13 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, u32 reg = 0, offset = 0; int pic_width = 0, this_frame_slices = 0, intf_ip_w = 0; u32 pkt_per_line = 0, eol_byte_num = 0, bytes_in_slice = 0; + u32 bpp; if (roi && (!roi->w || !roi->h)) return; + bpp = dsi_pixel_format_to_bpp(cfg->dst_format); + if (dsi_dsc_compression_enabled(mode)) { struct msm_display_dsc_info dsc; @@ -458,11 +461,11 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, bytes_in_slice = vdc.bytes_in_slice; } else if (roi) { width_final = roi->w; - stride_final = roi->w * 3; + stride_final = DIV_ROUND_UP(roi->w * bpp, 8); height_final = roi->h; } else { width_final = mode->h_active; - stride_final = mode->h_active * 3; + stride_final = DIV_ROUND_UP(mode->h_active * bpp, 8); height_final = mode->v_active; } @@ -579,7 +582,7 @@ void dsi_ctrl_hw_cmn_video_engine_setup(struct dsi_ctrl_hw *ctrl, reg |= (cfg->bllp_lp11_en ? BIT(12) : 0); reg |= (cfg->traffic_mode & 0x3) << 8; reg |= (cfg->vc_id & 0x3); - reg |= (video_mode_format_map[common_cfg->dst_format] & 0x3) << 4; + reg |= (video_mode_format_map[common_cfg->dst_format] & 0x7) << 4; DSI_W32(ctrl, DSI_VIDEO_MODE_CTRL, reg); reg = (common_cfg->swap_mode & 0x7) << 12; diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 41dee2f61823..892334fc1315 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -39,6 +39,7 @@ * @DSI_PIXEL_FORMAT_RGB111: * @DSI_PIXEL_FORMAT_RGB332: * @DSI_PIXEL_FORMAT_RGB444: + * @DSI_PIXEL_FORMAT_RGB101010: * @DSI_PIXEL_FORMAT_MAX: */ enum dsi_pixel_format { @@ -49,6 +50,7 @@ enum dsi_pixel_format { DSI_PIXEL_FORMAT_RGB111, DSI_PIXEL_FORMAT_RGB332, DSI_PIXEL_FORMAT_RGB444, + DSI_PIXEL_FORMAT_RGB101010, DSI_PIXEL_FORMAT_MAX }; @@ -740,6 +742,8 @@ static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt) return 8; case DSI_PIXEL_FORMAT_RGB444: return 12; + case DSI_PIXEL_FORMAT_RGB101010: + return 30; } return 24; } diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index cdde192e19ac..f71718443dda 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -929,6 +929,9 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, case 18: fmt = DSI_PIXEL_FORMAT_RGB666; break; + case 30: + fmt = DSI_PIXEL_FORMAT_RGB101010; + break; case 24: default: fmt = DSI_PIXEL_FORMAT_RGB888; diff --git a/msm/dsi/dsi_phy_timing_calc.c b/msm/dsi/dsi_phy_timing_calc.c index 6e2a625a3572..6efc8d781265 100644 --- a/msm/dsi/dsi_phy_timing_calc.c +++ b/msm/dsi/dsi_phy_timing_calc.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #include "dsi_phy_timing_calc.h" static const u32 bits_per_pixel[DSI_PIXEL_FORMAT_MAX] = { - 16, 18, 18, 24, 3, 8, 12 }; + 16, 18, 18, 24, 3, 8, 12, 30 }; static int dsi_phy_cmn_validate_and_set(struct timing_entry *t, char const *t_name) From 0dd45aa272dcd4f6247ba29a7b26be929960dc57 Mon Sep 17 00:00:00 2001 From: osaisruj Date: Sun, 17 Oct 2021 15:53:40 +0530 Subject: [PATCH 18/51] disp: msm: sde: add sysfs node to give panel power state Add sysfs node on connecter to get the panel power state. This node is used by the HAL to read display power state. Change-Id: I717e4b87513a845c867871f93876fc7c88ff7b2f Signed-off-by: osaisruj --- msm/sde/sde_connector.c | 62 +++++++++++++++++++++++++++++++++++++++++ msm/sde/sde_connector.h | 10 +++++++ msm/sde/sde_kms.c | 6 ++++ 3 files changed, 78 insertions(+) diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 013ebf81887f..6c6a5a6e3585 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1026,6 +1026,9 @@ void sde_connector_destroy(struct drm_connector *connector) c_conn = to_sde_connector(connector); + if (c_conn->sysfs_dev) + device_unregister(c_conn->sysfs_dev); + /* cancel if any pending esd work */ sde_connector_schedule_status_work(connector, false); @@ -2845,6 +2848,65 @@ static int _sde_connector_install_properties(struct drm_device *dev, return 0; } +static ssize_t panel_power_state_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *conn; + struct sde_connector *sde_conn; + + conn = dev_get_drvdata(device); + sde_conn = to_sde_connector(conn); + + return scnprintf(buf, PAGE_SIZE, "%d\n", sde_conn->last_panel_power_mode); +} + +static DEVICE_ATTR_RO(panel_power_state); + +static struct attribute *sde_connector_dev_attrs[] = { + &dev_attr_panel_power_state.attr, + NULL +}; + +static const struct attribute_group sde_connector_attr_group = { + .attrs = sde_connector_dev_attrs, +}; +static const struct attribute_group *sde_connector_attr_groups[] = { + &sde_connector_attr_group, + NULL, +}; + +int sde_connector_post_init(struct drm_device *dev, struct drm_connector *conn) +{ + struct sde_connector *c_conn; + int rc = 0; + + if (!dev || !dev->primary || !dev->primary->kdev || !conn) { + SDE_ERROR("invalid input param(s)\n"); + rc = -EINVAL; + return rc; + } + + c_conn = to_sde_connector(conn); + + if (conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return rc; + + c_conn->sysfs_dev = + device_create_with_groups(dev->primary->kdev->class, dev->primary->kdev, 0, + conn, sde_connector_attr_groups, "sde-conn-%d-%s", conn->index, + conn->name); + if (IS_ERR_OR_NULL(c_conn->sysfs_dev)) { + SDE_ERROR("connector:%d sysfs create failed rc:%ld\n", &c_conn->base.index, + PTR_ERR(c_conn->sysfs_dev)); + if (!c_conn->sysfs_dev) + rc = -EINVAL; + else + rc = PTR_ERR(c_conn->sysfs_dev); + } + + return rc; +} + struct drm_connector *sde_connector_init(struct drm_device *dev, struct drm_encoder *encoder, struct drm_panel *panel, diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 2407b7efed42..3caa1fa60666 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -511,6 +511,7 @@ struct sde_connector { int dpms_mode; int lp_mode; int last_panel_power_mode; + struct device *sysfs_dev; struct msm_property_info property_info; struct msm_property_data property_data[CONNECTOR_PROP_COUNT]; @@ -753,6 +754,15 @@ int sde_connector_set_property_for_commit(struct drm_connector *connector, struct drm_atomic_state *atomic_state, uint32_t property_idx, uint64_t value); +/** + * sde_connector_post_init - update connector object with post initialization. + * It can update the debugfs, sysfs, entries + * @dev: Pointer to drm device struct + * @conn: Pointer to drm connector + * Returns: Zero on success + */ +int sde_connector_post_init(struct drm_device *dev, struct drm_connector *conn); + /** * sde_connector_init - create drm connector object for a given display * @dev: Pointer to drm device struct diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index bb7f41ec65db..862fd2e18659 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2176,6 +2176,8 @@ static int sde_kms_postinit(struct msm_kms *kms) struct sde_kms *sde_kms = to_sde_kms(kms); struct drm_device *dev; struct drm_crtc *crtc; + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; int rc; if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev) { @@ -2192,6 +2194,10 @@ static int sde_kms_postinit(struct msm_kms *kms) drm_for_each_crtc(crtc, dev) sde_crtc_post_init(dev, crtc); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) + sde_connector_post_init(dev, conn); + drm_connector_list_iter_end(&conn_iter); return rc; } From 05ccf7d2787ab77e18a20d032e826b41b61880ad Mon Sep 17 00:00:00 2001 From: osaisruj Date: Fri, 29 Oct 2021 01:33:47 +0530 Subject: [PATCH 19/51] disp: msm: sde: add twm mode sysfs mode Add sysfs node on connector to get twm enable state. This node is used by the HAL to notify TWM entry and exit. Change-Id: I56a844076014c2e12075756f6b1bc42b91b48ad1 Signed-off-by: osaisruj --- msm/sde/sde_connector.c | 37 +++++++++++++++++++++++++++++++++++++ msm/sde/sde_connector.h | 2 ++ 2 files changed, 39 insertions(+) diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 6c6a5a6e3585..fdd72a459363 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -2860,10 +2860,46 @@ static ssize_t panel_power_state_show(struct device *device, return scnprintf(buf, PAGE_SIZE, "%d\n", sde_conn->last_panel_power_mode); } +static ssize_t twm_enable_store(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *conn; + struct sde_connector *sde_conn; + int rc; + int data; + + conn = dev_get_drvdata(device); + sde_conn = to_sde_connector(conn); + + rc = kstrtoint(buf, 10, &data); + if (rc) { + SDE_ERROR("kstrtoint failed, rc =%d\n", rc); + return -EINVAL; + } + sde_conn->twm_en = data ? true : false; + SDE_DEBUG("TWM: %s\n", sde_conn->twm_en ? "ENABLED" : "DISABLED"); + return count; +} + +static ssize_t twm_enable_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *conn; + struct sde_connector *sde_conn; + + conn = dev_get_drvdata(device); + sde_conn = to_sde_connector(conn); + + SDE_DEBUG("TWM: %s\n", sde_conn->twm_en ? "ENABLED" : "DISABLED"); + return scnprintf(buf, PAGE_SIZE, "%d\n", sde_conn->twm_en); +} + static DEVICE_ATTR_RO(panel_power_state); +static DEVICE_ATTR_RW(twm_enable); static struct attribute *sde_connector_dev_attrs[] = { &dev_attr_panel_power_state.attr, + &dev_attr_twm_enable.attr, NULL }; @@ -2958,6 +2994,7 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, c_conn->dpms_mode = DRM_MODE_DPMS_ON; c_conn->lp_mode = 0; c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON; + c_conn->twm_en = false; sde_kms = to_sde_kms(priv->kms); if (sde_kms->vbif[VBIF_NRT]) { diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 3caa1fa60666..ecbbefbf8b60 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -470,6 +470,7 @@ struct sde_connector_dyn_hdr_metadata { * @esd_status_interval: variable to change ESD check interval in millisec * @panel_dead: Flag to indicate if panel has gone bad * @esd_status_check: Flag to indicate if ESD thread is scheduled or not + * @twm_en: Flag to indicate if TWM mode is enabled or not * @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed * @bl_scale: BL scale value for ABA feature * @bl_scale_sv: BL scale value for sunlight visibility feature @@ -533,6 +534,7 @@ struct sde_connector { u32 esd_status_interval; bool panel_dead; bool esd_status_check; + bool twm_en; bool bl_scale_dirty; u32 bl_scale; From 1e20848d49ade9817606c79b1735d7d3a0cb6078 Mon Sep 17 00:00:00 2001 From: osaisruj Date: Mon, 1 Nov 2021 01:15:18 +0530 Subject: [PATCH 20/51] disp: msm: add support for twm entry Skip backlight updates and panel off commands during twm entry. Change-Id: I7656fa0d513a8a3e82d9bbbf5c3f85c1b84ee9da Signed-off-by: osaisruj --- msm/dsi/dsi_panel.c | 12 ++++++++++++ msm/dsi/dsi_panel.h | 3 ++- msm/sde/sde_connector.c | 7 +++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index cdde192e19ac..456fcf52574c 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -378,6 +378,10 @@ static int dsi_panel_power_off(struct dsi_panel *panel) { int rc = 0; + if (panel->is_twm_en) { + DSI_DEBUG("TWM Enabled, skip panel power off\n"); + return rc; + } if (gpio_is_valid(panel->reset_config.disp_en_gpio)) gpio_set_value(panel->reset_config.disp_en_gpio, 0); @@ -4305,6 +4309,10 @@ int dsi_panel_set_nolp(struct dsi_panel *panel) return -EINVAL; } + if (panel->is_twm_en) { + DSI_DEBUG("TWM Enabled, skip idle off\n"); + return rc; + } mutex_lock(&panel->panel_lock); if (!panel->panel_initialized) goto exit; @@ -4717,6 +4725,10 @@ int dsi_panel_disable(struct dsi_panel *panel) return -EINVAL; } + if (panel->is_twm_en) { + DSI_DEBUG("TWM Enabled, skip panel disable\n"); + return rc; + } mutex_lock(&panel->panel_lock); /* Avoid sending panel off commands when ESD recovery is underway */ diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index b0c259dacce1..f3902274930b 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, 2021 The Linux Foundation. All rights reserved. */ #ifndef _DSI_PANEL_H_ @@ -244,6 +244,7 @@ struct dsi_panel { bool reset_gpio_always_on; atomic_t esd_recovery_pending; + bool is_twm_en; bool panel_initialized; bool te_using_watchdog_timer; struct dsi_qsync_capabilities qsync_caps; diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index fdd72a459363..8725798c3fe4 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -2865,18 +2865,21 @@ static ssize_t twm_enable_store(struct device *device, { struct drm_connector *conn; struct sde_connector *sde_conn; + struct dsi_display *dsi_display; int rc; int data; conn = dev_get_drvdata(device); sde_conn = to_sde_connector(conn); - + dsi_display = (struct dsi_display *) sde_conn->display; rc = kstrtoint(buf, 10, &data); if (rc) { - SDE_ERROR("kstrtoint failed, rc =%d\n", rc); + SDE_ERROR("kstrtoint failed, rc = %d\n", rc); return -EINVAL; } sde_conn->twm_en = data ? true : false; + dsi_display->panel->is_twm_en = sde_conn->twm_en; + sde_conn->allow_bl_update = data ? false : true; SDE_DEBUG("TWM: %s\n", sde_conn->twm_en ? "ENABLED" : "DISABLED"); return count; } From 2dc0e4553c7fd176c2e351dfc29605f2f205c3d3 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Fri, 8 Oct 2021 10:25:24 +0530 Subject: [PATCH 21/51] disp: msm: sde: protect file private structure with mutex lock Access file private data structures inside the mutex lock only to avoid use-after-free issues. Change-Id: If70731f517bcb47d4515f131fecafe702064cb45 Signed-off-by: Krishna Manikandan --- msm/msm_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 5597b8d72da1..5eb8363e2198 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1488,7 +1488,7 @@ void msm_mode_object_event_notify(struct drm_mode_object *obj, static int msm_release(struct inode *inode, struct file *filp) { - struct drm_file *file_priv = filp->private_data; + struct drm_file *file_priv; struct drm_minor *minor; struct drm_device *dev; struct msm_drm_private *priv; @@ -1500,6 +1500,7 @@ static int msm_release(struct inode *inode, struct file *filp) mutex_lock(&msm_release_lock); + file_priv = filp->private_data; if (!file_priv) { ret = -EINVAL; goto end; From 20c46f6fa6ecde692a7ae316709d534d69730ca3 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Mon, 25 Oct 2021 22:05:03 +0530 Subject: [PATCH 22/51] disp: msm: dsi: remove early return from dma_cmd_wait_for_done In ASYNC wait mode, next command kickoff can happen before previous command ISR execution is completed in below sequence: ASYNC command A -> triggered dsi_ctrl_isr for command A -> fired and executed atomic_set(&dsi_ctrl->dma_irq_trig, 1); wait_for_done for command A -> returns early as dsi_ctrl->dma_irq_trig is 1 ASYNC Command B -> triggered wait_for_done for command B -> waiting for cmd_dma_done dsi_ctrl_isr for command A -> executes complete_all(&dsi_ctrl->irq_info.cmd_dma_done); wait_for_done for command B -> returns success incorrectly based on complete_all of previous command isr and disable_status_interrupt() is not called. This leads to refcount of dma_done going wrong and dsi_ctrl_isr is not enabled on suspend resume. To fix this issue, mark command transfer successful only based on complete_all(cmd_dma_done). This way disable_status_interrupt() will be always called either from dsi_ctrl_isr or wait_for_done(). Change-Id: I0379ea7ff82a1e077b95f6996d11d1722de00936 Signed-off-by: Ritesh Kumar --- msm/dsi/dsi_ctrl.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 89092690a678..c298e616ac65 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -390,13 +390,6 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct work_struct *work) dsi_hw_ops = dsi_ctrl->hw.ops; SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY); - /* - * This atomic state will be set if ISR has been triggered, - * so the wait is not needed. - */ - if (atomic_read(&dsi_ctrl->dma_irq_trig)) - goto done; - ret = wait_for_completion_timeout( &dsi_ctrl->irq_info.cmd_dma_done, msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); @@ -416,8 +409,8 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct work_struct *work) DSI_SINT_CMD_MODE_DMA_DONE); } -done: dsi_ctrl->dma_wait_queued = false; + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_EXIT); } static int dsi_ctrl_check_state(struct dsi_ctrl *dsi_ctrl, From 77edd61d98f0351bc0c81a8a171f666ba6b225d7 Mon Sep 17 00:00:00 2001 From: longzhao Date: Thu, 18 Nov 2021 18:00:26 +0800 Subject: [PATCH 23/51] disp: msm: sde: avoid sde irq enable or disable when sde irq not active During the sde_irq_update, the sde irq may not be active, the enable or disable will be nonsence. set the irq_num init value to negtive, if this value change, means sde irq_num has been initial. Change-Id: I7b23c662ccc9db0b38550897adb939305d941e6a Signed-off-by: longzhao --- msm/sde/sde_irq.c | 4 +++- msm/sde/sde_kms.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_irq.c b/msm/sde/sde_irq.c index e8574156512e..974c163a6770 100644 --- a/msm/sde/sde_irq.c +++ b/msm/sde/sde_irq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, 2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -22,6 +22,8 @@ void sde_irq_update(struct msm_kms *msm_kms, bool enable) SDE_ERROR("invalid kms arguments\n"); return; } + if (sde_kms->irq_num < 0) + return; sde_kms->irq_enabled = enable; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index bb7f41ec65db..4bd92b2c5a52 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -4795,6 +4795,7 @@ struct msm_kms *sde_kms_init(struct drm_device *dev) msm_kms_init(&sde_kms->base, &kms_funcs); sde_kms->dev = dev; + sde_kms->irq_num = -1; return &sde_kms->base; } From 67ef82eb35fb8004217b20ed033fa4688bed7ff5 Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Sat, 20 Nov 2021 12:50:17 +0530 Subject: [PATCH 24/51] disp: msm: sde: avoid CWB in power on commit This change depends on HAL change which sets CONNECTOR_SET_CRTC property to null for cwb conn, if cwb is enabled during power off commit. This causes power off commit crtc_state's active_changed and connectors_changed set to true, which is causing seamless_crtc to true during msm_disable_outputs and this leads to invalid crtc state. This change modifies the seamless_crtc condition and the msm_crtc_set_mode callback is early returned during such cases to power off crtc. Without this change, during power on commit crtc_duplicate_state is causing cwb to turn on and the release fence is being created with +2 offset in such case, leading to late release fence signalling and further GPU fence timeouts. Change-Id: Ibe87a8c0e8083d619ee6f502b2a946e1e8ef5553 Signed-off-by: Jayaprakash Madisetty --- msm/msm_atomic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/msm/msm_atomic.c b/msm/msm_atomic.c index 412d8b3bda05..049623486f38 100644 --- a/msm/msm_atomic.c +++ b/msm/msm_atomic.c @@ -55,7 +55,7 @@ static inline bool _msm_seamless_for_crtc(struct drm_device *dev, if (msm_is_mode_seamless_dms(&crtc_state->adjusted_mode) && !enable) return true; - if (!crtc_state->mode_changed && crtc_state->connectors_changed) { + if (!crtc_state->mode_changed && crtc_state->connectors_changed && crtc_state->active) { for_each_old_connector_in_state(state, connector, conn_state, i) { if ((conn_state->crtc == crtc_state->crtc) || @@ -282,6 +282,9 @@ msm_crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) mode = &new_crtc_state->mode; adjusted_mode = &new_crtc_state->adjusted_mode; + if (!new_crtc_state->active) + continue; + if (!new_crtc_state->mode_changed && new_crtc_state->connectors_changed) { if (_msm_seamless_for_conn(connector, From 81d15ab5bd99c64ca131f0fac485fdc07bd0b339 Mon Sep 17 00:00:00 2001 From: Rajeev Nandan Date: Tue, 23 Nov 2021 19:32:13 +0530 Subject: [PATCH 25/51] disp: msm: dsi: Clear slave dma status only for broadcast command In case of broadcast, for master controller, DMA_DONE bit gets cleared in dsi_ctrl_isr and for slave controller it gets cleared in clear_slave_dma_status. Current implementation checks DSI_CTRL_CMD_BROADCAST_MASTER flag to decide if it's slave or not. But, in the case of unicast, this flag is not set, leading to the unnecessary poll for clear_slave_dma_status for all unicast command transfers. Add a check to call clear_slave_dma_status only when the current command is broadcast on slave controller. Change-Id: I7156f8c12ec779b41dafc8fc67639814957ee51b Signed-off-by: Rajeev Nandan --- msm/dsi/dsi_ctrl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index c298e616ac65..764c605e4b96 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1550,7 +1550,8 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, if (dsi_ctrl->dma_wait_queued) dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl); - if (!(*flags & DSI_CTRL_CMD_BROADCAST_MASTER)) + if ((*flags & DSI_CTRL_CMD_BROADCAST) && + (!(*flags & DSI_CTRL_CMD_BROADCAST_MASTER))) dsi_ctrl_clear_slave_dma_status(dsi_ctrl, *flags); if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { From ad89bfc0d515f98b71fa688170deae37165968b2 Mon Sep 17 00:00:00 2001 From: osaisruj Date: Fri, 12 Nov 2021 19:51:35 +0530 Subject: [PATCH 26/51] disp: msm: sde: modify format specifier Modify error log with correct format specifier. Change-Id: Ifb9d3f2decdb9dcac92ee810454a1027b5b78636 Signed-off-by: osaisruj --- msm/sde/sde_fence.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/msm/sde/sde_fence.c b/msm/sde/sde_fence.c index dd9cc295f4e9..6b7a30fd733c 100644 --- a/msm/sde/sde_fence.c +++ b/msm/sde/sde_fence.c @@ -43,7 +43,7 @@ signed long sde_sync_wait(void *fnc, long timeout_ms) timeline_str, TIMELINE_VAL_LENGTH); SDE_ERROR( - "fence driver name:%s timeline name:%s seqno:0x%x timeline:%s signaled:0x%x\n", + "fence driver name:%s timeline name:%s seqno:0x%llx timeline:%s signaled:0x%x\n", fence->ops->get_driver_name(fence), fence->ops->get_timeline_name(fence), fence->seqno, timeline_str, @@ -132,7 +132,7 @@ static bool sde_fence_signaled(struct dma_fence *fence) bool status; status = ((int)(fence->seqno - f->ctx->done_count) <= 0); - SDE_DEBUG("status:%d fence seq:%d and timeline:%d\n", + SDE_DEBUG("status:%d fence seq:%llu and timeline:%d\n", status, fence->seqno, f->ctx->done_count); return status; } @@ -153,7 +153,7 @@ static void sde_fence_value_str(struct dma_fence *fence, char *str, int size) if (!fence || !str) return; - snprintf(str, size, "%d", fence->seqno); + snprintf(str, size, "%llu", fence->seqno); } static void sde_fence_timeline_value_str(struct dma_fence *fence, char *str, @@ -435,7 +435,7 @@ void sde_fence_list_dump(struct dma_fence *fence, struct seq_file **s) fence->ops->timeline_value_str(fence, timeline_str, TIMELINE_VAL_LENGTH); - seq_printf(*s, "fence name:%s timeline name:%s seqno:0x%x timeline:%s signaled:0x%x\n", + seq_printf(*s, "fence name:%s timeline name:%s seqno:0x%llx timeline:%s signaled:0x%x\n", fence->ops->get_driver_name(fence), fence->ops->get_timeline_name(fence), fence->seqno, timeline_str, From 841c696fb4428330bba619ddf2d0a9c57bb1c14c Mon Sep 17 00:00:00 2001 From: Sai Srujana Oruganti Date: Fri, 5 Nov 2021 13:53:07 +0530 Subject: [PATCH 27/51] disp: msm: dsi: add API to handle PHY programming during 0p9 collapse Add HW recommended programming sequence when PHY is allowed to turn off during idle state. Change-Id: Icdd50d5ebc338842a6629ec08fc0ef35453e1052 Signed-off-by: Sai Srujana Oruganti --- msm/dsi/dsi_catalog.c | 2 ++ msm/dsi/dsi_catalog.h | 2 ++ msm/dsi/dsi_phy.c | 3 +++ msm/dsi/dsi_phy_hw.h | 3 +++ msm/dsi/dsi_phy_hw_v4_0.c | 9 +++++++++ 5 files changed, 19 insertions(+) diff --git a/msm/dsi/dsi_catalog.c b/msm/dsi/dsi_catalog.c index 9c1dc9c49bfa..44a366fb140e 100644 --- a/msm/dsi/dsi_catalog.c +++ b/msm/dsi/dsi_catalog.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -293,6 +294,7 @@ static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy) dsi_phy_hw_v4_0_cache_phy_timings; phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk; phy->ops.commit_phy_timing = dsi_phy_hw_v4_0_commit_phy_timing; + phy->ops.phy_idle_off = dsi_phy_hw_v4_0_phy_idle_off; } /** diff --git a/msm/dsi/dsi_catalog.h b/msm/dsi/dsi_catalog.h index c3d2f174c71b..a35206c94f8c 100644 --- a/msm/dsi/dsi_catalog.h +++ b/msm/dsi/dsi_catalog.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DSI_CATALOG_H_ @@ -125,6 +126,7 @@ void dsi_phy_hw_v4_0_reset_clk_en_sel(struct dsi_phy_hw *phy); void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable); void dsi_phy_hw_v4_0_commit_phy_timing(struct dsi_phy_hw *phy, struct dsi_phy_per_lane_cfgs *timing); +void dsi_phy_hw_v4_0_phy_idle_off(struct dsi_phy_hw *phy); /* DSI controller common ops */ u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl); diff --git a/msm/dsi/dsi_phy.c b/msm/dsi/dsi_phy.c index 968e118e548d..f57b4245ecce 100644 --- a/msm/dsi/dsi_phy.c +++ b/msm/dsi/dsi_phy.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -356,6 +357,8 @@ static int dsi_phy_settings_init(struct platform_device *pdev, phy->allow_phy_power_off = of_property_read_bool(pdev->dev.of_node, "qcom,panel-allow-phy-poweroff"); + phy->hw.clamp_enable = of_property_read_bool(pdev->dev.of_node, + "qcom,phy-clamp-enable"); of_property_read_u32(pdev->dev.of_node, "qcom,dsi-phy-regulator-min-datarate-bps", diff --git a/msm/dsi/dsi_phy_hw.h b/msm/dsi/dsi_phy_hw.h index 62e9e012541b..97d3f86db3c4 100644 --- a/msm/dsi/dsi_phy_hw.h +++ b/msm/dsi/dsi_phy_hw.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DSI_PHY_HW_H_ @@ -354,6 +355,7 @@ struct dsi_phy_hw_ops { * @length: Length of the DSI dynamic refresh register base map. * @index: Instance ID of the controller. * @version: DSI PHY version. + * @clamp_enable True if phy clamp is enabled * @phy_clamp_base: Base address of phy clamp register map. * @feature_map: Features supported by DSI PHY. * @ops: Function pointer to PHY operations. @@ -366,6 +368,7 @@ struct dsi_phy_hw { u32 index; enum dsi_phy_version version; + bool clamp_enable; void __iomem *phy_clamp_base; DECLARE_BITMAP(feature_map, DSI_PHY_MAX_FEATURES); diff --git a/msm/dsi/dsi_phy_hw_v4_0.c b/msm/dsi/dsi_phy_hw_v4_0.c index c40b11e449d5..ae50b70dbeef 100644 --- a/msm/dsi/dsi_phy_hw_v4_0.c +++ b/msm/dsi/dsi_phy_hw_v4_0.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -858,3 +859,11 @@ void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable) DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg); wmb(); /* make sure request is set */ } + +void dsi_phy_hw_v4_0_phy_idle_off(struct dsi_phy_hw *phy) +{ + if (phy->version >= DSI_PHY_VERSION_4_2 && phy->clamp_enable) { + DSI_W32(phy, DSIPHY_CMN_CTRL_4, 0x1); + DSI_W32(phy, DSIPHY_CMN_CTRL_3, 0x0); + } +} From 2b5f47020cf32559d06990dffa48d947d32f68b2 Mon Sep 17 00:00:00 2001 From: Yashwanth Date: Wed, 15 Dec 2021 10:55:58 +0530 Subject: [PATCH 28/51] disp: msm: sde: update uidle_db_updates in both enable/disable cases uidle_db_updates are generated when CTL_x_UIDLE_ACTIVE is set to 1. It needs to enabled in both uidle enable and disable cases. CTL_x_UIDLE_ACTIVE is set to 0 only in cases where uidle configuration is not updated. Change-Id: I9e31dc00b3b79c12b0bcf51da21eb216746794a6 Signed-off-by: Raviteja Tamatam Signed-off-by: Yashwanth --- msm/sde/sde_core_perf.c | 13 ++++++++----- msm/sde/sde_core_perf.h | 9 ++++++++- msm/sde/sde_crtc.c | 8 +++++++- msm/sde/sde_crtc.h | 1 + msm/sde/sde_encoder.c | 1 - msm/sde/sde_hw_catalog.h | 1 + 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/msm/sde/sde_core_perf.c b/msm/sde/sde_core_perf.c index 02d992d06fb3..91c52867ed16 100644 --- a/msm/sde/sde_core_perf.c +++ b/msm/sde/sde_core_perf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -494,7 +494,7 @@ static void _sde_core_uidle_setup_cfg(struct sde_kms *kms, uidle->ops.set_uidle_ctl(uidle, &cfg); } -static void _sde_core_uidle_setup_ctl(struct drm_crtc *crtc, +void sde_core_uidle_setup_ctl(struct drm_crtc *crtc, bool enable) { struct drm_encoder *drm_enc; @@ -522,7 +522,7 @@ static int _sde_core_perf_enable_uidle(struct sde_kms *kms, SDE_EVT32(enable); _sde_core_uidle_setup_wd(kms, enable); _sde_core_uidle_setup_cfg(kms, enable); - _sde_core_uidle_setup_ctl(crtc, enable); + sde_core_uidle_setup_ctl(crtc, true); kms->perf.uidle_enabled = enable; @@ -577,7 +577,7 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, struct drm_crtc *tmp_crtc; struct sde_kms *kms; bool disable_uidle = false; - u32 fps; + u32 fps, num_crtc = 0; if (!crtc) { SDE_ERROR("invalid crtc\n"); @@ -603,6 +603,7 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, drm_for_each_crtc(tmp_crtc, crtc->dev) { if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) { + num_crtc++; /* * If DFPS is enabled with VFP, SDE clock and * transfer time will get fixed at max FPS @@ -620,7 +621,7 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, _sde_core_perf_is_cwb(tmp_crtc), disable_uidle, enable); - if (_sde_core_perf_is_wb(tmp_crtc) || + if ((num_crtc > 1) || _sde_core_perf_is_wb(tmp_crtc) || _sde_core_perf_is_cwb(tmp_crtc) || (!fps || fps > kms->perf.catalog->uidle_cfg.max_fps)) { disable_uidle = true; @@ -632,6 +633,8 @@ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, _sde_core_perf_enable_uidle(kms, crtc, (enable && !disable_uidle) ? true : false); + kms->perf.catalog->uidle_cfg.dirty = !enable; + /* If perf counters enabled, set them up now */ if (kms->catalog->uidle_cfg.debugfs_perf) _sde_core_perf_uidle_setup_cntr(kms, enable); diff --git a/msm/sde/sde_core_perf.h b/msm/sde/sde_core_perf.h index 8e9ac9b79547..ba51bbce92c3 100644 --- a/msm/sde/sde_core_perf.h +++ b/msm/sde/sde_core_perf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _SDE_CORE_PERF_H_ @@ -138,6 +138,13 @@ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc); */ void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable); +/** + * sde_core_uidle_setup_ctl - enable uidle DB control + * @crtc: Pointer to crtc + * @enable: enable/disable uidle DB + */ +void sde_core_uidle_setup_ctl(struct drm_crtc *crtc, bool enable); + /** * sde_core_perf_destroy - destroy the given core performance context * @perf: Pointer to core performance context diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 61b5c692ec85..e6811e616a58 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3322,8 +3322,13 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, _sde_crtc_blend_setup(crtc, old_state, true); _sde_crtc_dest_scaler_setup(crtc); - if (crtc->state->mode_changed) + if (crtc->state->mode_changed || sde_kms->perf.catalog->uidle_cfg.dirty) sde_core_perf_crtc_update_uidle(crtc, true); + else if (!test_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask) && + !sde_kms->perf.uidle_enabled) + sde_core_uidle_setup_ctl(crtc, false); + + test_and_clear_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask); /* * Since CP properties use AXI buffer to program the @@ -3994,6 +3999,7 @@ void sde_crtc_reset_sw_state(struct drm_crtc *crtc) /* mark other properties which need to be dirty for next update */ set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, &sde_crtc->revalidate_mask); + set_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask); if (cstate->num_ds_enabled) set_bit(SDE_CRTC_DIRTY_DEST_SCALER, cstate->dirty); } diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index e5b924dba454..43db78485c69 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -399,6 +399,7 @@ struct sde_crtc { enum sde_crtc_dirty_flags { SDE_CRTC_DIRTY_DEST_SCALER, SDE_CRTC_DIRTY_DIM_LAYERS, + SDE_CRTC_DIRTY_UIDLE, SDE_CRTC_DIRTY_MAX, }; diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 9cb8fc2c9229..2f4ccf9ae938 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -141,7 +141,6 @@ void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable) struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; if (phys && phys->hw_ctl && phys->hw_ctl->ops.uidle_enable) { - SDE_EVT32(DRMID(drm_enc), enable); phys->hw_ctl->ops.uidle_enable(phys->hw_ctl, enable); } } diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 3e7ab2ad90d2..bbe785d87754 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -938,6 +938,7 @@ struct sde_uidle_cfg { u32 debugfs_perf; bool debugfs_ctrl; bool perf_cntr_en; + bool dirty; }; /* struct sde_mdp_cfg : MDP TOP-BLK instance info From 401ab0dbb9f53634f877ed9a7c6b0dfdd98a2bff Mon Sep 17 00:00:00 2001 From: Satya Rama Aditya Pinapala Date: Mon, 8 Mar 2021 15:13:02 -0800 Subject: [PATCH 29/51] disp: msm: dsi: allocate DSI command buffer during bind The DMA buffer allocation for DSI happens during the first command transfer. This change moves this allocation to happen during bind. Change-Id: I7969a019a8b84282e8a153f5393c9a3de5a28043 Signed-off-by: Satya Rama Aditya Pinapala --- msm/dsi/dsi_display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 74c556be67e6..2330d73f5c0f 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6111,6 +6111,12 @@ int dsi_display_drm_bridge_init(struct dsi_display *display, display->bridge = bridge; priv->bridges[priv->num_bridges++] = &bridge->base; + if (display->tx_cmd_buf == NULL) { + rc = dsi_host_alloc_cmd_tx_buffer(display); + if (rc) + DSI_ERR("failed to allocate cmd tx buffer memory\n"); + } + error: mutex_unlock(&display->display_lock); return rc; From 9a1da8b4c3f7eda09f6a2ef3f605d98aab52a36b Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Fri, 31 Dec 2021 18:28:50 +0530 Subject: [PATCH 30/51] disp: msm: fix rsc static wakeup time calculation Currently RSC timer register programming is optimized for updating only during timing param changes and not during RSC state changes with same timing. Static wakeup time computation should consider panel jitter for RSC clk state too, else it can result in RSC hang. This change also removes extra logic for video mode prefil lines computation for rsc config as video mode does not enable RSC solver. Current issue scenario exposing the hang is in dual dsi display scenario where RSC is in clock state and static wakeup time is programmed by not considering panel jitter, after suspend/pmsuspend while waking up if RSC switches to command state if primary enabled first and vsync may arrive much early based on the panel jitter. RSC hw can not handle if TE arrives earlier than static wakeup time causing RSC hang. Change-Id: I1434fdd71eb04fdbe22b3601500493c818e9126d Signed-off-by: Prabhanjan Kandula Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_encoder.c | 13 +------------ msm/sde_rsc.c | 6 +----- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 2f4ccf9ae938..190e2a473384 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1376,20 +1376,9 @@ static int _sde_encoder_update_rsc_client( (rsc_config->prefill_lines != mode_info->prefill_lines) || (rsc_config->jitter_numer != mode_info->jitter_numer) || (rsc_config->jitter_denom != mode_info->jitter_denom)) { - rsc_config->fps = mode_info->frame_rate; rsc_config->vtotal = mode_info->vtotal; - /* - * for video mode, prefill lines should not go beyond vertical - * front porch for RSCC configuration. This will ensure bw - * downvotes are not sent within the active region. Additional - * -1 is to give one line time for rscc mode min_threshold. - */ - if (is_vid_mode && (mode_info->prefill_lines >= v_front_porch)) - rsc_config->prefill_lines = v_front_porch - 1; - else - rsc_config->prefill_lines = mode_info->prefill_lines; - + rsc_config->prefill_lines = mode_info->prefill_lines; rsc_config->jitter_numer = mode_info->jitter_numer; rsc_config->jitter_denom = mode_info->jitter_denom; sde_enc->rsc_state_init = false; diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index 4b4c13bca0a5..14d180568115 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -331,11 +331,7 @@ static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc, line_time_ns = div_u64(line_time_ns, rsc->cmd_config.vtotal); prefill_time_ns = line_time_ns * rsc->cmd_config.prefill_lines; - /* only take jitter into account for CMD mode */ - if (state == SDE_RSC_CMD_STATE) - total = frame_time_ns - frame_jitter - prefill_time_ns; - else - total = frame_time_ns - prefill_time_ns; + total = frame_time_ns - frame_jitter - prefill_time_ns; if (total < 0) { pr_err("invalid total time period time:%llu jiter_time:%llu blanking time:%llu\n", From 205c579c9a61f758d5d29ae0cc136cd68e2b46ac Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Thu, 21 Oct 2021 10:53:19 +0530 Subject: [PATCH 31/51] disp: msm: sde: avoid irq enable/disable during modeset Avoid irq enable/disable during modeset and trigger frame as posted start frame. This saves mode_set time and also avoids unbalanced vblank_irq in this usecase. Change-Id: I06958da5e52bc2aca0ddc60d2783615f80a839a4 Signed-off-by: Dhaval Patel Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_encoder.c | 16 +---------- msm/sde/sde_encoder_phys.h | 3 +- msm/sde/sde_encoder_phys_cmd.c | 50 +++------------------------------- 3 files changed, 6 insertions(+), 63 deletions(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 2f4ccf9ae938..ec11d2d0091d 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -1873,19 +1874,6 @@ static int _sde_encoder_rc_pre_modeset(struct drm_encoder *drm_enc, sde_enc->rc_state = SDE_ENC_RC_STATE_ON; } - ret = sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); - if (ret && ret != -EWOULDBLOCK) { - SDE_ERROR_ENC(sde_enc, - "wait for commit done returned %d\n", - ret); - SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, - ret, SDE_EVTLOG_ERROR); - ret = -EINVAL; - goto end; - } - - sde_encoder_irq_control(drm_enc, false); - SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_MODESET, SDE_EVTLOG_FUNC_CASE5); @@ -1920,8 +1908,6 @@ static int _sde_encoder_rc_post_modeset(struct drm_encoder *drm_enc, goto end; } - sde_encoder_irq_control(drm_enc, true); - _sde_encoder_update_rsc_client(drm_enc, true); SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 802140bd28c0..f3de4a43b8e3 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -275,7 +276,6 @@ struct sde_encoder_irq { * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @enable_state: Enable state tracking * @vblank_refcount: Reference count of vblank request - * @vblank_cached_refcount: Reference count of vblank cached request * @wbirq_refcount: Reference count of wb irq request * @vsync_cnt: Vsync count for the physical encoder * @underrun_cnt: Underrun count for the physical encoder @@ -325,7 +325,6 @@ struct sde_encoder_phys { enum sde_enc_enable_state enable_state; struct mutex *vblank_ctl_lock; atomic_t vblank_refcount; - atomic_t vblank_cached_refcount; atomic_t wbirq_refcount; atomic_t vsync_cnt; atomic_t underrun_cnt; diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 8dd05021abac..403573cecd26 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -340,8 +341,6 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( { struct sde_encoder_irq *irq; struct sde_kms *sde_kms; - int ret = 0; - u32 vblank_refcount; if (!phys_enc->sde_kms || !phys_enc->hw_pp || !phys_enc->hw_ctl) { SDE_ERROR("invalid args %d %d %d\n", !phys_enc->sde_kms, @@ -356,39 +355,13 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( sde_kms = phys_enc->sde_kms; - mutex_lock(phys_enc->vblank_ctl_lock); - vblank_refcount = atomic_read(&phys_enc->vblank_refcount); - if (vblank_refcount) { - ret = sde_encoder_helper_unregister_irq(phys_enc, - INTR_IDX_RDPTR); - if (ret) - SDE_ERROR( - "control vblank irq registration error %d\n", - ret); - if (vblank_refcount > 1) - SDE_ERROR( - "vblank_refcount mismatch detected, try to reset %d\n", - atomic_read(&phys_enc->vblank_refcount)); - else - atomic_set(&phys_enc->vblank_cached_refcount, 1); - - SDE_EVT32(DRMID(phys_enc->parent), - phys_enc->hw_pp->idx - PINGPONG_0, vblank_refcount, - atomic_read(&phys_enc->vblank_cached_refcount)); - } - atomic_set(&phys_enc->vblank_refcount, 0); - mutex_unlock(phys_enc->vblank_ctl_lock); - irq = &phys_enc->irq[INTR_IDX_CTL_START]; irq->hw_idx = phys_enc->hw_ctl->idx; - irq->irq_idx = -EINVAL; irq = &phys_enc->irq[INTR_IDX_PINGPONG]; irq->hw_idx = phys_enc->hw_pp->idx; - irq->irq_idx = -EINVAL; irq = &phys_enc->irq[INTR_IDX_RDPTR]; - irq->irq_idx = -EINVAL; if (phys_enc->has_intf_te) irq->hw_idx = phys_enc->hw_intf->idx; else @@ -396,17 +369,14 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; irq->hw_idx = phys_enc->intf_idx; - irq->irq_idx = -EINVAL; irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; - irq->irq_idx = -EINVAL; if (phys_enc->has_intf_te) irq->hw_idx = phys_enc->hw_intf->idx; else irq->hw_idx = phys_enc->hw_pp->idx; irq = &phys_enc->irq[INTR_IDX_WRPTR]; - irq->irq_idx = -EINVAL; if (phys_enc->has_intf_te) irq->hw_idx = phys_enc->hw_intf->idx; else @@ -831,7 +801,7 @@ static int sde_encoder_phys_cmd_control_vblank_irq( struct sde_encoder_phys_cmd *cmd_enc = to_sde_encoder_phys_cmd(phys_enc); int ret = 0; - u32 refcount, cached_refcount; + u32 refcount; struct sde_kms *sde_kms; if (!phys_enc || !phys_enc->hw_pp) { @@ -846,17 +816,11 @@ static int sde_encoder_phys_cmd_control_vblank_irq( goto end; refcount = atomic_read(&phys_enc->vblank_refcount); - cached_refcount = atomic_read(&phys_enc->vblank_cached_refcount); /* protect against negative */ if (!enable && refcount == 0) { - if (cached_refcount == 1) { - atomic_set(&phys_enc->vblank_cached_refcount, 0); - goto end; - } else { - ret = -EINVAL; - goto end; - } + ret = -EINVAL; + goto end; } SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n", @@ -876,11 +840,6 @@ static int sde_encoder_phys_cmd_control_vblank_irq( atomic_inc_return(&phys_enc->vblank_refcount); } - if (enable && cached_refcount) { - atomic_inc(&phys_enc->vblank_refcount); - atomic_set(&phys_enc->vblank_cached_refcount, 0); - } - end: mutex_unlock(phys_enc->vblank_ctl_lock); if (ret) { @@ -2129,7 +2088,6 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq->cb.func = sde_encoder_phys_cmd_wr_ptr_irq; atomic_set(&phys_enc->vblank_refcount, 0); - atomic_set(&phys_enc->vblank_cached_refcount, 0); atomic_set(&phys_enc->pending_kickoff_cnt, 0); atomic_set(&phys_enc->pending_retire_fence_cnt, 0); atomic_set(&cmd_enc->pending_vblank_cnt, 0); From ff90d96806efc2e321ed14f9785166522513ba05 Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Mon, 10 Jan 2022 22:12:12 +0530 Subject: [PATCH 32/51] disp: msm: sde: avoid tx wait during DMS for targets with dsc rev2 This change removes tx_wait during DMS for targets which have dsc_hw_rev_2. For targets with dsc_hw_rev_1, during DMS the tx_wait is needed since DSC registers are not double buffered and frame trigger needs to be serialized to avoid pp_timeout issues. Change-Id: I46479ed8713602d167e57c9d9d0f800f544607f2 Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_encoder.c | 12 ++++++++++++ msm/sde/sde_encoder_dce.c | 21 +++++++++++++++++++++ msm/sde/sde_encoder_dce.h | 7 +++++++ 3 files changed, 40 insertions(+) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index ec11d2d0091d..e7edc2033c10 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1874,6 +1874,18 @@ static int _sde_encoder_rc_pre_modeset(struct drm_encoder *drm_enc, sde_enc->rc_state = SDE_ENC_RC_STATE_ON; } + if (sde_encoder_has_dsc_hw_rev_2(sde_enc)) + goto skip_wait; + + ret = sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); + if (ret && ret != -EWOULDBLOCK) { + SDE_ERROR_ENC(sde_enc, "wait for commit done returned %d\n", ret); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, ret, SDE_EVTLOG_ERROR); + ret = -EINVAL; + goto end; + } + +skip_wait: SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, SDE_ENC_RC_STATE_MODESET, SDE_EVTLOG_FUNC_CASE5); diff --git a/msm/sde/sde_encoder_dce.c b/msm/sde/sde_encoder_dce.c index cde539fdd732..c299494c33df 100644 --- a/msm/sde/sde_encoder_dce.c +++ b/msm/sde/sde_encoder_dce.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. */ @@ -913,6 +914,26 @@ void sde_encoder_dce_set_bpp(struct msm_mode_info mode_info, sde_crtc->src_bpp, sde_crtc->target_bpp); } +bool sde_encoder_has_dsc_hw_rev_2(struct sde_encoder_virt *sde_enc) +{ + enum msm_display_compression_type comp_type; + int i; + + if (!sde_enc) + return false; + + comp_type = sde_enc->mode_info.comp_info.comp_type; + + if (comp_type != MSM_DISPLAY_COMPRESSION_DSC) + return false; + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) + if (sde_enc->hw_dsc[i]) + return test_bit(SDE_DSC_HW_REV_1_2, &sde_enc->hw_dsc[i]->caps->features); + + return false; +} + void sde_encoder_dce_disable(struct sde_encoder_virt *sde_enc) { enum msm_display_compression_type comp_type; diff --git a/msm/sde/sde_encoder_dce.h b/msm/sde/sde_encoder_dce.h index b217a03484fb..a406ee1c4d98 100644 --- a/msm/sde/sde_encoder_dce.h +++ b/msm/sde/sde_encoder_dce.h @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2017, 2020 The Linux Foundation. All rights reserved. */ @@ -36,4 +37,10 @@ int sde_encoder_dce_setup(struct sde_encoder_virt *sde_enc, */ void sde_encoder_dce_flush(struct sde_encoder_virt *sde_enc); +/** + * sde_encoder_has_dsc_hw_rev_2 :checks if dsc_hw_rev_1_2 feature is enabled + * @sde_enc: pointer to virtual encoder structure + */ +bool sde_encoder_has_dsc_hw_rev_2(struct sde_encoder_virt *sde_enc); + #endif /* __SDE_ENCODER_DCE_H__ */ From d55329a469cbe4a37f9042247d3d141733123c2d Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 22 Oct 2021 12:13:56 +0530 Subject: [PATCH 33/51] disp: msm: sde: disable vsync_in to update tear check This change updates the single buffer tear check registers when vsync_in is disabled. It allows mode switch frame trigger as posted start frame trigger. Change-Id: I8068736b2ea01f6e4160e765fc39d7fc2a8590c9 Signed-off-by: Dhaval Patel Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_encoder.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index e7edc2033c10..767cc4c00bc5 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -2608,7 +2608,6 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) &sde_enc->cur_master->intf_cfg_v1); _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false); - sde_encoder_control_te(drm_enc, true); memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi)); memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi)); @@ -2711,6 +2710,7 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc) sde_enc->cur_master->ops.restore(sde_enc->cur_master); _sde_encoder_virt_enable_helper(drm_enc); + sde_encoder_control_te(drm_enc, true); } static void sde_encoder_off_work(struct kthread_work *work) @@ -2792,6 +2792,9 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) return; } + /* turn off vsync_in to update tear check configuration */ + sde_encoder_control_te(drm_enc, false); + memset(&sde_enc->cur_master->intf_cfg_v1, 0, sizeof(sde_enc->cur_master->intf_cfg_v1)); @@ -2847,6 +2850,7 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) sde_enc->cur_master->ops.enable(sde_enc->cur_master); _sde_encoder_virt_enable_helper(drm_enc); + sde_encoder_control_te(drm_enc, true); } void sde_encoder_virt_reset(struct drm_encoder *drm_enc) From d32ac73186071dc6f025e47b60ddb37e3efe536a Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 22 Oct 2021 12:17:56 +0530 Subject: [PATCH 34/51] disp: msm: sde: disable vsync counter before tear check update Disable vsync counter before single buffer tear check update. It allows to trigger the resolution switch frame as posted start frame. Change-Id: I2726372fd0e6d14ab0f79e3e3b0731a074158682 Signed-off-by: Dhaval Patel Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_hw_intf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 5c4bc917d654..1a97ef8d361e 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #include @@ -543,20 +544,20 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, struct sde_hw_tear_check *te) { struct sde_hw_blk_reg_map *c; - int cfg; + u32 cfg = 0; if (!intf) return -EINVAL; c = &intf->hw; - cfg = BIT(19); /* VSYNC_COUNTER_EN */ if (te->hw_vsync_mode) cfg |= BIT(20); cfg |= te->vsync_count; SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); + wmb(); /* disable vsync counter before updating single buffer registers */ SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); SDE_REG_WRITE(c, INTF_TEAR_VSYNC_INIT_VAL, te->vsync_init_val); SDE_REG_WRITE(c, INTF_TEAR_RD_PTR_IRQ, te->rd_ptr_irq); @@ -567,6 +568,8 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, te->sync_threshold_start)); SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT, (te->start_pos + te->sync_threshold_start + 1)); + cfg |= BIT(19); /* VSYNC_COUNTER_EN */ + SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); return 0; } From c5ff99c3a31b75baf337a7f329903266a775ebae Mon Sep 17 00:00:00 2001 From: Yashwanth Date: Wed, 8 Dec 2021 11:18:32 +0530 Subject: [PATCH 35/51] disp: msm: sde: update TEAR_SYNC_WRCOUNT register before vsync counter During DMS, when tear check registers are updated near rd_ptr line count, it was resulting in a spurious rd_ptr_irq to which frame is getting latched and causing tearing on the screen. This change updates TEAR_SYNC_WRCOUNT register before disabling the vsync counter and adds a spinlock to avoid pre-emption. Change-Id: I986dc3ce6fb3da5fed758c2f50562df44f2ab557 Signed-off-by: Yashwanth --- msm/sde/sde_hw_intf.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 1a97ef8d361e..bc21321e3a9b 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -545,10 +545,12 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, { struct sde_hw_blk_reg_map *c; u32 cfg = 0; + spinlock_t tearcheck_spinlock; if (!intf) return -EINVAL; + spin_lock_init(&tearcheck_spinlock); c = &intf->hw; if (te->hw_vsync_mode) @@ -556,6 +558,14 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, cfg |= te->vsync_count; + /* + * Local spinlock is acquired here to avoid pre-emption + * as below register programming should be completed in + * less than 2^16 vsync clk cycles. + */ + spin_lock(&tearcheck_spinlock); + SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT, + (te->start_pos + te->sync_threshold_start + 1)); SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); wmb(); /* disable vsync counter before updating single buffer registers */ SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); @@ -566,10 +576,9 @@ static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, SDE_REG_WRITE(c, INTF_TEAR_SYNC_THRESH, ((te->sync_threshold_continue << 16) | te->sync_threshold_start)); - SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT, - (te->start_pos + te->sync_threshold_start + 1)); cfg |= BIT(19); /* VSYNC_COUNTER_EN */ SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); + spin_unlock(&tearcheck_spinlock); return 0; } From 8d57f083f2c20f9dfc28e9515d319d7bcff0fdf5 Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Fri, 22 Oct 2021 12:21:19 +0530 Subject: [PATCH 36/51] disp: msm: sde: cancel delayed_off_work before reinitialization Canceling delayed_off_work in encoder pre_modeset might not be executed in all cases, but the following encoder enable might initialize the work. This will lead to list corruption as delayed_off work list node is reinitialized before removing from linked list. Move canceling delayed_off_work to start of encoder mode_set to ensure work is canceled before reinitialization. Change-Id: I38687604f2eedced308ea02019c162022725534e Signed-off-by: Lei Chen Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_encoder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 767cc4c00bc5..c78066d282a0 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1842,9 +1842,6 @@ static int _sde_encoder_rc_pre_modeset(struct drm_encoder *drm_enc, { int ret = 0; - /* cancel delayed off work, if any */ - _sde_encoder_rc_cancel_delayed(sde_enc, sw_event); - mutex_lock(&sde_enc->rc_lock); if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) { @@ -2371,6 +2368,9 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, sde_connector_state_get_mode_info(conn->state, &sde_enc->mode_info); sde_encoder_dce_set_bpp(sde_enc->mode_info, sde_enc->crtc); + /* cancel delayed off work, if any */ + kthread_cancel_delayed_work_sync(&sde_enc->delayed_off_work); + /* release resources before seamless mode change */ ret = sde_encoder_virt_modeset_rc(drm_enc, adj_mode, true); if (ret) From f77b7c533c0bd59b2a0b0e5bda4974f062a73a8d Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Fri, 22 Oct 2021 12:25:08 +0530 Subject: [PATCH 37/51] disp: msm: sde: remove clearing cur_master in encoder enable function SDE IRQ callback can run in parallel thread to modeset after removing pp_done wait before pre_modeset. If cur_master is cleared in encoder enable function and irq callback is triggered at the same time, the irq callback could not be handled properly as cur_master is NULL.So remove clearing cur_master in encoder enable function to avoid the race condition between modeset and irq callback. Change-Id: I2059c699a68838b3c9f6a7dd658a35f178b18c42 Signed-off-by: Lei Chen Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_encoder.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c78066d282a0..5605f5399db0 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -2733,6 +2733,7 @@ static void sde_encoder_off_work(struct kthread_work *work) static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = NULL; + bool has_master_enc = false; int i, ret = 0; struct msm_compression_info *comp_info = NULL; struct drm_display_mode *cur_mode = NULL; @@ -2759,18 +2760,19 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) SDE_DEBUG_ENC(sde_enc, "\n"); SDE_EVT32(DRMID(drm_enc), cur_mode->hdisplay, cur_mode->vdisplay); - sde_enc->cur_master = NULL; for (i = 0; i < sde_enc->num_phys_encs; i++) { struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; if (phys && phys->ops.is_master && phys->ops.is_master(phys)) { SDE_DEBUG_ENC(sde_enc, "master is now idx %d\n", i); sde_enc->cur_master = phys; + has_master_enc = true; break; } } - if (!sde_enc->cur_master) { + if (!has_master_enc) { + sde_enc->cur_master = NULL; SDE_ERROR("virt encoder has no master! num_phys %d\n", i); return; } From bcb9619f9f536275baabefd097ae248f82360eaf Mon Sep 17 00:00:00 2001 From: Andhavarapu Karthik Date: Mon, 10 Jan 2022 12:33:39 +0530 Subject: [PATCH 38/51] disp: msm: sde: fix RM poll timeouts during PM suspend/resume usecase When PM resume commit occurs with mode_changed, enable flag set and active_changed flag not set, the RM reservation allocated is not cleared during crtc_destroy_state as encoder_mask in old_crtc_state is NULL. When there is resume commit from HAL, it polls for this pending reservation to be cleared causing poll timeouts. This change releases the pending reservation from the crtc->state->encoder mask, as the old_crtc_state encoder_mask will be reset with default values at start of PM resume. Change-Id: Ica1c90a6ea7ef7df08fcb976b6f1b54bbfeea357 Signed-off-by: Andhavarapu Karthik --- msm/sde/sde_crtc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index e6811e616a58..a17ffaeac08a 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -3482,6 +3483,7 @@ static void sde_crtc_destroy_state(struct drm_crtc *crtc, struct sde_crtc_state *cstate; struct drm_encoder *enc; struct sde_kms *sde_kms; + u32 encoder_mask; if (!crtc || !state) { SDE_ERROR("invalid argument(s)\n"); @@ -3497,9 +3499,11 @@ static void sde_crtc_destroy_state(struct drm_crtc *crtc, return; } - SDE_DEBUG("crtc%d\n", crtc->base.id); + encoder_mask = state->encoder_mask ? state->encoder_mask : + crtc->state->encoder_mask; + SDE_DEBUG("crtc%d\n, encoder_mask=%d", crtc->base.id, encoder_mask); - drm_for_each_encoder_mask(enc, crtc->dev, state->encoder_mask) + drm_for_each_encoder_mask(enc, crtc->dev, encoder_mask) sde_rm_release(&sde_kms->rm, enc, true); __drm_atomic_helper_crtc_destroy_state(state); From fb71974cf5e125f7811978af08f8c42b88b47070 Mon Sep 17 00:00:00 2001 From: Yahui Wang Date: Tue, 4 Jan 2022 13:49:19 +0800 Subject: [PATCH 39/51] disp: msm: sde: move sde power event call into kms post init The sde power event function needs to get actual sde kms irq number to handle irq update call, but it is not able to know the irq number before irq installation, so move sde power event call into kms post init to avoid unbalanced irq issues. Change-Id: Id262b86f98299fbb9a51c9ccb8e68c7bde7f57ed Signed-off-by: Yahui Wang --- msm/sde/sde_kms.c | 53 +++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 6785c65754dd..b9609ec6fc0f 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -111,6 +112,8 @@ static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms); static int _sde_kms_mmu_init(struct sde_kms *sde_kms); static int _sde_kms_register_events(struct msm_kms *kms, struct drm_mode_object *obj, u32 event, bool en); +static void sde_kms_handle_power_event(u32 event_type, void *usr); + bool sde_is_custom_client(void) { return sdecustom; @@ -2178,14 +2181,38 @@ static int sde_kms_postinit(struct msm_kms *kms) struct drm_crtc *crtc; struct drm_connector *conn; struct drm_connector_list_iter conn_iter; - int rc; + struct msm_drm_private *priv; + int i, rc; - if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev) { + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev || + !sde_kms->dev->dev_private) { SDE_ERROR("invalid sde_kms\n"); return -EINVAL; } dev = sde_kms->dev; + priv = sde_kms->dev->dev_private; + + /* + * Handle (re)initializations during power enable, the sde power + * event call has to be after drm_irq_install to handle irq update. + */ + sde_kms_handle_power_event(SDE_POWER_EVENT_POST_ENABLE, sde_kms); + sde_kms->power_event = sde_power_handle_register_event(&priv->phandle, + SDE_POWER_EVENT_POST_ENABLE | + SDE_POWER_EVENT_PRE_DISABLE, + sde_kms_handle_power_event, sde_kms, "kms"); + + if (sde_kms->splash_data.num_splash_displays) { + SDE_DEBUG("Skipping MDP Resources disable\n"); + } else { + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_set_quota(&priv->phandle, i, + SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, + SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + + pm_runtime_put_sync(sde_kms->dev->dev); + } rc = _sde_debugfs_init(sde_kms); if (rc) @@ -4686,7 +4713,7 @@ static int sde_kms_hw_init(struct msm_kms *kms) struct drm_device *dev; struct msm_drm_private *priv; struct platform_device *platformdev; - int i, irq_num, rc = -EINVAL; + int irq_num, rc = -EINVAL; if (!kms) { SDE_ERROR("invalid kms\n"); @@ -4735,26 +4762,6 @@ static int sde_kms_hw_init(struct msm_kms *kms) */ dev->mode_config.allow_fb_modifiers = true; - /* - * Handle (re)initializations during power enable - */ - sde_kms_handle_power_event(SDE_POWER_EVENT_POST_ENABLE, sde_kms); - sde_kms->power_event = sde_power_handle_register_event(&priv->phandle, - SDE_POWER_EVENT_POST_ENABLE | - SDE_POWER_EVENT_PRE_DISABLE, - sde_kms_handle_power_event, sde_kms, "kms"); - - if (sde_kms->splash_data.num_splash_displays) { - SDE_DEBUG("Skipping MDP Resources disable\n"); - } else { - for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) - sde_power_data_bus_set_quota(&priv->phandle, i, - SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, - SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); - - pm_runtime_put_sync(sde_kms->dev->dev); - } - sde_kms->affinity_notify.notify = sde_kms_irq_affinity_notify; sde_kms->affinity_notify.release = sde_kms_irq_affinity_release; From 58fe91002a987158cccc9c43a88140c12fdaf26e Mon Sep 17 00:00:00 2001 From: Yashwanth Date: Mon, 17 Jan 2022 11:37:56 +0530 Subject: [PATCH 40/51] disp: msm: sde: always set CTL_x_UIDLE_ACTIVE register to "1" As per HW recommendation, FAL10_VETO_OVERRIDE register can be programmed to disable FAL10 in alternate to disabling uidle at the sspp level as disabling UIDLE controller will only disable DPU traffic shaping and will not stop the system from entering FAL10 state. This change programs FAL10_VETO_OVERRIDE register during uidle disable and also sets CTL_x_UIDLE_ACTIVE register to always one to avoid race condition between different CTL paths. Change-Id: I0361543e345bf6c237ad60560e2b11604f5abf92 Signed-off-by: Yashwanth --- msm/sde/sde_crtc.c | 7 +------ msm/sde/sde_crtc.h | 2 +- msm/sde/sde_hw_uidle.c | 6 +++++- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index e6811e616a58..5bcbd67736a9 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -3324,11 +3325,6 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, if (crtc->state->mode_changed || sde_kms->perf.catalog->uidle_cfg.dirty) sde_core_perf_crtc_update_uidle(crtc, true); - else if (!test_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask) && - !sde_kms->perf.uidle_enabled) - sde_core_uidle_setup_ctl(crtc, false); - - test_and_clear_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask); /* * Since CP properties use AXI buffer to program the @@ -3999,7 +3995,6 @@ void sde_crtc_reset_sw_state(struct drm_crtc *crtc) /* mark other properties which need to be dirty for next update */ set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, &sde_crtc->revalidate_mask); - set_bit(SDE_CRTC_DIRTY_UIDLE, &sde_crtc->revalidate_mask); if (cstate->num_ds_enabled) set_bit(SDE_CRTC_DIRTY_DEST_SCALER, cstate->dirty); } diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 43db78485c69..4071e4841485 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -399,7 +400,6 @@ struct sde_crtc { enum sde_crtc_dirty_flags { SDE_CRTC_DIRTY_DEST_SCALER, SDE_CRTC_DIRTY_DIM_LAYERS, - SDE_CRTC_DIRTY_UIDLE, SDE_CRTC_DIRTY_MAX, }; diff --git a/msm/sde/sde_hw_uidle.c b/msm/sde/sde_hw_uidle.c index bb6915205c7e..858cf42a9f1c 100644 --- a/msm/sde/sde_hw_uidle.c +++ b/msm/sde/sde_hw_uidle.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * */ @@ -161,7 +162,7 @@ void sde_hw_uidle_setup_ctl(struct sde_hw_uidle *uidle, struct sde_uidle_ctl_cfg *cfg) { struct sde_hw_blk_reg_map *c = &uidle->hw; - u32 reg_val; + u32 reg_val, fal10_veto_regval = 0; reg_val = SDE_REG_READ(c, UIDLE_CTL); reg_val = (reg_val & ~BIT(31)) | (cfg->uidle_enable ? BIT(31) : 0); @@ -176,6 +177,9 @@ void sde_hw_uidle_setup_ctl(struct sde_hw_uidle *uidle, FAL10_EXIT_CNT_MSK); SDE_REG_WRITE(c, UIDLE_CTL, reg_val); + if (!cfg->uidle_enable) + fal10_veto_regval |= (BIT(31) | BIT(0)); + SDE_REG_WRITE(c, UIDLE_FAL10_VETO_OVERRIDE, fal10_veto_regval); } static void sde_hw_uilde_active_override(struct sde_hw_uidle *uidle, From 075e3e1fa1531eaff0927aea382818a09547544a Mon Sep 17 00:00:00 2001 From: Yahui Wang Date: Mon, 17 Jan 2022 16:53:25 +0800 Subject: [PATCH 41/51] disp: msm: sde: set NOAUTOEN for sde irq to match with power event If display cont-splash is enabled, then sde irq will be enabled after registration, but sde power event assumes irq to be disabled by default and will still try to enable irq with first power event call, then could cause unbalanced irq enable warning on boot up. Change-Id: Ic5482dd06501721664994f77cd5764140afb7a62 Signed-off-by: Yahui Wang --- msm/sde/sde_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_irq.c b/msm/sde/sde_irq.c index 974c163a6770..b83b07dc1f87 100644 --- a/msm/sde/sde_irq.c +++ b/msm/sde/sde_irq.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2019, 2021, The Linux Foundation. All rights reserved. */ @@ -103,7 +104,7 @@ void sde_irq_preinstall(struct msm_kms *kms) } /* disable irq until power event enables it */ - if (!sde_kms->splash_data.num_splash_displays && !sde_kms->irq_enabled) + if (!sde_kms->irq_enabled) irq_set_status_flags(sde_kms->irq_num, IRQ_NOAUTOEN); } From 986687d5d17e3f8a5056fc43924a17608c0e4c34 Mon Sep 17 00:00:00 2001 From: Sai Srujana Oruganti Date: Mon, 10 Jan 2022 15:22:46 +0530 Subject: [PATCH 42/51] disp: msm: sde: fix null pointer dereference Add condition to prevent null point dereference. Change-Id: If6019c0c7035a25ed87afa02c056044c8716bd64 Signed-off-by: Sai Srujana Oruganti --- msm/sde/sde_hw_reg_dma_v1.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/msm/sde/sde_hw_reg_dma_v1.c b/msm/sde/sde_hw_reg_dma_v1.c index 7b73dafecddc..917d76e0622b 100644 --- a/msm/sde/sde_hw_reg_dma_v1.c +++ b/msm/sde/sde_hw_reg_dma_v1.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1191,6 +1192,10 @@ static int last_cmd_v1(struct sde_hw_ctl *ctl, enum sde_reg_dma_queue q, //Lack of block support will be caught by kick_off memset(&hw, 0, sizeof(hw)); SET_UP_REG_DMA_REG(hw, reg_dma, kick_off.dma_type); + if (hw.hwversion == 0) { + DRM_ERROR("DMA type %d is unsupported\n", kick_off.dma_type); + return -EOPNOTSUPP; + } SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY, mode, ctl->idx, kick_off.queue_select, kick_off.dma_type, kick_off.op); From 3edfceab68d295c8a238aa8662012acee8482d99 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Mon, 29 Nov 2021 17:28:03 -0800 Subject: [PATCH 43/51] disp: msm: sde: while timing engine enabling poll for active region DCS commands triggered right after timing engine enable can conflict with blanking period causing command transfer failures. Right after timing engine enable poll for frame start and line count reaching active region of display before any DCS commands. Change-Id: Ia3967e01c3bb5bc82aa3549c300fa8335e00210c Signed-off-by: Prabhanjan Kandula --- msm/sde/sde_encoder_phys_vid.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 7e444aa4dc79..2937de7088e9 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -1107,12 +1107,41 @@ exit: phys_enc->enable_state = SDE_ENC_DISABLED; } +static int sde_encoder_phys_vid_poll_for_active_region(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_vid *vid_enc; + struct intf_timing_params *timing; + u32 line_cnt, v_inactive, poll_time_us, trial = 0; + + if (!phys_enc || !phys_enc->hw_intf || !phys_enc->hw_intf->ops.get_line_count) + return -EINVAL; + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + timing = &vid_enc->timing_params; + + /* if programmable fetch is not enabled return early */ + if (!programmable_fetch_get_num_lines(vid_enc, timing)) + return 0; + + poll_time_us = DIV_ROUND_UP(1000000, timing->vrefresh) / MAX_POLL_CNT; + v_inactive = timing->v_front_porch + timing->v_back_porch + timing->vsync_pulse_width; + + do { + usleep_range(poll_time_us, poll_time_us + 5); + line_cnt = phys_enc->hw_intf->ops.get_line_count(phys_enc->hw_intf); + trial++; + } while ((trial < MAX_POLL_CNT) || (line_cnt < v_inactive)); + + return (trial >= MAX_POLL_CNT) ? -ETIMEDOUT : 0; +} + static void sde_encoder_phys_vid_handle_post_kickoff( struct sde_encoder_phys *phys_enc) { unsigned long lock_flags; struct sde_encoder_phys_vid *vid_enc; u32 avr_mode; + u32 ret; if (!phys_enc) { SDE_ERROR("invalid encoder\n"); @@ -1135,6 +1164,10 @@ static void sde_encoder_phys_vid_handle_post_kickoff( 1); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + ret = sde_encoder_phys_vid_poll_for_active_region(phys_enc); + if (ret) + SDE_DEBUG_VIDENC(vid_enc, "poll for active failed ret:%d\n", ret); } phys_enc->enable_state = SDE_ENC_ENABLED; } From 74924557842e3e4f64e34f59d57ec118be3d7086 Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Mon, 24 Jan 2022 12:35:40 +0530 Subject: [PATCH 44/51] disp: msm: sde: set parent to xo for link clks while enterting suspend Clk framework will cache current parent and skip subsequent clk_set_parent calls if same parent is set. In case of deepsleep, clk's parent is reset to xo clks for link clocks but framework will still see cached parent and skip set_parent call. To avoid this state, set parent to xo clock for link clocks, before we enter suspend, so that framework and hw state are in correct state, when we exit from deepsleep. Change-Id: Ic7f70ec13497c70a8b4351ebfa49c0db98fc63ab Signed-off-by: Venkata Prahlad Valluru --- msm/dsi/dsi_clk_manager.c | 11 +++++++ msm/dsi/dsi_display.c | 60 +++++++++++++++++++++++++++++++++++++++ msm/dsi/dsi_display.h | 2 ++ 3 files changed, 73 insertions(+) diff --git a/msm/dsi/dsi_clk_manager.c b/msm/dsi/dsi_clk_manager.c index b8b5bec682c4..a213c6959b38 100644 --- a/msm/dsi/dsi_clk_manager.c +++ b/msm/dsi/dsi_clk_manager.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ @@ -172,6 +173,16 @@ int dsi_clk_update_parent(struct dsi_clk_link_set *parent, { int rc = 0; + if (!parent->byte_clk || !parent->pixel_clk) { + DSI_ERR("Invalid parent\n"); + return -EINVAL; + } + + if (!child->byte_clk || !child->pixel_clk) { + DSI_ERR("Invalid child\n"); + return -EINVAL; + } + rc = clk_set_parent(child->byte_clk, parent->byte_clk); if (rc) { DSI_ERR("failed to set byte clk parent\n"); diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 2330d73f5c0f..b72dabdc7b59 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -2657,6 +2658,38 @@ error: return rc; } +#ifdef CONFIG_DEEPSLEEP +static int dsi_display_unset_clk_src(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + DSI_DEBUG("[%s] unset source clocks\n", display->name); + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + + /* set ctrl clocks to xo source */ + rc = dsi_ctrl_set_clock_source(ctrl->ctrl, + &display->clock_info.xo_clks); + if (rc) { + DSI_ERR("[%s] failed to set source clocks, rc=%d\n", + display->name, rc); + return rc; + } + } + return 0; +} +#else +static inline int dsi_display_unset_clk_src(struct dsi_display *display) +{ + return 0; +} +#endif + static int dsi_display_set_clk_src(struct dsi_display *display) { int rc = 0; @@ -3442,6 +3475,7 @@ static int dsi_display_clocks_init(struct dsi_display *display) { int i, rc = 0, num_clk = 0; const char *clk_name; + const char *xo_byte = "xo_byte", *xo_pixel = "xo_pixel"; const char *src_byte = "src_byte", *src_pixel = "src_pixel"; const char *mux_byte = "mux_byte", *mux_pixel = "mux_pixel"; const char *cphy_byte = "cphy_byte", *cphy_pixel = "cphy_pixel"; @@ -3449,6 +3483,7 @@ static int dsi_display_clocks_init(struct dsi_display *display) const char *shadow_cphybyte = "shadow_cphybyte", *shadow_cphypixel = "shadow_cphypixel"; struct clk *dsi_clk; + struct dsi_clk_link_set *xo = &display->clock_info.xo_clks; struct dsi_clk_link_set *src = &display->clock_info.src_clks; struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; struct dsi_clk_link_set *cphy = &display->clock_info.cphy_clks; @@ -3479,6 +3514,15 @@ static int dsi_display_clocks_init(struct dsi_display *display) DSI_ERR("failed to get %s, rc=%d\n", clk_name, rc); + if (dsi_display_check_prefix(xo_byte, clk_name)) { + xo->byte_clk = NULL; + goto error; + } + if (dsi_display_check_prefix(xo_pixel, clk_name)) { + xo->pixel_clk = NULL; + goto error; + } + if (dsi_display_check_prefix(mux_byte, clk_name)) { mux->byte_clk = NULL; goto error; @@ -3524,6 +3568,16 @@ static int dsi_display_clocks_init(struct dsi_display *display) } } + if (dsi_display_check_prefix(xo_byte, clk_name)) { + xo->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(xo_pixel, clk_name)) { + xo->pixel_clk = dsi_clk; + continue; + } + if (dsi_display_check_prefix(src_byte, clk_name)) { src->byte_clk = dsi_clk; continue; @@ -8586,6 +8640,12 @@ int dsi_display_unprepare(struct dsi_display *display) DSI_ERR("[%s] failed to disable Link clocks, rc=%d\n", display->name, rc); + /* set to dsi clocks to xo clocks */ + rc = dsi_display_unset_clk_src(display); + if (rc) + DSI_ERR("[%s] failed to unset clocks, rc=%d\n", + display->name, rc); + rc = dsi_display_ctrl_deinit(display); if (rc) DSI_ERR("[%s] failed to deinit controller, rc=%d\n", diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index 2dc7bc7dd137..e2932a0d530d 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -110,6 +111,7 @@ struct dsi_display_boot_param { * @shadow_cphy_clks: Used for C-phy clock switch. */ struct dsi_display_clk_info { + struct dsi_clk_link_set xo_clks; struct dsi_clk_link_set src_clks; struct dsi_clk_link_set mux_clks; struct dsi_clk_link_set cphy_clks; From 1f5cc03a33c9216fc3933620d5c483491cf7713a Mon Sep 17 00:00:00 2001 From: Rajeev Nandan Date: Thu, 17 Feb 2022 00:33:59 +0530 Subject: [PATCH 45/51] disp: msm: dsi: fix compressed RGB101010 support The destination format for compressed rgb101010 should be the same as rgb888. After adding uncompressed RGB101010 support, the programming for compressed rgb101010 went wrong. Fix this to re-enable compressed rgb101010 format support. Change-Id: I805e15df14dda8ff0653a0dba8c4efe3fe0681fd Signed-off-by: Rajeev Nandan --- msm/dsi/dsi_display.c | 14 ++++++++++++++ msm/dsi/dsi_panel.c | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index b72dabdc7b59..e6c03fc7f6c0 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6972,6 +6972,20 @@ int dsi_display_get_modes(struct dsi_display *display, goto error; } + /* + * Update the host_config.dst_format for compressed RGB101010 + * pixel format. + */ + if (display->panel->host_config.dst_format == + DSI_PIXEL_FORMAT_RGB101010 && + display_mode.timing.dsc_enabled) { + display->panel->host_config.dst_format = + DSI_PIXEL_FORMAT_RGB888; + DSI_DEBUG("updated dst_format from %d to %d\n", + DSI_PIXEL_FORMAT_RGB101010, + display->panel->host_config.dst_format); + } + is_cmd_mode = (display_mode.panel_mode == DSI_OP_CMD_MODE); /* Setup widebus support */ diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 687d1036628d..cdfeb88e6873 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -934,6 +935,15 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, fmt = DSI_PIXEL_FORMAT_RGB666; break; case 30: + /* + * The destination pixel format (host->dst_format) depends + * upon the compression, and should be RGB888 if the DSC is + * enable. + * The DSC status information is inside the timing modes, that + * is parsed during first dsi_display_get_modes() call. + * The dst_format will be updated there depending upon the + * DSC status. + */ fmt = DSI_PIXEL_FORMAT_RGB101010; break; case 24: From 3c0f029ebbd7a78adebd8f6c12a65321f95f250d Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Sat, 19 Feb 2022 12:39:41 +0530 Subject: [PATCH 46/51] disp: msm: sde: validate plane mode and gem obj flags Add changes to validate the plane fb_translation mode and dma_buf flags of drm_gem_obj attached to plane. It avoids device panic on S2 translation fault and fails the drm_atomic_commit for which mismatch is detected. In current codeflow, only S1 mappings are modified when dma_buf is detached from Non_sec CB and attached to secure SB as part of msm_gem_get_iova_locked API, but S2 mapping entries are not modified and this crash is seen. Change-Id: I6bced92994cd8681cf69231e41bec0c262dafd33 Signed-off-by: Jayaprakash Madisetty --- msm/msm_drv.h | 3 +++ msm/msm_fb.c | 32 ++++++++++++++++++++++++++++++++ msm/sde/sde_plane.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 2c417ed21ad4..438c9abbec32 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -1128,6 +1129,8 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format); +int msm_fb_obj_get_attrs(struct drm_gem_object *obj, int *fb_ns, + int *fb_sec, int *fb_sec_dir, unsigned long *flags); struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); void msm_fbdev_free(struct drm_device *dev); diff --git a/msm/msm_fb.c b/msm/msm_fb.c index 5c59ac17f38a..2de3d8fd7177 100644 --- a/msm/msm_fb.c +++ b/msm/msm_fb.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -16,6 +17,8 @@ * this program. If not, see . */ +#include +#include #include #include #include @@ -378,3 +381,32 @@ msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format return fb; } + +int msm_fb_obj_get_attrs(struct drm_gem_object *obj, int *fb_ns, + int *fb_sec, int *fb_sec_dir, unsigned long *flags) +{ + + struct msm_gem_object *msm_obj = to_msm_bo(obj); + int ret = 0; + + if (!obj->import_attach) { + DRM_DEBUG("NULL attachment in drm gem object flags:0x%x\n", msm_obj->flags); + return -EINVAL; + } + + ret = dma_buf_get_flags(obj->import_attach->dmabuf, flags); + if (ret) { + DRM_ERROR("dma_buf_get_flags failure, err=%d\n", ret); + return ret; + } + + if (!(*flags & ION_FLAG_SECURE)) + *fb_ns = 1; + else if (*flags & ION_FLAG_CP_PIXEL) + *fb_sec = 1; + else if (*flags & (ION_FLAG_CP_SEC_DISPLAY | + ION_FLAG_CP_CAMERA_PREVIEW)) + *fb_sec_dir = 1; + + return ret; +} diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index 4afaf8abffb3..c8b1c78eb785 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (C) 2014-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -1962,6 +1963,39 @@ static void sde_plane_cleanup_fb(struct drm_plane *plane, } +static int _sde_plane_validate_fb(struct sde_plane *psde, + struct drm_plane_state *state) +{ + struct sde_plane_state *pstate; + struct drm_framebuffer *fb; + uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0; + unsigned long flags = 0; + int mode, ret = 0, n, i; + + pstate = to_sde_plane_state(state); + mode = sde_plane_get_property(pstate, + PLANE_PROP_FB_TRANSLATION_MODE); + + fb = state->fb; + n = fb->format->num_planes; + for (i = 0; i < n; i++) { + ret = msm_fb_obj_get_attrs(fb->obj[i], &fb_ns, &fb_sec, + &fb_sec_dir, &flags); + + if (!ret && ((fb_ns && (mode != SDE_DRM_FB_NON_SEC)) || + (fb_sec && (mode != SDE_DRM_FB_SEC)) || + (fb_sec_dir && (mode != SDE_DRM_FB_SEC_DIR_TRANS)))) { + SDE_ERROR_PLANE(psde, "mode:%d fb:%d dma_buf flags:0x%x rc:%d\n", + mode, fb->base.id, flags, ret); + SDE_EVT32(psde->base.base.id, fb->base.id, flags, + fb_ns, fb_sec, fb_sec_dir, ret, SDE_EVTLOG_ERROR); + return -EINVAL; + } + } + + return 0; +} + static void _sde_plane_sspp_atomic_check_mode_changed(struct sde_plane *psde, struct drm_plane_state *state, struct drm_plane_state *old_state) @@ -2631,6 +2665,11 @@ static int sde_plane_sspp_atomic_check(struct drm_plane *plane, return ret; ret = _sde_plane_validate_shared_crtc(psde, state); + if (ret) + return ret; + + ret = _sde_plane_validate_fb(psde, state); + if (ret) return ret; From caa5fa42476c09bbcb8e3d96c9c56d5b42de23d7 Mon Sep 17 00:00:00 2001 From: Andhavarapu Karthik Date: Thu, 10 Feb 2022 13:46:35 +0530 Subject: [PATCH 47/51] disp: msm: sde: take min ib votes from perf config Changes are made to get minimum ib vote for each bus from device tree entries rather than static values. Change-Id: Ibecb44ac6b8673c5d5b8979014c215ab3ce9e43f Signed-off-by: Andhavarapu Karthik --- msm/sde_power_handle.c | 56 +++++++++++++++++++++++++++++++++++++++++- msm/sde_power_handle.h | 14 +++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/msm/sde_power_handle.c b/msm/sde_power_handle.c index 88d945bc3e11..e17000a8ee23 100644 --- a/msm/sde_power_handle.c +++ b/msm/sde_power_handle.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. */ @@ -455,6 +456,40 @@ static int sde_power_mnoc_bus_parse(struct platform_device *pdev, return rc; } +static void sde_power_parse_ib_votes(struct platform_device *pdev, + struct sde_power_handle *phandle) +{ + int rc = 0; + u32 tmp = 0; + + if (!pdev || !phandle) { + pr_err("invalid input param pdev:%pK phandle:%pK\n", pdev, + phandle); + return; + } + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,sde-min-core-ib-kbps", &tmp); + if (rc) + pr_err("error reading min core ib vote. rc=%d, np=%x\n", rc, pdev->dev.of_node); + + phandle->min_ib_vote.min_core_ib = (!rc ? tmp*1000 : 0); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,sde-min-llcc-ib-kbps", &tmp); + if (rc) + pr_err("error reading min llcc ib vote. rc=%d\n", rc); + + phandle->min_ib_vote.min_llcc_ib = (!rc ? tmp*1000 : 0); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,sde-min-dram-ib-kbps", &tmp); + if (rc) + pr_err("error reading min dram ib vote. rc=%d\n", rc); + + phandle->min_ib_vote.min_dram_ib = (!rc ? tmp*1000 : 0); +} + static int sde_power_bus_parse(struct platform_device *pdev, struct sde_power_handle *phandle) { @@ -599,6 +634,8 @@ int sde_power_resource_init(struct platform_device *pdev, goto bus_err; } + sde_power_parse_ib_votes(pdev, phandle); + INIT_LIST_HEAD(&phandle->event_list); phandle->rsc_client = NULL; @@ -695,6 +732,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable) { int rc = 0, i = 0; struct dss_module_power *mp; + u32 bus_ib_quota = 0; if (!phandle) { pr_err("invalid input argument\n"); @@ -718,10 +756,26 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable) for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX && phandle->data_bus_handle[i].data_paths_cnt > 0; i++) { + + bus_ib_quota = 0; + switch (i) { + case SDE_POWER_HANDLE_DBUS_ID_MNOC: + bus_ib_quota = + phandle->min_ib_vote.min_core_ib; + break; + case SDE_POWER_HANDLE_DBUS_ID_LLCC: + bus_ib_quota = + phandle->min_ib_vote.min_llcc_ib; + break; + case SDE_POWER_HANDLE_DBUS_ID_EBI: + bus_ib_quota = + phandle->min_ib_vote.min_dram_ib; + } + rc = _sde_power_data_bus_set_quota( &phandle->data_bus_handle[i], SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, - SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + bus_ib_quota); if (rc) { pr_err("failed to set data bus vote id=%d rc=%d\n", i, rc); diff --git a/msm/sde_power_handle.h b/msm/sde_power_handle.h index 4273308c9268..5eff752dfcaf 100644 --- a/msm/sde_power_handle.h +++ b/msm/sde_power_handle.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ @@ -125,6 +126,18 @@ struct sde_power_reg_bus_handle { struct sde_power_bus_scaling_data scale_table[VOTE_INDEX_MAX]; }; +/** + * struct sde_min_ib_vote: ib votes on data bus + * @min_core_ib: ib vote on mnoc + * @min_llcc_ib: ib vote on llcc + * @min_dram_ib: ib vote on dram + */ +struct sde_min_ib_vote { + u32 min_core_ib; + u32 min_llcc_ib; + u32 min_dram_ib; +}; + /* * struct sde_power_event - local event registration structure * @client_name: name of the client registering @@ -165,6 +178,7 @@ struct sde_power_handle { u32 last_event_handled; struct sde_rsc_client *rsc_client; bool rsc_client_init; + struct sde_min_ib_vote min_ib_vote; }; /** From 3823e9f6ed9dad55c615bdd12dae78215a94c313 Mon Sep 17 00:00:00 2001 From: Samantha Tran Date: Tue, 7 Sep 2021 12:48:27 -0700 Subject: [PATCH 48/51] disp: msm: sde: remove redundant backlight update Current logic will unnecessarily call backlight update twice in cases where backlight level is changing. When this happens, there is a potential delay waiting for the first command to complete before sending the second backlight update with the same value. This change removes one backlight call and now only calls update if the property is marked as dirty. Change-Id: I260f0d73b3a5af9ced7ae261d247595f965a8d9e Signed-off-by: Samantha Tran --- msm/sde/sde_connector.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 8725798c3fe4..c8d98a10abb0 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -784,10 +784,6 @@ static int _sde_connector_update_dirty_properties( _sde_connector_update_power_locked(c_conn); mutex_unlock(&c_conn->lock); break; - case CONNECTOR_PROP_BL_SCALE: - case CONNECTOR_PROP_SV_BL_SCALE: - _sde_connector_update_bl_scale(c_conn); - break; case CONNECTOR_PROP_HDR_METADATA: _sde_connector_update_hdr_metadata(c_conn, c_state); break; From f9b6363fb76a0fc7ae897a153716cfbca9f419df Mon Sep 17 00:00:00 2001 From: Sai Srujana Oruganti Date: Fri, 11 Feb 2022 15:26:30 +0530 Subject: [PATCH 49/51] drm: msm: call rsc hw_init after hibernation When device boots from hibernation, probe function is not called and rsc need to initialize the hw at the first client update call. Change-Id: Iba3a3aaebbb8052ce93b8aac1746f33ea80795fb Signed-off-by: Sai Srujana Oruganti --- msm/sde_rsc.c | 70 ++++++++++++++++++++++++++++++++++++---------- msm/sde_rsc_priv.h | 5 ++++ 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index 14d180568115..82aff0540f4d 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "[sde_rsc:%s:%d]: " fmt, __func__, __LINE__ @@ -850,6 +851,33 @@ bool sde_rsc_client_is_state_update_complete( return vsync_timestamp0 != 0; } +static int sde_rsc_hw_init(struct sde_rsc_priv *rsc) +{ + int ret; + + ret = regulator_enable(rsc->fs); + if (ret) { + pr_err("sde rsc: fs on failed ret:%d\n", ret); + goto sde_rsc_fail; + } + + rsc->sw_fs_enabled = true; + + ret = sde_rsc_resource_enable(rsc); + if (ret < 0) { + pr_err("failed to enable sde rsc power resources rc:%d\n", ret); + goto sde_rsc_fail; + } + + if (sde_rsc_timer_calculate(rsc, NULL, SDE_RSC_IDLE_STATE)) + goto sde_rsc_fail; + + sde_rsc_resource_disable(rsc); + +sde_rsc_fail: + return ret; +} + /** * sde_rsc_client_state_update() - rsc client state update * Video mode, cmd mode and clk state are suppoed as modes. A client need to @@ -900,6 +928,13 @@ int sde_rsc_client_state_update(struct sde_rsc_client *caller_client, __builtin_return_address(0), rsc->current_state, caller_client->name, state); + /* hw init is required after hibernation */ + if (rsc->hw_reinit && rsc->need_hwinit && + state != SDE_RSC_IDLE_STATE) { + sde_rsc_hw_init(rsc); + rsc->need_hwinit = false; + } + /** * This can only happen if splash is active or qsync is enabled. * In both cases timers need to be updated for when a transition to @@ -1679,6 +1714,9 @@ static int sde_rsc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rsc); rsc->dev = &pdev->dev; + rsc->hw_reinit = of_property_read_bool(pdev->dev.of_node, + "qcom,sde-rsc-need-hw-reinit"); + of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version", &rsc->version); @@ -1746,25 +1784,12 @@ static int sde_rsc_probe(struct platform_device *pdev) goto sde_rsc_fail; } - ret = regulator_enable(rsc->fs); + ret = sde_rsc_hw_init(rsc); if (ret) { - pr_err("sde rsc: fs on failed ret:%d\n", ret); + pr_err("sde rsc: hw init failed ret:%d\n", ret); goto sde_rsc_fail; } - rsc->sw_fs_enabled = true; - - ret = sde_rsc_resource_enable(rsc); - if (ret < 0) { - pr_err("failed to enable sde rsc power resources rc:%d\n", ret); - goto sde_rsc_fail; - } - - if (sde_rsc_timer_calculate(rsc, NULL, SDE_RSC_IDLE_STATE)) - goto sde_rsc_fail; - - sde_rsc_resource_disable(rsc); - INIT_LIST_HEAD(&rsc->client_list); INIT_LIST_HEAD(&rsc->event_list); mutex_init(&rsc->client_lock); @@ -1792,6 +1817,20 @@ rsc_alloc_fail: return ret; } +static int sde_rsc_pm_freeze_late(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sde_rsc_priv *rsc = platform_get_drvdata(pdev); + + rsc->need_hwinit = true; + + return 0; +} + +static const struct dev_pm_ops sde_rsc_pm_ops = { + .freeze_late = sde_rsc_pm_freeze_late, +}; + static int sde_rsc_remove(struct platform_device *pdev) { struct sde_rsc_priv *rsc = platform_get_drvdata(pdev); @@ -1839,6 +1878,7 @@ static struct platform_driver sde_rsc_platform_driver = { .driver = { .name = "sde_rsc", .of_match_table = dt_match, + .pm = &sde_rsc_pm_ops, .suppress_bind_attrs = true, }, }; diff --git a/msm/sde_rsc_priv.h b/msm/sde_rsc_priv.h index 16d83ea2b5a3..778d833d0d9b 100644 --- a/msm/sde_rsc_priv.h +++ b/msm/sde_rsc_priv.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _SDE_RSC_PRIV_H_ @@ -154,6 +155,8 @@ struct sde_rsc_bw_config { * @phandle: module power handle for clocks * @fs: "MDSS GDSC" handle * @sw_fs_enabled: track "MDSS GDSC" sw vote during probe + * @need_hwinit: rsc hw init is required for the next update + * @hw_reinit: rsc hw reinit support enable * * @rpmh_dev: rpmh device node * @drv_io: sde drv io data mapping @@ -201,6 +204,8 @@ struct sde_rsc_priv { struct sde_power_handle phandle; struct regulator *fs; bool sw_fs_enabled; + bool need_hwinit; + bool hw_reinit; struct device *rpmh_dev; struct dss_io_data drv_io; From ebd2c679df88ba6941ed9311cb8430bbe0afda80 Mon Sep 17 00:00:00 2001 From: Kashish Jain Date: Tue, 8 Mar 2022 16:50:49 +0530 Subject: [PATCH 50/51] disp: msm: sde: Fix data width calculation when widebus is enabled Adjust the data width calculation to reduce the rounding off error when the widebus is enabled. Change-Id: Ia2fa4536ce519548989e2befcb22fb685f286c9e Signed-off-by: Kashish Jain --- msm/sde/sde_hw_intf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index bc21321e3a9b..925db925364a 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -258,10 +258,11 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, data_width = p->width; if (p->compression_en) { - data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3); - if (p->wide_bus_en) - data_width >>= 1; + data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 6); + else + data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3); + } else if (!dp_intf && p->wide_bus_en) { data_width = p->width >> 1; } else { From fdf36d71241ffa139c38cd906bef814f5f570ece Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Wed, 23 Mar 2022 15:36:45 +0530 Subject: [PATCH 51/51] disp: msm: use vzalloc for large allocations Large allocations using kzalloc can lead to timeouts. This updates the allocation calls accordingly to use vzalloc to remove requirements on contiguous memory. Change-Id: Ica54483787509ed0e9283289fc9d523e8cde9238 Signed-off-by: Nilaan Gunabalachandran Signed-off-by: Jayaprakash Madisetty --- msm/sde/sde_color_processing.c | 9 +++++---- msm/sde/sde_connector.c | 5 +++-- msm/sde/sde_crtc.c | 4 ++-- msm/sde/sde_plane.c | 6 +++--- msm/sde_dbg.c | 29 +++++++++++++++++++++++------ msm/sde_dbg_evtlog.c | 9 +++++---- 6 files changed, 41 insertions(+), 21 deletions(-) diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index 182378a636ed..b5cc70026bde 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -4476,7 +4477,7 @@ void sde_cp_crtc_enable(struct drm_crtc *drm_crtc) if (!num_mixers) return; mutex_lock(&crtc->crtc_cp_lock); - info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL); + info = vzalloc(sizeof(struct sde_kms_info)); if (info) { for (i = 0; i < ARRAY_SIZE(dspp_cap_update_func); i++) dspp_cap_update_func[i](crtc, info); @@ -4485,7 +4486,7 @@ void sde_cp_crtc_enable(struct drm_crtc *drm_crtc) info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_DSPP_INFO); } - kfree(info); + vfree(info); mutex_unlock(&crtc->crtc_cp_lock); } @@ -4500,12 +4501,12 @@ void sde_cp_crtc_disable(struct drm_crtc *drm_crtc) } crtc = to_sde_crtc(drm_crtc); mutex_lock(&crtc->crtc_cp_lock); - info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL); + info = vzalloc(sizeof(struct sde_kms_info)); if (info) msm_property_set_blob(&crtc->property_info, &crtc->dspp_blob_info, info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_DSPP_INFO); mutex_unlock(&crtc->crtc_cp_lock); - kfree(info); + vfree(info); } diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index c8d98a10abb0..404e8af8c80f 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -2633,7 +2634,7 @@ int sde_connector_set_blob_data(struct drm_connector *conn, return -EINVAL; } - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = vzalloc(sizeof(*info)); if (!info) return -ENOMEM; @@ -2691,7 +2692,7 @@ int sde_connector_set_blob_data(struct drm_connector *conn, SDE_KMS_INFO_DATALEN(info), prop_id); exit: - kfree(info); + vfree(info); return rc; } diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 1764b9110ade..132222fa68e9 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -5415,7 +5415,7 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, return; } - info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL); + info = vzalloc(sizeof(struct sde_kms_info)); if (!info) { SDE_ERROR("failed to allocate info memory\n"); return; @@ -5499,7 +5499,7 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_INFO); - kfree(info); + vfree(info); } static int _sde_crtc_get_output_fence(struct drm_crtc *crtc, diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index c8b1c78eb785..1aa639aefb6b 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -3665,7 +3665,7 @@ static void _sde_plane_setup_capabilities_blob(struct sde_plane *psde, sde_kms_info_add_keyint(info, "pipe_idx", pipe_id); index = (master_plane_id == 0) ? 0 : 1; - if (catalog->has_demura && + if (catalog->has_demura && psde->pipe < SSPP_MAX && catalog->demura_supported[psde->pipe][index] != ~0x0) sde_kms_info_add_keyint(info, "demura_block", index); @@ -3755,7 +3755,7 @@ static void _sde_plane_install_properties(struct drm_plane *plane, psde->catalog = catalog; is_master = !psde->is_virtual; - info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL); + info = vzalloc(sizeof(struct sde_kms_info)); if (!info) { SDE_ERROR("failed to allocate info memory\n"); return; @@ -3834,7 +3834,7 @@ static void _sde_plane_install_properties(struct drm_plane *plane, ARRAY_SIZE(e_fb_translation_mode), 0, PLANE_PROP_FB_TRANSLATION_MODE); - kfree(info); + vfree(info); } static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, diff --git a/msm/sde_dbg.c b/msm/sde_dbg.c index 23855af9c9f0..4d6a5e22d813 100644 --- a/msm/sde_dbg.c +++ b/msm/sde_dbg.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2009-2021, The Linux Foundation. All rights reserved. */ @@ -228,6 +229,7 @@ struct sde_dbg_regbuf { * struct sde_dbg_base - global sde debug base structure * @evtlog: event log instance * @reglog: reg log instance + * @reg_dump_base: base address of register dump region * @reg_base_list: list of register dumping regions * @dev: device pointer * @mutex: mutex to serialize access to serialze dumps, debugfs access @@ -253,6 +255,7 @@ struct sde_dbg_base { struct sde_dbg_evtlog *evtlog; struct sde_dbg_reglog *reglog; struct list_head reg_base_list; + void *reg_dump_base; void *reg_dump_addr; struct device *dev; struct mutex mutex; @@ -992,7 +995,7 @@ static void _sde_dbg_dump_sde_dbg_bus(struct sde_dbg_sde_debug_bus *bus) in_mem = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_MEM); if (in_mem && (!(*dump_mem))) { - *dump_mem = devm_kzalloc(sde_dbg_base.dev, list_size, GFP_KERNEL); + *dump_mem = vzalloc(list_size); bus->cmn.content_size = list_size / sizeof(u32); } @@ -1040,7 +1043,7 @@ static void _sde_dbg_dump_dsi_dbg_bus(struct sde_dbg_sde_debug_bus *bus) mutex_lock(&sde_dbg_dsi_mutex); in_mem = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_MEM); if (in_mem && (!(*dump_mem))) { - *dump_mem = devm_kzalloc(sde_dbg_base.dev, list_size, GFP_KERNEL); + *dump_mem = vzalloc(list_size); bus->cmn.content_size = list_size / sizeof(u32); } @@ -1086,8 +1089,10 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], mutex_lock(&sde_dbg_base.mutex); reg_dump_size = _sde_dbg_get_reg_dump_size(); - dbg_base->reg_dump_addr = devm_kzalloc(sde_dbg_base.dev, - reg_dump_size, GFP_KERNEL); + if (!dbg_base->reg_dump_base) + dbg_base->reg_dump_base = vzalloc(reg_dump_size); + + dbg_base->reg_dump_addr = dbg_base->reg_dump_base; if (!dbg_base->reg_dump_addr) pr_err("Failed to allocate memory for reg_dump_addr size:%d\n", @@ -1627,7 +1632,7 @@ static ssize_t sde_recovery_regdump_read(struct file *file, char __user *ubuf, if (!rbuf->dump_done && !rbuf->cur_blk) { if (!rbuf->buf) - rbuf->buf = kzalloc(DUMP_BUF_SIZE, GFP_KERNEL); + rbuf->buf = vzalloc(DUMP_BUF_SIZE); if (!rbuf->buf) { len = -ENOMEM; goto err; @@ -2402,6 +2407,7 @@ static void sde_dbg_reg_base_destroy(void) list_del(&blk_base->reg_base_head); kfree(blk_base); } + vfree(dbg_base->reg_dump_base); } static void sde_dbg_dsi_ctrl_destroy(void) @@ -2416,12 +2422,22 @@ static void sde_dbg_dsi_ctrl_destroy(void) mutex_unlock(&sde_dbg_dsi_mutex); } +static void sde_dbg_buses_destroy(void) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + + vfree(dbg_base->dbgbus_sde.cmn.dumped_content); + vfree(dbg_base->dbgbus_vbif_rt.cmn.dumped_content); + vfree(dbg_base->dbgbus_dsi.cmn.dumped_content); + vfree(dbg_base->dbgbus_lutdma.cmn.dumped_content); +} + /** * sde_dbg_destroy - destroy sde debug facilities */ void sde_dbg_destroy(void) { - kfree(sde_dbg_base.regbuf.buf); + vfree(sde_dbg_base.regbuf.buf); memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); _sde_dbg_debugfs_destroy(); sde_dbg_base_evtlog = NULL; @@ -2431,6 +2447,7 @@ void sde_dbg_destroy(void) sde_dbg_base.reglog = NULL; sde_dbg_reg_base_destroy(); sde_dbg_dsi_ctrl_destroy(); + sde_dbg_buses_destroy(); mutex_destroy(&sde_dbg_base.mutex); } diff --git a/msm/sde_dbg_evtlog.c b/msm/sde_dbg_evtlog.c index 21ae067957c5..59c8440e413d 100644 --- a/msm/sde_dbg_evtlog.c +++ b/msm/sde_dbg_evtlog.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -219,7 +220,7 @@ struct sde_dbg_evtlog *sde_evtlog_init(void) { struct sde_dbg_evtlog *evtlog; - evtlog = kzalloc(sizeof(*evtlog), GFP_KERNEL); + evtlog = vzalloc(sizeof(*evtlog)); if (!evtlog) return ERR_PTR(-ENOMEM); @@ -239,7 +240,7 @@ struct sde_dbg_reglog *sde_reglog_init(void) { struct sde_dbg_reglog *reglog; - reglog = kzalloc(sizeof(*reglog), GFP_KERNEL); + reglog = vzalloc(sizeof(*reglog)); if (!reglog) return ERR_PTR(-ENOMEM); @@ -350,7 +351,7 @@ void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog) list_del(&filter_node->list); kfree(filter_node); } - kfree(evtlog); + vfree(evtlog); } void sde_reglog_destroy(struct sde_dbg_reglog *reglog) @@ -358,5 +359,5 @@ void sde_reglog_destroy(struct sde_dbg_reglog *reglog) if (!reglog) return; - kfree(reglog); + vfree(reglog); }