diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c3519fd99f..572a9323d8 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 3134f065d4..4ad3e1fc34 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 ca26e1f8b7..34d98f4988 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 b2e1bf00b6..7624fc4926 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 b94c9e83a9..bb5be3de9d 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 33f872d6d6..b52a21347a 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 6949ed0226..447360391b 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 {