From 10996c18131ac7be0007c515005e6453b2844bbb Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Thu, 15 Aug 2019 17:05:07 -0700 Subject: [PATCH 01/10] disp: msm: add support for parsing VDC-m DTSI parameters Add support for parsing VDC-m DTSI parameters and also perform basic validation checks on those. Change-Id: I4b13cf04b1500c3c801c227658cb787bdad6174f Signed-off-by: Abhinav Kumar --- msm/dsi/dsi_defs.h | 10 ++- msm/dsi/dsi_panel.c | 191 ++++++++++++++++++++++++++++++++++++++++++++ msm/msm_drv.h | 47 +++++++++++ 3 files changed, 247 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index fe932e335623..cd0d2eb13d8f 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _DSI_DEFS_H_ @@ -402,7 +402,9 @@ struct dsi_panel_cmd_set { * panels in microseconds. * @dsi_transfer_time_us: Specifies dsi transfer time for command mode. * @dsc_enabled: DSC compression enabled. + * @vdc_enabled: VDC compression enabled. * @dsc: DSC compression configuration. + * @vdc: VDC compression configuration. * @roi_caps: Panel ROI capabilities. */ struct dsi_mode_info { @@ -425,7 +427,9 @@ struct dsi_mode_info { u32 mdp_transfer_time_us; u32 dsi_transfer_time_us; bool dsc_enabled; + bool vdc_enabled; struct msm_display_dsc_info *dsc; + struct msm_display_vdc_info *vdc; struct msm_roi_caps roi_caps; }; @@ -583,7 +587,9 @@ struct dsi_host_config { * @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time. * @topology: Topology selected for the panel * @dsc: DSC compression info + * @vdc: VDC compression info * @dsc_enabled: DSC compression enabled + * @vdc_enabled: VDC compression enabled * @roi_caps: Panel ROI capabilities */ struct dsi_display_mode_priv_info { @@ -602,7 +608,9 @@ struct dsi_display_mode_priv_info { struct msm_display_topology topology; struct msm_display_dsc_info dsc; + struct msm_display_vdc_info vdc; bool dsc_enabled; + bool vdc_enabled; struct msm_roi_caps roi_caps; }; diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 85a7e62b722a..93045e5c8ce8 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -2317,6 +2317,26 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, } priv_info->dsc.config.bits_per_pixel = data << 4; + rc = utils->read_u32(utils->data, "qcom,src-chroma-format", + &data); + if (rc) { + DSI_DEBUG("failed to parse qcom,src-chroma-format\n"); + rc = 0; + data = MSM_CHROMA_444; + } + + priv_info->dsc.chroma_format = data; + + rc = utils->read_u32(utils->data, "qcom,src-color-space", + &data); + if (rc) { + DSI_DEBUG("failed to parse qcom,src-color-space\n"); + rc = 0; + data = MSM_RGB; + } + + priv_info->dsc.source_color_space = data; + priv_info->dsc.config.block_pred_enable = utils->read_bool(utils->data, "qcom,mdss-dsc-block-prediction-enable"); @@ -2345,6 +2365,171 @@ error: return rc; } +static int dsi_panel_parse_vdc_params(struct dsi_display_mode *mode, + struct dsi_parser_utils *utils) +{ + u32 data; + int rc = -EINVAL; + const char *compression; + struct dsi_display_mode_priv_info *priv_info; + + if (!mode || !mode->priv_info) + return -EINVAL; + + priv_info = mode->priv_info; + + priv_info->vdc_enabled = false; + compression = utils->get_property(utils->data, + "qcom,compression-mode", NULL); + if (compression && !strcmp(compression, "vdc")) + priv_info->vdc_enabled = true; + + if (!priv_info->vdc_enabled) { + DSI_DEBUG("vdc compression is not enabled for the mode\n"); + return 0; + } + + rc = utils->read_u32(utils->data, "qcom,vdc-version", &data); + if (rc) { + priv_info->vdc.version_major = 0x1; + priv_info->vdc.version_minor = 0x1; + priv_info->vdc.version_release = 0x0; + rc = 0; + } else { + /* BITS[0..3] provides minor version and BITS[4..7] provide + * major version information + */ + priv_info->vdc.version_major = (data >> 4) & 0x0F; + priv_info->vdc.version_minor = data & 0x0F; + if ((priv_info->vdc.version_major != 0x1) && + ((priv_info->vdc.version_minor + != 0x1))) { + DSI_ERR("%s:unsupported major:%d minor:%d version\n", + __func__, + priv_info->vdc.version_major, + priv_info->vdc.version_minor + ); + rc = -EINVAL; + goto error; + } + } + + rc = utils->read_u32(utils->data, "qcom,vdc-version-release", &data); + if (rc) { + priv_info->vdc.version_release = 0x0; + rc = 0; + } else { + priv_info->vdc.version_release = data & 0xff; + /* only one release version is supported */ + if (priv_info->vdc.version_release != 0x0) { + DSI_ERR("unsupported vdc release version %d\n", + priv_info->vdc.version_release); + rc = -EINVAL; + goto error; + } + } + + DSI_INFO("vdc major: 0x%x minor : 0x%x release : 0x%x\n", + priv_info->vdc.version_major, + priv_info->vdc.version_minor, + priv_info->vdc.version_release); + + rc = utils->read_u32(utils->data, "qcom,vdc-slice-height", &data); + if (rc) { + DSI_ERR("failed to parse qcom,vdc-slice-height\n"); + goto error; + } + priv_info->vdc.slice_height = data; + + /* slice height should be atleast 16 lines */ + if (priv_info->vdc.slice_height < 16) { + DSI_ERR("invalid slice height %d\n", + priv_info->vdc.slice_height); + rc = -EINVAL; + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,vdc-slice-width", &data); + if (rc) { + DSI_ERR("failed to parse qcom,vdc-slice-width\n"); + goto error; + } + + priv_info->vdc.slice_width = data; + + /* + * slide-width should be multiple of 8 + * slice-width should be atlease 64 pixels + */ + if ((priv_info->vdc.slice_width & 7) || + (priv_info->vdc.slice_width < 64)) { + DSI_ERR("invalid slice width:%d\n", priv_info->vdc.slice_width); + rc = -EINVAL; + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,vdc-slice-per-pkt", &data); + if (rc) { + DSI_ERR("failed to parse qcom,vdc-slice-per-pkt\n"); + goto error; + } else if (!data || (data > 2)) { + DSI_ERR("invalid vdc slice-per-pkt:%d\n", data); + rc = -EINVAL; + goto error; + } + priv_info->vdc.slice_per_pkt = data; + + priv_info->vdc.frame_width = mode->timing.h_active; + priv_info->vdc.frame_height = mode->timing.v_active; + + rc = utils->read_u32(utils->data, "qcom,vdc-bit-per-component", + &data); + if (rc) { + DSI_ERR("failed to parse qcom,vdc-bit-per-component\n"); + goto error; + } + priv_info->vdc.bits_per_component = data; + + rc = utils->read_u32(utils->data, "qcom,mdss-pps-delay-ms", &data); + if (rc) { + DSI_DEBUG("pps-delay-ms not specified, defaulting to 0\n"); + data = 0; + } + priv_info->vdc.pps_delay_ms = data; + + rc = utils->read_u32(utils->data, "qcom,vdc-bit-per-pixel", + &data); + if (rc) { + DSI_ERR("failed to parse qcom,vdc-bit-per-pixel\n"); + goto error; + } + priv_info->vdc.bits_per_pixel = data << 4; + + rc = utils->read_u32(utils->data, "qcom,src-chroma-format", + &data); + if (rc) { + DSI_DEBUG("failed to parse qcom,src-chroma-format\n"); + rc = 0; + data = MSM_CHROMA_444; + } + priv_info->vdc.chroma_format = data; + + rc = utils->read_u32(utils->data, "qcom,src-color-space", + &data); + if (rc) { + DSI_DEBUG("failed to parse qcom,src-color-space\n"); + rc = 0; + data = MSM_RGB; + } + priv_info->vdc.source_color_space = data; + + mode->timing.vdc_enabled = true; + mode->timing.vdc = &priv_info->vdc; + +error: + return rc; +} + static int dsi_panel_parse_hdr_config(struct dsi_panel *panel) { int rc = 0; @@ -3423,6 +3608,12 @@ int dsi_panel_get_mode(struct dsi_panel *panel, goto parse_fail; } + rc = dsi_panel_parse_vdc_params(mode, utils); + if (rc) { + DSI_ERR("failed to parse vdc params, rc=%d\n", rc); + goto parse_fail; + } + rc = dsi_panel_parse_topology(prv_info, utils, topology_override); if (rc) { diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 06af73d5b518..14ec19871033 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -72,6 +72,13 @@ struct msm_gem_vma; #define MAX_BRIDGES 16 #define MAX_CONNECTORS 16 +#define MSM_RGB 0x0 +#define MSM_YUV 0x1 + +#define MSM_CHROMA_444 0x0 +#define MSM_CHROMA_422 0x1 +#define MSM_CHROMA_420 0x2 + #define TEARDOWN_DEADLOCK_RETRY_MAX 5 struct msm_file_private { @@ -322,6 +329,8 @@ struct msm_roi_caps { * @pclk_per_line: Compressed width. * @slice_last_group_size: Size of last group in pixels. * @slice_per_pkt: Number of slices per packet. + * @source_color_space: Source color space of DSC encoder + * @chroma_format: Chroma_format of DSC encoder. * @det_thresh_flatness: Flatness threshold. * @extra_width: Extra width required in timing calculations. * @pps_delay_ms: Post PPS command delay in milliseconds. @@ -338,12 +347,50 @@ struct msm_display_dsc_info { int pclk_per_line; int slice_last_group_size; int slice_per_pkt; + int source_color_space; + int chroma_format; int det_thresh_flatness; u32 extra_width; u32 pps_delay_ms; }; +/** + * struct msm_display_vdc_info - defines vdc configuration + * @version_major: major version number of VDC encoder. + * @version_minor: minor version number of VDC encoder. + * @source_color_space: source color space of VDC encoder + * @chroma_format: chroma_format of VDC encoder. + * @slice_height: slice height configuration of encoder. + * @slice_width: slice width configuration of encoder. + * @bytes_in_slice: number of bytes per slice . + * @slice_per_pkt: number of slices per packet. + * @bits_per_component: number of bits per component. + * @bits_per_pixel: number of bits per pixel. + * @frame_width: frame width configuration of encoder + * @frame_height: frame height configuration of encoder + * @pps_delay_ms: Post PPS command delay in milliseconds. + * @version_release: release version of VDC encoder. + */ +struct msm_display_vdc_info { + u8 version_major; + u8 version_minor; + u8 chroma_format; + u8 source_color_space; + + int slice_height; + int slice_width; + int bytes_in_slice; + int slice_per_pkt; + int bits_per_component; + int bits_per_pixel; + int frame_width; + int frame_height; + + u32 pps_delay_ms; + u32 version_release; +}; + /** * Bits/pixel target >> 4 (removing the fractional bits) * returns the integer bpp value from the drm_dsc_config struct From 497fe7758b4e7a0fdd60b75309763f571dbdfe70 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Thu, 15 Aug 2019 19:41:28 -0700 Subject: [PATCH 02/10] disp: msm: add VDC-m parameter calculation support Add support to calculate the parameters needed to configure the VDC-m encoder. These are also needed to configure the PPS command which shall be sent to the decoder. Change-Id: I36db93f7555aee34b5b893e389a7eb88d0e05f68 Signed-off-by: Abhinav Kumar --- msm/Makefile | 1 + msm/dsi/dsi_panel.c | 24 +- msm/msm_drv.h | 232 +++++++++++-- msm/sde_vdc_helper.c | 792 +++++++++++++++++++++++++++++++++++++++++++ msm/sde_vdc_helper.h | 49 +++ 5 files changed, 1077 insertions(+), 21 deletions(-) create mode 100644 msm/sde_vdc_helper.c create mode 100644 msm/sde_vdc_helper.h diff --git a/msm/Makefile b/msm/Makefile index 502575302fd6..dd8f77026878 100644 --- a/msm/Makefile +++ b/msm/Makefile @@ -74,6 +74,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_fence.o \ sde/sde_hw_qdss.o \ sde_dsc_helper.o \ + sde_vdc_helper.o \ msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ sde/sde_encoder_phys_wb.o \ diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 93045e5c8ce8..09f30b2decfb 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -14,6 +14,7 @@ #include "dsi_ctrl_hw.h" #include "dsi_parser.h" #include "sde_dsc_helper.h" +#include "sde_vdc_helper.h" /** * topology is currently defined by a set of following 3 values: @@ -2366,12 +2367,13 @@ error: } static int dsi_panel_parse_vdc_params(struct dsi_display_mode *mode, - struct dsi_parser_utils *utils) + struct dsi_parser_utils *utils, int traffic_mode, int panel_mode) { u32 data; int rc = -EINVAL; const char *compression; struct dsi_display_mode_priv_info *priv_info; + int intf_width; if (!mode || !mode->priv_info) return -EINVAL; @@ -2389,6 +2391,9 @@ static int dsi_panel_parse_vdc_params(struct dsi_display_mode *mode, return 0; } + priv_info->vdc.panel_mode = panel_mode; + priv_info->vdc.traffic_mode = traffic_mode; + rc = utils->read_u32(utils->data, "qcom,vdc-version", &data); if (rc) { priv_info->vdc.version_major = 0x1; @@ -2477,6 +2482,8 @@ static int dsi_panel_parse_vdc_params(struct dsi_display_mode *mode, rc = -EINVAL; goto error; } + + intf_width = mode->timing.h_active; priv_info->vdc.slice_per_pkt = data; priv_info->vdc.frame_width = mode->timing.h_active; @@ -2523,6 +2530,14 @@ static int dsi_panel_parse_vdc_params(struct dsi_display_mode *mode, } priv_info->vdc.source_color_space = data; + rc = sde_vdc_populate_config(&priv_info->vdc, + intf_width, traffic_mode); + if (rc) { + DSI_DEBUG("failed populating vdc config\n"); + rc = -EINVAL; + goto error; + } + mode->timing.vdc_enabled = true; mode->timing.vdc = &priv_info->vdc; @@ -3555,6 +3570,8 @@ int dsi_panel_get_mode(struct dsi_panel *panel, struct dsi_display_mode_priv_info *prv_info; u32 child_idx = 0; int rc = 0, num_timings; + int traffic_mode; + int panel_mode; void *utils_data = NULL; if (!panel || !mode) { @@ -3589,6 +3606,8 @@ int dsi_panel_get_mode(struct dsi_panel *panel, } utils_data = utils->data; + traffic_mode = panel->video_config.traffic_mode; + panel_mode = panel->panel_mode; dsi_for_each_child_node(timings_np, child_np) { if (index != child_idx++) @@ -3608,7 +3627,8 @@ int dsi_panel_get_mode(struct dsi_panel *panel, goto parse_fail; } - rc = dsi_panel_parse_vdc_params(mode, utils); + rc = dsi_panel_parse_vdc_params(mode, utils, traffic_mode, + panel_mode); if (rc) { DSI_ERR("failed to parse vdc params, rc=%d\n", rc); goto parse_fail; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 14ec19871033..02d95d872d20 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -357,38 +357,232 @@ struct msm_display_dsc_info { /** * struct msm_display_vdc_info - defines vdc configuration - * @version_major: major version number of VDC encoder. - * @version_minor: minor version number of VDC encoder. - * @source_color_space: source color space of VDC encoder - * @chroma_format: chroma_format of VDC encoder. - * @slice_height: slice height configuration of encoder. - * @slice_width: slice width configuration of encoder. - * @bytes_in_slice: number of bytes per slice . - * @slice_per_pkt: number of slices per packet. - * @bits_per_component: number of bits per component. - * @bits_per_pixel: number of bits per pixel. - * @frame_width: frame width configuration of encoder - * @frame_height: frame height configuration of encoder - * @pps_delay_ms: Post PPS command delay in milliseconds. - * @version_release: release version of VDC encoder. + * @version_major: major version number of VDC encoder. + * @version_minor: minor version number of VDC encoder. + * @source_color_space: source color space of VDC encoder + * @chroma_format: chroma_format of VDC encoder. + * @mppf_bpc_r_y: MPPF bpc for R/Y color component + * @mppf_bpc_g_cb: MPPF bpc for G/Cb color component + * @mppf_bpc_b_cr: MPPF bpc for B/Cr color component + * @mppf_bpc_y: MPPF bpc for Y color component + * @mppf_bpc_co: MPPF bpc for Co color component + * @mppf_bpc_cg: MPPF bpc for Cg color component + * @flatqp_vf_fbls: flatness qp very flat FBLs + * @flatqp_vf_nbls: flatness qp very flat NBLs + * @flatqp_sw_fbls: flatness qp somewhat flat FBLs + * @flatqp_sw_nbls: flatness qp somewhat flat NBLs + * @chroma_samples: number of chroma samples + * @split_panel_enable: indicates whether split panel is enabled + * @panel_mode: indicates panel is in video or cmd mode + * @traffic_mode: indicates burst/non-burst mode + * @flatness_qp_lut: LUT used to determine flatness QP + * @max_qp_lut: LUT used to determine maximum QP + * @tar_del_lut: LUT used to calculate RC target rate + * @lbda_brate_lut: lambda bitrate LUT for encoder + * @lbda_bf_lut: lambda buffer fullness lut for encoder + * @lbda_brate_lut_interp: interpolated lambda bitrate LUT + * @lbda_bf_lut_interp: interpolated lambda buffer fullness lut + * @num_of_active_ss: number of active soft slices + * @bits_per_component: number of bits per component. + * @max_pixels_per_line: maximum pixels per line + * @max_pixels_per_hs_line: maximum pixels per hs line + * @max_lines_per_frame: maximum lines per frame + * @max_lines_per_slice: maximum lines per slice + * @chunk_size: chunk size for encoder + * @chunk_size_bits: number of bits in the chunk + * @avg_block_bits: average block bits + * @per_chunk_pad_bits: number of bits per chunk pad + * @tot_pad_bits: total padding bits + * @rc_stuffing_bits: rate control stuffing bits + * @chunk_adj_bits: number of adjacent bits in the chunk + * @rc_buf_init_size_temp: temporary rate control buffer init size + * @init_tx_delay_temp: initial tx delay + * @rc_buffer_init_size: rate control buffer init size + * @rc_init_tx_delay: rate control buffer init tx delay + * @rc_init_tx_delay_px_times: rate control buffer init tx + * delay times pixels + * @rc_buffer_max_size: max size of rate control buffer + * @rc_tar_rate_scale_temp_a: rate control target rate scale parameter + * @rc_tar_rate_scale_temp_b: rate control target rate scale parameter + * @rc_tar_rate_scale: rate control target rate scale + * @block_max_bits: max bits in the block + * @rc_lambda_bitrate_scale: rate control lambda bitrate scale + * @rc_buffer_fullness_scale: rate control lambda fullness scale + * @rc_fullness_offset_thresh: rate control lambda fullness threshold + * @ramp_blocks: number of ramp blocks + * @bits_per_pixel: number of bits per pixel. + * @num_extra_mux_bits_init: initial value of number of extra mux bits + * @extra_crop_bits: number of extra crop bits + * @num_extra_mux_bits: value of number of extra mux bits + * @mppf_bits_comp_0: mppf bits in color component 0 + * @mppf_bits_comp_1: mppf bits in color component 1 + * @mppf_bits_comp_2: mppf bits in color component 2 + * @min_block_bits: min number of block bits + * @slice_height: slice height configuration of encoder. + * @slice_width: slice width configuration of encoder. + * @frame_width: frame width configuration of encoder + * @frame_height: frame height configuration of encoder + * @bytes_in_slice: Number of bytes in slice. + * @bytes_per_pkt: Number of bytes in packet. + * @eol_byte_num: Valid bytes at the end of line. + * @pclk_per_line: Compressed width. + * @slice_per_pkt: Number of slices per packet. + * @pkt_per_line: Number of packets per line. + * @min_ssm_delay: Min Sub-stream multiplexing delay + * @max_ssm_delay: Max Sub-stream multiplexing delay + * @input_ssm_out_latency: input Sub-stream multiplexing output latency + * @input_ssm_out_latency_min: min input Sub-stream multiplexing output latency + * @obuf_latency: Output buffer latency + * @base_hs_latency: base hard-slice latency + * @base_hs_latency_min: base hard-slice min latency + * @base_hs_latency_pixels: base hard-slice latency pixels + * @base_hs_latency_pixels_min: base hard-slice latency pixels(min) + * @base_initial_lines: base initial lines + * @base_top_up: base top up + * @output_rate: output rate + * @output_rate_ratio_100: output rate times 100 + * @burst_accum_pixels: burst accumulated pixels + * @ss_initial_lines: soft-slice initial lines + * @burst_initial_lines: burst mode initial lines + * @initial_lines: initial lines + * @obuf_base: output buffer base + * @obuf_extra_ss0: output buffer extra ss0 + * @obuf_extra_ss1: output buffer extra ss1 + * @obuf_extra_burst: output buffer extra burst + * @obuf_ss0: output buffer ss0 + * @obuf_ss1: output buffer ss1 + * @obuf_margin_words: output buffer margin words + * @ob0_max_addr: output buffer 0 max address + * @ob1_max_addr: output buffer 1 max address + * @slice_width_orig: original slice width + * @r2b0_max_addr: r2b0 max addr + * @r2b1_max_addr: r1b1 max addr + * @slice_num_px: number of pixels per slice + * @rc_target_rate_threshold: rate control target rate threshold + * @rc_fullness_offset_slope: rate control fullness offset slop + * @pps_delay_ms: Post PPS command delay in milliseconds. + * @version_release: release version of VDC encoder. + * @slice_num_bits: number of bits per slice + * @ramp_bits: number of ramp bits */ struct msm_display_vdc_info { u8 version_major; u8 version_minor; - u8 chroma_format; + u8 source_color_space; + u8 chroma_format; + u8 mppf_bpc_r_y; + u8 mppf_bpc_g_cb; + u8 mppf_bpc_b_cr; + u8 mppf_bpc_y; + u8 mppf_bpc_co; + u8 mppf_bpc_cg; + u8 flatqp_vf_fbls; + u8 flatqp_vf_nbls; + u8 flatqp_sw_fbls; + u8 flatqp_sw_nbls; + u8 chroma_samples; + u8 split_panel_enable; + u8 panel_mode; + u8 traffic_mode; + + u16 flatness_qp_lut[8]; + u16 max_qp_lut[8]; + u16 tar_del_lut[16]; + u16 lbda_brate_lut[16]; + u16 lbda_bf_lut[16]; + u16 lbda_brate_lut_interp[64]; + u16 lbda_bf_lut_interp[64]; + + u8 num_of_active_ss; + u8 bits_per_component; + + u16 max_pixels_per_line; + u16 max_pixels_per_hs_line; + u16 max_lines_per_frame; + u16 max_lines_per_slice; + + u16 chunk_size; + u16 chunk_size_bits; + + u16 avg_block_bits; + u16 per_chunk_pad_bits; + u16 tot_pad_bits; + u16 rc_stuffing_bits; + u16 chunk_adj_bits; + u16 rc_buf_init_size_temp; + u16 init_tx_delay_temp; + u16 rc_buffer_init_size; + u16 rc_init_tx_delay; + u16 rc_init_tx_delay_px_times; + u16 rc_buffer_max_size; + u16 rc_tar_rate_scale_temp_a; + u16 rc_tar_rate_scale_temp_b; + u16 rc_tar_rate_scale; + u16 block_max_bits; + u16 rc_lambda_bitrate_scale; + u16 rc_buffer_fullness_scale; + u16 rc_fullness_offset_thresh; + u16 ramp_blocks; + u16 bits_per_pixel; + u16 num_extra_mux_bits_init; + u16 extra_crop_bits; + u16 num_extra_mux_bits; + u16 mppf_bits_comp_0; + u16 mppf_bits_comp_1; + u16 mppf_bits_comp_2; + u16 min_block_bits; int slice_height; int slice_width; - int bytes_in_slice; - int slice_per_pkt; - int bits_per_component; - int bits_per_pixel; int frame_width; int frame_height; + int bytes_in_slice; + int bytes_per_pkt; + int eol_byte_num; + int pclk_per_line; + int slice_per_pkt; + int pkt_per_line; + + int min_ssm_delay; + int max_ssm_delay; + int input_ssm_out_latency; + int input_ssm_out_latency_min; + int obuf_latency; + int base_hs_latency; + int base_hs_latency_min; + int base_hs_latency_pixels; + int base_hs_latency_pixels_min; + int base_initial_lines; + int base_top_up; + int output_rate; + int output_rate_ratio_100; + int burst_accum_pixels; + int ss_initial_lines; + int burst_initial_lines; + int initial_lines; + int obuf_base; + int obuf_extra_ss0; + int obuf_extra_ss1; + int obuf_extra_burst; + int obuf_ss0; + int obuf_ss1; + int obuf_margin_words; + int ob0_max_addr; + int ob1_max_addr; + int slice_width_orig; + int r2b0_max_addr; + int r2b1_max_addr; + + u32 slice_num_px; + u32 rc_target_rate_threshold; + u32 rc_fullness_offset_slope; u32 pps_delay_ms; u32 version_release; + + u64 slice_num_bits; + u64 ramp_bits; }; /** diff --git a/msm/sde_vdc_helper.c b/msm/sde_vdc_helper.c new file mode 100644 index 000000000000..9272289883a2 --- /dev/null +++ b/msm/sde_vdc_helper.c @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include "msm_drv.h" +#include "sde_vdc_helper.h" + +enum sde_vdc_profile_type { + VDC_RGB_444_8BPC_8BPP, + VDC_RGB_444_8BPC_6BPP, + VDC_RGB_444_10BPC_10BPP, + VDC_RGB_444_108BPC_8BPP, + VDC_RGB_444_10BPC_7BPP, + VDC_RGB_444_10BPC_6BPP, + VDC_YUV_422_8BPC_6BPP, + VDC_YUV_422_8BPC_5BPP, + VDC_YUV_422_8BPC_4_75BPP, + VDC_YUV_422_10BPC_8BPP, + VDC_YUV_422_10BPC_6BPP, + VDC_YUV_422_10BPC_5_5BPP, + VDC_YUV_422_10BPC_5PP, + VDC_PROFILE_MAX +}; + +static u8 sde_vdc_mppf_bpc_r_y[VDC_PROFILE_MAX] = { + 2, 1, 3, 2, 2, 1, 3, 2, 2, 4, 3, 2, 2}; + +static u8 sde_vdc_mppf_bpc_g_cb[VDC_PROFILE_MAX] = { + 2, 2, 3, 2, 2, 2, 2, 2, 1, 3, 2, 2, 2}; + +static u8 sde_vdc_mppf_bpc_b_cr[VDC_PROFILE_MAX] = { + 2, 1, 3, 2, 2, 1, 2, 2, 1, 3, 2, 2, 2}; + +static u8 sde_vdc_mppf_bpc_y[VDC_PROFILE_MAX] = { + 2, 2, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0}; + +static u8 sde_vdc_mppf_bpc_co[VDC_PROFILE_MAX] = { + 2, 1, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0}; + +static u8 sde_vdc_mppf_bpc_cg[VDC_PROFILE_MAX] = { + 2, 1, 3, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0}; + +static u8 sde_vdc_flat_qp_vf_fbls[VDC_PROFILE_MAX] = { + 20, 24, 24, 24, 24, 24, 24, 24, 24, 8, 20, 18, 24}; + +static u8 sde_vdc_flat_qp_vf_nfbls[VDC_PROFILE_MAX] = { + 24, 28, 28, 28, 28, 28, 28, 28, 28, 16, 24, 20, 28}; + +static u8 sde_vdc_flat_qp_sf_fbls[VDC_PROFILE_MAX] = { + 24, 28, 28, 28, 28, 28, 28, 28, 28, 16, 24, 20, 28}; + +static u8 sde_vdc_flat_qp_sf_nbls[VDC_PROFILE_MAX] = { + 28, 40, 32, 28, 32, 28, 36, 36, 36, 16, 24, 24, 28}; + +static u16 sde_vdc_flat_qp_lut[VDC_PROFILE_MAX][VDC_FLAT_QP_LUT_SIZE] = { + {20, 20, 24, 24, 28, 32, 36, 40}, + {24, 24, 28, 32, 36, 40, 40, 40}, + {24, 24, 28, 32, 32, 36, 36, 36}, + {20, 24, 28, 28, 32, 36, 40, 44}, + {20, 24, 28, 32, 32, 36, 36, 40}, + {24, 28, 32, 32, 36, 40, 40, 40}, + {24, 28, 32, 34, 36, 38, 40, 40}, + {24, 28, 32, 36, 40, 42, 44, 44}, + {24, 28, 32, 36, 40, 42, 44, 44}, + {0, 8, 10, 12, 14, 16, 18, 20}, + {12, 16, 20, 20, 20, 24, 24, 28}, + {16, 18, 20, 22, 24, 26, 28, 28}, + {20, 22, 24, 26, 28, 28, 32, 32}, +}; + +static u16 sde_vdc_max_qp_lut[VDC_PROFILE_MAX][VDC_MAX_QP_LUT_SIZE] = { + {28, 28, 32, 32, 36, 42, 42, 48}, + {32, 32, 36, 40, 44, 48, 48, 52}, + {32, 32, 36, 36, 36, 40, 44, 48}, + {24, 28, 32, 32, 36, 40, 44, 48}, + {28, 28, 32, 32, 36, 42, 42, 48}, + {28, 32, 36, 40, 44, 44, 46, 52}, + {32, 32, 36, 40, 40, 44, 48, 48}, + {32, 32, 36, 40, 44, 48, 50, 52}, + {32, 32, 36, 40, 44, 48, 50, 52}, + {8, 12, 12, 16, 20, 24, 28, 28}, + {18, 20, 22, 24, 28, 30, 32, 40}, + {18, 20, 22, 24, 28, 30, 32, 40}, + {20, 20, 24, 24, 28, 28, 32, 36}, +}; + +static u16 sde_vdc_tar_del_lut[VDC_PROFILE_MAX][VDC_TAR_DEL_LUT_SIZE] = { + {128, 117, 107, 96, 85, 75, 64, 53, 43, 32, 24, 11, 0, 0, 0, 0}, + {96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0, 0, 0, 0}, + {160, 147, 133, 120, 107, 93, 80, 67, 53, 40, 27, 13, 0, 0, 0, 0}, + {128, 117, 107, 96, 85, 75, 64, 53, 43, 32, 21, 11, 0, 0, 0, 0}, + {112, 103, 93, 84, 75, 95, 56, 47, 37, 28, 19, 9, 0, 0, 0, 0}, + {96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0, 0, 0, 0}, + {96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0, 0, 0, 0}, + {80, 73, 67, 60, 53, 47, 40, 33, 27, 20, 13, 7, 0, 0, 0, 0}, + {76, 70, 63, 57, 51, 44, 38, 32, 25, 19, 13, 6, 0, 0, 0, 0}, + {128, 117, 107, 96, 85, 75, 64, 53, 43, 32, 21, 11, 0, 0, 0, 0}, + {96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0, 0, 0, 0}, + {88, 81, 73, 66, 59, 51, 44, 37, 29, 22, 15, 7, 0, 0, 0, 0}, + {80, 73, 67, 60, 53, 47, 40, 33, 27, 20, 13, 7, 0, 0, 0, 0}, +}; + +static u16 sde_vdc_lbda_brate_lut[VDC_PROFILE_MAX][VDC_LBDA_BRATE_LUT_SIZE] = { + {4, 6, 10, 16, 25, 40, 64, 102, 161, 256, 406, 645, 1024, 1625, + 2580, 4095}, + {8, 12, 18, 28, 42, 64, 97, 147, 223, 338, 512, 776, 1176, 1782, + 2702, 4095}, + {16, 23, 34, 48, 70, 102, 147, 213, 308, 446, 645, 933, 1351, + 1955, 2829, 4095}, + {8, 12, 18, 28, 42, 64, 97, 147, 223, 338, 512, 776, 1176, 1782, + 2702, 4095}, + {32, 44, 61, 84, 117, 161, 223, 308, 425, 588, 813, 1123, 1552, 2144, + 2963, 4095}, + {64, 84, 111, 147, 194, 256, 338, 446, 588, 776, 1024, 1351, 1782, + 2352, 3103, 4095}, + {1, 2, 3, 5, 9, 16, 28, 48, 84, 147, 256, 446, 776, 1351, 2352, 4095}, + {4, 6, 10, 16, 25, 40, 64, 102, 161, 256, 406, 645, 1024, 1625, + 2580, 4095}, + {4, 6, 10, 16, 25, 40, 64, 102, 161, 256, 406, 645, 1024, 1625, + 2580, 4095}, + {1, 2, 3, 5, 9, 16, 28, 48, 84, 147, 256, 446, 776, 1351, 2352, 4095}, + {1, 2, 3, 5, 9, 16, 28, 48, 84, 147, 256, 446, 776, 1351, 2352, 4095}, + {1, 2, 3, 5, 9, 16, 28, 48, 84, 147, 256, 446, 776, 1351, 2352, 4095}, + {1, 2, 3, 5, 9, 16, 28, 48, 84, 147, 256, 446, 776, 1351, 2352, 4095}, +}; + +static u16 sde_vdc_lbda_bf_lut[VDC_PROFILE_MAX][VDC_LBDA_BF_LUT_SIZE] = { + {1, 1, 2, 3, 4, 6, 9, 13, 19, 28, 40, 58, 84, 122, 176, 255}, + {1, 1, 2, 3, 4, 6, 9, 13, 19, 28, 40, 58, 84, 122, 176, 255}, + {1, 1, 2, 3, 4, 6, 9, 13, 19, 28, 40, 58, 84, 122, 176, 255}, + {1, 1, 2, 3, 4, 6, 9, 13, 19, 28, 40, 58, 84, 122, 176, 255}, + {4, 5, 7, 9, 12, 16, 21, 28, 37, 48, 64, 84, 111, 146, 193, 255}, + {1, 1, 1, 2, 3, 4, 6, 9, 14, 21, 32, 48, 73, 111, 168, 255}, + {1, 1, 1, 1, 2, 3, 4, 6, 10, 16, 25, 40, 64, 101, 161, 255}, + {1, 1, 1, 1, 2, 3, 4, 6, 10, 16, 25, 40, 64, 101, 161, 255}, + {1, 1, 1, 1, 2, 3, 4, 6, 10, 16, 25, 40, 64, 101, 161, 255}, + {1, 1, 1, 1, 2, 3, 4, 6, 10, 16, 25, 40, 64, 101, 161, 255}, + {1, 1, 1, 1, 2, 3, 4, 6, 10, 16, 25, 40, 64, 101, 161, 255}, + {1, 1, 1, 1, 2, 3, 4, 6, 10, 16, 25, 40, 64, 101, 161, 255}, + {1, 1, 1, 1, 2, 3, 4, 6, 10, 16, 25, 40, 64, 101, 161, 255}, +}; + +static int _get_vdc_profile_index(struct msm_display_vdc_info *vdc_info) +{ + int bpp, bpc; + int rc = -EINVAL; + + bpp = VDC_BPP(vdc_info->bits_per_pixel); + bpc = vdc_info->bits_per_component; + + if (vdc_info->chroma_format == MSM_CHROMA_444) { + if ((bpc == 8) && (bpp == 8)) + return VDC_RGB_444_8BPC_8BPP; + else if ((bpc == 8) && (bpp == 6)) + return VDC_RGB_444_8BPC_6BPP; + else if ((bpc == 10) && (bpp == 10)) + return VDC_RGB_444_10BPC_10BPP; + else if ((bpc == 10) && (bpp == 10)) + return VDC_RGB_444_10BPC_10BPP; + else if ((bpc == 10) && (bpp == 8)) + return VDC_RGB_444_108BPC_8BPP; + else if ((bpc == 10) && (bpp == 7)) + return VDC_RGB_444_10BPC_7BPP; + else if ((bpc == 10) && (bpp == 6)) + return VDC_RGB_444_10BPC_6BPP; + } else if (vdc_info->chroma_format == MSM_CHROMA_422) { + if ((bpc == 8) && (bpp == 6)) + return VDC_YUV_422_8BPC_6BPP; + else if ((bpc == 8) && (bpp == 5)) + return VDC_YUV_422_8BPC_5BPP; + else if ((bpc == 10) && (bpp == 8)) + return VDC_YUV_422_10BPC_8BPP; + else if ((bpc == 10) && (bpp == 6)) + return VDC_YUV_422_10BPC_6BPP; + else if ((bpc == 10) && (bpp == 5)) + return VDC_YUV_422_10BPC_5PP; + } + + pr_err("unsupported bpc:%d, bpp:%d\n", bpc, bpp); + + return rc; +} + +static void sde_vdc_dump_lut_params(struct msm_display_vdc_info *vdc_info) +{ + int i; + + pr_debug("vdc_info->mppf_bpc_r_y = %d\n", vdc_info->mppf_bpc_r_y); + pr_debug("vdc_info->mppf_bpc_g_cb = %d\n", vdc_info->mppf_bpc_g_cb); + pr_debug("vdc_info->mppf_bpc_b_cr = %d\n", vdc_info->mppf_bpc_b_cr); + pr_debug("vdc_info->mppf_bpc_y = %d\n", vdc_info->mppf_bpc_y); + pr_debug("vdc_info->mppf_bpc_co = %d\n", vdc_info->mppf_bpc_co); + pr_debug("vdc_info->mppf_bpc_cg = %d\n", vdc_info->mppf_bpc_cg); + pr_debug("vdc_info->flatqp_vf_fbls = %d\n", vdc_info->flatqp_vf_fbls); + pr_debug("vdc_info->flatqp_vf_nbls = %d\n", vdc_info->flatqp_vf_nbls); + pr_debug("vdc_info->flatqp_sw_fbls = %d\n", vdc_info->flatqp_sw_fbls); + pr_debug("vdc_info->flatqp_sw_nbls = %d\n", vdc_info->flatqp_sw_nbls); + + for (i = 0; i < VDC_FLAT_QP_LUT_SIZE; i++) + pr_debug("vdc_info->flatness_qp_lut[%d] = %d\n", + i, vdc_info->flatness_qp_lut[i]); + + for (i = 0; i < VDC_MAX_QP_LUT_SIZE; i++) + pr_debug("vdc_info->max_qp_lut[%d] = %d\n", + i, vdc_info->max_qp_lut[i]); + + for (i = 0; i < VDC_TAR_DEL_LUT_SIZE; i++) + pr_debug("vdc_info->tar_del_lut[%d] = %d\n", + i, vdc_info->tar_del_lut[i]); + + for (i = 0; i < VDC_LBDA_BRATE_LUT_SIZE; i++) + pr_debug("vdc_info->lbda_brate_lut[%d] = %d\n", + i, vdc_info->lbda_brate_lut[i]); + + for (i = 0; i < VDC_LBDA_BF_LUT_SIZE; i++) + pr_debug("vdc_info->lbda_bf_lut[%d] = %d\n", + i, vdc_info->lbda_bf_lut[i]); + + for (i = 0; i < VDC_LBDA_BRATE_REG_SIZE; i++) + pr_debug("vdc_info->lbda_brate_lut_interp[%d] = %d\n", + i, vdc_info->lbda_brate_lut_interp[i]); + + for (i = 0; i < VDC_LBDA_BRATE_REG_SIZE; i++) + pr_debug("vdc_info->lbda_bf_lut_interp[%d] = %d\n", + i, vdc_info->lbda_bf_lut_interp[i]); +} + +static void sde_vdc_dump_core_params(struct msm_display_vdc_info *vdc_info) +{ + pr_debug("vdc_info->num_of_active_ss = %d\n", + vdc_info->num_of_active_ss); + pr_debug("vdc_info->chunk_size = %d\n", + vdc_info->chunk_size); + pr_debug("vdc_info->chunk_size_bits = %d\n", + vdc_info->chunk_size_bits); + pr_debug("vdc_info->slice_num_px = %d\n", + vdc_info->slice_num_px); + pr_debug("vdc_info->avg_block_bits = %d\n", + vdc_info->avg_block_bits); + pr_debug("vdc_info->per_chunk_pad_bits = %d\n", + vdc_info->per_chunk_pad_bits); + pr_debug("vdc_info->tot_pad_bits = %d\n", + vdc_info->tot_pad_bits); + pr_debug("vdc_info->rc_stuffing_bits = %d\n", + vdc_info->rc_stuffing_bits); + pr_debug("vdc_info->slice_num_bits = %d\n", + vdc_info->slice_num_bits); + pr_debug("vdc_info->chunk_adj_bits = %d\n", + vdc_info->chunk_adj_bits); + pr_debug("vdc_info->rc_buf_init_size_temp = %d\n", + vdc_info->rc_buf_init_size_temp); + pr_debug("vdc_info->init_tx_delay_temp = %d\n", + vdc_info->init_tx_delay_temp); + pr_debug("vdc_info->rc_buffer_init_size = %d\n", + vdc_info->rc_buffer_init_size); + pr_debug("vdc_info->rc_init_tx_delay = %d\n", + vdc_info->rc_init_tx_delay); + pr_debug("vdc_info->rc_init_tx_delay_px_times = %d\n", + vdc_info->rc_init_tx_delay_px_times); + pr_debug("vdc_info->rc_buffer_max_size = %d\n", + vdc_info->rc_buffer_max_size); + pr_debug("vdc_info->rc_tar_rate_scale_temp_a = %d\n", + vdc_info->rc_tar_rate_scale_temp_a); + pr_debug("vdc_info->rc_tar_rate_scale_temp_b = %d\n", + vdc_info->rc_tar_rate_scale_temp_b); + pr_debug("vdc_info->rc_tar_rate_scale = %d\n", + vdc_info->rc_tar_rate_scale); + pr_debug("vdc_info->rc_target_rate_threshold = %d\n", + vdc_info->rc_target_rate_threshold); + pr_debug("vdc_info->chroma_samples = %d\n", + vdc_info->chroma_samples); + pr_debug("vdc_info->block_max_bits = %d\n", + vdc_info->block_max_bits); + pr_debug("vdc_info->rc_lambda_bitrate_scale = %d\n", + vdc_info->rc_lambda_bitrate_scale); + pr_debug("vdc_info->rc_buffer_fullness_scale = %d\n", + vdc_info->rc_buffer_fullness_scale); + pr_debug("vdc_info->rc_fullness_offset_thresh = %d\n", + vdc_info->rc_fullness_offset_thresh); + pr_debug("vdc_info->ramp_blocks = %d\n", + vdc_info->ramp_blocks); + pr_debug("vdc_info->ramp_bits = %d\n", + vdc_info->ramp_bits); + pr_debug("vdc_info->rc_fullness_offset_slope = %d\n", + vdc_info->rc_fullness_offset_slope); + pr_debug("vdc_info->num_extra_mux_bits_init = %d\n", + vdc_info->num_extra_mux_bits_init); + pr_debug("vdc_info->extra_crop_bits = %d\n", + vdc_info->extra_crop_bits); + pr_debug("vdc_info->num_extra_mux_bits = %d\n", + vdc_info->num_extra_mux_bits); + pr_debug("vdc_info->mppf_bits_comp_0 = %d\n", + vdc_info->mppf_bits_comp_0); + pr_debug("vdc_info->mppf_bits_comp_1 = %d\n", + vdc_info->mppf_bits_comp_1); + pr_debug("vdc_info->mppf_bits_comp_2 = %d\n", + vdc_info->mppf_bits_comp_2); + pr_debug("vdc_info->min_block_bits = %d\n", + vdc_info->min_block_bits); +} + +static void sde_vdc_dump_ext_core_params(struct msm_display_vdc_info *vdc_info) +{ + pr_debug("vdc_info->input_ssm_out_latency = %d\n", + vdc_info->input_ssm_out_latency); + pr_debug("vdc_info->input_ssm_out_latency_min = %d\n", + vdc_info->input_ssm_out_latency_min); + pr_debug("vdc_info->obuf_latency = %d\n", + vdc_info->obuf_latency); + pr_debug("vdc_info->base_hs_latency = %d\n", + vdc_info->base_hs_latency); + pr_debug("vdc_info->base_hs_latency_pixels = %d\n", + vdc_info->base_hs_latency_pixels); + pr_debug("vdc_info->base_hs_latency_pixels_min = %d\n", + vdc_info->base_hs_latency_pixels_min); + pr_debug("vdc_info->base_initial_lines = %d\n", + vdc_info->base_initial_lines); + pr_debug("vdc_info->base_top_up = %d\n", + vdc_info->base_top_up); + pr_debug("vdc_info->output_rate = %d\n", + vdc_info->output_rate); + pr_debug("vdc_info->output_rate_ratio_100 = %d\n", + vdc_info->output_rate_ratio_100); + pr_debug("vdc_info->burst_accum_pixels = %d\n", + vdc_info->burst_accum_pixels); + pr_debug("vdc_info->ss_initial_lines = %d\n", + vdc_info->ss_initial_lines); + pr_debug("vdc_info->burst_initial_lines = %d\n", + vdc_info->burst_initial_lines); + pr_debug("vdc_info->initial_lines = %d\n", + vdc_info->initial_lines); + pr_debug("vdc_info->obuf_base = %d\n", + vdc_info->obuf_base); + pr_debug("vdc_info->obuf_extra_ss0 = %d\n", + vdc_info->obuf_extra_ss0); + pr_debug("vdc_info->obuf_extra_ss1 = %d\n", + vdc_info->obuf_extra_ss1); + pr_debug("vdc_info->obuf_extra_burst = %d\n", + vdc_info->obuf_extra_burst); + pr_debug("vdc_info->obuf_ss0 = %d\n", + vdc_info->obuf_ss0); + pr_debug("vdc_info->obuf_ss1 = %d\n", + vdc_info->obuf_ss1); + pr_debug("vdc_info->obuf_margin_words = %d\n", + vdc_info->obuf_margin_words); + + pr_debug("vdc_info->ob0_max_addr = %d\n", + vdc_info->ob0_max_addr); + pr_debug("vdc_info->ob1_max_addr = %d\n", + vdc_info->ob1_max_addr); + + pr_debug("vdc_info->slice_width_orig = %d\n", + vdc_info->slice_width_orig); + pr_debug("vdc_info->r2b0_max_addr = %d\n", + vdc_info->r2b0_max_addr); + pr_debug("vdc_info->r2b1_max_addr = %d\n", + vdc_info->r2b1_max_addr); +} + +static int sde_vdc_populate_lut_params(struct msm_display_vdc_info *vdc_info) +{ + int bpp, bpc; + int i, profile_idx; + int x_0, x_1, lambda, idx_mod; + int x_0_idx, x_1_idx; + int idx; + + bpp = VDC_BPP(vdc_info->bits_per_pixel); + bpc = vdc_info->bits_per_component; + + profile_idx = _get_vdc_profile_index(vdc_info); + if (profile_idx == -EINVAL) { + pr_err("no matching profile found\n"); + return profile_idx; + } + + vdc_info->mppf_bpc_r_y = sde_vdc_mppf_bpc_r_y[profile_idx]; + vdc_info->mppf_bpc_g_cb = sde_vdc_mppf_bpc_g_cb[profile_idx]; + vdc_info->mppf_bpc_b_cr = sde_vdc_mppf_bpc_b_cr[profile_idx]; + vdc_info->mppf_bpc_y = sde_vdc_mppf_bpc_y[profile_idx]; + vdc_info->mppf_bpc_co = sde_vdc_mppf_bpc_co[profile_idx]; + vdc_info->mppf_bpc_cg = sde_vdc_mppf_bpc_cg[profile_idx]; + vdc_info->flatqp_vf_fbls = sde_vdc_flat_qp_vf_fbls[profile_idx]; + vdc_info->flatqp_vf_nbls = sde_vdc_flat_qp_vf_nfbls[profile_idx]; + vdc_info->flatqp_sw_fbls = sde_vdc_flat_qp_sf_fbls[profile_idx]; + vdc_info->flatqp_sw_nbls = sde_vdc_flat_qp_sf_nbls[profile_idx]; + + idx = profile_idx; + + for (i = 0; i < VDC_FLAT_QP_LUT_SIZE; i++) + vdc_info->flatness_qp_lut[i] = sde_vdc_flat_qp_lut[idx][i]; + + for (i = 0; i < VDC_MAX_QP_LUT_SIZE; i++) + vdc_info->max_qp_lut[i] = sde_vdc_max_qp_lut[idx][i]; + + for (i = 0; i < VDC_TAR_DEL_LUT_SIZE; i++) + vdc_info->tar_del_lut[i] = sde_vdc_tar_del_lut[idx][i]; + + for (i = 0; i < VDC_LBDA_BRATE_LUT_SIZE; i++) + vdc_info->lbda_brate_lut[i] = sde_vdc_lbda_brate_lut[idx][i]; + + for (i = 0; i < VDC_LBDA_BF_LUT_SIZE; i++) + vdc_info->lbda_bf_lut[i] = sde_vdc_lbda_bf_lut[idx][i]; + + for (i = 0; i < VDC_LBDA_BRATE_REG_SIZE; i++) { + idx_mod = i & 0x03; + + x_0_idx = i >> 2; + if (x_0_idx > VDC_LBDA_BRATE_LUT_SIZE - 1) + x_0_idx = VDC_LBDA_BRATE_LUT_SIZE - 1; + + x_1_idx = (i >> 2) + 1; + if (x_1_idx > VDC_LBDA_BRATE_LUT_SIZE - 1) + x_1_idx = VDC_LBDA_BRATE_LUT_SIZE - 1; + + x_0 = vdc_info->lbda_brate_lut[x_0_idx]; + x_1 = vdc_info->lbda_brate_lut[x_1_idx]; + + lambda = (((4 - idx_mod) * x_0 + idx_mod * x_1 + 2) >> 2); + vdc_info->lbda_brate_lut_interp[i] = lambda; + + x_0 = vdc_info->lbda_bf_lut[x_0_idx]; + x_1 = vdc_info->lbda_bf_lut[x_1_idx]; + + lambda = (((4 - idx_mod) * x_0 + idx_mod * x_1 + 2) >> 2); + vdc_info->lbda_bf_lut_interp[i] = lambda; + } + + sde_vdc_dump_lut_params(vdc_info); + return 0; +} + +static int sde_vdc_populate_core_params(struct msm_display_vdc_info *vdc_info, + int intf_width) +{ + u16 bpp; + u16 bpc; + u32 bpp_codec; + u64 temp, diff; + + if (!vdc_info) + return -EINVAL; + + if (!vdc_info->slice_width || + !vdc_info->slice_height || + intf_width < vdc_info->slice_width) { + pr_err("invalid input, intf_width=%d slice_width=%d\n", + intf_width, vdc_info->slice_width); + return -EINVAL; + } + + bpp = VDC_BPP(vdc_info->bits_per_pixel); + bpp_codec = 16 * bpp; + bpc = vdc_info->bits_per_component; + + vdc_info->num_of_active_ss = intf_width / vdc_info->slice_width; + + temp = vdc_info->slice_width * bpp_codec; + temp += 15; + temp >>= 4; + temp += 7; + temp >>= 3; + vdc_info->chunk_size = temp; + vdc_info->chunk_size_bits = temp * 8; + vdc_info->slice_num_px = vdc_info->slice_width * + vdc_info->slice_height; + + /* slice_num_px should be atleast 4096 */ + if (vdc_info->slice_num_px < 4096) { + pr_err("insufficient slice_num_px:%d\n", + vdc_info->slice_num_px); + return -EINVAL; + } + + vdc_info->avg_block_bits = bpp_codec; + + temp = (16 * vdc_info->chunk_size); + temp -= (vdc_info->slice_width * 2 * bpp_codec) >> 4; + vdc_info->per_chunk_pad_bits = temp; + + vdc_info->tot_pad_bits = (vdc_info->avg_block_bits + + vdc_info->per_chunk_pad_bits - 8); + + vdc_info->rc_stuffing_bits = ((vdc_info->tot_pad_bits + 8) / 9); + vdc_info->slice_num_bits = (8 * vdc_info->chunk_size * + vdc_info->slice_height); + + temp = (16 * vdc_info->chunk_size); + vdc_info->chunk_adj_bits = temp - + ((2 * vdc_info->slice_width * bpp_codec) >> 4); + + if (vdc_info->slice_width <= 720) + vdc_info->rc_buf_init_size_temp = 4096; + else if (vdc_info->slice_width <= 2048) + vdc_info->rc_buf_init_size_temp = 8192; + else + vdc_info->rc_buf_init_size_temp = 10752; + + vdc_info->init_tx_delay_temp = (vdc_info->rc_buf_init_size_temp / + vdc_info->avg_block_bits); + + temp = (vdc_info->init_tx_delay_temp * 16 * bpp_codec); + vdc_info->rc_buffer_init_size = temp >> 4; + + vdc_info->rc_init_tx_delay = vdc_info->rc_buffer_init_size / + vdc_info->avg_block_bits; + + vdc_info->rc_init_tx_delay_px_times = vdc_info->rc_init_tx_delay * 16; + + temp = (2 * vdc_info->rc_buffer_init_size); + temp = temp + (2 * vdc_info->slice_width * + RC_TARGET_RATE_EXTRA_FTBLS); + vdc_info->rc_buffer_max_size = temp; + + vdc_info->rc_tar_rate_scale_temp_a = ilog2(vdc_info->slice_num_px) + 1; + vdc_info->rc_tar_rate_scale_temp_b = ilog2(vdc_info->slice_num_px); + + vdc_info->rc_tar_rate_scale = 1 + vdc_info->rc_tar_rate_scale_temp_a; + + vdc_info->rc_target_rate_threshold = (1 << + (vdc_info->rc_tar_rate_scale - 1)); + + if (vdc_info->chroma_format == MSM_CHROMA_444) + vdc_info->chroma_samples = 16; + else if (vdc_info->chroma_format == MSM_CHROMA_422) + vdc_info->chroma_samples = 8; + else + vdc_info->chroma_samples = 4; + + temp = (2 * vdc_info->chroma_samples) + 16; + vdc_info->block_max_bits = (temp * bpc) + 7; + + temp = (1 << 12); + temp += (vdc_info->block_max_bits >> 1); + temp /= vdc_info->block_max_bits; + vdc_info->rc_lambda_bitrate_scale = temp; + + temp = (1 << 20); + temp /= vdc_info->rc_buffer_max_size; + vdc_info->rc_buffer_fullness_scale = temp; + + vdc_info->rc_fullness_offset_thresh = (vdc_info->slice_height / 6); + + temp = (vdc_info->slice_width >> 3); + temp = temp * vdc_info->rc_fullness_offset_thresh; + vdc_info->ramp_blocks = temp; + + temp = (vdc_info->rc_buffer_max_size - vdc_info->rc_buffer_init_size); + temp = temp << 16; + vdc_info->ramp_bits = temp; + + temp = vdc_info->ramp_bits / vdc_info->ramp_blocks; + vdc_info->rc_fullness_offset_slope = temp; + + temp = (2 * SSM_MAX_SE_SIZE) - 2; + vdc_info->num_extra_mux_bits_init = temp * 4; + + temp = vdc_info->slice_num_bits - vdc_info->num_extra_mux_bits_init; + if ((temp % SSM_MAX_SE_SIZE) == 0) { + vdc_info->extra_crop_bits = 0; + } else { + diff = vdc_info->slice_num_bits - + vdc_info->num_extra_mux_bits_init; + vdc_info->extra_crop_bits = (SSM_MAX_SE_SIZE - + (diff % SSM_MAX_SE_SIZE)); + } + + vdc_info->num_extra_mux_bits = vdc_info->num_extra_mux_bits_init - + vdc_info->extra_crop_bits; + + vdc_info->mppf_bits_comp_0 = 16 * vdc_info->mppf_bpc_r_y; + vdc_info->mppf_bits_comp_1 = vdc_info->chroma_samples * + vdc_info->mppf_bpc_g_cb; + vdc_info->mppf_bits_comp_2 = vdc_info->chroma_samples * + vdc_info->mppf_bpc_b_cr; + + vdc_info->min_block_bits = 8 + vdc_info->mppf_bits_comp_0 + + vdc_info->mppf_bits_comp_1 + vdc_info->mppf_bits_comp_2; + + sde_vdc_dump_core_params(vdc_info); + return 0; +} + +static void sde_vdc_intf_prog_params(struct msm_display_vdc_info *vdc_info, + int intf_width) +{ + int slice_per_pkt, slice_per_intf; + int bytes_in_slice, total_bytes_per_intf; + u16 bpp; + + slice_per_pkt = vdc_info->slice_per_pkt; + // is mode->timing.h_active always intf_width? + slice_per_intf = DIV_ROUND_UP(intf_width, + vdc_info->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; + + bpp = VDC_BPP(vdc_info->bits_per_pixel); + bytes_in_slice = DIV_ROUND_UP(vdc_info->slice_width * + bpp, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + vdc_info->eol_byte_num = total_bytes_per_intf % 3; + vdc_info->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + vdc_info->bytes_in_slice = bytes_in_slice; + vdc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt; + vdc_info->pkt_per_line = slice_per_intf / slice_per_pkt; + + pr_debug("eol_byte_num = %d pclk_per_line = %d\n", + vdc_info->eol_byte_num, vdc_info->pclk_per_line); + pr_debug("bytes_in_slice = %d bytes_per_pkt = %d\n", + vdc_info->bytes_in_slice, vdc_info->bytes_per_pkt); + pr_debug("pkt_per_line = %d\n", vdc_info->pkt_per_line); +} + +static void sde_vdc_ext_core_params(struct msm_display_vdc_info *vdc_info, + int traffic_mode) +{ + int temp; + int bpp; + int rc_init_tx_delay_px_times; + + bpp = VDC_BPP(vdc_info->bits_per_pixel); + + vdc_info->min_ssm_delay = SSM_MAX_SE_SIZE; + vdc_info->max_ssm_delay = SSM_MAX_SE_SIZE + 1; + + vdc_info->input_ssm_out_latency = MAX_PIPELINE_LATENCY + + (8 * vdc_info->max_ssm_delay); + + vdc_info->input_ssm_out_latency_min = (8 * vdc_info->min_ssm_delay); + + temp = (7 + OUT_BUF_UF_MARGIN); + temp *= OB_DATA_WIDTH; + temp += (SSM_MAX_SE_SIZE / 2); + + temp /= (bpp * 2); + temp += 1; + + vdc_info->obuf_latency = temp; + + temp = vdc_info->input_ssm_out_latency + + vdc_info->obuf_latency; + rc_init_tx_delay_px_times = vdc_info->rc_init_tx_delay_px_times; + rc_init_tx_delay_px_times /= 2; + + vdc_info->base_hs_latency = rc_init_tx_delay_px_times + temp; + + temp = vdc_info->rc_init_tx_delay_px_times; + temp /= 2; + temp += vdc_info->input_ssm_out_latency_min; + vdc_info->base_hs_latency_min = temp; + vdc_info->base_hs_latency_pixels = (vdc_info->base_hs_latency * 2); + + vdc_info->base_hs_latency_pixels_min = (2 * + vdc_info->base_hs_latency_min); + + temp = DIV_ROUND_UP(vdc_info->base_hs_latency_pixels, + vdc_info->slice_width); + + vdc_info->base_initial_lines = temp; + + temp = vdc_info->base_initial_lines * vdc_info->slice_width; + temp -= vdc_info->base_hs_latency_pixels; + vdc_info->base_top_up = temp; + + if (traffic_mode == VDC_TRAFFIC_BURST_MODE) + vdc_info->output_rate = OUTPUT_DATA_WIDTH; + else + vdc_info->output_rate = bpp * 2; + + temp = (bpp * 2 * 100); + temp /= vdc_info->output_rate; + + vdc_info->output_rate_ratio_100 = temp; + + if (traffic_mode == VDC_TRAFFIC_BURST_MODE) { + temp = vdc_info->output_rate_ratio_100 * + vdc_info->slice_width; + temp *= vdc_info->num_of_active_ss; + temp /= 100; + vdc_info->burst_accum_pixels = temp; + } else { + vdc_info->burst_accum_pixels = 0; + } + + if (vdc_info->num_of_active_ss > 1) + vdc_info->ss_initial_lines = 1; + else + vdc_info->ss_initial_lines = 0; + + if (traffic_mode == VDC_TRAFFIC_BURST_MODE) { + if ((vdc_info->burst_accum_pixels + + vdc_info->base_top_up) < vdc_info->slice_width) + vdc_info->burst_initial_lines = 1; + else + vdc_info->burst_initial_lines = 0; + } else { + vdc_info->burst_initial_lines = 0; + } + + vdc_info->initial_lines = 1 + vdc_info->base_initial_lines + + vdc_info->ss_initial_lines + + vdc_info->burst_initial_lines; + + temp = (vdc_info->base_initial_lines * vdc_info->slice_width); + temp -= vdc_info->base_hs_latency_pixels_min; + temp *= bpp; + vdc_info->obuf_base = temp; + + if (vdc_info->num_of_active_ss > 1) { + vdc_info->obuf_extra_ss0 = 2 * vdc_info->chunk_size_bits; + vdc_info->obuf_extra_ss1 = vdc_info->chunk_size_bits; + } else { + vdc_info->obuf_extra_ss0 = 0; + vdc_info->obuf_extra_ss1 = 0; + } + + vdc_info->obuf_extra_burst = vdc_info->burst_initial_lines * + vdc_info->chunk_size_bits; + + vdc_info->obuf_ss0 = vdc_info->rc_buffer_max_size + + vdc_info->obuf_base + vdc_info->obuf_extra_ss0 + + vdc_info->obuf_extra_burst; + + vdc_info->obuf_ss1 = vdc_info->rc_buffer_max_size + + vdc_info->obuf_base + vdc_info->obuf_extra_ss1 + + vdc_info->obuf_extra_burst; + + temp = OUT_BUF_OF_MARGIN_TC_10 * + vdc_info->chunk_size_bits; + temp /= 10; + temp /= SSM_MAX_SE_SIZE; + vdc_info->obuf_margin_words = max(OUT_BUF_OF_MARGIN_OB, + temp); + + if (vdc_info->num_of_active_ss == 2) { + vdc_info->ob0_max_addr = OB0_RAM_DEPTH - 1; + vdc_info->ob1_max_addr = OB1_RAM_DEPTH - 1; + } else { + vdc_info->ob0_max_addr = (2 * OB1_RAM_DEPTH) - 1; + vdc_info->ob1_max_addr = 0; + } + + if (vdc_info->split_panel_enable) { + temp = vdc_info->frame_width / vdc_info->num_of_active_ss; + temp /= NUM_ACTIVE_HS; + } else { + temp = vdc_info->frame_width / vdc_info->num_of_active_ss; + } + + vdc_info->slice_width_orig = temp; + + vdc_info->r2b0_max_addr = (MAX_PIXELS_PER_HS_LINE / 4); + vdc_info->r2b0_max_addr += 3; + + vdc_info->r2b1_max_addr = (MAX_PIXELS_PER_HS_LINE / 4); + vdc_info->r2b1_max_addr /= 2; + vdc_info->r2b1_max_addr += 3; + + sde_vdc_dump_ext_core_params(vdc_info); +} + +int sde_vdc_populate_config(struct msm_display_vdc_info *vdc_info, + int intf_width, int traffic_mode) +{ + int ret = 0; + + ret = sde_vdc_populate_core_params(vdc_info, intf_width); + if (ret) { + pr_err("failed to populate vdc core params %d\n", ret); + return ret; + } + + ret = sde_vdc_populate_lut_params(vdc_info); + if (ret) { + pr_err("failed to populate lut params %d\n", ret); + return ret; + } + + sde_vdc_intf_prog_params(vdc_info, intf_width); + + sde_vdc_ext_core_params(vdc_info, traffic_mode); + + return ret; +} diff --git a/msm/sde_vdc_helper.h b/msm/sde_vdc_helper.h new file mode 100644 index 000000000000..d72716d1af46 --- /dev/null +++ b/msm/sde_vdc_helper.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_VDC_HELPER_H__ +#define __SDE_VDC_HELPER_H__ + +#include "msm_drv.h" + +#define VDC_BPP(bits_per_pixel) (bits_per_pixel >> 4) + +#define VDC_NUM_BUF_RANGES (DSC_NUM_BUF_RANGES - 1) + +#define VDC_FLAT_QP_LUT_SIZE 8 +#define VDC_MAX_QP_LUT_SIZE 8 +#define VDC_TAR_DEL_LUT_SIZE 16 +#define VDC_LBDA_BRATE_LUT_SIZE 16 +#define VDC_LBDA_BF_LUT_SIZE 16 +#define VDC_LBDA_BRATE_REG_SIZE 64 + +#define VDC_VIDEO_MODE 0 +#define VDC_CMD_MODE 1 + +#define VDC_TRAFFIC_SYNC_PULSES 0 +#define VDC_TRAFFIC_SYNC_START_EVENTS 1 +#define VDC_TRAFFIC_BURST_MODE 2 + +#define MAX_PIPELINE_LATENCY 68 +#define OB_DATA_WIDTH 128 +#define OUT_BUF_FULL_THRESH 2 +#define OUT_BUF_UF_MARGIN 3 +#define OUT_BUF_OF_MARGIN_TC_10 5 +#define OUT_BUF_OF_MARGIN_OB 3 +#define OUTPUT_DATA_WIDTH 64 +#define OB0_RAM_DEPTH 912 +#define OB1_RAM_DEPTH 736 + +#define SSM_MAX_SE_SIZE 128 +#define RC_TARGET_RATE_EXTRA_FTBLS 2 + +#define NUM_ACTIVE_HS 1 +#define MAX_PIXELS_PER_HS_LINE 5120 + +int sde_vdc_populate_config(struct msm_display_vdc_info *vdc_info, + int intf_width, int traffic_mode); + +#endif /* __SDE_VDC_HELPER_H__ */ + From 85a5faaa74602f19ba6cef4b8859496886019f55 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Fri, 10 Jan 2020 14:00:29 -0800 Subject: [PATCH 03/10] disp: msm: add support for PPS command for VDC-m Add support for PPS command for VDC-m. This shall be sent from the encoder to the decoder such that both can produce the same model state. Change-Id: Iae48615eab7c91ef7ecc68b84334057de5090364 Signed-off-by: Abhinav Kumar --- msm/dsi/dsi_display.c | 7 +- msm/dsi/dsi_panel.c | 54 +++++++++----- msm/dsi/dsi_panel.h | 5 +- msm/sde_vdc_helper.c | 165 ++++++++++++++++++++++++++++++++++++++++++ msm/sde_vdc_helper.h | 14 +++- 5 files changed, 220 insertions(+), 25 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 5286d17910c9..484e84e2efad 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -7237,8 +7237,9 @@ int dsi_display_enable(struct dsi_display *display) } /* Block sending pps command if modeset is due to fps difference */ - if ((mode->priv_info->dsc_enabled) && - !(mode->dsi_mode_flags & DSI_MODE_FLAG_DMS_FPS)) { + if ((mode->priv_info->dsc_enabled || + mode->priv_info->vdc_enabled) && + !(mode->dsi_mode_flags & DSI_MODE_FLAG_DMS_FPS)) { rc = dsi_panel_update_pps(display->panel); if (rc) { DSI_ERR("[%s] panel pps cmd update failed, rc=%d\n", @@ -7406,7 +7407,7 @@ int dsi_display_update_pps(char *pps_cmd, void *disp) display = disp; mutex_lock(&display->display_lock); - memcpy(display->panel->dsc_pps_cmd, pps_cmd, DSI_CMD_PPS_SIZE); + memcpy(display->panel->dce_pps_cmd, pps_cmd, DSI_CMD_PPS_SIZE); mutex_unlock(&display->display_lock); return 0; diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 09f30b2decfb..dba11123806c 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -34,26 +34,37 @@ #define DEFAULT_PANEL_PREFILL_LINES 25 #define MIN_PREFILL_LINES 35 - -int dsi_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, char *buf, - int pps_id, u32 size) +static void dsi_dce_prepare_pps_header(char *buf, u32 pps_delay_ms) { char *bp; - char *dbgbp; - u32 header_size = 7; - dbgbp = buf; bp = buf; /* First 7 bytes are cmd header */ *bp++ = 0x0A; *bp++ = 1; *bp++ = 0; *bp++ = 0; - *bp++ = dsc->pps_delay_ms; + *bp++ = pps_delay_ms; *bp++ = 0; *bp++ = 128; +} - return sde_dsc_create_pps_buf_cmd(dsc, bp, pps_id, size - header_size); +static int dsi_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, + char *buf, int pps_id, u32 size) +{ + dsi_dce_prepare_pps_header(buf, dsc->pps_delay_ms); + buf += DSI_CMD_PPS_HDR_SIZE; + return sde_dsc_create_pps_buf_cmd(dsc, buf, pps_id, + size); +} + +static int dsi_vdc_create_pps_buf_cmd(struct msm_display_vdc_info *vdc, + char *buf, int pps_id, u32 size) +{ + dsi_dce_prepare_pps_header(buf, vdc->pps_delay_ms); + buf += DSI_CMD_PPS_HDR_SIZE; + return sde_vdc_create_pps_buf_cmd(vdc, buf, pps_id, + size); } static int dsi_panel_vreg_get(struct dsi_panel *panel) @@ -3771,17 +3782,22 @@ int dsi_panel_update_pps(struct dsi_panel *panel) set = &priv_info->cmd_sets[DSI_CMD_SET_PPS]; - rc = dsi_dsc_create_pps_buf_cmd(&priv_info->dsc, panel->dsc_pps_cmd, 0, - DSI_CMD_PPS_SIZE); - if (rc) { - DSI_ERR("failed to create pps cmd, rc=%d\n", rc); - goto error; - } - rc = dsi_panel_create_cmd_packets(panel->dsc_pps_cmd, - DSI_CMD_PPS_SIZE, 1, set->cmds); - if (rc) { - DSI_ERR("failed to create cmd packets, rc=%d\n", rc); - goto error; + if (priv_info->dsc_enabled) + dsi_dsc_create_pps_buf_cmd(&priv_info->dsc, + panel->dce_pps_cmd, 0, + DSI_CMD_PPS_SIZE - DSI_CMD_PPS_HDR_SIZE); + else if (priv_info->vdc_enabled) + dsi_vdc_create_pps_buf_cmd(&priv_info->vdc, + panel->dce_pps_cmd, 0, + DSI_CMD_PPS_SIZE - DSI_CMD_PPS_HDR_SIZE); + + if (priv_info->dsc_enabled || priv_info->vdc_enabled) { + rc = dsi_panel_create_cmd_packets(panel->dce_pps_cmd, + DSI_CMD_PPS_SIZE, 1, set->cmds); + if (rc) { + DSI_ERR("failed to create cmd packets, rc=%d\n", rc); + goto error; + } } rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PPS); diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index f5a38bcc7d0b..4b10e457a224 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _DSI_PANEL_H_ @@ -26,6 +26,7 @@ #define MAX_SV_BL_SCALE_LEVEL 65535 #define DSI_CMD_PPS_SIZE 135 +#define DSI_CMD_PPS_HDR_SIZE 7 #define DSI_MODE_MAX 32 enum dsi_panel_rotation { @@ -198,7 +199,7 @@ struct dsi_panel { bool te_using_watchdog_timer; u32 qsync_min_fps; - char dsc_pps_cmd[DSI_CMD_PPS_SIZE]; + char dce_pps_cmd[DSI_CMD_PPS_SIZE]; enum dsi_dms_mode dms_mode; bool sync_broadcast_en; diff --git a/msm/sde_vdc_helper.c b/msm/sde_vdc_helper.c index 9272289883a2..15b35648c11a 100644 --- a/msm/sde_vdc_helper.c +++ b/msm/sde_vdc_helper.c @@ -790,3 +790,168 @@ int sde_vdc_populate_config(struct msm_display_vdc_info *vdc_info, return ret; } + +int sde_vdc_create_pps_buf_cmd(struct msm_display_vdc_info *vdc_info, + char *buf, int pps_id, u32 len) +{ + char *bp = buf; + u32 i; + u32 slice_num_bits_ub, slice_num_bits_ldw; + + if (len < SDE_VDC_PPS_SIZE) + return -EINVAL; + + memset(buf, 0, len); + /* b0 */ + *bp++ = vdc_info->version_major; + /* b1 */ + *bp++ = vdc_info->version_minor; + /* b2 */ + *bp++ = vdc_info->version_release; + /* b3 */ + *bp++ = (pps_id & 0xff); /* pps1 */ + /* b4-b5 */ + *bp++ = ((vdc_info->frame_width >> 8) & 0xff); + *bp++ = (vdc_info->frame_width & 0x0ff); + /* b6-b7 */ + *bp++ = ((vdc_info->frame_height >> 8) & 0xff); + *bp++ = (vdc_info->frame_height & 0x0ff); + /* b8-b9 */ + *bp++ = ((vdc_info->slice_width >> 8) & 0xff); + *bp++ = (vdc_info->slice_width & 0x0ff); + /* b10-b11 */ + *bp++ = ((vdc_info->slice_height >> 8) & 0xff); + *bp++ = (vdc_info->slice_height & 0x0ff); + /* b12-b15 */ + *bp++ = ((vdc_info->slice_num_px >> 24) & 0xff); + *bp++ = ((vdc_info->slice_num_px >> 16) & 0xff); + *bp++ = ((vdc_info->slice_num_px >> 8) & 0xff); + *bp++ = (vdc_info->slice_num_px & 0x0ff); + /* b16-b17 */ + *bp++ = ((vdc_info->bits_per_pixel >> 8) & 0x3); + *bp++ = (vdc_info->bits_per_pixel & 0xff); + /* b18 */ + bp++; /* reserved */ + /* b19 */ + *bp++ = ((((vdc_info->bits_per_component - 8) >> 1) & 0x3) << 4)| + ((vdc_info->source_color_space & 0x3) << 2)| + (vdc_info->chroma_format & 0x3); + /* b20-b21 */ + bp++; /* reserved */ + bp++; /* reserved */ + + /* b22-b23 */ + *bp++ = ((vdc_info->chunk_size >> 8) & 0xff); + *bp++ = (vdc_info->chunk_size & 0x0ff); + + /* b24-b25 */ + bp++; /* reserved */ + bp++; /* reserved */ + + /* b26-b27 */ + *bp++ = ((vdc_info->rc_buffer_init_size >> 8) & 0xff); + *bp++ = (vdc_info->rc_buffer_init_size & 0x0ff); + + /* b28 */ + *bp++ = vdc_info->rc_stuffing_bits; + + /* b29 */ + *bp++ = vdc_info->rc_init_tx_delay; + + /* b30-b31 */ + *bp++ = ((vdc_info->rc_buffer_max_size >> 8) & 0xff); + *bp++ = (vdc_info->rc_buffer_max_size & 0x0ff); + + /* b32-b35 */ + *bp++ = ((vdc_info->rc_target_rate_threshold >> 24) & 0xff); + *bp++ = ((vdc_info->rc_target_rate_threshold >> 16) & 0xff); + *bp++ = ((vdc_info->rc_target_rate_threshold >> 8) & 0xff); + *bp++ = (vdc_info->rc_target_rate_threshold & 0x0ff); + + /* b36 */ + *bp++ = vdc_info->rc_tar_rate_scale; + /* b37 */ + *bp++ = vdc_info->rc_buffer_fullness_scale; + + /* b38-b39 */ + *bp++ = ((vdc_info->rc_fullness_offset_thresh >> 8) & 0xff); + *bp++ = (vdc_info->rc_fullness_offset_thresh & 0x0ff); + + /* b40-b42 */ + *bp++ = ((vdc_info->rc_fullness_offset_slope >> 16) & 0xff); + *bp++ = ((vdc_info->rc_fullness_offset_slope >> 8) & 0xff); + *bp++ = ((vdc_info->rc_fullness_offset_slope) & 0xff); + + /* b43 */ + *bp++ = (RC_TARGET_RATE_EXTRA_FTBLS & 0x0f); + /* b44 */ + *bp++ = vdc_info->flatqp_vf_fbls; + /* b45 */ + *bp++ = vdc_info->flatqp_vf_nbls; + /* b46 */ + *bp++ = vdc_info->flatqp_sw_fbls; + /* b47 */ + *bp++ = vdc_info->flatqp_sw_nbls; + + /* b48-b55 */ + for (i = 0; i < VDC_FLAT_QP_LUT_SIZE; i++) + *bp++ = vdc_info->flatness_qp_lut[i]; + + /* b56-b63 */ + for (i = 0; i < VDC_MAX_QP_LUT_SIZE; i++) + *bp++ = vdc_info->max_qp_lut[i]; + + /* b64-b79 */ + for (i = 0; i < VDC_TAR_DEL_LUT_SIZE; i++) + *bp++ = vdc_info->tar_del_lut[i]; + + /* b80 */ + bp++; /* reserved */ + + /* b81 */ + *bp++ = (((vdc_info->mppf_bpc_r_y & 0xf) << 4) | + (vdc_info->mppf_bpc_g_cb & 0xf)); + /* b82 */ + *bp++ = (((vdc_info->mppf_bpc_b_cr & 0xf) << 4) | + (vdc_info->mppf_bpc_y & 0xf)); + /* b83 */ + *bp++ = (((vdc_info->mppf_bpc_co & 0xf) << 4) | + (vdc_info->mppf_bpc_cg & 0xf)); + + /* b84 */ + bp++; /* reserved */ + /* b85 */ + bp++; /* reserved */ + /* b86 */ + bp++; /* reserved */ + + /* b87 */ + *bp++ = SSM_MAX_SE_SIZE; + + /* b88 */ + bp++; /* reserved */ + /* b89 */ + bp++; /* reserved */ + /* b90 */ + bp++; /* reserved */ + + /* b91 */ + slice_num_bits_ub = (vdc_info->slice_num_bits >> 32); + *bp++ = (slice_num_bits_ub & 0x0ff); + /* b92-b95 */ + slice_num_bits_ldw = (u32)vdc_info->slice_num_bits; + *bp++ = ((slice_num_bits_ldw >> 24) & 0xff); + *bp++ = ((slice_num_bits_ldw >> 16) & 0xff); + *bp++ = ((slice_num_bits_ldw >> 8) & 0xff); + *bp++ = (slice_num_bits_ldw & 0x0ff); + + /* b96 */ + bp++; + /* b97 */ + *bp++ = vdc_info->chunk_adj_bits; + /* b98-b99 */ + *bp++ = ((vdc_info->num_extra_mux_bits >> 8) & 0xff); + *bp++ = (vdc_info->num_extra_mux_bits & 0x0ff); + + return 0; +} diff --git a/msm/sde_vdc_helper.h b/msm/sde_vdc_helper.h index d72716d1af46..a8102874f05c 100644 --- a/msm/sde_vdc_helper.h +++ b/msm/sde_vdc_helper.h @@ -42,8 +42,20 @@ #define NUM_ACTIVE_HS 1 #define MAX_PIXELS_PER_HS_LINE 5120 +#define SDE_VDC_PPS_SIZE 128 + +/** + * sde_vdc_populate_config - populates the VDC encoder parameters + * for a given panel configuration + */ int sde_vdc_populate_config(struct msm_display_vdc_info *vdc_info, int intf_width, int traffic_mode); -#endif /* __SDE_VDC_HELPER_H__ */ +/** + * sde_vdc_create_pps_buf_cmd- creates the PPS buffer from the VDC + * parameters according to the VDC specification + */ +int sde_vdc_create_pps_buf_cmd(struct msm_display_vdc_info *vdc_info, + char *buf, int pps_id, u32 size); +#endif /* __SDE_VDC_HELPER_H__ */ From 3e0f65f8822cd56534f713c26d2b317688c8e26f Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Mon, 19 Aug 2019 18:06:29 -0700 Subject: [PATCH 04/10] disp: msm: program DSI compression registers for VDC-m Add the support to program DSI compression registers for VDC-m. These are calculated based on the VDC parameters and mode information. Change-Id: I09b163a496842331d5f2a78371f380180b3a15b8 Signed-off-by: Abhinav Kumar --- msm/dsi/dsi_ctrl_hw_cmn.c | 147 +++++++++++++++++++++++++++----------- msm/dsi/dsi_panel.c | 3 + msm/sde_vdc_helper.c | 2 +- msm/sde_vdc_helper.h | 2 + 4 files changed, 113 insertions(+), 41 deletions(-) diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index cc6cac32eb61..793a14d12723 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -14,6 +14,7 @@ #include "dsi_catalog.h" #include "sde_dbg.h" #include "sde_dsc_helper.h" +#include "sde_vdc_helper.h" #define MMSS_MISC_CLAMP_REG_OFF 0x0014 #define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21)) @@ -22,6 +23,22 @@ #define DSI_CTRL_DMA_LINK_SEL (BIT(12)|BIT(13)) #define DSI_CTRL_MDP0_LINK_SEL (BIT(20)|BIT(22)) +static bool dsi_dsc_compression_enabled(struct dsi_mode_info *mode) +{ + return (mode->dsc_enabled && mode->dsc); +} + +static bool dsi_vdc_compression_enabled(struct dsi_mode_info *mode) +{ + return (mode->vdc_enabled && mode->vdc); +} + +static bool dsi_compression_enabled(struct dsi_mode_info *mode) +{ + return (dsi_dsc_compression_enabled(mode) || + dsi_vdc_compression_enabled(mode)); +} + /* Unsupported formats default to RGB888 */ static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { 0x6, 0x7, 0x8, 0x8, 0x0, 0x3, 0x4 }; @@ -263,6 +280,33 @@ void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl, SDE_EVT32(ctrl->index, enable); } +/** + * get_dce_params() - get the dce params + * @mode: mode information. + * @width: width to be filled up + * @bytes_per_pkt: Bytes per packet to be filled up + * @pkt_per_line: Packet per line parameter + * @eol_byte_num: End-of-line byte number + * + * Get the compression parameters based on compression type. + */ +static void dsi_ctrl_hw_cmn_get_vid_dce_params(struct dsi_mode_info *mode, + u32 *width, u32 *bytes_per_pkt, u32 *pkt_per_line, + u32 *eol_byte_num) +{ + if (dsi_dsc_compression_enabled(mode)) { + *width = mode->dsc->pclk_per_line; + *bytes_per_pkt = mode->dsc->bytes_per_pkt; + *pkt_per_line = mode->dsc->pkt_per_line; + *eol_byte_num = mode->dsc->eol_byte_num; + } else if (dsi_vdc_compression_enabled(mode)) { + *width = mode->vdc->pclk_per_line; + *bytes_per_pkt = mode->vdc->bytes_per_pkt; + *pkt_per_line = mode->vdc->pkt_per_line; + *eol_byte_num = mode->vdc->eol_byte_num; + } +} + /** * set_video_timing() - set up the timing for video frame * @ctrl: Pointer to controller host hardware. @@ -276,25 +320,26 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, u32 reg = 0; u32 hs_start = 0; u32 hs_end, active_h_start, active_h_end, h_total, width = 0; + u32 bytes_per_pkt, pkt_per_line, eol_byte_num; u32 vs_start = 0, vs_end = 0; u32 vpos_start = 0, vpos_end, active_v_start, active_v_end, v_total; - if (mode->dsc_enabled && mode->dsc) { - width = mode->dsc->pclk_per_line; - reg = mode->dsc->bytes_per_pkt << 16; - reg |= (0x0b << 8); /* dtype of compressed image */ + if (dsi_compression_enabled(mode)) { + dsi_ctrl_hw_cmn_get_vid_dce_params(mode, + &width, &bytes_per_pkt, + &pkt_per_line, &eol_byte_num); + reg = bytes_per_pkt << 16; + /* data type of compressed image */ + reg |= (0x0b << 8); /* * pkt_per_line: * 0 == 1 pkt * 1 == 2 pkt * 2 == 4 pkt - * 3 pkt is not support + * 3 pkt is not supported */ - if (mode->dsc->pkt_per_line == 4) - reg |= (mode->dsc->pkt_per_line - 2) << 6; - else - reg |= (mode->dsc->pkt_per_line - 1) << 6; - reg |= mode->dsc->eol_byte_num << 4; + reg |= (pkt_per_line >> 1) << 6; + reg |= eol_byte_num << 4; reg |= 1; DSI_W32(ctrl, DSI_VIDEO_COMPRESSION_MODE_CTRL, reg); } else { @@ -358,52 +403,44 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, u32 height_final; u32 stream_total = 0, stream_ctrl = 0; u32 reg_ctrl = 0, reg_ctrl2 = 0, data = 0; + u32 reg = 0, offset = 0; + int pic_width, this_frame_slices, intf_ip_w; + u32 pkt_per_line, eol_byte_num, bytes_in_slice; if (roi && (!roi->w || !roi->h)) return; - if (mode->dsc_enabled && mode->dsc) { - u32 reg = 0; - u32 offset = 0; - int pic_width, this_frame_slices, intf_ip_w; + if (dsi_dsc_compression_enabled(mode)) { struct msm_display_dsc_info dsc; - memcpy(&dsc, mode->dsc, sizeof(dsc)); pic_width = roi ? roi->w : mode->h_active; + memcpy(&dsc, mode->dsc, sizeof(dsc)); + this_frame_slices = pic_width / dsc.config.slice_width; intf_ip_w = this_frame_slices * dsc.config.slice_width; + sde_dsc_populate_dsc_private_params(&dsc, intf_ip_w); - if (vc_id != 0) - offset = 16; - reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL); - reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2); width_final = dsc.pclk_per_line; stride_final = dsc.bytes_per_pkt; - height_final = roi ? roi->h : mode->v_active; + pkt_per_line = dsc.pkt_per_line; + eol_byte_num = dsc.eol_byte_num; + bytes_in_slice = dsc.bytes_in_slice; + } else if (dsi_vdc_compression_enabled(mode)) { + struct msm_display_vdc_info vdc; - reg = 0x39 << 8; - /* - * pkt_per_line: - * 0 == 1 pkt - * 1 == 2 pkt - * 2 == 4 pkt - * 3 pkt is not support - */ - if (dsc.pkt_per_line == 4) - reg |= (dsc.pkt_per_line - 2) << 6; - else - reg |= (dsc.pkt_per_line - 1) << 6; - reg |= dsc.eol_byte_num << 4; - reg |= 1; + pic_width = roi ? roi->w : mode->h_active; + memcpy(&vdc, mode->vdc, sizeof(vdc)); + this_frame_slices = pic_width / vdc.slice_width; + intf_ip_w = this_frame_slices * vdc.slice_width; - reg_ctrl &= ~(0xFFFF << offset); - reg_ctrl |= (reg << offset); - reg_ctrl2 &= ~(0xFFFF << offset); - reg_ctrl2 |= (dsc.bytes_in_slice << offset); + sde_vdc_intf_prog_params(&vdc, intf_ip_w); - DSI_CTRL_HW_DBG(ctrl, "reg_ctrl 0x%x reg_ctrl2 0x%x\n", - reg_ctrl, reg_ctrl2); + width_final = vdc.pclk_per_line; + stride_final = vdc.bytes_per_pkt; + pkt_per_line = vdc.pkt_per_line; + eol_byte_num = vdc.eol_byte_num; + bytes_in_slice = vdc.bytes_in_slice; } else if (roi) { width_final = roi->w; stride_final = roi->w * 3; @@ -414,6 +451,36 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, height_final = mode->v_active; } + if (dsi_compression_enabled(mode)) { + pic_width = roi ? roi->w : mode->h_active; + height_final = roi ? roi->h : mode->v_active; + reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL); + reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2); + + if (vc_id != 0) + offset = 16; + + reg = 0x39 << 8; + /* + * pkt_per_line: + * 0 == 1 pkt + * 1 == 2 pkt + * 2 == 4 pkt + * 3 pkt is not supported + */ + reg |= (pkt_per_line >> 1) << 6; + reg |= eol_byte_num << 4; + reg |= 1; + + reg_ctrl &= ~(0xFFFF << offset); + reg_ctrl |= (reg << offset); + reg_ctrl2 &= ~(0xFFFF << offset); + reg_ctrl2 |= (bytes_in_slice << offset); + + DSI_CTRL_HW_DBG(ctrl, "reg_ctrl 0x%x reg_ctrl2 0x%x\n", + reg_ctrl, reg_ctrl2); + } + /* HS Timer value */ DSI_W32(ctrl, DSI_HS_TIMER_CTRL, 0x3FD08); diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index dba11123806c..d24a6465bdbe 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -3729,6 +3729,9 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel, config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled; config->video_timing.dsc = &mode->priv_info->dsc; + config->video_timing.vdc_enabled = mode->priv_info->vdc_enabled; + config->video_timing.vdc = &mode->priv_info->vdc; + if (dyn_clk_caps->dyn_clk_support) config->bit_clk_rate_hz_override = mode->timing.clk_rate_hz; else diff --git a/msm/sde_vdc_helper.c b/msm/sde_vdc_helper.c index 15b35648c11a..fea7a6806670 100644 --- a/msm/sde_vdc_helper.c +++ b/msm/sde_vdc_helper.c @@ -582,7 +582,7 @@ static int sde_vdc_populate_core_params(struct msm_display_vdc_info *vdc_info, return 0; } -static void sde_vdc_intf_prog_params(struct msm_display_vdc_info *vdc_info, +void sde_vdc_intf_prog_params(struct msm_display_vdc_info *vdc_info, int intf_width) { int slice_per_pkt, slice_per_intf; diff --git a/msm/sde_vdc_helper.h b/msm/sde_vdc_helper.h index a8102874f05c..b446b7cc9f8d 100644 --- a/msm/sde_vdc_helper.h +++ b/msm/sde_vdc_helper.h @@ -57,5 +57,7 @@ int sde_vdc_populate_config(struct msm_display_vdc_info *vdc_info, */ int sde_vdc_create_pps_buf_cmd(struct msm_display_vdc_info *vdc_info, char *buf, int pps_id, u32 size); +void sde_vdc_intf_prog_params(struct msm_display_vdc_info *vdc_info, + int intf_width); #endif /* __SDE_VDC_HELPER_H__ */ From 88a43f2441a4ea6716594e7af207687988b22773 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 21 Aug 2019 16:50:06 -0700 Subject: [PATCH 05/10] disp: msm: sde: add hardware catalog support for VDC-m block Add hardware catalog support for VDC-m block to parse the register offsets and feature capabilities. Change-Id: I1bfbc4b6e7e9f34738d49fecdef4b427a0ccded7 Signed-off-by: Abhinav Kumar --- msm/sde/sde_hw_catalog.c | 103 +++++++++++++++++++++++++++++++++++++++ msm/sde/sde_hw_catalog.h | 47 ++++++++++++++++++ msm/sde/sde_hw_mdss.h | 9 +++- 3 files changed, 158 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 3ab9a242246f..9dcb6906b64f 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -318,6 +318,15 @@ enum { DSC_PROP_MAX, }; +enum { + VDC_OFF, + VDC_LEN, + VDC_REV, + VDC_ENC, + VDC_CTL, + VDC_PROP_MAX, +}; + enum { DS_TOP_OFF, DS_TOP_LEN, @@ -710,6 +719,14 @@ static struct sde_prop_type dsc_prop[] = { {DSC_422, "qcom,sde-dsc-native422-supp", false, PROP_TYPE_U32_ARRAY} }; +static struct sde_prop_type vdc_prop[] = { + {VDC_OFF, "qcom,sde-vdc-off", false, PROP_TYPE_U32_ARRAY}, + {VDC_LEN, "qcom,sde-vdc-size", false, PROP_TYPE_U32}, + {VDC_REV, "qcom,sde-vdc-hw-rev", false, PROP_TYPE_STRING}, + {VDC_ENC, "qcom,sde-vdc-enc", false, PROP_TYPE_U32_ARRAY}, + {VDC_CTL, "qcom,sde-vdc-ctl", false, PROP_TYPE_U32_ARRAY}, +}; + static struct sde_prop_type cdm_prop[] = { {HW_OFF, "qcom,sde-cdm-off", false, PROP_TYPE_U32_ARRAY}, {HW_LEN, "qcom,sde-cdm-size", false, PROP_TYPE_U32}, @@ -2784,6 +2801,85 @@ end: return rc; }; +static int sde_vdc_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[MAX_BLOCKS], i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[VDC_PROP_MAX]; + u32 off_count, vdc_rev; + const char *rev; + struct sde_vdc_cfg *vdc; + struct sde_vdc_sub_blks *sblk; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(VDC_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, vdc_prop, ARRAY_SIZE(vdc_prop), prop_count, + &off_count); + if (rc) + goto end; + + sde_cfg->vdc_count = off_count; + + rc = of_property_read_string(np, vdc_prop[VDC_REV].prop_name, &rev); + if ((rc == -EINVAL) || (rc == -ENODATA)) { + vdc_rev = SDE_VDC_HW_REV_1_1; + rc = 0; + } else if (!rc && !strcmp(rev, "vdc_1_1")) { + vdc_rev = SDE_VDC_HW_REV_1_1; + rc = 0; + } else { + SDE_ERROR("invalid vdc configuration\n"); + } + + rc = _read_dt_entry(np, vdc_prop, ARRAY_SIZE(vdc_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + vdc = sde_cfg->vdc + i; + + sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); + if (!sblk) { + rc = -ENOMEM; + /* catalog deinit will release the allocated blocks */ + goto end; + } + vdc->sblk = sblk; + + vdc->base = PROP_VALUE_ACCESS(prop_value, VDC_OFF, i); + vdc->id = VDC_0 + i; + vdc->len = PROP_VALUE_ACCESS(prop_value, VDC_LEN, 0); + snprintf(vdc->name, SDE_HW_BLK_NAME_LEN, "vdc_%u", + vdc->id - VDC_0); + + if (!prop_exists[VDC_LEN]) + vdc->len = DEFAULT_SDE_HW_BLOCK_LEN; + + sblk->enc.base = PROP_VALUE_ACCESS(prop_value, + VDC_ENC, i); + sblk->ctl.base = PROP_VALUE_ACCESS(prop_value, + VDC_CTL, i); + set_bit(SDE_VDC_HW_REV_1_1, &vdc->features); + } + +end: + kfree(prop_value); + return rc; +}; + static int sde_cdm_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) { @@ -4542,6 +4638,9 @@ void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg) for (i = 0; i < sde_cfg->pingpong_count; i++) kfree(sde_cfg->pingpong[i].sblk); + for (i = 0; i < sde_cfg->vdc_count; i++) + kfree(sde_cfg->vdc[i].sblk); + for (i = 0; i < sde_cfg->vbif_count; i++) { kfree(sde_cfg->vbif[i].dynamic_ot_rd_tbl.cfg); kfree(sde_cfg->vbif[i].dynamic_ot_wr_tbl.cfg); @@ -4634,6 +4733,10 @@ struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 hw_rev) if (rc) goto end; + rc = sde_vdc_parse_dt(np, sde_cfg); + if (rc) + goto end; + rc = sde_pp_parse_dt(np, sde_cfg); if (rc) goto end; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index d147bb23f77a..ac8f81fd4e35 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -404,6 +404,19 @@ enum { SDE_DSC_MAX }; +/** VDC sub-blocks/features + * @SDE_VDC_HW_REV_1_1 vdc block supports vdc 1.1 only + * @SDE_VDC_ENC vdc encoder sub block + * @SDE_VDC_CTL vdc ctl sub block + * @SDE_VDC_MAX + */ +enum { + SDE_VDC_HW_REV_1_1, + SDE_VDC_ENC, + SDE_VDC_CTL, + SDE_VDC_MAX +}; + /** * CTL sub-blocks * @SDE_CTL_SPLIT_DISPLAY CTL supports video mode split display @@ -594,6 +607,14 @@ struct sde_dsc_blk { SDE_HW_SUBBLK_INFO; }; +/** + * struct sde_vdc_blk : VDC Encoder sub-blk information + * @info: HW register and features supported by this sub-blk + */ +struct sde_vdc_blk { + SDE_HW_SUBBLK_INFO; +}; + /** * struct sde_format_extended - define sde specific pixel format+modifier * @fourcc_format: Base FOURCC pixel format code @@ -760,6 +781,15 @@ struct sde_dsc_sub_blks { struct sde_dsc_blk ctl; }; +/** + * struct sde_vdc_sub_blks : VDC sub-blks + * + */ +struct sde_vdc_sub_blks { + struct sde_vdc_blk enc; + struct sde_vdc_blk ctl; +}; + struct sde_wb_sub_blocks { u32 maxlinewidth; }; @@ -993,6 +1023,20 @@ struct sde_dsc_cfg { struct sde_dsc_sub_blks *sblk; }; +/** + * struct sde_vdc_cfg - information of VDC blocks + * @id enum identifying this block + * @base register offset of this block + * @len: length of hardware block + * @features bit mask identifying sub-blocks/features + * @enc VDC encoder register offset(relative to VDC base) + * @ctl VDC Control register offset(relative to VDC base) + */ +struct sde_vdc_cfg { + SDE_HW_BLK_INFO; + struct sde_vdc_sub_blks *sblk; +}; + /** * struct sde_cdm_cfg - information of chroma down blocks * @id enum identifying this block @@ -1442,6 +1486,9 @@ struct sde_mdss_cfg { u32 dsc_count; struct sde_dsc_cfg dsc[MAX_BLOCKS]; + u32 vdc_count; + struct sde_vdc_cfg vdc[MAX_BLOCKS]; + u32 cdm_count; struct sde_cdm_cfg cdm[MAX_BLOCKS]; diff --git a/msm/sde/sde_hw_mdss.h b/msm/sde/sde_hw_mdss.h index 6a75881176ce..3f9ed4b535e1 100644 --- a/msm/sde/sde_hw_mdss.h +++ b/msm/sde/sde_hw_mdss.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_HW_MDSS_H @@ -230,6 +230,13 @@ enum sde_dsc { DSC_MAX }; +enum sde_vdc { + VDC_NONE = 0, + VDC_0, + VDC_1, + VDC_MAX +}; + enum sde_intf { INTF_0 = 1, INTF_1, From d88b5b5c6704f5a42b2bb75d12159391f632580f Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 21 Aug 2019 19:59:43 -0700 Subject: [PATCH 06/10] disp: msm: add hardware register ops for VDC-m block Add hardware register set and programming for VDC-m block. Change-Id: I60ef27b507284521abdd10bb679a85303475ddc3 Signed-off-by: Abhinav Kumar --- msm/Makefile | 1 + msm/msm_drv.h | 4 + msm/sde/sde_hw_mdss.h | 6 + msm/sde/sde_hw_vdc.c | 453 ++++++++++++++++++++++++++++++++++++++++++ msm/sde/sde_hw_vdc.h | 88 ++++++++ msm/sde/sde_rm.c | 119 +++++++++++ 6 files changed, 671 insertions(+) create mode 100644 msm/sde/sde_hw_vdc.c create mode 100644 msm/sde/sde_hw_vdc.h diff --git a/msm/Makefile b/msm/Makefile index dd8f77026878..36c65e913409 100644 --- a/msm/Makefile +++ b/msm/Makefile @@ -70,6 +70,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ sde/sde_hw_reg_dma_v1.o \ sde/sde_hw_dsc.o \ sde/sde_hw_dsc_1_2.o \ + sde/sde_hw_vdc.o \ sde/sde_hw_ds.o \ sde/sde_fence.o \ sde/sde_hw_qdss.o \ diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 02d95d872d20..ac93e1f28d2b 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -220,10 +220,12 @@ enum msm_mdp_conn_property { * enum msm_display_compression_type - compression method used for pixel stream * @MSM_DISPLAY_COMPRESSION_NONE: Pixel data is not compressed * @MSM_DISPLAY_COMPRESSION_DSC: DSC compresison is used + * @MSM_DISPLAY_COMPRESSION_VDC: VDC compresison is used */ enum msm_display_compression_type { MSM_DISPLAY_COMPRESSION_NONE, MSM_DISPLAY_COMPRESSION_DSC, + MSM_DISPLAY_COMPRESSION_VDC }; /** @@ -652,6 +654,7 @@ struct msm_mode_info { * struct msm_resource_caps_info - defines hw resources * @num_lm number of layer mixers available * @num_dsc number of dsc available + * @num_vdc number of vdc available * @num_ctl number of ctl available * @num_3dmux number of 3d mux available * @max_mixer_width: max width supported by layer mixer @@ -659,6 +662,7 @@ struct msm_mode_info { struct msm_resource_caps_info { uint32_t num_lm; uint32_t num_dsc; + uint32_t num_vdc; uint32_t num_ctl; uint32_t num_3dmux; uint32_t max_mixer_width; diff --git a/msm/sde/sde_hw_mdss.h b/msm/sde/sde_hw_mdss.h index 3f9ed4b535e1..ff2c19cff2f8 100644 --- a/msm/sde/sde_hw_mdss.h +++ b/msm/sde/sde_hw_mdss.h @@ -103,6 +103,7 @@ enum sde_hw_blk_type { SDE_HW_BLK_INTF, SDE_HW_BLK_WB, SDE_HW_BLK_DSC, + SDE_HW_BLK_VDC, SDE_HW_BLK_MERGE_3D, SDE_HW_BLK_QDSS, SDE_HW_BLK_MAX, @@ -526,6 +527,7 @@ struct sde_mdss_color { #define SDE_DBG_MASK_UIDLE (1 << 15) #define SDE_DBG_MASK_SID (1 << 15) #define SDE_DBG_MASK_QDSS (1 << 16) +#define SDE_DBG_MASK_VDC (1 << 17) /** * struct sde_hw_cp_cfg: hardware dspp/lm feature payload. @@ -603,10 +605,12 @@ struct sde_sspp_index_info { * @ctl_ids: Stores the valid MDSS ctl block ids for the current mode * @lm_ids: Stores the valid MDSS layer mixer block ids for the current mode * @dsc_ids: Stores the valid MDSS DSC block ids for the current mode + * @vdc_ids: Stores the valid MDSS VDC block ids for the current mode * @pipes: Array of sspp info detected on this display * @ctl_cnt: Stores the active number of MDSS "top" blks of the current mode * @lm_cnt: Stores the active number of MDSS "LM" blks for the current mode * @dsc_cnt: Stores the active number of MDSS "dsc" blks for the current mode + * @vdc_cnt: Stores the valid MDSS VDC block ids for the current mode * @pipe_cnt: Stores the active number of "sspp" blks connected */ struct sde_splash_display { @@ -616,10 +620,12 @@ struct sde_splash_display { u8 ctl_ids[MAX_DATA_PATH_PER_DSIPLAY]; u8 lm_ids[MAX_DATA_PATH_PER_DSIPLAY]; u8 dsc_ids[MAX_DATA_PATH_PER_DSIPLAY]; + u8 vdc_ids[MAX_DATA_PATH_PER_DSIPLAY]; struct sde_sspp_index_info pipes[MAX_DATA_PATH_PER_DSIPLAY]; u8 ctl_cnt; u8 lm_cnt; u8 dsc_cnt; + u8 vdc_cnt; u8 pipe_cnt; }; diff --git a/msm/sde/sde_hw_vdc.c b/msm/sde/sde_hw_vdc.c new file mode 100644 index 000000000000..04a659a58ad9 --- /dev/null +++ b/msm/sde/sde_hw_vdc.c @@ -0,0 +1,453 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#include "sde_hw_mdss.h" +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_dsc.h" +#include "sde_hw_pingpong.h" +#include "sde_dbg.h" +#include "sde_kms.h" +#include "sde_hw_vdc.h" +#include "sde_vdc_helper.h" + +#define VDC_CMN_MAIN_CNF 0x00 + +/* SDE_VDC_ENC register offsets */ +#define ENC_OUT_BF_CTRL 0x00 +#define ENC_GENERAL_STATUS 0x04 +#define ENC_HSLICE_STATUS 0x08 +#define ENC_OUT_STATUS 0x0C +#define ENC_INT_STAT 0x10 +#define ENC_INT_CLR 0x14 +#define ENC_INT_ENABLE 0x18 +#define ENC_R2B_BUF_CTRL 0x1c +#define ENC_ORIG_SLICE 0x40 +#define ENC_DF_CTRL 0x44 +#define ENC_VDC_VERSION 0x80 +#define ENC_VDC_FRAME_SIZE 0x84 +#define ENC_VDC_SLICE_SIZE 0x88 +#define ENC_VDC_SLICE_PX 0x8c +#define ENC_VDC_MAIN_CONF 0x90 +#define ENC_VDC_CHUNK_SIZE 0x94 +#define ENC_VDC_RC_CONFIG_0 0x98 +#define ENC_VDC_RC_CONFIG_1 0x9c +#define ENC_VDC_RC_CONFIG_2 0xa0 +#define ENC_VDC_RC_CONFIG_3 0xa4 +#define ENC_VDC_RC_CONFIG_4 0xa8 +#define ENC_VDC_FLAT_CONFIG 0xac +#define ENC_VDC_FLAT_LUT_3_0 0xb0 +#define ENC_VDC_FLAT_LUT_7_4 0xb4 +#define ENC_VDC_MAX_QP_LUT_3_0 0xb8 +#define ENC_VDC_MAX_QP_LUT_7_4 0xbc +#define ENC_VDC_TAR_RATE_LUT_3_0 0xc0 +#define ENC_VDC_TAR_RATE_LUT_7_4 0xc4 +#define ENC_VDC_TAR_RATE_LUT_11_8 0xc8 +#define ENC_VDC_TAR_RATE_LUT_15_12 0xcc +#define ENC_VDC_MPPF_CONFIG 0xd0 +#define ENC_VDC_SSM_CONFIG 0xd4 +#define ENC_VDC_SLICE_NUM_BITS_0 0xd8 +#define ENC_VDC_SLICE_NUM_BITS_1 0xdc +#define ENC_VDC_RC_PRECOMPUTE 0xe0 +#define ENC_VDC_MPP_CONFIG 0xe4 +#define ENC_VDC_LBDA_BRATE_LUT 0x100 +#define ENC_VDC_LBDA_BF_LUT 0x180 +#define ENC_VDC_OTHER_RC 0x1c0 + +/* SDE_VDC_CTL register offsets */ +#define VDC_CTL 0x00 +#define VDC_CFG 0x04 +#define VDC_DATA_IN_SWAP 0x08 +#define VDC_CLK_CTRL 0x0C + +#define VDC_CTL_BLOCK_SIZE 0x300 + +static inline _vdc_subblk_offset(struct sde_hw_vdc *hw_vdc, int s_id, + u32 *idx) +{ + int rc = 0; + const struct sde_vdc_sub_blks *sblk; + + if (!hw_vdc) + return -EINVAL; + + sblk = hw_vdc->caps->sblk; + + switch (s_id) { + case SDE_VDC_ENC: + *idx = sblk->enc.base; + break; + case SDE_VDC_CTL: + *idx = sblk->ctl.base; + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static void sde_hw_vdc_disable(struct sde_hw_vdc *hw_vdc) +{ + struct sde_hw_blk_reg_map *vdc_reg; + u32 idx; + + if (!hw_vdc) + return; + + if (_vdc_subblk_offset(hw_vdc, SDE_VDC_CTL, &idx)) + return; + + vdc_reg = &hw_vdc->hw; + SDE_REG_WRITE(vdc_reg, VDC_CFG + idx, 0); + + /* common register */ + SDE_REG_WRITE(vdc_reg, VDC_CMN_MAIN_CNF, 0); +} + +static void sde_hw_vdc_config(struct sde_hw_vdc *hw_vdc, + struct msm_display_vdc_info *vdc) +{ + struct sde_hw_blk_reg_map *vdc_reg = &hw_vdc->hw; + u32 idx; + u32 data = 0; + int i = 0; + u8 bits_per_component; + int addr_off = 0; + u32 slice_num_bits_ub, slice_num_bits_ldw; + + if (!hw_vdc) + return; + + if (_vdc_subblk_offset(hw_vdc, SDE_VDC_ENC, &idx)) + return; + + data = ((vdc->ob1_max_addr & 0xffff) << 16); + data |= (vdc->ob0_max_addr & 0xffff); + SDE_REG_WRITE(vdc_reg, ENC_OUT_BF_CTRL + idx, data); + + data = ((vdc->r2b1_max_addr & 0xffff) << 16); + data |= (vdc->r2b0_max_addr & 0xffff); + SDE_REG_WRITE(vdc_reg, ENC_R2B_BUF_CTRL + idx, data); + + data = vdc->slice_width_orig; + SDE_REG_WRITE(vdc_reg, ENC_ORIG_SLICE + idx, data); + + data = 0; + if (vdc->panel_mode == VDC_VIDEO_MODE) + data |= BIT(9); + data |= ((vdc->num_of_active_ss - 1) << 12); + data |= vdc->initial_lines; + SDE_REG_WRITE(vdc_reg, ENC_DF_CTRL + idx, data); + + data = 0; + data |= (vdc->version_major << 24); + data |= (vdc->version_minor << 16); + data |= (vdc->version_release << 8); + SDE_REG_WRITE(vdc_reg, ENC_VDC_VERSION + idx, data); + + data = 0; + data |= (vdc->frame_width << 16); + data |= vdc->frame_height; + SDE_REG_WRITE(vdc_reg, ENC_VDC_FRAME_SIZE + idx, data); + + data = 0; + data |= (vdc->slice_width << 16); + data |= vdc->slice_height; + SDE_REG_WRITE(vdc_reg, ENC_VDC_SLICE_SIZE + idx, data); + + SDE_REG_WRITE(vdc_reg, ENC_VDC_SLICE_PX + idx, + vdc->slice_num_px); + + data = 0; + data |= (vdc->bits_per_pixel << 16); + if (vdc->bits_per_component == 8) + bits_per_component = 0; + else if (vdc->bits_per_component == 10) + bits_per_component = 1; + else + bits_per_component = 2; + data |= (bits_per_component << 4); + data |= (vdc->source_color_space << 2); + data |= vdc->chroma_format; + SDE_REG_WRITE(vdc_reg, ENC_VDC_MAIN_CONF + idx, + data); + + SDE_REG_WRITE(vdc_reg, ENC_VDC_CHUNK_SIZE + idx, + vdc->chunk_size); + + SDE_REG_WRITE(vdc_reg, ENC_VDC_RC_CONFIG_0 + idx, + vdc->rc_buffer_init_size); + + data = 0; + data |= (vdc->rc_stuffing_bits << 24); + data |= (vdc->rc_init_tx_delay << 16); + data |= vdc->rc_buffer_max_size; + SDE_REG_WRITE(vdc_reg, ENC_VDC_RC_CONFIG_1 + idx, data); + + SDE_REG_WRITE(vdc_reg, ENC_VDC_RC_CONFIG_2 + idx, + vdc->rc_target_rate_threshold); + + data = 0; + data |= (vdc->rc_tar_rate_scale << 24); + data |= (vdc->rc_buffer_fullness_scale << 16); + data |= vdc->rc_fullness_offset_thresh; + + SDE_REG_WRITE(vdc_reg, ENC_VDC_RC_CONFIG_3 + idx, data); + + data = 0; + data |= (vdc->rc_fullness_offset_slope << 8); + data |= RC_TARGET_RATE_EXTRA_FTBLS; + + SDE_REG_WRITE(vdc_reg, ENC_VDC_RC_CONFIG_4 + idx, data); + + data = 0; + data |= (vdc->flatqp_vf_fbls << 24); + data |= (vdc->flatqp_vf_nbls << 16); + data |= (vdc->flatqp_sw_fbls << 8); + data |= vdc->flatqp_sw_nbls; + SDE_REG_WRITE(vdc_reg, ENC_VDC_FLAT_CONFIG + idx, data); + + data = 0; + data |= (vdc->flatness_qp_lut[0] << 24); + data |= (vdc->flatness_qp_lut[1] << 16); + data |= (vdc->flatness_qp_lut[2] << 8); + data |= vdc->flatness_qp_lut[3]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_FLAT_LUT_3_0 + idx, data); + + data = 0; + data |= (vdc->flatness_qp_lut[4] << 24); + data |= (vdc->flatness_qp_lut[5] << 16); + data |= (vdc->flatness_qp_lut[6] << 8); + data |= vdc->flatness_qp_lut[7]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_FLAT_LUT_7_4 + idx, data); + + data = 0; + data |= (vdc->max_qp_lut[0] << 24); + data |= (vdc->max_qp_lut[1] << 16); + data |= (vdc->max_qp_lut[2] << 8); + data |= vdc->max_qp_lut[3]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_MAX_QP_LUT_3_0 + idx, data); + + data = 0; + data |= (vdc->max_qp_lut[4] << 24); + data |= (vdc->max_qp_lut[5] << 16); + data |= (vdc->max_qp_lut[6] << 8); + data |= vdc->max_qp_lut[7]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_MAX_QP_LUT_7_4 + idx, data); + + data = 0; + data |= (vdc->tar_del_lut[0] << 24); + data |= (vdc->tar_del_lut[1] << 16); + data |= (vdc->tar_del_lut[2] << 8); + data |= vdc->tar_del_lut[3]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_TAR_RATE_LUT_3_0 + idx, data); + + data = 0; + data |= (vdc->tar_del_lut[4] << 24); + data |= (vdc->tar_del_lut[5] << 16); + data |= (vdc->tar_del_lut[6] << 8); + data |= vdc->tar_del_lut[7]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_TAR_RATE_LUT_7_4 + idx, data); + + data = 0; + data |= (vdc->tar_del_lut[8] << 24); + data |= (vdc->tar_del_lut[9] << 16); + data |= (vdc->tar_del_lut[10] << 8); + data |= vdc->tar_del_lut[11]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_TAR_RATE_LUT_11_8 + idx, data); + + data = 0; + data |= (vdc->tar_del_lut[12] << 24); + data |= (vdc->tar_del_lut[13] << 16); + data |= (vdc->tar_del_lut[14] << 8); + data |= vdc->tar_del_lut[15]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_TAR_RATE_LUT_15_12 + idx, data); + + data = 0; + data |= (vdc->mppf_bpc_r_y << 20); + data |= (vdc->mppf_bpc_g_cb << 16); + data |= (vdc->mppf_bpc_b_cr << 12); + data |= (vdc->mppf_bpc_y << 8); + data |= (vdc->mppf_bpc_co << 4); + data |= vdc->mppf_bpc_cg; + SDE_REG_WRITE(vdc_reg, ENC_VDC_MPPF_CONFIG + idx, data); + + SDE_REG_WRITE(vdc_reg, ENC_VDC_SSM_CONFIG + idx, + SSM_MAX_SE_SIZE); + + slice_num_bits_ldw = (u32)vdc->slice_num_bits; + slice_num_bits_ub = vdc->slice_num_bits >> 32; + + SDE_REG_WRITE(vdc_reg, ENC_VDC_SLICE_NUM_BITS_0 + idx, + (slice_num_bits_ub & 0x0ff)); + + SDE_REG_WRITE(vdc_reg, ENC_VDC_SLICE_NUM_BITS_1 + idx, + slice_num_bits_ldw); + + data = 0; + data |= (vdc->chunk_adj_bits << 16); + data |= vdc->num_extra_mux_bits; + SDE_REG_WRITE(vdc_reg, ENC_VDC_RC_PRECOMPUTE + idx, data); + + for (i = 0; i < VDC_LBDA_BRATE_REG_SIZE; i += 2) { + data = 0; + data |= (vdc->lbda_brate_lut_interp[i] << 16); + data |= vdc->lbda_brate_lut_interp[i + 1]; + SDE_REG_WRITE(vdc_reg, + ENC_VDC_LBDA_BRATE_LUT + idx + + (addr_off * 4), + data); + addr_off++; + } + + for (i = 0; i < VDC_LBDA_BRATE_REG_SIZE; i += 4) { + data = 0; + data |= (vdc->lbda_bf_lut_interp[i] << 24); + data |= (vdc->lbda_bf_lut_interp[i + 1] << 16); + data |= (vdc->lbda_bf_lut_interp[i + 2] << 8); + data |= vdc->lbda_bf_lut_interp[i + 3]; + SDE_REG_WRITE(vdc_reg, ENC_VDC_LBDA_BF_LUT + idx + i, + data); + } + + data = 0; + data |= (vdc->min_block_bits << 16); + data |= vdc->rc_lambda_bitrate_scale; + SDE_REG_WRITE(vdc_reg, ENC_VDC_OTHER_RC + idx, + data); + /* program the vdc wrapper */ + if (_vdc_subblk_offset(hw_vdc, SDE_VDC_CTL, &idx)) + return; + + data = 0; + data = BIT(0); /* encoder enable */ + if (vdc->bits_per_component == 8) + data |= BIT(11); + if (vdc->chroma_format == MSM_CHROMA_422) { + data |= BIT(8); + data |= BIT(10); + } + + SDE_REG_WRITE(vdc_reg, VDC_CFG + idx, data); +} + +static void sde_hw_vdc_bind_pingpong_blk( + struct sde_hw_vdc *hw_vdc, + bool enable, + const enum sde_pingpong pp) +{ + struct sde_hw_blk_reg_map *vdc_reg; + int idx; + int mux_cfg = 0xF; /* Disabled */ + + if (!hw_vdc) + return; + + if (_vdc_subblk_offset(hw_vdc, SDE_VDC_CTL, &idx)) + return; + + vdc_reg = &hw_vdc->hw; + if (enable) + mux_cfg = (pp - PINGPONG_0) & 0xf; + + SDE_REG_WRITE(vdc_reg, VDC_CTL + idx, mux_cfg); +} + +static struct sde_vdc_cfg *_vdc_offset(enum sde_vdc vdc, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->vdc_count; i++) { + if (vdc == m->vdc[i].id) { + b->base_off = addr; + b->blk_off = m->vdc[i].base; + b->length = m->vdc[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_VDC; + return &m->vdc[i]; + } + } + + return NULL; +} + +static void _setup_vdc_ops(struct sde_hw_vdc_ops *ops, + unsigned long features) +{ + ops->vdc_disable = sde_hw_vdc_disable; + ops->vdc_config = sde_hw_vdc_config; + ops->bind_pingpong_blk = sde_hw_vdc_bind_pingpong_blk; +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_vdc *sde_hw_vdc_init(enum sde_vdc idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_vdc *c; + struct sde_vdc_cfg *cfg; + int rc; + u32 vdc_ctl_reg; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _vdc_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + + _setup_vdc_ops(&c->ops, c->caps->features); + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_VDC, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + if (_vdc_subblk_offset(c, SDE_VDC_CTL, &vdc_ctl_reg)) { + SDE_ERROR("vdc ctl not found\n"); + kfree(c); + return ERR_PTR(-EINVAL); + } + + if (c->idx == VDC_0) { + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, "vdc_ctl", + vdc_ctl_reg, + vdc_ctl_reg + VDC_CTL_BLOCK_SIZE, + c->hw.xin_id); + } + + return c; + +blk_init_error: + kfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_vdc_destroy(struct sde_hw_vdc *vdc) +{ + if (vdc) { + sde_hw_blk_destroy(&vdc->base); + kfree(vdc); + } +} diff --git a/msm/sde/sde_hw_vdc.h b/msm/sde/sde_hw_vdc.h new file mode 100644 index 000000000000..10ee9541e16e --- /dev/null +++ b/msm/sde/sde_hw_vdc.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_VDC_H +#define _SDE_HW_VDC_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_blk.h" + +struct sde_hw_vdc; +struct msm_display_vdc_info; + +/** + * struct sde_hw_vdc_ops - interface to the vdc hardware driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_vdc_ops { + /** + * vdc_disable - disable vdc + * @hw_vdc: Pointer to vdc context + */ + void (*vdc_disable)(struct sde_hw_vdc *hw_vdc); + + /** + * vdc_config - configures vdc encoder + * @hw_vdc: Pointer to vdc context + * @vdc: panel vdc parameters + */ + void (*vdc_config)(struct sde_hw_vdc *hw_vdc, + struct msm_display_vdc_info *vdc); + + /** + * bind_pingpong_blk - enable/disable the connection with pp + * @hw_vdc: Pointer to vdc context + * @enable: enable/disable connection + * @pp: pingpong blk id + */ + void (*bind_pingpong_blk)(struct sde_hw_vdc *hw_vdc, + bool enable, + const enum sde_pingpong pp); +}; + +struct sde_hw_vdc { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* vdc */ + enum sde_vdc idx; + const struct sde_vdc_cfg *caps; + + /* ops */ + struct sde_hw_vdc_ops ops; +}; + +/** + * sde_hw_vdc - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_vdc *to_sde_hw_vdc(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_vdc, base); +} + +/** + * sde_hw_vdc_init - initializes the vdc block for the passed + * vdc idx. + * @idx: VDC index for which driver object is required + * @addr: Mapped register io address of MDP + * @m: Pointer to mdss catalog data + * Returns: Error code or allocated sde_hw_vdc context + */ +struct sde_hw_vdc *sde_hw_vdc_init(enum sde_vdc idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_vdc_destroy - destroys vdc driver context + * should be called to free the context + * @vdc: Pointer to vdc driver context returned by sde_hw_vdc_init + */ +void sde_hw_vdc_destroy(struct sde_hw_vdc *vdc); + +#endif /*_SDE_HW_VDC_H */ diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index 18e7815bce26..370f16365a83 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -16,6 +16,7 @@ #include "sde_encoder.h" #include "sde_connector.h" #include "sde_hw_dsc.h" +#include "sde_hw_vdc.h" #include "sde_crtc.h" #include "sde_hw_qdss.h" @@ -185,6 +186,8 @@ static void _sde_rm_inc_resource_info(struct sde_rm *rm, avail_res->num_ctl++; else if (type == SDE_HW_BLK_DSC) avail_res->num_dsc++; + else if (type == SDE_HW_BLK_VDC) + avail_res->num_vdc++; } static void _sde_rm_dec_resource_info(struct sde_rm *rm, @@ -199,6 +202,8 @@ static void _sde_rm_dec_resource_info(struct sde_rm *rm, avail_res->num_ctl--; else if (type == SDE_HW_BLK_DSC) avail_res->num_dsc--; + else if (type == SDE_HW_BLK_VDC) + avail_res->num_vdc--; } void sde_rm_get_resource_info(struct sde_rm *rm, @@ -443,6 +448,9 @@ static void _sde_rm_hw_destroy(enum sde_hw_blk_type type, void *hw) case SDE_HW_BLK_DSC: sde_hw_dsc_destroy(hw); break; + case SDE_HW_BLK_VDC: + sde_hw_vdc_destroy(hw); + break; case SDE_HW_BLK_QDSS: sde_hw_qdss_destroy(hw); break; @@ -534,6 +542,9 @@ static int _sde_rm_hw_blk_create( case SDE_HW_BLK_DSC: hw = sde_hw_dsc_init(id, mmio, cat); break; + case SDE_HW_BLK_VDC: + hw = sde_hw_vdc_init(id, mmio, cat); + break; case SDE_HW_BLK_QDSS: hw = sde_hw_qdss_init(id, mmio, cat); break; @@ -613,6 +624,15 @@ static int _sde_rm_hw_blk_create_new(struct sde_rm *rm, } } + for (i = 0; i < cat->vdc_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_VDC, + cat->vdc[i].id, &cat->vdc[i]); + if (rc) { + SDE_ERROR("failed: vdc hw not available\n"); + goto fail; + } + } + for (i = 0; i < cat->intf_count; i++) { if (cat->intf[i].type == INTF_NONE) { SDE_DEBUG("skip intf %d with type none\n", i); @@ -1233,6 +1253,21 @@ static bool _sde_rm_check_dsc(struct sde_rm *rm, return true; } +static bool _sde_rm_check_vdc(struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_hw_blk *vdc) +{ + const struct sde_vdc_cfg *vdc_cfg = to_sde_hw_vdc(vdc->hw)->caps; + + /* Already reserved? */ + if (RESERVED_BY_OTHER(vdc, rsvp)) { + SDE_DEBUG("vdc %d already reserved\n", vdc_cfg->id); + return false; + } + + return true; +} + static int _sde_rm_reserve_dsc( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, @@ -1328,6 +1363,66 @@ static int _sde_rm_reserve_dsc( return 0; } +static int _sde_rm_reserve_vdc( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + const struct sde_rm_topology_def *top, + u8 *_vdc_ids) +{ + struct sde_rm_hw_iter iter_i; + struct sde_rm_hw_blk *vdc[MAX_BLOCKS]; + int alloc_count = 0; + int num_vdc_enc = top->num_comp_enc; + int i; + + if (!top->num_comp_enc) + return 0; + + if (reqs->hw_res.comp_info->comp_type != MSM_DISPLAY_COMPRESSION_VDC) + return 0; + + sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_VDC); + + /* Find a VDC */ + while (alloc_count != num_vdc_enc && + _sde_rm_get_hw_locked(rm, &iter_i)) { + + memset(&vdc, 0, sizeof(vdc)); + alloc_count = 0; + + if (_vdc_ids && (iter_i.blk->id != _vdc_ids[alloc_count])) + continue; + + if (!_sde_rm_check_vdc(rm, rsvp, iter_i.blk)) + continue; + + SDE_DEBUG("blk id = %d, _vdc_ids[%d] = %d\n", + iter_i.blk->id, + alloc_count, + _vdc_ids ? _vdc_ids[alloc_count] : -1); + + vdc[alloc_count++] = iter_i.blk; + } + + if (alloc_count != num_vdc_enc) { + SDE_ERROR("couldn't reserve %d vdc blocks for enc id %d\n", + num_vdc_enc, rsvp->enc_id); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(vdc); i++) { + if (!vdc[i]) + break; + + vdc[i]->rsvp_nxt = rsvp; + + SDE_EVT32(vdc[i]->type, rsvp->enc_id, vdc[i]->id); + } + + return 0; +} + static int _sde_rm_reserve_qdss( struct sde_rm *rm, struct sde_rm_rsvp *rsvp, @@ -1579,6 +1674,26 @@ static int _sde_rm_make_dsc_rsvp(struct sde_rm *rm, struct sde_rm_rsvp *rsvp, return 0; } +static int _sde_rm_make_vdc_rsvp(struct sde_rm *rm, struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + struct sde_splash_display *splash_display) +{ + int ret, i; + u8 *hw_ids = NULL; + + /* Check if splash data provided vdc_ids */ + if (splash_display) { + hw_ids = splash_display->vdc_ids; + for (i = 0; i < splash_display->vdc_cnt; i++) + SDE_DEBUG("splash_data.vdc_ids[%d] = %d\n", + i, splash_display->vdc_ids[i]); + } + + ret = _sde_rm_reserve_vdc(rm, rsvp, reqs, reqs->topology, hw_ids); + + return ret; +} + static int _sde_rm_make_next_rsvp(struct sde_rm *rm, struct drm_encoder *enc, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state, @@ -1635,6 +1750,10 @@ static int _sde_rm_make_next_rsvp(struct sde_rm *rm, struct drm_encoder *enc, if (ret) return ret; + ret = _sde_rm_make_vdc_rsvp(rm, rsvp, reqs, splash_display); + if (ret) + return ret; + ret = _sde_rm_reserve_qdss(rm, rsvp, reqs->topology, NULL); if (ret) return ret; From c4f5050e13df861d03f91e1224611c995af494ff Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Thu, 29 Aug 2019 19:35:31 -0700 Subject: [PATCH 07/10] disp: msm: add VDC topology related changes Add support to configure the DPU pipeline to support VDC-m topologies. Change-Id: Ib8ce9a0eaeaa838759fb09cb2ee164d4765e4989 Signed-off-by: Abhinav Kumar --- msm/dsi/dsi_drm.c | 8 +- msm/msm_drv.h | 5 + msm/sde/sde_connector.c | 4 +- msm/sde/sde_encoder.c | 10 + msm/sde/sde_encoder.h | 4 +- msm/sde/sde_encoder_dce.c | 351 +++++++++++++++++++++++++++++++-- msm/sde/sde_encoder_phys.h | 3 +- msm/sde/sde_encoder_phys_vid.c | 6 +- msm/sde/sde_hw_catalog.h | 1 + msm/sde/sde_hw_ctl.c | 39 ++++ msm/sde/sde_hw_ctl.h | 16 +- msm/sde/sde_rm.c | 2 + msm/sde/sde_rm.h | 25 +++ msm/sde_vdc_helper.c | 3 +- 14 files changed, 453 insertions(+), 24 deletions(-) diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 42cc009601d3..43984cb9e4f1 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ @@ -503,6 +503,12 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, sizeof(dsi_mode.priv_info->dsc)); mode_info->comp_info.comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1; + } else if (dsi_mode.priv_info->vdc_enabled) { + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_VDC; + memcpy(&mode_info->comp_info.vdc_info, &dsi_mode.priv_info->vdc, + sizeof(dsi_mode.priv_info->vdc)); + mode_info->comp_info.comp_ratio = + MSM_DISPLAY_COMPRESSION_RATIO_4_TO_1; } if (dsi_mode.priv_info->roi_caps.enabled) { diff --git a/msm/msm_drv.h b/msm/msm_drv.h index ac93e1f28d2b..4bf64fa57c0c 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -233,11 +233,13 @@ enum msm_display_compression_type { * @MSM_DISPLAY_COMPRESSION_NONE: no compression * @MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: 2 to 1 compression * @MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: 3 to 1 compression + * @MSM_DISPLAY_COMPRESSION_RATIO_4_TO_1: 4 to 1 compression */ enum msm_display_compression_ratio { MSM_DISPLAY_COMPRESSION_RATIO_NONE, MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, + MSM_DISPLAY_COMPRESSION_RATIO_4_TO_1, MSM_DISPLAY_COMPRESSION_RATIO_MAX, }; @@ -599,6 +601,8 @@ struct msm_display_vdc_info { * @comp_ratio: compression ratio * @dsc_info: dsc configuration if the compression * supported is DSC + * @vdc_info: vdc configuration if the compression + * supported is VDC */ struct msm_compression_info { enum msm_display_compression_type comp_type; @@ -606,6 +610,7 @@ struct msm_compression_info { union{ struct msm_display_dsc_info dsc_info; + struct msm_display_vdc_info vdc_info; }; }; diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 9ab79336bc70..939b4d03d64c 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -37,10 +37,12 @@ static const struct drm_prop_enum_list e_topology_name[] = { {SDE_RM_TOPOLOGY_NONE, "sde_none"}, {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"}, {SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, "sde_singlepipe_dsc"}, + {SDE_RM_TOPOLOGY_SINGLEPIPE_VDC, "sde_singlepipe_vdc"}, {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"}, {SDE_RM_TOPOLOGY_DUALPIPE_DSC, "sde_dualpipe_dsc"}, {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, "sde_dualpipemerge"}, {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, "sde_dualpipemerge_dsc"}, + {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC, "sde_dualpipemerge_vdc"}, {SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, "sde_dualpipe_dscmerge"}, {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"}, }; diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index f41c180ef327..c75cba867fb6 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -74,6 +74,7 @@ #define TOPOLOGY_DUALPIPE_MERGE_MODE(x) \ (((x) == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE) || \ ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE) || \ + ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC) || \ ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)) /** @@ -2040,6 +2041,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, struct list_head *connector_list; struct drm_connector *conn = NULL, *conn_iter; struct sde_rm_hw_iter dsc_iter, pp_iter, qdss_iter; + struct sde_rm_hw_iter vdc_iter; struct sde_rm_hw_request request_hw; enum sde_intf_mode intf_mode; bool is_cmd_mode = false; @@ -2160,6 +2162,14 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, sde_enc->hw_dsc[i] = (struct sde_hw_dsc *) dsc_iter.hw; } + sde_rm_init_hw_iter(&vdc_iter, drm_enc->base.id, SDE_HW_BLK_VDC); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + sde_enc->hw_vdc[i] = NULL; + if (!sde_rm_get_hw(&sde_kms->rm, &vdc_iter)) + break; + sde_enc->hw_vdc[i] = (struct sde_hw_vdc *) vdc_iter.hw; + } + /* Get PP for DSC configuration */ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { struct sde_hw_pingpong *pp = NULL; diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 599ef3a133d8..806d050b159f 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -135,6 +135,7 @@ struct sde_encoder_ops { * @hw_pp Handle to the pingpong blocks used for the display. No. * 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. * @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 @@ -205,9 +206,10 @@ struct sde_encoder_virt { struct sde_encoder_phys *cur_master; struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; + struct sde_hw_vdc *hw_vdc[MAX_CHANNELS_PER_ENC]; 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]; bool intfs_swapped; bool qdss_status; diff --git a/msm/sde/sde_encoder_dce.c b/msm/sde/sde_encoder_dce.c index 4e63aac8ecd0..8c8e9aaa6bc5 100644 --- a/msm/sde/sde_encoder_dce.c +++ b/msm/sde/sde_encoder_dce.c @@ -20,10 +20,12 @@ #include "sde_encoder_phys.h" #include "sde_power_handle.h" #include "sde_hw_dsc.h" +#include "sde_hw_vdc.h" #include "sde_crtc.h" #include "sde_trace.h" #include "sde_core_irq.h" #include "sde_dsc_helper.h" +#include "sde_vdc_helper.h" #define SDE_DEBUG_DCE(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\ (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) @@ -65,7 +67,7 @@ static int _dce_dsc_update_pic_dim(struct msm_display_dsc_info *dsc, } if ((pic_width % dsc->config.slice_width) || - (pic_height % dsc->config.slice_height)) { + (pic_height % dsc->config.slice_height)) { SDE_ERROR("pic_dim=%dx%d has to be multiple of slice=%dx%d\n", pic_width, pic_height, dsc->config.slice_width, dsc->config.slice_height); @@ -78,6 +80,29 @@ static int _dce_dsc_update_pic_dim(struct msm_display_dsc_info *dsc, return 0; } +static int _dce_vdc_update_pic_dim(struct msm_display_vdc_info *vdc, + int frame_width, int frame_height) +{ + if (!vdc || !frame_width || !frame_height) { + SDE_ERROR("invalid input: frame_width=%d frame_height=%d\n", + frame_width, frame_height); + return -EINVAL; + } + + if ((frame_width % vdc->slice_width) || + (frame_height % vdc->slice_height)) { + SDE_ERROR("pic_dim=%dx%d has to be multiple of slice=%dx%d\n", + frame_width, frame_height, + vdc->slice_width, vdc->slice_height); + return -EINVAL; + } + + vdc->frame_width = frame_width; + vdc->frame_height = frame_height; + + return 0; +} + static int _dce_dsc_initial_line_calc(struct msm_display_dsc_info *dsc, int enc_ip_width, int dsc_cmn_mode) @@ -223,24 +248,59 @@ static void _dce_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc, hw_dsc_pp->ops.enable_dsc(hw_dsc_pp); } -static inline bool _dce_check_half_panel_update(int num_dsc, - bool merge_3d, +static void _dce_vdc_pipe_cfg(struct sde_hw_vdc *hw_vdc, + struct sde_hw_pingpong *hw_pp, + struct msm_display_vdc_info *vdc, + enum sde_3d_blend_mode mode_3d, + bool disable_merge_3d, bool enable) +{ + + if (!vdc || !hw_vdc || !hw_pp) { + SDE_ERROR("invalid params %d %d %d\n", !vdc, !hw_vdc, + !hw_pp); + return; + } + + if (!enable) { + if (hw_vdc->ops.vdc_disable) + hw_vdc->ops.vdc_disable(hw_vdc); + + if (hw_vdc->ops.bind_pingpong_blk) + hw_vdc->ops.bind_pingpong_blk(hw_vdc, false, + PINGPONG_MAX); + + if (mode_3d && hw_pp->ops.reset_3d_mode) + hw_pp->ops.reset_3d_mode(hw_pp); + return; + } + + if (hw_vdc->ops.vdc_config) + hw_vdc->ops.vdc_config(hw_vdc, vdc); + + if (mode_3d && disable_merge_3d && hw_pp->ops.reset_3d_mode) { + SDE_DEBUG("disabling 3d mux\n"); + hw_pp->ops.reset_3d_mode(hw_pp); + } + + if (mode_3d && !disable_merge_3d && hw_pp->ops.setup_3d_mode) { + SDE_DEBUG("enabling 3d mux\n"); + hw_pp->ops.setup_3d_mode(hw_pp, mode_3d); + } + if (hw_vdc->ops.bind_pingpong_blk) + hw_vdc->ops.bind_pingpong_blk(hw_vdc, true, hw_pp->idx); + +} + +static inline bool _dce_check_half_panel_update(int num_lm, unsigned long affected_displays) { /** * partial update logic is currently supported only upto dual * pipe configurations. */ - - if (merge_3d) { - int num_mixers = 2; - - return (hweight_long(affected_displays) != num_mixers); - } else if (num_dsc > 1) { - return (hweight_long(affected_displays) != num_dsc); - } - return false; + return (hweight_long(affected_displays) != num_lm); } + static int _dce_dsc_setup(struct sde_encoder_virt *sde_enc, struct sde_encoder_kickoff_params *params) { @@ -263,7 +323,7 @@ static int _dce_dsc_setup(struct sde_encoder_virt *sde_enc, bool disable_merge_3d = false; int this_frame_slices; int intf_ip_w, enc_ip_w; - int num_intf, num_dsc; + int num_intf, num_dsc, num_lm; int ich_res; int dsc_common_mode = 0; int i; @@ -314,6 +374,7 @@ static int _dce_dsc_setup(struct sde_encoder_virt *sde_enc, num_intf = def->num_intf; mode_3d = (topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC) ? BLEND_3D_H_ROW_INT : BLEND_3D_NONE; + num_lm = def->num_lm; /* * If this encoder is driving more than one DSC encoder, they @@ -323,9 +384,8 @@ static int _dce_dsc_setup(struct sde_encoder_virt *sde_enc, _dce_dsc_update_pic_dim(dsc, roi->w, roi->h); merge_3d = (mode_3d != BLEND_3D_NONE) ? true: false; dsc_merge = (num_dsc > num_intf) ? true : false; - - half_panel_partial_update = _dce_check_half_panel_update( - num_dsc, merge_3d, params->affected_displays); + half_panel_partial_update = _dce_check_half_panel_update(num_lm, + params->affected_displays); if (half_panel_partial_update && merge_3d) disable_merge_3d = true; @@ -445,6 +505,176 @@ static int _dce_dsc_setup(struct sde_encoder_virt *sde_enc, return 0; } +static int _dce_vdc_setup(struct sde_encoder_virt *sde_enc, + struct sde_encoder_kickoff_params *params) +{ + struct drm_connector *drm_conn; + struct sde_kms *sde_kms; + struct msm_drm_private *priv; + struct drm_encoder *drm_enc; + struct sde_encoder_phys *enc_master; + struct sde_hw_vdc *hw_vdc[MAX_CHANNELS_PER_ENC]; + struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct msm_display_vdc_info *vdc = NULL; + enum sde_rm_topology_name topology; + const struct sde_rect *roi; + struct sde_hw_ctl *hw_ctl; + struct sde_hw_intf_cfg_v1 cfg; + enum sde_3d_blend_mode mode_3d; + bool half_panel_partial_update, merge_3d; + bool disable_merge_3d = false; + int this_frame_slices; + int intf_ip_w, enc_ip_w; + const struct sde_rm_topology_def *def; + int num_intf, num_vdc, num_lm; + int i; + int ret = 0; + + if (!sde_enc || !params || !sde_enc->phys_encs[0] || + !sde_enc->phys_encs[0]->connector) + return -EINVAL; + + drm_conn = sde_enc->phys_encs[0]->connector; + + topology = sde_connector_get_topology_name(drm_conn); + if (topology == SDE_RM_TOPOLOGY_NONE) { + SDE_ERROR_DCE(sde_enc, "topology not set yet\n"); + return -EINVAL; + } + + SDE_DEBUG_DCE(sde_enc, "topology:%d\n", topology); + SDE_EVT32(DRMID(&sde_enc->base), topology, + sde_enc->cur_conn_roi.x, + sde_enc->cur_conn_roi.y, + sde_enc->cur_conn_roi.w, + sde_enc->cur_conn_roi.h, + sde_enc->prv_conn_roi.x, + sde_enc->prv_conn_roi.y, + sde_enc->prv_conn_roi.w, + sde_enc->prv_conn_roi.h, + sde_enc->cur_master->cached_mode.hdisplay, + sde_enc->cur_master->cached_mode.vdisplay); + + if (sde_kms_rect_is_equal(&sde_enc->cur_conn_roi, + &sde_enc->prv_conn_roi)) + return ret; + + enc_master = sde_enc->cur_master; + roi = &sde_enc->cur_conn_roi; + hw_ctl = enc_master->hw_ctl; + vdc = &sde_enc->mode_info.comp_info.vdc_info; + + drm_enc = &sde_enc->base; + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + def = sde_rm_topology_get_topology_def(&sde_kms->rm, topology); + if (IS_ERR_OR_NULL(def)) + return -EINVAL; + + num_vdc = def->num_comp_enc; + num_intf = def->num_intf; + mode_3d = (topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC) ? + BLEND_3D_H_ROW_INT : BLEND_3D_NONE; + num_lm = def->num_lm; + + /* + * If this encoder is driving more than one VDC encoder, they + * operate in tandem, same pic dimension needs to be used by + * each of them.(pp-split is assumed to be not supported) + */ + _dce_vdc_update_pic_dim(vdc, roi->w, roi->h); + merge_3d = (mode_3d != BLEND_3D_NONE) ? true : false; + half_panel_partial_update = _dce_check_half_panel_update(num_lm, + params->affected_displays); + + if (half_panel_partial_update && merge_3d) + disable_merge_3d = true; + + this_frame_slices = roi->w / vdc->slice_width; + intf_ip_w = this_frame_slices * vdc->slice_width; + + sde_vdc_populate_config(vdc, intf_ip_w, vdc->traffic_mode); + + enc_ip_w = intf_ip_w; + + SDE_DEBUG_DCE(sde_enc, "pic_w: %d pic_h: %d\n", + roi->w, roi->h); + + for (i = 0; i < num_vdc; i++) { + bool active = !!((1 << i) & params->affected_displays); + + /* + * if half_panel partial update vdc should be bound to the pp + * that is driving the update, in other case when both the + * layer mixers are driving the update, vdc should be bound + * to left side pp + */ + if (merge_3d && half_panel_partial_update) + hw_pp[i] = (active) ? sde_enc->hw_pp[0] : + sde_enc->hw_pp[1]; + else + hw_pp[i] = sde_enc->hw_pp[i]; + hw_vdc[i] = sde_enc->hw_vdc[i]; + + if (!hw_vdc[i]) { + SDE_ERROR_DCE(sde_enc, "invalid params for VDC\n"); + SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, + i, active); + return -EINVAL; + } + + _dce_vdc_pipe_cfg(hw_vdc[i], hw_pp[i], + vdc, mode_3d, disable_merge_3d, active); + + memset(&cfg, 0, sizeof(cfg)); + cfg.vdc[cfg.vdc_count++] = hw_vdc[i]->idx; + + if (hw_ctl->ops.update_intf_cfg) + hw_ctl->ops.update_intf_cfg(hw_ctl, + &cfg, + active); + + if (hw_ctl->ops.update_bitmask_vdc) + hw_ctl->ops.update_bitmask_vdc(hw_ctl, + hw_vdc[i]->idx, active); + + SDE_DEBUG_DCE(sde_enc, + "update_intf_cfg hw_ctl[%d], vdc:%d, %s", + hw_ctl->idx, + cfg.vdc[0], + active ? "enabled" : "disabled"); + + if (mode_3d) { + memset(&cfg, 0, sizeof(cfg)); + + cfg.merge_3d[cfg.merge_3d_count++] = + hw_pp[i]->merge_3d->idx; + + if (hw_ctl->ops.update_intf_cfg) + hw_ctl->ops.update_intf_cfg(hw_ctl, + &cfg, + !disable_merge_3d); + + if (hw_ctl->ops.update_bitmask_merge3d) + hw_ctl->ops.update_bitmask_merge3d( + hw_ctl, + hw_pp[i]->merge_3d->idx, true); + + SDE_DEBUG("mode_3d %s, on CTL_%d PP-%d merge3d:%d\n", + disable_merge_3d ? + "disabled" : "enabled", + hw_ctl->idx - CTL_0, + hw_pp[i]->idx - PINGPONG_0, + hw_pp[i]->merge_3d ? + hw_pp[i]->merge_3d->idx - MERGE_3D_0 : + -1); + } + } + + return 0; +} + static void _dce_dsc_disable(struct sde_encoder_virt *sde_enc) { int i; @@ -494,7 +724,55 @@ static void _dce_dsc_disable(struct sde_encoder_virt *sde_enc) */ } -static bool _dce_dsc_is_dirty(struct sde_encoder_virt *sde_enc) + +static void _dce_vdc_disable(struct sde_encoder_virt *sde_enc) +{ + int i; + struct sde_hw_pingpong *hw_pp = NULL; + struct sde_hw_vdc *hw_vdc = NULL; + struct sde_hw_ctl *hw_ctl = NULL; + struct sde_hw_intf_cfg_v1 cfg; + + if (!sde_enc || !sde_enc->phys_encs[0] || + !sde_enc->phys_encs[0]->connector) { + SDE_ERROR("invalid params %d %d\n", + !sde_enc, sde_enc ? !sde_enc->phys_encs[0] : -1); + return; + } + + if (sde_enc->cur_master) + hw_ctl = sde_enc->cur_master->hw_ctl; + + memset(&cfg, 0, sizeof(cfg)); + + /* Disable VDC for all the pp's present in this topology */ + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + hw_pp = sde_enc->hw_pp[i]; + hw_vdc = sde_enc->hw_vdc[i]; + + _dce_vdc_pipe_cfg(hw_vdc, hw_pp, NULL, + BLEND_3D_NONE, false, + false); + + if (hw_vdc) { + sde_enc->dirty_vdc_ids[i] = hw_vdc->idx; + cfg.vdc[cfg.vdc_count++] = hw_vdc->idx; + } + } + + /* Clear the VDC ACTIVE config for this CTL */ + if (hw_ctl && hw_ctl->ops.update_intf_cfg) + hw_ctl->ops.update_intf_cfg(hw_ctl, &cfg, false); + + /** + * Since pending flushes from previous commit get cleared + * sometime after this point, setting VDC flush bits now + * will have no effect. Therefore dirty_vdc_ids track which + * VDC blocks must be flushed for the next trigger. + */ +} + +bool _dce_dsc_is_dirty(struct sde_encoder_virt *sde_enc) { int i; @@ -510,6 +788,21 @@ static bool _dce_dsc_is_dirty(struct sde_encoder_virt *sde_enc) return false; } +bool _dce_vdc_is_dirty(struct sde_encoder_virt *sde_enc) +{ + int i; + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + /** + * This dirty_vdc_hw field is set during VDC disable to + * indicate which VDC blocks need to be flushed + */ + if (sde_enc->dirty_vdc_ids[i]) + return true; + } + + return false; +} static void _dce_helper_flush_dsc(struct sde_encoder_virt *sde_enc) { @@ -529,6 +822,24 @@ static void _dce_helper_flush_dsc(struct sde_encoder_virt *sde_enc) } } +void _dce_helper_flush_vdc(struct sde_encoder_virt *sde_enc) +{ + int i; + struct sde_hw_ctl *hw_ctl = NULL; + enum sde_vdc vdc_idx; + + if (sde_enc->cur_master) + hw_ctl = sde_enc->cur_master->hw_ctl; + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + vdc_idx = sde_enc->dirty_vdc_ids[i]; + if (vdc_idx && hw_ctl && hw_ctl->ops.update_bitmask_vdc) + hw_ctl->ops.update_bitmask_vdc(hw_ctl, vdc_idx, 1); + + sde_enc->dirty_vdc_ids[i] = VDC_NONE; + } +} + void sde_encoder_dce_disable(struct sde_encoder_virt *sde_enc) { enum msm_display_compression_type comp_type; @@ -540,6 +851,8 @@ void sde_encoder_dce_disable(struct sde_encoder_virt *sde_enc) if (comp_type == MSM_DISPLAY_COMPRESSION_DSC) _dce_dsc_disable(sde_enc); + else if (comp_type == MSM_DISPLAY_COMPRESSION_VDC) + _dce_vdc_disable(sde_enc); } int sde_encoder_dce_flush(struct sde_encoder_virt *sde_enc) @@ -551,6 +864,8 @@ int sde_encoder_dce_flush(struct sde_encoder_virt *sde_enc) if (_dce_dsc_is_dirty(sde_enc)) _dce_helper_flush_dsc(sde_enc); + else if (_dce_vdc_is_dirty(sde_enc)) + _dce_helper_flush_vdc(sde_enc); return rc; } @@ -568,6 +883,8 @@ int sde_encoder_dce_setup(struct sde_encoder_virt *sde_enc, if (comp_type == MSM_DISPLAY_COMPRESSION_DSC) rc = _dce_dsc_setup(sde_enc, params); + else if (comp_type == MSM_DISPLAY_COMPRESSION_VDC) + rc = _dce_vdc_setup(sde_enc, params); return rc; } diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index fa887a3f7f2f..59ea2cc1aea2 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -610,7 +610,8 @@ static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode( topology = sde_connector_get_topology_name(phys_enc->connector); if (phys_enc->split_role == ENC_ROLE_SOLO && (topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE || - topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)) + topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC || + topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC)) return BLEND_3D_H_ROW_INT; return BLEND_3D_NONE; diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index b2d043a98e1c..b41e49e45777 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -89,6 +89,10 @@ static void drm_mode_to_intf_timing_params( timing->width = DIV_ROUND_UP(timing->width, 2); else timing->width = DIV_ROUND_UP(timing->width, 3); + } else if (phys_enc->hw_intf->cap->type != INTF_DP && + vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_VDC) { + comp_ratio = vid_enc->base.comp_ratio; + timing->width = DIV_ROUND_UP(timing->width, comp_ratio); } timing->height = mode->vdisplay; /* active height */ diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index ac8f81fd4e35..0b1367feec60 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -87,6 +87,7 @@ #define MAX_MERGE_3D_PER_CTL_V1 2 #define MAX_WB_PER_CTL_V1 1 #define MAX_CDM_PER_CTL_V1 1 +#define MAX_VDC_PER_CTL_V1 1 #define IS_SDE_CTL_REV_100(rev) \ ((rev) == SDE_CTL_CFG_VERSION_1_0_0) diff --git a/msm/sde/sde_hw_ctl.c b/msm/sde/sde_hw_ctl.c index 7b98b1b0caa8..f635ca4bd95a 100644 --- a/msm/sde/sde_hw_ctl.c +++ b/msm/sde/sde_hw_ctl.c @@ -65,6 +65,8 @@ #define CTL_INVALID_BIT 0xffff +#define VDC_IDX(i) ((i) + 16) + #define UPDATE_ACTIVE(r, idx, en) UPDATE_MASK((r), (idx), (en)) /** @@ -138,6 +140,11 @@ static const u32 intf_flush_tbl[INTF_MAX] = {SDE_NONE, 0, 1, 2, 3, 4, 5}; */ static const u32 dsc_flush_tbl[DSC_MAX] = {SDE_NONE, 0, 1, 2, 3, 4, 5}; +/** + * list of VDC bits in CTL_DSC_FLUSH + */ +static const u32 vdc_flush_tbl[DSC_MAX] = {SDE_NONE, 16, 17}; + /** * list of MERGE_3D bits in CTL_MERGE_3D_FLUSH */ @@ -557,6 +564,26 @@ static inline int sde_hw_ctl_update_bitmask_dsc_v1(struct sde_hw_ctl *ctx, return 0; } +static inline int sde_hw_ctl_update_bitmask_vdc(struct sde_hw_ctl *ctx, + enum sde_vdc vdc, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(vdc > SDE_NONE) || !(vdc < VDC_MAX)) { + SDE_ERROR("Unsupported vdc %d\n", vdc); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_dsc_flush_mask, vdc_flush_tbl[vdc], + enable); + if (ctx->flush.pending_dsc_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, DSC_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, DSC_IDX, 0); + return 0; +} + static inline int sde_hw_ctl_update_bitmask_merge3d_v1(struct sde_hw_ctl *ctx, enum sde_merge_3d merge_3d, bool enable) { @@ -1169,6 +1196,7 @@ static int sde_hw_ctl_update_intf_cfg(struct sde_hw_ctl *ctx, u32 merge_3d_active = 0; u32 wb_active = 0; u32 dsc_active = 0; + u32 vdc_active = 0; struct sde_hw_blk_reg_map *c; if (!ctx) @@ -1213,6 +1241,16 @@ static int sde_hw_ctl_update_intf_cfg(struct sde_hw_ctl *ctx, SDE_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active); } + if (cfg->vdc_count) { + vdc_active = SDE_REG_READ(c, CTL_DSC_ACTIVE); + for (i = 0; i < cfg->vdc_count; i++) { + if (cfg->vdc[i]) + UPDATE_ACTIVE(vdc_active, + VDC_IDX(cfg->vdc[i] - VDC_0), enable); + } + + SDE_REG_WRITE(c, CTL_DSC_ACTIVE, vdc_active); + } return 0; } @@ -1367,6 +1405,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, ops->update_bitmask_wb = sde_hw_ctl_update_bitmask_wb_v1; ops->update_bitmask_intf = sde_hw_ctl_update_bitmask_intf_v1; ops->update_bitmask_dsc = sde_hw_ctl_update_bitmask_dsc_v1; + ops->update_bitmask_vdc = sde_hw_ctl_update_bitmask_vdc; ops->update_bitmask_merge3d = sde_hw_ctl_update_bitmask_merge3d_v1; ops->update_bitmask_cwb = sde_hw_ctl_update_bitmask_cwb_v1; diff --git a/msm/sde/sde_hw_ctl.h b/msm/sde/sde_hw_ctl.h index 94e809d08110..515c271c8822 100644 --- a/msm/sde/sde_hw_ctl.h +++ b/msm/sde/sde_hw_ctl.h @@ -85,6 +85,8 @@ struct sde_hw_intf_cfg { * @cdm: Id of active cdm blocks * @dsc_count: No. of active dsc blocks * @dsc: Id of active dsc blocks + * @vdc_count: No. of active vdc blocks + * @vdc: Id of active vdc blocks */ struct sde_hw_intf_cfg_v1 { uint32_t intf_count; @@ -106,6 +108,9 @@ struct sde_hw_intf_cfg_v1 { uint32_t dsc_count; enum sde_dsc dsc[MAX_DSC_PER_CTL_V1]; + + uint32_t vdc_count; + enum sde_vdc vdc[MAX_VDC_PER_CTL_V1]; }; /** @@ -260,7 +265,8 @@ struct sde_hw_ctl_ops { int (*setup_intf_cfg_v1)(struct sde_hw_ctl *ctx, struct sde_hw_intf_cfg_v1 *cfg); - /** Update the interface selection with input WB config + /** + * Update the interface selection with input WB config * @ctx : ctl path ctx pointer * @cfg : pointer to input wb config * @enable : set if true, clear otherwise @@ -386,6 +392,14 @@ struct sde_hw_ctl_ops { int (*update_bitmask_dsc)(struct sde_hw_ctl *ctx, enum sde_dsc blk, bool enable); + /** + * update_bitmask_vdc: updates mask corresponding to vdc + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_vdc)(struct sde_hw_ctl *ctx, + enum sde_vdc blk, bool enable); + /** * update_bitmask_merge3d: updates mask corresponding to merge_3d * @blk : blk id diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index 370f16365a83..9b4e592a9239 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -57,10 +57,12 @@ static const struct sde_rm_topology_def g_ctl_ver_1_top_table[] = { { SDE_RM_TOPOLOGY_NONE, 0, 0, 0, 0, false }, { SDE_RM_TOPOLOGY_SINGLEPIPE, 1, 0, 1, 1, false }, { SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, 1, 1, 1, 1, false }, + { SDE_RM_TOPOLOGY_SINGLEPIPE_VDC, 1, 1, 1, 1, false }, { SDE_RM_TOPOLOGY_DUALPIPE, 2, 0, 2, 1, true }, { SDE_RM_TOPOLOGY_DUALPIPE_DSC, 2, 2, 2, 1, true }, { SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, 2, 0, 1, 1, false }, { SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, 2, 1, 1, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC, 2, 1, 1, 1, false }, { SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, 2, 2, 1, 1, false }, { SDE_RM_TOPOLOGY_PPSPLIT, 1, 0, 2, 1, true }, }; diff --git a/msm/sde/sde_rm.h b/msm/sde/sde_rm.h index 01d66dddaa77..df1fb5ffa55e 100644 --- a/msm/sde/sde_rm.h +++ b/msm/sde/sde_rm.h @@ -19,10 +19,12 @@ * @SDE_RM_TOPOLOGY_NONE: No topology in use currently * @SDE_RM_TOPOLOGY_SINGLEPIPE: 1 LM, 1 PP, 1 INTF/WB * @SDE_RM_TOPOLOGY_SINGLEPIPE_DSC: 1 LM, 1 DSC, 1 PP, 1 INTF/WB + * @SDE_RM_TOPOLOGY_SINGLEPIPE_VDC: 1 LM, 1 VDC, 1 PP, 1 INTF/WB * @SDE_RM_TOPOLOGY_DUALPIPE: 2 LM, 2 PP, 2 INTF/WB * @SDE_RM_TOPOLOGY_DUALPIPE_DSC: 2 LM, 2 DSC, 2 PP, 2 INTF/WB * @SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE: 2 LM, 2 PP, 3DMux, 1 INTF/WB * @SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC: 2 LM, 2 PP, 3DMux, 1 DSC, 1 INTF/WB + * @SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC: 2 LM, 2 PP, 3DMux, 1 VDC, 1 INTF/WB * @SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE: 2 LM, 2 PP, 2 DSC Merge, 1 INTF/WB * @SDE_RM_TOPOLOGY_PPSPLIT: 1 LM, 2 PPs, 2 INTF/WB */ @@ -30,10 +32,12 @@ enum sde_rm_topology_name { SDE_RM_TOPOLOGY_NONE = 0, SDE_RM_TOPOLOGY_SINGLEPIPE, SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, + SDE_RM_TOPOLOGY_SINGLEPIPE_VDC, SDE_RM_TOPOLOGY_DUALPIPE, SDE_RM_TOPOLOGY_DUALPIPE_DSC, SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, + SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_VDC, SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, SDE_RM_TOPOLOGY_PPSPLIT, SDE_RM_TOPOLOGY_MAX, @@ -299,6 +303,27 @@ static inline const struct sde_rm_topology_def* return &rm->topology_tbl[topology]; } +/** + * sde_rm_topology_get_num_lm - returns number of mixers + * used for this topology + * @rm: SDE Resource Manager handle + * @topology: topology selected for the display + * @return: number of lms + */ +static inline int sde_rm_topology_get_num_lm(struct sde_rm *rm, + enum sde_rm_topology_name topology) +{ + if ((!rm) || (topology <= SDE_RM_TOPOLOGY_NONE) || + (topology >= SDE_RM_TOPOLOGY_MAX)) { + pr_err("invalid arguments: rm:%d topology:%d\n", + rm == NULL, topology); + + return -EINVAL; + } + + return rm->topology_tbl[topology].num_lm; +} + /** * sde_rm_ext_blk_create_reserve - Create external HW blocks * in resource manager and reserve for specific encoder. diff --git a/msm/sde_vdc_helper.c b/msm/sde_vdc_helper.c index fea7a6806670..3101a7ea7aad 100644 --- a/msm/sde_vdc_helper.c +++ b/msm/sde_vdc_helper.c @@ -607,7 +607,8 @@ void sde_vdc_intf_prog_params(struct msm_display_vdc_info *vdc_info, total_bytes_per_intf = bytes_in_slice * slice_per_intf; vdc_info->eol_byte_num = total_bytes_per_intf % 3; - vdc_info->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + vdc_info->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, + 3); vdc_info->bytes_in_slice = bytes_in_slice; vdc_info->bytes_per_pkt = bytes_in_slice * slice_per_pkt; vdc_info->pkt_per_line = slice_per_intf / slice_per_pkt; From 64ee2c4d728cffcf3da8d7bf36cec980cb304be8 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Tue, 3 Sep 2019 19:07:05 -0700 Subject: [PATCH 08/10] disp: msm: dsi: add generic API for calculating horizontal timings Add a generic API which calculates the horizontal timings based on the compression type in case compression is enabled and even for non-compression cases. Replace the usage of the DSC macros with this generic API. Change-Id: Ie9174c20adc51a0be7c9127529d41faa4b473b55 Signed-off-by: Abhinav Kumar --- msm/dsi/dsi_ctrl.c | 2 +- msm/dsi/dsi_defs.h | 44 +++++++++++++++++------------------ msm/dsi/dsi_display.c | 6 ++--- msm/dsi/dsi_panel.c | 4 ++-- msm/dsi/dsi_phy_timing_calc.c | 2 +- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 0a3486c14d32..155feaa28d98 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -913,7 +913,7 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, do_div(bit_rate, dsi_transfer_time_us); bit_rate = bit_rate * num_of_lanes; } else { - h_period = DSI_H_TOTAL_DSC(timing); + h_period = dsi_h_total_dce(timing); v_period = DSI_V_TOTAL(timing); bit_rate = h_period * v_period * timing->refresh_rate * bpp; } diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index cd0d2eb13d8f..4662b88a6a1f 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -16,29 +16,6 @@ #define DSI_V_TOTAL(t) (((t)->v_active) + ((t)->v_back_porch) + \ ((t)->v_sync_width) + ((t)->v_front_porch)) -#define DSI_H_TOTAL_DSC(t) \ - ({\ - u64 value;\ - if ((t)->dsc_enabled && (t)->dsc)\ - value = (t)->dsc->pclk_per_line;\ - else\ - value = (t)->h_active;\ - value = value + (t)->h_back_porch + (t)->h_sync_width +\ - (t)->h_front_porch;\ - value;\ - }) - -#define DSI_H_ACTIVE_DSC(t) \ - ({\ - u64 value;\ - if ((t)->dsc_enabled && (t)->dsc)\ - value = (t)->dsc->pclk_per_line;\ - else\ - value = (t)->h_active;\ - value;\ - }) - - #define DSI_DEBUG_NAME_LEN 32 #define display_for_each_ctrl(index, display) \ for (index = 0; (index < (display)->ctrl_count) &&\ @@ -726,4 +703,25 @@ static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt) } return 24; } + +static inline u64 dsi_h_active_dce(struct dsi_mode_info *mode) +{ + u64 h_active = 0; + + if (mode->dsc_enabled && mode->dsc) + h_active = mode->dsc->pclk_per_line; + else if (mode->vdc_enabled && mode->vdc) + h_active = mode->vdc->pclk_per_line; + else + h_active = mode->h_active; + + return h_active; +} + +static inline u64 dsi_h_total_dce(struct dsi_mode_info *mode) +{ + return dsi_h_active_dce(mode) + mode->h_back_porch + + mode->h_sync_width + mode->h_front_porch; +} + #endif /* _DSI_DEFS_H_ */ diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 484e84e2efad..1917adac2b5a 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -3964,7 +3964,7 @@ static void _dsi_display_calc_pipe_delay(struct dsi_display *display, hr_bit_to_esc_ratio = ((dsi_ctrl->clk_freq.byte_clk_rate * 4 * 1000) / esc_clk_rate_hz); - hsync_period = DSI_H_TOTAL_DSC(&mode->timing); + hsync_period = dsi_h_total_dce(&mode->timing); delay->pipe_delay = (hsync_period + 1) / pclk_to_esc_ratio; if (!display->panel->video_config.eof_bllp_lp11_en) delay->pipe_delay += (17 / pclk_to_esc_ratio) + @@ -4367,7 +4367,7 @@ static int dsi_display_get_dfps_timing(struct dsi_display *display, rc = dsi_display_dfps_calc_front_porch( curr_refresh_rate, timing->refresh_rate, - DSI_H_TOTAL_DSC(timing), + dsi_h_total_dce(timing), DSI_V_TOTAL(timing), timing->v_front_porch, &adj_mode->timing.v_front_porch); @@ -4378,7 +4378,7 @@ static int dsi_display_get_dfps_timing(struct dsi_display *display, curr_refresh_rate, timing->refresh_rate, DSI_V_TOTAL(timing), - DSI_H_TOTAL_DSC(timing), + dsi_h_total_dce(timing), timing->h_front_porch, &adj_mode->timing.h_front_porch); if (!rc) diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index d24a6465bdbe..1085801d56dd 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -2195,7 +2195,7 @@ static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, * function dsi_panel_calc_dsi_transfer_time( ) * as we set it based on dsi clock or mdp transfer time. */ - pixel_clk_khz = (DSI_H_TOTAL_DSC(&mode->timing) * + pixel_clk_khz = (dsi_h_total_dce(&mode->timing) * DSI_V_TOTAL(&mode->timing) * mode->timing.refresh_rate); do_div(pixel_clk_khz, 1000); @@ -3504,7 +3504,7 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, min_bitclk_hz = (bits_per_line * timing->v_active * timing->refresh_rate); } else { - total_active_pixels = ((DSI_H_ACTIVE_DSC(timing) + total_active_pixels = ((dsi_h_active_dce(timing) * timing->v_active)); /* calculate the actual bitclk needed to transfer the frame */ min_bitclk_hz = (total_active_pixels * (timing->refresh_rate) * diff --git a/msm/dsi/dsi_phy_timing_calc.c b/msm/dsi/dsi_phy_timing_calc.c index c10d986de5ab..d321d08b6c6f 100644 --- a/msm/dsi/dsi_phy_timing_calc.c +++ b/msm/dsi/dsi_phy_timing_calc.c @@ -661,7 +661,7 @@ int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy, struct phy_timing_ops *ops = phy->ops.timing_ops; memset(&desc, 0x0, sizeof(desc)); - h_total = DSI_H_TOTAL_DSC(mode); + h_total = dsi_h_total_dce(mode); v_total = DSI_V_TOTAL(mode); bpp = bits_per_pixel[host->dst_format]; From 27844b7b60e84af552dbc8653672f77ed09a1a5c Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Fri, 10 Jan 2020 19:14:07 -0800 Subject: [PATCH 09/10] disp: msm: dp: remove usage of compression ratio enum from DP driver As overall display driver is moving away from hard-coded compression ratios, prepare the DP driver for the same by removing the usage of the compression ratio enum. Change-Id: I298db7d20baed8afec9f96dff8c7e950702bfec9 Signed-off-by: Abhinav Kumar --- msm/dp/dp_ctrl.c | 2 +- msm/dp/dp_display.c | 4 +- msm/dp/dp_drm.c | 4 +- msm/dp/dp_mst_drm.c | 2 +- msm/dp/dp_panel.c | 104 +++++++++++++-------------------- msm/dp/dp_panel.h | 2 +- msm/sde/sde_encoder_phys_vid.c | 5 +- 7 files changed, 51 insertions(+), 72 deletions(-) diff --git a/msm/dp/dp_ctrl.c b/msm/dp/dp_ctrl.c index 062a8e8580e4..be90c50c0e52 100644 --- a/msm/dp/dp_ctrl.c +++ b/msm/dp/dp_ctrl.c @@ -1002,7 +1002,7 @@ static void dp_ctrl_mst_calculate_rg(struct dp_ctrl_private *ctrl, u32 x_int = 0, y_frac_enum = 0; u64 target_strm_sym, ts_int_fixp, ts_frac_fixp, y_frac_enum_fixp; - if (panel->pinfo.comp_info.comp_ratio) + if (panel->pinfo.comp_info.comp_ratio > 1) bpp = DSC_BPP(panel->pinfo.comp_info.dsc_info.config); /* min_slot_cnt */ diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 2288838300ae..a7420c7bb955 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -1721,7 +1721,7 @@ static void dp_display_update_dsc_resources(struct dp_display_private *dp, u32 dsc_blk_cnt = 0; if (panel->pinfo.comp_info.comp_type == MSM_DISPLAY_COMPRESSION_DSC && - panel->pinfo.comp_info.comp_ratio) { + (panel->pinfo.comp_info.comp_ratio > 1)) { dsc_blk_cnt = panel->pinfo.h_active / dp->parser->max_dp_dsc_input_width_pixs; if (panel->pinfo.h_active % @@ -2084,7 +2084,7 @@ static enum drm_mode_status dp_display_validate_mode( dp_display->convert_to_dp_mode(dp_display, panel, mode, &dp_mode); - dsc_en = dp_mode.timing.comp_info.comp_ratio ? true : false; + dsc_en = (dp_mode.timing.comp_info.comp_ratio > 1) ? true : false; mode_bpp = dsc_en ? DSC_BPP(dp_mode.timing.comp_info.dsc_info.config) : dp_mode.timing.bpp; diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index f7f6a003c28a..a2022cf47345 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -418,7 +418,7 @@ int dp_connector_get_mode_info(struct drm_connector *connector, dp_disp->convert_to_dp_mode(dp_disp, dp_panel, drm_mode, &dp_mode); - if (dp_mode.timing.comp_info.comp_ratio) { + if (dp_mode.timing.comp_info.comp_ratio > 1) { memcpy(&mode_info->comp_info, &dp_mode.timing.comp_info, sizeof(mode_info->comp_info)); diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c index cbbf5c4c5bc5..f7ecb5542eed 100644 --- a/msm/dp/dp_mst_drm.c +++ b/msm/dp/dp_mst_drm.c @@ -526,7 +526,7 @@ static int dp_mst_calc_pbn_mode(struct dp_display_mode *dp_mode) bool dsc_en; s64 pbn_fp; - dsc_en = dp_mode->timing.comp_info.comp_ratio ? true : false; + dsc_en = (dp_mode->timing.comp_info.comp_ratio > 1) ? true : false; bpp = dsc_en ? DSC_BPP(dp_mode->timing.comp_info.dsc_info.config) : dp_mode->timing.bpp; diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 2b79572408cd..b6ae4727a8cd 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -20,6 +20,10 @@ #define VSC_EXT_VESA_SDP_SUPPORTED BIT(4) #define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5) +#define DP_COMPRESSION_RATIO_2_TO_1 2 +#define DP_COMPRESSION_RATIO_3_TO_1 3 +#define DP_COMPRESSION_RATIO_NONE 1 + enum dp_panel_hdr_pixel_encoding { RGB, YCbCr444, @@ -1001,16 +1005,8 @@ static void dp_panel_calc_tu_parameters(struct dp_panel *dp_panel, in.fec_en = dp_panel->fec_en; in.num_of_dsc_slices = pinfo->comp_info.dsc_info.slice_per_pkt; - switch (pinfo->comp_info.comp_ratio) { - case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: - in.compress_ratio = 200; - break; - case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: - in.compress_ratio = 300; - break; - default: - in.compress_ratio = 100; - } + if (pinfo->comp_info.comp_ratio) + in.compress_ratio = pinfo->comp_info.comp_ratio * 100; _dp_panel_calc_tu(&in, tu_table); } @@ -1064,32 +1060,25 @@ static void dp_panel_config_tr_unit(struct dp_panel *dp_panel) catalog->update_transfer_unit(catalog); } -struct dp_dsc_dto_data { - enum msm_display_compression_ratio comp_ratio; - u32 org_bpp; /* bits */ - u32 dto_numerator; - u32 dto_denominator; -}; - -struct dp_dsc_dto_data dto_tbl[] = { - {MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 24, 1, 2}, - {MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 30, 5, 8}, - {MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 24, 1, 3}, - {MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 30, 5, 12}, -}; - -static void _dp_panel_get_dto_m_n(enum msm_display_compression_ratio ratio, - u32 org_bpp, u32 *dto_n, u32 *dto_d) +static void dp_panel_get_dto_params(u8 comp_ratio, u32 *num, u32 *denom, + u32 org_bpp) { - u32 idx; - - for (idx = 0; idx < ARRAY_SIZE(dto_tbl); idx++) { - if (ratio == dto_tbl[idx].comp_ratio && - org_bpp == dto_tbl[idx].org_bpp) { - *dto_n = dto_tbl[idx].dto_numerator; - *dto_d = dto_tbl[idx].dto_denominator; - return; - } + if ((comp_ratio == 2) && (org_bpp == 24)) { + *num = 1; + *denom = 2; + } else if ((comp_ratio == 2) && (org_bpp == 30)) { + *num = 5; + *denom = 8; + } else if ((comp_ratio == 3) && (org_bpp == 24)) { + *num = 1; + *denom = 3; + } else if ((comp_ratio == 3) && (org_bpp == 30)) { + *num = 5; + *denom = 12; + } else { + DP_ERR("dto params not found\n"); + *num = 0; + *denom = 1; } } @@ -1134,7 +1123,7 @@ static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel) } static void _dp_panel_dsc_get_num_extra_pclk(struct msm_display_dsc_info *dsc, - enum msm_display_compression_ratio ratio) + u8 ratio) { unsigned int dto_n = 0, dto_d = 0, remainder; int ack_required, last_few_ack_required, accum_ack; @@ -1142,8 +1131,8 @@ static void _dp_panel_dsc_get_num_extra_pclk(struct msm_display_dsc_info *dsc, int start, temp, line_width = dsc->config.pic_width/2; s64 temp1_fp, temp2_fp; - _dp_panel_get_dto_m_n(ratio, dsc->config.bits_per_component * 3, - &dto_n, &dto_d); + dp_panel_get_dto_params(ratio, &dto_n, &dto_d, + dsc->config.bits_per_component * 3); ack_required = dsc->pclk_per_line; @@ -1219,7 +1208,7 @@ static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel, static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, struct msm_display_dsc_info *dsc, - enum msm_display_compression_ratio ratio, + u8 ratio, struct dp_display_mode *dp_mode) { int comp_ratio, intf_width; @@ -1238,17 +1227,8 @@ static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, slice_per_intf = DIV_ROUND_UP(intf_width, dsc->config.slice_width); - switch (ratio) { - case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: - comp_ratio = 200; - break; - case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: - comp_ratio = 300; - break; - default: - comp_ratio = 100; - break; - } + if (ratio) + comp_ratio = ratio * 100; temp1_fp = drm_fixp_from_fraction(comp_ratio, 100); temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1); @@ -1457,7 +1437,7 @@ static int dp_panel_dsc_prepare_basic_params( DIV_ROUND_UP(dp_mode->timing.h_active, slice_width); comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC; - comp_info->comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1; + comp_info->comp_ratio = DP_COMPRESSION_RATIO_3_TO_1; return 0; } @@ -2136,16 +2116,12 @@ static u32 _dp_panel_calc_be_in_lane(struct dp_panel *dp_panel) if (!dp_panel->mst_state) return be_in_lane; - switch (pinfo->comp_info.comp_ratio) { - case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: + if (pinfo->comp_info.comp_ratio == DP_COMPRESSION_RATIO_2_TO_1) denominator = 16; /* 2 * bits-in-byte */ - break; - case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: + else if (pinfo->comp_info.comp_ratio == DP_COMPRESSION_RATIO_3_TO_1) denominator = 24; /* 3 * bits-in-byte */ - break; - default: - denominator = 8; /* 1 * bits-in-byte */ - } + else + denominator = 8; numerator = (pinfo->h_active + pinfo->h_back_porch + pinfo->h_front_porch + pinfo->h_sync_width) * @@ -2205,8 +2181,8 @@ static void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable) dsc->dsc_en = true; dsc->dto_en = true; - _dp_panel_get_dto_m_n(comp_info->comp_ratio, pinfo->bpp, - &dsc->dto_n, &dsc->dto_d); + dp_panel_get_dto_params(comp_info->comp_ratio, &dsc->dto_n, + &dsc->dto_d, pinfo->bpp); } else { dsc->dsc_en = false; dsc->dto_en = false; @@ -2957,9 +2933,11 @@ static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, dp_mode->timing.widebus_en = dp_panel->widebus_en; dp_mode->timing.dsc_overhead_fp = 0; - if (dp_panel->dsc_en && dsc_cap) { - comp_info = &dp_mode->timing.comp_info; + comp_info = &dp_mode->timing.comp_info; + comp_info->comp_ratio = DP_COMPRESSION_RATIO_NONE; + comp_info->comp_type = MSM_DISPLAY_COMPRESSION_NONE; + if (dp_panel->dsc_en && dsc_cap) { if (dp_panel_dsc_prepare_basic_params(comp_info, dp_mode, dp_panel)) { DP_DEBUG("prepare DSC basic params failed\n"); diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h index 212b61524b22..9120c476f348 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ #ifndef _DP_PANEL_H_ diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index b41e49e45777..a8e779ab1a25 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -135,7 +135,8 @@ static void drm_mode_to_intf_timing_params( * compression ratio */ if (phys_enc->hw_intf->cap->type == INTF_DP && - (timing->wide_bus_en || vid_enc->base.comp_ratio)) { + (timing->wide_bus_en || + (vid_enc->base.comp_ratio > 1))) { timing->width = timing->width >> 1; timing->xres = timing->xres >> 1; timing->h_back_porch = timing->h_back_porch >> 1; @@ -143,7 +144,7 @@ static void drm_mode_to_intf_timing_params( timing->hsync_pulse_width = timing->hsync_pulse_width >> 1; if (vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_DSC && - vid_enc->base.comp_ratio) { + (vid_enc->base.comp_ratio > 1)) { timing->compression_en = true; timing->extra_dto_cycles = vid_enc->base.dsc_extra_pclk_cycle_cnt; From e3f23771bab9b3411686d84c5464df4dd818afe5 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Thu, 14 Nov 2019 19:17:52 -0800 Subject: [PATCH 10/10] disp: msm: add support for variable compression ratios Currently the compression ratio is hard-coded to either 2:1 or 3:1 in several places. This is not sufficient for new compression algorithms as they can support higher compression ratios. Add support for calculating the compression ratios from the source and target bpp thereby eliminating hard-coding. Change-Id: I6383f3d0c781193d0a9ed74df5a95d8e856edb3d Signed-off-by: Abhinav Kumar --- msm/dsi/dsi_drm.c | 18 ++++++++++++++---- msm/msm_drv.c | 24 +++++++++++++++++++++++- msm/msm_drv.h | 20 +++++--------------- msm/sde/sde_encoder_phys.h | 2 +- msm/sde/sde_encoder_phys_vid.c | 19 ++++++------------- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 43984cb9e4f1..90f03add80eb 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -472,6 +472,8 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, { struct dsi_display_mode dsi_mode; struct dsi_mode_info *timing; + int chroma_format; + int src_bpp, tar_bpp; if (!drm_mode || !mode_info) return -EINVAL; @@ -498,17 +500,25 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; if (dsi_mode.priv_info->dsc_enabled) { + chroma_format = dsi_mode.priv_info->dsc.chroma_format; mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC; memcpy(&mode_info->comp_info.dsc_info, &dsi_mode.priv_info->dsc, sizeof(dsi_mode.priv_info->dsc)); - mode_info->comp_info.comp_ratio = - MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1; + tar_bpp = dsi_mode.priv_info->dsc.config.bits_per_pixel >> 4; + src_bpp = msm_get_src_bpc(chroma_format, + dsi_mode.priv_info->dsc.config.bits_per_component); + mode_info->comp_info.comp_ratio = mult_frac(1, src_bpp, + tar_bpp); } else if (dsi_mode.priv_info->vdc_enabled) { + chroma_format = dsi_mode.priv_info->vdc.chroma_format; mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_VDC; memcpy(&mode_info->comp_info.vdc_info, &dsi_mode.priv_info->vdc, sizeof(dsi_mode.priv_info->vdc)); - mode_info->comp_info.comp_ratio = - MSM_DISPLAY_COMPRESSION_RATIO_4_TO_1; + tar_bpp = dsi_mode.priv_info->vdc.bits_per_pixel >> 4; + src_bpp = msm_get_src_bpc(chroma_format, + dsi_mode.priv_info->vdc.bits_per_component); + mode_info->comp_info.comp_ratio = mult_frac(1, src_bpp, + tar_bpp); } if (dsi_mode.priv_info->roi_caps.enabled) { diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 4e315bdcf38a..2623c4bdefbc 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -301,6 +301,28 @@ u32 msm_readl(const void __iomem *addr) return val; } +int msm_get_src_bpc(int chroma_format, + int bpc) +{ + int src_bpp; + + switch (chroma_format) { + case MSM_CHROMA_444: + src_bpp = bpc * 3; + break; + case MSM_CHROMA_422: + src_bpp = bpc * 2; + break; + case MSM_CHROMA_420: + src_bpp = mult_frac(bpc, 3, 2); + break; + default: + src_bpp = bpc * 3; + break; + } + return src_bpp; +} + struct vblank_work { struct kthread_work work; int crtc_id; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 4bf64fa57c0c..d8fb43e25b31 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -228,20 +228,8 @@ enum msm_display_compression_type { MSM_DISPLAY_COMPRESSION_VDC }; -/** - * enum msm_display_compression_ratio - compression ratio - * @MSM_DISPLAY_COMPRESSION_NONE: no compression - * @MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: 2 to 1 compression - * @MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: 3 to 1 compression - * @MSM_DISPLAY_COMPRESSION_RATIO_4_TO_1: 4 to 1 compression - */ -enum msm_display_compression_ratio { - MSM_DISPLAY_COMPRESSION_RATIO_NONE, - MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, - MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, - MSM_DISPLAY_COMPRESSION_RATIO_4_TO_1, - MSM_DISPLAY_COMPRESSION_RATIO_MAX, -}; +#define MSM_DISPLAY_COMPRESSION_RATIO_NONE 1 +#define MSM_DISPLAY_COMPRESSION_RATIO_MAX 5 /** * enum msm_display_caps - features/capabilities supported by displays @@ -606,7 +594,7 @@ struct msm_display_vdc_info { */ struct msm_compression_info { enum msm_display_compression_type comp_type; - enum msm_display_compression_ratio comp_ratio; + u32 comp_ratio; union{ struct msm_display_dsc_info dsc_info; @@ -1231,4 +1219,6 @@ int msm_get_mixer_count(struct msm_drm_private *priv, const struct drm_display_mode *mode, const struct msm_resource_caps_info *res, u32 *num_lm); +int msm_get_src_bpc(int chroma_format, int bpc); + #endif /* __MSM_DRV_H__ */ diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 59ea2cc1aea2..6cea9324f8e2 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -310,7 +310,7 @@ struct sde_encoder_phys { struct sde_hw_intf_cfg intf_cfg; struct sde_hw_intf_cfg_v1 intf_cfg_v1; enum msm_display_compression_type comp_type; - enum msm_display_compression_ratio comp_ratio; + u32 comp_ratio; u32 dsc_extra_pclk_cycle_cnt; u32 dsc_extra_disp_width; bool wide_bus_en; diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index a8e779ab1a25..31a1eb6167b5 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -50,8 +50,6 @@ static void drm_mode_to_intf_timing_params( struct intf_timing_params *timing) { const struct sde_encoder_phys *phys_enc = &vid_enc->base; - enum msm_display_compression_ratio comp_ratio = - MSM_DISPLAY_COMPRESSION_RATIO_NONE; memset(timing, 0, sizeof(*timing)); @@ -82,17 +80,12 @@ static void drm_mode_to_intf_timing_params( */ timing->width = mode->hdisplay; /* active width */ - if (phys_enc->hw_intf->cap->type != INTF_DP && - vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_DSC) { - comp_ratio = vid_enc->base.comp_ratio; - if (comp_ratio == MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1) - timing->width = DIV_ROUND_UP(timing->width, 2); - else - timing->width = DIV_ROUND_UP(timing->width, 3); - } else if (phys_enc->hw_intf->cap->type != INTF_DP && - vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_VDC) { - comp_ratio = vid_enc->base.comp_ratio; - timing->width = DIV_ROUND_UP(timing->width, comp_ratio); + if (phys_enc->hw_intf->cap->type != INTF_DP) { + if ((vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_DSC) || + (vid_enc->base.comp_type == + MSM_DISPLAY_COMPRESSION_VDC)) + timing->width = DIV_ROUND_UP(timing->width, + vid_enc->base.comp_ratio); } timing->height = mode->vdisplay; /* active height */