Пример #1
0
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);
}
Пример #5
0
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;
}
Пример #7
0
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;
}
Пример #9
0
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);
}
Пример #11
0
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);
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
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);
}
Пример #15
0
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;
}
Пример #16
0
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;
}
Пример #21
0
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);
	}
}
Пример #29
0
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;
}