msm: mdss: modularize DSC code to support 4K DSC split-panel
Display Steam Compression (DSC) use-cases requires parameter calculations that affect MDP and DSI separately. Current implementation is not modular and calculates all the parameters in one big subroutine. Due to this, an issue has occurred where parameters that affect DSI relies on picture width where as DSI parameters should be calculated only based on uncompressed width to a particular DSI controller. Also current MDP driver tries to service DSC setup for all different topologies in a single subroutine and has become very error prone. Modularize MDP DSC setup so that it is easy to maintain and also add support for partial update for 4K DSC split-panel. Change-Id: I7057e6a5a22a72a9a216e5bc9f7f946675bfbbb8 Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
This commit is contained in:
parent
84dd9d0e06
commit
21341d4cc5
9 changed files with 1021 additions and 649 deletions
|
@ -376,9 +376,6 @@ struct dsi_err_container {
|
|||
#define MDSS_DSI_COMMAND_COMPRESSION_MODE_CTRL2 0x02ac
|
||||
#define MDSS_DSI_COMMAND_COMPRESSION_MODE_CTRL3 0x02b0
|
||||
|
||||
|
||||
#define DSC_PPS_LEN 128
|
||||
|
||||
struct mdss_dsi_ctrl_pdata {
|
||||
int ndx; /* panel_num */
|
||||
int (*on) (struct mdss_panel_data *pdata);
|
||||
|
|
|
@ -29,26 +29,10 @@
|
|||
#define MIN_REFRESH_RATE 48
|
||||
#define DEFAULT_MDP_TRANSFER_TIME 14000
|
||||
|
||||
#define CEIL(x, y) (((x) + ((y)-1)) / (y))
|
||||
|
||||
#define VSYNC_DELAY msecs_to_jiffies(17)
|
||||
|
||||
DEFINE_LED_TRIGGER(bl_led_trigger);
|
||||
|
||||
/*
|
||||
* rc_buf_thresh = {896, 1792, 2688, 3548, 4480, 5376, 6272, 6720,
|
||||
* 7168, 7616, 7744, 7872, 8000, 8064, 8192};
|
||||
* (x >> 6) & 0x0ff)
|
||||
*/
|
||||
static u32 dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
|
||||
0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e};
|
||||
static char dsc_rc_range_min_qp[] = {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5,
|
||||
5, 5, 7, 13};
|
||||
static char dsc_rc_range_max_qp[] = {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11,
|
||||
12, 13, 13, 15};
|
||||
static char dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8,
|
||||
-8, -10, -10, -12, -12, -12, -12};
|
||||
|
||||
void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl)
|
||||
{
|
||||
if (ctrl->pwm_pmi)
|
||||
|
@ -1060,121 +1044,9 @@ static int mdss_dsi_parse_fbc_params(struct device_node *np,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_dsc_to_buf(struct dsc_desc *dsc, char *buf,
|
||||
int pps_id, int major, int minor)
|
||||
{
|
||||
char *bp;
|
||||
char data;
|
||||
int i, bpp;
|
||||
|
||||
bp = buf;
|
||||
*bp++ = ((major << 4) | minor); /* pps0 */
|
||||
*bp++ = pps_id; /* pps1 */
|
||||
bp++; /* pps2, reserved */
|
||||
|
||||
data = dsc->line_buf_depth & 0x0f;
|
||||
data |= (dsc->bpc << 4);
|
||||
*bp++ = data; /* pps3 */
|
||||
|
||||
bpp = dsc->bpp;
|
||||
bpp <<= 4; /* 4 fraction bits */
|
||||
data = (bpp >> 8);
|
||||
data &= 0x03; /* upper two bits */
|
||||
data |= (dsc->block_pred_enable << 5);
|
||||
data |= (dsc->convert_rgb << 4);
|
||||
data |= (dsc->enable_422 << 3);
|
||||
data |= (dsc->vbr_enable << 2);
|
||||
*bp++ = data; /* pps4 */
|
||||
*bp++ = bpp; /* pps5 */
|
||||
|
||||
*bp++ = (dsc->pic_height >> 8); /* pps6 */
|
||||
*bp++ = (dsc->pic_height & 0x0ff); /* pps7 */
|
||||
*bp++ = (dsc->pic_width >> 8); /* pps8 */
|
||||
*bp++ = (dsc->pic_width & 0x0ff); /* pps9 */
|
||||
|
||||
*bp++ = (dsc->slice_height >> 8); /* pps10 */
|
||||
*bp++ = (dsc->slice_height & 0x0ff); /* pps11 */
|
||||
*bp++ = (dsc->slice_width >> 8); /* pps12 */
|
||||
*bp++ = (dsc->slice_width & 0x0ff); /* pps13 */
|
||||
|
||||
*bp++ = (dsc->chunk_size >> 8); /* pps14 */
|
||||
*bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */
|
||||
|
||||
data = dsc->initial_xmit_delay >> 8;
|
||||
data &= 0x03;
|
||||
*bp++ = data; /* pps16, bit 0, 1 */
|
||||
*bp++ = dsc->initial_xmit_delay; /* pps17 */
|
||||
|
||||
*bp++ = (dsc->initial_dec_delay >> 8); /* pps18 */
|
||||
*bp++ = dsc->initial_dec_delay; /* pps19 */
|
||||
|
||||
bp++; /* pps20, reserved */
|
||||
|
||||
*bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */
|
||||
|
||||
data = (dsc->scale_increment_interval >> 8);
|
||||
data &= 0x0f;
|
||||
*bp++ = data; /* pps22 */
|
||||
*bp++ = dsc->scale_increment_interval; /* pps23 */
|
||||
|
||||
data = (dsc->scale_decrement_interval >> 8);
|
||||
data &= 0x0f;
|
||||
*bp++ = data; /* pps24 */
|
||||
*bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */
|
||||
|
||||
bp++; /* pps26, reserved */
|
||||
|
||||
*bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */
|
||||
|
||||
*bp++ = (dsc->nfl_bpg_offset >> 8); /* pps28 */
|
||||
*bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */
|
||||
*bp++ = (dsc->slice_bpg_offset >> 8); /* pps30 */
|
||||
*bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */
|
||||
|
||||
*bp++ = (dsc->initial_offset >> 8); /* pps32 */
|
||||
*bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */
|
||||
|
||||
*bp++ = (dsc->final_offset >> 8); /* pps34 */
|
||||
*bp++ = (dsc->final_offset & 0x0ff); /* pps35 */
|
||||
|
||||
*bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */
|
||||
*bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */
|
||||
|
||||
*bp++ = (dsc->rc_model_size >> 8); /* pps38 */
|
||||
*bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */
|
||||
|
||||
*bp++ = (dsc->edge_factor & 0x0f); /* pps40 */
|
||||
|
||||
*bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */
|
||||
*bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */
|
||||
|
||||
data = (dsc->tgt_offset_hi << 4);
|
||||
data |= (dsc->tgt_offset_lo & 0x0f);
|
||||
*bp++ = data; /* pps43 */
|
||||
|
||||
for (i = 0; i < 14; i++)
|
||||
*bp++ = dsc->buf_thresh[i]; /* pps44 - pps57 */
|
||||
|
||||
for (i = 0; i < 15; i++) { /* pps58 - pps87 */
|
||||
data = (dsc->range_min_qp[i] & 0x1f); /* 5 bits */
|
||||
data <<= 3;
|
||||
data |= ((dsc->range_max_qp[i] >> 2) & 0x07); /* 3 bits */
|
||||
*bp++ = data;
|
||||
data = (dsc->range_max_qp[i] & 0x03); /* 2 bits */
|
||||
data <<= 6;
|
||||
data |= (dsc->range_bpg_offset[i] & 0x3f); /* 6 bits */
|
||||
*bp++ = data;
|
||||
}
|
||||
|
||||
/* pps88 to pps127 are reserved */
|
||||
|
||||
return DSC_PPS_LEN; /* 128 */
|
||||
}
|
||||
|
||||
void mdss_dsi_panel_dsc_pps_send(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||
struct mdss_panel_info *pinfo)
|
||||
{
|
||||
struct dsc_desc *dsc;
|
||||
struct dsi_panel_cmds pcmds;
|
||||
struct dsi_cmd_desc cmd;
|
||||
|
||||
|
@ -1184,8 +1056,8 @@ void mdss_dsi_panel_dsc_pps_send(struct mdss_dsi_ctrl_pdata *ctrl,
|
|||
memset(&pcmds, 0, sizeof(pcmds));
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
dsc = &pinfo->dsc;
|
||||
cmd.dchdr.dlen = mdss_dsc_to_buf(dsc, ctrl->pps_buf, 0 , 1, 0);
|
||||
cmd.dchdr.dlen = mdss_panel_dsc_prepare_pps_buf(&pinfo->dsc,
|
||||
ctrl->pps_buf, 0 , 1, 0);
|
||||
cmd.dchdr.dtype = DTYPE_PPS;
|
||||
cmd.dchdr.last = 1;
|
||||
cmd.dchdr.wait = 10;
|
||||
|
@ -1200,195 +1072,10 @@ void mdss_dsi_panel_dsc_pps_send(struct mdss_dsi_ctrl_pdata *ctrl,
|
|||
mdss_dsi_panel_cmds_send(ctrl, &pcmds, CMD_REQ_COMMIT);
|
||||
}
|
||||
|
||||
int mdss_dsc_initial_line_calc(int bpc, int xmit_delay,
|
||||
int slice_width, int slice_per_line)
|
||||
{
|
||||
int ssm_delay;
|
||||
int total_pixels;
|
||||
|
||||
ssm_delay = ((bpc < 10) ? 83 : 91);
|
||||
total_pixels = ssm_delay * 3 + xmit_delay + 47;
|
||||
total_pixels += ((slice_per_line > 1) ? (ssm_delay * 3) : 0);
|
||||
|
||||
return CEIL(total_pixels, slice_width);
|
||||
}
|
||||
|
||||
void mdss_dsc_parameters_calc(struct dsc_desc *dsc, int width, int height)
|
||||
{
|
||||
int bpp, bpc;
|
||||
int mux_words_size;
|
||||
int groups_per_line, groups_total;
|
||||
int min_rate_buffer_size;
|
||||
int hrd_delay;
|
||||
int pre_num_extra_mux_bits, num_extra_mux_bits;
|
||||
int slice_bits;
|
||||
int target_bpp_x16;
|
||||
int data;
|
||||
int final_value, final_scale;
|
||||
int slice_per_line, bytes_in_slice, total_bytes;
|
||||
|
||||
if (!dsc || !width || !height)
|
||||
return;
|
||||
|
||||
dsc->pic_width = width;
|
||||
dsc->pic_height = height;
|
||||
|
||||
if ((dsc->pic_width % dsc->slice_width) ||
|
||||
(dsc->pic_height % dsc->slice_height)) {
|
||||
pr_err("Error: pic_dim=%dx%d has to be multiple of slice_dim=%dx%d\n",
|
||||
dsc->pic_width, dsc->pic_height,
|
||||
dsc->slice_width, dsc->slice_height);
|
||||
return;
|
||||
}
|
||||
|
||||
dsc->rc_model_size = 8192; /* rate_buffer_size */
|
||||
dsc->first_line_bpg_offset = 12;
|
||||
dsc->min_qp_flatness = 3;
|
||||
dsc->max_qp_flatness = 12;
|
||||
dsc->line_buf_depth = 9;
|
||||
|
||||
dsc->edge_factor = 6;
|
||||
dsc->quant_incr_limit0 = 11;
|
||||
dsc->quant_incr_limit1 = 11;
|
||||
dsc->tgt_offset_hi = 3;
|
||||
dsc->tgt_offset_lo = 3;
|
||||
|
||||
dsc->buf_thresh = dsc_rc_buf_thresh;
|
||||
dsc->range_min_qp = dsc_rc_range_min_qp;
|
||||
dsc->range_max_qp = dsc_rc_range_max_qp;
|
||||
dsc->range_bpg_offset = dsc_rc_range_bpg_offset;
|
||||
|
||||
bpp = dsc->bpp;
|
||||
bpc = dsc->bpc;
|
||||
|
||||
if (bpp == 8)
|
||||
dsc->initial_offset = 6144;
|
||||
else
|
||||
dsc->initial_offset = 2048; /* bpp = 12 */
|
||||
|
||||
if (bpc == 8)
|
||||
mux_words_size = 48;
|
||||
else
|
||||
mux_words_size = 64; /* bpc == 12 */
|
||||
|
||||
slice_per_line = CEIL(dsc->pic_width, dsc->slice_width);
|
||||
|
||||
dsc->pkt_per_line = slice_per_line / dsc->slice_per_pkt;
|
||||
if (slice_per_line % dsc->slice_per_pkt)
|
||||
dsc->pkt_per_line = 1; /* default*/
|
||||
|
||||
bytes_in_slice = CEIL(dsc->pic_width, slice_per_line);
|
||||
|
||||
bytes_in_slice *= dsc->bpp; /* bites per compressed pixel */
|
||||
bytes_in_slice = CEIL(bytes_in_slice, 8);
|
||||
|
||||
dsc->bytes_in_slice = bytes_in_slice;
|
||||
|
||||
pr_debug("%s: slice_per_line=%d pkt_per_line=%d bytes_in_slice=%d\n",
|
||||
__func__, slice_per_line, dsc->pkt_per_line, bytes_in_slice);
|
||||
|
||||
total_bytes = bytes_in_slice * slice_per_line;
|
||||
dsc->eol_byte_num = total_bytes % 3;
|
||||
dsc->pclk_per_line = CEIL(total_bytes, 3);
|
||||
|
||||
dsc->slice_last_group_size = 3 - dsc->eol_byte_num;
|
||||
|
||||
pr_debug("%s: pclk_per_line=%d total_bytes=%d eol_byte_num=%d\n",
|
||||
__func__, dsc->pclk_per_line, total_bytes, dsc->eol_byte_num);
|
||||
|
||||
dsc->bytes_per_pkt = bytes_in_slice * dsc->slice_per_pkt;
|
||||
|
||||
dsc->det_thresh_flatness = 7 + 2*(bpc - 8);
|
||||
|
||||
dsc->initial_xmit_delay = dsc->rc_model_size / (2 * bpp);
|
||||
|
||||
dsc->initial_lines = mdss_dsc_initial_line_calc(bpc,
|
||||
dsc->initial_xmit_delay, dsc->slice_width, slice_per_line);
|
||||
|
||||
groups_per_line = CEIL(dsc->slice_width, 3);
|
||||
|
||||
dsc->chunk_size = dsc->slice_width * bpp / 8;
|
||||
if ((dsc->slice_width * bpp) % 8)
|
||||
dsc->chunk_size++;
|
||||
|
||||
/* rbs-min */
|
||||
min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset +
|
||||
dsc->initial_xmit_delay * bpp +
|
||||
groups_per_line * dsc->first_line_bpg_offset;
|
||||
|
||||
hrd_delay = CEIL(min_rate_buffer_size, bpp);
|
||||
|
||||
dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
|
||||
|
||||
dsc->initial_scale_value = 8 * dsc->rc_model_size /
|
||||
(dsc->rc_model_size - dsc->initial_offset);
|
||||
|
||||
slice_bits = 8 * dsc->chunk_size * dsc->slice_height;
|
||||
|
||||
groups_total = groups_per_line * dsc->slice_height;
|
||||
|
||||
data = dsc->first_line_bpg_offset * 2048;
|
||||
|
||||
dsc->nfl_bpg_offset = CEIL(data, (dsc->slice_height - 1));
|
||||
|
||||
pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2);
|
||||
|
||||
num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size -
|
||||
((slice_bits - pre_num_extra_mux_bits) % mux_words_size));
|
||||
|
||||
data = 2048 * (dsc->rc_model_size - dsc->initial_offset
|
||||
+ num_extra_mux_bits);
|
||||
dsc->slice_bpg_offset = CEIL(data, groups_total);
|
||||
|
||||
/* bpp * 16 + 0.5 */
|
||||
data = bpp * 16;
|
||||
data *= 2;
|
||||
data++;
|
||||
data /= 2;
|
||||
target_bpp_x16 = data;
|
||||
|
||||
data = (dsc->initial_xmit_delay * target_bpp_x16) / 16;
|
||||
final_value = dsc->rc_model_size - data + num_extra_mux_bits;
|
||||
|
||||
final_scale = 8 * dsc->rc_model_size /
|
||||
(dsc->rc_model_size - final_value);
|
||||
|
||||
dsc->final_offset = final_value;
|
||||
|
||||
data = (final_scale - 9) * (dsc->nfl_bpg_offset +
|
||||
dsc->slice_bpg_offset);
|
||||
dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
|
||||
|
||||
dsc->scale_decrement_interval = groups_per_line /
|
||||
(dsc->initial_scale_value - 8);
|
||||
|
||||
pr_debug("%s: initial_xmit_delay=%d\n", __func__,
|
||||
dsc->initial_xmit_delay);
|
||||
|
||||
pr_debug("%s: bpg_offset, nfl=%d slice=%d\n", __func__,
|
||||
dsc->nfl_bpg_offset, dsc->slice_bpg_offset);
|
||||
|
||||
pr_debug("%s: groups_per_line=%d chunk_size=%d\n", __func__,
|
||||
groups_per_line, dsc->chunk_size);
|
||||
pr_debug("%s:min_rate_buffer_size=%d hrd_delay=%d\n", __func__,
|
||||
min_rate_buffer_size, hrd_delay);
|
||||
pr_debug("%s:initial_dec_delay=%d initial_scale_value=%d\n", __func__,
|
||||
dsc->initial_dec_delay, dsc->initial_scale_value);
|
||||
pr_debug("%s:slice_bits=%d, groups_total=%d\n", __func__,
|
||||
slice_bits, groups_total);
|
||||
pr_debug("%s: first_line_bgp_offset=%d slice_height=%d\n", __func__,
|
||||
dsc->first_line_bpg_offset, dsc->slice_height);
|
||||
pr_debug("%s:final_value=%d final_scale=%d\n", __func__,
|
||||
final_value, final_scale);
|
||||
pr_debug("%s: sacle_increment_interval=%d scale_decrement_interval=%d\n",
|
||||
__func__, dsc->scale_increment_interval,
|
||||
dsc->scale_decrement_interval);
|
||||
}
|
||||
|
||||
static int mdss_dsi_parse_dsc_params(struct device_node *np,
|
||||
struct mdss_panel_timing *timing, bool is_split_display)
|
||||
{
|
||||
u32 data;
|
||||
u32 data, intf_width;
|
||||
int rc = 0;
|
||||
struct dsc_desc *dsc = &timing->dsc;
|
||||
|
||||
|
@ -1426,19 +1113,20 @@ static int mdss_dsi_parse_dsc_params(struct device_node *np,
|
|||
if (rc)
|
||||
goto end;
|
||||
dsc->slice_width = data;
|
||||
intf_width = timing->xres;
|
||||
|
||||
if (timing->xres % dsc->slice_width) {
|
||||
if (intf_width % dsc->slice_width) {
|
||||
pr_err("%s: Error: multiple of slice-width:%d should match panel-width:%d\n",
|
||||
__func__, dsc->slice_width, timing->xres);
|
||||
__func__, dsc->slice_width, intf_width);
|
||||
goto end;
|
||||
}
|
||||
|
||||
data = timing->xres / dsc->slice_width;
|
||||
data = intf_width / dsc->slice_width;
|
||||
if (((timing->dsc_enc_total > 1) && ((data != 2) && (data != 4))) ||
|
||||
((timing->dsc_enc_total == 1) && (data > 2))) {
|
||||
pr_err("%s: Error: max 2 slice per encoder. slice-width:%d should match panel-width:%d dsc_enc_total:%d\n",
|
||||
__func__, dsc->slice_width,
|
||||
timing->xres, timing->dsc_enc_total);
|
||||
intf_width, timing->dsc_enc_total);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1447,6 +1135,19 @@ static int mdss_dsi_parse_dsc_params(struct device_node *np,
|
|||
goto end;
|
||||
dsc->slice_per_pkt = data;
|
||||
|
||||
/*
|
||||
* slice_per_pkt can be either 1 or all slices_per_intf
|
||||
*/
|
||||
if ((dsc->slice_per_pkt > 1) && (dsc->slice_per_pkt !=
|
||||
DIV_ROUND_UP(intf_width, dsc->slice_width))) {
|
||||
pr_err("Error: slice_per_pkt can be either 1 or all slices_per_intf\n");
|
||||
pr_err("%s: slice_per_pkt=%d, slice_width=%d intf_width=%d\n",
|
||||
__func__,
|
||||
dsc->slice_per_pkt, dsc->slice_width, intf_width);
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pr_debug("%s: num_enc:%d :slice h=%d w=%d s_pkt=%d\n", __func__,
|
||||
timing->dsc_enc_total, dsc->slice_height,
|
||||
dsc->slice_width, dsc->slice_per_pkt);
|
||||
|
@ -1474,10 +1175,11 @@ static int mdss_dsi_parse_dsc_params(struct device_node *np,
|
|||
dsc->config_by_manufacture_cmd = of_property_read_bool(np,
|
||||
"qcom,mdss-dsc-config-by-manufacture-cmd");
|
||||
|
||||
mdss_dsc_parameters_calc(&timing->dsc, timing->xres, timing->yres);
|
||||
mdss_panel_dsc_parameters_calc(&timing->dsc);
|
||||
mdss_panel_dsc_pclk_param_calc(&timing->dsc, intf_width);
|
||||
|
||||
timing->dsc.full_frame_slices =
|
||||
CEIL(timing->dsc.pic_width, timing->dsc.slice_width);
|
||||
DIV_ROUND_UP(intf_width, timing->dsc.slice_width);
|
||||
|
||||
timing->compression_mode = COMPRESSION_DSC;
|
||||
|
||||
|
|
|
@ -1088,15 +1088,15 @@ static inline uint8_t pp_vig_csc_pipe_val(struct mdss_mdp_pipe *pipe)
|
|||
}
|
||||
|
||||
/*
|
||||
* when DUAL_LM_SINGLE_DISPLAY is used with 2 DSC encoders, DSC_MERGE is
|
||||
* used during full frame updates. Now when we go from full frame update
|
||||
* to right-only update, we need to disable DSC_MERGE. However, DSC_MERGE
|
||||
* is controlled through DSC0_COMMON_MODE register which is double buffered,
|
||||
* and this double buffer update is tied to LM0. Now for right-only update,
|
||||
* LM0 will not get double buffer update signal. So DSC_MERGE is not disabled
|
||||
* for right-only update which is wrong HW state and leads ping-pong timeout.
|
||||
* Workaround for this is to use LM0->DSC0 pair for right-only update
|
||||
* and disable DSC_MERGE.
|
||||
* when split_lm topology is used without 3D_Mux, either DSC_MERGE or
|
||||
* split_panel is used during full frame updates. Now when we go from
|
||||
* full frame update to right-only update, we need to disable DSC_MERGE or
|
||||
* split_panel. However, those are controlled through DSC0_COMMON_MODE
|
||||
* register which is double buffered, and this double buffer update is tied to
|
||||
* LM0. Now for right-only update, LM0 will not get double buffer update signal.
|
||||
* So DSC_MERGE or split_panel is not disabled for right-only update which is
|
||||
* a wrong HW state and leads ping-pong timeout. Workaround for this is to use
|
||||
* LM0->DSC0 pair for right-only update and disable DSC_MERGE or split_panel.
|
||||
*
|
||||
* However using LM0->DSC0 pair for right-only update requires many changes
|
||||
* at various levels of SW. To lower the SW impact and still support
|
||||
|
@ -1112,11 +1112,12 @@ static inline bool mdss_mdp_is_lm_swap_needed(struct mdss_data_type *mdata,
|
|||
!mctl->panel_data || !mctl->mfd)
|
||||
return false;
|
||||
|
||||
return (is_dual_lm_single_display(mctl->mfd)) &&
|
||||
return (is_dsc_compression(&mctl->panel_data->panel_info)) &&
|
||||
(mctl->panel_data->panel_info.partial_update_enabled) &&
|
||||
(mdss_has_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU)) &&
|
||||
(is_dsc_compression(&mctl->panel_data->panel_info)) &&
|
||||
(mctl->panel_data->panel_info.dsc_enc_total == 2) &&
|
||||
((mctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) ||
|
||||
((mctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) &&
|
||||
(mctl->panel_data->panel_info.dsc_enc_total == 2))) &&
|
||||
(!mctl->mixer_left->valid_roi) &&
|
||||
(mctl->mixer_right->valid_roi);
|
||||
}
|
||||
|
@ -1132,6 +1133,8 @@ void mdss_mdp_hist_irq_disable(u32 irq);
|
|||
void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
|
||||
int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
|
||||
void (*fnc_ptr)(void *), void *arg);
|
||||
int mdss_mdp_set_intr_callback_nosync(u32 intr_type, u32 intf_num,
|
||||
void (*fnc_ptr)(void *), void *arg);
|
||||
|
||||
void mdss_mdp_footswitch_ctrl_splash(int on);
|
||||
void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable);
|
||||
|
@ -1449,7 +1452,6 @@ struct mdss_mdp_writeback *mdss_mdp_wb_assign(u32 id, u32 reg_index);
|
|||
struct mdss_mdp_writeback *mdss_mdp_wb_alloc(u32 caps, u32 reg_index);
|
||||
void mdss_mdp_wb_free(struct mdss_mdp_writeback *wb);
|
||||
|
||||
void mdss_dsc_parameters_calc(struct dsc_desc *dsc, int width, int height);
|
||||
void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_panel_info *pinfo);
|
||||
|
||||
|
|
|
@ -50,9 +50,70 @@ static inline u64 apply_inverse_fudge_factor(u64 val,
|
|||
|
||||
static DEFINE_MUTEX(mdss_mdp_ctl_lock);
|
||||
|
||||
static inline int __mdss_mdp_ctl_get_mixer_off(struct mdss_mdp_mixer *mixer);
|
||||
static u32 mdss_mdp_get_vbp_factor_max(struct mdss_mdp_ctl *ctl);
|
||||
|
||||
static void __mdss_mdp_reset_mixercfg(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
u32 off;
|
||||
int i, nmixers;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
||||
if (!ctl || !mdata)
|
||||
return;
|
||||
|
||||
nmixers = mdata->nmixers_intf + mdata->nmixers_wb;
|
||||
|
||||
for (i = 0; i < nmixers; i++) {
|
||||
off = MDSS_MDP_REG_CTL_LAYER(i);
|
||||
mdss_mdp_ctl_write(ctl, off, 0);
|
||||
|
||||
off += MDSS_MDP_REG_CTL_LAYER_EXTN(i);
|
||||
mdss_mdp_ctl_write(ctl, off, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int __mdss_mdp_ctl_get_mixer_off(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
|
||||
if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
|
||||
return MDSS_MDP_CTL_X_LAYER_5;
|
||||
else
|
||||
return MDSS_MDP_REG_CTL_LAYER(mixer->num);
|
||||
} else {
|
||||
return MDSS_MDP_REG_CTL_LAYER(mixer->num +
|
||||
MDSS_MDP_INTF_LAYERMIXER3);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int __mdss_mdp_ctl_get_mixer_extn_off(
|
||||
struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
|
||||
if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
|
||||
return MDSS_MDP_REG_CTL_LAYER_EXTN(5);
|
||||
else
|
||||
return MDSS_MDP_REG_CTL_LAYER_EXTN(mixer->num);
|
||||
} else {
|
||||
return MDSS_MDP_REG_CTL_LAYER_EXTN(mixer->num +
|
||||
MDSS_MDP_INTF_LAYERMIXER3);
|
||||
}
|
||||
}
|
||||
|
||||
u32 mdss_mdp_get_mixercfg(struct mdss_mdp_mixer *mixer, bool extn)
|
||||
{
|
||||
u32 mixer_off;
|
||||
|
||||
if (!mixer || !mixer->ctl)
|
||||
return 0;
|
||||
|
||||
if (extn)
|
||||
mixer_off = __mdss_mdp_ctl_get_mixer_extn_off(mixer);
|
||||
else
|
||||
mixer_off = __mdss_mdp_ctl_get_mixer_off(mixer);
|
||||
|
||||
return mdss_mdp_ctl_read(mixer->ctl, mixer_off);
|
||||
}
|
||||
|
||||
static inline u32 mdss_mdp_get_pclk_rate(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
|
||||
|
@ -2393,13 +2454,13 @@ static inline int mdss_mdp_set_split_ctl(struct mdss_mdp_ctl *ctl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void mdss_mdp_ctl_dsc_enable(struct mdss_mdp_mixer *mixer)
|
||||
static inline void __dsc_enable(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
mdss_mdp_pingpong_write(mixer->pingpong_base,
|
||||
MDSS_MDP_REG_PP_DSC_MODE, 1);
|
||||
}
|
||||
|
||||
static inline void mdss_mdp_ctl_dsc_disable(struct mdss_mdp_mixer *mixer)
|
||||
static inline void __dsc_disable(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
char __iomem *offset = mdata->mdp_base;
|
||||
|
@ -2418,7 +2479,7 @@ static inline void mdss_mdp_ctl_dsc_disable(struct mdss_mdp_mixer *mixer)
|
|||
writel_relaxed(0, offset + MDSS_MDP_REG_DSC_COMMON_MODE);
|
||||
}
|
||||
|
||||
static void mdss_mdp_ctl_dsc_config(struct mdss_mdp_mixer *mixer,
|
||||
static void __dsc_config(struct mdss_mdp_mixer *mixer,
|
||||
struct dsc_desc *dsc, u32 mode, bool ich_reset_override)
|
||||
{
|
||||
u32 data;
|
||||
|
@ -2533,11 +2594,10 @@ static void mdss_mdp_ctl_dsc_config(struct mdss_mdp_mixer *mixer,
|
|||
writel_relaxed(data, offset + MDSS_MDP_REG_DSC_RC);
|
||||
}
|
||||
|
||||
static void mdss_mdp_ctl_dsc_config_thresh(struct mdss_mdp_mixer *mixer,
|
||||
struct mdss_panel_info *pinfo)
|
||||
static void __dsc_config_thresh(struct mdss_mdp_mixer *mixer,
|
||||
struct dsc_desc *dsc)
|
||||
{
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
struct dsc_desc *dsc = &pinfo->dsc;
|
||||
char __iomem *offset, *off;
|
||||
u32 *lp;
|
||||
char *cp;
|
||||
|
@ -2583,80 +2643,61 @@ static void mdss_mdp_ctl_dsc_config_thresh(struct mdss_mdp_mixer *mixer,
|
|||
}
|
||||
}
|
||||
|
||||
void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl,
|
||||
static bool __is_dsc_merge_enabled(u32 common_mode)
|
||||
{
|
||||
return common_mode & BIT(1);
|
||||
}
|
||||
|
||||
static bool __dsc_is_3d_mux_enabled(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_panel_info *pinfo)
|
||||
{
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
struct mdss_mdp_mixer *mixer_left = ctl->mixer_left;
|
||||
struct mdss_mdp_mixer *mixer_right = NULL;
|
||||
struct dsc_desc *dsc = &pinfo->dsc;
|
||||
u32 pic_width = 0, pic_height = 0;
|
||||
u32 mode = 0;
|
||||
bool recalc_dsc_params = false;
|
||||
bool ich_reset_override = false;
|
||||
bool dsc_merge = false, mux_3d = false;
|
||||
bool left_valid = false, right_valid = false;
|
||||
return ctl && is_dual_lm_single_display(ctl->mfd) &&
|
||||
pinfo && (pinfo->dsc_enc_total == 1);
|
||||
}
|
||||
|
||||
if (!ctl->is_master) {
|
||||
pr_debug("skip slave ctl because master will program for both\n");
|
||||
return;
|
||||
/* must be called from master ctl */
|
||||
static u32 __dsc_get_common_mode(struct mdss_mdp_ctl *ctl, bool mux_3d)
|
||||
{
|
||||
u32 common_mode = 0;
|
||||
|
||||
if (ctl->is_video_mode)
|
||||
common_mode = BIT(2);
|
||||
|
||||
if (mdss_mdp_is_both_lm_valid(ctl))
|
||||
common_mode |= BIT(0);
|
||||
|
||||
if (is_dual_lm_single_display(ctl->mfd)) {
|
||||
if (mux_3d)
|
||||
common_mode &= ~BIT(0);
|
||||
else if (mdss_mdp_is_both_lm_valid(ctl)) /* dsc_merge */
|
||||
common_mode |= BIT(1);
|
||||
}
|
||||
|
||||
if (pinfo->type == MIPI_VIDEO_PANEL)
|
||||
mode = BIT(2);
|
||||
return common_mode;
|
||||
}
|
||||
|
||||
/* pingpong split with DSC needs to be handled */
|
||||
if (is_split_lm(ctl->mfd)) {
|
||||
mixer_right = ctl->mixer_right;
|
||||
if (is_dual_lm_single_display(ctl->mfd)) {
|
||||
if (pinfo->dsc_enc_total == 2) {
|
||||
/* DSC Merge */
|
||||
if (mdss_mdp_is_both_lm_valid(ctl)) {
|
||||
mode |= BIT(1);
|
||||
dsc_merge = true;
|
||||
}
|
||||
} else {
|
||||
mux_3d = true;
|
||||
}
|
||||
}
|
||||
static void __dsc_get_pic_dim(struct mdss_mdp_mixer *mixer_l,
|
||||
struct mdss_mdp_mixer *mixer_r, u32 *pic_w, u32 *pic_h)
|
||||
{
|
||||
bool valid_l = mixer_l && mixer_l->valid_roi;
|
||||
bool valid_r = mixer_r && mixer_r->valid_roi;
|
||||
|
||||
/*
|
||||
* two independent decoders on DDIC requires
|
||||
* split 2p2d mode but it is not supported yet.
|
||||
*/
|
||||
if (mdss_mdp_is_both_lm_valid(ctl) && !mux_3d)
|
||||
mode |= BIT(0); /* assumming 1 decoder on panel side */
|
||||
*pic_w = 0;
|
||||
*pic_h = 0;
|
||||
|
||||
if (valid_l) {
|
||||
*pic_w = mixer_l->roi.w;
|
||||
*pic_h = mixer_l->roi.h;
|
||||
}
|
||||
|
||||
left_valid = mixer_left->valid_roi;
|
||||
right_valid = mixer_right && mixer_right->valid_roi;
|
||||
|
||||
if (left_valid) {
|
||||
pic_width = mixer_left->roi.w;
|
||||
pic_height = mixer_left->roi.h;
|
||||
recalc_dsc_params = true;
|
||||
if (valid_r) {
|
||||
*pic_w += mixer_r->roi.w;
|
||||
*pic_h = mixer_r->roi.h;
|
||||
}
|
||||
}
|
||||
|
||||
if (mixer_right && right_valid) {
|
||||
pic_width += mixer_right->roi.w;
|
||||
pic_height = mixer_right->roi.h; /* height on both lm is same */
|
||||
|
||||
if (is_dual_lm_single_display(ctl->mfd)) {
|
||||
recalc_dsc_params = true;
|
||||
} else { /* DUAL_LM_DUAL_DISPLAY */
|
||||
struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
struct mdss_panel_info *spinfo =
|
||||
&sctl->panel_data->panel_info;
|
||||
|
||||
mdss_dsc_parameters_calc(&spinfo->dsc,
|
||||
pic_width, pic_height);
|
||||
}
|
||||
}
|
||||
|
||||
/* re-calculate DSC params before configuring them to MDP */
|
||||
if (recalc_dsc_params)
|
||||
mdss_dsc_parameters_calc(dsc, pic_width, pic_height);
|
||||
|
||||
static bool __is_ich_reset_override_needed(bool pu_en, struct dsc_desc *dsc)
|
||||
{
|
||||
/*
|
||||
* As per the DSC spec, ICH_RESET can be either end of the slice line
|
||||
* or at the end of the slice. HW internally generates ich_reset at
|
||||
|
@ -2672,49 +2713,65 @@ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl,
|
|||
* then HW will generate ich_reset at end of the slice. This is a
|
||||
* mismatch. Prevent this by overriding HW's decision.
|
||||
*/
|
||||
if (pinfo->partial_update_enabled && !dsc_merge &&
|
||||
(dsc->full_frame_slices > 1) &&
|
||||
(dsc->slice_width == dsc->pic_width))
|
||||
ich_reset_override = true;
|
||||
return pu_en && dsc && (dsc->full_frame_slices > 1) &&
|
||||
(dsc->slice_width == dsc->pic_width);
|
||||
}
|
||||
|
||||
/*
|
||||
* From this point onwards, left_valid and right_valid variables
|
||||
* will represent only DSC encoders and does not represent use of
|
||||
* layer mixers. So if both are valid, both encoders are used. If
|
||||
* left_valid is true then left DSC encoder is used, same for right.
|
||||
*/
|
||||
static void __dsc_setup_dual_lm_single_display(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_panel_info *pinfo)
|
||||
{
|
||||
u32 pic_width = 0, pic_height = 0;
|
||||
u32 intf_ip_w, enc_ip_w, common_mode, this_frame_slices;
|
||||
bool valid_l, valid_r;
|
||||
bool enable_right_dsc;
|
||||
bool mux_3d, ich_reset_override;
|
||||
struct dsc_desc *dsc;
|
||||
struct mdss_mdp_mixer *mixer_l, *mixer_r;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
||||
if (!pinfo || !ctl || !ctl->is_master ||
|
||||
!is_dual_lm_single_display(ctl->mfd))
|
||||
return;
|
||||
|
||||
dsc = &pinfo->dsc;
|
||||
mixer_l = ctl->mixer_left;
|
||||
mixer_r = ctl->mixer_right;
|
||||
|
||||
mux_3d = __dsc_is_3d_mux_enabled(ctl, pinfo);
|
||||
common_mode = __dsc_get_common_mode(ctl, mux_3d);
|
||||
__dsc_get_pic_dim(mixer_l, mixer_r, &pic_width, &pic_height);
|
||||
|
||||
valid_l = mixer_l->valid_roi;
|
||||
valid_r = mixer_r->valid_roi;
|
||||
if (mdss_mdp_is_lm_swap_needed(mdata, ctl)) {
|
||||
right_valid = false;
|
||||
left_valid = true;
|
||||
valid_l = true;
|
||||
valid_r = false;
|
||||
}
|
||||
|
||||
if ((is_dual_lm_single_display(ctl->mfd)) &&
|
||||
(pinfo->partial_update_enabled) &&
|
||||
(pinfo->dsc_enc_total == 2) && (dsc->full_frame_slices == 4) &&
|
||||
this_frame_slices = pic_width / dsc->slice_width;
|
||||
|
||||
/* enable or disable pp_split + DSC_Merge based on partial update */
|
||||
if ((pinfo->partial_update_enabled) && !mux_3d &&
|
||||
(dsc->full_frame_slices == 4) &&
|
||||
(mdss_has_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT))) {
|
||||
|
||||
if (mdss_mdp_is_both_lm_valid(ctl)) {
|
||||
if (valid_l && valid_r) {
|
||||
/* left + right */
|
||||
|
||||
pr_debug("full line (4 slices) or middle 2 slice partial update\n");
|
||||
writel_relaxed(0x0,
|
||||
mdata->mdp_base + mdata->ppb[0].ctl_off);
|
||||
writel_relaxed(0x0,
|
||||
mdata->mdp_base + MDSS_MDP_REG_DCE_SEL);
|
||||
} else if (mixer_left->valid_roi || mixer_right->valid_roi) {
|
||||
} else if (valid_l || valid_r) {
|
||||
/* left-only or right-only */
|
||||
|
||||
u32 this_frame_slices =
|
||||
dsc->pic_width / dsc->slice_width;
|
||||
|
||||
if (this_frame_slices == 2) {
|
||||
pr_debug("2 slice parital update, use merge\n");
|
||||
|
||||
/* tandem + merge */
|
||||
mode = BIT(1) | BIT(0);
|
||||
common_mode = BIT(1) | BIT(0);
|
||||
|
||||
right_valid = true;
|
||||
left_valid = true;
|
||||
valid_r = true;
|
||||
valid_l = true;
|
||||
|
||||
writel_relaxed(0x2 << 4, mdata->mdp_base +
|
||||
mdata->ppb[0].ctl_off);
|
||||
|
@ -2722,46 +2779,239 @@ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl,
|
|||
mdata->mdp_base + MDSS_MDP_REG_DCE_SEL);
|
||||
} else {
|
||||
pr_debug("only one slice partial update\n");
|
||||
writel_relaxed(0x0,
|
||||
mdata->mdp_base +
|
||||
writel_relaxed(0x0, mdata->mdp_base +
|
||||
mdata->ppb[0].ctl_off);
|
||||
writel_relaxed(0x0,
|
||||
mdata->mdp_base + MDSS_MDP_REG_DCE_SEL);
|
||||
writel_relaxed(0x0, mdata->mdp_base +
|
||||
MDSS_MDP_REG_DCE_SEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (left_valid) {
|
||||
mdss_mdp_ctl_dsc_config(mixer_left, dsc, mode,
|
||||
ich_reset_override);
|
||||
mdss_mdp_ctl_dsc_config_thresh(mixer_left, pinfo);
|
||||
mdss_mdp_ctl_dsc_enable(mixer_left);
|
||||
} else {
|
||||
mdss_mdp_ctl_dsc_disable(mixer_left);
|
||||
writel_relaxed(0x0, mdata->mdp_base + MDSS_MDP_REG_DCE_SEL);
|
||||
}
|
||||
|
||||
if (mixer_right) {
|
||||
bool enable_right_dsc = right_valid;
|
||||
mdss_panel_dsc_update_pic_dim(dsc, pic_width, pic_height);
|
||||
|
||||
if (mux_3d && left_valid)
|
||||
enable_right_dsc = false;
|
||||
intf_ip_w = this_frame_slices * dsc->slice_width;
|
||||
mdss_panel_dsc_pclk_param_calc(dsc, intf_ip_w);
|
||||
|
||||
if (enable_right_dsc) {
|
||||
mdss_mdp_ctl_dsc_config(mixer_right, dsc, mode,
|
||||
ich_reset_override);
|
||||
mdss_mdp_ctl_dsc_config_thresh(mixer_right, pinfo);
|
||||
mdss_mdp_ctl_dsc_enable(mixer_right);
|
||||
} else {
|
||||
mdss_mdp_ctl_dsc_disable(mixer_right);
|
||||
}
|
||||
enc_ip_w = intf_ip_w;
|
||||
/* if dsc_merge, both encoders work on same number of slices */
|
||||
if (__is_dsc_merge_enabled(common_mode))
|
||||
enc_ip_w /= 2;
|
||||
mdss_panel_dsc_initial_line_calc(dsc, enc_ip_w);
|
||||
|
||||
/*
|
||||
* __is_ich_reset_override_needed should be called only after
|
||||
* updating pic dimension, mdss_panel_dsc_update_pic_dim.
|
||||
*/
|
||||
ich_reset_override = __is_ich_reset_override_needed(
|
||||
pinfo->partial_update_enabled, dsc);
|
||||
if (valid_l) {
|
||||
__dsc_config(mixer_l, dsc, common_mode, ich_reset_override);
|
||||
__dsc_config_thresh(mixer_l, dsc);
|
||||
__dsc_enable(mixer_l);
|
||||
} else {
|
||||
__dsc_disable(mixer_l);
|
||||
}
|
||||
|
||||
enable_right_dsc = valid_r;
|
||||
if (mux_3d && valid_l)
|
||||
enable_right_dsc = false;
|
||||
|
||||
if (enable_right_dsc) {
|
||||
__dsc_config(mixer_r, dsc, common_mode, ich_reset_override);
|
||||
__dsc_config_thresh(mixer_r, dsc);
|
||||
__dsc_enable(mixer_r);
|
||||
} else {
|
||||
__dsc_disable(mixer_r);
|
||||
}
|
||||
|
||||
pr_debug("mix%d: valid_l=%d mix%d: valid_r=%d mode=%d, pic_dim:%dx%d mux_3d=%d intf_ip_w=%d enc_ip_w=%d ich_ovrd=%d\n",
|
||||
mixer_l->num, valid_l, mixer_r->num, valid_r,
|
||||
common_mode, pic_width, pic_height,
|
||||
mux_3d, intf_ip_w, enc_ip_w, ich_reset_override);
|
||||
|
||||
MDSS_XLOG(mixer_l->num, valid_l, mixer_r->num, valid_r,
|
||||
common_mode, pic_width, pic_height,
|
||||
mux_3d, intf_ip_w, enc_ip_w, ich_reset_override);
|
||||
}
|
||||
|
||||
static void __dsc_setup_dual_lm_dual_display(
|
||||
struct mdss_mdp_ctl *ctl, struct mdss_panel_info *pinfo,
|
||||
struct mdss_mdp_ctl *sctl, struct mdss_panel_info *spinfo)
|
||||
{
|
||||
u32 pic_width = 0, pic_height = 0;
|
||||
u32 intf_ip_w, enc_ip_w, common_mode, this_frame_slices;
|
||||
bool valid_l, valid_r;
|
||||
bool ich_reset_override;
|
||||
struct dsc_desc *dsc_l, *dsc_r;
|
||||
struct mdss_mdp_mixer *mixer_l, *mixer_r;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
||||
if (!pinfo || !ctl || !sctl || !spinfo ||
|
||||
!ctl->is_master || !ctl->mfd ||
|
||||
(ctl->mfd->split_mode != MDP_DUAL_LM_DUAL_DISPLAY))
|
||||
return;
|
||||
|
||||
dsc_l = &pinfo->dsc;
|
||||
dsc_r = &spinfo->dsc;
|
||||
|
||||
mixer_l = ctl->mixer_left;
|
||||
mixer_r = ctl->mixer_right;
|
||||
|
||||
common_mode = __dsc_get_common_mode(ctl, false);
|
||||
/*
|
||||
* In this topology, both DSC use same pic dimension. So no need to
|
||||
* maintain two separate local copies.
|
||||
*/
|
||||
__dsc_get_pic_dim(mixer_l, mixer_r, &pic_width, &pic_height);
|
||||
|
||||
valid_l = mixer_l->valid_roi;
|
||||
valid_r = mixer_r->valid_roi;
|
||||
if (mdss_mdp_is_lm_swap_needed(mdata, ctl)) {
|
||||
valid_l = true;
|
||||
valid_r = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since both DSC use same pic dimension, set same pic dimension
|
||||
* to both DSC structures.
|
||||
*/
|
||||
mdss_panel_dsc_update_pic_dim(dsc_l, pic_width, pic_height);
|
||||
mdss_panel_dsc_update_pic_dim(dsc_r, pic_width, pic_height);
|
||||
|
||||
this_frame_slices = pic_width / dsc_l->slice_width;
|
||||
intf_ip_w = this_frame_slices * dsc_l->slice_width;
|
||||
if (valid_l && valid_r)
|
||||
intf_ip_w /= 2;
|
||||
/*
|
||||
* In this topology when both interfaces are active, they have same
|
||||
* load so intf_ip_w will be same.
|
||||
*/
|
||||
mdss_panel_dsc_pclk_param_calc(dsc_l, intf_ip_w);
|
||||
mdss_panel_dsc_pclk_param_calc(dsc_r, intf_ip_w);
|
||||
|
||||
/*
|
||||
* In this topology, since there is no dsc_merge, uncompressed input
|
||||
* to encoder and interface is same.
|
||||
*/
|
||||
enc_ip_w = intf_ip_w;
|
||||
mdss_panel_dsc_initial_line_calc(dsc_l, enc_ip_w);
|
||||
mdss_panel_dsc_initial_line_calc(dsc_r, enc_ip_w);
|
||||
|
||||
/*
|
||||
* __is_ich_reset_override_needed should be called only after
|
||||
* updating pic dimension, mdss_panel_dsc_update_pic_dim.
|
||||
*/
|
||||
ich_reset_override = __is_ich_reset_override_needed(
|
||||
pinfo->partial_update_enabled, dsc_l);
|
||||
|
||||
if (valid_l) {
|
||||
__dsc_config(mixer_l, dsc_l, common_mode, ich_reset_override);
|
||||
__dsc_config_thresh(mixer_l, dsc_l);
|
||||
__dsc_enable(mixer_l);
|
||||
} else {
|
||||
__dsc_disable(mixer_l);
|
||||
}
|
||||
|
||||
if (valid_r) {
|
||||
__dsc_config(mixer_r, dsc_r, common_mode, ich_reset_override);
|
||||
__dsc_config_thresh(mixer_r, dsc_r);
|
||||
__dsc_enable(mixer_r);
|
||||
} else {
|
||||
__dsc_disable(mixer_r);
|
||||
}
|
||||
|
||||
pr_debug("mix%d: valid_l=%d mix%d: valid_r=%d mode=%d, pic_dim:%dx%d intf_ip_w=%d enc_ip_w=%d ich_ovrd=%d\n",
|
||||
mixer_l->num, valid_l, mixer_r->num, valid_r,
|
||||
common_mode, pic_width, pic_height,
|
||||
intf_ip_w, enc_ip_w, ich_reset_override);
|
||||
|
||||
MDSS_XLOG(mixer_l->num, valid_l, mixer_r->num, valid_r,
|
||||
common_mode, pic_width, pic_height,
|
||||
intf_ip_w, enc_ip_w, ich_reset_override);
|
||||
}
|
||||
|
||||
static void __dsc_setup_single_lm_single_display(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_panel_info *pinfo)
|
||||
{
|
||||
u32 pic_width = 0, pic_height = 0;
|
||||
u32 intf_ip_w, enc_ip_w, common_mode, this_frame_slices;
|
||||
bool valid;
|
||||
bool ich_reset_override;
|
||||
struct dsc_desc *dsc;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
|
||||
if (!pinfo || !ctl || !ctl->is_master)
|
||||
return;
|
||||
|
||||
dsc = &pinfo->dsc;
|
||||
mixer = ctl->mixer_left;
|
||||
valid = mixer->valid_roi;
|
||||
|
||||
common_mode = __dsc_get_common_mode(ctl, false);
|
||||
__dsc_get_pic_dim(mixer, NULL, &pic_width, &pic_height);
|
||||
|
||||
mdss_panel_dsc_update_pic_dim(dsc, pic_width, pic_height);
|
||||
|
||||
this_frame_slices = pic_width / dsc->slice_width;
|
||||
intf_ip_w = this_frame_slices * dsc->slice_width;
|
||||
mdss_panel_dsc_pclk_param_calc(dsc, intf_ip_w);
|
||||
|
||||
enc_ip_w = intf_ip_w;
|
||||
mdss_panel_dsc_initial_line_calc(dsc, enc_ip_w);
|
||||
|
||||
/*
|
||||
* __is_ich_reset_override_needed should be called only after
|
||||
* updating pic dimension, mdss_panel_dsc_update_pic_dim.
|
||||
*/
|
||||
ich_reset_override = __is_ich_reset_override_needed(
|
||||
pinfo->partial_update_enabled, dsc);
|
||||
if (valid) {
|
||||
__dsc_config(mixer, dsc, common_mode, ich_reset_override);
|
||||
__dsc_config_thresh(mixer, dsc);
|
||||
__dsc_enable(mixer);
|
||||
} else {
|
||||
__dsc_disable(mixer);
|
||||
}
|
||||
|
||||
pr_debug("mix%d: valid=%d mode=%d, pic_dim:%dx%d intf_ip_w=%d enc_ip_w=%d ich_ovrd=%d\n",
|
||||
mixer->num, valid, common_mode, pic_width, pic_height,
|
||||
intf_ip_w, enc_ip_w, ich_reset_override);
|
||||
|
||||
MDSS_XLOG(mixer->num, valid, common_mode, pic_width, pic_height,
|
||||
intf_ip_w, enc_ip_w, ich_reset_override);
|
||||
}
|
||||
|
||||
void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_panel_info *pinfo)
|
||||
{
|
||||
struct mdss_mdp_ctl *sctl;
|
||||
struct mdss_panel_info *spinfo;
|
||||
|
||||
if (!is_dsc_compression(pinfo))
|
||||
return;
|
||||
|
||||
if (!ctl->is_master) {
|
||||
pr_debug("skip slave ctl because master will program for both\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ctl->mfd->split_mode) {
|
||||
case MDP_DUAL_LM_SINGLE_DISPLAY:
|
||||
__dsc_setup_dual_lm_single_display(ctl, pinfo);
|
||||
break;
|
||||
case MDP_DUAL_LM_DUAL_DISPLAY:
|
||||
sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
spinfo = &sctl->panel_data->panel_info;
|
||||
|
||||
__dsc_setup_dual_lm_dual_display(ctl, pinfo, sctl, spinfo);
|
||||
break;
|
||||
default:
|
||||
/* pp_split is not supported yet */
|
||||
__dsc_setup_single_lm_single_display(ctl, pinfo);
|
||||
break;
|
||||
}
|
||||
pr_debug("mix%d: valid_roi=%d mix%d: valid_roi=%d mode=%d, pic_dim:%dx%d\n",
|
||||
mixer_left->num, left_valid,
|
||||
mixer_right ? mixer_right->num : -1, right_valid,
|
||||
mode, pic_width, pic_height);
|
||||
MDSS_XLOG(mixer_left->num, left_valid,
|
||||
mixer_right ? mixer_right->num : -1, right_valid,
|
||||
mode, pic_width, pic_height);
|
||||
}
|
||||
|
||||
static int mdss_mdp_ctl_fbc_enable(int enable,
|
||||
|
@ -3331,8 +3581,7 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)
|
|||
if (ctl->mfd && ctl->panel_data) {
|
||||
mdss_mdp_pp_resume(ctl->mfd);
|
||||
|
||||
if (ctl->panel_data->panel_info.compression_mode ==
|
||||
COMPRESSION_DSC) {
|
||||
if (is_dsc_compression(&ctl->panel_data->panel_info)) {
|
||||
mdss_mdp_ctl_dsc_setup(ctl,
|
||||
&ctl->panel_data->panel_info);
|
||||
} else if (ctl->panel_data->panel_info.compression_mode ==
|
||||
|
@ -3438,7 +3687,7 @@ static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
|
|||
outsize = (mixer->height << 16) | mixer->width;
|
||||
mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, outsize);
|
||||
|
||||
if (pinfo->compression_mode == COMPRESSION_DSC) {
|
||||
if (is_dsc_compression(pinfo)) {
|
||||
mdss_mdp_ctl_dsc_setup(ctl, pinfo);
|
||||
} else if (pinfo->compression_mode == COMPRESSION_FBC) {
|
||||
ret = mdss_mdp_ctl_fbc_enable(1, ctl->mixer_left,
|
||||
|
@ -3517,7 +3766,6 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int power_state)
|
|||
struct mdss_mdp_ctl *sctl;
|
||||
int ret = 0;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
u32 off;
|
||||
|
||||
pr_debug("ctl_num=%d, power_state=%d\n", ctl->num, ctl->power_state);
|
||||
|
||||
|
@ -3561,18 +3809,12 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int power_state)
|
|||
mdss_mdp_ctl_split_display_enable(0, ctl, sctl);
|
||||
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, 0);
|
||||
if (sctl)
|
||||
if (sctl) {
|
||||
mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_TOP, 0);
|
||||
|
||||
if (ctl->mixer_left) {
|
||||
off = __mdss_mdp_ctl_get_mixer_off(ctl->mixer_left);
|
||||
mdss_mdp_ctl_write(ctl, off, 0);
|
||||
__mdss_mdp_reset_mixercfg(sctl);
|
||||
}
|
||||
|
||||
if (ctl->mixer_right) {
|
||||
off = __mdss_mdp_ctl_get_mixer_off(ctl->mixer_right);
|
||||
mdss_mdp_ctl_write(ctl, off, 0);
|
||||
}
|
||||
__mdss_mdp_reset_mixercfg(ctl);
|
||||
|
||||
ctl->play_cnt = 0;
|
||||
|
||||
|
@ -3821,7 +4063,7 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
|
|||
mixercfg_extn = 0;
|
||||
u32 fg_alpha = 0, bg_alpha = 0;
|
||||
struct mdss_mdp_pipe *pipe;
|
||||
struct mdss_mdp_ctl *ctl = NULL;
|
||||
struct mdss_mdp_ctl *ctl, *ctl_hw;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
struct mdss_mdp_mixer *mixer_hw = mdss_mdp_mixer_get(master_ctl,
|
||||
mixer_mux);
|
||||
|
@ -3834,12 +4076,12 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
|
|||
if (!ctl)
|
||||
return;
|
||||
|
||||
ctl_hw = ctl;
|
||||
mixer_hw->params_changed = 0;
|
||||
|
||||
/* check if mixer setup for rotator is needed */
|
||||
if (mixer_hw->rotator_mode) {
|
||||
int nmixers = mdata->nmixers_intf + mdata->nmixers_wb;
|
||||
for (i = 0; i < nmixers; i++)
|
||||
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0);
|
||||
__mdss_mdp_reset_mixercfg(ctl_hw);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3850,10 +4092,22 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
|
|||
else
|
||||
mixer = mdss_mdp_mixer_get(master_ctl,
|
||||
MDSS_MDP_MIXER_MUX_RIGHT);
|
||||
ctl_hw = mixer->ctl;
|
||||
} else {
|
||||
mixer = mixer_hw;
|
||||
}
|
||||
|
||||
/*
|
||||
* if lm_swap was used on MDP_DUAL_LM_DUAL_DISPLAY then we need to
|
||||
* reset mixercfg every frame because there might be a stale value
|
||||
* in mixerfcfg register.
|
||||
*/
|
||||
if ((ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) &&
|
||||
is_dsc_compression(&ctl->panel_data->panel_info) &&
|
||||
ctl->panel_data->panel_info.partial_update_enabled &&
|
||||
mdss_has_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU))
|
||||
__mdss_mdp_reset_mixercfg(ctl_hw);
|
||||
|
||||
if (!mixer->valid_roi) {
|
||||
/*
|
||||
* resetting mixer config is specifically needed when split
|
||||
|
@ -3861,10 +4115,10 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
|
|||
* one side.
|
||||
*/
|
||||
off = __mdss_mdp_ctl_get_mixer_off(mixer_hw);
|
||||
mdss_mdp_ctl_write(ctl, off, 0);
|
||||
mdss_mdp_ctl_write(ctl_hw, off, 0);
|
||||
/* Program ctl layer extension bits */
|
||||
mdss_mdp_ctl_write(ctl,
|
||||
off + MDSS_MDP_REG_CTL_LAYER_EXTN_OFFSET, 0);
|
||||
off = __mdss_mdp_ctl_get_mixer_extn_off(mixer_hw);
|
||||
mdss_mdp_ctl_write(ctl_hw, off, 0);
|
||||
|
||||
MDSS_XLOG(mixer->num, mixer_hw->num, XLOG_FUNC_EXIT);
|
||||
return;
|
||||
|
@ -4015,11 +4269,11 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
|
|||
|
||||
update_mixer:
|
||||
if (mixer_hw->num == MDSS_MDP_INTF_LAYERMIXER3)
|
||||
ctl->flush_bits |= BIT(20);
|
||||
ctl_hw->flush_bits |= BIT(20);
|
||||
else if (mixer_hw->type == MDSS_MDP_MIXER_TYPE_WRITEBACK)
|
||||
ctl->flush_bits |= BIT(9) << mixer_hw->num;
|
||||
ctl_hw->flush_bits |= BIT(9) << mixer_hw->num;
|
||||
else
|
||||
ctl->flush_bits |= BIT(6) << mixer_hw->num;
|
||||
ctl_hw->flush_bits |= BIT(6) << mixer_hw->num;
|
||||
|
||||
/* Read GC enable/disable status on LM */
|
||||
mixer_op_mode |=
|
||||
|
@ -4036,10 +4290,10 @@ update_mixer:
|
|||
mdata->bcolor2 & 0xFFF);
|
||||
|
||||
off = __mdss_mdp_ctl_get_mixer_off(mixer_hw);
|
||||
mdss_mdp_ctl_write(ctl, off, mixercfg);
|
||||
mdss_mdp_ctl_write(ctl_hw, off, mixercfg);
|
||||
/* Program ctl layer extension bits */
|
||||
mdss_mdp_ctl_write(ctl, off + MDSS_MDP_REG_CTL_LAYER_EXTN_OFFSET,
|
||||
mixercfg_extn);
|
||||
off = __mdss_mdp_ctl_get_mixer_extn_off(mixer_hw);
|
||||
mdss_mdp_ctl_write(ctl_hw, off, mixercfg_extn);
|
||||
|
||||
pr_debug("mixer=%d hw=%d cfg=0%08x cfg_extn=0x%08x op_mode=0x%08x w=%d h=%d bc0=0x%x bc1=0x%x\n",
|
||||
mixer->num, mixer_hw->num, mixercfg, mixercfg_extn,
|
||||
|
@ -5014,33 +5268,6 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_mixer_switch(struct mdss_mdp_ctl *ctl,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline int __mdss_mdp_ctl_get_mixer_off(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
|
||||
if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3)
|
||||
return MDSS_MDP_CTL_X_LAYER_5;
|
||||
else
|
||||
return MDSS_MDP_REG_CTL_LAYER(mixer->num);
|
||||
} else {
|
||||
return MDSS_MDP_REG_CTL_LAYER(mixer->num +
|
||||
MDSS_MDP_INTF_LAYERMIXER3);
|
||||
}
|
||||
}
|
||||
|
||||
u32 mdss_mdp_get_mixercfg(struct mdss_mdp_mixer *mixer, bool extn)
|
||||
{
|
||||
u32 mixer_off;
|
||||
|
||||
if (!mixer || !mixer->ctl)
|
||||
return 0;
|
||||
|
||||
mixer_off = __mdss_mdp_ctl_get_mixer_off(mixer);
|
||||
mixer_off = extn ? (mixer_off + MDSS_MDP_REG_CTL_LAYER_EXTN_OFFSET) :
|
||||
mixer_off;
|
||||
|
||||
return mdss_mdp_ctl_read(mixer->ctl, mixer_off);
|
||||
}
|
||||
|
||||
static int __mdss_mdp_mixer_handoff_helper(struct mdss_mdp_mixer *mixer,
|
||||
struct mdss_mdp_pipe *pipe)
|
||||
{
|
||||
|
|
|
@ -134,6 +134,8 @@ enum mdss_mdp_ctl_index {
|
|||
|
||||
#define MDSS_MDP_REG_CTL_LAYER(lm) \
|
||||
((lm == 5) ? (0x024) : ((lm) * 0x004))
|
||||
#define MDSS_MDP_REG_CTL_LAYER_EXTN(lm) \
|
||||
((lm == 5) ? (0x54) : (MDSS_MDP_REG_CTL_LAYER(lm) + 0x40))
|
||||
#define MDSS_MDP_REG_CTL_TOP 0x014
|
||||
#define MDSS_MDP_REG_CTL_FLUSH 0x018
|
||||
#define MDSS_MDP_REG_CTL_START 0x01C
|
||||
|
|
|
@ -34,10 +34,18 @@ static DEFINE_MUTEX(cmd_clk_mtx);
|
|||
|
||||
struct mdss_mdp_cmd_ctx {
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
u32 pp_num;
|
||||
|
||||
bool right_only_update; /* set only if DUAL_LM_SINGLE_DISPLAY + PU */
|
||||
u32 right_only_pp_num; /* used only if DUAL_LM_SINGLE_DISPLAY + PU */
|
||||
u32 default_pp_num;
|
||||
u32 current_pp_num;
|
||||
/*
|
||||
* aux_pp_num will be set only when topology is using split-lm.
|
||||
* aux_pp_num will be used only when MDSS_QUIRK_DSC_RIGHT_ONLY_PU
|
||||
* quirk is set and on following partial updates.
|
||||
*
|
||||
* right-only update on DUAL_LM_SINGLE_DISPLAY with DSC_MERGE
|
||||
* right-only update on DUAL_LM_DUAL_DISPLAY with DSC
|
||||
*/
|
||||
u32 aux_pp_num;
|
||||
|
||||
u8 ref_cnt;
|
||||
struct completion stop_comp;
|
||||
|
@ -77,6 +85,19 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx);
|
|||
static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx);
|
||||
static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg);
|
||||
|
||||
static bool __mdss_mdp_cmd_is_aux_pp_needed(struct mdss_data_type *mdata,
|
||||
struct mdss_mdp_ctl *mctl)
|
||||
{
|
||||
return (mdata && mctl && mctl->is_master &&
|
||||
mdss_has_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU) &&
|
||||
is_dsc_compression(&mctl->panel_data->panel_info) &&
|
||||
((mctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) ||
|
||||
((mctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) &&
|
||||
(mctl->panel_data->panel_info.dsc_enc_total == 1))) &&
|
||||
!mctl->mixer_left->valid_roi &&
|
||||
mctl->mixer_right->valid_roi);
|
||||
}
|
||||
|
||||
static bool __mdss_mdp_cmd_is_panel_power_off(struct mdss_mdp_cmd_ctx *ctx)
|
||||
{
|
||||
return mdss_panel_is_power_off(ctx->panel_power_state);
|
||||
|
@ -822,10 +843,11 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx)
|
|||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
||||
pr_debug("%pS-->%s: task:%s ctx%d\n", __builtin_return_address(0),
|
||||
__func__, current->group_leader->comm, ctx->pp_num);
|
||||
__func__, current->group_leader->comm, ctx->current_pp_num);
|
||||
|
||||
mutex_lock(&ctx->clk_mtx);
|
||||
MDSS_XLOG(ctx->pp_num, atomic_read(&ctx->koff_cnt), mdata->bus_ref_cnt);
|
||||
MDSS_XLOG(ctx->current_pp_num, atomic_read(&ctx->koff_cnt),
|
||||
mdata->bus_ref_cnt);
|
||||
|
||||
mdss_bus_bandwidth_ctrl(true);
|
||||
|
||||
|
@ -845,10 +867,11 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx)
|
|||
}
|
||||
|
||||
pr_debug("%pS-->%s: task:%s ctx%d\n", __builtin_return_address(0),
|
||||
__func__, current->group_leader->comm, ctx->pp_num);
|
||||
__func__, current->group_leader->comm, ctx->current_pp_num);
|
||||
|
||||
mutex_lock(&ctx->clk_mtx);
|
||||
MDSS_XLOG(ctx->pp_num, atomic_read(&ctx->koff_cnt), mdata->bus_ref_cnt);
|
||||
MDSS_XLOG(ctx->current_pp_num, atomic_read(&ctx->koff_cnt),
|
||||
mdata->bus_ref_cnt);
|
||||
|
||||
mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND);
|
||||
|
||||
|
@ -938,13 +961,9 @@ static void mdss_mdp_cmd_intf_recovery(void *data, int event)
|
|||
|
||||
spin_lock_irqsave(&ctx->koff_lock, flags);
|
||||
if (reset_done && atomic_add_unless(&ctx->koff_cnt, -1, 0)) {
|
||||
u32 pp_num = ctx->right_only_update ? ctx->right_only_pp_num :
|
||||
ctx->pp_num;
|
||||
|
||||
pr_debug("%s: intf_num=%d\n", __func__, ctx->ctl->intf_num);
|
||||
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
pp_num);
|
||||
|
||||
ctx->current_pp_num);
|
||||
if (mdss_mdp_cmd_do_notifier(ctx))
|
||||
notify_frame_timeout = true;
|
||||
}
|
||||
|
@ -961,7 +980,6 @@ static void mdss_mdp_cmd_pingpong_done(void *arg)
|
|||
struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX];
|
||||
struct mdss_mdp_vsync_handler *tmp;
|
||||
ktime_t vsync_time;
|
||||
u32 pp_num;
|
||||
|
||||
if (!ctx) {
|
||||
pr_err("%s: invalid ctx\n", __func__);
|
||||
|
@ -980,11 +998,12 @@ static void mdss_mdp_cmd_pingpong_done(void *arg)
|
|||
|
||||
spin_lock(&ctx->koff_lock);
|
||||
|
||||
pp_num = ctx->right_only_update ? ctx->right_only_pp_num :
|
||||
ctx->pp_num;
|
||||
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, pp_num);
|
||||
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
ctx->current_pp_num);
|
||||
mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
ctx->current_pp_num, NULL, NULL);
|
||||
|
||||
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), pp_num);
|
||||
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), ctx->current_pp_num);
|
||||
|
||||
if (atomic_add_unless(&ctx->koff_cnt, -1, 0)) {
|
||||
if (atomic_read(&ctx->koff_cnt))
|
||||
|
@ -1003,10 +1022,11 @@ static void mdss_mdp_cmd_pingpong_done(void *arg)
|
|||
}
|
||||
|
||||
pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d cnt=%d\n", __func__,
|
||||
ctl->num, ctl->intf_num, pp_num,
|
||||
ctl->num, ctl->intf_num, ctx->current_pp_num,
|
||||
atomic_read(&ctx->koff_cnt));
|
||||
|
||||
trace_mdp_cmd_pingpong_done(ctl, pp_num, atomic_read(&ctx->koff_cnt));
|
||||
trace_mdp_cmd_pingpong_done(ctl, ctx->current_pp_num,
|
||||
atomic_read(&ctx->koff_cnt));
|
||||
|
||||
spin_unlock(&ctx->koff_lock);
|
||||
}
|
||||
|
@ -1277,24 +1297,25 @@ static int mdss_mdp_setup_vsync(struct mdss_mdp_cmd_ctx *ctx,
|
|||
pr_debug("%pS->%s: vsync_cnt=%d changed=%d enable=%d ctl:%d pp:%d\n",
|
||||
__builtin_return_address(0), __func__,
|
||||
ctx->vsync_irq_cnt, changed, enable,
|
||||
ctx->ctl->num, ctx->pp_num);
|
||||
ctx->ctl->num, ctx->default_pp_num);
|
||||
|
||||
if (changed) {
|
||||
if (enable) {
|
||||
/* enable clocks and irq */
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
|
||||
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
|
||||
ctx->pp_num);
|
||||
ctx->default_pp_num);
|
||||
} else {
|
||||
/* disable clocks and irq */
|
||||
mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
|
||||
ctx->pp_num);
|
||||
ctx->default_pp_num);
|
||||
/*
|
||||
* check the intr status and clear the irq before
|
||||
* disabling the clocks
|
||||
*/
|
||||
mdss_mdp_intr_check_and_clear(
|
||||
MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num);
|
||||
MDSS_MDP_IRQ_PING_PONG_RD_PTR,
|
||||
ctx->default_pp_num);
|
||||
|
||||
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
|
||||
}
|
||||
|
@ -1457,19 +1478,16 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
atomic_read(&ctx->koff_cnt));
|
||||
|
||||
if (rc <= 0) {
|
||||
u32 status, mask, pp_num;
|
||||
u32 status, mask;
|
||||
|
||||
pp_num = ctx->right_only_update ?
|
||||
ctx->right_only_pp_num : ctx->pp_num;
|
||||
|
||||
mask = BIT(MDSS_MDP_IRQ_PING_PONG_COMP + pp_num);
|
||||
mask = BIT(MDSS_MDP_IRQ_PING_PONG_COMP + ctx->current_pp_num);
|
||||
status = mask & readl_relaxed(ctl->mdata->mdp_base +
|
||||
MDSS_MDP_REG_INTR_STATUS);
|
||||
|
||||
if (status) {
|
||||
pr_warn("pp done but irq not triggered\n");
|
||||
mdss_mdp_irq_clear(ctl->mdata,
|
||||
MDSS_MDP_IRQ_PING_PONG_COMP, pp_num);
|
||||
MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
ctx->current_pp_num);
|
||||
local_irq_save(flags);
|
||||
mdss_mdp_cmd_pingpong_done(ctl);
|
||||
local_irq_restore(flags);
|
||||
|
@ -1556,8 +1574,7 @@ static void mdss_mdp_cmd_set_sync_ctx(
|
|||
/* only master ctl is valid and pingpong split with DSC is pending */
|
||||
static void mdss_mdp_cmd_dsc_reconfig(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
struct mdss_panel_info *pinfo, *spinfo;
|
||||
struct mdss_mdp_ctl *sctl = NULL;
|
||||
struct mdss_panel_info *pinfo;
|
||||
bool changed = false;
|
||||
|
||||
if (!ctl || !ctl->is_master)
|
||||
|
@ -1567,19 +1584,12 @@ static void mdss_mdp_cmd_dsc_reconfig(struct mdss_mdp_ctl *ctl)
|
|||
if (pinfo->compression_mode != COMPRESSION_DSC)
|
||||
return;
|
||||
|
||||
sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
|
||||
changed = ctl->mixer_left->roi_changed;
|
||||
if (is_dual_lm_single_display(ctl->mfd))
|
||||
if (is_split_lm(ctl->mfd))
|
||||
changed |= ctl->mixer_right->roi_changed;
|
||||
|
||||
if (changed)
|
||||
mdss_mdp_ctl_dsc_setup(ctl, pinfo);
|
||||
|
||||
if (sctl && sctl->mixer_left->roi_changed) {
|
||||
spinfo = &sctl->panel_data->panel_info;
|
||||
mdss_mdp_ctl_dsc_setup(sctl, spinfo);
|
||||
}
|
||||
}
|
||||
|
||||
static int mdss_mdp_cmd_set_partial_roi(struct mdss_mdp_ctl *ctl)
|
||||
|
@ -1772,11 +1782,10 @@ static int mdss_mdp_cmd_enable_cmd_autorefresh(struct mdss_mdp_ctl *ctl,
|
|||
* for left+right case, pingpong_done is enabled for both and
|
||||
* only the last pingpong_done should trigger the notification
|
||||
*/
|
||||
int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
||||
static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
||||
{
|
||||
struct mdss_mdp_ctl *sctl = NULL;
|
||||
struct mdss_mdp_ctl *sctl = NULL, *mctl = ctl;
|
||||
struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL;
|
||||
u32 pp_num;
|
||||
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
|
||||
|
||||
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
|
||||
|
@ -1786,19 +1795,21 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
}
|
||||
|
||||
if (ctx->intf_stopped) {
|
||||
pr_err("ctx=%d stopped already\n", ctx->pp_num);
|
||||
pr_err("ctx=%d stopped already\n", ctx->current_pp_num);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
reinit_completion(&ctx->readptr_done);
|
||||
/* sctl will be null for right only in the case of Partial update */
|
||||
sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
|
||||
if (sctl && (sctl->roi.w == 0 || sctl->roi.h == 0)) {
|
||||
/* left update only */
|
||||
sctl = NULL;
|
||||
if (!ctl->is_master) {
|
||||
mctl = mdss_mdp_get_main_ctl(ctl);
|
||||
} else {
|
||||
sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
if (sctl && (sctl->roi.w == 0 || sctl->roi.h == 0)) {
|
||||
/* left update only */
|
||||
sctl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
reinit_completion(&ctx->readptr_done);
|
||||
mdss_mdp_ctl_perf_set_transaction_status(ctl,
|
||||
PERF_HW_MDP_STATE, PERF_STATUS_BUSY);
|
||||
|
||||
|
@ -1816,17 +1827,14 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
if (__mdss_mdp_cmd_is_panel_power_off(ctx))
|
||||
mdss_mdp_cmd_panel_on(ctl, sctl);
|
||||
|
||||
pp_num = ctx->pp_num;
|
||||
if (is_dual_lm_single_display(ctl->mfd) &&
|
||||
!ctl->mixer_left->valid_roi &&
|
||||
!mdss_mdp_is_lm_swap_needed(mdata, ctl)) {
|
||||
ctx->right_only_update = true;
|
||||
pp_num = ctx->right_only_pp_num;
|
||||
} else {
|
||||
ctx->right_only_update = false;
|
||||
}
|
||||
ctx->current_pp_num = ctx->default_pp_num;
|
||||
if (sctx)
|
||||
sctx->current_pp_num = sctx->default_pp_num;
|
||||
|
||||
MDSS_XLOG(ctl->num, pp_num,
|
||||
if (__mdss_mdp_cmd_is_aux_pp_needed(mdata, mctl))
|
||||
ctx->current_pp_num = ctx->aux_pp_num;
|
||||
|
||||
MDSS_XLOG(ctl->num, ctx->current_pp_num,
|
||||
ctl->roi.x, ctl->roi.y, ctl->roi.w, ctl->roi.h);
|
||||
|
||||
atomic_inc(&ctx->koff_cnt);
|
||||
|
@ -1843,7 +1851,9 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
*/
|
||||
mdss_mdp_resource_control(ctl, MDP_RSRC_CTL_EVENT_KICKOFF);
|
||||
|
||||
mdss_mdp_cmd_dsc_reconfig(ctl);
|
||||
if (!ctl->is_master)
|
||||
mctl = mdss_mdp_get_main_ctl(ctl);
|
||||
mdss_mdp_cmd_dsc_reconfig(mctl);
|
||||
|
||||
mdss_mdp_cmd_set_partial_roi(ctl);
|
||||
|
||||
|
@ -1870,9 +1880,15 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
wait_for_completion(&ctx->readptr_done);
|
||||
}
|
||||
|
||||
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, pp_num);
|
||||
if (sctx)
|
||||
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, sctx->pp_num);
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
ctx->current_pp_num, mdss_mdp_cmd_pingpong_done, ctl);
|
||||
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->current_pp_num);
|
||||
if (sctx) {
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
sctx->current_pp_num, mdss_mdp_cmd_pingpong_done, sctl);
|
||||
mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
sctx->current_pp_num);
|
||||
}
|
||||
|
||||
if (!ctx->autorefresh_pending_frame_cnt && !ctl->cmd_autorefresh_en) {
|
||||
/* Kickoff */
|
||||
|
@ -1892,7 +1908,8 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
}
|
||||
|
||||
mb();
|
||||
MDSS_XLOG(ctl->num, pp_num, atomic_read(&ctx->koff_cnt));
|
||||
MDSS_XLOG(ctl->num, ctx->current_pp_num,
|
||||
sctx ? sctx->current_pp_num : -1, atomic_read(&ctx->koff_cnt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1918,11 +1935,11 @@ int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl, bool locked)
|
|||
|
||||
if (mdss_mdp_cmd_tearcheck_setup(ctx, locked)) {
|
||||
pr_warn("%s: ctx%d tearcheck setup failed\n", __func__,
|
||||
ctx->pp_num);
|
||||
ctx->current_pp_num);
|
||||
} else {
|
||||
if (sctx && mdss_mdp_cmd_tearcheck_setup(sctx, locked))
|
||||
pr_warn("%s: ctx%d tearcheck setup failed\n", __func__,
|
||||
sctx->pp_num);
|
||||
sctx->current_pp_num);
|
||||
else
|
||||
mdss_mdp_tearcheck_enable(ctl, true);
|
||||
}
|
||||
|
@ -1974,19 +1991,7 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl,
|
|||
}
|
||||
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
|
||||
ctx->pp_num, NULL, NULL);
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
ctx->pp_num, NULL, NULL);
|
||||
|
||||
/*
|
||||
* In case of DUAL_LM_SINGLE_DISPLAY, right PP is always enabled
|
||||
* if partial update is enabled. So disable interrupt callback
|
||||
* when not needed.
|
||||
*/
|
||||
if (ctl->panel_data->panel_info.partial_update_enabled &&
|
||||
is_dual_lm_single_display(ctl->mfd))
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
ctx->right_only_pp_num, NULL, NULL);
|
||||
ctx->default_pp_num, NULL, NULL);
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
|
@ -2268,13 +2273,14 @@ static int mdss_mdp_cmd_early_wake_up(struct mdss_mdp_ctl *ctl)
|
|||
}
|
||||
|
||||
static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
|
||||
struct mdss_mdp_cmd_ctx *ctx, int pp_num,
|
||||
struct mdss_mdp_cmd_ctx *ctx, int default_pp_num, int aux_pp_num,
|
||||
bool pingpong_split_slave)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ctx->ctl = ctl;
|
||||
ctx->pp_num = pp_num;
|
||||
ctx->default_pp_num = default_pp_num;
|
||||
ctx->aux_pp_num = aux_pp_num;
|
||||
ctx->pingpong_split_slave = pingpong_split_slave;
|
||||
ctx->pp_timeout_report_cnt = 0;
|
||||
init_waitqueue_head(&ctx->pp_waitq);
|
||||
|
@ -2301,32 +2307,12 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
|
|||
|
||||
ctx->intf_stopped = 0;
|
||||
|
||||
pr_debug("%s: ctx=%p num=%d\n", __func__, ctx, ctx->pp_num);
|
||||
pr_debug("%s: ctx=%p num=%d aux=%d\n", __func__, ctx,
|
||||
default_pp_num, aux_pp_num);
|
||||
MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt));
|
||||
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR,
|
||||
ctx->pp_num, mdss_mdp_cmd_readptr_done, ctl);
|
||||
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
|
||||
mdss_mdp_cmd_pingpong_done, ctl);
|
||||
|
||||
/*
|
||||
* In case of DUAL_LM_SINGLE_DISPLAY with partial update enabled, right
|
||||
* PP is used when right-only update is committed. For such use-case,
|
||||
* separate corresponding interrupt callback needs to be registered.
|
||||
*/
|
||||
if (ctl->panel_data->panel_info.partial_update_enabled &&
|
||||
is_dual_lm_single_display(ctl->mfd)) {
|
||||
|
||||
ctx->right_only_pp_num = ctl->mixer_right->num;
|
||||
|
||||
pr_debug("%s: left_pp=%d right_pp=%d\n", __func__,
|
||||
ctx->pp_num, ctx->right_only_pp_num);
|
||||
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP,
|
||||
ctx->right_only_pp_num,
|
||||
mdss_mdp_cmd_pingpong_done, ctl);
|
||||
}
|
||||
ctx->default_pp_num, mdss_mdp_cmd_readptr_done, ctl);
|
||||
|
||||
ret = mdss_mdp_cmd_tearcheck_setup(ctx, false);
|
||||
if (ret)
|
||||
|
@ -2342,6 +2328,7 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
struct mdss_mdp_ctl *sctl = NULL;
|
||||
struct mdss_mdp_mixer *mixer;
|
||||
int ret;
|
||||
u32 default_pp_num, aux_pp_num;
|
||||
|
||||
if (session >= MAX_SESSIONS)
|
||||
return 0;
|
||||
|
@ -2372,23 +2359,59 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
}
|
||||
}
|
||||
ctx->ref_cnt++;
|
||||
ctl->intf_ctx[MASTER_CTX] = ctx;
|
||||
|
||||
|
||||
mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
|
||||
if (!mixer) {
|
||||
pr_err("mixer not setup correctly\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
default_pp_num = mixer->num;
|
||||
|
||||
ctl->intf_ctx[MASTER_CTX] = ctx;
|
||||
if (is_split_lm(ctl->mfd)) {
|
||||
if (is_dual_lm_single_display(ctl->mfd)) {
|
||||
mixer = mdss_mdp_mixer_get(ctl,
|
||||
MDSS_MDP_MIXER_MUX_RIGHT);
|
||||
if (!mixer) {
|
||||
pr_err("right mixer not setup correctly for dual_lm_single_display\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
aux_pp_num = mixer->num;
|
||||
} else { /* DUAL_LM_DUAL_DISPLAY */
|
||||
struct mdss_mdp_ctl *mctl = ctl;
|
||||
|
||||
/*
|
||||
* pp_num for master ctx is same as mixer num independent
|
||||
* of pingpong split enabled/disabled
|
||||
*/
|
||||
ret = mdss_mdp_cmd_ctx_setup(ctl, ctx, mixer->num, false);
|
||||
if (!mctl->is_master) {
|
||||
mctl = mdss_mdp_get_main_ctl(ctl);
|
||||
if (!mctl) {
|
||||
pr_err("%s master ctl cannot be NULL\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctl->is_master) /* setup is called for master */
|
||||
mixer = mdss_mdp_mixer_get(mctl,
|
||||
MDSS_MDP_MIXER_MUX_RIGHT);
|
||||
else
|
||||
mixer = mdss_mdp_mixer_get(mctl,
|
||||
MDSS_MDP_MIXER_MUX_LEFT);
|
||||
|
||||
if (!mixer) {
|
||||
pr_err("right mixer not setup correctly for dual_lm_dual_display\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
aux_pp_num = mixer->num;
|
||||
}
|
||||
} else {
|
||||
aux_pp_num = default_pp_num;
|
||||
}
|
||||
|
||||
ret = mdss_mdp_cmd_ctx_setup(ctl, ctx,
|
||||
default_pp_num, aux_pp_num, false);
|
||||
if (ret) {
|
||||
pr_err("mdss_mdp_cmd_ctx_setup failed for ping ping: %d\n",
|
||||
mixer->num);
|
||||
pr_err("mdss_mdp_cmd_ctx_setup failed for default_pp:%d aux_pp:%d\n",
|
||||
default_pp_num, aux_pp_num);
|
||||
ctx->ref_cnt--;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -2415,7 +2438,7 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
|
||||
ctl->intf_ctx[SLAVE_CTX] = ctx;
|
||||
|
||||
ret = mdss_mdp_cmd_ctx_setup(ctl, ctx, session, true);
|
||||
ret = mdss_mdp_cmd_ctx_setup(ctl, ctx, session, session, true);
|
||||
if (ret) {
|
||||
pr_err("mdss_mdp_cmd_ctx_setup failed for slave ping pong block");
|
||||
ctx->ref_cnt--;
|
||||
|
@ -2427,6 +2450,7 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
|
||||
void mdss_mdp_switch_roi_reset(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
struct mdss_mdp_ctl *mctl = ctl;
|
||||
struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
|
||||
|
||||
if (!ctl->panel_data ||
|
||||
|
@ -2437,7 +2461,9 @@ void mdss_mdp_switch_roi_reset(struct mdss_mdp_ctl *ctl)
|
|||
if (sctl && sctl->panel_data)
|
||||
sctl->panel_data->panel_info.roi = sctl->roi;
|
||||
|
||||
mdss_mdp_cmd_dsc_reconfig(ctl);
|
||||
if (!ctl->is_master)
|
||||
mctl = mdss_mdp_get_main_ctl(ctl);
|
||||
mdss_mdp_cmd_dsc_reconfig(mctl);
|
||||
|
||||
mdss_mdp_cmd_set_partial_roi(ctl);
|
||||
}
|
||||
|
|
|
@ -113,6 +113,26 @@ int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_set_intr_callback_nosync(u32 intr_type, u32 intf_num,
|
||||
void (*fnc_ptr)(void *), void *arg)
|
||||
{
|
||||
int index;
|
||||
|
||||
index = mdss_mdp_intr2index(intr_type, intf_num);
|
||||
if (index < 0) {
|
||||
pr_warn("invalid intr type=%u intf_num=%u\n",
|
||||
intr_type, intf_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WARN(mdp_intr_cb[index].func && fnc_ptr,
|
||||
"replacing current intr callback for ndx=%d\n", index);
|
||||
mdp_intr_cb[index].func = fnc_ptr;
|
||||
mdp_intr_cb[index].arg = arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mdss_mdp_intr_done(int index)
|
||||
{
|
||||
void (*fnc)(void *);
|
||||
|
|
|
@ -23,6 +23,20 @@
|
|||
|
||||
#define NUM_INTF 2
|
||||
|
||||
/*
|
||||
* rc_buf_thresh = {896, 1792, 2688, 3548, 4480, 5376, 6272, 6720,
|
||||
* 7168, 7616, 7744, 7872, 8000, 8064, 8192};
|
||||
* (x >> 6) & 0x0ff)
|
||||
*/
|
||||
static u32 dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54,
|
||||
0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e};
|
||||
static char dsc_rc_range_min_qp[] = {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5,
|
||||
5, 5, 7, 13};
|
||||
static char dsc_rc_range_max_qp[] = {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11,
|
||||
12, 13, 13, 15};
|
||||
static char dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8,
|
||||
-8, -10, -10, -12, -12, -12, -12};
|
||||
|
||||
int mdss_panel_debugfs_fbc_setup(struct mdss_panel_debugfs_info *debugfs_info,
|
||||
struct mdss_panel_info *panel_info, struct dentry *parent)
|
||||
{
|
||||
|
@ -631,5 +645,325 @@ void mdss_panel_info_from_timing(struct mdss_panel_timing *pt,
|
|||
/* override te parameters if panel is in sw te mode */
|
||||
if (pinfo->sim_panel_mode == SIM_SW_TE_MODE)
|
||||
mdss_panel_override_te_params(pinfo);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* All the calculations done by this routine only depend on slice_width
|
||||
* and slice_height. They are independent of picture dimesion and dsc_merge.
|
||||
* Thus this function should be called only when slice dimension changes.
|
||||
* Since currently we don't support dynamic slice dimension changes, this
|
||||
* routine shall be called only during probe.
|
||||
*/
|
||||
void mdss_panel_dsc_parameters_calc(struct dsc_desc *dsc)
|
||||
{
|
||||
int bpp, bpc;
|
||||
int mux_words_size;
|
||||
int groups_per_line, groups_total;
|
||||
int min_rate_buffer_size;
|
||||
int hrd_delay;
|
||||
int pre_num_extra_mux_bits, num_extra_mux_bits;
|
||||
int slice_bits;
|
||||
int target_bpp_x16;
|
||||
int data;
|
||||
int final_value, final_scale;
|
||||
|
||||
dsc->rc_model_size = 8192; /* rate_buffer_size */
|
||||
dsc->first_line_bpg_offset = 12;
|
||||
dsc->min_qp_flatness = 3;
|
||||
dsc->max_qp_flatness = 12;
|
||||
dsc->line_buf_depth = 9;
|
||||
|
||||
dsc->edge_factor = 6;
|
||||
dsc->quant_incr_limit0 = 11;
|
||||
dsc->quant_incr_limit1 = 11;
|
||||
dsc->tgt_offset_hi = 3;
|
||||
dsc->tgt_offset_lo = 3;
|
||||
|
||||
dsc->buf_thresh = dsc_rc_buf_thresh;
|
||||
dsc->range_min_qp = dsc_rc_range_min_qp;
|
||||
dsc->range_max_qp = dsc_rc_range_max_qp;
|
||||
dsc->range_bpg_offset = dsc_rc_range_bpg_offset;
|
||||
|
||||
bpp = dsc->bpp;
|
||||
bpc = dsc->bpc;
|
||||
|
||||
if (bpp == 8)
|
||||
dsc->initial_offset = 6144;
|
||||
else
|
||||
dsc->initial_offset = 2048; /* bpp = 12 */
|
||||
|
||||
if (bpc == 8)
|
||||
mux_words_size = 48;
|
||||
else
|
||||
mux_words_size = 64; /* bpc == 12 */
|
||||
|
||||
dsc->slice_last_group_size = 3 - (dsc->slice_width % 3);
|
||||
|
||||
dsc->det_thresh_flatness = 7 + 2*(bpc - 8);
|
||||
|
||||
dsc->initial_xmit_delay = dsc->rc_model_size / (2 * bpp);
|
||||
|
||||
groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3);
|
||||
|
||||
dsc->chunk_size = dsc->slice_width * bpp / 8;
|
||||
if ((dsc->slice_width * bpp) % 8)
|
||||
dsc->chunk_size++;
|
||||
|
||||
/* rbs-min */
|
||||
min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset +
|
||||
dsc->initial_xmit_delay * bpp +
|
||||
groups_per_line * dsc->first_line_bpg_offset;
|
||||
|
||||
hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp);
|
||||
|
||||
dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay;
|
||||
|
||||
dsc->initial_scale_value = 8 * dsc->rc_model_size /
|
||||
(dsc->rc_model_size - dsc->initial_offset);
|
||||
|
||||
slice_bits = 8 * dsc->chunk_size * dsc->slice_height;
|
||||
|
||||
groups_total = groups_per_line * dsc->slice_height;
|
||||
|
||||
data = dsc->first_line_bpg_offset * 2048;
|
||||
|
||||
dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1));
|
||||
|
||||
pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2);
|
||||
|
||||
num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size -
|
||||
((slice_bits - pre_num_extra_mux_bits) % mux_words_size));
|
||||
|
||||
data = 2048 * (dsc->rc_model_size - dsc->initial_offset
|
||||
+ num_extra_mux_bits);
|
||||
dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total);
|
||||
|
||||
/* bpp * 16 + 0.5 */
|
||||
data = bpp * 16;
|
||||
data *= 2;
|
||||
data++;
|
||||
data /= 2;
|
||||
target_bpp_x16 = data;
|
||||
|
||||
data = (dsc->initial_xmit_delay * target_bpp_x16) / 16;
|
||||
final_value = dsc->rc_model_size - data + num_extra_mux_bits;
|
||||
|
||||
final_scale = 8 * dsc->rc_model_size /
|
||||
(dsc->rc_model_size - final_value);
|
||||
|
||||
dsc->final_offset = final_value;
|
||||
|
||||
data = (final_scale - 9) * (dsc->nfl_bpg_offset +
|
||||
dsc->slice_bpg_offset);
|
||||
dsc->scale_increment_interval = (2048 * dsc->final_offset) / data;
|
||||
|
||||
dsc->scale_decrement_interval = groups_per_line /
|
||||
(dsc->initial_scale_value - 8);
|
||||
|
||||
pr_debug("initial_xmit_delay=%d\n", dsc->initial_xmit_delay);
|
||||
pr_debug("bpg_offset, nfl=%d slice=%d\n",
|
||||
dsc->nfl_bpg_offset, dsc->slice_bpg_offset);
|
||||
pr_debug("groups_per_line=%d chunk_size=%d\n",
|
||||
groups_per_line, dsc->chunk_size);
|
||||
pr_debug("min_rate_buffer_size=%d hrd_delay=%d\n",
|
||||
min_rate_buffer_size, hrd_delay);
|
||||
pr_debug("initial_dec_delay=%d initial_scale_value=%d\n",
|
||||
dsc->initial_dec_delay, dsc->initial_scale_value);
|
||||
pr_debug("slice_bits=%d, groups_total=%d\n", slice_bits, groups_total);
|
||||
pr_debug("first_line_bgp_offset=%d slice_height=%d\n",
|
||||
dsc->first_line_bpg_offset, dsc->slice_height);
|
||||
pr_debug("final_value=%d final_scale=%d\n", final_value, final_scale);
|
||||
pr_debug("sacle_increment_interval=%d scale_decrement_interval=%d\n",
|
||||
dsc->scale_increment_interval, dsc->scale_decrement_interval);
|
||||
}
|
||||
|
||||
void mdss_panel_dsc_update_pic_dim(struct dsc_desc *dsc,
|
||||
int pic_width, int pic_height)
|
||||
{
|
||||
if (!dsc || !pic_width || !pic_height) {
|
||||
pr_err("Error: invalid input. pic_width=%d pic_height=%d\n",
|
||||
pic_width, pic_height);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pic_width % dsc->slice_width) ||
|
||||
(pic_height % dsc->slice_height)) {
|
||||
pr_err("Error: pic_dim=%dx%d has to be multiple of slice_dim=%dx%d\n",
|
||||
pic_width, pic_height,
|
||||
dsc->slice_width, dsc->slice_height);
|
||||
return;
|
||||
}
|
||||
|
||||
dsc->pic_width = pic_width;
|
||||
dsc->pic_height = pic_height;
|
||||
}
|
||||
|
||||
void mdss_panel_dsc_initial_line_calc(struct dsc_desc *dsc, int enc_ip_width)
|
||||
{
|
||||
int ssm_delay, total_pixels, soft_slice_per_enc;
|
||||
|
||||
#define MAX_XMIT_DELAY 512
|
||||
if (!dsc || !enc_ip_width || !dsc->slice_width ||
|
||||
(enc_ip_width < dsc->slice_width) ||
|
||||
(dsc->initial_xmit_delay > MAX_XMIT_DELAY)) {
|
||||
pr_err("Error: invalid input\n");
|
||||
return;
|
||||
}
|
||||
#undef MAX_XMIT_DELAY
|
||||
|
||||
soft_slice_per_enc = enc_ip_width / dsc->slice_width;
|
||||
ssm_delay = ((dsc->bpc < 10) ? 84 : 92);
|
||||
total_pixels = ssm_delay * 3 + dsc->initial_xmit_delay + 47;
|
||||
if (soft_slice_per_enc > 1)
|
||||
total_pixels += (ssm_delay * 3);
|
||||
|
||||
dsc->initial_lines = DIV_ROUND_UP(total_pixels, dsc->slice_width);
|
||||
}
|
||||
|
||||
void mdss_panel_dsc_pclk_param_calc(struct dsc_desc *dsc, int intf_width)
|
||||
{
|
||||
int slice_per_pkt, slice_per_intf;
|
||||
int bytes_in_slice, total_bytes_per_intf;
|
||||
|
||||
if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt ||
|
||||
(intf_width < dsc->slice_width)) {
|
||||
pr_err("Error: invalid input. intf_width=%d slice_width=%d\n",
|
||||
intf_width,
|
||||
dsc ? dsc->slice_width : -1);
|
||||
return;
|
||||
}
|
||||
|
||||
slice_per_pkt = dsc->slice_per_pkt;
|
||||
slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width);
|
||||
|
||||
/*
|
||||
* If slice_per_pkt is greater than slice_per_intf then default to 1.
|
||||
* This can happen during partial update.
|
||||
*/
|
||||
if (slice_per_pkt > slice_per_intf)
|
||||
slice_per_pkt = 1;
|
||||
|
||||
bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8);
|
||||
total_bytes_per_intf = bytes_in_slice * slice_per_intf;
|
||||
|
||||
dsc->eol_byte_num = total_bytes_per_intf % 3;
|
||||
dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3);
|
||||
dsc->bytes_in_slice = bytes_in_slice;
|
||||
dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt;
|
||||
dsc->pkt_per_line = slice_per_intf / slice_per_pkt;
|
||||
|
||||
pr_debug("slice_per_pkt=%d slice_per_intf=%d bytes_in_slice=%d total_bytes_per_intf=%d\n",
|
||||
slice_per_pkt, slice_per_intf,
|
||||
bytes_in_slice, total_bytes_per_intf);
|
||||
}
|
||||
|
||||
int mdss_panel_dsc_prepare_pps_buf(struct dsc_desc *dsc, char *buf,
|
||||
int pps_id, int major, int minor)
|
||||
{
|
||||
char *bp;
|
||||
char data;
|
||||
int i, bpp;
|
||||
|
||||
bp = buf;
|
||||
*bp++ = ((major << 4) | minor); /* pps0 */
|
||||
*bp++ = pps_id; /* pps1 */
|
||||
bp++; /* pps2, reserved */
|
||||
|
||||
data = dsc->line_buf_depth & 0x0f;
|
||||
data |= (dsc->bpc << 4);
|
||||
*bp++ = data; /* pps3 */
|
||||
|
||||
bpp = dsc->bpp;
|
||||
bpp <<= 4; /* 4 fraction bits */
|
||||
data = (bpp >> 8);
|
||||
data &= 0x03; /* upper two bits */
|
||||
data |= (dsc->block_pred_enable << 5);
|
||||
data |= (dsc->convert_rgb << 4);
|
||||
data |= (dsc->enable_422 << 3);
|
||||
data |= (dsc->vbr_enable << 2);
|
||||
*bp++ = data; /* pps4 */
|
||||
*bp++ = bpp; /* pps5 */
|
||||
|
||||
*bp++ = (dsc->pic_height >> 8); /* pps6 */
|
||||
*bp++ = (dsc->pic_height & 0x0ff); /* pps7 */
|
||||
*bp++ = (dsc->pic_width >> 8); /* pps8 */
|
||||
*bp++ = (dsc->pic_width & 0x0ff); /* pps9 */
|
||||
|
||||
*bp++ = (dsc->slice_height >> 8); /* pps10 */
|
||||
*bp++ = (dsc->slice_height & 0x0ff); /* pps11 */
|
||||
*bp++ = (dsc->slice_width >> 8); /* pps12 */
|
||||
*bp++ = (dsc->slice_width & 0x0ff); /* pps13 */
|
||||
|
||||
*bp++ = (dsc->chunk_size >> 8); /* pps14 */
|
||||
*bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */
|
||||
|
||||
data = dsc->initial_xmit_delay >> 8;
|
||||
data &= 0x03;
|
||||
*bp++ = data; /* pps16, bit 0, 1 */
|
||||
*bp++ = dsc->initial_xmit_delay; /* pps17 */
|
||||
|
||||
*bp++ = (dsc->initial_dec_delay >> 8); /* pps18 */
|
||||
*bp++ = dsc->initial_dec_delay; /* pps19 */
|
||||
|
||||
bp++; /* pps20, reserved */
|
||||
|
||||
*bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */
|
||||
|
||||
data = (dsc->scale_increment_interval >> 8);
|
||||
data &= 0x0f;
|
||||
*bp++ = data; /* pps22 */
|
||||
*bp++ = dsc->scale_increment_interval; /* pps23 */
|
||||
|
||||
data = (dsc->scale_decrement_interval >> 8);
|
||||
data &= 0x0f;
|
||||
*bp++ = data; /* pps24 */
|
||||
*bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */
|
||||
|
||||
bp++; /* pps26, reserved */
|
||||
|
||||
*bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */
|
||||
|
||||
*bp++ = (dsc->nfl_bpg_offset >> 8); /* pps28 */
|
||||
*bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */
|
||||
*bp++ = (dsc->slice_bpg_offset >> 8); /* pps30 */
|
||||
*bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */
|
||||
|
||||
*bp++ = (dsc->initial_offset >> 8); /* pps32 */
|
||||
*bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */
|
||||
|
||||
*bp++ = (dsc->final_offset >> 8); /* pps34 */
|
||||
*bp++ = (dsc->final_offset & 0x0ff); /* pps35 */
|
||||
|
||||
*bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */
|
||||
*bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */
|
||||
|
||||
*bp++ = (dsc->rc_model_size >> 8); /* pps38 */
|
||||
*bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */
|
||||
|
||||
*bp++ = (dsc->edge_factor & 0x0f); /* pps40 */
|
||||
|
||||
*bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */
|
||||
*bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */
|
||||
|
||||
data = (dsc->tgt_offset_hi << 4);
|
||||
data |= (dsc->tgt_offset_lo & 0x0f);
|
||||
*bp++ = data; /* pps43 */
|
||||
|
||||
for (i = 0; i < 14; i++)
|
||||
*bp++ = dsc->buf_thresh[i]; /* pps44 - pps57 */
|
||||
|
||||
for (i = 0; i < 15; i++) { /* pps58 - pps87 */
|
||||
data = (dsc->range_min_qp[i] & 0x1f); /* 5 bits */
|
||||
data <<= 3;
|
||||
data |= ((dsc->range_max_qp[i] >> 2) & 0x07); /* 3 bits */
|
||||
*bp++ = data;
|
||||
data = (dsc->range_max_qp[i] & 0x03); /* 2 bits */
|
||||
data <<= 6;
|
||||
data |= (dsc->range_bpg_offset[i] & 0x3f); /* 6 bits */
|
||||
*bp++ = data;
|
||||
}
|
||||
|
||||
/* pps88 to pps127 are reserved */
|
||||
|
||||
return DSC_PPS_LEN; /* 128 */
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ struct panel_id {
|
|||
#define LVDS_PANEL 11 /* LVDS */
|
||||
#define EDP_PANEL 12 /* LVDS */
|
||||
|
||||
#define DSC_PPS_LEN 128
|
||||
|
||||
static inline const char *mdss_panel2str(u32 panel)
|
||||
{
|
||||
static const char const *names[] = {
|
||||
|
@ -427,10 +429,34 @@ enum {
|
|||
};
|
||||
|
||||
struct dsc_desc {
|
||||
/*
|
||||
* Following parameters can change per frame if partial update is on
|
||||
*/
|
||||
int pic_height;
|
||||
int pic_width;
|
||||
int initial_lines;
|
||||
|
||||
/*
|
||||
* Following parameters are used for DSI and not for MDP. They can
|
||||
* change per frame if partial update is enabled.
|
||||
*/
|
||||
int pkt_per_line;
|
||||
int bytes_in_slice;
|
||||
int bytes_per_pkt;
|
||||
int eol_byte_num;
|
||||
int pclk_per_line; /* width */
|
||||
|
||||
/*
|
||||
* Following parameters only changes when slice dimensions are changed.
|
||||
*/
|
||||
int full_frame_slices; /* denotes number of slice per intf */
|
||||
int slice_height;
|
||||
int slice_width;
|
||||
int chunk_size;
|
||||
|
||||
int slice_last_group_size;
|
||||
int bpp; /* target bit per pixel */
|
||||
int bpc; /* bit per component */
|
||||
int bpp; /* target bits per pixel */
|
||||
int bpc; /* uncompressed bits per component */
|
||||
int line_buf_depth;
|
||||
bool config_by_manufacture_cmd;
|
||||
bool block_pred_enable;
|
||||
|
@ -440,19 +466,6 @@ struct dsc_desc {
|
|||
int input_10_bits;
|
||||
int slice_per_pkt;
|
||||
|
||||
int pic_height;
|
||||
int pic_width;
|
||||
int slice_height;
|
||||
int slice_width;
|
||||
int chunk_size;
|
||||
int full_frame_slices; /* denotes number of slice in full frame */
|
||||
|
||||
int pkt_per_line;
|
||||
int bytes_in_slice;
|
||||
int bytes_per_pkt;
|
||||
int eol_byte_num;
|
||||
int pclk_per_line; /* width */
|
||||
|
||||
int initial_dec_delay;
|
||||
int initial_xmit_delay;
|
||||
|
||||
|
@ -911,6 +924,55 @@ int mdss_rect_cmp(struct mdss_rect *rect1, struct mdss_rect *rect2);
|
|||
*/
|
||||
void mdss_panel_override_te_params(struct mdss_panel_info *pinfo);
|
||||
|
||||
/**
|
||||
* mdss_panel_dsc_parameters_calc: calculate DSC parameters
|
||||
* @dsc: pointer to DSC structure associated with panel_info
|
||||
*/
|
||||
void mdss_panel_dsc_parameters_calc(struct dsc_desc *dsc);
|
||||
|
||||
/**
|
||||
* mdss_panel_dsc_update_pic_dim: update DSC structure with picture dimension
|
||||
* @dsc: pointer to DSC structure associated with panel_info
|
||||
* @pic_width: Picture width
|
||||
* @pic_height: Picture height
|
||||
*/
|
||||
void mdss_panel_dsc_update_pic_dim(struct dsc_desc *dsc,
|
||||
int pic_width, int pic_height);
|
||||
|
||||
/**
|
||||
* mdss_panel_dsc_initial_line_calc: update DSC initial line buffering
|
||||
* @dsc: pointer to DSC structure associated with panel_info
|
||||
* @enc_ip_width: uncompressed input width for DSC enc represented by @dsc
|
||||
* i.e.
|
||||
* * 720 for full frame single_display_dual_lm: 1440x2560
|
||||
* * 1080 for full frame dual_display_dual_lm: 2160x3840
|
||||
* * 360 for partial frame single_display_dual_lm: 360x2560
|
||||
*/
|
||||
void mdss_panel_dsc_initial_line_calc(struct dsc_desc *dsc, int enc_ip_width);
|
||||
|
||||
/**
|
||||
* mdss_panel_dsc_pclk_param_calc: calculate DSC params related to DSI
|
||||
* @dsc: pointer to DSC structure associated with panel_info
|
||||
* @intf_width: Uncompressed width per interface
|
||||
* i.e.
|
||||
* * 1440 for full frame single_display_dual_lm: 1440x2560
|
||||
* * 1080 for full frame dual_display_dual_lm: 2160x3840
|
||||
* * 720 for partial frame single_display_dual_lm: 720x2560
|
||||
*/
|
||||
void mdss_panel_dsc_pclk_param_calc(struct dsc_desc *dsc, int intf_width);
|
||||
|
||||
/**
|
||||
* mdss_panel_dsc_prepare_pps_buf - prepares Picture Parameter Set to be sent to panel
|
||||
* @dsc: pointer to DSC structure associated with panel_info
|
||||
* @buf: buffer that holds PPS
|
||||
* @pps_id: pps_identifier
|
||||
* @major: major version of the DSC encoder
|
||||
* @minot: minor version of the DSC encoder
|
||||
*
|
||||
* returns length of the PPS buffer.
|
||||
*/
|
||||
int mdss_panel_dsc_prepare_pps_buf(struct dsc_desc *dsc, char *buf,
|
||||
int pps_id, int major, int minor);
|
||||
#ifdef CONFIG_FB_MSM_MDSS
|
||||
int mdss_panel_debugfs_init(struct mdss_panel_info *panel_info,
|
||||
char const *panel_name);
|
||||
|
|
Loading…
Add table
Reference in a new issue