bool dce110_compressor_is_fbc_enabled_in_hw( struct compressor *compressor, uint32_t *inst) { /* Check the hardware register */ uint32_t value; value = dm_read_reg(compressor->ctx, mmFBC_STATUS); if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) { if (inst != NULL) *inst = compressor->attached_inst; return true; } value = dm_read_reg(compressor->ctx, mmFBC_MISC); if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) { value = dm_read_reg(compressor->ctx, mmFBC_CNTL); if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) { if (inst != NULL) *inst = compressor->attached_inst; return true; } } return false; }
static bool is_hw_busy(struct engine *engine) { uint32_t i2c_sw_status = 0; uint32_t value = dal_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); i2c_sw_status = get_reg_field_value( value, DC_I2C_SW_STATUS, DC_I2C_SW_STATUS); if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE) return false; reset_hw_engine(engine); value = dal_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); i2c_sw_status = get_reg_field_value( value, DC_I2C_SW_STATUS, DC_I2C_SW_STATUS); return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE; }
/* * Function: * void setup_scaling_configuration * * Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps * Input: data * * Output: * void */ static bool setup_scaling_configuration( struct dce110_transform *xfm110, const struct scaler_data *data) { bool is_scaling_needed = false; struct dc_context *ctx = xfm110->base.ctx; uint32_t value = 0; if (data->taps.h_taps + data->taps.v_taps > 2) { set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE); set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN); is_scaling_needed = true; } else { set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE); set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN); } if (data->taps.h_taps_c + data->taps.v_taps_c > 2) { set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE_C); set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN_C); is_scaling_needed = true; } else if (data->format != PIXEL_FORMAT_420BPP12) { set_reg_field_value( value, get_reg_field_value(value, SCLV_MODE, SCL_MODE), SCLV_MODE, SCL_MODE_C); set_reg_field_value( value, get_reg_field_value(value, SCLV_MODE, SCL_PSCL_EN), SCLV_MODE, SCL_PSCL_EN_C); } else { set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE_C); set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN_C); } dm_write_reg(ctx, mmSCLV_MODE, value); value = 0; set_reg_field_value(value, data->taps.h_taps - 1, SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS); set_reg_field_value(value, data->taps.v_taps - 1, SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS); set_reg_field_value(value, data->taps.h_taps_c - 1, SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS_C); set_reg_field_value(value, data->taps.v_taps_c - 1, SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS_C); dm_write_reg(ctx, mmSCLV_TAP_CONTROL, value); value = 0; /* * 0 - Replaced out of bound pixels with black pixel * (or any other required color) * 1 - Replaced out of bound pixels with the edge pixel */ set_reg_field_value(value, 1, SCLV_CONTROL, SCL_BOUNDARY_MODE); dm_write_reg(ctx, mmSCLV_CONTROL, value); return is_scaling_needed; }
static enum gpio_result get_value( const struct hw_gpio_pin *ptr, uint32_t *value) { struct hw_hpd_dce110 *pin = HPD_DCE110_FROM_BASE(ptr); /* in Interrupt mode we ask for SENSE bit */ if (ptr->mode == GPIO_MODE_INTERRUPT) { uint32_t regval; uint32_t hpd_delayed = 0; uint32_t hpd_sense = 0; regval = dm_read_reg( ptr->ctx, pin->addr.DC_HPD_INT_STATUS); hpd_delayed = get_reg_field_value( regval, DC_HPD_INT_STATUS, DC_HPD_SENSE_DELAYED); hpd_sense = get_reg_field_value( regval, DC_HPD_INT_STATUS, DC_HPD_SENSE); *value = hpd_delayed; return GPIO_RESULT_OK; } /* in any other modes, operate as normal GPIO */ return dal_hw_gpio_get_value(ptr, value); }
static void power_on_lut(struct transform *xfm, bool power_on, bool inputgamma, bool regamma) { uint32_t value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL); int i; if (power_on) { if (inputgamma) set_reg_field_value( value, 1, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_DIS); if (regamma) set_reg_field_value( value, 1, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_DIS); } else { if (inputgamma) set_reg_field_value( value, 0, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_DIS); if (regamma) set_reg_field_value( value, 0, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_DIS); } dm_write_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL, value); for (i = 0; i < 3; i++) { value = dm_read_reg(xfm->ctx, mmDCFEV_MEM_PWR_CTRL); if (get_reg_field_value(value, DCFEV_MEM_PWR_CTRL, COL_MAN_INPUT_GAMMA_MEM_PWR_DIS) && get_reg_field_value(value, DCFEV_MEM_PWR_CTRL, COL_MAN_GAMMA_CORR_MEM_PWR_DIS)) break; udelay(2); } }
static enum i2c_channel_operation_result get_channel_status( struct i2c_engine *engine, uint8_t *returned_bytes) { uint32_t i2c_sw_status = 0; uint32_t value = dal_read_reg(engine->base.ctx, mmDC_I2C_SW_STATUS); i2c_sw_status = get_reg_field_value( value, DC_I2C_SW_STATUS, DC_I2C_SW_STATUS); if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW) return I2C_CHANNEL_OPERATION_ENGINE_BUSY; else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_STOPPED_ON_NACK_MASK) return I2C_CHANNEL_OPERATION_NO_RESPONSE; else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_TIMEOUT_MASK) return I2C_CHANNEL_OPERATION_TIMEOUT; else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_ABORTED_MASK) return I2C_CHANNEL_OPERATION_FAILED; else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_DONE_MASK) return I2C_CHANNEL_OPERATION_SUCCEEDED; /* in DAL2, I2C_RESULT_OK was returned */ return I2C_CHANNEL_OPERATION_NOT_STARTED; }
static bool hpd_ack( struct irq_service *irq_service, const struct irq_source_info *info) { uint32_t addr = info->status_reg; uint32_t value = dm_read_reg(irq_service->ctx, addr); uint32_t current_status = get_reg_field_value( value, HPD0_DC_HPD_INT_STATUS, DC_HPD_SENSE_DELAYED); dal_irq_service_ack_generic(irq_service, info); value = dm_read_reg(irq_service->ctx, info->enable_reg); set_reg_field_value( value, current_status ? 0 : 1, HPD0_DC_HPD_INT_CONTROL, DC_HPD_INT_POLARITY); dm_write_reg(irq_service->ctx, info->enable_reg, value); return true; }
static uint32_t get_clock(struct display_clock *dc) { uint32_t disp_clock = get_validation_clock(dc); uint32_t target_div = INVALID_DIVIDER; uint32_t addr = mmDENTIST_DISPCLK_CNTL; uint32_t value = 0; uint32_t field = 0; struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc); if (disp_clk->dfs_bypass_enabled && disp_clk->dfs_bypass_disp_clk) return disp_clk->dfs_bypass_disp_clk; /* Read the mmDENTIST_DISPCLK_CNTL to get the currently programmed DID DENTIST_DISPCLK_WDIVIDER.*/ value = dm_read_reg(dc->ctx, addr); field = get_reg_field_value( value, DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER); /* Convert DENTIST_DISPCLK_WDIVIDER to actual divider*/ target_div = dal_divider_range_get_divider( divider_ranges, DIVIDER_RANGE_MAX, field); if (target_div != INVALID_DIVIDER) /* Calculate the current DFS clock in KHz. Should be okay up to 42.9 THz before overflowing.*/ disp_clock = (DIVIDER_RANGE_SCALE_FACTOR * disp_clk->dentist_vco_freq_khz) / target_div; return disp_clock; }
static void wait_for_fbc_state_changed( struct dce110_compressor *cp110, bool enabled) { uint8_t counter = 0; uint32_t addr = mmFBC_STATUS; uint32_t value; while (counter < 10) { value = dm_read_reg(cp110->base.ctx, addr); if (get_reg_field_value( value, FBC_STATUS, FBC_ENABLE_STATUS) == enabled) break; msleep(10); counter++; } if (counter == 10) { DC_LOG_WARNING("%s: wait counter exceeded, changes to HW not applied", __func__); } else { DC_LOG_SYNC("FBC status changed to %d", enabled); } }
static void enable_afmt_clock( const struct hw_ctx_audio *hw_ctx, enum engine_id engine_id, bool enable_flag) { uint32_t engine_offs = engine_offset[engine_id]; uint32_t value; uint32_t count = 0; uint32_t enable = enable_flag ? 1:0; /* Enable Audio packets*/ value = dal_read_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs); /*enable AFMT clock*/ set_reg_field_value(value, enable, AFMT_CNTL, AFMT_AUDIO_CLOCK_EN); dal_write_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs, value); /*wait for AFMT clock to turn on, * the expectation is that this * should complete in 1-2 reads) */ do { /* Wait for 1us between subsequent register reads.*/ dal_delay_in_microseconds(1); value = dal_read_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs); } while (get_reg_field_value(value, AFMT_CNTL, AFMT_AUDIO_CLOCK_ON) != enable && count++ < 10); }
static void read_dce_straps( struct dc_context *ctx, struct resource_straps *straps) { uint32_t reg_val = dm_read_reg_soc15(ctx, mmCC_DC_MISC_STRAPS, 0); straps->audio_stream_number = get_reg_field_value(reg_val, CC_DC_MISC_STRAPS, AUDIO_STREAM_NUMBER); straps->hdmi_disable = get_reg_field_value(reg_val, CC_DC_MISC_STRAPS, HDMI_DISABLE); reg_val = dm_read_reg_soc15(ctx, mmDC_PINSTRAPS, 0); straps->dc_pinstraps_audio = get_reg_field_value(reg_val, DC_PINSTRAPS, DC_PINSTRAPS_AUDIO); }
static uint32_t dce110_timing_generator_v_get_vblank_counter(struct timing_generator *tg) { uint32_t addr = mmCRTCV_STATUS_FRAME_COUNT; uint32_t value = dm_read_reg(tg->ctx, addr); uint32_t field = get_reg_field_value( value, CRTCV_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT); return field; }
static bool dce110_timing_generator_v_is_in_vertical_blank( struct timing_generator *tg) { uint32_t addr = 0; uint32_t value = 0; uint32_t field = 0; addr = mmCRTCV_STATUS; value = dm_read_reg(tg->ctx, addr); field = get_reg_field_value(value, CRTCV_STATUS, CRTC_V_BLANK); return field == 1; }
static bool dce_aud_endpoint_valid(struct audio *audio) { uint32_t value; uint32_t port_connectivity; value = AZ_REG_READ( AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT); port_connectivity = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT, PORT_CONNECTIVITY); return !(port_connectivity == 1); }
bool dce_mem_input_v_is_surface_pending(struct mem_input *mem_input) { struct dce_mem_input *mem_input110 = TO_DCE_MEM_INPUT(mem_input); uint32_t value; value = dm_read_reg(mem_input110->base.ctx, mmUNP_GRPH_UPDATE); if (get_reg_field_value(value, UNP_GRPH_UPDATE, GRPH_SURFACE_UPDATE_PENDING)) return true; mem_input->current_address = mem_input->request_address; return false; }
static bool dce110_timing_generator_v_is_counter_moving(struct timing_generator *tg) { uint32_t value; uint32_t h1 = 0; uint32_t h2 = 0; uint32_t v1 = 0; uint32_t v2 = 0; value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION); h1 = get_reg_field_value( value, CRTCV_STATUS_POSITION, CRTC_HORZ_COUNT); v1 = get_reg_field_value( value, CRTCV_STATUS_POSITION, CRTC_VERT_COUNT); value = dm_read_reg(tg->ctx, mmCRTCV_STATUS_POSITION); h2 = get_reg_field_value( value, CRTCV_STATUS_POSITION, CRTC_HORZ_COUNT); v2 = get_reg_field_value( value, CRTCV_STATUS_POSITION, CRTC_VERT_COUNT); if (h1 == h2 && v1 == v2) return false; else return true; }
static void process_channel_reply( struct i2c_engine *engine, struct i2c_reply_transaction_data *reply) { uint8_t length = reply->length; uint8_t *buffer = reply->data; struct i2c_hw_engine_dce110 *i2c_hw_engine_dce110 = FROM_I2C_ENGINE(engine); uint32_t value = dal_read_reg(engine->base.ctx, mmDC_I2C_DATA); /*set index*/ set_reg_field_value( value, i2c_hw_engine_dce110->buffer_used_write, DC_I2C_DATA, DC_I2C_INDEX); set_reg_field_value( value, 1, DC_I2C_DATA, DC_I2C_DATA_RW); set_reg_field_value( value, 1, DC_I2C_DATA, DC_I2C_INDEX_WRITE); dal_write_reg(engine->base.ctx, mmDC_I2C_DATA, value); while (length) { /* after reading the status, * if the I2C operation executed successfully * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller * should read data bytes from I2C circular data buffer */ value = dal_read_reg(engine->base.ctx, mmDC_I2C_DATA); *buffer++ = get_reg_field_value( value, DC_I2C_DATA, DC_I2C_DATA); --length; } }
/* enable Azalia audio */ static void enable_azalia_audio( const struct hw_ctx_audio *hw_ctx, enum engine_id engine_id) { uint32_t value; value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL); if (get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, AUDIO_ENABLED) != 1) set_reg_field_value(value, 1, AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, AUDIO_ENABLED); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value); }
static bool get_current_pixel_storage_depth( struct line_buffer *base, enum lb_pixel_depth *depth) { struct line_buffer_dce110 *lb = LB110_FROM_BASE(base); uint32_t value = 0; if (depth == NULL) return false; value = dal_read_reg( base->dal_context, lb->lbx_data_format); switch (get_reg_field_value(value, LB_DATA_FORMAT, PIXEL_DEPTH)) { case 0: *depth = LB_PIXEL_DEPTH_30BPP; break; case 1: *depth = LB_PIXEL_DEPTH_24BPP; break; case 2: *depth = LB_PIXEL_DEPTH_18BPP; break; case 3: *depth = LB_PIXEL_DEPTH_36BPP; break; default: dal_logger_write(base->dal_context->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "%s: Invalid LB pixel depth", __func__); *depth = LB_PIXEL_DEPTH_30BPP; break; } return true; }
static uint32_t get_speed( const struct i2c_engine *i2c_engine) { const struct i2c_hw_engine_dce110 *engine = FROM_I2C_ENGINE(i2c_engine); const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED; uint32_t pre_scale = 0; uint32_t value = dal_read_reg(i2c_engine->base.ctx, addr); pre_scale = get_reg_field_value( value, DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE); /* [anaumov] it seems following is unnecessary */ /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/ return pre_scale ? engine->reference_frequency / pre_scale : engine->base.default_speed; }
static void program_color_matrix_v( struct dce_transform *xfm_dce, const struct out_csc_color_matrix *tbl_entry, enum grph_color_adjust_option options) { struct dc_context *ctx = xfm_dce->base.ctx; uint32_t cntl_value = dm_read_reg(ctx, mmCOL_MAN_OUTPUT_CSC_CONTROL); bool use_set_a = (get_reg_field_value(cntl_value, COL_MAN_OUTPUT_CSC_CONTROL, OUTPUT_CSC_MODE) != 4); set_reg_field_value( cntl_value, 0, COL_MAN_OUTPUT_CSC_CONTROL, OUTPUT_CSC_MODE); if (use_set_a) { { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C11_C12_A; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[0], OUTPUT_CSC_C11_C12_A, OUTPUT_CSC_C11_A); set_reg_field_value( value, tbl_entry->regval[1], OUTPUT_CSC_C11_C12_A, OUTPUT_CSC_C12_A); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C13_C14_A; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[2], OUTPUT_CSC_C13_C14_A, OUTPUT_CSC_C13_A); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[3], OUTPUT_CSC_C13_C14_A, OUTPUT_CSC_C14_A); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C21_C22_A; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[4], OUTPUT_CSC_C21_C22_A, OUTPUT_CSC_C21_A); /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[5], OUTPUT_CSC_C21_C22_A, OUTPUT_CSC_C22_A); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C23_C24_A; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[6], OUTPUT_CSC_C23_C24_A, OUTPUT_CSC_C23_A); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[7], OUTPUT_CSC_C23_C24_A, OUTPUT_CSC_C24_A); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C31_C32_A; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[8], OUTPUT_CSC_C31_C32_A, OUTPUT_CSC_C31_A); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[9], OUTPUT_CSC_C31_C32_A, OUTPUT_CSC_C32_A); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C33_C34_A; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[10], OUTPUT_CSC_C33_C34_A, OUTPUT_CSC_C33_A); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[11], OUTPUT_CSC_C33_C34_A, OUTPUT_CSC_C34_A); dm_write_reg(ctx, addr, value); } set_reg_field_value( cntl_value, 4, COL_MAN_OUTPUT_CSC_CONTROL, OUTPUT_CSC_MODE); } else { { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C11_C12_B; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[0], OUTPUT_CSC_C11_C12_B, OUTPUT_CSC_C11_B); set_reg_field_value( value, tbl_entry->regval[1], OUTPUT_CSC_C11_C12_B, OUTPUT_CSC_C12_B); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C13_C14_B; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[2], OUTPUT_CSC_C13_C14_B, OUTPUT_CSC_C13_B); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[3], OUTPUT_CSC_C13_C14_B, OUTPUT_CSC_C14_B); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C21_C22_B; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[4], OUTPUT_CSC_C21_C22_B, OUTPUT_CSC_C21_B); /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[5], OUTPUT_CSC_C21_C22_B, OUTPUT_CSC_C22_B); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C23_C24_B; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[6], OUTPUT_CSC_C23_C24_B, OUTPUT_CSC_C23_B); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[7], OUTPUT_CSC_C23_C24_B, OUTPUT_CSC_C24_B); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C31_C32_B; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[8], OUTPUT_CSC_C31_C32_B, OUTPUT_CSC_C31_B); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[9], OUTPUT_CSC_C31_C32_B, OUTPUT_CSC_C32_B); dm_write_reg(ctx, addr, value); } { uint32_t value = 0; uint32_t addr = mmOUTPUT_CSC_C33_C34_B; /* fixed S2.13 format */ set_reg_field_value( value, tbl_entry->regval[10], OUTPUT_CSC_C33_C34_B, OUTPUT_CSC_C33_B); /* fixed S0.13 format */ set_reg_field_value( value, tbl_entry->regval[11], OUTPUT_CSC_C33_C34_B, OUTPUT_CSC_C34_B); dm_write_reg(ctx, addr, value); } set_reg_field_value( cntl_value, 5, COL_MAN_OUTPUT_CSC_CONTROL, OUTPUT_CSC_MODE); } dm_write_reg(ctx, mmCOL_MAN_OUTPUT_CSC_CONTROL, cntl_value); }
static enum gpio_result set_config( struct hw_gpio_pin *ptr, const struct gpio_config_data *config_data) { struct hw_ddc_dce80 *pin = FROM_HW_GPIO_PIN(ptr); struct hw_gpio *hw_gpio = NULL; uint32_t addr; uint32_t regval; uint32_t ddc_data_pd_en = 0; uint32_t ddc_clk_pd_en = 0; uint32_t aux_pad_mode = 0; hw_gpio = &pin->base.base; if (hw_gpio == NULL) { ASSERT_CRITICAL(false); return GPIO_RESULT_NULL_HANDLE; } /* switch dual mode GPIO to I2C/AUX mode */ addr = hw_gpio->pin_reg.DC_GPIO_DATA_MASK.addr; regval = dm_read_reg(ptr->ctx, addr); ddc_data_pd_en = get_reg_field_value( regval, DC_GPIO_DDC1_MASK, DC_GPIO_DDC1DATA_PD_EN); ddc_clk_pd_en = get_reg_field_value( regval, DC_GPIO_DDC1_MASK, DC_GPIO_DDC1CLK_PD_EN); aux_pad_mode = get_reg_field_value( regval, DC_GPIO_DDC1_MASK, AUX_PAD1_MODE); switch (config_data->config.ddc.type) { case GPIO_DDC_CONFIG_TYPE_MODE_I2C: /* On plug-in, there is a transient level on the pad * which must be discharged through the internal pull-down. * Enable internal pull-down, 2.5msec discharge time * is required for detection of AUX mode */ if (hw_gpio->base.en != GPIO_DDC_LINE_VIP_PAD) { if (!ddc_data_pd_en || !ddc_clk_pd_en) { set_reg_field_value( regval, 1, DC_GPIO_DDC1_MASK, DC_GPIO_DDC1DATA_PD_EN); set_reg_field_value( regval, 1, DC_GPIO_DDC1_MASK, DC_GPIO_DDC1CLK_PD_EN); dm_write_reg(ptr->ctx, addr, regval); if (config_data->type == GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) /* should not affect normal I2C R/W */ /* [anaumov] in DAL2, there was * dc_service_delay_in_microseconds(2500); */ msleep(3); } } else { uint32_t reg2 = regval; uint32_t sda_pd_dis = 0; uint32_t scl_pd_dis = 0; sda_pd_dis = get_reg_field_value( reg2, DC_GPIO_I2CPAD_MASK, DC_GPIO_SDA_PD_DIS); scl_pd_dis = get_reg_field_value( reg2, DC_GPIO_I2CPAD_MASK, DC_GPIO_SCL_PD_DIS); if (sda_pd_dis) { sda_pd_dis = 0; dm_write_reg(ptr->ctx, addr, reg2); if (config_data->type == GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) /* should not affect normal I2C R/W */ /* [anaumov] in DAL2, there was * dc_service_delay_in_microseconds(2500); */ msleep(3); } if (!scl_pd_dis) { scl_pd_dis = 1; dm_write_reg(ptr->ctx, addr, reg2); if (config_data->type == GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) /* should not affect normal I2C R/W */ /* [anaumov] in DAL2, there was * dc_service_delay_in_microseconds(2500); */ msleep(3); } } if (aux_pad_mode) { /* let pins to get de-asserted * before setting pad to I2C mode */ if (config_data->config.ddc.data_en_bit_present || config_data->config.ddc.clock_en_bit_present) /* [anaumov] in DAL2, there was * dc_service_delay_in_microseconds(2000); */ msleep(2); /* set the I2C pad mode */ /* read the register again, * some bits may have been changed */ regval = dm_read_reg(ptr->ctx, addr); set_reg_field_value( regval, 0, DC_GPIO_DDC1_MASK, AUX_PAD1_MODE); dm_write_reg(ptr->ctx, addr, regval); } return GPIO_RESULT_OK; case GPIO_DDC_CONFIG_TYPE_MODE_AUX: /* set the AUX pad mode */ if (!aux_pad_mode) { set_reg_field_value( regval, 1, DC_GPIO_DDC1_MASK, AUX_PAD1_MODE); dm_write_reg(ptr->ctx, addr, regval); } return GPIO_RESULT_OK; case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT: if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) && (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) { setup_i2c_polling( ptr->ctx, pin->addr.dc_i2c_ddc_setup, 1, 0); return GPIO_RESULT_OK; } break; case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT: if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) && (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) { setup_i2c_polling( ptr->ctx, pin->addr.dc_i2c_ddc_setup, 1, 1); return GPIO_RESULT_OK; } break; case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING: if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) && (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) { setup_i2c_polling( ptr->ctx, pin->addr.dc_i2c_ddc_setup, 0, 0); return GPIO_RESULT_OK; } break; } BREAK_TO_DEBUGGER(); return GPIO_RESULT_NON_SPECIFIC_ERROR; }
/* get current channel spliting */ static bool get_channel_splitting_mapping( const struct hw_ctx_audio *hw_ctx, enum engine_id engine_id, struct audio_channel_associate_info *audio_mapping) { uint32_t value = 0; if (audio_mapping == NULL) return false; value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO); /*0xFFFFFFFF*/ if (get_reg_field_value(value, AZALIA_F0_CODEC_PIN_ASSOCIATION_INFO, ASSOCIATION_INFO) != MULTI_CHANNEL_SPLIT_NO_ASSO_INFO) { uint32_t multi_channel01_enable = 0; uint32_t multi_channel23_enable = 0; uint32_t multi_channel45_enable = 0; uint32_t multi_channel67_enable = 0; /* get the one we set.*/ audio_mapping->u32all = value; /* check each enable status*/ value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE); multi_channel01_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL01_ENABLE); multi_channel23_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL23_ENABLE); multi_channel45_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL45_ENABLE); multi_channel67_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL67_ENABLE); if (multi_channel01_enable == 0 && multi_channel23_enable == 0 && multi_channel45_enable == 0 && multi_channel67_enable == 0) dal_logger_write(hw_ctx->ctx->logger, LOG_MAJOR_HW_TRACE, LOG_MINOR_COMPONENT_AUDIO, "Audio driver did not enable multi-channel\n"); return true; } return false; }
static void configure_azalia( const struct hw_ctx_audio *hw_ctx, enum signal_type signal, const struct audio_crtc_info *crtc_info, const struct audio_info *audio_info) { uint32_t speakers = audio_info->flags.info.ALLSPEAKERS; uint32_t value; uint32_t field = 0; enum audio_format_code audio_format_code; uint32_t format_index; uint32_t index; bool is_ac3_supported = false; bool is_audio_format_supported = false; union audio_sample_rates sample_rate; uint32_t strlen = 0; /* Speaker Allocation */ /* uint32_t value; uint32_t field = 0;*/ value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER); set_reg_field_value(value, speakers, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, SPEAKER_ALLOCATION); /* LFE_PLAYBACK_LEVEL = LFEPBL * LFEPBL = 0 : Unknown or refer to other information * LFEPBL = 1 : 0dB playback * LFEPBL = 2 : +10dB playback * LFE_BL = 3 : Reserved */ set_reg_field_value(value, 0, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, LFE_PLAYBACK_LEVEL); set_reg_field_value(value, 0, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, HDMI_CONNECTION); set_reg_field_value(value, 0, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, DP_CONNECTION); field = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, EXTRA_CONNECTION_INFO); field &= ~0x1; set_reg_field_value(value, field, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, EXTRA_CONNECTION_INFO); /* set audio for output signal */ switch (signal) { case SIGNAL_TYPE_HDMI_TYPE_A: set_reg_field_value(value, 1, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, HDMI_CONNECTION); break; case SIGNAL_TYPE_WIRELESS: { /*LSB used for "is wireless" flag */ field = 0; field = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, EXTRA_CONNECTION_INFO); field |= 0x1; set_reg_field_value(value, field, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, EXTRA_CONNECTION_INFO); set_reg_field_value(value, 1, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, HDMI_CONNECTION); } break; case SIGNAL_TYPE_EDP: case SIGNAL_TYPE_DISPLAY_PORT: case SIGNAL_TYPE_DISPLAY_PORT_MST: set_reg_field_value(value, 1, AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, DP_CONNECTION); break; default: break; } write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, value); /* Wireless Display identification */ value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION); set_reg_field_value(value, signal == SIGNAL_TYPE_WIRELESS ? 1 : 0, AZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION, WIRELESS_DISPLAY_IDENTIFICATION); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION, value); /* Audio Descriptors */ /* pass through all formats */ for (format_index = 0; format_index < AUDIO_FORMAT_CODE_COUNT; format_index++) { audio_format_code = (AUDIO_FORMAT_CODE_FIRST + format_index); /* those are unsupported, skip programming */ if (audio_format_code == AUDIO_FORMAT_CODE_1BITAUDIO || audio_format_code == AUDIO_FORMAT_CODE_DST) continue; value = 0; /* check if supported */ is_audio_format_supported = dal_audio_hw_ctx_is_audio_format_supported( hw_ctx, audio_info, audio_format_code, &index); if (is_audio_format_supported) { const struct audio_mode *audio_mode = &audio_info->modes[index]; union audio_sample_rates sample_rates = audio_mode->sample_rates; uint8_t byte2 = audio_mode->max_bit_rate; /* adjust specific properties */ switch (audio_format_code) { case AUDIO_FORMAT_CODE_LINEARPCM: { dal_hw_ctx_audio_check_audio_bandwidth( hw_ctx, crtc_info, audio_mode->channel_count, signal, &sample_rates); byte2 = audio_mode->sample_size; set_reg_field_value(value, sample_rates.all, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, SUPPORTED_FREQUENCIES_STEREO); } break; case AUDIO_FORMAT_CODE_AC3: is_ac3_supported = true; break; case AUDIO_FORMAT_CODE_DOLBYDIGITALPLUS: case AUDIO_FORMAT_CODE_DTS_HD: case AUDIO_FORMAT_CODE_MAT_MLP: case AUDIO_FORMAT_CODE_DST: case AUDIO_FORMAT_CODE_WMAPRO: byte2 = audio_mode->vendor_specific; break; default: break; } /* fill audio format data */ set_reg_field_value(value, audio_mode->channel_count - 1, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, MAX_CHANNELS); set_reg_field_value(value, sample_rates.all, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, SUPPORTED_FREQUENCIES); set_reg_field_value(value, byte2, AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, DESCRIPTOR_BYTE_2); } /* if */ write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 + format_index, value); } /* for */ if (is_ac3_supported) dal_write_reg(hw_ctx->ctx, mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS, 0x05); /* check for 192khz/8-Ch support for HBR requirements */ sample_rate.all = 0; sample_rate.rate.RATE_192 = 1; dal_hw_ctx_audio_check_audio_bandwidth( hw_ctx, crtc_info, 8, signal, &sample_rate); set_high_bit_rate_capable(hw_ctx, sample_rate.rate.RATE_192); /* Audio and Video Lipsync */ set_video_latency(hw_ctx, audio_info->video_latency); set_audio_latency(hw_ctx, audio_info->audio_latency); value = 0; set_reg_field_value(value, audio_info->manufacture_id, AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0, MANUFACTURER_ID); set_reg_field_value(value, audio_info->product_id, AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0, PRODUCT_ID); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0, value); value = 0; /*get display name string length */ while (audio_info->display_name[strlen++] != '\0') { if (strlen >= MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS) break; } set_reg_field_value(value, strlen, AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1, SINK_DESCRIPTION_LEN); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1, value); /* *write the port ID: *PORT_ID0 = display index *PORT_ID1 = 16bit BDF *(format MSB->LSB: 8bit Bus, 5bit Device, 3bit Function) */ value = 0; set_reg_field_value(value, audio_info->port_id[0], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2, PORT_ID0); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2, value); value = 0; set_reg_field_value(value, audio_info->port_id[1], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3, PORT_ID1); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3, value); /*write the 18 char monitor string */ value = 0; set_reg_field_value(value, audio_info->display_name[0], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4, DESCRIPTION0); set_reg_field_value(value, audio_info->display_name[1], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4, DESCRIPTION1); set_reg_field_value(value, audio_info->display_name[2], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4, DESCRIPTION2); set_reg_field_value(value, audio_info->display_name[3], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4, DESCRIPTION3); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4, value); value = 0; set_reg_field_value(value, audio_info->display_name[4], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5, DESCRIPTION4); set_reg_field_value(value, audio_info->display_name[5], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5, DESCRIPTION5); set_reg_field_value(value, audio_info->display_name[6], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5, DESCRIPTION6); set_reg_field_value(value, audio_info->display_name[7], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5, DESCRIPTION7); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5, value); value = 0; set_reg_field_value(value, audio_info->display_name[8], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6, DESCRIPTION8); set_reg_field_value(value, audio_info->display_name[9], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6, DESCRIPTION9); set_reg_field_value(value, audio_info->display_name[10], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6, DESCRIPTION10); set_reg_field_value(value, audio_info->display_name[11], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6, DESCRIPTION11); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6, value); value = 0; set_reg_field_value(value, audio_info->display_name[12], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7, DESCRIPTION12); set_reg_field_value(value, audio_info->display_name[13], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7, DESCRIPTION13); set_reg_field_value(value, audio_info->display_name[14], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7, DESCRIPTION14); set_reg_field_value(value, audio_info->display_name[15], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7, DESCRIPTION15); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7, value); value = 0; set_reg_field_value(value, audio_info->display_name[16], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8, DESCRIPTION16); set_reg_field_value(value, audio_info->display_name[17], AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8, DESCRIPTION17); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8, value); }
static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc) { uint32_t dispclk_cntl_value; uint32_t dp_ref_clk_cntl_value; uint32_t dp_ref_clk_cntl_src_sel_value; uint32_t dp_ref_clk_khz = 600000; uint32_t target_div = INVALID_DIVIDER; struct display_clock_dce110 *disp_clk = FROM_DISPLAY_CLOCK(dc); /* ASSERT DP Reference Clock source is from DFS*/ dp_ref_clk_cntl_value = dm_read_reg(dc->ctx, mmDPREFCLK_CNTL); dp_ref_clk_cntl_src_sel_value = get_reg_field_value( dp_ref_clk_cntl_value, DPREFCLK_CNTL, DPREFCLK_SRC_SEL); ASSERT(dp_ref_clk_cntl_src_sel_value == 0); /* Read the mmDENTIST_DISPCLK_CNTL to get the currently * programmed DID DENTIST_DPREFCLK_WDIVIDER*/ dispclk_cntl_value = dm_read_reg(dc->ctx, mmDENTIST_DISPCLK_CNTL); /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/ target_div = dal_divider_range_get_divider( divider_ranges, DIVIDER_RANGE_MAX, get_reg_field_value(dispclk_cntl_value, DENTIST_DISPCLK_CNTL, DENTIST_DPREFCLK_WDIVIDER)); if (target_div != INVALID_DIVIDER) { /* Calculate the current DFS clock, in kHz.*/ dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR * disp_clk->dentist_vco_freq_khz) / target_div; } /* SW will adjust DP REF Clock average value for all purposes * (DP DTO / DP Audio DTO and DP GTC) if clock is spread for all cases: -if SS enabled on DP Ref clock and HW de-spreading enabled with SW calculations for DS_INCR/DS_MODULO (this is planned to be default case) -if SS enabled on DP Ref clock and HW de-spreading enabled with HW calculations (not planned to be used, but average clock should still be valid) -if SS enabled on DP Ref clock and HW de-spreading disabled (should not be case with CIK) then SW should program all rates generated according to average value (case as with previous ASICs) */ if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) { struct fixed32_32 ss_percentage = dal_fixed32_32_div_int( dal_fixed32_32_from_fraction( disp_clk->gpu_pll_ss_percentage, disp_clk->gpu_pll_ss_divider), 200); struct fixed32_32 adj_dp_ref_clk_khz; ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one, ss_percentage); adj_dp_ref_clk_khz = dal_fixed32_32_mul_int( ss_percentage, dp_ref_clk_khz); dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz); } return dp_ref_clk_khz; }
static void release_engine( struct engine *engine) { struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); struct i2c_engine *base = NULL; bool safe_to_reset; uint32_t value = 0; base = &hw_engine->base.base; /* Restore original HW engine speed */ base->funcs->set_speed(base, hw_engine->base.original_speed); /* Release I2C */ { value = dal_read_reg(engine->ctx, mmDC_I2C_ARBITRATION); set_reg_field_value( value, 1, DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG); dal_write_reg(engine->ctx, mmDC_I2C_ARBITRATION, value); } /* Reset HW engine */ { uint32_t i2c_sw_status = 0; value = dal_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); i2c_sw_status = get_reg_field_value( value, DC_I2C_SW_STATUS, DC_I2C_SW_STATUS); /* if used by SW, safe to reset */ safe_to_reset = (i2c_sw_status == 1); } { value = dal_read_reg(engine->ctx, mmDC_I2C_CONTROL); if (safe_to_reset) set_reg_field_value( value, 1, DC_I2C_CONTROL, DC_I2C_SOFT_RESET); set_reg_field_value( value, 1, DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET); dal_write_reg(engine->ctx, mmDC_I2C_CONTROL, value); } /* HW I2c engine - clock gating feature */ if (!hw_engine->engine_keep_power_up_count) disable_i2c_hw_engine(hw_engine); }
void dce80_stream_encoder_dp_blank( struct stream_encoder *enc) { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); struct dc_context *ctx = enc110->base.ctx; uint32_t addr = LINK_REG(DP_VID_STREAM_CNTL); uint32_t value = dm_read_reg(ctx, addr); uint32_t retries = 0; uint32_t max_retries = DP_BLANK_MAX_RETRY * 10; /* Note: For CZ, we are changing driver default to disable * stream deferred to next VBLANK. If results are positive, we * will make the same change to all DCE versions. There are a * handful of panels that cannot handle disable stream at * HBLANK and will result in a white line flash across the * screen on stream disable. */ /* Specify the video stream disable point * (2 = start of the next vertical blank) */ set_reg_field_value( value, 2, DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER); /* Larger delay to wait until VBLANK - use max retry of * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode + * a little more because we may not trust delay accuracy. */ max_retries = DP_BLANK_MAX_RETRY * 150; /* disable DP stream */ set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE); dm_write_reg(ctx, addr, value); /* the encoder stops sending the video stream * at the start of the vertical blanking. * Poll for DP_VID_STREAM_STATUS == 0 */ do { value = dm_read_reg(ctx, addr); if (!get_reg_field_value( value, DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS)) break; udelay(10); ++retries; } while (retries < max_retries); ASSERT(retries <= max_retries); /* Tell the DP encoder to ignore timing from CRTC, must be done after * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is * complete, stream status will be stuck in video stream enabled state, * i.e. DP_VID_STREAM_STATUS stuck at 1. */ addr = LINK_REG(DP_STEER_FIFO); value = dm_read_reg(ctx, addr); set_reg_field_value(value, true, DP_STEER_FIFO, DP_STEER_FIFO_RESET); dm_write_reg(ctx, addr, value); }
void dce80_stream_encoder_set_mst_bandwidth( struct stream_encoder *enc, struct fixed31_32 avg_time_slots_per_mtp) { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); struct dc_context *ctx = enc110->base.ctx; uint32_t addr; uint32_t field; uint32_t value; uint32_t retries = 0; uint32_t x = dal_fixed31_32_floor( avg_time_slots_per_mtp); uint32_t y = dal_fixed31_32_ceil( dal_fixed31_32_shl( dal_fixed31_32_sub_int( avg_time_slots_per_mtp, x), 26)); { addr = LINK_REG(DP_MSE_RATE_CNTL); value = dm_read_reg(ctx, addr); set_reg_field_value( value, x, DP_MSE_RATE_CNTL, DP_MSE_RATE_X); set_reg_field_value( value, y, DP_MSE_RATE_CNTL, DP_MSE_RATE_Y); dm_write_reg(ctx, addr, value); } /* wait for update to be completed on the link */ /* i.e. DP_MSE_RATE_UPDATE_PENDING field (read only) */ /* is reset to 0 (not pending) */ { addr = LINK_REG(DP_MSE_RATE_UPDATE); do { value = dm_read_reg(ctx, addr); field = get_reg_field_value( value, DP_MSE_RATE_UPDATE, DP_MSE_RATE_UPDATE_PENDING); if (!(field & DP_MSE_RATE_UPDATE__DP_MSE_RATE_UPDATE_PENDING_MASK)) break; udelay(10); ++retries; } while (retries < DP_MST_UPDATE_MAX_RETRY); } }
static void program_input_csc( struct transform *xfm, enum dc_color_space color_space) { int arr_size = sizeof(input_csc_matrix)/sizeof(struct input_csc_matrix); struct dc_context *ctx = xfm->ctx; const uint32_t *regval = NULL; bool use_set_a; uint32_t value; int i; for (i = 0; i < arr_size; i++) if (input_csc_matrix[i].color_space == color_space) { regval = input_csc_matrix[i].regval; break; } if (regval == NULL) { BREAK_TO_DEBUGGER(); return; } /* * 1 == set A, the logic is 'if currently we're not using set A, * then use set A, otherwise use set B' */ value = dm_read_reg(ctx, mmCOL_MAN_INPUT_CSC_CONTROL); use_set_a = get_reg_field_value( value, COL_MAN_INPUT_CSC_CONTROL, INPUT_CSC_MODE) != 1; if (use_set_a) { /* fixed S2.13 format */ value = 0; set_reg_field_value( value, regval[0], INPUT_CSC_C11_C12_A, INPUT_CSC_C11_A); set_reg_field_value( value, regval[1], INPUT_CSC_C11_C12_A, INPUT_CSC_C12_A); dm_write_reg(ctx, mmINPUT_CSC_C11_C12_A, value); value = 0; set_reg_field_value( value, regval[2], INPUT_CSC_C13_C14_A, INPUT_CSC_C13_A); set_reg_field_value( value, regval[3], INPUT_CSC_C13_C14_A, INPUT_CSC_C14_A); dm_write_reg(ctx, mmINPUT_CSC_C13_C14_A, value); value = 0; set_reg_field_value( value, regval[4], INPUT_CSC_C21_C22_A, INPUT_CSC_C21_A); set_reg_field_value( value, regval[5], INPUT_CSC_C21_C22_A, INPUT_CSC_C22_A); dm_write_reg(ctx, mmINPUT_CSC_C21_C22_A, value); value = 0; set_reg_field_value( value, regval[6], INPUT_CSC_C23_C24_A, INPUT_CSC_C23_A); set_reg_field_value( value, regval[7], INPUT_CSC_C23_C24_A, INPUT_CSC_C24_A); dm_write_reg(ctx, mmINPUT_CSC_C23_C24_A, value); value = 0; set_reg_field_value( value, regval[8], INPUT_CSC_C31_C32_A, INPUT_CSC_C31_A); set_reg_field_value( value, regval[9], INPUT_CSC_C31_C32_A, INPUT_CSC_C32_A); dm_write_reg(ctx, mmINPUT_CSC_C31_C32_A, value); value = 0; set_reg_field_value( value, regval[10], INPUT_CSC_C33_C34_A, INPUT_CSC_C33_A); set_reg_field_value( value, regval[11], INPUT_CSC_C33_C34_A, INPUT_CSC_C34_A); dm_write_reg(ctx, mmINPUT_CSC_C33_C34_A, value); } else { /* fixed S2.13 format */ value = 0; set_reg_field_value( value, regval[0], INPUT_CSC_C11_C12_B, INPUT_CSC_C11_B); set_reg_field_value( value, regval[1], INPUT_CSC_C11_C12_B, INPUT_CSC_C12_B); dm_write_reg(ctx, mmINPUT_CSC_C11_C12_B, value); value = 0; set_reg_field_value( value, regval[2], INPUT_CSC_C13_C14_B, INPUT_CSC_C13_B); set_reg_field_value( value, regval[3], INPUT_CSC_C13_C14_B, INPUT_CSC_C14_B); dm_write_reg(ctx, mmINPUT_CSC_C13_C14_B, value); value = 0; set_reg_field_value( value, regval[4], INPUT_CSC_C21_C22_B, INPUT_CSC_C21_B); set_reg_field_value( value, regval[5], INPUT_CSC_C21_C22_B, INPUT_CSC_C22_B); dm_write_reg(ctx, mmINPUT_CSC_C21_C22_B, value); value = 0; set_reg_field_value( value, regval[6], INPUT_CSC_C23_C24_B, INPUT_CSC_C23_B); set_reg_field_value( value, regval[7], INPUT_CSC_C23_C24_B, INPUT_CSC_C24_B); dm_write_reg(ctx, mmINPUT_CSC_C23_C24_B, value); value = 0; set_reg_field_value( value, regval[8], INPUT_CSC_C31_C32_B, INPUT_CSC_C31_B); set_reg_field_value( value, regval[9], INPUT_CSC_C31_C32_B, INPUT_CSC_C32_B); dm_write_reg(ctx, mmINPUT_CSC_C31_C32_B, value); value = 0; set_reg_field_value( value, regval[10], INPUT_CSC_C33_C34_B, INPUT_CSC_C33_B); set_reg_field_value( value, regval[11], INPUT_CSC_C33_C34_B, INPUT_CSC_C34_B); dm_write_reg(ctx, mmINPUT_CSC_C33_C34_B, value); } /* KK: leave INPUT_CSC_CONVERSION_MODE at default */ value = 0; /* * select 8.4 input type instead of default 12.0. From the discussion * with HW team, this format depends on the UNP surface format, so for * 8-bit we should select 8.4 (4 bits truncated). For 10 it should be * 10.2. For Carrizo we only support 8-bit surfaces on underlay pipe * so we can always keep this at 8.4 (input_type=2). If the later asics * start supporting 10+ bits, we will have a problem: surface * programming including UNP_GRPH* is being done in DalISR after this, * so either we pass surface format to here, or move this logic to ISR */ set_reg_field_value( value, 2, COL_MAN_INPUT_CSC_CONTROL, INPUT_CSC_INPUT_TYPE); set_reg_field_value( value, use_set_a ? 1 : 2, COL_MAN_INPUT_CSC_CONTROL, INPUT_CSC_MODE); dm_write_reg(ctx, mmCOL_MAN_INPUT_CSC_CONTROL, value); }
static bool construct( struct i2c_hw_engine_dce110 *engine_dce110, const struct i2c_hw_engine_dce110_create_arg *arg) { uint32_t xtal_ref_div = 0; uint32_t value = 0; /*ddc_setup_offset of dce80 and dce110 have the same register name * but different offset. Do not need different array*/ if (arg->engine_id >= sizeof(ddc_setup_offset) / sizeof(int32_t)) return false; if (arg->engine_id >= sizeof(ddc_speed_offset) / sizeof(int32_t)) return false; if (!arg->reference_frequency) return false; if (!dal_i2c_hw_engine_construct(&engine_dce110->base, arg->ctx)) return false; engine_dce110->base.base.base.funcs = &engine_funcs; engine_dce110->base.base.funcs = &i2c_engine_funcs; engine_dce110->base.funcs = &i2c_hw_engine_funcs; engine_dce110->base.default_speed = arg->default_speed; engine_dce110->engine_id = arg->engine_id; engine_dce110->buffer_used_bytes = 0; engine_dce110->transaction_count = 0; engine_dce110->engine_keep_power_up_count = 1; /*values which are not included by arg*/ engine_dce110->addr.DC_I2C_DDCX_SETUP = mmDC_I2C_DDC1_SETUP + ddc_setup_offset[arg->engine_id]; engine_dce110->addr.DC_I2C_DDCX_SPEED = mmDC_I2C_DDC1_SPEED + ddc_speed_offset[arg->engine_id]; value = dal_read_reg( engine_dce110->base.base.base.ctx, mmMICROSECOND_TIME_BASE_DIV); xtal_ref_div = get_reg_field_value( value, MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV); if (xtal_ref_div == 0) { dal_logger_write( engine_dce110->base.base.base.ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_I2C_AUX, "Invalid base timer divider\n", __func__); xtal_ref_div = 2; } /*Calculating Reference Clock by divding original frequency by * XTAL_REF_DIV. * At upper level, uint32_t reference_frequency = * dal_i2caux_get_reference_clock(as) >> 1 * which already divided by 2. So we need x2 to get original * reference clock from ppll_info */ engine_dce110->reference_frequency = (arg->reference_frequency * 2) / xtal_ref_div; return true; }