diff --git a/msm/dsi/dsi_catalog.c b/msm/dsi/dsi_catalog.c index 36573e67728b..fc686bd3b9b7 100644 --- a/msm/dsi/dsi_catalog.c +++ b/msm/dsi/dsi_catalog.c @@ -163,7 +163,11 @@ int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, case DSI_CTRL_VERSION_2_2: case DSI_CTRL_VERSION_2_3: case DSI_CTRL_VERSION_2_4: + ctrl->phy_isolation_enabled = phy_isolation_enabled; + dsi_catalog_cmn_init(ctrl, version); + break; case DSI_CTRL_VERSION_2_5: + ctrl->widebus_support = true; ctrl->phy_isolation_enabled = phy_isolation_enabled; dsi_catalog_cmn_init(ctrl, version); break; diff --git a/msm/dsi/dsi_catalog.h b/msm/dsi/dsi_catalog.h index 400e1698467d..cfd864bb59c2 100644 --- a/msm/dsi/dsi_catalog.h +++ b/msm/dsi/dsi_catalog.h @@ -170,7 +170,7 @@ void dsi_ctrl_hw_cmn_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on); void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, struct dsi_mode_info *mode, - u32 h_stride, + struct dsi_host_common_cfg *cfg, u32 vc_id, struct dsi_rect *roi); void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl); diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 7f861e002a09..08ddfbe8d7b5 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -2255,7 +2255,7 @@ int dsi_ctrl_timing_setup(struct dsi_ctrl *dsi_ctrl) dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing, - dsi_ctrl->host_config.video_timing.h_active * 3, + &dsi_ctrl->host_config.common_config, 0x0, &dsi_ctrl->roi); dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true); @@ -2714,7 +2714,7 @@ int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl) if (dsi_ctrl->hw.ops.setup_cmd_stream) dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing, - dsi_ctrl->host_config.video_timing.h_active * 3, + &dsi_ctrl->host_config.common_config, 0x0, NULL); } else { DSI_CTRL_ERR(dsi_ctrl, "invalid panel mode for resolution switch\n"); @@ -2802,7 +2802,7 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled) dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, &dsi_ctrl->host_config.video_timing, - dsi_ctrl->host_config.video_timing.h_active * 3, + &dsi_ctrl->host_config.common_config, 0x0, NULL); } else { diff --git a/msm/dsi/dsi_ctrl_hw.h b/msm/dsi/dsi_ctrl_hw.h index 09ca165078f3..9e438baac40b 100644 --- a/msm/dsi/dsi_ctrl_hw.h +++ b/msm/dsi/dsi_ctrl_hw.h @@ -432,14 +432,15 @@ struct dsi_ctrl_hw_ops { * setup_cmd_stream() - set up parameters for command pixel streams * @ctrl: Pointer to controller host hardware. * @mode: Pointer to mode information. - * @h_stride: Horizontal stride in bytes. + * @cfg: DSI host configuration that is common to both + * video and command modes. * @vc_id: stream_id. * * Setup parameters for command mode pixel stream size. */ void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl, struct dsi_mode_info *mode, - u32 h_stride, + struct dsi_host_common_cfg *cfg, u32 vc_id, struct dsi_rect *roi); @@ -850,6 +851,7 @@ struct dsi_ctrl_hw_ops { * dsi controller and run only dsi controller. * @null_insertion_enabled: A boolean property to allow dsi controller to * insert null packet. + * @widebus_support: 48 bit wide data bus is supported. */ struct dsi_ctrl_hw { void __iomem *base; @@ -870,6 +872,7 @@ struct dsi_ctrl_hw { bool phy_isolation_enabled; bool null_insertion_enabled; + bool widebus_support; }; #endif /* _DSI_CTRL_HW_H_ */ diff --git a/msm/dsi/dsi_ctrl_hw_cmn.c b/msm/dsi/dsi_ctrl_hw_cmn.c index c895420a3413..340938e4f29c 100644 --- a/msm/dsi/dsi_ctrl_hw_cmn.c +++ b/msm/dsi/dsi_ctrl_hw_cmn.c @@ -342,6 +342,16 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, reg |= eol_byte_num << 4; reg |= 1; DSI_W32(ctrl, DSI_VIDEO_COMPRESSION_MODE_CTRL, reg); + + if (ctrl->widebus_support) { + reg = DSI_R32(ctrl, DSI_VIDEO_MODE_CTRL); + reg |= BIT(25); + DSI_W32(ctrl, DSI_VIDEO_MODE_CTRL, reg); + } + + mode->h_active = DIV_ROUND_UP(mode->h_active * + mode->pclk_scale.numer, + mode->pclk_scale.denom); } else { width = mode->h_active; } @@ -388,14 +398,15 @@ void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, * setup_cmd_stream() - set up parameters for command pixel streams * @ctrl: Pointer to controller host hardware. * @mode: Pointer to mode information. - * @h_stride: Horizontal stride in bytes. + * @cfg: DSI host configuration that is common to both + * video and command modes. * @vc_id: stream_id * * Setup parameters for command mode pixel stream size. */ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, struct dsi_mode_info *mode, - u32 h_stride, + struct dsi_host_common_cfg *cfg, u32 vc_id, struct dsi_rect *roi) { @@ -421,7 +432,7 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, sde_dsc_populate_dsc_private_params(&dsc, intf_ip_w); - width_final = dsc.pclk_per_line; + width_final = dsc.bytes_per_pkt * dsc.pkt_per_line; stride_final = dsc.bytes_per_pkt; pkt_per_line = dsc.pkt_per_line; eol_byte_num = dsc.eol_byte_num; @@ -436,7 +447,7 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, sde_vdc_intf_prog_params(&vdc, intf_ip_w); - width_final = vdc.pclk_per_line; + width_final = vdc.bytes_per_pkt * vdc.pkt_per_line; stride_final = vdc.bytes_per_pkt; pkt_per_line = vdc.pkt_per_line; eol_byte_num = vdc.eol_byte_num; @@ -447,13 +458,23 @@ void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, height_final = roi->h; } else { width_final = mode->h_active; - stride_final = h_stride; + stride_final = mode->h_active * 3; 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; + + if (ctrl->widebus_support) { + width_final = DIV_ROUND_UP(width_final, 6); + reg = DSI_R32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2); + reg |= BIT(20); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2, reg); + } else { + width_final = DIV_ROUND_UP(width_final, 3); + } + reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL); reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2); diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h index 86ca54e8a1f6..a6dbb1081a0a 100644 --- a/msm/dsi/dsi_defs.h +++ b/msm/dsi/dsi_defs.h @@ -16,6 +16,8 @@ #define DSI_V_TOTAL(t) (((t)->v_active) + ((t)->v_back_porch) + \ ((t)->v_sync_width) + ((t)->v_front_porch)) +#define DSI_H_SCALE(h, s) (DIV_ROUND_UP((h) * (s)->numer, (s)->denom)) + #define DSI_DEBUG_NAME_LEN 32 #define display_for_each_ctrl(index, display) \ for (index = 0; (index < (display)->ctrl_count) &&\ @@ -398,6 +400,7 @@ struct dsi_panel_cmd_set { * @vdc_enabled: VDC compression enabled. * @dsc: DSC compression configuration. * @vdc: VDC compression configuration. + * @pclk_scale: pclk scale factor, target bpp to source bpp * @roi_caps: Panel ROI capabilities. */ struct dsi_mode_info { @@ -423,6 +426,7 @@ struct dsi_mode_info { bool vdc_enabled; struct msm_display_dsc_info *dsc; struct msm_display_vdc_info *vdc; + struct msm_ratio pclk_scale; struct msm_roi_caps roi_caps; }; @@ -585,7 +589,9 @@ struct dsi_host_config { * @vdc: VDC compression info * @dsc_enabled: DSC compression enabled * @vdc_enabled: VDC compression enabled + * @pclk_scale: pclk scale factor, target bpp to source bpp * @roi_caps: Panel ROI capabilities + * @widebus_support 48 bit wide data bus is supported by hw */ struct dsi_display_mode_priv_info { struct dsi_panel_cmd_set cmd_sets[DSI_CMD_SET_MAX]; @@ -606,7 +612,9 @@ struct dsi_display_mode_priv_info { struct msm_display_vdc_info vdc; bool dsc_enabled; bool vdc_enabled; + struct msm_ratio pclk_scale; struct msm_roi_caps roi_caps; + bool widebus_support; }; /** @@ -738,8 +746,12 @@ static inline u64 dsi_h_active_dce(struct dsi_mode_info *mode) 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; + u64 h_total = dsi_h_active_dce(mode); + + h_total += DSI_H_SCALE(mode->h_back_porch, &mode->pclk_scale) + + DSI_H_SCALE(mode->h_front_porch, &mode->pclk_scale) + + DSI_H_SCALE(mode->h_sync_width, &mode->pclk_scale); + return h_total; } #endif /* _DSI_DEFS_H_ */ diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index b9806a42a1e3..fc9462cd0a7d 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -5277,7 +5277,7 @@ end: int dsi_display_dev_remove(struct platform_device *pdev) { - int rc = 0i, i = 0; + int rc = 0, i = 0; struct dsi_display *display; struct dsi_display_ctrl *ctrl; @@ -6143,6 +6143,10 @@ int dsi_display_get_modes(struct dsi_display *display, is_cmd_mode = (display_mode.panel_mode == DSI_OP_CMD_MODE); + /* Setup widebus support */ + display_mode.priv_info->widebus_support = + ctrl->ctrl->hw.widebus_support; + /* Calculate dsi frame transfer time */ if (is_cmd_mode) { dsi_panel_calc_dsi_transfer_time( diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 9494d0d93179..19a41015edf9 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -58,6 +58,9 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode, if (dsi_mode->priv_info) { dsi_mode->timing.dsc_enabled = dsi_mode->priv_info->dsc_enabled; dsi_mode->timing.dsc = &dsi_mode->priv_info->dsc; + dsi_mode->timing.vdc_enabled = dsi_mode->priv_info->vdc_enabled; + dsi_mode->timing.vdc = &dsi_mode->priv_info->vdc; + dsi_mode->timing.pclk_scale = dsi_mode->priv_info->pclk_scale; } if (msm_is_mode_seamless(drm_mode)) @@ -470,7 +473,6 @@ 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) @@ -497,26 +499,23 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, sizeof(struct msm_display_topology)); 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)); - 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)); - 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); + } + + if (mode_info->comp_info.comp_type) { + tar_bpp = dsi_mode.priv_info->pclk_scale.numer; + src_bpp = dsi_mode.priv_info->pclk_scale.denom; mode_info->comp_info.comp_ratio = mult_frac(1, src_bpp, tar_bpp); + mode_info->wide_bus_en = dsi_mode.priv_info->widebus_support; } if (dsi_mode.priv_info->roi_caps.enabled) { diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 6ef7b9d0380a..d258aaba5daf 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -728,6 +728,10 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode, mode->clk_rate_hz = !rc ? tmp64 : 0; display_mode->priv_info->clk_rate_hz = mode->clk_rate_hz; + mode->pclk_scale.numer = 1; + mode->pclk_scale.denom = 1; + display_mode->priv_info->pclk_scale = mode->pclk_scale; + rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us", &mode->mdp_transfer_time_us); if (!rc) @@ -2416,8 +2420,15 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, goto error; } + priv_info->pclk_scale.numer = + priv_info->dsc.config.bits_per_pixel >> 4; + priv_info->pclk_scale.denom = msm_get_src_bpc( + priv_info->dsc.chroma_format, + priv_info->dsc.config.bits_per_component); + mode->timing.dsc_enabled = true; mode->timing.dsc = &priv_info->dsc; + mode->timing.pclk_scale = priv_info->pclk_scale; error: return rc; @@ -2595,8 +2606,15 @@ static int dsi_panel_parse_vdc_params(struct dsi_display_mode *mode, goto error; } + priv_info->pclk_scale.numer = + priv_info->vdc.bits_per_pixel >> 4; + priv_info->pclk_scale.denom = msm_get_src_bpc( + priv_info->vdc.chroma_format, + priv_info->vdc.bits_per_component); + mode->timing.vdc_enabled = true; mode->timing.vdc = &priv_info->vdc; + mode->timing.pclk_scale = priv_info->pclk_scale; error: return rc; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 1843a53a768f..c74468f89619 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -290,6 +290,16 @@ enum panel_op_mode { MSM_DISPLAY_MODE_MAX, }; +/** + * struct msm_ratio - integer ratio + * @numer: numerator + * @denom: denominator + */ +struct msm_ratio { + uint32_t numer; + uint32_t denom; +}; + /** * enum msm_event_wait - type of HW events to wait for * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c3519fd99ff6..572a9323d873 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -2635,7 +2635,6 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) phys->comp_type = comp_info->comp_type; phys->comp_ratio = comp_info->comp_ratio; - phys->wide_bus_en = sde_enc->mode_info.wide_bus_en; phys->frame_trigger_mode = sde_enc->frame_trigger_mode; phys->poms_align_vsync = disp_info->poms_align_vsync; if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) { @@ -2643,7 +2642,15 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) comp_info->dsc_info.pclk_per_line; phys->dsc_extra_disp_width = comp_info->dsc_info.extra_width; + phys->dce_bytes_per_line = + comp_info->dsc_info.bytes_per_pkt * + comp_info->dsc_info.pkt_per_line; + } else if (phys->comp_type == MSM_DISPLAY_COMPRESSION_VDC) { + phys->dce_bytes_per_line = + comp_info->vdc_info.bytes_per_pkt * + comp_info->vdc_info.pkt_per_line; } + if (phys != sde_enc->cur_master) { /** * on DMS request, the encoder will be enabled diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 3134f065d41c..4ad3e1fc344f 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -550,4 +550,20 @@ static inline struct sde_kms *sde_encoder_get_kms(struct drm_encoder *drm_enc) return to_sde_kms(priv->kms); } + +/* + * sde_encoder_is_widebus_enabled - check if widebus is enabled for current mode + * @drm_enc: Pointer to drm encoder structure + * @Return: true if widebus is enabled for current mode + */ +static inline bool sde_encoder_is_widebus_enabled(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) + return false; + + sde_enc = to_sde_encoder_virt(drm_enc); + return sde_enc->mode_info.wide_bus_en; +} #endif /* __SDE_ENCODER_H__ */ diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index ca26e1f8b75c..34d98f4988ec 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -270,8 +270,8 @@ struct sde_encoder_irq { * @comp_ratio: Compression ratio * @dsc_extra_pclk_cycle_cnt: Extra pclk cycle count for DSC over DP * @dsc_extra_disp_width: Additional display width for DSC over DP - * @wide_bus_en: Wide-bus configuraiton * @poms_align_vsync: poms with vsync aligned + * @dce_bytes_per_line: Compressed bytes per line * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @enable_state: Enable state tracking * @vblank_refcount: Reference count of vblank request @@ -317,8 +317,8 @@ struct sde_encoder_phys { u32 comp_ratio; u32 dsc_extra_pclk_cycle_cnt; u32 dsc_extra_disp_width; - bool wide_bus_en; bool poms_align_vsync; + u32 dce_bytes_per_line; spinlock_t *enc_spinlock; enum sde_enc_enable_state enable_state; struct mutex *vblank_ctl_lock; @@ -758,6 +758,7 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc, /** * sde_encoder_helper_setup_misr - helper function to setup misr + * @phys_enc: Pointer to physical encoder structure * @enable: enable/disable flag * @frame_count: frame count for misr */ @@ -766,6 +767,7 @@ void sde_encoder_helper_setup_misr(struct sde_encoder_phys *phys_enc, /** * sde_encoder_helper_collect_misr - helper function to collect misr + * @phys_enc: Pointer to physical encoder structure * @nonblock: blocking/non-blocking flag * @misr_value: pointer to misr value * @Return: zero on success diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index b2e1bf00b660..7624fc492611 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1146,6 +1146,10 @@ static void sde_encoder_phys_cmd_enable_helper( (phys_enc->comp_type != MSM_DISPLAY_COMPRESSION_NONE), false); + if (hw_intf->ops.enable_wide_bus) + hw_intf->ops.enable_wide_bus(hw_intf, + sde_encoder_is_widebus_enabled(phys_enc->parent)); + /* * For pp-split, skip setting the flush bit for the slave intf, since * both intfs use same ctl and HW will only flush the master. diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index b94c9e83a924..bb5be3de9dc1 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -78,17 +78,8 @@ static void drm_mode_to_intf_timing_params( * <----------------- [hv]sync_end -------> * <---------------------------- [hv]total -------------> */ - timing->width = mode->hdisplay; /* active width */ - - 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->poms_align_vsync = phys_enc->poms_align_vsync; + timing->width = mode->hdisplay; /* active width */ timing->height = mode->vdisplay; /* active height */ timing->xres = timing->width; timing->yres = timing->height; @@ -104,8 +95,11 @@ static void drm_mode_to_intf_timing_params( timing->underflow_clr = 0xff; timing->hsync_skew = mode->hskew; timing->v_front_porch_fixed = vid_enc->base.vfp_cached; - if (vid_enc->base.comp_type != MSM_DISPLAY_COMPRESSION_NONE) + + if (vid_enc->base.comp_type != MSM_DISPLAY_COMPRESSION_NONE) { timing->compression_en = true; + timing->dce_bytes_per_line = vid_enc->base.dce_bytes_per_line; + } /* DSI controller cannot handle active-low sync signals. */ if (phys_enc->hw_intf->cap->type == INTF_DSI) { @@ -122,7 +116,7 @@ static void drm_mode_to_intf_timing_params( timing->v_front_porch = 0; } - timing->wide_bus_en = vid_enc->base.wide_bus_en; + timing->wide_bus_en = sde_encoder_is_widebus_enabled(phys_enc->parent); /* * for DP, divide the horizonal parameters by 2 when @@ -148,6 +142,22 @@ static void drm_mode_to_intf_timing_params( } } + /* + * for DSI, if compression is enabled, then divide the horizonal active + * timing parameters by compression ratio. + */ + if ((phys_enc->hw_intf->cap->type != INTF_DP) && + ((vid_enc->base.comp_type == + MSM_DISPLAY_COMPRESSION_DSC) || + (vid_enc->base.comp_type == + MSM_DISPLAY_COMPRESSION_VDC))) { + // adjust active dimensions + timing->width = DIV_ROUND_UP(timing->width, + vid_enc->base.comp_ratio); + timing->xres = DIV_ROUND_UP(timing->xres, + vid_enc->base.comp_ratio); + } + /* * For edp only: * DISPLAY_V_START = (VBP * HCYCLE) + HBP diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 33f872d6d625..b52a21347a7f 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -197,88 +197,112 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, u32 hsync_period, vsync_period; u32 display_v_start, display_v_end; u32 hsync_start_x, hsync_end_x; + u32 hsync_data_start_x, hsync_data_end_x; u32 active_h_start, active_h_end; u32 active_v_start, active_v_end; u32 active_hctl, display_hctl, hsync_ctl; u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity; u32 panel_format; - u32 intf_cfg, intf_cfg2; + u32 intf_cfg, intf_cfg2 = 0; u32 display_data_hctl = 0, active_data_hctl = 0; + u32 data_width; bool dp_intf = false; /* read interface_cfg */ intf_cfg = SDE_REG_READ(c, INTF_CONFIG); - hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width + - p->h_front_porch; - vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height + - p->v_front_porch; - - display_v_start = ((p->vsync_pulse_width + p->v_back_porch) * - hsync_period) + p->hsync_skew; - display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) + - p->hsync_skew - 1; - - hsync_start_x = p->h_back_porch + p->hsync_pulse_width; - hsync_end_x = hsync_period - p->h_front_porch - 1; if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP) dp_intf = true; - if (p->width != p->xres) { - active_h_start = hsync_start_x; - active_h_end = active_h_start + p->xres - 1; - } else { - active_h_start = 0; - active_h_end = 0; - } + hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width + + p->h_front_porch; + vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height + + p->v_front_porch; - if (p->height != p->yres) { - active_v_start = display_v_start; - active_v_end = active_v_start + (p->yres * hsync_period) - 1; - } else { - active_v_start = 0; - active_v_end = 0; - } - - if (active_h_end) { - active_hctl = (active_h_end << 16) | active_h_start; - intf_cfg |= BIT(29); /* ACTIVE_H_ENABLE */ - } else { - active_hctl = 0; - } - - if (active_v_end) - intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */ + display_v_start = ((p->vsync_pulse_width + p->v_back_porch) * + hsync_period) + p->hsync_skew; + display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) + + p->hsync_skew - 1; hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; - display_hctl = (hsync_end_x << 16) | hsync_start_x; - if (dp_intf) { - active_h_start = hsync_start_x; - active_h_end = active_h_start + p->xres - 1; - active_v_start = display_v_start; - active_v_end = active_v_start + (p->yres * hsync_period) - 1; + hsync_start_x = p->h_back_porch + p->hsync_pulse_width; + hsync_end_x = hsync_period - p->h_front_porch - 1; - display_v_start += p->hsync_pulse_width + p->h_back_porch; + /* + * DATA_HCTL_EN controls data timing which can be different from + * video timing. It is recommended to enable it for all cases, except + * if compression is enabled in 1 pixel per clock mode + */ + if (!p->compression_en || p->wide_bus_en) + intf_cfg2 |= BIT(4); - active_hctl = (active_h_end << 16) | active_h_start; - display_hctl = active_hctl; + if (p->wide_bus_en) + intf_cfg2 |= BIT(0); + + /* + * If widebus is disabled: + * For uncompressed stream, the data is valid for the entire active + * window period. + * For compressed stream, data is valid for a shorter time period + * inside the active window depending on the compression ratio. + * + * If widebus is enabled: + * For uncompressed stream, data is valid for only half the active + * window, since the data rate is doubled in this mode. + * p->width holds the adjusted width for DP but unadjusted width for DSI + * For compressed stream, data validity window needs to be adjusted for + * compression ratio and then further halved. + */ + data_width = p->width; + + if (p->compression_en) { + data_width = DIV_ROUND_UP(p->dce_bytes_per_line, 3); + + if (p->wide_bus_en) + data_width >>= 1; + } else if (!dp_intf && p->wide_bus_en) { + data_width = p->width >> 1; + } else { + data_width = p->width; } - intf_cfg2 = 0; + hsync_data_start_x = hsync_start_x; + hsync_data_end_x = hsync_start_x + data_width - 1; + + display_hctl = (hsync_end_x << 16) | hsync_start_x; + display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x; + + if (dp_intf) { + // DP timing adjustment + display_v_start += p->hsync_pulse_width + p->h_back_porch; + display_v_end -= p->h_front_porch; + } + + intf_cfg |= BIT(29); /* ACTIVE_H_ENABLE */ + intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */ + active_h_start = hsync_start_x; + active_h_end = active_h_start + p->xres - 1; + active_v_start = display_v_start; + active_v_end = active_v_start + (p->yres * hsync_period) - 1; + + active_hctl = (active_h_end << 16) | active_h_start; + + if (dp_intf) { + display_hctl = active_hctl; + + if (p->compression_en) { + active_data_hctl = (hsync_start_x + + p->extra_dto_cycles) << 16; + active_data_hctl += hsync_start_x; + + display_data_hctl = active_data_hctl; + } + } _check_and_set_comp_bit(ctx, p->dsc_4hs_merge, p->compression_en, &intf_cfg2); - if (dp_intf && p->compression_en) { - active_data_hctl = (hsync_start_x + p->extra_dto_cycles) << 16; - active_data_hctl += hsync_start_x; - - display_data_hctl = active_data_hctl; - - intf_cfg2 |= BIT(4); - } - den_polarity = 0; if (ctx->cap->type == INTF_HDMI) { hsync_polarity = p->yres >= 720 ? 0 : 1; @@ -730,6 +754,24 @@ static void sde_hw_intf_enable_compressed_input(struct sde_hw_intf *intf, SDE_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); } +static void sde_hw_intf_enable_wide_bus(struct sde_hw_intf *intf, + bool enable) +{ + struct sde_hw_blk_reg_map *c; + u32 intf_cfg2; + + if (!intf) + return; + + c = &intf->hw; + intf_cfg2 = SDE_REG_READ(c, INTF_CONFIG2); + intf_cfg2 &= ~BIT(0); + + intf_cfg2 |= enable ? BIT(0) : 0; + + SDE_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); +} + static void _setup_intf_ops(struct sde_hw_intf_ops *ops, unsigned long cap) { @@ -745,6 +787,7 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops, ops->avr_trigger = sde_hw_intf_avr_trigger; ops->avr_ctrl = sde_hw_intf_avr_ctrl; ops->enable_compressed_input = sde_hw_intf_enable_compressed_input; + ops->enable_wide_bus = sde_hw_intf_enable_wide_bus; if (cap & BIT(SDE_INTF_INPUT_CTRL)) ops->bind_pingpong_blk = sde_hw_intf_bind_pingpong_blk; diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index 6949ed022617..447360391b2a 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -33,11 +33,12 @@ struct intf_timing_params { u32 underflow_clr; u32 hsync_skew; u32 v_front_porch_fixed; - bool wide_bus_en; /* for DP only */ + bool wide_bus_en; bool compression_en; u32 extra_dto_cycles; /* for DP only */ bool dsc_4hs_merge; /* DSC 4HS merge */ bool poms_align_vsync; /* poms with vsync aligned */ + u32 dce_bytes_per_line; }; struct intf_prog_fetch { @@ -199,6 +200,11 @@ struct sde_hw_intf_ops { */ int (*check_and_reset_tearcheck)(struct sde_hw_intf *intf, struct intf_tear_status *status); + + /** + * Enable processing of 2 pixels per clock + */ + void (*enable_wide_bus)(struct sde_hw_intf *intf, bool enable); }; struct sde_hw_intf {