static void execute_transaction( struct dce_i2c_hw *dce_i2c_hw) { REG_UPDATE_N(SETUP, 5, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY), 0, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY), 0); REG_UPDATE_5(DC_I2C_CONTROL, DC_I2C_SOFT_RESET, 0, DC_I2C_SW_STATUS_RESET, 0, DC_I2C_SEND_RESET, 0, DC_I2C_GO, 0, DC_I2C_TRANSACTION_COUNT, dce_i2c_hw->transaction_count - 1); /* start I2C transfer */ REG_UPDATE(DC_I2C_CONTROL, DC_I2C_GO, 1); /* all transactions were executed and HW buffer became empty * (even though it actually happens when status becomes DONE) */ dce_i2c_hw->transaction_count = 0; dce_i2c_hw->buffer_used_bytes = 0; }
static void dce110_se_disable_dp_audio( struct stream_encoder *enc) { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); uint32_t value = REG_READ(DP_SEC_CNTL); /* Disable Audio packets */ REG_UPDATE_5(DP_SEC_CNTL, DP_SEC_ASP_ENABLE, 0, DP_SEC_ATP_ENABLE, 0, DP_SEC_AIP_ENABLE, 0, DP_SEC_ACM_ENABLE, 0, DP_SEC_STREAM_ENABLE, 0); /* This register shared with encoder info frame. Therefore we need to keep master enabled if at least on of the fields is not 0 */ if (value != 0) REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1); }
static bool process_transaction( struct dce_i2c_hw *dce_i2c_hw, struct i2c_request_transaction_data *request) { uint32_t length = request->length; uint8_t *buffer = request->data; bool last_transaction = false; uint32_t value = 0; last_transaction = ((dce_i2c_hw->transaction_count == 3) || (request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) || (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)); switch (dce_i2c_hw->transaction_count) { case 0: REG_UPDATE_5(DC_I2C_TRANSACTION0, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; case 1: REG_UPDATE_5(DC_I2C_TRANSACTION1, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; case 2: REG_UPDATE_5(DC_I2C_TRANSACTION2, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; case 3: REG_UPDATE_5(DC_I2C_TRANSACTION3, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; default: /* TODO Warning ? */ break; } /* Write the I2C address and I2C data * into the hardware circular buffer, one byte per entry. * As an example, the 7-bit I2C slave address for CRT monitor * for reading DDC/EDID information is 0b1010001. * For an I2C send operation, the LSB must be programmed to 0; * for I2C receive operation, the LSB must be programmed to 1. */ if (dce_i2c_hw->transaction_count == 0) { value = REG_SET_4(DC_I2C_DATA, 0, DC_I2C_DATA_RW, false, DC_I2C_DATA, request->address, DC_I2C_INDEX, 0, DC_I2C_INDEX_WRITE, 1); dce_i2c_hw->buffer_used_write = 0; } else value = REG_SET_2(DC_I2C_DATA, 0, DC_I2C_DATA_RW, false, DC_I2C_DATA, request->address); dce_i2c_hw->buffer_used_write++; if (!(request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)) { while (length) { REG_SET_2(DC_I2C_DATA, value, DC_I2C_INDEX_WRITE, 0, DC_I2C_DATA, *buffer++); dce_i2c_hw->buffer_used_write++; --length; } } ++dce_i2c_hw->transaction_count; dce_i2c_hw->buffer_used_bytes += length + 1; return last_transaction; }
/* setup stream encoder in hdmi mode */ static void dce110_stream_encoder_hdmi_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, int actual_pix_clk_khz, bool enable_audio) { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); struct bp_encoder_control cntl = {0}; cntl.action = ENCODER_CONTROL_SETUP; cntl.engine_id = enc110->base.id; cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; cntl.enable_dp_audio = enable_audio; cntl.pixel_clock = actual_pix_clk_khz; cntl.lanes_number = LANE_COUNT_FOUR; if (enc110->base.bp->funcs->encoder_control( enc110->base.bp, &cntl) != BP_RESULT_OK) return; dce110_stream_encoder_set_stream_attribute_helper(enc110, crtc_timing); /* setup HDMI engine */ if (!enc110->se_mask->HDMI_DATA_SCRAMBLE_EN) { REG_UPDATE_3(HDMI_CONTROL, HDMI_PACKET_GEN_VERSION, 1, HDMI_KEEPOUT_MODE, 1, HDMI_DEEP_COLOR_ENABLE, 0); } else if (enc110->regs->DIG_FE_CNTL) { REG_UPDATE_5(HDMI_CONTROL, HDMI_PACKET_GEN_VERSION, 1, HDMI_KEEPOUT_MODE, 1, HDMI_DEEP_COLOR_ENABLE, 0, HDMI_DATA_SCRAMBLE_EN, 0, HDMI_CLOCK_CHANNEL_RATE, 0); } switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_888: REG_UPDATE(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 0); break; case COLOR_DEPTH_101010: if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) { REG_UPDATE_2(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 1, HDMI_DEEP_COLOR_ENABLE, 0); } else { REG_UPDATE_2(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 1, HDMI_DEEP_COLOR_ENABLE, 1); } break; case COLOR_DEPTH_121212: if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) { REG_UPDATE_2(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 2, HDMI_DEEP_COLOR_ENABLE, 0); } else { REG_UPDATE_2(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 2, HDMI_DEEP_COLOR_ENABLE, 1); } break; case COLOR_DEPTH_161616: REG_UPDATE_2(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 3, HDMI_DEEP_COLOR_ENABLE, 1); break; default: break; } if (enc110->se_mask->HDMI_DATA_SCRAMBLE_EN) { if (actual_pix_clk_khz >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) { /* enable HDMI data scrambler * HDMI_CLOCK_CHANNEL_RATE_MORE_340M * Clock channel frequency is 1/4 of character rate. */ REG_UPDATE_2(HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN, 1, HDMI_CLOCK_CHANNEL_RATE, 1); } else if (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) { /* TODO: New feature for DCE11, still need to implement */ /* enable HDMI data scrambler * HDMI_CLOCK_CHANNEL_FREQ_EQUAL_TO_CHAR_RATE * Clock channel frequency is the same * as character rate */ REG_UPDATE_2(HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN, 1, HDMI_CLOCK_CHANNEL_RATE, 0); } } REG_UPDATE_3(HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT, 1, HDMI_GC_SEND, 1, HDMI_NULL_SEND, 1); /* following belongs to audio */ REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, 1); REG_UPDATE(AFMT_INFOFRAME_CONTROL0, AFMT_AUDIO_INFO_UPDATE, 1); REG_UPDATE(HDMI_INFOFRAME_CONTROL1, HDMI_AUDIO_INFO_LINE, VBI_LINE_0 + 2); REG_UPDATE(HDMI_GC, HDMI_GC_AVMUTE, 0); }