diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c | 265 |
1 files changed, 219 insertions, 46 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c index 4befce6cd87a..25ca72139e5f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c @@ -1224,26 +1224,46 @@ void dce110_timing_generator_setup_global_swap_lock( /* This pipe will belong to GSL Group zero. */ set_reg_field_value(value, - 1, - DCP_GSL_CONTROL, - DCP_GSL0_EN); + 1, + DCP_GSL_CONTROL, + DCP_GSL0_EN); set_reg_field_value(value, - gsl_params->gsl_master == tg->inst, - DCP_GSL_CONTROL, - DCP_GSL_MASTER_EN); + gsl_params->gsl_master == tg->inst, + DCP_GSL_CONTROL, + DCP_GSL_MASTER_EN); set_reg_field_value(value, - HFLIP_READY_DELAY, - DCP_GSL_CONTROL, - DCP_GSL_HSYNC_FLIP_FORCE_DELAY); + HFLIP_READY_DELAY, + DCP_GSL_CONTROL, + DCP_GSL_HSYNC_FLIP_FORCE_DELAY); /* Keep signal low (pending high) during 6 lines. * Also defines minimum interval before re-checking signal. */ set_reg_field_value(value, - HFLIP_CHECK_DELAY, - DCP_GSL_CONTROL, - DCP_GSL_HSYNC_FLIP_CHECK_DELAY); + HFLIP_CHECK_DELAY, + DCP_GSL_CONTROL, + DCP_GSL_HSYNC_FLIP_CHECK_DELAY); + + dm_write_reg(tg->ctx, CRTC_REG(mmDCP_GSL_CONTROL), value); + value = 0; + + set_reg_field_value(value, + gsl_params->gsl_master, + DCIO_GSL0_CNTL, + DCIO_GSL0_VSYNC_SEL); + + set_reg_field_value(value, + 0, + DCIO_GSL0_CNTL, + DCIO_GSL0_TIMING_SYNC_SEL); + + set_reg_field_value(value, + 0, + DCIO_GSL0_CNTL, + DCIO_GSL0_GLOBAL_UNLOCK_SEL); + + dm_write_reg(tg->ctx, CRTC_REG(mmDCIO_GSL0_CNTL), value); { @@ -1253,38 +1273,38 @@ void dce110_timing_generator_setup_global_swap_lock( CRTC_REG(mmCRTC_V_TOTAL)); set_reg_field_value(value, - 0,/* DCP_GSL_PURPOSE_SURFACE_FLIP */ - DCP_GSL_CONTROL, - DCP_GSL_SYNC_SOURCE); + 0,/* DCP_GSL_PURPOSE_SURFACE_FLIP */ + DCP_GSL_CONTROL, + DCP_GSL_SYNC_SOURCE); /* Checkpoint relative to end of frame */ check_point = get_reg_field_value(value_crtc_vtotal, - CRTC_V_TOTAL, - CRTC_V_TOTAL); + CRTC_V_TOTAL, + CRTC_V_TOTAL); dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_GSL_WINDOW), 0); } set_reg_field_value(value, - 1, - DCP_GSL_CONTROL, - DCP_GSL_DELAY_SURFACE_UPDATE_PENDING); + 1, + DCP_GSL_CONTROL, + DCP_GSL_DELAY_SURFACE_UPDATE_PENDING); dm_write_reg(tg->ctx, address, value); /********************************************************************/ address = CRTC_REG(mmCRTC_GSL_CONTROL); - value = 0; + value = dm_read_reg(tg->ctx, address); set_reg_field_value(value, - check_point - FLIP_READY_BACK_LOOKUP, - CRTC_GSL_CONTROL, - CRTC_GSL_CHECK_LINE_NUM); + check_point - FLIP_READY_BACK_LOOKUP, + CRTC_GSL_CONTROL, + CRTC_GSL_CHECK_LINE_NUM); set_reg_field_value(value, - VFLIP_READY_DELAY, - CRTC_GSL_CONTROL, - CRTC_GSL_FORCE_DELAY); + VFLIP_READY_DELAY, + CRTC_GSL_CONTROL, + CRTC_GSL_FORCE_DELAY); dm_write_reg(tg->ctx, address, value); } @@ -1555,6 +1575,138 @@ void dce110_timing_generator_enable_reset_trigger( dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value); } +void dce110_timing_generator_enable_crtc_reset( + struct timing_generator *tg, + int source_tg_inst, + struct crtc_trigger_info *crtc_tp) +{ + uint32_t value = 0; + uint32_t rising_edge = 0; + uint32_t falling_edge = 0; + struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); + + /* Setup trigger edge */ + switch (crtc_tp->event) { + case CRTC_EVENT_VSYNC_RISING: + rising_edge = 1; + break; + + case CRTC_EVENT_VSYNC_FALLING: + falling_edge = 1; + break; + } + + value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL)); + + set_reg_field_value(value, + source_tg_inst, + CRTC_TRIGB_CNTL, + CRTC_TRIGB_SOURCE_SELECT); + + set_reg_field_value(value, + TRIGGER_POLARITY_SELECT_LOGIC_ZERO, + CRTC_TRIGB_CNTL, + CRTC_TRIGB_POLARITY_SELECT); + + set_reg_field_value(value, + rising_edge, + CRTC_TRIGB_CNTL, + CRTC_TRIGB_RISING_EDGE_DETECT_CNTL); + + set_reg_field_value(value, + falling_edge, + CRTC_TRIGB_CNTL, + CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL); + + set_reg_field_value(value, + 1, /* clear trigger status */ + CRTC_TRIGB_CNTL, + CRTC_TRIGB_CLEAR); + + dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL), value); + + /**************************************************************/ + + switch (crtc_tp->delay) { + case TRIGGER_DELAY_NEXT_LINE: + value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL)); + + set_reg_field_value(value, + 0, /* force H count to H_TOTAL and V count to V_TOTAL */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_MODE); + + set_reg_field_value(value, + 0, /* TriggerB - we never use TriggerA */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_TRIG_SEL); + + set_reg_field_value(value, + 1, /* clear trigger status */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_CLEAR); + + dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value); + + value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL)); + + set_reg_field_value(value, + 1, + CRTC_VERT_SYNC_CONTROL, + CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR); + + set_reg_field_value(value, + 2, + CRTC_VERT_SYNC_CONTROL, + CRTC_AUTO_FORCE_VSYNC_MODE); + + break; + + case TRIGGER_DELAY_NEXT_PIXEL: + value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL)); + + set_reg_field_value(value, + 1, + CRTC_VERT_SYNC_CONTROL, + CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR); + + set_reg_field_value(value, + 0, + CRTC_VERT_SYNC_CONTROL, + CRTC_AUTO_FORCE_VSYNC_MODE); + + dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL), value); + + value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL)); + + set_reg_field_value(value, + 2, /* force H count to H_TOTAL and V count to V_TOTAL */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_MODE); + + set_reg_field_value(value, + 1, /* TriggerB - we never use TriggerA */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_TRIG_SEL); + + set_reg_field_value(value, + 1, /* clear trigger status */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_CLEAR); + + dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value); + break; + } + + value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_MODE)); + + set_reg_field_value(value, + 2, + CRTC_MASTER_UPDATE_MODE, + MASTER_UPDATE_MODE); + + dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_MASTER_UPDATE_MODE), value); +} void dce110_timing_generator_disable_reset_trigger( struct timing_generator *tg) { @@ -1564,34 +1716,48 @@ void dce110_timing_generator_disable_reset_trigger( value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL)); set_reg_field_value(value, - 0, /* force counter now mode is disabled */ - CRTC_FORCE_COUNT_NOW_CNTL, - CRTC_FORCE_COUNT_NOW_MODE); + 0, /* force counter now mode is disabled */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_MODE); set_reg_field_value(value, - 1, /* clear trigger status */ - CRTC_FORCE_COUNT_NOW_CNTL, - CRTC_FORCE_COUNT_NOW_CLEAR); + 1, /* clear trigger status */ + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_CLEAR); dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL), value); + value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL)); + + set_reg_field_value(value, + 1, + CRTC_VERT_SYNC_CONTROL, + CRTC_FORCE_VSYNC_NEXT_LINE_CLEAR); + + set_reg_field_value(value, + 0, + CRTC_VERT_SYNC_CONTROL, + CRTC_AUTO_FORCE_VSYNC_MODE); + + dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_VERT_SYNC_CONTROL), value); + /********************************************************************/ value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL)); set_reg_field_value(value, - TRIGGER_SOURCE_SELECT_LOGIC_ZERO, - CRTC_TRIGB_CNTL, - CRTC_TRIGB_SOURCE_SELECT); + TRIGGER_SOURCE_SELECT_LOGIC_ZERO, + CRTC_TRIGB_CNTL, + CRTC_TRIGB_SOURCE_SELECT); set_reg_field_value(value, - TRIGGER_POLARITY_SELECT_LOGIC_ZERO, - CRTC_TRIGB_CNTL, - CRTC_TRIGB_POLARITY_SELECT); + TRIGGER_POLARITY_SELECT_LOGIC_ZERO, + CRTC_TRIGB_CNTL, + CRTC_TRIGB_POLARITY_SELECT); set_reg_field_value(value, - 1, /* clear trigger status */ - CRTC_TRIGB_CNTL, - CRTC_TRIGB_CLEAR); + 1, /* clear trigger status */ + CRTC_TRIGB_CNTL, + CRTC_TRIGB_CLEAR); dm_write_reg(tg->ctx, CRTC_REG(mmCRTC_TRIGB_CNTL), value); } @@ -1611,10 +1777,16 @@ bool dce110_timing_generator_did_triggered_reset_occur( struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); uint32_t value = dm_read_reg(tg->ctx, CRTC_REG(mmCRTC_FORCE_COUNT_NOW_CNTL)); - - return get_reg_field_value(value, - CRTC_FORCE_COUNT_NOW_CNTL, - CRTC_FORCE_COUNT_NOW_OCCURRED) != 0; + uint32_t value1 = dm_read_reg(tg->ctx, + CRTC_REG(mmCRTC_VERT_SYNC_CONTROL)); + bool force = get_reg_field_value(value, + CRTC_FORCE_COUNT_NOW_CNTL, + CRTC_FORCE_COUNT_NOW_OCCURRED) != 0; + bool vert_sync = get_reg_field_value(value1, + CRTC_VERT_SYNC_CONTROL, + CRTC_FORCE_VSYNC_NEXT_LINE_OCCURRED) != 0; + + return (force || vert_sync); } /** @@ -1928,6 +2100,7 @@ static const struct timing_generator_funcs dce110_tg_funcs = { .setup_global_swap_lock = dce110_timing_generator_setup_global_swap_lock, .enable_reset_trigger = dce110_timing_generator_enable_reset_trigger, + .enable_crtc_reset = dce110_timing_generator_enable_crtc_reset, .disable_reset_trigger = dce110_timing_generator_disable_reset_trigger, .tear_down_global_swap_lock = dce110_timing_generator_tear_down_global_swap_lock, |