Commit 9ea16f64 authored by Timur Kristóf's avatar Timur Kristóf Committed by Alex Deucher
Browse files

drm/amd/display: Read EDID from VBIOS embedded panel info

Some board manufacturers hardcode the EDID for the embedded
panel in the VBIOS. This EDID should be used when the panel
doesn't have a DDC.

For reference, see the legacy non-DC display code:
amdgpu_atombios_encoder_get_lcd_info()

This is necessary to support embedded connectors without DDC.

Fixes: 4562236b ("drm/amd/dc: Add dc display driver (v2)")
Link: https://gitlab.freedesktop.org/drm/amd/-/work_items/5192


Signed-off-by: default avatarTimur Kristóf <timur.kristof@gmail.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
(cherry picked from commit eb105e63b474c11ef6a84a1c6b18100d851ff364)
parent 60af4605
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -1313,6 +1313,60 @@ static enum bp_result bios_parser_get_embedded_panel_info(
	return BP_RESULT_FAILURE;
}

static enum bp_result get_embedded_panel_extra_info(
	struct bios_parser *bp,
	struct embedded_panel_info *info,
	const uint32_t table_offset)
{
	uint8_t *record = bios_get_image(&bp->base, table_offset, 1);
	ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
	ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;

	while (*record != ATOM_RECORD_END_TYPE) {
		switch (*record) {
		case LCD_MODE_PATCH_RECORD_MODE_TYPE:
			record += sizeof(ATOM_PATCH_RECORD_MODE);
			break;
		case LCD_RTS_RECORD_TYPE:
			record += sizeof(ATOM_LCD_RTS_RECORD);
			break;
		case LCD_CAP_RECORD_TYPE:
			record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
			break;
		case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
			fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
			if (fake_edid_record->ucFakeEDIDLength) {
				if (fake_edid_record->ucFakeEDIDLength == 128)
					info->fake_edid_size =
						fake_edid_record->ucFakeEDIDLength;
				else
					info->fake_edid_size =
						fake_edid_record->ucFakeEDIDLength * 128;

				info->fake_edid = fake_edid_record->ucFakeEDIDString;

				record += struct_size(fake_edid_record,
						      ucFakeEDIDString,
						      info->fake_edid_size);
			} else {
				/* empty fake edid record must be 3 bytes long */
				record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
			}
			break;
		case LCD_PANEL_RESOLUTION_RECORD_TYPE:
			panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
			info->panel_width_mm = panel_res_record->usHSize;
			info->panel_height_mm = panel_res_record->usVSize;
			record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
			break;
		default:
			return BP_RESULT_BADBIOSTABLE;
		}
	}

	return BP_RESULT_OK;
}

static enum bp_result get_embedded_panel_info_v1_2(
	struct bios_parser *bp,
	struct embedded_panel_info *info)
@@ -1429,6 +1483,10 @@ static enum bp_result get_embedded_panel_info_v1_2(
	if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
		info->lcd_timing.misc_info.API_ENABLED = true;

	if (lvds->usExtInfoTableOffset)
		return get_embedded_panel_extra_info(bp, info,
			le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info));

	return BP_RESULT_OK;
}

@@ -1554,6 +1612,10 @@ static enum bp_result get_embedded_panel_info_v1_3(
			(uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
				lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;

	if (lvds->usExtInfoTableOffset)
		return get_embedded_panel_extra_info(bp, info,
			le16_to_cpu(lvds->usExtInfoTableOffset) + DATA_TABLES(LCD_Info));

	return BP_RESULT_OK;
}

+4 −0
Original line number Diff line number Diff line
@@ -153,6 +153,10 @@ struct embedded_panel_info {
	uint32_t drr_enabled;
	uint32_t min_drr_refresh_rate;
	bool realtek_eDPToLVDS;
	uint16_t panel_width_mm;
	uint16_t panel_height_mm;
	uint16_t fake_edid_size;
	const uint8_t *fake_edid;
};

struct dc_firmware_info {