Merge "disp: msm: sde: pass sde_enc to sde_encoder_control_te"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
abdb501164
@@ -5040,18 +5040,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
|
||||
break;
|
||||
case SDE_POWER_EVENT_PRE_DISABLE:
|
||||
drm_for_each_encoder_mask(encoder, crtc->dev,
|
||||
crtc->state->encoder_mask) {
|
||||
/*
|
||||
* disable the vsync source after updating the
|
||||
* rsc state. rsc state update might have vsync wait
|
||||
* and vsync source must be disabled after it.
|
||||
* It will avoid generating any vsync from this point
|
||||
* till mode-2 entry. It is SW workaround for HW
|
||||
* limitation and should not be removed without
|
||||
* checking the updated design.
|
||||
*/
|
||||
sde_encoder_control_te(encoder, false);
|
||||
}
|
||||
crtc->state->encoder_mask)
|
||||
sde_encoder_idle_pc_enter(encoder);
|
||||
|
||||
spin_lock_irqsave(&sde_crtc->spin_lock, flags);
|
||||
node = NULL;
|
||||
|
@@ -1453,6 +1453,22 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
|
||||
}
|
||||
}
|
||||
|
||||
static void sde_encoder_control_te(struct sde_encoder_virt *sde_enc, bool enable)
|
||||
{
|
||||
struct sde_encoder_phys *phys;
|
||||
int i;
|
||||
|
||||
if (!sde_enc) {
|
||||
SDE_ERROR("invalid sde encoder\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
phys = sde_enc->phys_encs[i];
|
||||
if (phys && phys->ops.control_te)
|
||||
phys->ops.control_te(phys, enable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
|
||||
@@ -1468,13 +1484,13 @@ int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
|
||||
sde_encoder_control_te(drm_enc, false);
|
||||
sde_encoder_control_te(sde_enc, false);
|
||||
|
||||
memcpy(&disp_info, &sde_enc->disp_info, sizeof(disp_info));
|
||||
disp_info.is_te_using_watchdog_timer = watchdog_te;
|
||||
_sde_encoder_update_vsync_source(sde_enc, &disp_info);
|
||||
|
||||
sde_encoder_control_te(drm_enc, true);
|
||||
sde_encoder_control_te(sde_enc, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2183,9 +2199,9 @@ static int _sde_encoder_rc_post_modeset(struct drm_encoder *drm_enc,
|
||||
/* toggle te bit to update vsync source for sim cmd mode panels */
|
||||
if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_CMD_MODE)
|
||||
&& sde_enc->disp_info.is_te_using_watchdog_timer) {
|
||||
sde_encoder_control_te(drm_enc, false);
|
||||
sde_encoder_control_te(sde_enc, false);
|
||||
_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info);
|
||||
sde_encoder_control_te(drm_enc, true);
|
||||
sde_encoder_control_te(sde_enc, true);
|
||||
}
|
||||
|
||||
_sde_encoder_update_rsc_client(drm_enc, true);
|
||||
@@ -2728,28 +2744,28 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
||||
sde_encoder_virt_modeset_rc(drm_enc, adj_mode, msm_mode, false);
|
||||
}
|
||||
|
||||
void sde_encoder_control_te(struct drm_encoder *drm_enc, bool enable)
|
||||
void sde_encoder_idle_pc_enter(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc;
|
||||
struct sde_encoder_phys *phys;
|
||||
int i;
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
|
||||
if (!drm_enc) {
|
||||
SDE_ERROR("invalid parameters\n");
|
||||
SDE_ERROR("invalid encoder\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
if (!sde_enc) {
|
||||
SDE_ERROR("invalid sde encoder\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* disable the vsync source after updating the
|
||||
* rsc state. rsc state update might have vsync wait
|
||||
* and vsync source must be disabled after it.
|
||||
* It will avoid generating any vsync from this point
|
||||
* till mode-2 entry. It is SW workaround for HW
|
||||
* limitation and should not be removed without
|
||||
* checking the updated design.
|
||||
*/
|
||||
sde_encoder_control_te(sde_enc, false);
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
phys = sde_enc->phys_encs[i];
|
||||
if (phys && phys->ops.control_te)
|
||||
phys->ops.control_te(phys, enable);
|
||||
}
|
||||
if (sde_enc->cur_master && sde_enc->cur_master->ops.idle_pc_cache_display_status)
|
||||
sde_enc->cur_master->ops.idle_pc_cache_display_status(sde_enc->cur_master);
|
||||
}
|
||||
|
||||
static int _sde_encoder_input_connect(struct input_handler *handler,
|
||||
@@ -3022,7 +3038,7 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc)
|
||||
sde_enc->cur_master->ops.restore(sde_enc->cur_master);
|
||||
|
||||
_sde_encoder_virt_enable_helper(drm_enc);
|
||||
sde_encoder_control_te(drm_enc, true);
|
||||
sde_encoder_control_te(sde_enc, true);
|
||||
|
||||
/*
|
||||
* During IPC misr ctl register is reset.
|
||||
@@ -3180,11 +3196,11 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
|
||||
sizeof(sde_enc->cur_master->intf_cfg_v1));
|
||||
|
||||
/* turn off vsync_in to update tear check configuration */
|
||||
sde_encoder_control_te(drm_enc, false);
|
||||
sde_encoder_control_te(sde_enc, false);
|
||||
sde_encoder_populate_encoder_phys(drm_enc, sde_enc, msm_mode);
|
||||
|
||||
_sde_encoder_virt_enable_helper(drm_enc);
|
||||
sde_encoder_control_te(drm_enc, true);
|
||||
sde_encoder_control_te(sde_enc, true);
|
||||
}
|
||||
|
||||
void sde_encoder_virt_reset(struct drm_encoder *drm_enc)
|
||||
|
@@ -396,11 +396,10 @@ bool sde_encoder_get_vblank_timestamp(struct drm_encoder *encoder,
|
||||
ktime_t *tvblank);
|
||||
|
||||
/**
|
||||
* sde_encoder_control_te - control enabling/disabling VSYNC_IN_EN
|
||||
* sde_encoder_idle_pc_enter - control enable/disable VSYNC_IN_EN & cache display status at ipc
|
||||
* @encoder: encoder pointer
|
||||
* @enable: boolean to indicate enable/disable
|
||||
*/
|
||||
void sde_encoder_control_te(struct drm_encoder *encoder, bool enable);
|
||||
void sde_encoder_idle_pc_enter(struct drm_encoder *encoder);
|
||||
|
||||
/**
|
||||
* sde_encoder_virt_restore - restore the encoder configs
|
||||
|
@@ -140,6 +140,7 @@ struct sde_encoder_virt_ops {
|
||||
* count and underrun line count
|
||||
* @add_to_minidump: Add this phys_enc data to minidumps
|
||||
* @disable_autorefresh: Disable autorefresh
|
||||
* @idle_pc_cache_display_status: caches display status at idle power collapse
|
||||
*/
|
||||
|
||||
struct sde_encoder_phys_ops {
|
||||
@@ -194,6 +195,7 @@ struct sde_encoder_phys_ops {
|
||||
u32 (*get_underrun_line_count)(struct sde_encoder_phys *phys);
|
||||
void (*add_to_minidump)(struct sde_encoder_phys *phys);
|
||||
void (*disable_autorefresh)(struct sde_encoder_phys *phys);
|
||||
void (*idle_pc_cache_display_status)(struct sde_encoder_phys *phys);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -275,6 +277,7 @@ struct sde_encoder_irq {
|
||||
* @hw_dnsc_blur: Hardware interface to the downscale blur registers
|
||||
* @sde_kms: Pointer to the sde_kms top level
|
||||
* @cached_mode: DRM mode cached at mode_set time, acted on in enable
|
||||
* @wd_jitter : Pointer to watchdog jitter prams
|
||||
* @enabled: Whether the encoder has enabled and running a mode
|
||||
* @split_role: Role to play in a split-panel configuration
|
||||
* @intf_mode: Interface mode
|
||||
@@ -333,6 +336,7 @@ struct sde_encoder_phys {
|
||||
struct sde_hw_dnsc_blur *hw_dnsc_blur;
|
||||
struct sde_kms *sde_kms;
|
||||
struct drm_display_mode cached_mode;
|
||||
struct intf_wd_jitter_params wd_jitter;
|
||||
enum sde_enc_split_role split_role;
|
||||
enum sde_intf_mode intf_mode;
|
||||
enum sde_intf intf_idx;
|
||||
|
@@ -2037,30 +2037,42 @@ static void sde_encoder_phys_cmd_trigger_start(
|
||||
cmd_enc->wr_ptr_wait_success = false;
|
||||
}
|
||||
|
||||
static void _sde_encoder_phys_cmd_calculate_wd_params(struct sde_encoder_phys *phys_enc,
|
||||
struct intf_wd_jitter_params *wd_jitter)
|
||||
static void _sde_encoder_phys_cmd_calculate_wd_params(struct sde_encoder_phys *phys_enc)
|
||||
{
|
||||
u32 nominal_te_value;
|
||||
struct sde_encoder_virt *sde_enc;
|
||||
struct msm_mode_info *mode_info;
|
||||
const u32 multiplier = 1 << 10;
|
||||
struct intf_wd_jitter_params wd_jtr;
|
||||
|
||||
sde_enc = to_sde_encoder_virt(phys_enc->parent);
|
||||
mode_info = &sde_enc->mode_info;
|
||||
|
||||
if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_INSTANTANEOUS_JITTER)
|
||||
wd_jitter->jitter = mult_frac(multiplier, mode_info->wd_jitter.inst_jitter_numer,
|
||||
if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_INSTANTANEOUS_JITTER) {
|
||||
wd_jtr.jitter = mult_frac(multiplier,
|
||||
mode_info->wd_jitter.inst_jitter_numer,
|
||||
(mode_info->wd_jitter.inst_jitter_denom * 100));
|
||||
phys_enc->wd_jitter.jitter = wd_jtr.jitter;
|
||||
}
|
||||
|
||||
if (mode_info->wd_jitter.jitter_type & MSM_DISPLAY_WD_LTJ_JITTER) {
|
||||
nominal_te_value = CALCULATE_WD_LOAD_VALUE(mode_info->frame_rate) * MDP_TICK_COUNT;
|
||||
wd_jitter->ltj_max = mult_frac(nominal_te_value, mode_info->wd_jitter.ltj_max_numer,
|
||||
wd_jtr.ltj_max = mult_frac(nominal_te_value,
|
||||
mode_info->wd_jitter.ltj_max_numer,
|
||||
(mode_info->wd_jitter.ltj_max_denom) * 100);
|
||||
wd_jitter->ltj_slope = mult_frac((1 << 16), wd_jitter->ltj_max,
|
||||
wd_jtr.ltj_slope = mult_frac((1 << 16), wd_jtr.ltj_max,
|
||||
(mode_info->wd_jitter.ltj_time_sec * mode_info->frame_rate));
|
||||
phys_enc->wd_jitter.ltj_max = wd_jtr.ltj_max;
|
||||
phys_enc->wd_jitter.ltj_slope = wd_jtr.ltj_slope;
|
||||
}
|
||||
|
||||
phys_enc->hw_intf->ops.configure_wd_jitter(phys_enc->hw_intf, wd_jitter);
|
||||
phys_enc->hw_intf->ops.configure_wd_jitter(phys_enc->hw_intf, &phys_enc->wd_jitter);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_cmd_store_ltj_values(struct sde_encoder_phys *phys_enc)
|
||||
{
|
||||
if (phys_enc && phys_enc->hw_intf->ops.get_wd_ltj_status)
|
||||
phys_enc->hw_intf->ops.get_wd_ltj_status(phys_enc->hw_intf, &phys_enc->wd_jitter);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phys_enc,
|
||||
@@ -2068,7 +2080,6 @@ static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phy
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc;
|
||||
struct sde_connector *sde_conn;
|
||||
struct intf_wd_jitter_params wd_jitter = {0, 0};
|
||||
|
||||
if (!phys_enc || !phys_enc->hw_intf)
|
||||
return;
|
||||
@@ -2083,7 +2094,7 @@ static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phy
|
||||
phys_enc->hw_intf->ops.setup_vsync_source) {
|
||||
vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0;
|
||||
if (phys_enc->hw_intf->ops.configure_wd_jitter)
|
||||
_sde_encoder_phys_cmd_calculate_wd_params(phys_enc, &wd_jitter);
|
||||
_sde_encoder_phys_cmd_calculate_wd_params(phys_enc);
|
||||
phys_enc->hw_intf->ops.setup_vsync_source(phys_enc->hw_intf,
|
||||
sde_enc->mode_info.frame_rate);
|
||||
} else {
|
||||
@@ -2136,6 +2147,7 @@ static void sde_encoder_phys_cmd_init_ops(struct sde_encoder_phys_ops *ops)
|
||||
ops->collect_misr = sde_encoder_helper_collect_misr;
|
||||
ops->add_to_minidump = sde_encoder_phys_cmd_add_enc_to_minidump;
|
||||
ops->disable_autorefresh = _sde_encoder_phys_disable_autorefresh;
|
||||
ops->idle_pc_cache_display_status = sde_encoder_phys_cmd_store_ltj_values;
|
||||
}
|
||||
|
||||
static inline bool sde_encoder_phys_cmd_intf_te_supported(
|
||||
|
@@ -2493,6 +2493,7 @@ static int sde_intf_parse_dt(struct device_node *np,
|
||||
set_bit(SDE_INTF_MDP_VSYNC_FC, &intf->features);
|
||||
set_bit(SDE_INTF_TE_32BIT, &intf->features);
|
||||
set_bit(SDE_INTF_TE_SINGLE_UPDATE, &intf->features);
|
||||
set_bit(SDE_INTF_WD_LTJ_CTL, &intf->features);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -606,6 +606,7 @@ enum {
|
||||
* @SDE_INTF_MDP_VSYNC_FC INTF block has mdp vsync frame counter
|
||||
* @SDE_INTF_AVR_STATUS INTF block has AVR_STATUS field in AVR_CONTROL register
|
||||
* @SDE_INTF_WD_JITTER INTF block has WD timer jitter support
|
||||
* @SDE_INTF_WD_LTJ_CTL INTF block has WD long term jitter control support
|
||||
* @SDE_INTF_MAX
|
||||
*/
|
||||
enum {
|
||||
@@ -622,6 +623,7 @@ enum {
|
||||
SDE_INTF_MDP_VSYNC_FC,
|
||||
SDE_INTF_AVR_STATUS,
|
||||
SDE_INTF_WD_JITTER,
|
||||
SDE_INTF_WD_LTJ_CTL,
|
||||
SDE_INTF_MAX
|
||||
};
|
||||
|
||||
|
@@ -65,6 +65,8 @@
|
||||
#define INTF_MISR_CTRL 0x180
|
||||
#define INTF_MISR_SIGNATURE 0x184
|
||||
|
||||
#define INTF_WD_TIMER_0_LTJ_CTL 0x200
|
||||
#define INTF_WD_TIMER_0_LTJ_CTL1 0x204
|
||||
#define INTF_VSYNC_TIMESTAMP_CTRL 0x210
|
||||
#define INTF_VSYNC_TIMESTAMP0 0x214
|
||||
#define INTF_VSYNC_TIMESTAMP1 0x218
|
||||
@@ -76,6 +78,8 @@
|
||||
#define INTF_WD_TIMER_0_CTL 0x230
|
||||
#define INTF_WD_TIMER_0_CTL2 0x234
|
||||
#define INTF_WD_TIMER_0_LOAD_VALUE 0x238
|
||||
#define INTF_WD_TIMER_0_LTJ_INT_STATUS 0x240
|
||||
#define INTF_WD_TIMER_0_LTJ_FRAC_STATUS 0x244
|
||||
#define INTF_MUX 0x25C
|
||||
#define INTF_UNDERRUN_COUNT 0x268
|
||||
#define INTF_STATUS 0x26C
|
||||
@@ -496,6 +500,40 @@ static void sde_hw_intf_configure_wd_timer_jitter(struct sde_hw_intf *intf,
|
||||
if (wd_jitter->ltj_max)
|
||||
reg |= BIT(30);
|
||||
SDE_REG_WRITE(c, INTF_WD_TIMER_0_JITTER_CTL, reg);
|
||||
|
||||
if (intf->cap->features & BIT(SDE_INTF_WD_LTJ_CTL)) {
|
||||
if (wd_jitter->ltj_step_dir && wd_jitter->ltj_initial_val) {
|
||||
reg = ((wd_jitter->ltj_step_dir & 0x1) << 31) |
|
||||
(wd_jitter->ltj_initial_val & 0x1FFFFF);
|
||||
SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_CTL, reg);
|
||||
wd_jitter->ltj_step_dir = 0;
|
||||
wd_jitter->ltj_initial_val = 0;
|
||||
}
|
||||
|
||||
if (wd_jitter->ltj_fractional_val) {
|
||||
SDE_REG_WRITE(c, INTF_WD_TIMER_0_LTJ_CTL1, wd_jitter->ltj_fractional_val);
|
||||
wd_jitter->ltj_fractional_val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void sde_hw_intf_read_wd_ltj_ctl(struct sde_hw_intf *intf,
|
||||
struct intf_wd_jitter_params *wd_jitter)
|
||||
{
|
||||
struct sde_hw_blk_reg_map *c;
|
||||
u32 reg;
|
||||
|
||||
c = &intf->hw;
|
||||
|
||||
if (intf->cap->features & BIT(SDE_INTF_WD_LTJ_CTL)) {
|
||||
reg = SDE_REG_READ(c, INTF_WD_TIMER_0_LTJ_INT_STATUS);
|
||||
wd_jitter->ltj_step_dir = reg & BIT(31);
|
||||
wd_jitter->ltj_initial_val = (reg & 0x1FFFFF);
|
||||
|
||||
reg = SDE_REG_READ(c, INTF_WD_TIMER_0_LTJ_FRAC_STATUS);
|
||||
wd_jitter->ltj_fractional_val = (reg & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void sde_hw_intf_setup_vsync_source(struct sde_hw_intf *intf, u32 frame_rate)
|
||||
@@ -1039,6 +1077,9 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
|
||||
|
||||
if (cap & BIT(SDE_INTF_WD_JITTER))
|
||||
ops->configure_wd_jitter = sde_hw_intf_configure_wd_timer_jitter;
|
||||
|
||||
if (cap & BIT(SDE_INTF_WD_LTJ_CTL))
|
||||
ops->get_wd_ltj_status = sde_hw_intf_read_wd_ltj_ctl;
|
||||
}
|
||||
|
||||
struct sde_hw_blk_reg_map *sde_hw_intf_init(enum sde_intf idx,
|
||||
|
@@ -73,13 +73,18 @@ struct intf_avr_params {
|
||||
* jitter : max instantaneous jitter.
|
||||
* ltj_max : max long term jitter value.
|
||||
* ltj_slope : slope of long term jitter.
|
||||
*ltj_step_dir: direction of the step in LTJ
|
||||
*ltj_initial_val: LTJ initial value
|
||||
*ltj_fractional_val: LTJ fractional initial value
|
||||
*/
|
||||
struct intf_wd_jitter_params {
|
||||
u32 jitter;
|
||||
u32 ltj_max;
|
||||
u32 ltj_slope;
|
||||
u8 ltj_step_dir;
|
||||
u32 ltj_initial_val;
|
||||
u32 ltj_fractional_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_hw_intf_ops : Interface to the interface Hw driver functions
|
||||
* Assumption is these functions will be called after clocks are enabled
|
||||
@@ -95,6 +100,8 @@ struct intf_wd_jitter_params {
|
||||
* converts it into line count
|
||||
* @setup_vsync_source: Configure vsync source selection for intf
|
||||
* @configure_wd_jitter: Configure WD jitter.
|
||||
* @ write_wd_ltj: Write WD long term jitter.
|
||||
* @get_wd_ltj_status: Read WD long term jitter status.
|
||||
* @bind_pingpong_blk: enable/disable the connection with pingpong which will
|
||||
* feed pixels to this interface
|
||||
*/
|
||||
@@ -132,6 +139,10 @@ struct sde_hw_intf_ops {
|
||||
void (*setup_vsync_source)(struct sde_hw_intf *intf, u32 frame_rate);
|
||||
void (*configure_wd_jitter)(struct sde_hw_intf *intf,
|
||||
struct intf_wd_jitter_params *wd_jitter);
|
||||
void (*write_wd_ltj)(struct sde_hw_intf *intf,
|
||||
struct intf_wd_jitter_params *wd_jitter);
|
||||
void (*get_wd_ltj_status)(struct sde_hw_intf *intf,
|
||||
struct intf_wd_jitter_params *wd_jitter);
|
||||
|
||||
void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
|
||||
bool enable,
|
||||
|
Reference in New Issue
Block a user