From 718cd254966380c52761fe9cf137cbae1af0687c Mon Sep 17 00:00:00 2001 From: Satya Rama Aditya Pinapala Date: Mon, 30 Aug 2021 14:08:42 -0700 Subject: [PATCH] disp: msm: add support for INTF WD jitter Change adds support for the INTF watchdog timer jitter feature for MDSS 9.x. Change-Id: I2cf821b5b5724f9adee95c282e0ec09719489a85 Signed-off-by: Satya Rama Aditya Pinapala Signed-off-by: Narendra Muppalla --- msm/dsi/dsi_defs.h | 3 ++ msm/dsi/dsi_drm.c | 1 + msm/dsi/dsi_panel.c | 64 +++++++++++++++++++++++++++++++--- msm/msm_drv.h | 32 +++++++++++++++++ msm/sde/sde_encoder_phys_cmd.c | 29 +++++++++++++++ msm/sde/sde_hw_catalog.c | 1 + msm/sde/sde_hw_catalog.h | 2 ++ msm/sde/sde_hw_intf.c | 49 +++++++++++++++++++++++--- msm/sde/sde_hw_intf.h | 15 ++++++++ 9 files changed, 188 insertions(+), 8 deletions(-) diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index a61bd397ef..3428c78cd7 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -620,6 +621,7 @@ struct dsi_host_config { * @topology: Topology selected for the panel * @dsc: DSC compression info * @vdc: VDC compression info + * @wd_jitter: WD Jitter config. * @dsc_enabled: DSC compression enabled * @vdc_enabled: VDC compression enabled * @pclk_scale: pclk scale factor, target bpp to source bpp @@ -647,6 +649,7 @@ struct dsi_display_mode_priv_info { struct msm_display_topology topology; struct msm_display_dsc_info dsc; struct msm_display_vdc_info vdc; + struct msm_display_wd_jitter_config wd_jitter; bool dsc_enabled; bool vdc_enabled; struct msm_ratio pclk_scale; diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 5dd52b978d..0216d31a0d 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -638,6 +638,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, dsi_mode->priv_info->mdp_transfer_time_us; mode_info->disable_rsc_solver = dsi_mode->priv_info->disable_rsc_solver; mode_info->qsync_min_fps = dsi_mode->timing.qsync_min_fps; + mode_info->wd_jitter = dsi_mode->priv_info->wd_jitter; memcpy(&mode_info->topology, &dsi_mode->priv_info->topology, sizeof(struct msm_display_topology)); diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 07ba0595ef..7afd324394 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -2203,16 +2203,71 @@ static int dsi_panel_parse_misc_features(struct dsi_panel *panel) return 0; } +static int dsi_panel_parse_wd_jitter_config(struct dsi_display_mode_priv_info *priv_info, + struct dsi_parser_utils *utils, u32 *jitter) +{ + int rc = 0; + struct msm_display_wd_jitter_config *wd_jitter = &priv_info->wd_jitter; + u32 ltj[DEFAULT_PANEL_JITTER_ARRAY_SIZE] = {0, 1}; + u32 ltj_time = 0; + const u32 min_ltj = 10; + + if (!(utils->read_bool(utils->data, "qcom,dsi-wd-jitter-enable"))) { + priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR; + priv_info->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR; + return 0; + } + + rc = utils->read_u32_array(utils->data, "qcom,dsi-wd-ltj-max-jitter", ltj, + DEFAULT_PANEL_JITTER_ARRAY_SIZE); + rc |= utils->read_u32(utils->data, "qcom,dsi-wd-ltj-time-sec", <j_time); + if (rc || !ltj[1] || !ltj_time || (ltj[0] / ltj[1] < min_ltj)) { + DSI_DEBUG("No valid long term jitter defined\n"); + priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR; + priv_info->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR; + rc = -EINVAL; + } else { + wd_jitter->ltj_max_numer = ltj[0]; + wd_jitter->ltj_max_denom = ltj[1]; + wd_jitter->ltj_time_sec = ltj_time; + wd_jitter->jitter_type = MSM_DISPLAY_WD_LTJ_JITTER; + } + + if (jitter[0] && jitter[1]) { + if (jitter[0] / jitter[1] > MAX_PANEL_JITTER) { + wd_jitter->inst_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR; + wd_jitter->inst_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR; + } else { + wd_jitter->inst_jitter_numer = jitter[0]; + wd_jitter->inst_jitter_denom = jitter[1]; + } + wd_jitter->jitter_type |= MSM_DISPLAY_WD_INSTANTANEOUS_JITTER; + } else if (rc) { + wd_jitter->inst_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR; + wd_jitter->inst_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR; + wd_jitter->jitter_type |= MSM_DISPLAY_WD_INSTANTANEOUS_JITTER; + } + + priv_info->panel_jitter_numer = rc ? + wd_jitter->inst_jitter_numer : wd_jitter->ltj_max_numer; + priv_info->panel_jitter_denom = rc ? + wd_jitter->inst_jitter_denom : wd_jitter->ltj_max_denom; + + return 0; +} + static int dsi_panel_parse_jitter_config( struct dsi_display_mode *mode, struct dsi_parser_utils *utils) { int rc; struct dsi_display_mode_priv_info *priv_info; + struct dsi_panel *panel; u32 jitter[DEFAULT_PANEL_JITTER_ARRAY_SIZE] = {0, 0}; u64 jitter_val = 0; priv_info = mode->priv_info; + panel = container_of(utils, struct dsi_panel, utils); rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-panel-jitter", jitter, DEFAULT_PANEL_JITTER_ARRAY_SIZE); @@ -2223,10 +2278,11 @@ static int dsi_panel_parse_jitter_config( jitter_val = div_u64(jitter_val, jitter[1]); } - if (rc || !jitter_val || (jitter_val > MAX_PANEL_JITTER)) { + if (panel->te_using_watchdog_timer) { + dsi_panel_parse_wd_jitter_config(priv_info, utils, jitter); + } else if (rc || !jitter_val || (jitter_val > MAX_PANEL_JITTER)) { priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR; - priv_info->panel_jitter_denom = - DEFAULT_PANEL_JITTER_DENOMINATOR; + priv_info->panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR; } else { priv_info->panel_jitter_numer = jitter[0]; priv_info->panel_jitter_denom = jitter[1]; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index b188ab5113..1ca8b7a451 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -257,6 +257,18 @@ enum msm_display_compression_type { MSM_DISPLAY_COMPRESSION_VDC }; +/** + * enum msm_display_wd_jitter_type - Type of WD jitter used + * @MSM_DISPLAY_WD_JITTER_NONE: No WD timer jitter enabled + * @MSM_DISPLAY_WD_INSTANTANEOUS_JITTER: Instantaneous WD jitter enabled + * @MSM_DISPLAY_WD_LTJ_JITTER: LTJ WD jitter enabled + */ +enum msm_display_wd_jitter_type { + MSM_DISPLAY_WD_JITTER_NONE = BIT(0), + MSM_DISPLAY_WD_INSTANTANEOUS_JITTER = BIT(1), + MSM_DISPLAY_WD_LTJ_JITTER = BIT(2), +}; + #define MSM_DISPLAY_COMPRESSION_RATIO_NONE 1 #define MSM_DISPLAY_COMPRESSION_RATIO_MAX 5 @@ -744,6 +756,24 @@ struct msm_dyn_clk_list { u32 *pixel_clks_khz; }; +/** + * struct msm_display_wd_jitter_config - defines jitter properties for WD timer + * @jitter_type: Type of WD jitter enabled. + * @inst_jitter_numer: Instantaneous jitter numerator. + * @inst_jitter_denom: Instantaneous jitter denominator. + * @ltj_max_numer: LTJ max numerator. + * @ltj_max_denom: LTJ max denominator. + * @ltj_time_sec: LTJ time in seconds. + */ +struct msm_display_wd_jitter_config { + enum msm_display_wd_jitter_type jitter_type; + u32 inst_jitter_numer; + u32 inst_jitter_denom; + u32 ltj_max_numer; + u32 ltj_max_denom; + u32 ltj_time_sec; +}; + /** * struct msm_mode_info - defines all msm custom mode info * @frame_rate: frame_rate of the mode @@ -764,6 +794,7 @@ struct msm_dyn_clk_list { * @disable_rsc_solver: Dynamically disable RSC solver for the timing mode due to lower bitclk rate. * @dyn_clk_list: List of dynamic clock rates for RFI. * @qsync_min_fps: qsync min fps rate + * @wd_jitter: Info for WD jitter. */ struct msm_mode_info { uint32_t frame_rate; @@ -783,6 +814,7 @@ struct msm_mode_info { bool disable_rsc_solver; struct msm_dyn_clk_list dyn_clk_list; u32 qsync_min_fps; + struct msm_display_wd_jitter_config wd_jitter; }; /** diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index c58f3b4bc0..34f75020b5 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1894,11 +1894,38 @@ static void sde_encoder_phys_cmd_trigger_start( cmd_enc->wr_ptr_wait_success = false; } +static void _sde_encoder_phys_cmd_calculate_wd_params(struct sde_encoder_phys *phys_enc, + struct intf_wd_jitter_params *wd_jitter) +{ + u32 nominal_te_value; + struct sde_encoder_virt *sde_enc; + struct msm_mode_info *mode_info; + const u32 multiplier = 1 << 10; + + sde_enc = to_sde_encoder_virt(phys_enc->parent); + mode_info = &sde_enc->mode_info; + + if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_INSTANTANEOUS_JITTER) + wd_jitter->jitter = mult_frac(multiplier, mode_info->wd_jitter.inst_jitter_numer, + (mode_info->wd_jitter.inst_jitter_denom * 100)); + + if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_LTJ_JITTER) { + nominal_te_value = CALCULATE_WD_LOAD_VALUE(mode_info->frame_rate) * MDP_TICK_COUNT; + wd_jitter->ltj_max = mult_frac(nominal_te_value, mode_info->wd_jitter.ltj_max_numer, + (mode_info->wd_jitter.ltj_max_denom) * 100); + wd_jitter->ltj_slope = mult_frac((1 << 16), wd_jitter->ltj_max, + (mode_info->wd_jitter.ltj_time_sec * mode_info->frame_rate)); + } + + phys_enc->hw_intf->ops.configure_wd_jitter(phys_enc->hw_intf, wd_jitter); +} + static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phys_enc, u32 vsync_source, struct msm_display_info *disp_info) { struct sde_encoder_virt *sde_enc; struct sde_connector *sde_conn; + struct intf_wd_jitter_params wd_jitter = {0, 0}; if (!phys_enc || !phys_enc->hw_intf) return; @@ -1912,6 +1939,8 @@ static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phy if ((disp_info->is_te_using_watchdog_timer || sde_conn->panel_dead) && phys_enc->hw_intf->ops.setup_vsync_source) { vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0; + if (phys_enc->hw_intf->ops.configure_wd_jitter) + _sde_encoder_phys_cmd_calculate_wd_params(phys_enc, &wd_jitter); phys_enc->hw_intf->ops.setup_vsync_source(phys_enc->hw_intf, sde_enc->mode_info.frame_rate); } else { diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index ebd3e82f47..ddd6b1f14d 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -2366,6 +2366,7 @@ static int sde_intf_parse_dt(struct device_node *np, if (SDE_HW_MAJOR(sde_cfg->hw_rev) >= SDE_HW_MAJOR(SDE_HW_VER_900)) { set_bit(SDE_INTF_MDP_VSYNC_TS, &intf->features); + set_bit(SDE_INTF_WD_JITTER, &intf->features); } } diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index c86280a403..63432cbb01 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -567,6 +567,7 @@ enum { * @SDE_INTF_PANEL_VSYNC_TS INTF block has panel vsync timestamp logged * @SDE_INTF_MDP_VSYNC_TS INTF block has mdp vsync timestamp logged * @SDE_INTF_AVR_STATUS INTF block has AVR_STATUS field in AVR_CONTROL register + * @SDE_INTF_WD_JITTER INTF block has WD timer jitter support * @SDE_INTF_MAX */ enum { @@ -579,6 +580,7 @@ enum { SDE_INTF_PANEL_VSYNC_TS, SDE_INTF_MDP_VSYNC_TS, SDE_INTF_AVR_STATUS, + SDE_INTF_WD_JITTER, SDE_INTF_MAX }; diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 2c2f7481aa..7675b89940 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -69,6 +69,9 @@ #define INTF_VSYNC_TIMESTAMP1 0x218 #define INTF_MDP_VSYNC_TIMESTAMP0 0x21C #define INTF_MDP_VSYNC_TIMESTAMP1 0x220 +#define INTF_WD_TIMER_0_JITTER_CTL 0x224 +#define INTF_WD_TIMER_0_LTJ_SLOPE 0x228 +#define INTF_WD_TIMER_0_LTJ_MAX 0x22C #define INTF_WD_TIMER_0_CTL 0x230 #define INTF_WD_TIMER_0_CTL2 0x234 #define INTF_WD_TIMER_0_LOAD_VALUE 0x238 @@ -455,8 +458,39 @@ static void sde_hw_intf_setup_prg_fetch( SDE_REG_WRITE(c, INTF_CONFIG, fetch_enable); } -static void sde_hw_intf_setup_vsync_source(struct sde_hw_intf *intf, - u32 frame_rate) +static void sde_hw_intf_configure_wd_timer_jitter(struct sde_hw_intf *intf, + struct intf_wd_jitter_params *wd_jitter) +{ + struct sde_hw_blk_reg_map *c; + u32 reg, jitter_ctl = 0; + + c = &intf->hw; + + /* + * Load Jitter values with jitter feature disabled. + */ + SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, 0x1); + + if (wd_jitter->jitter) + jitter_ctl |= ((wd_jitter->jitter & 0x3FF) << 16); + + if (wd_jitter->ltj_max) { + SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_MAX, wd_jitter->ltj_max); + SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_SLOPE, wd_jitter->ltj_slope); + } + + reg = SDE_REG_READ(c, INTF_WD_TIMER_0_JITTER_CTL); + reg |= jitter_ctl; + SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, reg); + + if (wd_jitter->jitter) + reg |= BIT(31); + if (wd_jitter->ltj_max) + reg |= BIT(30); + SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, reg); +} + +static void sde_hw_intf_setup_vsync_source(struct sde_hw_intf *intf, u32 frame_rate) { struct sde_hw_blk_reg_map *c; u32 reg; @@ -466,7 +500,11 @@ static void sde_hw_intf_setup_vsync_source(struct sde_hw_intf *intf, c = &intf->hw; - SDE_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, CALCULATE_WD_LOAD_VALUE(frame_rate)); + reg = CALCULATE_WD_LOAD_VALUE(frame_rate); + if (intf->cap->features & BIT(SDE_INTF_WD_JITTER)) + reg *= MDP_TICK_COUNT; + + SDE_REG_WRITE(c, INTF_WD_TIMER_0_LOAD_VALUE, reg); SDE_REG_WRITE(c, INTF_WD_TIMER_0_CTL, BIT(0)); /* clear timer */ reg = SDE_REG_READ(c, INTF_WD_TIMER_0_CTL2); @@ -928,6 +966,9 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops, if (cap & (BIT(SDE_INTF_PANEL_VSYNC_TS) | BIT(SDE_INTF_MDP_VSYNC_TS))) ops->get_vsync_timestamp = sde_hw_intf_get_vsync_timestamp; + + if (cap & BIT(SDE_INTF_WD_JITTER)) + ops->configure_wd_jitter = sde_hw_intf_configure_wd_timer_jitter; } struct sde_hw_blk_reg_map *sde_hw_intf_init(enum sde_intf idx, diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index 2da19bb46b..3c5737051a 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -65,6 +66,17 @@ struct intf_avr_params { u32 avr_mode; /* one of enum @sde_rm_qsync_modes */ u32 avr_step_lines; /* 0 or 1 means disabled */ }; +/** + * struct intf_wd_jitter_params : Interface to the INTF WD Jitter params. + * jitter : max instantaneous jitter. + * ltj_max : max long term jitter value. + * ltj_slope : slope of long term jitter. + */ +struct intf_wd_jitter_params { + u32 jitter; + u32 ltj_max; + u32 ltj_slope; +}; /** * struct sde_hw_intf_ops : Interface to the interface Hw driver functions @@ -80,6 +92,7 @@ struct intf_avr_params { * @ get_underrun_line_count: reads current underrun pixel clock count and * converts it into line count * @setup_vsync_source: Configure vsync source selection for intf + * @configure_wd_jitter: Configure WD jitter. * @bind_pingpong_blk: enable/disable the connection with pingpong which will * feed pixels to this interface */ @@ -115,6 +128,8 @@ struct sde_hw_intf_ops { u32 (*get_underrun_line_count)(struct sde_hw_intf *intf); void (*setup_vsync_source)(struct sde_hw_intf *intf, u32 frame_rate); + void (*configure_wd_jitter)(struct sde_hw_intf *intf, + struct intf_wd_jitter_params *wd_jitter); void (*bind_pingpong_blk)(struct sde_hw_intf *intf, bool enable,