diff options
| -rw-r--r-- | linux-core/radeon_atombios.c | 168 | 
1 files changed, 168 insertions, 0 deletions
| diff --git a/linux-core/radeon_atombios.c b/linux-core/radeon_atombios.c index 0915a7f8..90a367a0 100644 --- a/linux-core/radeon_atombios.c +++ b/linux-core/radeon_atombios.c @@ -77,6 +77,11 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de  	return i2c;  } +static struct radeon_i2c_bus_rec radeon_parse_i2c_record(struct drm_device *dev, ATOM_I2C_RECORD *record) +{ +    return radeon_lookup_gpio(dev, record->sucI2cId.bfI2C_LineMux); +} +  static void radeon_atom_apply_quirks(struct drm_device *dev, int index)  {  	struct drm_radeon_private *dev_priv = dev->dev_private; @@ -100,6 +105,165 @@ static void radeon_atom_apply_quirks(struct drm_device *dev, int index)  	}  } +const int object_connector_convert[] = +{ CONNECTOR_NONE, +  CONNECTOR_DVI_I, +  CONNECTOR_DVI_I, +  CONNECTOR_DVI_D, +  CONNECTOR_DVI_D, +  CONNECTOR_VGA, +  CONNECTOR_CTV, +  CONNECTOR_STV, +  CONNECTOR_NONE, +  CONNECTOR_DIN, +  CONNECTOR_SCART, +  CONNECTOR_HDMI_TYPE_A, +  CONNECTOR_HDMI_TYPE_B, +  CONNECTOR_HDMI_TYPE_B, +  CONNECTOR_LVDS, +  CONNECTOR_DIN, +  CONNECTOR_NONE, +  CONNECTOR_NONE, +  CONNECTOR_NONE, +  CONNECTOR_DISPLAY_PORT, +}; + +bool radeon_get_atom_connector_info_from_bios_object_table(struct drm_device *dev) +{ +	struct drm_radeon_private *dev_priv = dev->dev_private; +	struct radeon_mode_info *mode_info = &dev_priv->mode_info; +	struct atom_context *ctx = mode_info->atom_context; +	int index = GetIndexIntoMasterTable(DATA, Object_Header); +	uint16_t size, data_offset; +	uint8_t frev, crev; +	ATOM_CONNECTOR_OBJECT_TABLE *con_obj; +	ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL; +	ATOM_OBJECT_HEADER *obj_header; +	int i, j; + +	atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); + +	if (crev < 2) +		return false; + + +	obj_header = (ATOM_OBJECT_HEADER *)(ctx->bios + data_offset); + +	con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)(ctx->bios + data_offset + obj_header->usConnectorObjectTableOffset); +	DRM_ERROR("Num of objects %d\n", con_obj->ucNumberOfObjects); + +	for (i = 0; i < con_obj->ucNumberOfObjects; i++) { +		ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *src_dst_table; +		ATOM_COMMON_RECORD_HEADER *record; +		uint8_t obj_id, num, obj_type; +		int record_base; +		uint16_t con_obj_id = le16_to_cpu(con_obj->asObjects[i].usObjectID); + +		obj_id = (con_obj_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; +		num = (con_obj_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT; +		obj_type = (con_obj_id & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; +		if (obj_type != GRAPH_OBJECT_TYPE_CONNECTOR) +			continue; + +		DRM_ERROR("offset is %04x\n", le16_to_cpu(con_obj->asObjects[i].usSrcDstTableOffset)); +		src_dst_table = (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) +			(ctx->bios + data_offset + le16_to_cpu(con_obj->asObjects[i].usSrcDstTableOffset)); + +		DRM_ERROR("object id %04x %02x\n", obj_id, src_dst_table->ucNumberOfSrc); +	        +		if ((dev_priv->chip_family == CHIP_RS780) && +		    (obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) { +			uint32_t slot_config, ct; + +			// TODO +		} else +			mode_info->bios_connector[i].connector_type = object_connector_convert[obj_id]; + +		if (mode_info->bios_connector[i].connector_type == CONNECTOR_NONE) +			mode_info->bios_connector[i].valid = false; +		else +			mode_info->bios_connector[i].valid = true; +		mode_info->bios_connector[i].devices = 0; + +		for (j = 0; j < src_dst_table->ucNumberOfSrc; j++) { +			uint8_t sobj_id; + +			sobj_id = (src_dst_table->usSrcObjectID[j] & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; +			DRM_ERROR("src object id %04x %d\n", src_dst_table->usSrcObjectID[j], sobj_id); + +			switch(sobj_id) { +			case ENCODER_OBJECT_ID_INTERNAL_LVDS: +				mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_LCD1_INDEX); +				break; +			case ENCODER_OBJECT_ID_INTERNAL_TMDS1: +			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: +				mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP1_INDEX); +				break; +			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: +				if (num == 1) +					mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP1_INDEX); +				else +					mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP2_INDEX); +				mode_info->bios_connector[i].tmds_type = TMDS_UNIPHY; +				break; +			case ENCODER_OBJECT_ID_INTERNAL_TMDS2: +			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: +				mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP2_INDEX); +				mode_info->bios_connector[i].tmds_type = TMDS_EXT; +				break; +			case ENCODER_OBJECT_ID_INTERNAL_LVTM1: +			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: +				mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP3_INDEX); +				mode_info->bios_connector[i].tmds_type = TMDS_LVTMA; +				break; +			case ENCODER_OBJECT_ID_INTERNAL_DAC1: +			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: +				if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN || +				    mode_info->bios_connector[i].connector_type == CONNECTOR_STV || +				    mode_info->bios_connector[i].connector_type == CONNECTOR_CTV) +					mode_info->bios_connector[i].valid = false; +				else +					mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_CRT1_INDEX); +				mode_info->bios_connector[i].dac_type = DAC_PRIMARY; +				break; +			case ENCODER_OBJECT_ID_INTERNAL_DAC2: +			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: +				if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN || +				    mode_info->bios_connector[i].connector_type == CONNECTOR_STV || +				    mode_info->bios_connector[i].connector_type == CONNECTOR_CTV) +					mode_info->bios_connector[i].valid = false; +				else +					mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_CRT2_INDEX); +				mode_info->bios_connector[i].dac_type = DAC_TVDAC; +				break; +			} +		} + +		record = (ATOM_COMMON_RECORD_HEADER *) +			(ctx->bios + data_offset + le16_to_cpu(con_obj->asObjects[i].usRecordOffset)); +		record_base = le16_to_cpu(con_obj->asObjects[i].usRecordOffset); + +		while (record->ucRecordType > 0 && +		       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { +			DRM_ERROR("record type %d\n", record->ucRecordType); + +			switch(record->ucRecordType) { +			case ATOM_I2C_RECORD_TYPE: +				mode_info->bios_connector[i].ddc_i2c = radeon_parse_i2c_record(dev, (ATOM_I2C_RECORD *)record); +				break; +			case ATOM_HPD_INT_RECORD_TYPE: +				break; +			case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE: +				break; +			} +			record = (ATOM_COMMON_RECORD_HEADER *)((char *)record + record->ucRecordSize); +		} + +	} +	return true; +} + +  bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev)  {  	struct drm_radeon_private *dev_priv = dev->dev_private; @@ -112,6 +276,10 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device  	union atom_supported_devices *supported_devices;  	int i,j; + +	if (radeon_get_atom_connector_info_from_bios_object_table(dev)) +		return true; +  	atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);  	supported_devices = (union atom_supported_devices *)(ctx->bios + data_offset); | 
