diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_aux.c | 146 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_aux.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c | 5 |
8 files changed, 141 insertions, 66 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index 4febf4ef7240..937b5cffd7ef 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -171,24 +171,24 @@ static void submit_channel_request( (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT))); if (REG(AUXN_IMPCAL)) { /* clear_aux_error */ - REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK, - 1, - 0); + REG_UPDATE_SEQ_2(AUXN_IMPCAL, + AUXN_CALOUT_ERROR_AK, 1, + AUXN_CALOUT_ERROR_AK, 0); - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK, - 1, - 0); + REG_UPDATE_SEQ_2(AUXP_IMPCAL, + AUXP_CALOUT_ERROR_AK, 1, + AUXP_CALOUT_ERROR_AK, 0); /* force_default_calibrate */ - REG_UPDATE_1BY1_2(AUXN_IMPCAL, + REG_UPDATE_SEQ_2(AUXN_IMPCAL, AUXN_IMPCAL_ENABLE, 1, AUXN_IMPCAL_OVERRIDE_ENABLE, 0); /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */ - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE, - 1, - 0); + REG_UPDATE_SEQ_2(AUXP_IMPCAL, + AUXP_IMPCAL_OVERRIDE_ENABLE, 1, + AUXP_IMPCAL_OVERRIDE_ENABLE, 0); } /* set the delay and the number of bytes to write */ @@ -267,7 +267,7 @@ static int read_channel_reply(struct dce_aux *engine, uint32_t size, if (!bytes_replied) return -1; - REG_UPDATE_1BY1_3(AUX_SW_DATA, + REG_UPDATE_SEQ_3(AUX_SW_DATA, AUX_SW_INDEX, 0, AUX_SW_AUTOINCREMENT_DISABLE, 1, AUX_SW_DATA_RW, 1); @@ -317,9 +317,10 @@ static enum aux_channel_operation_result get_channel_status( *returned_bytes = 0; /* poll to make sure that SW_DONE is asserted */ - value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1, + REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1, 10, aux110->timeout_period/10); + value = REG_READ(AUX_SW_STATUS); /* in case HPD is LOW, exit AUX transaction */ if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON; @@ -374,7 +375,6 @@ static bool acquire( struct dce_aux *engine, struct ddc *ddc) { - enum gpio_result result; if (!is_engine_available(engine)) @@ -439,12 +439,12 @@ static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payl return I2CAUX_TRANSACTION_ACTION_DP_READ; } -int dce_aux_transfer(struct ddc_service *ddc, - struct aux_payload *payload) +int dce_aux_transfer_raw(struct ddc_service *ddc, + struct aux_payload *payload, + enum aux_channel_operation_result *operation_result) { struct ddc *ddc_pin = ddc->ddc_pin; struct dce_aux *aux_engine; - enum aux_channel_operation_result operation_result; struct aux_request_transaction_data aux_req; struct aux_reply_transaction_data aux_rep; uint8_t returned_bytes = 0; @@ -455,7 +455,8 @@ int dce_aux_transfer(struct ddc_service *ddc, memset(&aux_rep, 0, sizeof(aux_rep)); aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; - acquire(aux_engine, ddc_pin); + if (!acquire(aux_engine, ddc_pin)) + return -1; if (payload->i2c_over_aux) aux_req.type = AUX_TRANSACTION_TYPE_I2C; @@ -470,28 +471,26 @@ int dce_aux_transfer(struct ddc_service *ddc, aux_req.data = payload->data; submit_channel_request(aux_engine, &aux_req); - operation_result = get_channel_status(aux_engine, &returned_bytes); - - switch (operation_result) { - case AUX_CHANNEL_OPERATION_SUCCEEDED: - res = read_channel_reply(aux_engine, payload->length, - payload->data, payload->reply, - &status); - break; - case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: - res = 0; - break; - case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: - case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: - case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: + *operation_result = get_channel_status(aux_engine, &returned_bytes); + + if (*operation_result == AUX_CHANNEL_OPERATION_SUCCEEDED) { + read_channel_reply(aux_engine, payload->length, + payload->data, payload->reply, + &status); + res = returned_bytes; + } else { res = -1; - break; } + release_engine(aux_engine); return res; } -#define AUX_RETRY_MAX 7 +#define AUX_MAX_RETRIES 7 +#define AUX_MAX_DEFER_RETRIES 7 +#define AUX_MAX_I2C_DEFER_RETRIES 7 +#define AUX_MAX_INVALID_REPLY_RETRIES 2 +#define AUX_MAX_TIMEOUT_RETRIES 3 bool dce_aux_transfer_with_retries(struct ddc_service *ddc, struct aux_payload *payload) @@ -499,24 +498,85 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, int i, ret = 0; uint8_t reply; bool payload_reply = true; + enum aux_channel_operation_result operation_result; + int aux_ack_retries = 0, + aux_defer_retries = 0, + aux_i2c_defer_retries = 0, + aux_timeout_retries = 0, + aux_invalid_reply_retries = 0; if (!payload->reply) { payload_reply = false; payload->reply = &reply; } - for (i = 0; i < AUX_RETRY_MAX; i++) { - ret = dce_aux_transfer(ddc, payload); - - if (ret >= 0) { - if (*payload->reply == 0) { - if (!payload_reply) - payload->reply = NULL; - return true; + for (i = 0; i < AUX_MAX_RETRIES; i++) { + ret = dce_aux_transfer_raw(ddc, payload, &operation_result); + switch (operation_result) { + case AUX_CHANNEL_OPERATION_SUCCEEDED: + aux_timeout_retries = 0; + aux_invalid_reply_retries = 0; + + switch (*payload->reply) { + case AUX_TRANSACTION_REPLY_AUX_ACK: + if (!payload->write && payload->length != ret) { + if (++aux_ack_retries >= AUX_MAX_RETRIES) + goto fail; + else + udelay(300); + } else + return true; + break; + + case AUX_TRANSACTION_REPLY_AUX_DEFER: + case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_NACK: + case AUX_TRANSACTION_REPLY_I2C_OVER_AUX_DEFER: + if (++aux_defer_retries >= AUX_MAX_DEFER_RETRIES) + goto fail; + break; + + case AUX_TRANSACTION_REPLY_I2C_DEFER: + aux_defer_retries = 0; + if (++aux_i2c_defer_retries >= AUX_MAX_I2C_DEFER_RETRIES) + goto fail; + break; + + case AUX_TRANSACTION_REPLY_AUX_NACK: + case AUX_TRANSACTION_REPLY_HPD_DISCON: + default: + goto fail; } - } + break; + + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: + if (++aux_invalid_reply_retries >= AUX_MAX_INVALID_REPLY_RETRIES) + goto fail; + else + udelay(400); + break; + + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: + if (++aux_timeout_retries >= AUX_MAX_TIMEOUT_RETRIES) + goto fail; + else { + /* + * DP 1.4, 2.8.2: AUX Transaction Response/Reply Timeouts + * According to the DP spec there should be 3 retries total + * with a 400us wait inbetween each. Hardware already waits + * for 550us therefore no wait is required here. + */ + } + break; - udelay(1000); + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: + case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: + default: + goto fail; + } } + +fail: + if (!payload_reply) + payload->reply = NULL; return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h index d27f22c05e4b..aab5f0c34584 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h @@ -123,8 +123,9 @@ bool dce110_aux_engine_acquire( struct dce_aux *aux_engine, struct ddc *ddc); -int dce_aux_transfer(struct ddc_service *ddc, - struct aux_payload *cmd); +int dce_aux_transfer_raw(struct ddc_service *ddc, + struct aux_payload *cmd, + enum aux_channel_operation_result *operation_result); bool dce_aux_transfer_with_retries(struct ddc_service *ddc, struct aux_payload *cmd); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 71d5777de961..f70437aae8e0 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -978,7 +978,7 @@ static bool dce110_clock_source_power_down( } static bool get_pixel_clk_frequency_100hz( - struct clock_source *clock_source, + const struct clock_source *clock_source, unsigned int inst, unsigned int *pixel_clk_khz) { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index c2926cf19dee..aa586672e8cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -213,9 +213,6 @@ static bool dce_dmcu_setup_psr(struct dmcu *dmcu, link->link_enc->funcs->psr_program_secondary_packet(link->link_enc, psr_context->sdpTransmitLineNumDeadline); - if (psr_context->psr_level.bits.SKIP_SMU_NOTIFICATION) - REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1); - /* waitDMCUReadyForCmd */ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, dmcu_wait_reg_ready_interval, @@ -594,7 +591,7 @@ static bool dcn10_dmcu_setup_psr(struct dmcu *dmcu, link->link_enc->funcs->psr_program_secondary_packet(link->link_enc, psr_context->sdpTransmitLineNumDeadline); - if (psr_context->psr_level.bits.SKIP_SMU_NOTIFICATION) + if (psr_context->allow_smu_optimizations) REG_UPDATE(SMU_INTERRUPT_CONTROL, DC_SMU_INT_ENABLE, 1); /* waitDMCUReadyForCmd */ @@ -615,6 +612,7 @@ static bool dcn10_dmcu_setup_psr(struct dmcu *dmcu, psr_context->psrFrameCaptureIndicationReq; masterCmdData1.bits.aux_chan = psr_context->channel; masterCmdData1.bits.aux_repeat = psr_context->aux_repeats; + masterCmdData1.bits.allow_smu_optimizations = psr_context->allow_smu_optimizations; dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG1), masterCmdData1.u32All); @@ -635,6 +633,7 @@ static bool dcn10_dmcu_setup_psr(struct dmcu *dmcu, dm_write_reg(dmcu->ctx, REG(MASTER_COMM_DATA_REG3), masterCmdData3.u32All); + /* setDMCUParam_Cmd */ REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, PSR_SET); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h index c24c0e5ea44e..60ce56f60ae3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h @@ -199,16 +199,16 @@ struct dce_dmcu { ******************************************************************/ union dce_dmcu_psr_config_data_reg1 { struct { - unsigned int timehyst_frames:8; /*[7:0]*/ - unsigned int hyst_lines:7; /*[14:8]*/ - unsigned int rfb_update_auto_en:1; /*[15:15]*/ - unsigned int dp_port_num:3; /*[18:16]*/ - unsigned int dcp_sel:3; /*[21:19]*/ - unsigned int phy_type:1; /*[22:22]*/ - unsigned int frame_cap_ind:1; /*[23:23]*/ - unsigned int aux_chan:3; /*[26:24]*/ - unsigned int aux_repeat:4; /*[30:27]*/ - unsigned int reserved:1; /*[31:31]*/ + unsigned int timehyst_frames:8; /*[7:0]*/ + unsigned int hyst_lines:7; /*[14:8]*/ + unsigned int rfb_update_auto_en:1; /*[15:15]*/ + unsigned int dp_port_num:3; /*[18:16]*/ + unsigned int dcp_sel:3; /*[21:19]*/ + unsigned int phy_type:1; /*[22:22]*/ + unsigned int frame_cap_ind:1; /*[23:23]*/ + unsigned int aux_chan:3; /*[26:24]*/ + unsigned int aux_repeat:4; /*[30:27]*/ + unsigned int allow_smu_optimizations:1; /*[31:31]*/ } bits; unsigned int u32All; }; @@ -236,7 +236,7 @@ union dce_dmcu_psr_config_data_reg3 { struct { unsigned int psr_level:16; /*[15:0]*/ unsigned int link_rate:4; /*[19:16]*/ - unsigned int reserved:12; /*[31:20]*/ + unsigned int reserved:12; /*[31:20]*/ } bits; unsigned int u32All; }; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c index 40f2d6e0b122..cd26161bcc4d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c @@ -346,6 +346,16 @@ static void release_engine( } +static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw) +{ + unsigned int arbitrate; + + REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate); + if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY) + return false; + return true; +} + struct dce_i2c_hw *acquire_i2c_hw_engine( struct resource_pool *pool, struct ddc *ddc) @@ -368,7 +378,7 @@ struct dce_i2c_hw *acquire_i2c_hw_engine( if (!dce_i2c_hw) return NULL; - if (pool->i2c_hw_buffer_in_use) + if (pool->i2c_hw_buffer_in_use || !is_engine_available(dce_i2c_hw)) return NULL; do { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h index 7f19bb439665..575500755b2e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h @@ -29,7 +29,8 @@ enum dc_i2c_status { DC_I2C_STATUS__DC_I2C_STATUS_IDLE, DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW, - DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW + DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW, + DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY = 2, }; enum dc_i2c_arbitration { @@ -129,7 +130,8 @@ enum { I2C_SF(DC_I2C_DATA, DC_I2C_DATA, mask_sh),\ I2C_SF(DC_I2C_DATA, DC_I2C_INDEX, mask_sh),\ I2C_SF(DC_I2C_DATA, DC_I2C_INDEX_WRITE, mask_sh),\ - I2C_SF(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, mask_sh) + I2C_SF(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, mask_sh),\ + I2C_SF(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, mask_sh) #define I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh)\ I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh),\ @@ -170,6 +172,7 @@ struct dce_i2c_shift { uint8_t DC_I2C_INDEX; uint8_t DC_I2C_INDEX_WRITE; uint8_t XTAL_REF_DIV; + uint8_t DC_I2C_REG_RW_CNTL_STATUS; }; struct dce_i2c_mask { @@ -207,6 +210,7 @@ struct dce_i2c_mask { uint32_t DC_I2C_INDEX; uint32_t DC_I2C_INDEX_WRITE; uint32_t XTAL_REF_DIV; + uint32_t DC_I2C_REG_RW_CNTL_STATUS; }; struct dce_i2c_registers { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 1fa2d4fd7a35..14309fe6f2e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -272,7 +272,8 @@ static void dce110_update_hdmi_info_packet( static void dce110_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, - enum dc_color_space output_color_space) + enum dc_color_space output_color_space, + uint32_t enable_sdp_splitting) { #if defined(CONFIG_DRM_AMD_DC_DCN1_0) uint32_t h_active_start; @@ -977,7 +978,7 @@ static void dce110_stream_encoder_dp_unblank( uint64_t m_vid_l = n_vid; - m_vid_l *= param->pixel_clk_khz; + m_vid_l *= param->timing.pix_clk_100hz / 10; m_vid_l = div_u64(m_vid_l, param->link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ); |