Merge "disp: msm: add support for INTF WD jitter"
Šī revīzija ir iekļauta:

revīziju iesūtīja
Gerrit - the friendly Code Review server

revīzija
9931042038
@@ -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;
|
||||
|
@@ -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));
|
||||
|
@@ -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];
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -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 {
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
};
|
||||
|
||||
|
@@ -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 = 0;
|
||||
@@ -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 |= BIT(8); /* enable heartbeat timer */
|
||||
@@ -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,
|
||||
|
@@ -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,
|
||||
|
Atsaukties uz šo jaunā problēmā
Block a user