diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index ead4fcb290ed..3f0affef1305 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.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. */ #include @@ -615,15 +615,23 @@ void dsi_ctrl_hw_cmn_cmd_engine_setup(struct dsi_ctrl_hw *ctrl, reg |= cmd_mode_format_map[common_cfg->dst_format]; DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL, reg); - reg = DSI_R32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2); - reg |= BIT(16); - DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2, reg); + if (!cfg->mdp_idle_ctrl_en) { + reg = DSI_R32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2); + reg |= BIT(16); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2, reg); + } reg = cfg->wr_mem_start & 0xFF; reg |= (cfg->wr_mem_continue & 0xFF) << 8; reg |= (cfg->insert_dcs_command ? BIT(16) : 0); DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL, reg); + if (cfg->mdp_idle_ctrl_en) { + reg = cfg->mdp_idle_ctrl_len & 0x3FF; + reg |= BIT(12); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_IDLE_CTRL, reg); + } + DSI_CTRL_HW_DBG(ctrl, "Cmd engine setup done\n"); } diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 9f424781b78f..41dee2f61823 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.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 _DSI_DEFS_H_ @@ -542,12 +542,17 @@ struct dsi_video_engine_cfg { * @wr_mem_continue: DCS command for write_memory_continue. * @insert_dcs_command: Insert DCS command as first byte of payload * of the pixel data. + * @mdp_idle_ctrl_en: Enable idle insertion between command mode mdp packets. + * @mdp_idle_ctrl_len: No. of dsi pclk cycles of idle time to insert between + * command mode mdp packets. */ struct dsi_cmd_engine_cfg { u32 max_cmd_packets_interleave; u32 wr_mem_start; u32 wr_mem_continue; bool insert_dcs_command; + bool mdp_idle_ctrl_en; + u32 mdp_idle_ctrl_len; }; /** diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index a4bfad36c655..260be3e257f2 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -595,9 +595,6 @@ static bool dsi_display_validate_reg_read(struct dsi_panel *panel) for (i = 0; i < count; i++) len += lenp[i]; - for (i = 0; i < len; i++) - j += len; - for (j = 0; j < config->groups; ++j) { for (i = 0; i < len; ++i) { if (config->return_buf[i] != diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 3830a7eb8aa4..cdde192e19ac 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1590,6 +1590,21 @@ static int dsi_panel_parse_cmd_host_config(struct dsi_cmd_engine_cfg *cfg, goto error; } + cfg->mdp_idle_ctrl_en = + utils->read_bool(utils->data, "qcom,mdss-dsi-mdp-idle-ctrl-en"); + + if (cfg->mdp_idle_ctrl_en) { + val = 0; + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-mdp-idle-ctrl-len", &val); + if (rc) { + DSI_DEBUG("[%s] mdp idle ctrl len is not defined\n", name); + cfg->mdp_idle_ctrl_len = 0; + cfg->mdp_idle_ctrl_en = false; + rc = 0; + } else { + cfg->mdp_idle_ctrl_len = val; + } + } error: return rc; } diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 40b5e1064d96..00c321821e43 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include "msm_drv.h" @@ -989,6 +990,15 @@ static void context_close(struct msm_file_private *ctx) kfree(ctx); } +static void msm_preclose(struct drm_device *dev, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + + if (kms && kms->funcs && kms->funcs->preclose) + kms->funcs->preclose(kms, file); +} + static void msm_postclose(struct drm_device *dev, struct drm_file *file) { struct msm_drm_private *priv = dev->dev_private; @@ -1513,6 +1523,14 @@ static int msm_release(struct inode *inode, struct file *filp) kfree(node); } + /** + * Handle preclose operation here for removing fb's whose + * refcount > 1. This operation is not triggered from upstream + * drm as msm_driver does not support DRIVER_LEGACY feature. + */ + if (drm_is_current_master(file_priv)) + msm_preclose(dev, file_priv); + return drm_release(inode, filp); } diff --git a/msm/msm_kms.h b/msm/msm_kms.h index e56407afb241..058f97cdf53a 100644 --- a/msm/msm_kms.h +++ b/msm/msm_kms.h @@ -93,6 +93,7 @@ struct msm_kms_funcs { struct drm_encoder *slave_encoder, bool is_cmd_mode); void (*postopen)(struct msm_kms *kms, struct drm_file *file); + void (*preclose)(struct msm_kms *kms, struct drm_file *file); void (*postclose)(struct msm_kms *kms, struct drm_file *file); void (*lastclose)(struct msm_kms *kms); int (*register_events)(struct msm_kms *kms, diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index 5f04f8e19188..260e713c34d2 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -2574,17 +2574,16 @@ static void _sde_crtc_set_input_fence_timeout(struct sde_crtc_state *cstate) cstate->input_fence_timeout_ns *= NSEC_PER_MSEC; } -/** - * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings - * @cstate: Pointer to sde crtc state - */ -static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate) +void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state) { u32 i; + struct sde_crtc_state *cstate; - if (!cstate) + if (!state) return; + cstate = to_sde_crtc_state(state); + for (i = 0; i < cstate->num_dim_layers; i++) memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i])); @@ -2613,7 +2612,7 @@ static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc, if (!usr_ptr) { /* usr_ptr is null when setting the default property value */ - _sde_crtc_clear_dim_layers_v1(cstate); + _sde_crtc_clear_dim_layers_v1(&cstate->base); SDE_DEBUG("dim_layer data removed\n"); goto clear; } diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index 98ee9a46090c..09646cc718ea 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -957,4 +957,10 @@ int sde_crtc_get_num_datapath(struct drm_crtc *crtc, */ void sde_crtc_reset_sw_state(struct drm_crtc *crtc); +/** + * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings + * @cstate: Pointer to drm crtc state + */ +void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state); + #endif /* _SDE_CRTC_H_ */ diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c4d7c021d311..cb5990cd52bb 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1721,6 +1721,7 @@ static int _sde_encoder_rc_kickoff(struct drm_encoder *drm_enc, if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { sde_encoder_irq_control(drm_enc, true); + _sde_encoder_pm_qos_add_request(drm_enc); } else { /* enable all the clks and resources */ ret = _sde_encoder_resource_control_helper(drm_enc, @@ -1959,6 +1960,7 @@ static int _sde_encoder_rc_idle(struct drm_encoder *drm_enc, if (is_vid_mode) { sde_encoder_irq_control(drm_enc, false); + _sde_encoder_pm_qos_remove_request(drm_enc); } else { /* disable all the clks and resources */ _sde_encoder_update_rsc_client(drm_enc, false); @@ -2272,9 +2274,9 @@ static int sde_encoder_virt_modeset_rc(struct drm_encoder *drm_enc, if (pre_modeset) { intf_mode = sde_encoder_get_intf_mode(drm_enc); - if (msm_is_mode_seamless_dms(adj_mode) || - (msm_is_mode_seamless_dyn_clk(adj_mode) && - is_cmd_mode)) { + if ((msm_is_mode_seamless_dms(adj_mode) || + msm_is_mode_seamless_dyn_clk(adj_mode)) && + is_cmd_mode) { /* restore resource state before releasing them */ ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_PRE_MODESET); @@ -2298,9 +2300,9 @@ static int sde_encoder_virt_modeset_rc(struct drm_encoder *drm_enc, adj_mode); } } else { - if (msm_is_mode_seamless_dms(adj_mode) || - (msm_is_mode_seamless_dyn_clk(adj_mode) && - is_cmd_mode)) + if ((msm_is_mode_seamless_dms(adj_mode) || + msm_is_mode_seamless_dyn_clk(adj_mode)) && + is_cmd_mode) sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_POST_MODESET); else if (msm_is_mode_seamless_poms(adj_mode)) diff --git a/msm/sde/sde_fence.c b/msm/sde/sde_fence.c index 5007c2dffbfd..dd9cc295f4e9 100644 --- a/msm/sde/sde_fence.c +++ b/msm/sde/sde_fence.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__ @@ -131,7 +131,7 @@ static bool sde_fence_signaled(struct dma_fence *fence) struct sde_fence *f = to_sde_fence(fence); bool status; - status = (int)((fence->seqno - f->ctx->done_count) <= 0); + status = ((int)(fence->seqno - f->ctx->done_count) <= 0); SDE_DEBUG("status:%d fence seq:%d and timeline:%d\n", status, fence->seqno, f->ctx->done_count); return status; diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index e48a1e20f8b3..e0df384d81cd 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2368,6 +2368,223 @@ static void sde_kms_destroy(struct msm_kms *kms) kfree(sde_kms); } +static void sde_kms_helper_clear_dim_layers(struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *crtc_state = NULL; + struct sde_crtc_state *c_state; + + if (!state || !crtc) { + SDE_ERROR("invalid params\n"); + return; + } + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + c_state = to_sde_crtc_state(crtc_state); + + _sde_crtc_clear_dim_layers_v1(crtc_state); + set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, c_state->dirty); +} + +static int sde_kms_set_crtc_for_conn(struct drm_device *dev, + struct drm_encoder *enc, struct drm_atomic_state *state) +{ + struct drm_connector *conn = NULL; + struct drm_connector *tmp_conn = NULL; + struct drm_connector_list_iter conn_iter; + struct drm_crtc_state *crtc_state = NULL; + struct drm_connector_state *conn_state = NULL; + int ret = 0; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(tmp_conn, &conn_iter) { + if (enc == tmp_conn->state->best_encoder) { + conn = tmp_conn; + break; + } + } + drm_connector_list_iter_end(&conn_iter); + + if (!conn || !enc->crtc) { + SDE_ERROR("invalid params for enc:%d\n", DRMID(enc)); + return -EINVAL; + } + + crtc_state = drm_atomic_get_crtc_state(state, enc->crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + SDE_ERROR("error %d getting crtc %d state\n", + ret, DRMID(enc->crtc)); + return ret; + } + + conn_state = drm_atomic_get_connector_state(state, conn); + if (IS_ERR(conn_state)) { + ret = PTR_ERR(conn_state); + SDE_ERROR("error %d getting connector %d state\n", + ret, DRMID(conn)); + return ret; + } + + crtc_state->active = true; + ret = drm_atomic_set_crtc_for_connector(conn_state, enc->crtc); + if (ret) + SDE_ERROR("error %d setting the crtc\n", ret); + + return ret; +} + +static void _sde_kms_plane_force_remove(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state; + int ret = 0; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + SDE_ERROR("error %d getting plane %d state\n", + ret, plane->base.id); + return; + } + + plane->old_fb = plane->fb; + + SDE_DEBUG("disabling plane %d\n", plane->base.id); + + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret != 0) + SDE_ERROR("error %d disabling plane %d\n", ret, + plane->base.id); + + drm_atomic_set_fb_for_plane(plane_state, NULL); +} + +static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file, + struct drm_atomic_state *state) +{ + struct drm_device *dev = sde_kms->dev; + struct drm_framebuffer *fb, *tfb; + struct list_head fbs; + struct drm_plane *plane; + struct drm_crtc *crtc = NULL; + unsigned int crtc_mask = 0; + int ret = 0; + + INIT_LIST_HEAD(&fbs); + + list_for_each_entry_safe(fb, tfb, &file->fbs, filp_head) { + if (drm_framebuffer_read_refcount(fb) > 1) { + list_move_tail(&fb->filp_head, &fbs); + + drm_for_each_plane(plane, dev) { + if (plane->state && plane->state->fb == fb) { + if (plane->state->crtc) + crtc_mask |= drm_crtc_mask(plane->state->crtc); + _sde_kms_plane_force_remove(plane, state); + } + } + } else { + list_del_init(&fb->filp_head); + drm_framebuffer_put(fb); + } + } + + if (list_empty(&fbs)) { + SDE_DEBUG("skip commit as no fb(s)\n"); + return 0; + } + + drm_for_each_crtc(crtc, dev) { + if ((crtc_mask & drm_crtc_mask(crtc)) && crtc->state->active) { + struct drm_encoder *drm_enc; + + drm_for_each_encoder_mask(drm_enc, crtc->dev, + crtc->state->encoder_mask) { + ret = sde_kms_set_crtc_for_conn(dev, drm_enc, state); + if (ret) + goto error; + } + sde_kms_helper_clear_dim_layers(state, crtc); + } + } + + SDE_EVT32(state, crtc_mask); + SDE_DEBUG("null commit after removing all the pipes\n"); + ret = drm_atomic_commit(state); + +error: + if (ret) { + /* + * move the fbs back to original list, so it would be + * handled during drm_release + */ + list_for_each_entry_safe(fb, tfb, &fbs, filp_head) + list_move_tail(&fb->filp_head, &file->fbs); + + SDE_ERROR("atomic commit failed in preclose, ret:%d\n", ret); + goto end; + } + + while (!list_empty(&fbs)) { + fb = list_first_entry(&fbs, typeof(*fb), filp_head); + + list_del_init(&fb->filp_head); + drm_framebuffer_put(fb); + } + +end: + return ret; +} + +static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_device *dev = sde_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + unsigned int i; + struct drm_atomic_state *state = NULL; + struct drm_modeset_acquire_ctx ctx; + int ret = 0; + + /* cancel pending flip event */ + for (i = 0; i < priv->num_crtcs; i++) + sde_crtc_complete_flip(priv->crtcs[i], file); + + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (WARN_ON(ret)) { + goto end; + } + + state = drm_atomic_state_alloc(dev); + if (!state) { + ret = -ENOMEM; + goto end; + } + + state->acquire_ctx = &ctx; + + for (i = 0; i < TEARDOWN_DEADLOCK_RETRY_MAX; i++) { + ret = _sde_kms_remove_fbs(sde_kms, file, state); + if (ret != -EDEADLK) + break; + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + } + +end: + if (state) + drm_atomic_state_put(state); + + SDE_DEBUG("sde preclose done, ret:%d\n", ret); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + static int _sde_kms_helper_reset_custom_properties(struct sde_kms *sde_kms, struct drm_atomic_state *state) { @@ -3388,12 +3605,7 @@ static void _sde_kms_null_commit(struct drm_device *dev, struct drm_encoder *enc) { struct drm_modeset_acquire_ctx ctx; - struct drm_connector *conn = NULL; - struct drm_connector *tmp_conn = NULL; - struct drm_connector_list_iter conn_iter; struct drm_atomic_state *state = NULL; - struct drm_crtc_state *crtc_state = NULL; - struct drm_connector_state *conn_state = NULL; int retry_cnt = 0; int ret = 0; @@ -3417,32 +3629,10 @@ retry: } state->acquire_ctx = &ctx; - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(tmp_conn, &conn_iter) { - if (enc == tmp_conn->state->best_encoder) { - conn = tmp_conn; - break; - } - } - drm_connector_list_iter_end(&conn_iter); - if (!conn) { - SDE_ERROR("error in finding conn for enc:%d\n", DRMID(enc)); - goto end; - } - - crtc_state = drm_atomic_get_crtc_state(state, enc->crtc); - conn_state = drm_atomic_get_connector_state(state, conn); - if (IS_ERR(conn_state)) { - SDE_ERROR("error %d getting connector %d state\n", - ret, DRMID(conn)); - goto end; - } - - crtc_state->active = true; - ret = drm_atomic_set_crtc_for_connector(conn_state, enc->crtc); + ret = sde_kms_set_crtc_for_conn(dev, enc, state); if (ret) - SDE_ERROR("error %d setting the crtc\n", ret); + goto end; ret = drm_atomic_commit(state); if (ret) @@ -3748,6 +3938,7 @@ static const struct msm_kms_funcs kms_funcs = { .irq_postinstall = sde_irq_postinstall, .irq_uninstall = sde_irq_uninstall, .irq = sde_irq, + .preclose = sde_kms_preclose, .lastclose = sde_kms_lastclose, .prepare_fence = sde_kms_prepare_fence, .prepare_commit = sde_kms_prepare_commit, diff --git a/msm/sde_dbg.c b/msm/sde_dbg.c index 89715d376f24..12ca18734ebc 100644 --- a/msm/sde_dbg.c +++ b/msm/sde_dbg.c @@ -266,6 +266,7 @@ struct sde_dbg_base { struct sde_dbg_evtlog *evtlog; struct sde_dbg_reglog *reglog; struct list_head reg_base_list; + void *reg_dump_addr; struct device *dev; struct mutex mutex; @@ -488,6 +489,7 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, char *base_addr, char *addr, size_t len_bytes, u32 **dump_mem) { u32 in_log, in_mem, len_align, len_padded; + struct sde_dbg_base *dbg_base = &sde_dbg_base; u32 *dump_addr = NULL; char *end_addr; int i; @@ -515,9 +517,10 @@ static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, end_addr = addr + len_bytes; if (in_mem) { - if (dump_mem && !(*dump_mem)) - *dump_mem = devm_kzalloc(sde_dbg_base.dev, len_padded, - GFP_KERNEL); + if (dump_mem && !(*dump_mem)) { + *dump_mem = dbg_base->reg_dump_addr; + dbg_base->reg_dump_addr += len_padded; + } if (dump_mem && *dump_mem) { dump_addr = *dump_mem; @@ -590,6 +593,49 @@ static u32 _sde_dbg_get_dump_range(struct sde_dbg_reg_offset *range_node, return length; } +static u32 _sde_dbg_get_reg_blk_size(struct sde_dbg_reg_base *dbg) +{ + u32 len, len_align, len_padded; + u32 size = 0; + struct sde_dbg_reg_range *range_node; + + if (!dbg || !dbg->base) { + pr_err("dbg base is null!\n"); + return 0; + } + + if (!list_empty(&dbg->sub_range_list)) { + list_for_each_entry(range_node, &dbg->sub_range_list, head) { + len = _sde_dbg_get_dump_range(&range_node->offset, + dbg->max_offset); + len_align = (len + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN; + len_padded = len_align * REG_DUMP_ALIGN; + size += REG_BASE_NAME_LEN + RANGE_NAME_LEN + len_padded; + } + } else { + len = dbg->max_offset; + len_align = (len + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN; + len_padded = len_align * REG_DUMP_ALIGN; + size += REG_BASE_NAME_LEN + RANGE_NAME_LEN + len_padded; + } + return size; +} + +static u32 _sde_dbg_get_reg_dump_size(void) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_reg_base *blk_base; + u32 size = 0; + + if (!dbg_base) + return 0; + + list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) { + size += _sde_dbg_get_reg_blk_size(blk_base); + } + return size; +} + static int _sde_dump_reg_range_cmp(void *priv, struct list_head *a, struct list_head *b) { @@ -635,6 +681,7 @@ static void _sde_dump_reg_by_ranges(struct sde_dbg_reg_base *dbg, char *addr; size_t len; struct sde_dbg_reg_range *range_node; + struct sde_dbg_base *dbg_base = &sde_dbg_base; if (!dbg || !(dbg->base || dbg->cb)) { pr_err("dbg base is null!\n"); @@ -664,6 +711,12 @@ static void _sde_dump_reg_by_ranges(struct sde_dbg_reg_base *dbg, addr, range_node->offset.start, range_node->offset.end); + scnprintf(dbg_base->reg_dump_addr, REG_BASE_NAME_LEN, + dbg->name); + dbg_base->reg_dump_addr += REG_BASE_NAME_LEN; + scnprintf(dbg_base->reg_dump_addr, RANGE_NAME_LEN, + range_node->range_name); + dbg_base->reg_dump_addr += RANGE_NAME_LEN; _sde_dump_reg(range_node->range_name, reg_dump_flag, dbg->base, addr, len, &range_node->reg_dump); @@ -676,6 +729,10 @@ static void _sde_dump_reg_by_ranges(struct sde_dbg_reg_base *dbg, dbg->max_offset); addr = dbg->base; len = dbg->max_offset; + scnprintf(dbg_base->reg_dump_addr, REG_BASE_NAME_LEN, + dbg->name); + dbg_base->reg_dump_addr += REG_BASE_NAME_LEN; + dbg_base->reg_dump_addr += RANGE_NAME_LEN; _sde_dump_reg(dbg->name, reg_dump_flag, dbg->base, addr, len, &dbg->reg_dump); } @@ -1286,9 +1343,20 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], bool dump_secure) { int i; + u32 reg_dump_size; + struct sde_dbg_base *dbg_base = &sde_dbg_base; 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_addr && + sde_mini_dump_add_region("reg_dump", + reg_dump_size, dbg_base->reg_dump_addr) < 0) + pr_err("minidump add regdump failed\n"); + if (dump_all) sde_evtlog_dump_all(sde_dbg_base.evtlog);