Merge "disp: msm: sde: add support for ppb size programming"

这个提交包含在:
qctecmdr
2023-02-20 11:19:36 -08:00
提交者 Gerrit - the friendly Code Review server
当前提交 32f7d3149a
修改 10 个文件,包含 223 行新增6 行删除

查看文件

@@ -1184,6 +1184,24 @@ int sde_connector_state_get_mode_info(struct drm_connector_state *conn_state,
int sde_connector_get_lm_cnt_from_topology(struct drm_connector *conn,
const struct drm_display_mode *drm_mode);
/**
* sde_conn_get_max_mode_width - retrieves the maximum width from all modes
* conn: Pointer to DRM connector object
*/
static inline u32 sde_conn_get_max_mode_width(struct drm_connector *conn)
{
u32 maxw = 0;
struct drm_display_mode *mode;
if (!conn)
return maxw;
list_for_each_entry(mode, &conn->modes, head)
maxw = maxw > mode->hdisplay ? maxw : mode->hdisplay;
return maxw;
}
/**
* sde_connector_state_get_topology - get topology from given connector state
* conn_state: Pointer to the DRM connector state object

查看文件

@@ -1431,6 +1431,85 @@ static int _sde_encoder_update_roi(struct drm_encoder *drm_enc)
return 0;
}
static void _sde_encoder_update_ppb_size(struct drm_encoder *drm_enc)
{
struct sde_kms *sde_kms;
struct sde_hw_mdp *hw_mdp;
struct drm_display_mode *mode;
struct sde_encoder_virt *sde_enc;
u32 maxw, pixels_per_pp, num_lm_or_pp, latency_lines;
int i;
if (!drm_enc) {
SDE_ERROR("invalid encoder parameter\n");
return;
}
sde_enc = to_sde_encoder_virt(drm_enc);
if (!sde_enc->cur_master || !sde_enc->cur_master->connector) {
SDE_ERROR_ENC(sde_enc, "invalid master or conn\n");
return;
}
/* program only for realtime displays */
if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_VIRTUAL)
return;
sde_kms = sde_encoder_get_kms(&sde_enc->base);
if (!sde_kms) {
SDE_ERROR_ENC(sde_enc, "invalid sde_kms\n");
return;
}
/* check if hw support is available, early return if not available */
if (sde_kms->catalog->ppb_sz_program == SDE_PPB_SIZE_THRU_NONE)
return;
hw_mdp = sde_kms->hw_mdp;
if (!hw_mdp) {
SDE_ERROR_ENC(sde_enc, "invalid mdp top\n");
return;
}
mode = &drm_enc->crtc->state->adjusted_mode;
num_lm_or_pp = sde_enc->cur_channel_cnt;
latency_lines = sde_kms->catalog->ppb_buf_max_lines;
for (i = 0; i < num_lm_or_pp; i++) {
struct sde_hw_pingpong *hw_pp = sde_enc->hw_pp[i];
if (!hw_pp) {
SDE_ERROR_ENC(sde_enc, "invalid hw_pp i:%d pp_cnt:%d\n", i, num_lm_or_pp);
return;
}
if (hw_pp->ops.set_ppb_fifo_size) {
pixels_per_pp = mult_frac(mode->hdisplay, latency_lines, num_lm_or_pp);
hw_pp->ops.set_ppb_fifo_size(hw_pp, pixels_per_pp);
SDE_EVT32(DRMID(drm_enc), i, hw_pp->idx, mode->hdisplay, pixels_per_pp,
sde_kms->catalog->ppb_sz_program, SDE_EVTLOG_FUNC_CASE1);
SDE_DEBUG_ENC(sde_enc, "hw-pp i:%d pp_cnt:%d pixels_per_pp:%d\n",
i, num_lm_or_pp, pixels_per_pp);
} else if (hw_mdp->ops.set_ppb_fifo_size) {
maxw = sde_conn_get_max_mode_width(sde_enc->cur_master->connector);
if (!maxw) {
SDE_ERROR_ENC(sde_enc, "failed to get max horizantal resolution\n");
return;
}
pixels_per_pp = mult_frac(maxw, latency_lines, num_lm_or_pp);
hw_mdp->ops.set_ppb_fifo_size(hw_mdp, hw_pp->idx, pixels_per_pp);
SDE_EVT32(DRMID(drm_enc), i, hw_pp->idx, maxw, pixels_per_pp,
sde_kms->catalog->ppb_sz_program, SDE_EVTLOG_FUNC_CASE2);
SDE_DEBUG_ENC(sde_enc, "hw-pp i:%d pp_cnt:%d pixels_per_pp:%d\n",
i, num_lm_or_pp, pixels_per_pp);
} else {
SDE_ERROR_ENC(sde_enc, "invalid - ppb fifo size support is partial\n");
}
}
}
void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, u32 vsync_source)
{
struct sde_vsync_source_cfg vsync_cfg = { 0 };
@@ -2549,12 +2628,14 @@ static void _sde_encoder_virt_populate_hw_res(struct drm_encoder *drm_enc)
struct sde_rm_hw_request request_hw;
int i, j;
sde_enc->cur_channel_cnt = 0;
sde_rm_init_hw_iter(&pp_iter, drm_enc->base.id, SDE_HW_BLK_PINGPONG);
for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
sde_enc->hw_pp[i] = NULL;
if (!sde_rm_get_hw(&sde_kms->rm, &pp_iter))
break;
sde_enc->hw_pp[i] = to_sde_hw_pingpong(pp_iter.hw);
sde_enc->cur_channel_cnt++;
}
for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -3000,6 +3081,9 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info);
if (!sde_encoder_in_cont_splash(drm_enc))
_sde_encoder_update_ppb_size(drm_enc);
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));
_sde_encoder_control_fal10_veto(drm_enc, true);

查看文件

@@ -158,6 +158,7 @@ enum sde_sim_qsync_event {
* pingpong blocks can be different than num_phys_encs.
* @hw_dsc: Array of DSC block handles used for the display.
* @hw_vdc: Array of VDC block handles used for the display.
* @cur_channel_cnt Number of data channels currently used for the display
* @dirty_dsc_ids: Cached dsc indexes for dirty DSC blocks needing flush
* @intfs_swapped Whether or not the phys_enc interfaces have been swapped
* for partial update right-only cases, such as pingpong
@@ -243,6 +244,7 @@ struct sde_encoder_virt {
struct sde_hw_pingpong *hw_dsc_pp[MAX_CHANNELS_PER_ENC];
enum sde_dsc dirty_dsc_ids[MAX_CHANNELS_PER_ENC];
enum sde_vdc dirty_vdc_ids[MAX_CHANNELS_PER_ENC];
u32 cur_channel_cnt;
bool intfs_swapped;
bool qdss_status;

查看文件

@@ -147,6 +147,7 @@
#define DEFAULT_AXI_BUS_WIDTH 32
#define DEFAULT_CPU_MASK 0
#define DEFAULT_CPU_DMA_LATENCY PM_QOS_DEFAULT_VALUE
#define DEFAULT_PPB_BUF_MAX_LINES 4
/* Uidle values */
#define SDE_UIDLE_FAL10_EXIT_CNT 128
@@ -4050,6 +4051,9 @@ static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg)
}
}
if (sde_cfg->ppb_sz_program == SDE_PPB_SIZE_THRU_PINGPONG)
set_bit(SDE_PINGPONG_SET_SIZE, &pp->features);
sblk->dither.base = PROP_VALUE_ACCESS(prop_value, DITHER_OFF,
i);
if (sblk->dither.base) {
@@ -4243,6 +4247,9 @@ static int sde_top_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
else if (major_version < SDE_HW_MAJOR(SDE_HW_VER_810))
set_bit(SDE_MDP_WD_TIMER, &cfg->mdp[0].features);
if (cfg->ppb_sz_program == SDE_PPB_SIZE_THRU_TOP)
set_bit(SDE_MDP_TOP_PPB_SET_SIZE, &cfg->mdp[0].features);
rc = _add_to_irq_offset_list(cfg, SDE_INTR_HWBLK_TOP,
SDE_INTR_TOP_INTR, cfg->mdp[0].base);
if (rc)
@@ -5017,6 +5024,9 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
set_bit(SDE_FEATURE_HDR, sde_cfg->features);
sde_cfg->mdss_hw_block_size = DEFAULT_MDSS_HW_BLOCK_SIZE;
/* Set target specific value based on sytems recommendation if not same as default value */
sde_cfg->ppb_buf_max_lines = DEFAULT_PPB_BUF_MAX_LINES;
for (i = 0; i < SSPP_MAX; i++) {
sde_cfg->demura_supported[i][0] = ~0x0;
sde_cfg->demura_supported[i][1] = ~0x0;
@@ -5399,6 +5409,8 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev)
set_bit(SDE_FEATURE_EPT_FPS, sde_cfg->features);
sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH;
sde_cfg->autorefresh_disable_seq = AUTOREFRESH_DISABLE_SEQ2;
/* if pingpong block supports it this should not be set on top block */
sde_cfg->ppb_sz_program = SDE_PPB_SIZE_THRU_TOP;
sde_cfg->perf.min_prefill_lines = 40;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->qos_target_time_ns = 11160;

查看文件

@@ -151,6 +151,8 @@
#define DNSC_BLUR_MAX_RATIO_COUNT 7
#define MDP_PPB_FIFO_ENTRY_SIZE 4
/*
* UIDLE supported versions
*/
@@ -267,8 +269,8 @@ struct sde_intr_irq_offsets {
* @SDE_MDP_DHDR_MEMPOOL Dynamic HDR Metadata mempool present
* @SDE_MDP_DHDR_MEMPOOL_4K Dynamic HDR mempool is 4k aligned
* @SDE_MDP_PERIPH_TOP_REMOVED Indicates if periph top0 block is removed
* @SDE_MDP_MAX Maximum value
* @SDE_MDP_TOP_PPB_SET_SIZE Indicates if top block supports ppb size setting
* @SDE_MDP_MAX Maximum value
*/
enum {
SDE_MDP_PANIC_PER_PIPE = 0x1,
@@ -281,6 +283,7 @@ enum {
SDE_MDP_DHDR_MEMPOOL,
SDE_MDP_DHDR_MEMPOOL_4K,
SDE_MDP_PERIPH_TOP_0_REMOVED,
SDE_MDP_TOP_PPB_SET_SIZE,
SDE_MDP_MAX
};
@@ -512,6 +515,7 @@ enum {
* @SDE_PINGPONG_MERGE_3D, Separate MERGE_3D block exists
* @SDE_PINGPONG_CWB, PP block supports CWB
* @SDE_PINGPONG_CWB_DITHER, PP block supports CWB dither
* @SDE_PINGPONG_SET_SIZE, PP block supports setting latency buffer size
* @SDE_PINGPONG_MAX
*/
enum {
@@ -525,6 +529,7 @@ enum {
SDE_PINGPONG_MERGE_3D,
SDE_PINGPONG_CWB,
SDE_PINGPONG_CWB_DITHER,
SDE_PINGPONG_SET_SIZE,
SDE_PINGPONG_MAX
};
@@ -731,6 +736,18 @@ enum {
SDE_UIDLE_MAX
};
/**
* sde_ppb_size_option PPB size limit programming choice
* @SDE_PPB_SIZE_THRU_NONE ppb size programming not available
* @SDE_PPB_SIZE_THRU_TOP ppb size programming supported in top block
* @SDE_PPB_SIZE_THRU_PINGPONG ppb size programming supported in pingpong block
*/
enum sde_ppb_size_option {
SDE_PPB_SIZE_THRU_NONE,
SDE_PPB_SIZE_THRU_TOP,
SDE_PPB_SIZE_THRU_PINGPONG,
};
/**
* MDSS features - For enabling target specific functionality in @sde_mdss_cfg "features" bitmap
* @SDE_FEATURE_CDP Client driven prefetch supported
@@ -1941,6 +1958,8 @@ struct sde_perf_cfg {
* @dnsc_blur_filter_count supported filter count for downscale blur
* @ipcc_protocol_id ipcc protocol id for the hw
* @ipcc_client_phys_id dpu ipcc client id for the hw, physical client id if supported
* @ppb_sz_program enum value for pingpong buffer size programming choice by hw
* @ppb_buf_max_lines maximum lines needed for pingpong latency buffer size
*/
struct sde_mdss_cfg {
/* Block Revisions */
@@ -2062,6 +2081,9 @@ struct sde_mdss_cfg {
u32 ipcc_protocol_id;
u32 ipcc_client_phys_id;
enum sde_ppb_size_option ppb_sz_program;
u32 ppb_buf_max_lines;
};
struct sde_mdss_hw_cfg_handler {

查看文件

@@ -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-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
@@ -42,6 +42,9 @@
#define MERGE_3D_MODE 0x004
#define MERGE_3D_MUX 0x000
#define PPB_FIFO_SIZE_CFG 0x01C
#define PPB_FIFO_SIZE_MASK 0x0FFF
static struct sde_merge_3d_cfg *_merge_3d_offset(enum sde_merge_3d idx,
struct sde_mdss_cfg *m,
void __iomem *addr,
@@ -439,6 +442,22 @@ line_count_exit:
return line;
}
static void sde_hw_pp_set_ppb_fifo_size(struct sde_hw_pingpong *pp, u32 pixels)
{
struct sde_hw_blk_reg_map *c;
u32 val;
if (!pp)
return;
c = &pp->hw;
/* covert to fifo units, 4 pixels can be stored per fifo */
val = (pixels / MDP_PPB_FIFO_ENTRY_SIZE) & 0x0FFF;
SDE_REG_WRITE(c, PPB_FIFO_SIZE_CFG, val);
}
static void sde_hw_pp_setup_3d_merge_mode(struct sde_hw_pingpong *pp,
enum sde_3d_blend_mode cfg)
{
@@ -473,7 +492,11 @@ static void _setup_pingpong_ops(struct sde_hw_pingpong_ops *ops,
ops->get_autorefresh = sde_hw_pp_get_autorefresh_config;
ops->poll_timeout_wr_ptr = sde_hw_pp_poll_timeout_wr_ptr;
ops->get_line_count = sde_hw_pp_get_line_count;
} else if (hw_cap->features & BIT(SDE_PINGPONG_SET_SIZE)) {
/* PPB_FIFO_CFG offset conflicts with legacy PP Tear registers */
ops->set_ppb_fifo_size = sde_hw_pp_set_ppb_fifo_size;
}
if (hw_cap->features & BIT(SDE_PINGPONG_DSC)) {
ops->setup_dsc = sde_hw_pp_setup_dsc;
ops->enable_dsc = sde_hw_pp_dsc_enable;

查看文件

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
@@ -131,6 +131,11 @@ struct sde_hw_pingpong_ops {
* get PP features supported by this instance
*/
unsigned long (*get_hw_caps)(struct sde_hw_pingpong *pp);
/**
* set_ppb_fifo_size - set ppb latency buffer size to a fixed value
*/
void (*set_ppb_fifo_size)(struct sde_hw_pingpong *pp, u32 pixels);
};
struct sde_hw_merge_3d_ops {

查看文件

@@ -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-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
@@ -118,6 +118,8 @@
#define HW_FENCE_IPCC_FENCE_PROTOCOL_ID 4
#define HW_FENCE_DPU_FENCE_PROTOCOL_ID 3
static int ppb_offset_map[PINGPONG_MAX] = {1, 0, 3, 2, 5, 4, 7, 7, 6, 6, -1, -1};
static void sde_hw_setup_split_pipe(struct sde_hw_mdp *mdp,
struct split_pipe_cfg *cfg)
{
@@ -767,6 +769,38 @@ static void sde_hw_setup_hw_fences_config(struct sde_hw_mdp *mdp, u32 protocol_i
SDE_REG_WRITE(&c, offset, val);
}
void sde_hw_top_set_ppb_fifo_size(struct sde_hw_mdp *mdp, u32 pp, u32 sz)
{
struct sde_hw_blk_reg_map c;
u32 offset, val, pp_index;
if (!mdp) {
SDE_ERROR("invalid mdp instance\n");
return;
}
if (pp >= PINGPONG_MAX || ppb_offset_map[pp - PINGPONG_0] < 0) {
SDE_ERROR("invalid pingpong index:%d max:%d\n", pp, PINGPONG_MAX);
return;
}
pp_index = pp - PINGPONG_0;
c = mdp->hw;
offset = PPB_FIFO_SIZE + ((ppb_offset_map[pp_index] / 2) * 0x4);
spin_lock(&mdp->slock);
/* read, modify & update *respective 16 bit fields */
val = SDE_REG_READ(&c, offset);
/* divide by 4 as each fifo entry can store 4 pixels */
sz = (sz / MDP_PPB_FIFO_ENTRY_SIZE) & 0xFFFF;
sz = ppb_offset_map[pp_index] % 2 ? (sz << 16) : sz;
val = (ppb_offset_map[pp_index] % 2) ? (val & 0xFFFF) : (val & 0xFFFF0000);
SDE_REG_WRITE(&c, offset, val | sz);
spin_unlock(&mdp->slock);
}
static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, unsigned long cap, u32 hw_fence_rev)
{
ops->setup_split_pipe = sde_hw_setup_split_pipe;
@@ -793,6 +827,9 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, unsigned long cap, u32 hw
ops->hw_fence_input_timestamp_ctrl = sde_hw_hw_fence_timestamp_ctrl;
ops->hw_fence_input_status = sde_hw_input_hw_fence_status;
}
if (cap & BIT(SDE_MDP_TOP_PPB_SET_SIZE))
ops->set_ppb_fifo_size = sde_hw_top_set_ppb_fifo_size;
}
static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
@@ -839,6 +876,8 @@ struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
return ERR_PTR(-EINVAL);
}
spin_lock_init(&mdp->slock);
/*
* Assign ops
*/

查看文件

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
@@ -230,6 +230,14 @@ struct sde_hw_mdp_ops {
* @enable: indicates if timestamps should be cleared
*/
void (*hw_fence_input_timestamp_ctrl)(struct sde_hw_mdp *mdp, bool enable, bool clear);
/**
* set_ppb_fifo_size - set ppb latency buffer size to a fixed value
* @mdp: mdp top context driver
* @pp: indicates pingpong block id
* @sz: indicates size of the ppb in terms of pixels
*/
void (*set_ppb_fifo_size)(struct sde_hw_mdp *mdp, u32 pp, u32 sz);
};
struct sde_hw_mdp {
@@ -239,6 +247,8 @@ struct sde_hw_mdp {
enum sde_mdp idx;
const struct sde_mdp_cfg *caps;
spinlock_t slock;
/* ops */
struct sde_hw_mdp_ops ops;
};

查看文件

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _SDE_HWIO_H
@@ -33,6 +34,7 @@
#define PPB0_CONFIG 0x334
#define PPB1_CNTL 0x338
#define PPB1_CONFIG 0x33C
#define PPB_FIFO_SIZE 0x350
#define PPB2_CNTL 0x370
#define PPB3_CNTL 0x374
#define HW_EVENTS_CTL 0x37C