From d00d22818f5ddfee24a6329f8eae2350d15582df Mon Sep 17 00:00:00 2001 From: Patrick Magauran Date: Sat, 28 Nov 2020 19:02:36 -0500 Subject: [PATCH 1/5] Begin work on opregion decoding --- i915ovmf.c | 14 +- i915ovmf.inf | 2 + intel_opregion.c | 650 ++++++++++++++++++++++++ intel_opregion.h | 1237 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1902 insertions(+), 1 deletion(-) create mode 100644 intel_opregion.c create mode 100644 intel_opregion.h diff --git a/i915ovmf.c b/i915ovmf.c index 923e5f4..5b19e7f 100755 --- a/i915ovmf.c +++ b/i915ovmf.c @@ -21,6 +21,7 @@ #include #include #include +#include "intel_opregion.h" i915_CONTROLLER g_private = {SIGNATURE_32('i', '9', '1', '5')}; @@ -252,7 +253,7 @@ SetupOpRegion(IN EFI_PCI_IO_PROTOCOL *PciIo, EFI_STATUS Status; EFI_PHYSICAL_ADDRESS Address; UINT8 *BytePointer; - + struct intel_opregion OpRegion; if (mOpRegionSize == 0) { return EFI_INVALID_PARAMETER; } @@ -283,6 +284,17 @@ SetupOpRegion(IN EFI_PCI_IO_PROTOCOL *PciIo, ZeroMem(BytePointer + mOpRegionSize, OpRegionResidual); } + OpRegion.header=(struct opregion_header *) BytePointer; + OpRegion.vbt =(struct vbt_header *) (BytePointer + 1024); + + Status = decodeVBT(OpRegion.vbt, BytePointer); + if (EFI_ERROR(Status)) { + DEBUG((EFI_D_ERROR, "%a: %a: failed to decode OpRegion: %r\n", + __FUNCTION__, GetPciName(PciInfo), Status)); + return Status; + } + + // for(int i=0;i +#include + +/* + * The child device config, aka the display device data structure, provides a + * description of a port and its configuration on the platform. + * + * The child device config size has been increased, and fields have been added + * and their meaning has changed over time. Care must be taken when accessing + * basically any of the fields to ensure the correct interpretation for the BDB + * version in question. + * + * When we copy the child device configs to dev_priv->vbt.child_dev, we reserve + * space for the full structure below, and initialize the tail not actually + * present in VBT to zeros. Accessing those fields is fine, as long as the + * default zero is taken into account, again according to the BDB version. + * + * BDB versions 155 and below are considered legacy, and version 155 seems to be + * a baseline for some of the VBT documentation. When adding new fields, please + * include the BDB version when the field was added, if it's above that. + */ +struct child_device_config +{ + UINT16 handle; + UINT16 device_type; /* See DEVICE_TYPE_* above */ + + union + { + UINT8 device_id[10]; /* ascii string */ + struct + { + UINT8 i2c_speed; + UINT8 dp_onboard_redriver; /* 158 */ + UINT8 dp_ondock_redriver; /* 158 */ + UINT8 hdmi_level_shifter_value : 5; /* 169 */ + UINT8 hdmi_max_data_rate : 3; /* 204 */ + UINT16 dtd_buf_ptr; /* 161 */ + UINT8 edidless_efp : 1; /* 161 */ + UINT8 compression_enable : 1; /* 198 */ + UINT8 compression_method : 1; /* 198 */ + UINT8 ganged_edp : 1; /* 202 */ + UINT8 reserved0 : 4; + UINT8 compression_structure_index : 4; /* 198 */ + UINT8 reserved1 : 4; + UINT8 slave_port; /* 202 */ + UINT8 reserved2; + } __packed; + } __packed; + + UINT16 addin_offset; + UINT8 dvo_port; /* See DEVICE_PORT_* and DVO_PORT_* above */ + UINT8 i2c_pin; + UINT8 slave_addr; + UINT8 ddc_pin; + UINT16 edid_ptr; + UINT8 dvo_cfg; /* See DEVICE_CFG_* above */ + + union + { + struct + { + UINT8 dvo2_port; + UINT8 i2c2_pin; + UINT8 slave2_addr; + UINT8 ddc2_pin; + } __packed; + struct + { + UINT8 efp_routed : 1; /* 158 */ + UINT8 lane_reversal : 1; /* 184 */ + UINT8 lspcon : 1; /* 192 */ + UINT8 iboost : 1; /* 196 */ + UINT8 hpd_invert : 1; /* 196 */ + UINT8 use_vbt_vswing : 1; /* 218 */ + UINT8 flag_reserved : 2; + UINT8 hdmi_support : 1; /* 158 */ + UINT8 dp_support : 1; /* 158 */ + UINT8 tmds_support : 1; /* 158 */ + UINT8 support_reserved : 5; + UINT8 aux_channel; + UINT8 dongle_detect; + } __packed; + } __packed; + + UINT8 pipe_cap : 2; + UINT8 sdvo_stall : 1; /* 158 */ + UINT8 hpd_status : 2; + UINT8 integrated_encoder : 1; + UINT8 capabilities_reserved : 2; + UINT8 dvo_wiring; /* See DEVICE_WIRE_* above */ + + union + { + UINT8 dvo2_wiring; + UINT8 mipi_bridge_type; /* 171 */ + } __packed; + + UINT16 extended_type; + UINT8 dvo_function; + UINT8 dp_usb_type_c : 1; /* 195 */ + UINT8 tbt : 1; /* 209 */ + UINT8 flags2_reserved : 2; /* 195 */ + UINT8 dp_port_trace_length : 4; /* 209 */ + UINT8 dp_gpio_index; /* 195 */ + UINT16 dp_gpio_pin_num; /* 195 */ + UINT8 dp_iboost_level : 4; /* 196 */ + UINT8 hdmi_iboost_level : 4; /* 196 */ + UINT8 dp_max_link_rate : 2; /* 216 CNL+ */ + UINT8 dp_max_link_rate_reserved : 6; /* 216 */ +} __packed; + +/* Get BDB block size given a pointer to Block ID. */ +static UINT32 _get_blocksize(const UINT8 *block_base) +{ + /* The MIPI Sequence Block v3+ has a separate size field. */ + if (*block_base == BDB_MIPI_SEQUENCE && *(block_base + 3) >= 3) + return *((const UINT32 *)(block_base + 4)); + else + return *((const UINT16 *)(block_base + 1)); +} + +static struct bdb_block *find_section(struct context *context, int section_id) +{ + const struct bdb_header *bdb = context->bdb; + int length = context->size; + struct bdb_block *block; + const UINT8 *base = (const UINT8 *)bdb; + int index = 0; + UINT32 total, current_size; + unsigned char current_id; + + /* skip to first section */ + index += bdb->header_size; + total = bdb->bdb_size; + if (total > length) + total = length; + + block = malloc(sizeof(*block)); + if (!block) { + DebugPrint(EFI_D_ERROR, "i915: out of memory"); + exit(EXIT_FAILURE); + } + + /* walk the sections looking for section_id */ + while (index + 3 < total) { + current_id = *(base + index); + current_size = _get_blocksize(base + index); + index += 3; + + if (index + current_size > total) + return NULL; + + if (current_id == section_id) { + block->id = current_id; + block->size = current_size; + block->data = base + index; + return block; + } + + index += current_size; + } + + free(block); + return NULL; +} +static const char *dvo_port_names[] = { + [DVO_PORT_HDMIA] = "HDMI-A", + [DVO_PORT_HDMIB] = "HDMI-B", + [DVO_PORT_HDMIC] = "HDMI-C", + [DVO_PORT_HDMID] = "HDMI-D", + [DVO_PORT_LVDS] = "LVDS", + [DVO_PORT_TV] = "TV", + [DVO_PORT_CRT] = "CRT", + [DVO_PORT_DPB] = "DP-B", + [DVO_PORT_DPC] = "DP-C", + [DVO_PORT_DPD] = "DP-D", + [DVO_PORT_DPA] = "DP-A", + [DVO_PORT_DPE] = "DP-E", + [DVO_PORT_HDMIE] = "HDMI-E", + [DVO_PORT_MIPIA] = "MIPI-A", + [DVO_PORT_MIPIB] = "MIPI-B", + [DVO_PORT_MIPIC] = "MIPI-C", + [DVO_PORT_MIPID] = "MIPI-D", +}; + +static const char *dvo_port(UINT8 type) +{ + if (type < ARRAY_SIZE(dvo_port_names) && dvo_port_names[type]) + return dvo_port_names[type]; + else + return "unknown"; +} +#define DEVICE_HANDLE_CRT 0x01 +#define DEVICE_HANDLE_EFP1 0x04 +#define DEVICE_HANDLE_EFP2 0x40 +#define DEVICE_HANDLE_EFP3 0x20 +#define DEVICE_HANDLE_EFP4 0x10 +#define DEVICE_HANDLE_LPF1 0x08 +#define DEVICE_HANDLE_LFP2 0x80 + +#define DEVICE_TYPE_DP_DVI 0x68d6 +#define DEVICE_TYPE_DVI 0x68d2 +#define DEVICE_TYPE_MIPI 0x7cc2 +static const struct { + unsigned char handle; + const char *name; +} child_device_handles[] = { + { DEVICE_HANDLE_CRT, "CRT" }, + { DEVICE_HANDLE_EFP1, "EFP 1 (HDMI/DVI/DP)" }, + { DEVICE_HANDLE_EFP2, "EFP 2 (HDMI/DVI/DP)" }, + { DEVICE_HANDLE_EFP3, "EFP 3 (HDMI/DVI/DP)" }, + { DEVICE_HANDLE_EFP4, "EFP 4 (HDMI/DVI/DP)" }, + { DEVICE_HANDLE_LPF1, "LFP 1 (eDP)" }, + { DEVICE_HANDLE_LFP2, "LFP 2 (eDP)" }, +}; +static const int num_child_device_handles = + sizeof(child_device_handles) / sizeof(child_device_handles[0]); + +static const char *child_device_handle(unsigned char handle) +{ + int i; + + for (i = 0; i < num_child_device_handles; i++) + if (child_device_handles[i].handle == handle) + return child_device_handles[i].name; + + return "unknown"; +} +static const struct { + unsigned short type; + const char *name; +} child_device_types[] = { + { DEVICE_TYPE_NONE, "none" }, + { DEVICE_TYPE_CRT, "CRT" }, + { DEVICE_TYPE_TV, "TV" }, + { DEVICE_TYPE_EFP, "EFP" }, + { DEVICE_TYPE_LFP, "LFP" }, + { DEVICE_TYPE_CRT_DPMS, "CRT" }, + { DEVICE_TYPE_CRT_DPMS_HOTPLUG, "CRT" }, + { DEVICE_TYPE_TV_COMPOSITE, "TV composite" }, + { DEVICE_TYPE_TV_MACROVISION, "TV" }, + { DEVICE_TYPE_TV_RF_COMPOSITE, "TV" }, + { DEVICE_TYPE_TV_SVIDEO_COMPOSITE, "TV S-Video" }, + { DEVICE_TYPE_TV_SCART, "TV SCART" }, + { DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR, "TV" }, + { DEVICE_TYPE_EFP_HOTPLUG_PWR, "EFP" }, + { DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR, "DVI" }, + { DEVICE_TYPE_EFP_DVI_I, "DVI-I" }, + { DEVICE_TYPE_EFP_DVI_D_DUAL, "DL-DVI-D" }, + { DEVICE_TYPE_EFP_DVI_D_HDCP, "DVI-D" }, + { DEVICE_TYPE_OPENLDI_HOTPLUG_PWR, "OpenLDI" }, + { DEVICE_TYPE_OPENLDI_DUALPIX, "OpenLDI" }, + { DEVICE_TYPE_LFP_PANELLINK, "PanelLink" }, + { DEVICE_TYPE_LFP_CMOS_PWR, "CMOS LFP" }, + { DEVICE_TYPE_LFP_LVDS_PWR, "LVDS" }, + { DEVICE_TYPE_LFP_LVDS_DUAL, "LVDS" }, + { DEVICE_TYPE_LFP_LVDS_DUAL_HDCP, "LVDS" }, + { DEVICE_TYPE_INT_LFP, "LFP" }, + { DEVICE_TYPE_INT_TV, "TV" }, + { DEVICE_TYPE_DP, "DisplayPort" }, + { DEVICE_TYPE_DP_DUAL_MODE, "DisplayPort/HDMI/DVI" }, + { DEVICE_TYPE_DP_DVI, "DisplayPort/DVI" }, + { DEVICE_TYPE_HDMI, "HDMI/DVI" }, + { DEVICE_TYPE_DVI, "DVI" }, + { DEVICE_TYPE_eDP, "eDP" }, + { DEVICE_TYPE_MIPI, "MIPI" }, +}; +static const int num_child_device_types = + sizeof(child_device_types) / sizeof(child_device_types[0]); + +static const char *child_device_type(unsigned short type) +{ + int i; + + for (i = 0; i < num_child_device_types; i++) + if (child_device_types[i].type == type) + return child_device_types[i].name; + + return "unknown"; +} +static const struct { + unsigned short mask; + const char *name; +} child_device_type_bits[] = { + { DEVICE_TYPE_CLASS_EXTENSION, "Class extension" }, + { DEVICE_TYPE_POWER_MANAGEMENT, "Power management" }, + { DEVICE_TYPE_HOTPLUG_SIGNALING, "Hotplug signaling" }, + { DEVICE_TYPE_INTERNAL_CONNECTOR, "Internal connector" }, + { DEVICE_TYPE_NOT_HDMI_OUTPUT, "HDMI output" }, /* decoded as inverse */ + { DEVICE_TYPE_MIPI_OUTPUT, "MIPI output" }, + { DEVICE_TYPE_COMPOSITE_OUTPUT, "Composite output" }, + { DEVICE_TYPE_DUAL_CHANNEL, "Dual channel" }, + { 1 << 7, "Content protection" }, + { DEVICE_TYPE_HIGH_SPEED_LINK, "High speed link" }, + { DEVICE_TYPE_LVDS_SIGNALING, "LVDS signaling" }, + { DEVICE_TYPE_TMDS_DVI_SIGNALING, "TMDS/DVI signaling" }, + { DEVICE_TYPE_VIDEO_SIGNALING, "Video signaling" }, + { DEVICE_TYPE_DISPLAYPORT_OUTPUT, "DisplayPort output" }, + { DEVICE_TYPE_DIGITAL_OUTPUT, "Digital output" }, + { DEVICE_TYPE_ANALOG_OUTPUT, "Analog output" }, +}; + +static void dump_child_device_type_bits(UINT16 type) +{ + int i; + + type ^= DEVICE_TYPE_NOT_HDMI_OUTPUT; + + for (i = 0; i < ARRAY_SIZE(child_device_type_bits); i++) { + if (child_device_type_bits[i].mask & type) + DebugPrint(EFI_D_ERROR, "i915: \t\t\t%s\n", child_device_type_bits[i].name); + } +} +static const char *mipi_bridge_type(UINT8 type) +{ + switch (type) { + case 1: + return "ASUS"; + case 2: + return "Toshiba"; + case 3: + return "Renesas"; + default: + return "unknown"; + } +} +static void dump_child_device(struct context *context, + const struct child_device_config *child) +{ + if (!child->device_type) + return; + + DebugPrint(EFI_D_ERROR, "i915: Child device info:\n"); + DebugPrint(EFI_D_ERROR, "i915: \tDevice handle: 0x%04x (%s)\n", child->handle, + child_device_handle(child->handle)); + DebugPrint(EFI_D_ERROR, "i915: \tDevice type: 0x%04x (%s)\n", child->device_type, + child_device_type(child->device_type)); + dump_child_device_type_bits(child->device_type); + + if (context->bdb->version < 152) { + DebugPrint(EFI_D_ERROR, "i915: \tSignature: %.*s\n", (int)sizeof(child->device_id), child->device_id); + } else { + DebugPrint(EFI_D_ERROR, "i915: \tI2C speed: 0x%02x\n", child->i2c_speed); + DebugPrint(EFI_D_ERROR, "i915: \tDP onboard redriver: 0x%02x\n", child->dp_onboard_redriver); + DebugPrint(EFI_D_ERROR, "i915: \tDP ondock redriver: 0x%02x\n", child->dp_ondock_redriver); + DebugPrint(EFI_D_ERROR, "i915: \tHDMI level shifter value: 0x%02x\n", child->hdmi_level_shifter_value); + // dump_hmdi_max_data_rate(child->hdmi_max_data_rate); + DebugPrint(EFI_D_ERROR, "i915: \tOffset to DTD buffer for edidless CHILD: 0x%02x\n", child->dtd_buf_ptr); + DebugPrint(EFI_D_ERROR, "i915: \tEdidless EFP: %s\n", YESNO(child->edidless_efp)); + DebugPrint(EFI_D_ERROR, "i915: \tCompression enable: %s\n", YESNO(child->compression_enable)); + DebugPrint(EFI_D_ERROR, "i915: \tCompression method CPS: %s\n", YESNO(child->compression_method)); + DebugPrint(EFI_D_ERROR, "i915: \tDual pipe ganged eDP: %s\n", YESNO(child->ganged_edp)); + DebugPrint(EFI_D_ERROR, "i915: \tCompression structure index: 0x%02x)\n", child->compression_structure_index); + DebugPrint(EFI_D_ERROR, "i915: \tSlave DDI port: 0x%02x (%s)\n", child->slave_port, dvo_port(child->slave_port)); + } + + DebugPrint(EFI_D_ERROR, "i915: \tAIM offset: %d\n", child->addin_offset); + DebugPrint(EFI_D_ERROR, "i915: \tDVO Port: 0x%02x (%s)\n", child->dvo_port, dvo_port(child->dvo_port)); + + DebugPrint(EFI_D_ERROR, "i915: \tAIM I2C pin: 0x%02x\n", child->i2c_pin); + DebugPrint(EFI_D_ERROR, "i915: \tAIM Slave address: 0x%02x\n", child->slave_addr); + DebugPrint(EFI_D_ERROR, "i915: \tDDC pin: 0x%02x\n", child->ddc_pin); + DebugPrint(EFI_D_ERROR, "i915: \tEDID buffer ptr: 0x%02x\n", child->edid_ptr); + DebugPrint(EFI_D_ERROR, "i915: \tDVO config: 0x%02x\n", child->dvo_cfg); + + if (context->bdb->version < 155) { + DebugPrint(EFI_D_ERROR, "i915: \tDVO2 Port: 0x%02x (%s)\n", child->dvo2_port, dvo_port(child->dvo2_port)); + DebugPrint(EFI_D_ERROR, "i915: \tI2C2 pin: 0x%02x\n", child->i2c2_pin); + DebugPrint(EFI_D_ERROR, "i915: \tSlave2 address: 0x%02x\n", child->slave2_addr); + DebugPrint(EFI_D_ERROR, "i915: \tDDC2 pin: 0x%02x\n", child->ddc2_pin); + } else { + DebugPrint(EFI_D_ERROR, "i915: \tEFP routed through dock: %s\n", YESNO(child->efp_routed)); + DebugPrint(EFI_D_ERROR, "i915: \tLane reversal: %s\n", YESNO(child->lane_reversal)); + DebugPrint(EFI_D_ERROR, "i915: \tOnboard LSPCON: %s\n", YESNO(child->lspcon)); + DebugPrint(EFI_D_ERROR, "i915: \tIboost enable: %s\n", YESNO(child->iboost)); + DebugPrint(EFI_D_ERROR, "i915: \tHPD sense invert: %s\n", YESNO(child->hpd_invert)); + DebugPrint(EFI_D_ERROR, "i915: \tHDMI compatible? %s\n", YESNO(child->hdmi_support)); + DebugPrint(EFI_D_ERROR, "i915: \tDP compatible? %s\n", YESNO(child->dp_support)); + DebugPrint(EFI_D_ERROR, "i915: \tTMDS compatible? %s\n", YESNO(child->tmds_support)); + DebugPrint(EFI_D_ERROR, "i915: \tAux channel: 0x%02x\n", child->aux_channel); + DebugPrint(EFI_D_ERROR, "i915: \tDongle detect: 0x%02x\n", child->dongle_detect); + } + + DebugPrint(EFI_D_ERROR, "i915: \tPipe capabilities: 0x%02x\n", child->pipe_cap); + DebugPrint(EFI_D_ERROR, "i915: \tSDVO stall signal available: %s\n", YESNO(child->sdvo_stall)); + DebugPrint(EFI_D_ERROR, "i915: \tHotplug connect status: 0x%02x\n", child->hpd_status); + DebugPrint(EFI_D_ERROR, "i915: \tIntegrated encoder instead of SDVO: %s\n", YESNO(child->integrated_encoder)); + DebugPrint(EFI_D_ERROR, "i915: \tDVO wiring: 0x%02x\n", child->dvo_wiring); + + if (context->bdb->version < 171) { + DebugPrint(EFI_D_ERROR, "i915: \tDVO2 wiring: 0x%02x\n", child->dvo2_wiring); + } else { + DebugPrint(EFI_D_ERROR, "i915: \tMIPI bridge type: %02x (%s)\n", child->mipi_bridge_type, + mipi_bridge_type(child->mipi_bridge_type)); + } + + DebugPrint(EFI_D_ERROR, "i915: \tDevice class extension: 0x%02x\n", child->extended_type); + DebugPrint(EFI_D_ERROR, "i915: \tDVO function: 0x%02x\n", child->dvo_function); + + if (context->bdb->version >= 195) { + DebugPrint(EFI_D_ERROR, "i915: \tDP USB type C support: %s\n", YESNO(child->dp_usb_type_c)); + DebugPrint(EFI_D_ERROR, "i915: \t2X DP GPIO index: 0x%02x\n", child->dp_gpio_index); + DebugPrint(EFI_D_ERROR, "i915: \t2X DP GPIO pin number: 0x%02x\n", child->dp_gpio_pin_num); + } + + if (context->bdb->version >= 196) { + DebugPrint(EFI_D_ERROR, "i915: \tIBoost level for HDMI: 0x%02x\n", child->hdmi_iboost_level); + DebugPrint(EFI_D_ERROR, "i915: \tIBoost level for DP/eDP: 0x%02x\n", child->dp_iboost_level); + } +} +#define min(a,b) (((a)<(b))?(a):(b)) +#define max(a,b) (((a)>(b))?(a):(b)) + +static void dump_child_devices(struct context *context, const UINT8 *devices, + UINT8 child_dev_num, UINT8 child_dev_size) +{ + struct child_device_config *child; + int i; + + /* + * Use a temp buffer so dump_child_device() doesn't have to worry about + * accessing the struct beyond child_dev_size. The tail, if any, remains + * initialized to zero. + */ + child = calloc(1, sizeof(*child)); + + for (i = 0; i < child_dev_num; i++) { + memcpy(child, devices + i * child_dev_size, + min(sizeof(*child), child_dev_size)); + + dump_child_device(context, child); + } + + free(child); +} +static void dumpNull(struct context *context, + const struct bdb_block *block) { + DebugPrint(EFI_D_ERROR, "i915: undefined block \n"); + } +static void dump_general_definitions(struct context *context, + const struct bdb_block *block) +{ + const struct bdb_general_definitions *defs = block->data; + int child_dev_num; + + child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size; + + DebugPrint(EFI_D_ERROR, "i915: CRT DDC GMBUS addr: 0x%02x\n", defs->crt_ddc_gmbus_pin); + DebugPrint(EFI_D_ERROR, "i915: Use ACPI DPMS CRT power states: %s\n", + YESNO(defs->dpms_acpi)); + DebugPrint(EFI_D_ERROR, "i915: Skip CRT detect at boot: %s\n", + YESNO(defs->skip_boot_crt_detect)); + DebugPrint(EFI_D_ERROR, "i915: Use DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim)); + DebugPrint(EFI_D_ERROR, "i915: Boot display type: 0x%02x%02x\n", defs->boot_display[1], + defs->boot_display[0]); + DebugPrint(EFI_D_ERROR, "i915: Child device size: %d\n", defs->child_dev_size); + DebugPrint(EFI_D_ERROR, "i915: Child device count: %d\n", child_dev_num); + + dump_child_devices(context, defs->devices, + child_dev_num, defs->child_dev_size); +} + +static void dump_legacy_child_devices(struct context *context, + const struct bdb_block *block) +{ + const struct bdb_legacy_child_devices *defs = block->data; + int child_dev_num; + + child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size; + + DebugPrint(EFI_D_ERROR, "i915: Child device size: %d\n", defs->child_dev_size); + DebugPrint(EFI_D_ERROR, "i915: Child device count: %d\n", child_dev_num); + + dump_child_devices(context, defs->devices, + child_dev_num, defs->child_dev_size); +} +struct dumper dumpers[] = { + { + .id = BDB_GENERAL_FEATURES, + .name = "General features block", + .dump = dumpNull, + }, + { + .id = BDB_GENERAL_DEFINITIONS, + .name = "General definitions block", + .dump = dump_general_definitions, + }, + { + .id = BDB_CHILD_DEVICE_TABLE, + .name = "Legacy child devices block", + .dump = dump_legacy_child_devices, + }, + { + .id = BDB_LVDS_OPTIONS, + .name = "LVDS options block", + .dump = dumpNull, + }, + { + .id = BDB_LVDS_LFP_DATA_PTRS, + .name = "LVDS timing pointer data", + .dump = dumpNull, + }, + { + .id = BDB_LVDS_LFP_DATA, + .name = "LVDS panel data block", + .dump = dumpNull, + }, + { + .id = BDB_LVDS_BACKLIGHT, + .name = "Backlight info block", + .dump = dumpNull, + }, + { + .id = BDB_SDVO_LVDS_OPTIONS, + .name = "SDVO LVDS options block", + .dump = dumpNull, + }, + { + .id = BDB_SDVO_PANEL_DTDS, + .name = "SDVO panel dtds", + .dump = dumpNull, + }, + { + .id = BDB_DRIVER_FEATURES, + .name = "Driver feature data block", + .dump = dumpNull, + }, + { + .id = BDB_EDP, + .name = "eDP block", + .dump = dumpNull, + }, + { + .id = BDB_PSR, + .name = "PSR block", + .dump = dumpNull, + }, + { + .id = BDB_MIPI_CONFIG, + .name = "MIPI configuration block", + .dump = dumpNull, + }, + { + .id = BDB_MIPI_SEQUENCE, + .name = "MIPI sequence block", + .dump = dumpNull, + }, + { + .id = BDB_COMPRESSION_PARAMETERS, + .name = "Compression parameters block", + .dump = dumpNull, + }, +}; +static BOOLEAN dump_section(struct context *context, int section_id) +{ + struct dumper *dumper = NULL; + struct bdb_block *block; + int i; + + block = find_section(context, section_id); + if (!block) + return FALSE; + + for (i = 0; i < ARRAY_SIZE(dumpers); i++) { + if (block->id == dumpers[i].id) { + dumper = &dumpers[i]; + break; + } + } + + if (dumper && dumper->name) + DebugPrint(EFI_D_ERROR, "BDB block %d - %s:\n", block->id, dumper->name); + else + DebugPrint(EFI_D_ERROR, "BDB block %d - Unknown, no decoding available:\n", + block->id); + + //if (context->hexdump) + // hex_dump_block(block); + if (dumper && dumper->dump) + dumper->dump(context, block); + DebugPrint(EFI_D_ERROR, "\n"); + + free(block); + + return TRUE; +} +EFI_STATUS decodeVBT( struct vbt_header *vbt, UINT8 *VBIOS) +{ + //UINT8 *VBIOS; +// int index; +// int fd; + //struct vbt_header *vbt = NULL; + int i; +// const char *filename = NULL; + //int size; + struct context context = { + .panel_type = -1, + }; +// int block_number = -1; + //BOOLEAN header_only = FALSE, describe = FALSE; + + + + + /* Scour memory looking for the VBT signature */ + + + context.vbt = vbt; + context.bdb = (const struct bdb_header *)(vbt + vbt->bdb_offset); + context.size = 8192; + +/* if (!context.devid) { + const char *devid_string = getenv("DEVICE"); + if (devid_string) + context.devid = strtoul(devid_string, NULL, 16); + } + if (!context.devid) + context.devid = get_device_id(VBIOS, size); + if (!context.devid) + DebugPrint(EFI_D_ERROR, "Warning: could not find PCI device ID!\n"); + + if (context.panel_type == -1) + context.panel_type = get_panel_type(&context); + if (context.panel_type == -1) { + DebugPrint(EFI_D_ERROR, "Warning: panel type not set, using 0\n"); + context.panel_type = 0; + } */ + +/* if (describe) { + print_description(&context); + } else if (header_only) { + dump_headers(&context); + } else if (block_number != -1) { + dump specific section only + if (!dump_section(&context, block_number)) { + DebugPrint(EFI_D_ERROR, "Block %d not found\n", block_number); + return EXIT_FAILURE; + } + } else { */ + // dump_headers(&context); + + /* dump all sections */ + for (i = 0; i < 256; i++) + dump_section(&context, i); +// } + + return 0; +} \ No newline at end of file diff --git a/intel_opregion.h b/intel_opregion.h new file mode 100644 index 0000000..f6249c6 --- /dev/null +++ b/intel_opregion.h @@ -0,0 +1,1237 @@ +/* + * Copyright 2008 Intel Corporation + * Copyright 2008 Red Hat + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include +#include +#include +#include +#include + +#include "QemuFwCfgLib.h" +#include "i915_display.h" +#include "i915_gop.h" +#include "i915ovmf.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define OPREGION_HEADER_OFFSET 0 +#define OPREGION_ACPI_OFFSET 0x100 +#define ACPI_CLID 0x01ac /* current lid state indicator */ +#define ACPI_CDCK 0x01b0 /* current docking state indicator */ +#define OPREGION_SWSCI_OFFSET 0x200 +#define OPREGION_ASLE_OFFSET 0x300 +#define OPREGION_VBT_OFFSET 0x400 +#define OPREGION_ASLE_EXT_OFFSET 0x1C00 + +#define OPREGION_SIGNATURE "IntelGraphicsMem" +#define MBOX_ACPI (1 << 0) +#define MBOX_SWSCI (1 << 1) +#define MBOX_ASLE (1 << 2) +#define MBOX_ASLE_EXT (1 << 4) +#define __packed __attribute__((packed)) +struct opregion_header +{ + UINT8 signature[16]; + UINT32 size; + struct + { + UINT8 rsvd; + UINT8 revision; + UINT8 minor; + UINT8 major; + } __packed over; + UINT8 bios_ver[32]; + UINT8 vbios_ver[16]; + UINT8 driver_ver[16]; + UINT32 mboxes; + UINT32 driver_model; + UINT32 pcon; + UINT8 dver[32]; + UINT8 rsvd[124]; +} __packed; + +/* OpRegion mailbox #1: public ACPI methods */ +struct opregion_acpi +{ + UINT32 drdy; /* driver readiness */ + UINT32 csts; /* notification status */ + UINT32 cevt; /* current event */ + UINT8 rsvd1[20]; + UINT32 didl[8]; /* supported display devices ID list */ + UINT32 cpdl[8]; /* currently presented display list */ + UINT32 cadl[8]; /* currently active display list */ + UINT32 nadl[8]; /* next active devices list */ + UINT32 aslp; /* ASL sleep time-out */ + UINT32 tidx; /* toggle table index */ + UINT32 chpd; /* current hotplug enable indicator */ + UINT32 clid; /* current lid state*/ + UINT32 cdck; /* current docking state */ + UINT32 sxsw; /* Sx state resume */ + UINT32 evts; /* ASL supported events */ + UINT32 cnot; /* current OS notification */ + UINT32 nrdy; /* driver status */ + UINT32 did2[7]; /* extended supported display devices ID list */ + UINT32 cpd2[7]; /* extended attached display devices list */ + UINT8 rsvd2[4]; +} __packed; + +/* OpRegion mailbox #2: SWSCI */ +struct opregion_swsci +{ + UINT32 scic; /* SWSCI command|status|data */ + UINT32 parm; /* command parameters */ + UINT32 dslp; /* driver sleep time-out */ + UINT8 rsvd[244]; +} __packed; + +/* OpRegion mailbox #3: ASLE */ +struct opregion_asle +{ + UINT32 ardy; /* driver readiness */ + UINT32 aslc; /* ASLE interrupt command */ + UINT32 tche; /* technology enabled indicator */ + UINT32 alsi; /* current ALS illuminance reading */ + UINT32 bclp; /* backlight brightness to set */ + UINT32 pfit; /* panel fitting state */ + UINT32 cblv; /* current brightness level */ + UINT16 bclm[20]; /* backlight level duty cycle mapping table */ + UINT32 cpfm; /* current panel fitting mode */ + UINT32 epfm; /* enabled panel fitting modes */ + UINT8 plut[74]; /* panel LUT and identifier */ + UINT32 pfmb; /* PWM freq and min brightness */ + UINT32 cddv; /* color correction default values */ + UINT32 pcft; /* power conservation features */ + UINT32 srot; /* supported rotation angles */ + UINT32 iuer; /* IUER events */ + UINT64 fdss; + UINT32 fdsp; + UINT32 stat; + UINT64 rvda; /* Physical (2.0) or relative from opregion (2.1+) + * address of raw VBT data. */ + UINT32 rvds; /* Size of raw vbt data */ + UINT8 rsvd[58]; +} __packed; + +/* OpRegion mailbox #5: ASLE ext */ +struct opregion_asle_ext +{ + UINT32 phed; /* Panel Header */ + UINT8 bddc[256]; /* Panel EDID */ + UINT8 rsvd[764]; +} __packed; +/** + * struct vbt_header - VBT Header structure + * @signature: VBT signature, always starts with "$VBT" + * @version: Version of this structure + * @header_size: Size of this structure + * @vbt_size: Size of VBT (VBT Header, BDB Header and data blocks) + * @vbt_checksum: Checksum + * @reserved0: Reserved + * @bdb_offset: Offset of &struct bdb_header from beginning of VBT + * @aim_offset: Offsets of add-in data blocks from beginning of VBT + */ +struct vbt_header +{ + UINT8 signature[20]; + UINT16 version; + UINT16 header_size; + UINT16 vbt_size; + UINT8 vbt_checksum; + UINT8 reserved0; + UINT32 bdb_offset; + UINT32 aim_offset[4]; +} __packed; + +/** + * struct bdb_header - BDB Header structure + * @signature: BDB signature "BIOS_DATA_BLOCK" + * @version: Version of the data block definitions + * @header_size: Size of this structure + * @bdb_size: Size of BDB (BDB Header and data blocks) + */ +struct bdb_header +{ + UINT8 signature[16]; + UINT16 version; + UINT16 header_size; + UINT16 bdb_size; +} __packed; + +struct intel_opregion +{ + struct opregion_header *header; + struct opregion_acpi *acpi; + struct opregion_swsci *swsci; + struct opregion_asle *asle; + struct vbt_header *vbt; + struct bdb_header *bdb; + struct opregion_asle_ext *asle_ext; +}; +struct bdb_block +{ + UINT8 id; + UINT32 size; + const void *data; +}; +struct context +{ + const struct vbt_header *vbt; + const struct bdb_header *bdb; + int size; + + UINT32 devid; + int panel_type; + BOOLEAN dump_all_panel_types; + BOOLEAN hexdump; +}; + +struct dumper +{ + UINT8 id; + const char *name; + void (*dump)(struct context *context, + const struct bdb_block *block); +}; + + +enum bdb_block_id +{ + BDB_GENERAL_FEATURES = 1, + BDB_GENERAL_DEFINITIONS = 2, + BDB_OLD_TOGGLE_LIST = 3, + BDB_MODE_SUPPORT_LIST = 4, + BDB_GENERIC_MODE_TABLE = 5, + BDB_EXT_MMIO_REGS = 6, + BDB_SWF_IO = 7, + BDB_SWF_MMIO = 8, + BDB_PSR = 9, + BDB_MODE_REMOVAL_TABLE = 10, + BDB_CHILD_DEVICE_TABLE = 11, + BDB_DRIVER_FEATURES = 12, + BDB_DRIVER_PERSISTENCE = 13, + BDB_EXT_TABLE_PTRS = 14, + BDB_DOT_CLOCK_OVERRIDE = 15, + BDB_DISPLAY_SELECT = 16, + BDB_DRIVER_ROTATION = 18, + BDB_DISPLAY_REMOVE = 19, + BDB_OEM_CUSTOM = 20, + BDB_EFP_LIST = 21, /* workarounds for VGA hsync/vsync */ + BDB_SDVO_LVDS_OPTIONS = 22, + BDB_SDVO_PANEL_DTDS = 23, + BDB_SDVO_LVDS_PNP_IDS = 24, + BDB_SDVO_LVDS_POWER_SEQ = 25, + BDB_TV_OPTIONS = 26, + BDB_EDP = 27, + BDB_LVDS_OPTIONS = 40, + BDB_LVDS_LFP_DATA_PTRS = 41, + BDB_LVDS_LFP_DATA = 42, + BDB_LVDS_BACKLIGHT = 43, + BDB_LVDS_POWER = 44, + BDB_MIPI_CONFIG = 52, + BDB_MIPI_SEQUENCE = 53, + BDB_COMPRESSION_PARAMETERS = 56, + BDB_SKIP = 254, /* VBIOS private block, ignore */ +}; + + + +/* Get to bdb section of vbt. THen Scan through to read off the ids of the blocks until we find general definitions or legacy child devices. THen read them +* +*/ +struct bdb_legacy_child_devices { + UINT8 child_dev_size; + UINT8 devices[0]; /* presumably 7 * 33 */ +} __attribute__ ((packed)); +/* Driver readiness indicator */ +#define ASLE_ARDY_READY (1 << 0) +#define ASLE_ARDY_NOT_READY (0 << 0) + +/* ASLE Interrupt Command (ASLC) bits */ +#define ASLC_SET_ALS_ILLUM (1 << 0) +#define ASLC_SET_BACKLIGHT (1 << 1) +#define ASLC_SET_PFIT (1 << 2) +#define ASLC_SET_PWM_FREQ (1 << 3) +#define ASLC_SUPPORTED_ROTATION_ANGLES (1 << 4) +#define ASLC_BUTTON_ARRAY (1 << 5) +#define ASLC_CONVERTIBLE_INDICATOR (1 << 6) +#define ASLC_DOCKING_INDICATOR (1 << 7) +#define ASLC_ISCT_STATE_CHANGE (1 << 8) +#define ASLC_REQ_MSK 0x1ff +/* response bits */ +#define ASLC_ALS_ILLUM_FAILED (1 << 10) +#define ASLC_BACKLIGHT_FAILED (1 << 12) +#define ASLC_PFIT_FAILED (1 << 14) +#define ASLC_PWM_FREQ_FAILED (1 << 16) +#define ASLC_ROTATION_ANGLES_FAILED (1 << 18) +#define ASLC_BUTTON_ARRAY_FAILED (1 << 20) +#define ASLC_CONVERTIBLE_FAILED (1 << 22) +#define ASLC_DOCKING_FAILED (1 << 24) +#define ASLC_ISCT_STATE_FAILED (1 << 26) + +/* Technology enabled indicator */ +#define ASLE_TCHE_ALS_EN (1 << 0) +#define ASLE_TCHE_BLC_EN (1 << 1) +#define ASLE_TCHE_PFIT_EN (1 << 2) +#define ASLE_TCHE_PFMB_EN (1 << 3) + +/* ASLE backlight brightness to set */ +#define ASLE_BCLP_VALID (1 << 31) +#define ASLE_BCLP_MSK (~(1 << 31)) + +/* ASLE panel fitting request */ +#define ASLE_PFIT_VALID (1 << 31) +#define ASLE_PFIT_CENTER (1 << 0) +#define ASLE_PFIT_STRETCH_TEXT (1 << 1) +#define ASLE_PFIT_STRETCH_GFX (1 << 2) + +/* PWM frequency and minimum brightness */ +#define ASLE_PFMB_BRIGHTNESS_MASK (0xff) +#define ASLE_PFMB_BRIGHTNESS_VALID (1 << 8) +#define ASLE_PFMB_PWM_MASK (0x7ffffe00) +#define ASLE_PFMB_PWM_VALID (1 << 31) + +#define ASLE_CBLV_VALID (1 << 31) + +/* IUER */ +#define ASLE_IUER_DOCKING (1 << 7) +#define ASLE_IUER_CONVERTIBLE (1 << 6) +#define ASLE_IUER_ROTATION_LOCK_BTN (1 << 4) +#define ASLE_IUER_VOLUME_DOWN_BTN (1 << 3) +#define ASLE_IUER_VOLUME_UP_BTN (1 << 2) +#define ASLE_IUER_WINDOWS_BTN (1 << 1) +#define ASLE_IUER_POWER_BTN (1 << 0) + +/* Software System Control Interrupt (SWSCI) */ +#define SWSCI_SCIC_INDICATOR (1 << 0) +#define SWSCI_SCIC_MAIN_FUNCTION_SHIFT 1 +#define SWSCI_SCIC_MAIN_FUNCTION_MASK (0xf << 1) +#define SWSCI_SCIC_SUB_FUNCTION_SHIFT 8 +#define SWSCI_SCIC_SUB_FUNCTION_MASK (0xff << 8) +#define SWSCI_SCIC_EXIT_PARAMETER_SHIFT 8 +#define SWSCI_SCIC_EXIT_PARAMETER_MASK (0xff << 8) +#define SWSCI_SCIC_EXIT_STATUS_SHIFT 5 +#define SWSCI_SCIC_EXIT_STATUS_MASK (7 << 5) +#define SWSCI_SCIC_EXIT_STATUS_SUCCESS 1 + +#define SWSCI_FUNCTION_CODE(main, sub) \ + ((main) << SWSCI_SCIC_MAIN_FUNCTION_SHIFT | \ + (sub) << SWSCI_SCIC_SUB_FUNCTION_SHIFT) + +/* SWSCI: Get BIOS Data (GBDA) */ +#define SWSCI_GBDA 4 +#define SWSCI_GBDA_SUPPORTED_CALLS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 0) +#define SWSCI_GBDA_REQUESTED_CALLBACKS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 1) +#define SWSCI_GBDA_BOOT_DISPLAY_PREF SWSCI_FUNCTION_CODE(SWSCI_GBDA, 4) +#define SWSCI_GBDA_PANEL_DETAILS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 5) +#define SWSCI_GBDA_TV_STANDARD SWSCI_FUNCTION_CODE(SWSCI_GBDA, 6) +#define SWSCI_GBDA_INTERNAL_GRAPHICS SWSCI_FUNCTION_CODE(SWSCI_GBDA, 7) +#define SWSCI_GBDA_SPREAD_SPECTRUM SWSCI_FUNCTION_CODE(SWSCI_GBDA, 10) + +/* SWSCI: System BIOS Callbacks (SBCB) */ +#define SWSCI_SBCB 6 +#define SWSCI_SBCB_SUPPORTED_CALLBACKS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 0) +#define SWSCI_SBCB_INIT_COMPLETION SWSCI_FUNCTION_CODE(SWSCI_SBCB, 1) +#define SWSCI_SBCB_PRE_HIRES_SET_MODE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 3) +#define SWSCI_SBCB_POST_HIRES_SET_MODE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 4) +#define SWSCI_SBCB_DISPLAY_SWITCH SWSCI_FUNCTION_CODE(SWSCI_SBCB, 5) +#define SWSCI_SBCB_SET_TV_FORMAT SWSCI_FUNCTION_CODE(SWSCI_SBCB, 6) +#define SWSCI_SBCB_ADAPTER_POWER_STATE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 7) +#define SWSCI_SBCB_DISPLAY_POWER_STATE SWSCI_FUNCTION_CODE(SWSCI_SBCB, 8) +#define SWSCI_SBCB_SET_BOOT_DISPLAY SWSCI_FUNCTION_CODE(SWSCI_SBCB, 9) +#define SWSCI_SBCB_SET_PANEL_DETAILS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 10) +#define SWSCI_SBCB_SET_INTERNAL_GFX SWSCI_FUNCTION_CODE(SWSCI_SBCB, 11) +#define SWSCI_SBCB_POST_HIRES_TO_DOS_FS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 16) +#define SWSCI_SBCB_SUSPEND_RESUME SWSCI_FUNCTION_CODE(SWSCI_SBCB, 17) +#define SWSCI_SBCB_SET_SPREAD_SPECTRUM SWSCI_FUNCTION_CODE(SWSCI_SBCB, 18) +#define SWSCI_SBCB_POST_VBE_PM SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19) +#define SWSCI_SBCB_ENABLE_DISABLE_AUDIO SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21) + +#define MAX_DSLP 1500 + +#define OPREGION_SIZE (8 * 1024) + +/* + * Copyright © 2006-2016 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +/* + * This information is private to VBT parsing in intel_bios.c. + * + * Please do NOT include anywhere else. + */ + + + + +/* + * There are several types of BIOS data blocks (BDBs), each block has + * an ID and size in the first 3 bytes (ID in first, size in next 2). + * Known types are listed below. + */ + + +/* + * Block 1 - General Bit Definitions + */ + +struct bdb_general_features +{ + /* bits 1 */ + UINT8 panel_fitting : 2; + UINT8 flexaim : 1; + UINT8 msg_enable : 1; + UINT8 clear_screen : 3; + UINT8 color_flip : 1; + + /* bits 2 */ + UINT8 download_ext_vbt : 1; + UINT8 enable_ssc : 1; + UINT8 ssc_freq : 1; + UINT8 enable_lfp_on_override : 1; + UINT8 disable_ssc_ddt : 1; + UINT8 underscan_vga_timings : 1; + UINT8 display_clock_mode : 1; + UINT8 vbios_hotplug_support : 1; + + /* bits 3 */ + UINT8 disable_smooth_vision : 1; + UINT8 single_dvi : 1; + UINT8 rotate_180 : 1; /* 181 */ + UINT8 fdi_rx_polarity_inverted : 1; + UINT8 vbios_extended_mode : 1; /* 160 */ + UINT8 copy_ilfp_dtd_to_sdvo_lvds_dtd : 1; /* 160 */ + UINT8 panel_best_fit_timing : 1; /* 160 */ + UINT8 ignore_strap_state : 1; /* 160 */ + + /* bits 4 */ + UINT8 legacy_monitor_detect; + + /* bits 5 */ + UINT8 int_crt_support : 1; + UINT8 int_tv_support : 1; + UINT8 int_efp_support : 1; + UINT8 dp_ssc_enable : 1; /* PCH attached eDP supports SSC */ + UINT8 dp_ssc_freq : 1; /* SSC freq for PCH attached eDP */ + UINT8 dp_ssc_dongle_supported : 1; + UINT8 rsvd11 : 2; /* finish byte */ +} __packed; + +/* + * Block 2 - General Bytes Definition + */ + +/* pre-915 */ +#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ +#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */ +#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */ +#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */ + +/* Pre 915 */ +#define DEVICE_TYPE_NONE 0x00 +#define DEVICE_TYPE_CRT 0x01 +#define DEVICE_TYPE_TV 0x09 +#define DEVICE_TYPE_EFP 0x12 +#define DEVICE_TYPE_LFP 0x22 +/* On 915+ */ +#define DEVICE_TYPE_CRT_DPMS 0x6001 +#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001 +#define DEVICE_TYPE_TV_COMPOSITE 0x0209 +#define DEVICE_TYPE_TV_MACROVISION 0x0289 +#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c +#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609 +#define DEVICE_TYPE_TV_SCART 0x0209 +#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009 +#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012 +#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052 +#define DEVICE_TYPE_EFP_DVI_I 0x6053 +#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152 +#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2 +#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062 +#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162 +#define DEVICE_TYPE_LFP_PANELLINK 0x5012 +#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042 +#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062 +#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162 +#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2 + +/* Add the device class for LFP, TV, HDMI */ +#define DEVICE_TYPE_INT_LFP 0x1022 +#define DEVICE_TYPE_INT_TV 0x1009 +#define DEVICE_TYPE_HDMI 0x60D2 +#define DEVICE_TYPE_DP 0x68C6 +#define DEVICE_TYPE_DP_DUAL_MODE 0x60D6 +#define DEVICE_TYPE_eDP 0x78C6 + +#define DEVICE_TYPE_CLASS_EXTENSION (1 << 15) +#define DEVICE_TYPE_POWER_MANAGEMENT (1 << 14) +#define DEVICE_TYPE_HOTPLUG_SIGNALING (1 << 13) +#define DEVICE_TYPE_INTERNAL_CONNECTOR (1 << 12) +#define DEVICE_TYPE_NOT_HDMI_OUTPUT (1 << 11) +#define DEVICE_TYPE_MIPI_OUTPUT (1 << 10) +#define DEVICE_TYPE_COMPOSITE_OUTPUT (1 << 9) +#define DEVICE_TYPE_DUAL_CHANNEL (1 << 8) +#define DEVICE_TYPE_HIGH_SPEED_LINK (1 << 6) +#define DEVICE_TYPE_LVDS_SIGNALING (1 << 5) +#define DEVICE_TYPE_TMDS_DVI_SIGNALING (1 << 4) +#define DEVICE_TYPE_VIDEO_SIGNALING (1 << 3) +#define DEVICE_TYPE_DISPLAYPORT_OUTPUT (1 << 2) +#define DEVICE_TYPE_DIGITAL_OUTPUT (1 << 1) +#define DEVICE_TYPE_ANALOG_OUTPUT (1 << 0) + +/* + * Bits we care about when checking for DEVICE_TYPE_eDP. Depending on the + * system, the other bits may or may not be set for eDP outputs. + */ +#define DEVICE_TYPE_eDP_BITS \ + (DEVICE_TYPE_INTERNAL_CONNECTOR | \ + DEVICE_TYPE_MIPI_OUTPUT | \ + DEVICE_TYPE_COMPOSITE_OUTPUT | \ + DEVICE_TYPE_DUAL_CHANNEL | \ + DEVICE_TYPE_LVDS_SIGNALING | \ + DEVICE_TYPE_TMDS_DVI_SIGNALING | \ + DEVICE_TYPE_VIDEO_SIGNALING | \ + DEVICE_TYPE_DISPLAYPORT_OUTPUT | \ + DEVICE_TYPE_ANALOG_OUTPUT) + +#define DEVICE_TYPE_DP_DUAL_MODE_BITS \ + (DEVICE_TYPE_INTERNAL_CONNECTOR | \ + DEVICE_TYPE_MIPI_OUTPUT | \ + DEVICE_TYPE_COMPOSITE_OUTPUT | \ + DEVICE_TYPE_LVDS_SIGNALING | \ + DEVICE_TYPE_TMDS_DVI_SIGNALING | \ + DEVICE_TYPE_VIDEO_SIGNALING | \ + DEVICE_TYPE_DISPLAYPORT_OUTPUT | \ + DEVICE_TYPE_DIGITAL_OUTPUT | \ + DEVICE_TYPE_ANALOG_OUTPUT) + +#define DEVICE_CFG_NONE 0x00 +#define DEVICE_CFG_12BIT_DVOB 0x01 +#define DEVICE_CFG_12BIT_DVOC 0x02 +#define DEVICE_CFG_24BIT_DVOBC 0x09 +#define DEVICE_CFG_24BIT_DVOCB 0x0a +#define DEVICE_CFG_DUAL_DVOB 0x11 +#define DEVICE_CFG_DUAL_DVOC 0x12 +#define DEVICE_CFG_DUAL_DVOBC 0x13 +#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19 +#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a + +#define DEVICE_WIRE_NONE 0x00 +#define DEVICE_WIRE_DVOB 0x01 +#define DEVICE_WIRE_DVOC 0x02 +#define DEVICE_WIRE_DVOBC 0x03 +#define DEVICE_WIRE_DVOBB 0x05 +#define DEVICE_WIRE_DVOCC 0x06 +#define DEVICE_WIRE_DVOB_MASTER 0x0d +#define DEVICE_WIRE_DVOC_MASTER 0x0e + +/* dvo_port pre BDB 155 */ +#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */ +#define DEVICE_PORT_DVOB 0x01 +#define DEVICE_PORT_DVOC 0x02 + +/* dvo_port BDB 155+ */ +#define DVO_PORT_HDMIA 0 +#define DVO_PORT_HDMIB 1 +#define DVO_PORT_HDMIC 2 +#define DVO_PORT_HDMID 3 +#define DVO_PORT_LVDS 4 +#define DVO_PORT_TV 5 +#define DVO_PORT_CRT 6 +#define DVO_PORT_DPB 7 +#define DVO_PORT_DPC 8 +#define DVO_PORT_DPD 9 +#define DVO_PORT_DPA 10 +#define DVO_PORT_DPE 11 /* 193 */ +#define DVO_PORT_HDMIE 12 /* 193 */ +#define DVO_PORT_DPF 13 /* N/A */ +#define DVO_PORT_HDMIF 14 /* N/A */ +#define DVO_PORT_DPG 15 +#define DVO_PORT_HDMIG 16 +#define DVO_PORT_MIPIA 21 /* 171 */ +#define DVO_PORT_MIPIB 22 /* 171 */ +#define DVO_PORT_MIPIC 23 /* 171 */ +#define DVO_PORT_MIPID 24 /* 171 */ + +#define HDMI_MAX_DATA_RATE_PLATFORM 0 /* 204 */ +#define HDMI_MAX_DATA_RATE_297 1 /* 204 */ +#define HDMI_MAX_DATA_RATE_165 2 /* 204 */ + +#define LEGACY_CHILD_DEVICE_CONFIG_SIZE 33 + +/* DDC Bus DDI Type 155+ */ +enum vbt_gmbus_ddi +{ + DDC_BUS_DDI_B = 0x1, + DDC_BUS_DDI_C, + DDC_BUS_DDI_D, + DDC_BUS_DDI_F, + ICL_DDC_BUS_DDI_A = 0x1, + ICL_DDC_BUS_DDI_B, + TGL_DDC_BUS_DDI_C, + ICL_DDC_BUS_PORT_1 = 0x4, + ICL_DDC_BUS_PORT_2, + ICL_DDC_BUS_PORT_3, + ICL_DDC_BUS_PORT_4, + TGL_DDC_BUS_PORT_5, + TGL_DDC_BUS_PORT_6, +}; + +#define DP_AUX_A 0x40 +#define DP_AUX_B 0x10 +#define DP_AUX_C 0x20 +#define DP_AUX_D 0x30 +#define DP_AUX_E 0x50 +#define DP_AUX_F 0x60 +#define DP_AUX_G 0x70 + +#define VBT_DP_MAX_LINK_RATE_HBR3 0 +#define VBT_DP_MAX_LINK_RATE_HBR2 1 +#define VBT_DP_MAX_LINK_RATE_HBR 2 +#define VBT_DP_MAX_LINK_RATE_LBR 3 +#define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4)) +#define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2)) +#define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4)) +#define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8)) +#define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4)) +#define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2)) +#define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4)) +#define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8)) +#define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000 + +#define YESNO(val) ((val) ? "yes" : "no") + + +struct bdb_general_definitions +{ + /* DDC GPIO */ + UINT8 crt_ddc_gmbus_pin; + + /* DPMS bits */ + UINT8 dpms_acpi : 1; + UINT8 skip_boot_crt_detect : 1; + UINT8 dpms_aim : 1; + UINT8 rsvd1 : 5; /* finish byte */ + + /* boot device bits */ + UINT8 boot_display[2]; + UINT8 child_dev_size; + + /* + * Device info: + * If TV is present, it'll be at devices[0]. + * LVDS will be next, either devices[0] or [1], if present. + * On some platforms the number of device is 6. But could be as few as + * 4 if both TV and LVDS are missing. + * And the device num is related with the size of general definition + * block. It is obtained by using the following formula: + * number = (block_size - sizeof(bdb_general_definitions))/ + * defs->child_dev_size; + */ + UINT8 devices[0]; +} __packed; + +/* + * Block 9 - SRD Feature Block + */ + +struct psr_table +{ + /* Feature bits */ + UINT8 full_link : 1; + UINT8 require_aux_to_wakeup : 1; + UINT8 feature_bits_rsvd : 6; + + /* Wait times */ + UINT8 idle_frames : 4; + UINT8 lines_to_wait : 3; + UINT8 wait_times_rsvd : 1; + + /* TP wake up time in multiple of 100 */ + UINT16 tp1_wakeup_time; + UINT16 tp2_tp3_wakeup_time; +} __packed; + +struct bdb_psr +{ + struct psr_table psr_table[16]; + + /* PSR2 TP2/TP3 wakeup time for 16 panels */ + UINT32 psr2_tp2_tp3_wakeup_time; +} __packed; + +/* + * Block 12 - Driver Features Data Block + */ + +#define BDB_DRIVER_FEATURE_NO_LVDS 0 +#define BDB_DRIVER_FEATURE_INT_LVDS 1 +#define BDB_DRIVER_FEATURE_SDVO_LVDS 2 +#define BDB_DRIVER_FEATURE_INT_SDVO_LVDS 3 + +struct bdb_driver_features +{ + UINT8 boot_dev_algorithm : 1; + UINT8 block_display_switch : 1; + UINT8 allow_display_switch : 1; + UINT8 hotplug_dvo : 1; + UINT8 dual_view_zoom : 1; + UINT8 int15h_hook : 1; + UINT8 sprite_in_clone : 1; + UINT8 primary_lfp_id : 1; + + UINT16 boot_mode_x; + UINT16 boot_mode_y; + UINT8 boot_mode_bpp; + UINT8 boot_mode_refresh; + + UINT16 enable_lfp_primary : 1; + UINT16 selective_mode_pruning : 1; + UINT16 dual_frequency : 1; + UINT16 render_clock_freq : 1; /* 0: high freq; 1: low freq */ + UINT16 nt_clone_support : 1; + UINT16 power_scheme_ui : 1; /* 0: CUI; 1: 3rd party */ + UINT16 sprite_display_assign : 1; /* 0: secondary; 1: primary */ + UINT16 cui_aspect_scaling : 1; + UINT16 preserve_aspect_ratio : 1; + UINT16 sdvo_device_power_down : 1; + UINT16 crt_hotplug : 1; + UINT16 lvds_config : 2; + UINT16 tv_hotplug : 1; + UINT16 hdmi_config : 2; + + UINT8 static_display : 1; + UINT8 reserved2 : 7; + UINT16 legacy_crt_max_x; + UINT16 legacy_crt_max_y; + UINT8 legacy_crt_max_refresh; + + UINT8 hdmi_termination; + UINT8 custom_vbt_version; + /* Driver features data block */ + UINT16 rmpm_enabled : 1; + UINT16 s2ddt_enabled : 1; + UINT16 dpst_enabled : 1; + UINT16 bltclt_enabled : 1; + UINT16 adb_enabled : 1; + UINT16 drrs_enabled : 1; + UINT16 grs_enabled : 1; + UINT16 gpmt_enabled : 1; + UINT16 tbt_enabled : 1; + UINT16 psr_enabled : 1; + UINT16 ips_enabled : 1; + UINT16 reserved3 : 4; + UINT16 pc_feature_valid : 1; +} __packed; + +/* + * Block 22 - SDVO LVDS General Options + */ + +struct bdb_sdvo_lvds_options +{ + UINT8 panel_backlight; + UINT8 h40_set_panel_type; + UINT8 panel_type; + UINT8 ssc_clk_freq; + UINT16 als_low_trip; + UINT16 als_high_trip; + UINT8 sclalarcoeff_tab_row_num; + UINT8 sclalarcoeff_tab_row_size; + UINT8 coefficient[8]; + UINT8 panel_misc_bits_1; + UINT8 panel_misc_bits_2; + UINT8 panel_misc_bits_3; + UINT8 panel_misc_bits_4; +} __packed; + +/* + * Block 23 - SDVO LVDS Panel DTDs + */ + +struct lvds_dvo_timing +{ + UINT16 clock; /**< In 10khz */ + UINT8 hactive_lo; + UINT8 hblank_lo; + UINT8 hblank_hi : 4; + UINT8 hactive_hi : 4; + UINT8 vactive_lo; + UINT8 vblank_lo; + UINT8 vblank_hi : 4; + UINT8 vactive_hi : 4; + UINT8 hsync_off_lo; + UINT8 hsync_pulse_width_lo; + UINT8 vsync_pulse_width_lo : 4; + UINT8 vsync_off_lo : 4; + UINT8 vsync_pulse_width_hi : 2; + UINT8 vsync_off_hi : 2; + UINT8 hsync_pulse_width_hi : 2; + UINT8 hsync_off_hi : 2; + UINT8 himage_lo; + UINT8 vimage_lo; + UINT8 vimage_hi : 4; + UINT8 himage_hi : 4; + UINT8 h_border; + UINT8 v_border; + UINT8 rsvd1 : 3; + UINT8 digital : 2; + UINT8 vsync_positive : 1; + UINT8 hsync_positive : 1; + UINT8 non_interlaced : 1; +} __packed; + +struct bdb_sdvo_panel_dtds +{ + struct lvds_dvo_timing dtds[4]; +} __packed; + +/* + * Block 27 - eDP VBT Block + */ + +#define EDP_18BPP 0 +#define EDP_24BPP 1 +#define EDP_30BPP 2 +#define EDP_RATE_1_62 0 +#define EDP_RATE_2_7 1 +#define EDP_LANE_1 0 +#define EDP_LANE_2 1 +#define EDP_LANE_4 3 +#define EDP_PREEMPHASIS_NONE 0 +#define EDP_PREEMPHASIS_3_5dB 1 +#define EDP_PREEMPHASIS_6dB 2 +#define EDP_PREEMPHASIS_9_5dB 3 +#define EDP_VSWING_0_4V 0 +#define EDP_VSWING_0_6V 1 +#define EDP_VSWING_0_8V 2 +#define EDP_VSWING_1_2V 3 + +struct edp_fast_link_params +{ + UINT8 rate : 4; + UINT8 lanes : 4; + UINT8 preemphasis : 4; + UINT8 vswing : 4; +} __packed; + +struct edp_pwm_delays +{ + UINT16 pwm_on_to_backlight_enable; + UINT16 backlight_disable_to_pwm_off; +} __packed; + +struct edp_full_link_params +{ + UINT8 preemphasis : 4; + UINT8 vswing : 4; +} __packed; +struct edp_power_seq { + UINT16 t3; + UINT16 t7; + UINT16 t9; + UINT16 t10; + UINT16 t12; +} __attribute__ ((packed)); + +struct bdb_edp +{ + struct edp_power_seq power_seqs[16]; + UINT32 color_depth; + struct edp_fast_link_params fast_link_params[16]; + UINT32 sdrrs_msa_timing_delay; + + /* ith bit indicates enabled/disabled for (i+1)th panel */ + UINT16 edp_s3d_feature; /* 162 */ + UINT16 edp_t3_optimization; /* 165 */ + UINT64 edp_vswing_preemph; /* 173 */ + UINT16 fast_link_training; /* 182 */ + UINT16 dpcd_600h_write_required; /* 185 */ + struct edp_pwm_delays pwm_delays[16]; /* 186 */ + UINT16 full_link_params_provided; /* 199 */ + struct edp_full_link_params full_link_params[16]; /* 199 */ +} __packed; + +/* + * Block 40 - LFP Data Block + */ + +/* Mask for DRRS / Panel Channel / SSC / BLT control bits extraction */ +#define MODE_MASK 0x3 + +struct bdb_lvds_options +{ + UINT8 panel_type; + UINT8 panel_type2; /* 212 */ + /* LVDS capabilities, stored in a dword */ + UINT8 pfit_mode : 2; + UINT8 pfit_text_mode_enhanced : 1; + UINT8 pfit_gfx_mode_enhanced : 1; + UINT8 pfit_ratio_auto : 1; + UINT8 pixel_dither : 1; + UINT8 lvds_edid : 1; + UINT8 rsvd2 : 1; + UINT8 rsvd4; + /* LVDS Panel channel bits stored here */ + UINT32 lvds_panel_channel_bits; + /* LVDS SSC (Spread Spectrum Clock) bits stored here. */ + UINT16 ssc_bits; + UINT16 ssc_freq; + UINT16 ssc_ddt; + /* Panel color depth defined here */ + UINT16 panel_color_depth; + /* LVDS panel type bits stored here */ + UINT32 dps_panel_type_bits; + /* LVDS backlight control type bits stored here */ + UINT32 blt_control_type_bits; + + UINT16 lcdvcc_s0_enable; /* 200 */ + UINT32 rotation; /* 228 */ +} __packed; + +/* + * Block 41 - LFP Data Table Pointers + */ + +/* LFP pointer table contains entries to the struct below */ +struct lvds_lfp_data_ptr +{ + UINT16 fp_timing_offset; /* offsets are from start of bdb */ + UINT8 fp_table_size; + UINT16 dvo_timing_offset; + UINT8 dvo_table_size; + UINT16 panel_pnp_id_offset; + UINT8 pnp_table_size; +} __packed; + +struct bdb_lvds_lfp_data_ptrs +{ + UINT8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ + struct lvds_lfp_data_ptr ptr[16]; +} __packed; + +/* + * Block 42 - LFP Data Tables + */ + +/* LFP data has 3 blocks per entry */ +struct lvds_fp_timing +{ + UINT16 x_res; + UINT16 y_res; + UINT32 lvds_reg; + UINT32 lvds_reg_val; + UINT32 pp_on_reg; + UINT32 pp_on_reg_val; + UINT32 pp_off_reg; + UINT32 pp_off_reg_val; + UINT32 pp_cycle_reg; + UINT32 pp_cycle_reg_val; + UINT32 pfit_reg; + UINT32 pfit_reg_val; + UINT16 terminator; +} __packed; + +struct lvds_pnp_id +{ + UINT16 mfg_name; + UINT16 product_code; + UINT32 serial; + UINT8 mfg_week; + UINT8 mfg_year; +} __packed; + +struct lvds_lfp_data_entry +{ + struct lvds_fp_timing fp_timing; + struct lvds_dvo_timing dvo_timing; + struct lvds_pnp_id pnp_id; +} __packed; + +struct bdb_lvds_lfp_data +{ + struct lvds_lfp_data_entry data[16]; +} __packed; + +/* + * Block 43 - LFP Backlight Control Data Block + */ + +#define BDB_BACKLIGHT_TYPE_NONE 0 +#define BDB_BACKLIGHT_TYPE_PWM 2 + +struct lfp_backlight_data_entry +{ + UINT8 type : 2; + UINT8 active_low_pwm : 1; + UINT8 obsolete1 : 5; + UINT16 pwm_freq_hz; + UINT8 min_brightness; + UINT8 obsolete2; + UINT8 obsolete3; +} __packed; + +struct lfp_backlight_control_method +{ + UINT8 type : 4; + UINT8 controller : 4; +} __packed; + +struct bdb_lfp_backlight_data +{ + UINT8 entry_size; + struct lfp_backlight_data_entry data[16]; + UINT8 level[16]; + struct lfp_backlight_control_method backlight_control[16]; +} __packed; + +/* Block 52 contains MiPi Panel info + * 6 such enteries will there. Index into correct + * entery is based on the panel_index in #40 LFP + */ +#define MAX_MIPI_CONFIGURATIONS 6 +struct mipi_config { + UINT16 panel_id; + + /* General Params */ + UINT32 dithering:1; + UINT32 rsvd1:1; + UINT32 panel_type:1; + UINT32 panel_arch_type:2; + UINT32 cmd_mode:1; + UINT32 vtm:2; + UINT32 cabc:1; + UINT32 pwm_blc:1; + + /* Bit 13:10 + * 000 - Reserved, 001 - RGB565, 002 - RGB666, + * 011 - RGB666Loosely packed, 100 - RGB888, + * others - rsvd + */ + UINT32 videomode_color_format:4; + + /* Bit 15:14 + * 0 - No rotation, 1 - 90 degree + * 2 - 180 degree, 3 - 270 degree + */ + UINT32 rotation:2; + UINT32 bta:1; + UINT32 rsvd2:15; + + /* 2 byte Port Description */ + UINT16 dual_link:2; + UINT16 lane_cnt:2; + UINT16 pixel_overlap:3; + UINT16 rsvd3:9; + + /* 2 byte DSI COntroller params */ + /* 0 - Using DSI PHY, 1 - TE usage */ + UINT16 dsi_usage:1; + UINT16 rsvd4:15; + + UINT8 rsvd5[5]; + UINT32 dsi_ddr_clk; + UINT32 bridge_ref_clk; + + UINT8 byte_clk_sel:2; + UINT8 rsvd6:6; + + /* DPHY Flags */ + UINT16 dphy_param_valid:1; + UINT16 eot_disabled:1; + UINT16 clk_stop:1; + UINT16 rsvd7:13; + + UINT32 hs_tx_timeout; + UINT32 lp_rx_timeout; + UINT32 turn_around_timeout; + UINT32 device_reset_timer; + UINT32 master_init_timer; + UINT32 dbi_bw_timer; + UINT32 lp_byte_clk_val; + + /* 4 byte Dphy Params */ + UINT32 prepare_cnt:6; + UINT32 rsvd8:2; + UINT32 clk_zero_cnt:8; + UINT32 trail_cnt:5; + UINT32 rsvd9:3; + UINT32 exit_zero_cnt:6; + UINT32 rsvd10:2; + + UINT32 clk_lane_switch_cnt; + UINT32 hl_switch_cnt; + + UINT32 rsvd11[6]; + + /* timings based on dphy spec */ + UINT8 tclk_miss; + UINT8 tclk_post; + UINT8 rsvd12; + UINT8 tclk_pre; + UINT8 tclk_prepare; + UINT8 tclk_settle; + UINT8 tclk_term_enable; + UINT8 tclk_trail; + UINT16 tclk_prepare_clkzero; + UINT8 rsvd13; + UINT8 td_term_enable; + UINT8 teot; + UINT8 ths_exit; + UINT8 ths_prepare; + UINT16 ths_prepare_hszero; + UINT8 rsvd14; + UINT8 ths_settle; + UINT8 ths_skip; + UINT8 ths_trail; + UINT8 tinit; + UINT8 tlpx; + UINT8 rsvd15[3]; + + /* GPIOs */ + UINT8 panel_enable; + UINT8 bl_enable; + UINT8 pwm_enable; + UINT8 reset_r_n; + UINT8 pwr_down_r; + UINT8 stdby_r_n; + +} __attribute__ ((packed)); + +/* Block 52 contains MiPi configuration block + * 6 * bdb_mipi_config, followed by 6 pps data + * block below + */ +struct mipi_pps_data { + UINT16 panel_on_delay; + UINT16 bl_enable_delay; + UINT16 bl_disable_delay; + UINT16 panel_off_delay; + UINT16 panel_power_cycle_delay; +} __attribute__ ((packed)); + +struct bdb_mipi_config +{ + struct mipi_config config[MAX_MIPI_CONFIGURATIONS]; + struct mipi_pps_data pps[MAX_MIPI_CONFIGURATIONS]; +} __packed; + +/* + * Block 53 - MIPI Sequence Block + */ + +struct bdb_mipi_sequence +{ + UINT8 version; + UINT8 data[0]; /* up to 6 variable length blocks */ +} __packed; + +/* + * Block 56 - Compression Parameters + */ + +#define VBT_RC_BUFFER_BLOCK_SIZE_1KB 0 +#define VBT_RC_BUFFER_BLOCK_SIZE_4KB 1 +#define VBT_RC_BUFFER_BLOCK_SIZE_16KB 2 +#define VBT_RC_BUFFER_BLOCK_SIZE_64KB 3 + +#define VBT_DSC_LINE_BUFFER_DEPTH(vbt_value) ((vbt_value) + 8) /* bits */ +#define VBT_DSC_MAX_BPP(vbt_value) (6 + (vbt_value)*2) + +struct dsc_compression_parameters_entry +{ + UINT8 version_major : 4; + UINT8 version_minor : 4; + + UINT8 rc_buffer_block_size : 2; + UINT8 reserved1 : 6; + + /* + * Buffer size in bytes: + * + * 4 ^ rc_buffer_block_size * 1024 * (rc_buffer_size + 1) bytes + */ + UINT8 rc_buffer_size; + UINT32 slices_per_line; + + UINT8 line_buffer_depth : 4; + UINT8 reserved2 : 4; + + /* Flag Bits 1 */ + UINT8 block_prediction_enable : 1; + UINT8 reserved3 : 7; + + UINT8 max_bpp; /* mapping */ + + /* Color depth capabilities */ + UINT8 reserved4 : 1; + UINT8 support_8bpc : 1; + UINT8 support_10bpc : 1; + UINT8 support_12bpc : 1; + UINT8 reserved5 : 4; + + UINT16 slice_height; +} __packed; + +struct bdb_compression_parameters +{ + UINT16 entry_size; + struct dsc_compression_parameters_entry data[16]; +} __packed; + +EFI_STATUS decodeVBT( struct vbt_header *vbt, UINT8 *VBIOS); From 8a0c8bcfbb0439ff6b4cbc132165d2c1f1c7fd0b Mon Sep 17 00:00:00 2001 From: Patrick Magauran Date: Sun, 29 Nov 2020 11:15:12 -0500 Subject: [PATCH 2/5] Successfully Reads and decodes Opregion and VBT. --- i915ovmf.c | 2 +- intel_opregion.c | 317 +++++++++++++++++++++++++++-------------------- intel_opregion.h | 3 +- 3 files changed, 184 insertions(+), 138 deletions(-) diff --git a/i915ovmf.c b/i915ovmf.c index 5b19e7f..3173e79 100755 --- a/i915ovmf.c +++ b/i915ovmf.c @@ -287,7 +287,7 @@ SetupOpRegion(IN EFI_PCI_IO_PROTOCOL *PciIo, OpRegion.header=(struct opregion_header *) BytePointer; OpRegion.vbt =(struct vbt_header *) (BytePointer + 1024); - Status = decodeVBT(OpRegion.vbt, BytePointer); + Status = decodeVBT(OpRegion.vbt, 1024, BytePointer); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "%a: %a: failed to decode OpRegion: %r\n", __FUNCTION__, GetPciName(PciInfo), Status)); diff --git a/intel_opregion.c b/intel_opregion.c index 2cd9cce..6900957 100644 --- a/intel_opregion.c +++ b/intel_opregion.c @@ -1,7 +1,9 @@ #include "intel_opregion.h" -#include -#include +//TODO CONVVERT to EFI_STATUS RETURN TYPEs + +//#include +//#include /* * The child device config, aka the display device data structure, provides a @@ -136,23 +138,29 @@ static struct bdb_block *find_section(struct context *context, int section_id) total = bdb->bdb_size; if (total > length) total = length; - - block = malloc(sizeof(*block)); - if (!block) { - DebugPrint(EFI_D_ERROR, "i915: out of memory"); - exit(EXIT_FAILURE); - } + DebugPrint(EFI_D_ERROR, "i915: finding section %d\n", section_id); + //block = malloc(sizeof(*block)); /* walk the sections looking for section_id */ - while (index + 3 < total) { + while (index + 3 < total) + { current_id = *(base + index); current_size = _get_blocksize(base + index); index += 3; + //DebugPrint(EFI_D_ERROR, "i915: current id %d; index: %d; location 0x%04x; current_size: %d\n", current_id, index, (base + index), current_size); if (index + current_size > total) return NULL; - if (current_id == section_id) { + if (current_id == section_id) + { + block = (struct bdb_block *)AllocatePool(sizeof(block)); + if (!block) + { + DebugPrint(EFI_D_ERROR, "i915: out of memory"); + //TODO CONVVERT to EFI_STATUS RETURN TYPEs + // exit(EXIT_FAILURE); + } block->id = current_id; block->size = current_size; block->data = base + index; @@ -162,7 +170,7 @@ static struct bdb_block *find_section(struct context *context, int section_id) index += current_size; } - free(block); + FreePool(block); return NULL; } static const char *dvo_port_names[] = { @@ -192,28 +200,29 @@ static const char *dvo_port(UINT8 type) else return "unknown"; } -#define DEVICE_HANDLE_CRT 0x01 -#define DEVICE_HANDLE_EFP1 0x04 -#define DEVICE_HANDLE_EFP2 0x40 -#define DEVICE_HANDLE_EFP3 0x20 -#define DEVICE_HANDLE_EFP4 0x10 -#define DEVICE_HANDLE_LPF1 0x08 -#define DEVICE_HANDLE_LFP2 0x80 - -#define DEVICE_TYPE_DP_DVI 0x68d6 -#define DEVICE_TYPE_DVI 0x68d2 -#define DEVICE_TYPE_MIPI 0x7cc2 -static const struct { +#define DEVICE_HANDLE_CRT 0x01 +#define DEVICE_HANDLE_EFP1 0x04 +#define DEVICE_HANDLE_EFP2 0x40 +#define DEVICE_HANDLE_EFP3 0x20 +#define DEVICE_HANDLE_EFP4 0x10 +#define DEVICE_HANDLE_LPF1 0x08 +#define DEVICE_HANDLE_LFP2 0x80 + +#define DEVICE_TYPE_DP_DVI 0x68d6 +#define DEVICE_TYPE_DVI 0x68d2 +#define DEVICE_TYPE_MIPI 0x7cc2 +static const struct +{ unsigned char handle; const char *name; } child_device_handles[] = { - { DEVICE_HANDLE_CRT, "CRT" }, - { DEVICE_HANDLE_EFP1, "EFP 1 (HDMI/DVI/DP)" }, - { DEVICE_HANDLE_EFP2, "EFP 2 (HDMI/DVI/DP)" }, - { DEVICE_HANDLE_EFP3, "EFP 3 (HDMI/DVI/DP)" }, - { DEVICE_HANDLE_EFP4, "EFP 4 (HDMI/DVI/DP)" }, - { DEVICE_HANDLE_LPF1, "LFP 1 (eDP)" }, - { DEVICE_HANDLE_LFP2, "LFP 2 (eDP)" }, + {DEVICE_HANDLE_CRT, "CRT"}, + {DEVICE_HANDLE_EFP1, "EFP 1 (HDMI/DVI/DP)"}, + {DEVICE_HANDLE_EFP2, "EFP 2 (HDMI/DVI/DP)"}, + {DEVICE_HANDLE_EFP3, "EFP 3 (HDMI/DVI/DP)"}, + {DEVICE_HANDLE_EFP4, "EFP 4 (HDMI/DVI/DP)"}, + {DEVICE_HANDLE_LPF1, "LFP 1 (eDP)"}, + {DEVICE_HANDLE_LFP2, "LFP 2 (eDP)"}, }; static const int num_child_device_handles = sizeof(child_device_handles) / sizeof(child_device_handles[0]); @@ -228,44 +237,45 @@ static const char *child_device_handle(unsigned char handle) return "unknown"; } -static const struct { +static const struct +{ unsigned short type; const char *name; } child_device_types[] = { - { DEVICE_TYPE_NONE, "none" }, - { DEVICE_TYPE_CRT, "CRT" }, - { DEVICE_TYPE_TV, "TV" }, - { DEVICE_TYPE_EFP, "EFP" }, - { DEVICE_TYPE_LFP, "LFP" }, - { DEVICE_TYPE_CRT_DPMS, "CRT" }, - { DEVICE_TYPE_CRT_DPMS_HOTPLUG, "CRT" }, - { DEVICE_TYPE_TV_COMPOSITE, "TV composite" }, - { DEVICE_TYPE_TV_MACROVISION, "TV" }, - { DEVICE_TYPE_TV_RF_COMPOSITE, "TV" }, - { DEVICE_TYPE_TV_SVIDEO_COMPOSITE, "TV S-Video" }, - { DEVICE_TYPE_TV_SCART, "TV SCART" }, - { DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR, "TV" }, - { DEVICE_TYPE_EFP_HOTPLUG_PWR, "EFP" }, - { DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR, "DVI" }, - { DEVICE_TYPE_EFP_DVI_I, "DVI-I" }, - { DEVICE_TYPE_EFP_DVI_D_DUAL, "DL-DVI-D" }, - { DEVICE_TYPE_EFP_DVI_D_HDCP, "DVI-D" }, - { DEVICE_TYPE_OPENLDI_HOTPLUG_PWR, "OpenLDI" }, - { DEVICE_TYPE_OPENLDI_DUALPIX, "OpenLDI" }, - { DEVICE_TYPE_LFP_PANELLINK, "PanelLink" }, - { DEVICE_TYPE_LFP_CMOS_PWR, "CMOS LFP" }, - { DEVICE_TYPE_LFP_LVDS_PWR, "LVDS" }, - { DEVICE_TYPE_LFP_LVDS_DUAL, "LVDS" }, - { DEVICE_TYPE_LFP_LVDS_DUAL_HDCP, "LVDS" }, - { DEVICE_TYPE_INT_LFP, "LFP" }, - { DEVICE_TYPE_INT_TV, "TV" }, - { DEVICE_TYPE_DP, "DisplayPort" }, - { DEVICE_TYPE_DP_DUAL_MODE, "DisplayPort/HDMI/DVI" }, - { DEVICE_TYPE_DP_DVI, "DisplayPort/DVI" }, - { DEVICE_TYPE_HDMI, "HDMI/DVI" }, - { DEVICE_TYPE_DVI, "DVI" }, - { DEVICE_TYPE_eDP, "eDP" }, - { DEVICE_TYPE_MIPI, "MIPI" }, + {DEVICE_TYPE_NONE, "none"}, + {DEVICE_TYPE_CRT, "CRT"}, + {DEVICE_TYPE_TV, "TV"}, + {DEVICE_TYPE_EFP, "EFP"}, + {DEVICE_TYPE_LFP, "LFP"}, + {DEVICE_TYPE_CRT_DPMS, "CRT"}, + {DEVICE_TYPE_CRT_DPMS_HOTPLUG, "CRT"}, + {DEVICE_TYPE_TV_COMPOSITE, "TV composite"}, + {DEVICE_TYPE_TV_MACROVISION, "TV"}, + {DEVICE_TYPE_TV_RF_COMPOSITE, "TV"}, + {DEVICE_TYPE_TV_SVIDEO_COMPOSITE, "TV S-Video"}, + {DEVICE_TYPE_TV_SCART, "TV SCART"}, + {DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR, "TV"}, + {DEVICE_TYPE_EFP_HOTPLUG_PWR, "EFP"}, + {DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR, "DVI"}, + {DEVICE_TYPE_EFP_DVI_I, "DVI-I"}, + {DEVICE_TYPE_EFP_DVI_D_DUAL, "DL-DVI-D"}, + {DEVICE_TYPE_EFP_DVI_D_HDCP, "DVI-D"}, + {DEVICE_TYPE_OPENLDI_HOTPLUG_PWR, "OpenLDI"}, + {DEVICE_TYPE_OPENLDI_DUALPIX, "OpenLDI"}, + {DEVICE_TYPE_LFP_PANELLINK, "PanelLink"}, + {DEVICE_TYPE_LFP_CMOS_PWR, "CMOS LFP"}, + {DEVICE_TYPE_LFP_LVDS_PWR, "LVDS"}, + {DEVICE_TYPE_LFP_LVDS_DUAL, "LVDS"}, + {DEVICE_TYPE_LFP_LVDS_DUAL_HDCP, "LVDS"}, + {DEVICE_TYPE_INT_LFP, "LFP"}, + {DEVICE_TYPE_INT_TV, "TV"}, + {DEVICE_TYPE_DP, "DisplayPort"}, + {DEVICE_TYPE_DP_DUAL_MODE, "DisplayPort/HDMI/DVI"}, + {DEVICE_TYPE_DP_DVI, "DisplayPort/DVI"}, + {DEVICE_TYPE_HDMI, "HDMI/DVI"}, + {DEVICE_TYPE_DVI, "DVI"}, + {DEVICE_TYPE_eDP, "eDP"}, + {DEVICE_TYPE_MIPI, "MIPI"}, }; static const int num_child_device_types = sizeof(child_device_types) / sizeof(child_device_types[0]); @@ -280,26 +290,27 @@ static const char *child_device_type(unsigned short type) return "unknown"; } -static const struct { +static const struct +{ unsigned short mask; const char *name; } child_device_type_bits[] = { - { DEVICE_TYPE_CLASS_EXTENSION, "Class extension" }, - { DEVICE_TYPE_POWER_MANAGEMENT, "Power management" }, - { DEVICE_TYPE_HOTPLUG_SIGNALING, "Hotplug signaling" }, - { DEVICE_TYPE_INTERNAL_CONNECTOR, "Internal connector" }, - { DEVICE_TYPE_NOT_HDMI_OUTPUT, "HDMI output" }, /* decoded as inverse */ - { DEVICE_TYPE_MIPI_OUTPUT, "MIPI output" }, - { DEVICE_TYPE_COMPOSITE_OUTPUT, "Composite output" }, - { DEVICE_TYPE_DUAL_CHANNEL, "Dual channel" }, - { 1 << 7, "Content protection" }, - { DEVICE_TYPE_HIGH_SPEED_LINK, "High speed link" }, - { DEVICE_TYPE_LVDS_SIGNALING, "LVDS signaling" }, - { DEVICE_TYPE_TMDS_DVI_SIGNALING, "TMDS/DVI signaling" }, - { DEVICE_TYPE_VIDEO_SIGNALING, "Video signaling" }, - { DEVICE_TYPE_DISPLAYPORT_OUTPUT, "DisplayPort output" }, - { DEVICE_TYPE_DIGITAL_OUTPUT, "Digital output" }, - { DEVICE_TYPE_ANALOG_OUTPUT, "Analog output" }, + {DEVICE_TYPE_CLASS_EXTENSION, "Class extension"}, + {DEVICE_TYPE_POWER_MANAGEMENT, "Power management"}, + {DEVICE_TYPE_HOTPLUG_SIGNALING, "Hotplug signaling"}, + {DEVICE_TYPE_INTERNAL_CONNECTOR, "Internal connector"}, + {DEVICE_TYPE_NOT_HDMI_OUTPUT, "HDMI output"}, /* decoded as inverse */ + {DEVICE_TYPE_MIPI_OUTPUT, "MIPI output"}, + {DEVICE_TYPE_COMPOSITE_OUTPUT, "Composite output"}, + {DEVICE_TYPE_DUAL_CHANNEL, "Dual channel"}, + {1 << 7, "Content protection"}, + {DEVICE_TYPE_HIGH_SPEED_LINK, "High speed link"}, + {DEVICE_TYPE_LVDS_SIGNALING, "LVDS signaling"}, + {DEVICE_TYPE_TMDS_DVI_SIGNALING, "TMDS/DVI signaling"}, + {DEVICE_TYPE_VIDEO_SIGNALING, "Video signaling"}, + {DEVICE_TYPE_DISPLAYPORT_OUTPUT, "DisplayPort output"}, + {DEVICE_TYPE_DIGITAL_OUTPUT, "Digital output"}, + {DEVICE_TYPE_ANALOG_OUTPUT, "Analog output"}, }; static void dump_child_device_type_bits(UINT16 type) @@ -308,14 +319,16 @@ static void dump_child_device_type_bits(UINT16 type) type ^= DEVICE_TYPE_NOT_HDMI_OUTPUT; - for (i = 0; i < ARRAY_SIZE(child_device_type_bits); i++) { + for (i = 0; i < ARRAY_SIZE(child_device_type_bits); i++) + { if (child_device_type_bits[i].mask & type) DebugPrint(EFI_D_ERROR, "i915: \t\t\t%s\n", child_device_type_bits[i].name); } } static const char *mipi_bridge_type(UINT8 type) { - switch (type) { + switch (type) + { case 1: return "ASUS"; case 2: @@ -327,26 +340,29 @@ static const char *mipi_bridge_type(UINT8 type) } } static void dump_child_device(struct context *context, - const struct child_device_config *child) + const struct child_device_config *child) { if (!child->device_type) return; DebugPrint(EFI_D_ERROR, "i915: Child device info:\n"); DebugPrint(EFI_D_ERROR, "i915: \tDevice handle: 0x%04x (%s)\n", child->handle, - child_device_handle(child->handle)); + child_device_handle(child->handle)); DebugPrint(EFI_D_ERROR, "i915: \tDevice type: 0x%04x (%s)\n", child->device_type, - child_device_type(child->device_type)); + child_device_type(child->device_type)); dump_child_device_type_bits(child->device_type); - if (context->bdb->version < 152) { + if (context->bdb->version < 152) + { DebugPrint(EFI_D_ERROR, "i915: \tSignature: %.*s\n", (int)sizeof(child->device_id), child->device_id); - } else { + } + else + { DebugPrint(EFI_D_ERROR, "i915: \tI2C speed: 0x%02x\n", child->i2c_speed); DebugPrint(EFI_D_ERROR, "i915: \tDP onboard redriver: 0x%02x\n", child->dp_onboard_redriver); DebugPrint(EFI_D_ERROR, "i915: \tDP ondock redriver: 0x%02x\n", child->dp_ondock_redriver); DebugPrint(EFI_D_ERROR, "i915: \tHDMI level shifter value: 0x%02x\n", child->hdmi_level_shifter_value); - // dump_hmdi_max_data_rate(child->hdmi_max_data_rate); + // dump_hmdi_max_data_rate(child->hdmi_max_data_rate); DebugPrint(EFI_D_ERROR, "i915: \tOffset to DTD buffer for edidless CHILD: 0x%02x\n", child->dtd_buf_ptr); DebugPrint(EFI_D_ERROR, "i915: \tEdidless EFP: %s\n", YESNO(child->edidless_efp)); DebugPrint(EFI_D_ERROR, "i915: \tCompression enable: %s\n", YESNO(child->compression_enable)); @@ -365,12 +381,15 @@ static void dump_child_device(struct context *context, DebugPrint(EFI_D_ERROR, "i915: \tEDID buffer ptr: 0x%02x\n", child->edid_ptr); DebugPrint(EFI_D_ERROR, "i915: \tDVO config: 0x%02x\n", child->dvo_cfg); - if (context->bdb->version < 155) { + if (context->bdb->version < 155) + { DebugPrint(EFI_D_ERROR, "i915: \tDVO2 Port: 0x%02x (%s)\n", child->dvo2_port, dvo_port(child->dvo2_port)); DebugPrint(EFI_D_ERROR, "i915: \tI2C2 pin: 0x%02x\n", child->i2c2_pin); DebugPrint(EFI_D_ERROR, "i915: \tSlave2 address: 0x%02x\n", child->slave2_addr); DebugPrint(EFI_D_ERROR, "i915: \tDDC2 pin: 0x%02x\n", child->ddc2_pin); - } else { + } + else + { DebugPrint(EFI_D_ERROR, "i915: \tEFP routed through dock: %s\n", YESNO(child->efp_routed)); DebugPrint(EFI_D_ERROR, "i915: \tLane reversal: %s\n", YESNO(child->lane_reversal)); DebugPrint(EFI_D_ERROR, "i915: \tOnboard LSPCON: %s\n", YESNO(child->lspcon)); @@ -389,32 +408,37 @@ static void dump_child_device(struct context *context, DebugPrint(EFI_D_ERROR, "i915: \tIntegrated encoder instead of SDVO: %s\n", YESNO(child->integrated_encoder)); DebugPrint(EFI_D_ERROR, "i915: \tDVO wiring: 0x%02x\n", child->dvo_wiring); - if (context->bdb->version < 171) { + if (context->bdb->version < 171) + { DebugPrint(EFI_D_ERROR, "i915: \tDVO2 wiring: 0x%02x\n", child->dvo2_wiring); - } else { + } + else + { DebugPrint(EFI_D_ERROR, "i915: \tMIPI bridge type: %02x (%s)\n", child->mipi_bridge_type, - mipi_bridge_type(child->mipi_bridge_type)); + mipi_bridge_type(child->mipi_bridge_type)); } DebugPrint(EFI_D_ERROR, "i915: \tDevice class extension: 0x%02x\n", child->extended_type); DebugPrint(EFI_D_ERROR, "i915: \tDVO function: 0x%02x\n", child->dvo_function); - if (context->bdb->version >= 195) { + if (context->bdb->version >= 195) + { DebugPrint(EFI_D_ERROR, "i915: \tDP USB type C support: %s\n", YESNO(child->dp_usb_type_c)); DebugPrint(EFI_D_ERROR, "i915: \t2X DP GPIO index: 0x%02x\n", child->dp_gpio_index); DebugPrint(EFI_D_ERROR, "i915: \t2X DP GPIO pin number: 0x%02x\n", child->dp_gpio_pin_num); } - if (context->bdb->version >= 196) { + if (context->bdb->version >= 196) + { DebugPrint(EFI_D_ERROR, "i915: \tIBoost level for HDMI: 0x%02x\n", child->hdmi_iboost_level); DebugPrint(EFI_D_ERROR, "i915: \tIBoost level for DP/eDP: 0x%02x\n", child->dp_iboost_level); } } -#define min(a,b) (((a)<(b))?(a):(b)) -#define max(a,b) (((a)>(b))?(a):(b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) static void dump_child_devices(struct context *context, const UINT8 *devices, - UINT8 child_dev_num, UINT8 child_dev_size) + UINT8 child_dev_num, UINT8 child_dev_size) { struct child_device_config *child; int i; @@ -424,23 +448,27 @@ static void dump_child_devices(struct context *context, const UINT8 *devices, * accessing the struct beyond child_dev_size. The tail, if any, remains * initialized to zero. */ - child = calloc(1, sizeof(*child)); + child = (struct child_device_config *)AllocateZeroPool(sizeof(*child)); + + //child = calloc(1, sizeof(*child)); - for (i = 0; i < child_dev_num; i++) { - memcpy(child, devices + i * child_dev_size, - min(sizeof(*child), child_dev_size)); + for (i = 0; i < child_dev_num; i++) + { + CopyMem(child, devices + i * child_dev_size, + min(sizeof(*child), child_dev_size)); dump_child_device(context, child); } - free(child); + FreePool(child); } static void dumpNull(struct context *context, - const struct bdb_block *block) { - DebugPrint(EFI_D_ERROR, "i915: undefined block \n"); - } + const struct bdb_block *block) +{ + DebugPrint(EFI_D_ERROR, "i915: undefined block \n"); +} static void dump_general_definitions(struct context *context, - const struct bdb_block *block) + const struct bdb_block *block) { const struct bdb_general_definitions *defs = block->data; int child_dev_num; @@ -449,21 +477,21 @@ static void dump_general_definitions(struct context *context, DebugPrint(EFI_D_ERROR, "i915: CRT DDC GMBUS addr: 0x%02x\n", defs->crt_ddc_gmbus_pin); DebugPrint(EFI_D_ERROR, "i915: Use ACPI DPMS CRT power states: %s\n", - YESNO(defs->dpms_acpi)); + YESNO(defs->dpms_acpi)); DebugPrint(EFI_D_ERROR, "i915: Skip CRT detect at boot: %s\n", - YESNO(defs->skip_boot_crt_detect)); + YESNO(defs->skip_boot_crt_detect)); DebugPrint(EFI_D_ERROR, "i915: Use DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim)); DebugPrint(EFI_D_ERROR, "i915: Boot display type: 0x%02x%02x\n", defs->boot_display[1], - defs->boot_display[0]); + defs->boot_display[0]); DebugPrint(EFI_D_ERROR, "i915: Child device size: %d\n", defs->child_dev_size); DebugPrint(EFI_D_ERROR, "i915: Child device count: %d\n", child_dev_num); dump_child_devices(context, defs->devices, - child_dev_num, defs->child_dev_size); + child_dev_num, defs->child_dev_size); } static void dump_legacy_child_devices(struct context *context, - const struct bdb_block *block) + const struct bdb_block *block) { const struct bdb_legacy_child_devices *defs = block->data; int child_dev_num; @@ -474,7 +502,7 @@ static void dump_legacy_child_devices(struct context *context, DebugPrint(EFI_D_ERROR, "i915: Child device count: %d\n", child_dev_num); dump_child_devices(context, defs->devices, - child_dev_num, defs->child_dev_size); + child_dev_num, defs->child_dev_size); } struct dumper dumpers[] = { { @@ -563,8 +591,10 @@ static BOOLEAN dump_section(struct context *context, int section_id) if (!block) return FALSE; - for (i = 0; i < ARRAY_SIZE(dumpers); i++) { - if (block->id == dumpers[i].id) { + for (i = 0; i < ARRAY_SIZE(dumpers); i++) + { + if (block->id == dumpers[i].id) + { dumper = &dumpers[i]; break; } @@ -574,7 +604,7 @@ static BOOLEAN dump_section(struct context *context, int section_id) DebugPrint(EFI_D_ERROR, "BDB block %d - %s:\n", block->id, dumper->name); else DebugPrint(EFI_D_ERROR, "BDB block %d - Unknown, no decoding available:\n", - block->id); + block->id); //if (context->hexdump) // hex_dump_block(block); @@ -582,36 +612,51 @@ static BOOLEAN dump_section(struct context *context, int section_id) dumper->dump(context, block); DebugPrint(EFI_D_ERROR, "\n"); - free(block); + //FreePool (block); return TRUE; } -EFI_STATUS decodeVBT( struct vbt_header *vbt, UINT8 *VBIOS) +EFI_STATUS decodeVBT(struct vbt_header *vbt, int vbt_off, UINT8 *VBIOS) { //UINT8 *VBIOS; -// int index; -// int fd; + // int index; + // int fd; //struct vbt_header *vbt = NULL; - int i; -// const char *filename = NULL; - //int size; + int i, bdb_off; + // const char *filename = NULL; + //int size = 8192; struct context context = { .panel_type = -1, }; -// int block_number = -1; + // int block_number = -1; //BOOLEAN header_only = FALSE, describe = FALSE; + /* Scour memory looking for the VBT signature */ + /* Scour memory looking for the VBT signature */ + // for (i = 0; i + 4 < size; i++) { + // if (!CompareMem (VBIOS + i, "$VBT", 4)) { + // vbt_off = i; + // vbt = (struct vbt_header *)(VBIOS + i); + // DebugPrint(EFI_D_ERROR, "VBT signature Found, sig: %.4s at 0x%04x\n", *(VBIOS + i), i); + // break; + // } else { + // } + // } - /* Scour memory looking for the VBT signature */ - + // if (!vbt) { + // DebugPrint(EFI_D_ERROR, "VBT signature missing\n"); + // // return EXIT_FAILURE; + // } context.vbt = vbt; - context.bdb = (const struct bdb_header *)(vbt + vbt->bdb_offset); - context.size = 8192; + bdb_off = vbt_off + vbt->bdb_offset; -/* if (!context.devid) { + context.bdb = (const struct bdb_header *)(VBIOS + bdb_off); + context.size = 8192; + DebugPrint(EFI_D_ERROR, "i915: vbt: 0x%04x, bdb: 0x%04x, sig: %s, bsig: %s \n", context.vbt, context.bdb, context.vbt->signature, context.bdb->signature); + /* if (!context.devid) { const char *devid_string = getenv("DEVICE"); if (devid_string) context.devid = strtoul(devid_string, NULL, 16); @@ -628,7 +673,7 @@ EFI_STATUS decodeVBT( struct vbt_header *vbt, UINT8 *VBIOS) context.panel_type = 0; } */ -/* if (describe) { + /* if (describe) { print_description(&context); } else if (header_only) { dump_headers(&context); @@ -641,10 +686,10 @@ EFI_STATUS decodeVBT( struct vbt_header *vbt, UINT8 *VBIOS) } else { */ // dump_headers(&context); - /* dump all sections */ - for (i = 0; i < 256; i++) - dump_section(&context, i); -// } + /* dump all sections */ + for (i = 0; i < 256; i++) + dump_section(&context, i); + // } return 0; } \ No newline at end of file diff --git a/intel_opregion.h b/intel_opregion.h index f6249c6..b19cb17 100644 --- a/intel_opregion.h +++ b/intel_opregion.h @@ -30,6 +30,7 @@ #include #include #include +#include #include "QemuFwCfgLib.h" #include "i915_display.h" @@ -1234,4 +1235,4 @@ struct bdb_compression_parameters struct dsc_compression_parameters_entry data[16]; } __packed; -EFI_STATUS decodeVBT( struct vbt_header *vbt, UINT8 *VBIOS); +EFI_STATUS decodeVBT( struct vbt_header *vbt, int vbt_off, UINT8 *VBIOS); From 228dd94a493aad471df33da4e8ae797fe75684f8 Mon Sep 17 00:00:00 2001 From: Patrick Magauran Date: Sun, 29 Nov 2020 23:07:02 -0500 Subject: [PATCH 3/5] Auto display detection! --- i915_controller.h | 355 ++++++++++++++++++++- i915_display.c | 126 ++++++-- i915_display.h | 6 +- i915_dp.c | 10 +- i915_dp.h | 6 +- i915_gmbus.c | 3 +- i915_gmbus.h | 41 +-- i915_gop.h | 6 +- i915_hdmi.c | 94 +++++- i915_hdmi.h | 5 +- i915_reg.h | 32 +- i915ovmf.c | 45 ++- i915ovmf.h | 5 +- intel_opregion.c | 777 ++++++++++++++++++++++++++++------------------ intel_opregion.h | 230 ++++---------- intel_vbt.c | 24 ++ intel_vbt.h | 0 17 files changed, 1215 insertions(+), 550 deletions(-) create mode 100644 intel_vbt.c create mode 100644 intel_vbt.h diff --git a/i915_controller.h b/i915_controller.h index a486c5c..63c814a 100644 --- a/i915_controller.h +++ b/i915_controller.h @@ -1,8 +1,151 @@ #include #include #include +#include "i915_reg.h" +#ifndef INTEL_CONTROLLERH +#define INTEL_CONTROLLERH + +struct opregion_header +{ + UINT8 signature[16]; + UINT32 size; + struct + { + UINT8 rsvd; + UINT8 revision; + UINT8 minor; + UINT8 major; + } __packed over; + UINT8 bios_ver[32]; + UINT8 vbios_ver[16]; + UINT8 driver_ver[16]; + UINT32 mboxes; + UINT32 driver_model; + UINT32 pcon; + UINT8 dver[32]; + UINT8 rsvd[124]; +} __packed; + +/* OpRegion mailbox #1: public ACPI methods */ +struct opregion_acpi +{ + UINT32 drdy; /* driver readiness */ + UINT32 csts; /* notification status */ + UINT32 cevt; /* current event */ + UINT8 rsvd1[20]; + UINT32 didl[8]; /* supported display devices ID list */ + UINT32 cpdl[8]; /* currently presented display list */ + UINT32 cadl[8]; /* currently active display list */ + UINT32 nadl[8]; /* next active devices list */ + UINT32 aslp; /* ASL sleep time-out */ + UINT32 tidx; /* toggle table index */ + UINT32 chpd; /* current hotplug enable indicator */ + UINT32 clid; /* current lid state*/ + UINT32 cdck; /* current docking state */ + UINT32 sxsw; /* Sx state resume */ + UINT32 evts; /* ASL supported events */ + UINT32 cnot; /* current OS notification */ + UINT32 nrdy; /* driver status */ + UINT32 did2[7]; /* extended supported display devices ID list */ + UINT32 cpd2[7]; /* extended attached display devices list */ + UINT8 rsvd2[4]; +} __packed; + +/* OpRegion mailbox #2: SWSCI */ +struct opregion_swsci +{ + UINT32 scic; /* SWSCI command|status|data */ + UINT32 parm; /* command parameters */ + UINT32 dslp; /* driver sleep time-out */ + UINT8 rsvd[244]; +} __packed; + +/* OpRegion mailbox #3: ASLE */ +struct opregion_asle +{ + UINT32 ardy; /* driver readiness */ + UINT32 aslc; /* ASLE interrupt command */ + UINT32 tche; /* technology enabled indicator */ + UINT32 alsi; /* current ALS illuminance reading */ + UINT32 bclp; /* backlight brightness to set */ + UINT32 pfit; /* panel fitting state */ + UINT32 cblv; /* current brightness level */ + UINT16 bclm[20]; /* backlight level duty cycle mapping table */ + UINT32 cpfm; /* current panel fitting mode */ + UINT32 epfm; /* enabled panel fitting modes */ + UINT8 plut[74]; /* panel LUT and identifier */ + UINT32 pfmb; /* PWM freq and min brightness */ + UINT32 cddv; /* color correction default values */ + UINT32 pcft; /* power conservation features */ + UINT32 srot; /* supported rotation angles */ + UINT32 iuer; /* IUER events */ + UINT64 fdss; + UINT32 fdsp; + UINT32 stat; + UINT64 rvda; /* Physical (2.0) or relative from opregion (2.1+) + * address of raw VBT data. */ + UINT32 rvds; /* Size of raw vbt data */ + UINT8 rsvd[58]; +} __packed; + +/* OpRegion mailbox #5: ASLE ext */ +struct opregion_asle_ext +{ + UINT32 phed; /* Panel Header */ + UINT8 bddc[256]; /* Panel EDID */ + UINT8 rsvd[764]; +} __packed; +/** + * struct vbt_header - VBT Header structure + * @signature: VBT signature, always starts with "$VBT" + * @version: Version of this structure + * @header_size: Size of this structure + * @vbt_size: Size of VBT (VBT Header, BDB Header and data blocks) + * @vbt_checksum: Checksum + * @reserved0: Reserved + * @bdb_offset: Offset of &struct bdb_header from beginning of VBT + * @aim_offset: Offsets of add-in data blocks from beginning of VBT + */ +struct vbt_header +{ + UINT8 signature[20]; + UINT16 version; + UINT16 header_size; + UINT16 vbt_size; + UINT8 vbt_checksum; + UINT8 reserved0; + UINT32 bdb_offset; + UINT32 aim_offset[4]; +} __packed; + +/** + * struct bdb_header - BDB Header structure + * @signature: BDB signature "BIOS_DATA_BLOCK" + * @version: Version of the data block definitions + * @header_size: Size of this structure + * @bdb_size: Size of BDB (BDB Header and data blocks) + */ +struct bdb_header +{ + UINT8 signature[16]; + UINT16 version; + UINT16 header_size; + UINT16 bdb_size; +} __packed; +struct intel_opregion +{ + struct opregion_header *header; + struct opregion_acpi *acpi; + struct opregion_swsci *swsci; + struct opregion_asle *asle; + struct vbt_header *vbt; + struct bdb_header *bdb; + struct opregion_asle_ext *asle_ext; + struct child_device_config * children; + UINT8 numChildren; + +}; -#pragma once #pragma pack(1) typedef struct { UINT8 magic[8]; @@ -49,6 +192,213 @@ typedef struct { UINT8 checksum; } EDID; #pragma pack() +/* + * The child device config, aka the display device data structure, provides a + * description of a port and its configuration on the platform. + * + * The child device config size has been increased, and fields have been added + * and their meaning has changed over time. Care must be taken when accessing + * basically any of the fields to ensure the correct interpretation for the BDB + * version in question. + * + * When we copy the child device configs to dev_priv->vbt.child_dev, we reserve + * space for the full structure below, and initialize the tail not actually + * present in VBT to zeros. Accessing those fields is fine, as long as the + * default zero is taken into account, again according to the BDB version. + * + * BDB versions 155 and below are considered legacy, and version 155 seems to be + * a baseline for some of the VBT documentation. When adding new fields, please + * include the BDB version when the field was added, if it's above that. + */ +struct child_device_config +{ + UINT16 handle; + UINT16 device_type; /* See DEVICE_TYPE_* above */ + + union + { + UINT8 device_id[10]; /* ascii string */ + struct + { + UINT8 i2c_speed; + UINT8 dp_onboard_redriver; /* 158 */ + UINT8 dp_ondock_redriver; /* 158 */ + UINT8 hdmi_level_shifter_value : 5; /* 169 */ + UINT8 hdmi_max_data_rate : 3; /* 204 */ + UINT16 dtd_buf_ptr; /* 161 */ + UINT8 edidless_efp : 1; /* 161 */ + UINT8 compression_enable : 1; /* 198 */ + UINT8 compression_method : 1; /* 198 */ + UINT8 ganged_edp : 1; /* 202 */ + UINT8 reserved0 : 4; + UINT8 compression_structure_index : 4; /* 198 */ + UINT8 reserved1 : 4; + UINT8 slave_port; /* 202 */ + UINT8 reserved2; + } __packed; + } __packed; + + UINT16 addin_offset; + UINT8 dvo_port; /* See DEVICE_PORT_* and DVO_PORT_* above */ + UINT8 i2c_pin; + UINT8 slave_addr; + UINT8 ddc_pin; + UINT16 edid_ptr; + UINT8 dvo_cfg; /* See DEVICE_CFG_* above */ + + union + { + struct + { + UINT8 dvo2_port; + UINT8 i2c2_pin; + UINT8 slave2_addr; + UINT8 ddc2_pin; + } __packed; + struct + { + UINT8 efp_routed : 1; /* 158 */ + UINT8 lane_reversal : 1; /* 184 */ + UINT8 lspcon : 1; /* 192 */ + UINT8 iboost : 1; /* 196 */ + UINT8 hpd_invert : 1; /* 196 */ + UINT8 use_vbt_vswing : 1; /* 218 */ + UINT8 flag_reserved : 2; + UINT8 hdmi_support : 1; /* 158 */ + UINT8 dp_support : 1; /* 158 */ + UINT8 tmds_support : 1; /* 158 */ + UINT8 support_reserved : 5; + UINT8 aux_channel; + UINT8 dongle_detect; + } __packed; + } __packed; + + UINT8 pipe_cap : 2; + UINT8 sdvo_stall : 1; /* 158 */ + UINT8 hpd_status : 2; + UINT8 integrated_encoder : 1; + UINT8 capabilities_reserved : 2; + UINT8 dvo_wiring; /* See DEVICE_WIRE_* above */ + + union + { + UINT8 dvo2_wiring; + UINT8 mipi_bridge_type; /* 171 */ + } __packed; + + UINT16 extended_type; + UINT8 dvo_function; + UINT8 dp_usb_type_c : 1; /* 195 */ + UINT8 tbt : 1; /* 209 */ + UINT8 flags2_reserved : 2; /* 195 */ + UINT8 dp_port_trace_length : 4; /* 209 */ + UINT8 dp_gpio_index; /* 195 */ + UINT16 dp_gpio_pin_num; /* 195 */ + UINT8 dp_iboost_level : 4; /* 196 */ + UINT8 hdmi_iboost_level : 4; /* 196 */ + UINT8 dp_max_link_rate : 2; /* 216 CNL+ */ + UINT8 dp_max_link_rate_reserved : 6; /* 216 */ +} __packed; + +struct ddi_vbt_port_info { + /* Non-NULL if port present. */ + const struct child_device_config *child; + + int max_tmds_clock; + + /* This is an index in the HDMI/DVI DDI buffer translation table. */ + u8 hdmi_level_shift; + u8 hdmi_level_shift_set:1; + + u8 supports_dvi:1; + u8 supports_hdmi:1; + u8 supports_dp:1; + u8 supports_edp:1; + u8 supports_typec_usb:1; + u8 supports_tbt:1; + + u8 alternate_aux_channel; + u8 alternate_ddc_pin; + + u8 dp_boost_level; + u8 hdmi_boost_level; + int dp_max_link_rate; /* 0 for not limited by VBT */ + enum port port; + +}; +struct intel_vbt_data { + //struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ + //struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ + + /* Feature bits */ + unsigned int int_tv_support:1; + unsigned int lvds_dither:1; + unsigned int int_crt_support:1; + unsigned int lvds_use_ssc:1; + unsigned int int_lvds_support:1; + unsigned int display_clock_mode:1; + unsigned int fdi_rx_polarity_inverted:1; + unsigned int panel_type:4; + int lvds_ssc_freq; + unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + //enum drm_panel_orientation orientation; + +// enum drrs_support_type drrs_type; + + // struct { + // int rate; + // int lanes; + // int preemphasis; + // int vswing; + // bool low_vswing; + // bool initialized; + // int bpp; + // struct edp_power_seq pps; + // bool hobl; + // } edp; + + // struct { + // bool enable; + // bool full_link; + // bool require_aux_wakeup; + // int idle_frames; + // enum psr_lines_to_wait lines_to_wait; + // int tp1_wakeup_time_us; + // int tp2_tp3_wakeup_time_us; + // int psr2_tp2_tp3_wakeup_time_us; + // } psr; + + // struct { + // u16 pwm_freq_hz; + // bool present; + // bool active_low_pwm; + // u8 min_brightness; /* min_brightness/255 of max */ + // u8 controller; /* brightness controller number */ + // enum intel_backlight_type type; + // } backlight; + + // /* MIPI DSI */ + // struct { + // u16 panel_id; + // struct mipi_config *config; + // struct mipi_pps_data *pps; + // u16 bl_ports; + // u16 cabc_ports; + // u8 seq_version; + // u32 size; + // u8 *data; + // const u8 *sequence[MIPI_SEQ_MAX]; + // u8 *deassert_seq; /* Used by fixup_mipi_sequences() */ + // enum drm_panel_orientation orientation; + // } dsi; + + // int crt_ddc_pin; + + //struct list_head display_devices; + + struct ddi_vbt_port_info ddi_port_info[I915_MAX_PORTS]; + //struct sdvo_device_mapping sdvo_mappings[2]; +}; typedef enum ConnectorTypes {HDMI, DVI, VGA, eDP, DPSST, DPMST} ConnectorType; typedef struct { UINT64 Signature; @@ -76,4 +426,7 @@ typedef struct { UINT32 LinkRate; UINT8 LaneCount; } OutputPath; + struct intel_opregion * opRegion; + struct intel_vbt_data vbt; } i915_CONTROLLER; +#endif \ No newline at end of file diff --git a/i915_display.c b/i915_display.c index 22b216d..5e2c1ec 100644 --- a/i915_display.c +++ b/i915_display.c @@ -2,13 +2,13 @@ #include #include "i915_display.h" - +#include "intel_opregion.h" static i915_CONTROLLER *controller; static EFI_STATUS ReadEDID(EDID *result) { - EFI_STATUS status; - switch (controller->OutputPath.ConType) + EFI_STATUS status = EFI_SUCCESS; + /* switch (controller->OutputPath.ConType) { case HDMI: status = ReadEDIDHDMI(result, controller); @@ -24,7 +24,7 @@ static EFI_STATUS ReadEDID(EDID *result) default: status = EFI_NOT_FOUND; break; - } + } */ DebugPrint(EFI_D_ERROR, "Reading PP_STATUS: %u \n", controller->read32(PP_STATUS)); @@ -308,7 +308,9 @@ EFI_STATUS SetupAndEnablePlane() UINT32 horz_active = controller->edid.detailTimings[DETAIL_TIME_SELCTION].horzActive | ((UINT32)(controller->edid.detailTimings[DETAIL_TIME_SELCTION] - .horzActiveBlankMsb >> 4) << 8); + .horzActiveBlankMsb >> + 4) + << 8); UINT32 vert_active = controller->edid.detailTimings[DETAIL_TIME_SELCTION].vertActive | ((UINT32)(controller->edid.detailTimings[DETAIL_TIME_SELCTION].vertActiveBlankMsb >> 4) << 8); @@ -335,9 +337,87 @@ EFI_STATUS SetupAndEnablePlane() controller->read32(_DSPACNTR), controller->FbBase); return EFI_SUCCESS; } -EFI_STATUS setOutputPath() +static BOOLEAN isCurrentPortPresent(enum port port, UINT32 found) { + switch (port) + { + case PORT_A: + + return controller->read32(DDI_BUF_CTL(PORT_A)) && DDI_INIT_DISPLAY_DETECTED; + case PORT_B: + return found & SFUSE_STRAP_DDIB_DETECTED; + case PORT_C: + return found & SFUSE_STRAP_DDIC_DETECTED; + case PORT_D: + return found & SFUSE_STRAP_DDID_DETECTED; + default: + return false; + } +} +static EFI_STATUS setOutputPath(i915_CONTROLLER *controller, UINT32 found) +{ + EFI_STATUS Status = EFI_SUCCESS; + + if (controller->is_gvt) + { + + EDID *result; + controller->OutputPath.ConType = HDMI; + controller->OutputPath.DPLL = 1; + + controller->OutputPath.Port = PORT_B; + for (int i = 1; i <= 6; i++) + { + Status = ReadEDIDHDMI(result, controller, i); + if (!Status) + { + controller->edid = *result; + return Status; + } + } + return EFI_NOT_FOUND; + } + for (int i = 0; i < controller->opRegion->numChildren; i++) + { + EDID *result; + + struct ddi_vbt_port_info ddi_port_info = controller->vbt.ddi_port_info[i]; + + // UINT32* port = &controller->OutputPath.Port; + if (!isCurrentPortPresent(ddi_port_info.port, found)) + { + continue; + } + if (ddi_port_info.supports_dp || ddi_port_info.supports_edp) + { + Status = ReadEDIDDP(result, controller, intel_bios_port_aux_ch(controller, ddi_port_info.port)); + if (!Status) + { + controller->OutputPath.ConType = ddi_port_info.port == PORT_A ? eDP : DPSST; + controller->OutputPath.DPLL = 1; + controller->edid = *result; + controller->OutputPath.Port = ddi_port_info.port; + DebugPrint(EFI_D_ERROR, "I915: DUsing Connector Mode: %d, On Port %d", controller->OutputPath.ConType, controller->OutputPath.Port); + + return Status; + } + } + if (ddi_port_info.supports_dvi || ddi_port_info.supports_hdmi) + { + Status = ReadEDIDHDMI(result, controller, ddi_port_info.alternate_ddc_pin); + if (!Status) + { + controller->OutputPath.ConType = HDMI; + controller->OutputPath.DPLL = 1; + controller->edid = *result; + + controller->OutputPath.Port = ddi_port_info.port; + DebugPrint(EFI_D_ERROR, "I915: HUsing Connector Mode: %d, On Port %d", controller->OutputPath.ConType, controller->OutputPath.Port); + return Status; + } + } + } /* DDI_BUF_CTL_A bit 0 detects presence of DP for DDIA/eDP SFUSE_STRAP FOR REST @@ -348,11 +428,8 @@ EFI_STATUS setOutputPath() controller->OutputPath.DPLL = 1; controller->OutputPath.Port = PORT_B; */ - controller->OutputPath.ConType = eDP; - controller->OutputPath.DPLL = 1; - controller->OutputPath.Port = PORT_A; - return EFI_SUCCESS; + return Status; } static int cnp_rawclk(i915_CONTROLLER *controller) @@ -379,8 +456,9 @@ static void PrintReg(UINT64 reg, const char *name) // DebugPrint(EFI_D_ERROR, "%a\n", name); DebugPrint(EFI_D_ERROR, "i915: Reg %a(%08x), val: %08x\n", name, reg, controller->read32(reg)); } -static void PrintAllRegs() { - UINT32 port = controller->OutputPath.Port; +static void PrintAllRegs() +{ + UINT32 port = controller->OutputPath.Port; PrintReg(PP_CONTROL, "PP_CONTROL"); PrintReg(_BXT_BLC_PWM_FREQ1, "_BXT_BLC_PWM_FREQ1"); @@ -431,7 +509,6 @@ EFI_STATUS setDisplayGraphicsMode(UINT32 ModeNumber) CHECK_STATUS_ERROR(status); - status = SetupDDIBuffer(); CHECK_STATUS_ERROR(status); @@ -553,7 +630,6 @@ EFI_STATUS setDisplayGraphicsMode(UINT32 ModeNumber) } status = RETURN_ABORTED; - controller->write32(PP_CONTROL, 7); PrintAllRegs(); @@ -565,7 +641,7 @@ EFI_STATUS setDisplayGraphicsMode(UINT32 ModeNumber) return status; } -STATIC UINT8 edid_fallback[] = { + STATIC UINT8 edid_fallback[] = { // generic 1280x720 0, 255, 255, 255, 255, 255, 255, 0, 34, 240, 84, 41, 1, 0, 0, 0, 4, 23, 1, 4, 165, 52, 32, 120, 35, 252, 129, 164, 85, 77, @@ -578,7 +654,7 @@ STATIC UINT8 edid_fallback[] = { 50, 48, 112, 10, 32, 32, 0, 161 // the test monitor // 0,255,255,255,255,255,255,0,6,179,192,39,141,30,0,0,49,26,1,3,128,60,34,120,42,83,165,167,86,82,156,38,17,80,84,191,239,0,209,192,179,0,149,0,129,128,129,64,129,192,113,79,1,1,2,58,128,24,113,56,45,64,88,44,69,0,86,80,33,0,0,30,0,0,0,255,0,71,67,76,77,84,74,48,48,55,56,50,49,10,0,0,0,253,0,50,75,24,83,17,0,10,32,32,32,32,32,32,0,0,0,252,0,65,83,85,83,32,86,90,50,55,57,10,32,32,1,153,2,3,34,113,79,1,2,3,17,18,19,4,20,5,14,15,29,30,31,144,35,9,23,7,131,1,0,0,101,3,12,0,32,0,140,10,208,138,32,224,45,16,16,62,150,0,86,80,33,0,0,24,1,29,0,114,81,208,30,32,110,40,85,0,86,80,33,0,0,30,1,29,0,188,82,208,30,32,184,40,85,64,86,80,33,0,0,30,140,10,208,144,32,64,49,32,12,64,85,0,86,80,33,0,0,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,237 -}; +}; EFI_STATUS SetupPPS() { @@ -588,7 +664,6 @@ EFI_STATUS SetupPPS() controller->write32(_BXT_BLC_PWM_FREQ1, max); controller->write32(_BXT_BLC_PWM_DUTY1, max); -\ UINT32 val = controller->read32(BKL_GRAN_CTL); val |= 1; controller->write32(BKL_GRAN_CTL, val); @@ -603,7 +678,6 @@ EFI_STATUS DisplayInit(i915_CONTROLLER *iController) EFI_STATUS Status; controller = iController; - setOutputPath(); /* 1. Enable PCH reset handshake. */ // intel_pch_reset_handshake(dev_priv, !HAS_PCH_NOP(dev_priv)); controller->write32(HSW_NDE_RSTWRN_OPT, @@ -710,6 +784,11 @@ EFI_STATUS DisplayInit(i915_CONTROLLER *iController) // intel_ddi_init(PORT_A); UINT32 found = controller->read32(SFUSE_STRAP); DebugPrint(EFI_D_ERROR, "i915: SFUSE_STRAP = %08x\n", found); + Status = setOutputPath(controller, found); + if (EFI_ERROR(Status)) + { + DebugPrint(EFI_D_ERROR, "i915: failed to Set OutputPath\n"); + } // UINT32* port = &controller->OutputPath.Port; /* UINT32* port = &(controller->OutputPath.Port); @@ -738,14 +817,17 @@ EFI_STATUS DisplayInit(i915_CONTROLLER *iController) // it somehow fails on real hardware // Verified functional on i7-10710U Status = ReadEDID(&controller->edid); - if (EFI_ERROR(Status)) - { - DebugPrint(EFI_D_ERROR, "i915: failed to read EDID\n"); - for (UINT32 i = 0; i < 128; i++) + if (*(UINT64 *)controller->edid.magic != 0x00FFFFFFFFFFFF00uLL) { +for (UINT32 i = 0; i < 128; i++) { ((UINT8 *)&controller->edid)[i] = edid_fallback[i]; } } + /* if (EFI_ERROR(Status)) + { + DebugPrint(EFI_D_ERROR, "i915: failed to read EDID\n"); + + } */ DebugPrint(EFI_D_ERROR, "i915: got EDID:\n"); for (UINT32 i = 0; i < 16; i++) { diff --git a/i915_display.h b/i915_display.h index 971a4f0..1b1595c 100644 --- a/i915_display.h +++ b/i915_display.h @@ -1,5 +1,6 @@ #pragma once - +#ifndef i915_DISPLAYH +#define i915_DISPLAYH #include #include "i915_controller.h" #include @@ -409,4 +410,5 @@ EFI_STATUS DisplayInit(i915_CONTROLLER *iController); EFI_STATUS setDisplayGraphicsMode( UINT32 ModeNumber ); -EFI_STATUS TrainDisplayPort(i915_CONTROLLER* controller); \ No newline at end of file +EFI_STATUS TrainDisplayPort(i915_CONTROLLER* controller); +#endif \ No newline at end of file diff --git a/i915_dp.c b/i915_dp.c index 50eff3a..fb1869b 100644 --- a/i915_dp.c +++ b/i915_dp.c @@ -29,13 +29,11 @@ #define PP_REFERENCE_DIVIDER_SHIFT 8 #define PANEL_POWER_CYCLE_DELAY_MASK (0x1f) #define PANEL_POWER_CYCLE_DELAY_SHIFT 0 -EFI_STATUS ReadEDIDDP(EDID *result, i915_CONTROLLER* controller) { - UINT32 pin = 0; +EFI_STATUS ReadEDIDDP(EDID *result, i915_CONTROLLER* controller, UINT8 pin) { UINT32 *p = (UINT32 *)result; - for (pin = 0; pin <= 5; pin++) - { + DebugPrint(EFI_D_ERROR, "i915: trying DP aux %d\n", pin); // aux message header is 3-4 bytes: ctrl8 addr16 len8 // the data is big endian @@ -105,7 +103,7 @@ EFI_STATUS ReadEDIDDP(EDID *result, i915_CONTROLLER* controller) { if (aux_status & (DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_RECEIVE_ERROR)) { - continue; + return EFI_NOT_FOUND; } // i2c read 1 byte * 128 DebugPrint(EFI_D_ERROR, "i915: reading DP aux %d\n", pin); @@ -189,7 +187,7 @@ EFI_STATUS ReadEDIDDP(EDID *result, i915_CONTROLLER* controller) { controller->OutputPath.AuxCh = pin; return EFI_SUCCESS; } - } + return EFI_NOT_FOUND; } diff --git a/i915_dp.h b/i915_dp.h index aed718d..07ae27c 100644 --- a/i915_dp.h +++ b/i915_dp.h @@ -1,4 +1,5 @@ - +#ifndef i915_DPH +#define i915_DPH #define PP_ON (0xC7208) #define PP_OFF (0xC720C) #define PP_DIVISOR 0x61210 /* Cedartrail */ @@ -1361,4 +1362,5 @@ EFI_STATUS SetupDDIBufferDP(i915_CONTROLLER* controller); EFI_STATUS SetupTranscoderAndPipeEDP(i915_CONTROLLER* controller); EFI_STATUS SetupTranscoderAndPipeDP(i915_CONTROLLER* controller); void intel_dp_pps_init(i915_CONTROLLER* controller); -EFI_STATUS ReadEDIDDP(EDID *result, i915_CONTROLLER* controller); \ No newline at end of file +EFI_STATUS ReadEDIDDP(EDID *result, i915_CONTROLLER* controller, UINT8 pin); +#endif \ No newline at end of file diff --git a/i915_gmbus.c b/i915_gmbus.c index e0c1223..d091b9d 100644 --- a/i915_gmbus.c +++ b/i915_gmbus.c @@ -4,6 +4,7 @@ EFI_STATUS gmbusWait(i915_CONTROLLER *controller, UINT32 wanted) { UINTN counter = 0; + for (;;) { UINT32 status = controller->read32(gmbusStatus); counter += 1; @@ -14,7 +15,7 @@ EFI_STATUS gmbusWait(i915_CONTROLLER *controller, UINT32 wanted) { } if (status & GMBUS_SATOER) { //failed - DebugPrint(EFI_D_ERROR, "i915: gmbus error\n"); + DebugPrint(EFI_D_ERROR, "i915: gmbus error on %d\n", wanted); return EFI_DEVICE_ERROR; } if (status & wanted) { diff --git a/i915_gmbus.h b/i915_gmbus.h index 1b02f95..84668bf 100644 --- a/i915_gmbus.h +++ b/i915_gmbus.h @@ -1,3 +1,5 @@ +#ifndef i915_GMBUSH +#define i915_GMBUSH #include "i915_reg.h" #include "i915_controller.h" @@ -10,23 +12,25 @@ #define GMBUS_RATE_1MHZ (3 << 8) /* reserved on Pineview */ #define GMBUS_HOLD_EXT (1 << 7) /* 300ns hold time, rsvd on Pineview */ #define GMBUS_BYTE_CNT_OVERRIDE (1 << 6) -#define GMBUS_PIN_DISABLED 0 -#define GMBUS_PIN_SSC 1 -#define GMBUS_PIN_VGADDC 2 -#define GMBUS_PIN_PANEL 3 -#define GMBUS_PIN_DPD_CHV 3 /* HDMID_CHV */ -#define GMBUS_PIN_DPC 4 /* HDMIC */ -#define GMBUS_PIN_DPB 5 /* SDVO, HDMIB */ -#define GMBUS_PIN_DPD 6 /* HDMID */ -#define GMBUS_PIN_RESERVED 7 /* 7 reserved */ -#define GMBUS_PIN_1_BXT 1 /* BXT+ (atom) and CNP+ (big core) */ -#define GMBUS_PIN_2_BXT 2 -#define GMBUS_PIN_3_BXT 3 -#define GMBUS_PIN_4_CNP 4 -#define GMBUS_PIN_9_TC1_ICP 9 -#define GMBUS_PIN_10_TC2_ICP 10 -#define GMBUS_PIN_11_TC3_ICP 11 -#define GMBUS_PIN_12_TC4_ICP 12 +#define GMBUS_PIN_DISABLED 0 +#define GMBUS_PIN_SSC 1 +#define GMBUS_PIN_VGADDC 2 +#define GMBUS_PIN_PANEL 3 +#define GMBUS_PIN_DPD_CHV 3 /* HDMID_CHV */ +#define GMBUS_PIN_DPC 4 /* HDMIC */ +#define GMBUS_PIN_DPB 5 /* SDVO, HDMIB */ +#define GMBUS_PIN_DPD 6 /* HDMID */ +#define GMBUS_PIN_RESERVED 7 /* 7 reserved */ +#define GMBUS_PIN_1_BXT 1 /* BXT+ (atom) and CNP+ (big core) */ +#define GMBUS_PIN_2_BXT 2 +#define GMBUS_PIN_3_BXT 3 +#define GMBUS_PIN_4_CNP 4 +#define GMBUS_PIN_9_TC1_ICP 9 +#define GMBUS_PIN_10_TC2_ICP 10 +#define GMBUS_PIN_11_TC3_ICP 11 +#define GMBUS_PIN_12_TC4_ICP 12 +#define GMBUS_PIN_13_TC5_TGP 13 +#define GMBUS_PIN_14_TC6_TGP 14 #define gmbusCommand (PCH_DISPLAY_BASE+0x5104) #define GMBUS_SW_CLR_INT (1 << 31) @@ -56,4 +60,5 @@ #define gmbusData (PCH_DISPLAY_BASE+0x510C) #define GMBUS4 (PCH_DISPLAY_BASE+0x5110) -EFI_STATUS gmbusWait(i915_CONTROLLER *, UINT32); \ No newline at end of file +EFI_STATUS gmbusWait(i915_CONTROLLER *, UINT32); +#endif \ No newline at end of file diff --git a/i915_gop.h b/i915_gop.h index e19d98c..2b16037 100644 --- a/i915_gop.h +++ b/i915_gop.h @@ -1,5 +1,6 @@ #pragma once - +#ifndef i915_GOPH +#define i915_GOPH #include #include "i915_display.h" #include @@ -10,4 +11,5 @@ EFI_STATUS i915GraphicsFramebufferConfigure(i915_CONTROLLER *controller); -EFI_STATUS i915GraphicsSetupOutput(EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, UINT32 x_active, UINT32 y_active); \ No newline at end of file +EFI_STATUS i915GraphicsSetupOutput(EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput, UINT32 x_active, UINT32 y_active); +#endif \ No newline at end of file diff --git a/i915_hdmi.c b/i915_hdmi.c index ad3afe4..f9e7623 100644 --- a/i915_hdmi.c +++ b/i915_hdmi.c @@ -6,18 +6,65 @@ #include "i915_hdmi.h" #include "i915_reg.h" #include -EFI_STATUS ReadEDIDHDMI(EDID *result, i915_CONTROLLER* controller) { - UINT32 pin = 0; +static int intel_hdmi_source_max_tmds_clock() +{ + // struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + int max_tmds_clock; + //, vbt_max_tmds_clock; + + // if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + // max_tmds_clock = 594000; + // else if (INTEL_GEN(dev_priv) >= 8 || IS_HASWELL(dev_priv)) + max_tmds_clock = 300000; + // else if (INTEL_GEN(dev_priv) >= 5) + // max_tmds_clock = 225000; + // else + // max_tmds_clock = 165000; + + // vbt_max_tmds_clock = intel_bios_max_tmds_clock(encoder); + // if (vbt_max_tmds_clock) + // max_tmds_clock = min(max_tmds_clock, vbt_max_tmds_clock); + + return max_tmds_clock; +} +static int hdmi_port_clock_limit() +{ + //struct intel_encoder *encoder = &hdmi_to_dig_port(hdmi)->base; + int max_tmds_clock = intel_hdmi_source_max_tmds_clock(); + + return max_tmds_clock; +} +INT32 intel_hdmi_link_required(int pixel_clock, int bpp) +{ + /* pixel_clock is in kHz, divide bpp by 8 for bit to Byte conversion */ + return DIV_ROUND_UP(pixel_clock * bpp, 8); +} +static BOOLEAN intel_hdmi_valid_link_rate(UINT32 pixelClock) +{ + /* const struct drm_display_mode *fixed_mode = + intel_dp->attached_connector->panel.fixed_mode; */ + int mode_rate, max_rate; + + mode_rate = intel_hdmi_link_required(pixelClock * 10, 8); + max_rate = hdmi_port_clock_limit(); + DebugPrint(EFI_D_ERROR, "Mode: %u, Max:%u\n", mode_rate, max_rate); + if (mode_rate > max_rate) + return FALSE; + + return TRUE; +} +EFI_STATUS ReadEDIDHDMI(EDID *result, i915_CONTROLLER *controller, UINT8 pin) +{ // it's an INTEL GPU, there's no way we could be big endian UINT32 *p = (UINT32 *)result; // try all the pins on GMBUS - for (pin = 1; pin <= 6; pin++) { DebugPrint(EFI_D_ERROR, "i915: trying pin %d\n", pin); controller->write32(gmbusSelect, pin); if (EFI_ERROR(gmbusWait(controller, GMBUS_HW_RDY))) { - continue; + + return EFI_NOT_FOUND; } // set read offset: i2cWrite(0x50, &offset, 1); controller->write32(gmbusData, 0); @@ -27,6 +74,8 @@ EFI_STATUS ReadEDIDHDMI(EDID *result, i915_CONTROLLER* controller) { GMBUS_SW_RDY); // gmbusWait(controller,GMBUS_HW_WAIT_PHASE); gmbusWait(controller, GMBUS_HW_RDY); + DebugPrint(EFI_D_ERROR, "i915: trying pin %d\n", pin); + // read the edid: i2cRead(0x50, &edid, 128); // note that we could fail here! controller->write32(gmbusCommand, (0x50 << GMBUS_SLAVE_ADDR_SHIFT) | @@ -38,12 +87,16 @@ EFI_STATUS ReadEDIDHDMI(EDID *result, i915_CONTROLLER* controller) { { if (EFI_ERROR(gmbusWait(controller, GMBUS_HW_RDY))) { + DebugPrint(EFI_D_ERROR, "i915: trying pin %d\n", pin); + break; } p[i >> 2] = controller->read32(gmbusData); } // gmbusWait(controller,GMBUS_HW_WAIT_PHASE); gmbusWait(controller, GMBUS_HW_RDY); + DebugPrint(EFI_D_ERROR, "i915: trying pin %d\n", pin); + for (UINT32 i = 0; i < 16; i++) { for (UINT32 j = 0; j < 8; j++) @@ -54,6 +107,32 @@ EFI_STATUS ReadEDIDHDMI(EDID *result, i915_CONTROLLER* controller) { } if (i >= 128 && *(UINT64 *)result->magic == 0x00FFFFFFFFFFFF00uLL) { + if (!intel_hdmi_valid_link_rate(result->detailTimings[DETAIL_TIME_SELCTION].pixelClock)) + { + for (int j = 0; j < 4; j++) + { + if (result->detailTimings[j].pixelClock > 0 && intel_hdmi_valid_link_rate(result->detailTimings[j].pixelClock)) + { + result->detailTimings[DETAIL_TIME_SELCTION] = result->detailTimings[j]; + return EFI_SUCCESS; + } + } + DebugPrint(EFI_D_ERROR, "pixelClock: %d\n", result->detailTimings[DETAIL_TIME_SELCTION].pixelClock); + + for (int j = 0; j < 4; j++) + { + if (result->detailTimings[j].pixelClock >> 1 > 0 && intel_hdmi_valid_link_rate(result->detailTimings[j].pixelClock >> 1)) + { + result->detailTimings[j].pixelClock = result->detailTimings[j].pixelClock >> 1; + result->detailTimings[DETAIL_TIME_SELCTION] = result->detailTimings[j]; + return EFI_SUCCESS; + } + } + DebugPrint(EFI_D_ERROR, "pixelClock: %d\n", result->detailTimings[DETAIL_TIME_SELCTION].pixelClock); + } + // if (result->detailTimings[DETAIL_TIME_SELCTION].pixelClock > 3) { + // result->detailTimings[DETAIL_TIME_SELCTION].pixelClock >> 1; + // } return EFI_SUCCESS; } } @@ -234,7 +313,8 @@ static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, } } -EFI_STATUS SetupClockHDMI(i915_CONTROLLER* controller) { +EFI_STATUS SetupClockHDMI(i915_CONTROLLER *controller) +{ UINT32 ctrl1, cfgcr1, cfgcr2; struct skl_wrpll_params wrpll_params = { @@ -245,7 +325,7 @@ EFI_STATUS SetupClockHDMI(i915_CONTROLLER* controller) { * See comment in intel_dpll_hw_state to understand why we always use 0 * as the DPLL id in this function. Basically, we put them in the first 6 bits then shift them into place for easier comparison */ - ctrl1 = DPLL_CTRL1_OVERRIDE(0); //Enable Programming + ctrl1 = DPLL_CTRL1_OVERRIDE(0); //Enable Programming ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); //Set Mode to HDMI { @@ -392,7 +472,7 @@ EFI_STATUS SetupClockHDMI(i915_CONTROLLER* controller) { DebugPrint(EFI_D_ERROR, "i915: DPLL_CTRL2 = %08x\n", controller->read32(DPLL_CTRL2)); return EFI_SUCCESS; } -EFI_STATUS SetupTranscoderAndPipeHDMI(i915_CONTROLLER* controller) +EFI_STATUS SetupTranscoderAndPipeHDMI(i915_CONTROLLER *controller) { UINT32 horz_active = controller->edid.detailTimings[DETAIL_TIME_SELCTION].horzActive | ((UINT32)(controller->edid.detailTimings[DETAIL_TIME_SELCTION].horzActiveBlankMsb >> 4) << 8); diff --git a/i915_hdmi.h b/i915_hdmi.h index d841f0d..5e81b49 100644 --- a/i915_hdmi.h +++ b/i915_hdmi.h @@ -1,3 +1,5 @@ +#ifndef i915_HDMIH +#define i915_HDMIH #define DPLL_CTRL1_HDMI_MODE(id) (1 << ((id) * 6 + 5)) #define _DPLL1_CFGCR1 0x6C040 #define _DPLL2_CFGCR1 0x6C048 @@ -61,4 +63,5 @@ struct skl_wrpll_context { }; EFI_STATUS SetupClockHDMI(i915_CONTROLLER* controller); EFI_STATUS SetupTranscoderAndPipeHDMI(i915_CONTROLLER* controller); -EFI_STATUS ReadEDIDHDMI(EDID *result, i915_CONTROLLER* controller); \ No newline at end of file +EFI_STATUS ReadEDIDHDMI(EDID *result, i915_CONTROLLER* controller, UINT8 pin); +#endif \ No newline at end of file diff --git a/i915_reg.h b/i915_reg.h index 5d1b648..5e35501 100644 --- a/i915_reg.h +++ b/i915_reg.h @@ -1,3 +1,5 @@ +#ifndef i915_REGH +#define i915_REGH #define PCH_DISPLAY_BASE 0xc0000u #define DETAIL_TIME_SELCTION 0 #define DPLL_CTRL1 (0x6C058) @@ -137,4 +139,32 @@ #define VSYNCSHIFT_EDP 0x6f028 #define SFUSE_STRAP 0xc2014 #define SFUSE_STRAP_FUSE_LOCK (1 << 13) -#define SFUSE_STRAP_RAW_FREQUENCY (1 << 8) \ No newline at end of file +#define SFUSE_STRAP_RAW_FREQUENCY (1 << 8) +enum port { + PORT_NONE = -1, + + PORT_A = 0, + PORT_B, + PORT_C, + PORT_D, + PORT_E, + PORT_F, + PORT_G, + PORT_H, + PORT_I, + + I915_MAX_PORTS +}; + +typedef UINT8 u8; +typedef UINT16 u16; + +typedef UINT32 u32; +typedef UINT64 u64; +typedef BOOLEAN bool; +#define true TRUE +#define false FALSE +#define __packed __attribute__((packed)) + + +#endif \ No newline at end of file diff --git a/i915ovmf.c b/i915ovmf.c index 3173e79..7021ec9 100755 --- a/i915ovmf.c +++ b/i915ovmf.c @@ -287,7 +287,9 @@ SetupOpRegion(IN EFI_PCI_IO_PROTOCOL *PciIo, OpRegion.header=(struct opregion_header *) BytePointer; OpRegion.vbt =(struct vbt_header *) (BytePointer + 1024); - Status = decodeVBT(OpRegion.vbt, 1024, BytePointer); + Status = decodeVBT(&OpRegion, 1024); + + g_private.opRegion = &OpRegion; if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR, "%a: %a: failed to decode OpRegion: %r\n", __FUNCTION__, GetPciName(PciInfo), Status)); @@ -527,6 +529,35 @@ EFI_STATUS EFIAPI i915ControllerDriverStart( g_private.read32 = read32; g_private.read64 = read64; + + + + // setup OpRegion from fw_cfg (IgdAssignmentDxe) + DebugPrint(EFI_D_ERROR, "i915: before QEMU shenanigans\n"); + + QemuFwCfgInitialize(); + + if ( + + QemuFwCfgIsAvailable() + + ) { + // setup opregion + Status = SetupFwcfgStuff(Private->PciIo); + DebugPrint(EFI_D_ERROR, "i915: SetupFwcfgStuff returns %d\n", Status); + } + DebugPrint(EFI_D_ERROR, "i915: after QEMU shenanigans\n"); + + parse_ddi_ports(&g_private, 228); //TODO Dyn bdb Version + + g_private.gmadr = 0; + g_private.is_gvt = 0; + if (read64(0x78000) == 0x4776544776544776ULL) { + DebugPrint(EFI_D_ERROR, "GVT-G Enabled\n"); + g_private.gmadr = read32(0x78040); + g_private.is_gvt = 1; + // apertureSize=read32(0x78044); + } // BEGIN IG AND DISPLAY CONFIG DisplayInit(&g_private); @@ -552,13 +583,7 @@ EFI_STATUS EFIAPI i915ControllerDriverStart( // (Private->PciIo,EfiPciIoWidthUint32,0x18,1,&bar_work); // DebugPrint(EFI_D_ERROR,"i915: aperture confirmed at %016x\n",bar_work); // GVT-g gmadr issue - g_private.gmadr = 0; - g_private.is_gvt = 0; - if (read64(0x78000) == 0x4776544776544776ULL) { - g_private.gmadr = read32(0x78040); - g_private.is_gvt = 1; - // apertureSize=read32(0x78044); - } + DebugPrint(EFI_D_ERROR, "i915: gmadr = %08x, size = %08x, hgmadr = %08x, hsize = %08x\n", g_private.gmadr, read32(0x78044), read32(0x78048), @@ -608,7 +633,7 @@ EFI_STATUS EFIAPI i915ControllerDriverStart( ((UINT32)(addr >> 32) & 0x7F0u) | ((UINT32)addr & 0xFFFFF000u) | 11; } - // setup OpRegion from fw_cfg (IgdAssignmentDxe) +/* // setup OpRegion from fw_cfg (IgdAssignmentDxe) DebugPrint(EFI_D_ERROR, "i915: before QEMU shenanigans\n"); QemuFwCfgInitialize(); @@ -622,7 +647,7 @@ EFI_STATUS EFIAPI i915ControllerDriverStart( Status = SetupFwcfgStuff(Private->PciIo); DebugPrint(EFI_D_ERROR, "i915: SetupFwcfgStuff returns %d\n", Status); } - DebugPrint(EFI_D_ERROR, "i915: after QEMU shenanigans\n"); + DebugPrint(EFI_D_ERROR, "i915: after QEMU shenanigans\n"); */ // TODO: turn on backlight if found in OpRegion, need eDP initialization // first... diff --git a/i915ovmf.h b/i915ovmf.h index 6b07c17..2e01243 100644 --- a/i915ovmf.h +++ b/i915ovmf.h @@ -1,3 +1,5 @@ +#ifndef i915_OVMFH +#define i915_OVMFH #include "i915_reg.h" //registers are in bar 0 //frame buffer is in bar 2 @@ -9,4 +11,5 @@ #define I915_READ read32 -#define I915_WRITE write32 \ No newline at end of file +#define I915_WRITE write32 +#endif \ No newline at end of file diff --git a/intel_opregion.c b/intel_opregion.c index 6900957..cdc65f8 100644 --- a/intel_opregion.c +++ b/intel_opregion.c @@ -5,114 +5,6 @@ //#include //#include -/* - * The child device config, aka the display device data structure, provides a - * description of a port and its configuration on the platform. - * - * The child device config size has been increased, and fields have been added - * and their meaning has changed over time. Care must be taken when accessing - * basically any of the fields to ensure the correct interpretation for the BDB - * version in question. - * - * When we copy the child device configs to dev_priv->vbt.child_dev, we reserve - * space for the full structure below, and initialize the tail not actually - * present in VBT to zeros. Accessing those fields is fine, as long as the - * default zero is taken into account, again according to the BDB version. - * - * BDB versions 155 and below are considered legacy, and version 155 seems to be - * a baseline for some of the VBT documentation. When adding new fields, please - * include the BDB version when the field was added, if it's above that. - */ -struct child_device_config -{ - UINT16 handle; - UINT16 device_type; /* See DEVICE_TYPE_* above */ - - union - { - UINT8 device_id[10]; /* ascii string */ - struct - { - UINT8 i2c_speed; - UINT8 dp_onboard_redriver; /* 158 */ - UINT8 dp_ondock_redriver; /* 158 */ - UINT8 hdmi_level_shifter_value : 5; /* 169 */ - UINT8 hdmi_max_data_rate : 3; /* 204 */ - UINT16 dtd_buf_ptr; /* 161 */ - UINT8 edidless_efp : 1; /* 161 */ - UINT8 compression_enable : 1; /* 198 */ - UINT8 compression_method : 1; /* 198 */ - UINT8 ganged_edp : 1; /* 202 */ - UINT8 reserved0 : 4; - UINT8 compression_structure_index : 4; /* 198 */ - UINT8 reserved1 : 4; - UINT8 slave_port; /* 202 */ - UINT8 reserved2; - } __packed; - } __packed; - - UINT16 addin_offset; - UINT8 dvo_port; /* See DEVICE_PORT_* and DVO_PORT_* above */ - UINT8 i2c_pin; - UINT8 slave_addr; - UINT8 ddc_pin; - UINT16 edid_ptr; - UINT8 dvo_cfg; /* See DEVICE_CFG_* above */ - - union - { - struct - { - UINT8 dvo2_port; - UINT8 i2c2_pin; - UINT8 slave2_addr; - UINT8 ddc2_pin; - } __packed; - struct - { - UINT8 efp_routed : 1; /* 158 */ - UINT8 lane_reversal : 1; /* 184 */ - UINT8 lspcon : 1; /* 192 */ - UINT8 iboost : 1; /* 196 */ - UINT8 hpd_invert : 1; /* 196 */ - UINT8 use_vbt_vswing : 1; /* 218 */ - UINT8 flag_reserved : 2; - UINT8 hdmi_support : 1; /* 158 */ - UINT8 dp_support : 1; /* 158 */ - UINT8 tmds_support : 1; /* 158 */ - UINT8 support_reserved : 5; - UINT8 aux_channel; - UINT8 dongle_detect; - } __packed; - } __packed; - - UINT8 pipe_cap : 2; - UINT8 sdvo_stall : 1; /* 158 */ - UINT8 hpd_status : 2; - UINT8 integrated_encoder : 1; - UINT8 capabilities_reserved : 2; - UINT8 dvo_wiring; /* See DEVICE_WIRE_* above */ - - union - { - UINT8 dvo2_wiring; - UINT8 mipi_bridge_type; /* 171 */ - } __packed; - - UINT16 extended_type; - UINT8 dvo_function; - UINT8 dp_usb_type_c : 1; /* 195 */ - UINT8 tbt : 1; /* 209 */ - UINT8 flags2_reserved : 2; /* 195 */ - UINT8 dp_port_trace_length : 4; /* 209 */ - UINT8 dp_gpio_index; /* 195 */ - UINT16 dp_gpio_pin_num; /* 195 */ - UINT8 dp_iboost_level : 4; /* 196 */ - UINT8 hdmi_iboost_level : 4; /* 196 */ - UINT8 dp_max_link_rate : 2; /* 216 CNL+ */ - UINT8 dp_max_link_rate_reserved : 6; /* 216 */ -} __packed; - /* Get BDB block size given a pointer to Block ID. */ static UINT32 _get_blocksize(const UINT8 *block_base) { @@ -123,11 +15,10 @@ static UINT32 _get_blocksize(const UINT8 *block_base) return *((const UINT16 *)(block_base + 1)); } -static struct bdb_block *find_section(struct context *context, int section_id) +static EFI_STATUS find_section(struct context *context, int section_id, struct bdb_block *block) { const struct bdb_header *bdb = context->bdb; int length = context->size; - struct bdb_block *block; const UINT8 *base = (const UINT8 *)bdb; int index = 0; UINT32 total, current_size; @@ -150,11 +41,10 @@ static struct bdb_block *find_section(struct context *context, int section_id) //DebugPrint(EFI_D_ERROR, "i915: current id %d; index: %d; location 0x%04x; current_size: %d\n", current_id, index, (base + index), current_size); if (index + current_size > total) - return NULL; + return EFI_NOT_FOUND; if (current_id == section_id) { - block = (struct bdb_block *)AllocatePool(sizeof(block)); if (!block) { DebugPrint(EFI_D_ERROR, "i915: out of memory"); @@ -164,14 +54,13 @@ static struct bdb_block *find_section(struct context *context, int section_id) block->id = current_id; block->size = current_size; block->data = base + index; - return block; + return EFI_SUCCESS; } index += current_size; } - FreePool(block); - return NULL; + return EFI_NOT_FOUND; } static const char *dvo_port_names[] = { [DVO_PORT_HDMIA] = "HDMI-A", @@ -342,7 +231,7 @@ static const char *mipi_bridge_type(UINT8 type) static void dump_child_device(struct context *context, const struct child_device_config *child) { - if (!child->device_type) + //if (!child->device_type) return; DebugPrint(EFI_D_ERROR, "i915: Child device info:\n"); @@ -437,10 +326,11 @@ static void dump_child_device(struct context *context, #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) -static void dump_child_devices(struct context *context, const UINT8 *devices, - UINT8 child_dev_num, UINT8 child_dev_size) +static EFI_STATUS get_child_devices(struct context *context, const UINT8 *devices, + UINT8 child_dev_num, UINT8 child_dev_size) { struct child_device_config *child; + struct child_device_config * children = (struct child_device_config *)AllocateZeroPool(child_dev_num * sizeof(*child)); int i; /* @@ -456,240 +346,511 @@ static void dump_child_devices(struct context *context, const UINT8 *devices, { CopyMem(child, devices + i * child_dev_size, min(sizeof(*child), child_dev_size)); - - dump_child_device(context, child); + children[i] = *child; + //dump_child_device(context, child); } - + context->children = children; + context->numChildren = child_dev_num; FreePool(child); + return EFI_SUCCESS; } -static void dumpNull(struct context *context, - const struct bdb_block *block) -{ - DebugPrint(EFI_D_ERROR, "i915: undefined block \n"); -} -static void dump_general_definitions(struct context *context, - const struct bdb_block *block) + +static EFI_STATUS decode_vbt_child_blocks(struct context *context, + const struct bdb_block *block) { + EFI_STATUS status = EFI_SUCCESS; const struct bdb_general_definitions *defs = block->data; int child_dev_num; child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size; - + /* DebugPrint(EFI_D_ERROR, "i915: CRT DDC GMBUS addr: 0x%02x\n", defs->crt_ddc_gmbus_pin); DebugPrint(EFI_D_ERROR, "i915: Use ACPI DPMS CRT power states: %s\n", YESNO(defs->dpms_acpi)); DebugPrint(EFI_D_ERROR, "i915: Skip CRT detect at boot: %s\n", YESNO(defs->skip_boot_crt_detect)); - DebugPrint(EFI_D_ERROR, "i915: Use DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim)); - DebugPrint(EFI_D_ERROR, "i915: Boot display type: 0x%02x%02x\n", defs->boot_display[1], - defs->boot_display[0]); + DebugPrint(EFI_D_ERROR, "i915: Use DPMS on AIM devices: %s\n", YESNO(defs->dpms_aim)); */ + if (block->id == BDB_GENERAL_DEFINITIONS) + { + DebugPrint(EFI_D_ERROR, "i915: Boot display type: 0x%02x%02x\n", defs->boot_display[1], + defs->boot_display[0]); + } DebugPrint(EFI_D_ERROR, "i915: Child device size: %d\n", defs->child_dev_size); DebugPrint(EFI_D_ERROR, "i915: Child device count: %d\n", child_dev_num); - dump_child_devices(context, defs->devices, - child_dev_num, defs->child_dev_size); + status = get_child_devices(context, defs->devices, + child_dev_num, defs->child_dev_size); + int i; + + for (i = 0; i < child_dev_num; i++) + { + + //children[i] = *child; + dump_child_device(context, &(context->children[i])); + } + return status; } -static void dump_legacy_child_devices(struct context *context, - const struct bdb_block *block) +EFI_STATUS decodeVBT(struct intel_opregion * opRegion, int vbt_off) { - const struct bdb_legacy_child_devices *defs = block->data; - int child_dev_num; + struct vbt_header *vbt = opRegion->vbt; + UINT8 *VBIOS = (UINT8 *) opRegion->header; + EFI_STATUS status = EFI_SUCCESS; + //UINT8 *VBIOS; + // int index; + // int fd; + //struct vbt_header *vbt = NULL; + int bdb_off; + // const char *filename = NULL; + //int size = 8192; + struct context context = { + .panel_type = -1, + }; - child_dev_num = (block->size - sizeof(*defs)) / defs->child_dev_size; + context.vbt = vbt; + bdb_off = vbt_off + vbt->bdb_offset; - DebugPrint(EFI_D_ERROR, "i915: Child device size: %d\n", defs->child_dev_size); - DebugPrint(EFI_D_ERROR, "i915: Child device count: %d\n", child_dev_num); + context.bdb = (const struct bdb_header *)(VBIOS + bdb_off); + context.size = 8192; + DebugPrint(EFI_D_ERROR, "i915: vbt: 0x%04x, bdb: 0x%04x, sig: %s, bsig: %s \n", context.vbt, context.bdb, context.vbt->signature, context.bdb->signature); - dump_child_devices(context, defs->devices, - child_dev_num, defs->child_dev_size); -} -struct dumper dumpers[] = { - { - .id = BDB_GENERAL_FEATURES, - .name = "General features block", - .dump = dumpNull, - }, - { - .id = BDB_GENERAL_DEFINITIONS, - .name = "General definitions block", - .dump = dump_general_definitions, - }, - { - .id = BDB_CHILD_DEVICE_TABLE, - .name = "Legacy child devices block", - .dump = dump_legacy_child_devices, - }, - { - .id = BDB_LVDS_OPTIONS, - .name = "LVDS options block", - .dump = dumpNull, - }, - { - .id = BDB_LVDS_LFP_DATA_PTRS, - .name = "LVDS timing pointer data", - .dump = dumpNull, - }, - { - .id = BDB_LVDS_LFP_DATA, - .name = "LVDS panel data block", - .dump = dumpNull, - }, - { - .id = BDB_LVDS_BACKLIGHT, - .name = "Backlight info block", - .dump = dumpNull, - }, - { - .id = BDB_SDVO_LVDS_OPTIONS, - .name = "SDVO LVDS options block", - .dump = dumpNull, - }, - { - .id = BDB_SDVO_PANEL_DTDS, - .name = "SDVO panel dtds", - .dump = dumpNull, - }, - { - .id = BDB_DRIVER_FEATURES, - .name = "Driver feature data block", - .dump = dumpNull, - }, - { - .id = BDB_EDP, - .name = "eDP block", - .dump = dumpNull, - }, - { - .id = BDB_PSR, - .name = "PSR block", - .dump = dumpNull, - }, - { - .id = BDB_MIPI_CONFIG, - .name = "MIPI configuration block", - .dump = dumpNull, - }, + struct bdb_block *block = (struct bdb_block *)AllocatePool(sizeof(block)); + + status = find_section(&context, BDB_GENERAL_DEFINITIONS, block); + if (!EFI_ERROR(status)) { - .id = BDB_MIPI_SEQUENCE, - .name = "MIPI sequence block", - .dump = dumpNull, - }, + status = decode_vbt_child_blocks(&context, block); + } + else { - .id = BDB_COMPRESSION_PARAMETERS, - .name = "Compression parameters block", - .dump = dumpNull, - }, -}; -static BOOLEAN dump_section(struct context *context, int section_id) + status = find_section(&context, BDB_CHILD_DEVICE_TABLE, block); + if (!EFI_ERROR(status)) + { + + status = decode_vbt_child_blocks(&context, block); + } + } + if (!EFI_ERROR(status)){ + opRegion->children = context.children; + opRegion->numChildren = context.numChildren; + } + return status; +} + + +static enum port get_port_by_ddc_pin(i915_CONTROLLER *i915, u8 ddc_pin) { - struct dumper *dumper = NULL; - struct bdb_block *block; - int i; + const struct ddi_vbt_port_info *info; + enum port port; - block = find_section(context, section_id); - if (!block) - return FALSE; + for_each_port(port) { + info = &i915->vbt.ddi_port_info[port]; - for (i = 0; i < ARRAY_SIZE(dumpers); i++) - { - if (block->id == dumpers[i].id) - { - dumper = &dumpers[i]; - break; - } + if (info->child && ddc_pin == info->alternate_ddc_pin) + return port; } - if (dumper && dumper->name) - DebugPrint(EFI_D_ERROR, "BDB block %d - %s:\n", block->id, dumper->name); - else - DebugPrint(EFI_D_ERROR, "BDB block %d - Unknown, no decoding available:\n", - block->id); + return PORT_NONE; +} - //if (context->hexdump) - // hex_dump_block(block); - if (dumper && dumper->dump) - dumper->dump(context, block); - DebugPrint(EFI_D_ERROR, "\n"); +static void sanitize_ddc_pin(i915_CONTROLLER *dev_priv, + enum port port) +{ + struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; + enum port p; - //FreePool (block); + if (!info->alternate_ddc_pin) + return; - return TRUE; + p = get_port_by_ddc_pin(dev_priv, info->alternate_ddc_pin); + if (p != PORT_NONE) { + DebugPrint(EFI_D_ERROR, + "port %c trying to use the same DDC pin (0x%x) as port %c, " + "disabling port %c DVI/HDMI support\n", + port_name(port), info->alternate_ddc_pin, + port_name(p), port_name(p)); + + /* + * If we have multiple ports supposedly sharing the + * pin, then dvi/hdmi couldn't exist on the shared + * port. Otherwise they share the same ddc bin and + * system couldn't communicate with them separately. + * + * Give inverse child device order the priority, + * last one wins. Yes, there are real machines + * (eg. Asrock B250M-HDV) where VBT has both + * port A and port E with the same AUX ch and + * we must pick port E :( + */ + info = &dev_priv->vbt.ddi_port_info[p]; + + info->supports_dvi = false; + info->supports_hdmi = false; + info->alternate_ddc_pin = 0; + } } -EFI_STATUS decodeVBT(struct vbt_header *vbt, int vbt_off, UINT8 *VBIOS) + +static enum port get_port_by_aux_ch(i915_CONTROLLER *i915, u8 aux_ch) { - //UINT8 *VBIOS; - // int index; - // int fd; - //struct vbt_header *vbt = NULL; - int i, bdb_off; - // const char *filename = NULL; - //int size = 8192; - struct context context = { - .panel_type = -1, + const struct ddi_vbt_port_info *info; + enum port port; + + for_each_port(port) { + info = &i915->vbt.ddi_port_info[port]; + + if (info->child && aux_ch == info->alternate_aux_channel) + return port; + } + + return PORT_NONE; +} + +static void sanitize_aux_ch(i915_CONTROLLER *dev_priv, + enum port port) +{ + struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; + enum port p; + + if (!info->alternate_aux_channel) + return; + + p = get_port_by_aux_ch(dev_priv, info->alternate_aux_channel); + if (p != PORT_NONE) { + DebugPrint(EFI_D_ERROR, + "port %c trying to use the same AUX CH (0x%x) as port %c, " + "disabling port %c DP support\n", + port_name(port), info->alternate_aux_channel, + port_name(p), port_name(p)); + + /* + * If we have multiple ports supposedlt sharing the + * aux channel, then DP couldn't exist on the shared + * port. Otherwise they share the same aux channel + * and system couldn't communicate with them separately. + * + * Give inverse child device order the priority, + * last one wins. Yes, there are real machines + * (eg. Asrock B250M-HDV) where VBT has both + * port A and port E with the same AUX ch and + * we must pick port E :( + */ + info = &dev_priv->vbt.ddi_port_info[p]; + + info->supports_dp = false; + info->alternate_aux_channel = 0; + } +} + +// static const u8 cnp_ddc_pin_map[] = { +// [0] = 0, /* N/A */ +// [DDC_BUS_DDI_B] = GMBUS_PIN_1_BXT, +// [DDC_BUS_DDI_C] = GMBUS_PIN_2_BXT, +// [DDC_BUS_DDI_D] = GMBUS_PIN_4_CNP, /* sic */ +// [DDC_BUS_DDI_F] = GMBUS_PIN_3_BXT, /* sic */ +// }; + +/* static const u8 icp_ddc_pin_map[] = { + [ICL_DDC_BUS_DDI_A] = GMBUS_PIN_1_BXT, + [ICL_DDC_BUS_DDI_B] = GMBUS_PIN_2_BXT, + [TGL_DDC_BUS_DDI_C] = GMBUS_PIN_3_BXT, + [ICL_DDC_BUS_PORT_1] = GMBUS_PIN_9_TC1_ICP, + [ICL_DDC_BUS_PORT_2] = GMBUS_PIN_10_TC2_ICP, + [ICL_DDC_BUS_PORT_3] = GMBUS_PIN_11_TC3_ICP, + [ICL_DDC_BUS_PORT_4] = GMBUS_PIN_12_TC4_ICP, + [TGL_DDC_BUS_PORT_5] = GMBUS_PIN_13_TC5_TGP, + [TGL_DDC_BUS_PORT_6] = GMBUS_PIN_14_TC6_TGP, +}; */ + +static u8 map_ddc_pin(i915_CONTROLLER *dev_priv, u8 vbt_pin) +{ + return vbt_pin; + +} + +static enum port __dvo_port_to_port(int n_ports, int n_dvo, + const int port_mapping[][3], u8 dvo_port) +{ + enum port port; + int i; + + for (port = PORT_A; port < n_ports; port++) { + for (i = 0; i < n_dvo; i++) { + if (port_mapping[port][i] == -1) + break; + + if (dvo_port == port_mapping[port][i]) + return port; + } + } + + return PORT_NONE; +} +static u8 translate_iboost(u8 val) +{ + static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */ + + if (val >= ARRAY_SIZE(mapping)) { + DebugPrint(EFI_D_ERROR, "i915: Unsupported I_boost value found in VBT (%d), display may not work properly\n", val); + return 0; + } + return mapping[val]; +} +static enum port dvo_port_to_port(i915_CONTROLLER *dev_priv, + u8 dvo_port) +{ + /* + * Each DDI port can have more than one value on the "DVO Port" field, + * so look for all the possible values for each port. + */ + static const int port_mapping[][3] = { + [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 }, + [PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 }, + [PORT_C] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 }, + [PORT_D] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 }, + [PORT_E] = { DVO_PORT_HDMIE, DVO_PORT_DPE, DVO_PORT_CRT }, + [PORT_F] = { DVO_PORT_HDMIF, DVO_PORT_DPF, -1 }, + [PORT_G] = { DVO_PORT_HDMIG, DVO_PORT_DPG, -1 }, + [PORT_H] = { DVO_PORT_HDMIH, DVO_PORT_DPH, -1 }, + [PORT_I] = { DVO_PORT_HDMII, DVO_PORT_DPI, -1 }, }; - // int block_number = -1; - //BOOLEAN header_only = FALSE, describe = FALSE; + /* + * Bspec lists the ports as A, B, C, D - however internally in our + * driver we keep them as PORT_A, PORT_B, PORT_D and PORT_E so the + * registers in Display Engine match the right offsets. Apply the + * mapping here to translate from VBT to internal convention. + */ +/* static const int rkl_port_mapping[][3] = { + [PORT_A] = { DVO_PORT_HDMIA, DVO_PORT_DPA, -1 }, + [PORT_B] = { DVO_PORT_HDMIB, DVO_PORT_DPB, -1 }, + [PORT_C] = { -1 }, + [PORT_D] = { DVO_PORT_HDMIC, DVO_PORT_DPC, -1 }, + [PORT_E] = { DVO_PORT_HDMID, DVO_PORT_DPD, -1 }, + }; + */ + + return __dvo_port_to_port(ARRAY_SIZE(port_mapping), + ARRAY_SIZE(port_mapping[0]), + port_mapping, + dvo_port); +} - /* Scour memory looking for the VBT signature */ - /* Scour memory looking for the VBT signature */ - // for (i = 0; i + 4 < size; i++) { - // if (!CompareMem (VBIOS + i, "$VBT", 4)) { - // vbt_off = i; - // vbt = (struct vbt_header *)(VBIOS + i); - // DebugPrint(EFI_D_ERROR, "VBT signature Found, sig: %.4s at 0x%04x\n", *(VBIOS + i), i); - // break; - // } else { +static void parse_ddi_port(i915_CONTROLLER *dev_priv, + const struct child_device_config *child, + UINT8 bdb_version) +{ + struct ddi_vbt_port_info *info; + BOOLEAN is_dvi, is_hdmi, is_dp, is_edp, is_crt; + enum port port; + port = dvo_port_to_port(dev_priv, child->dvo_port); + if (port == PORT_NONE) + return; - // } - // } + info = &dev_priv->vbt.ddi_port_info[port]; + info->port = port; - // if (!vbt) { - // DebugPrint(EFI_D_ERROR, "VBT signature missing\n"); - // // return EXIT_FAILURE; - // } + if (info->child) { + DebugPrint(EFI_D_ERROR, + "More than one child device for port %c in VBT, using the first.\n", + port_name(port)); + return; + } - context.vbt = vbt; - bdb_off = vbt_off + vbt->bdb_offset; + is_dvi = child->device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; + is_dp = child->device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; + is_crt = child->device_type & DEVICE_TYPE_ANALOG_OUTPUT; + is_hdmi = is_dvi && (child->device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0; + is_edp = is_dp && (child->device_type & DEVICE_TYPE_INTERNAL_CONNECTOR); + + if (port == PORT_A && is_dvi) { + DebugPrint(EFI_D_ERROR, + "VBT claims port A supports DVI%s, ignoring\n", + is_hdmi ? "/HDMI" : ""); + is_dvi = FALSE; + is_hdmi = FALSE; + } - context.bdb = (const struct bdb_header *)(VBIOS + bdb_off); - context.size = 8192; - DebugPrint(EFI_D_ERROR, "i915: vbt: 0x%04x, bdb: 0x%04x, sig: %s, bsig: %s \n", context.vbt, context.bdb, context.vbt->signature, context.bdb->signature); - /* if (!context.devid) { - const char *devid_string = getenv("DEVICE"); - if (devid_string) - context.devid = strtoul(devid_string, NULL, 16); - } - if (!context.devid) - context.devid = get_device_id(VBIOS, size); - if (!context.devid) - DebugPrint(EFI_D_ERROR, "Warning: could not find PCI device ID!\n"); - - if (context.panel_type == -1) - context.panel_type = get_panel_type(&context); - if (context.panel_type == -1) { - DebugPrint(EFI_D_ERROR, "Warning: panel type not set, using 0\n"); - context.panel_type = 0; + info->supports_dvi = is_dvi; + info->supports_hdmi = is_hdmi; + info->supports_dp = is_dp; + info->supports_edp = is_edp; + + if (bdb_version >= 195) + info->supports_typec_usb = child->dp_usb_type_c; + + if (bdb_version >= 209) + info->supports_tbt = child->tbt; + + DebugPrint(EFI_D_ERROR, + "Port %c VBT info: CRT:%d DVI:%d HDMI:%d DP:%d eDP:%d USB-Type-C:%d TBT:%d type:%04x\n", + port_name(port), is_crt, is_dvi, is_hdmi, is_dp, is_edp, + info->supports_typec_usb, info->supports_tbt, child->device_type); + + if (is_dvi) { + UINT8 ddc_pin; + + ddc_pin = map_ddc_pin(dev_priv, child->ddc_pin); + // if (intel_gmbus_is_valid_pin(dev_priv, ddc_pin)) { + info->alternate_ddc_pin = ddc_pin; + sanitize_ddc_pin(dev_priv, port); + /* } else { + DebugPrint(EFI_D_ERROR, + "Port %c has invalid DDC pin %d, " + "sticking to defaults\n", + port_name(port), ddc_pin); + } */ + } + + if (is_dp) { + info->alternate_aux_channel = child->aux_channel; + + sanitize_aux_ch(dev_priv, port); + } + + if (bdb_version >= 158) { + /* The VBT HDMI level shift values match the table we have. */ + UINT8 hdmi_level_shift = child->hdmi_level_shifter_value; + DebugPrint(EFI_D_ERROR, + "VBT HDMI level shift for port %c: %d\n", + port_name(port), + hdmi_level_shift); + info->hdmi_level_shift = hdmi_level_shift; + info->hdmi_level_shift_set = TRUE; + } + +/* if (bdb_version >= 204) { + int max_tmds_clock; + + switch (child->hdmi_max_data_rate) { + default: + MISSING_CASE(child->hdmi_max_data_rate); + fallthrough; + case HDMI_MAX_DATA_RATE_PLATFORM: + max_tmds_clock = 0; + break; + case HDMI_MAX_DATA_RATE_297: + max_tmds_clock = 297000; + break; + case HDMI_MAX_DATA_RATE_165: + max_tmds_clock = 165000; + break; + } + + if (max_tmds_clock) + DebugPrint(EFI_D_ERROR, + "VBT HDMI max TMDS clock for port %c: %d kHz\n", + port_name(port), max_tmds_clock); + info->max_tmds_clock = max_tmds_clock; } */ - /* if (describe) { - print_description(&context); - } else if (header_only) { - dump_headers(&context); - } else if (block_number != -1) { - dump specific section only - if (!dump_section(&context, block_number)) { - DebugPrint(EFI_D_ERROR, "Block %d not found\n", block_number); - return EXIT_FAILURE; + /* Parse the I_boost config for SKL and above */ + if (bdb_version >= 196 && child->iboost) { + info->dp_boost_level = translate_iboost(child->dp_iboost_level); + DebugPrint(EFI_D_ERROR, + "VBT (e)DP boost level for port %c: %d\n", + port_name(port), info->dp_boost_level); + info->hdmi_boost_level = translate_iboost(child->hdmi_iboost_level); + DebugPrint(EFI_D_ERROR, + "VBT HDMI boost level for port %c: %d\n", + port_name(port), info->hdmi_boost_level); + } + + /* DP max link rate for CNL+ */ + if (bdb_version >= 216) { + switch (child->dp_max_link_rate) { + default: + case VBT_DP_MAX_LINK_RATE_HBR3: + info->dp_max_link_rate = 810000; + break; + case VBT_DP_MAX_LINK_RATE_HBR2: + info->dp_max_link_rate = 540000; + break; + case VBT_DP_MAX_LINK_RATE_HBR: + info->dp_max_link_rate = 270000; + break; + case VBT_DP_MAX_LINK_RATE_LBR: + info->dp_max_link_rate = 162000; + break; } - } else { */ - // dump_headers(&context); + DebugPrint(EFI_D_ERROR, + "VBT DP max link rate for port %c: %d\n", + port_name(port), info->dp_max_link_rate); + } + + info->child = child; +} + +void parse_ddi_ports(i915_CONTROLLER *dev_priv, UINT8 bdb_version) +{ +/* struct display_device_data *devdata; + + if (!HAS_DDI(dev_priv) && !IS_CHERRYVIEW(dev_priv)) + return; + */ + if (bdb_version < 155) + return; + struct context context; + struct bdb_header bdb; + bdb.version = bdb_version; + context.bdb = &bdb; + for (int i = 0; i < dev_priv->opRegion->numChildren; i++ ) { + dump_child_device(&context, &dev_priv->opRegion->children[i]); + parse_ddi_port(dev_priv, &dev_priv->opRegion->children[i], bdb_version); //TODO Update to dyn version + + } + //list_for_each_entry(devdata, &dev_priv->vbt.display_devices, node) +} +enum aux_ch intel_bios_port_aux_ch(i915_CONTROLLER *dev_priv, + enum port port) +{ + const struct ddi_vbt_port_info *info = + &dev_priv->vbt.ddi_port_info[port]; + enum aux_ch aux_ch; + + if (!info->alternate_aux_channel) { + aux_ch = (enum aux_ch)port; + + DebugPrint(EFI_D_ERROR, + "using AUX %c for port %c (platform default)\n", + aux_ch_name(aux_ch), port_name(port)); + return aux_ch; + } + + switch (info->alternate_aux_channel) { + case DP_AUX_A: + aux_ch = AUX_CH_A; + break; + case DP_AUX_B: + aux_ch = AUX_CH_B; + break; + case DP_AUX_C: + aux_ch = AUX_CH_C; + break; + case DP_AUX_D: + aux_ch = AUX_CH_D; + break; + case DP_AUX_E: + aux_ch = AUX_CH_E; + break; + case DP_AUX_F: + aux_ch = AUX_CH_F; + break; + case DP_AUX_G: + aux_ch = AUX_CH_G; + break; + // case DP_AUX_H: + // aux_ch = AUX_CH_H; + // break; + // case DP_AUX_I: + // aux_ch = AUX_CH_I; + // break; + default: + aux_ch = AUX_CH_A; + break; + } - /* dump all sections */ - for (i = 0; i < 256; i++) - dump_section(&context, i); - // } + DebugPrint(EFI_D_ERROR, "using AUX %c for port %c (VBT)\n", + aux_ch_name(aux_ch), port_name(port)); - return 0; + return aux_ch; } \ No newline at end of file diff --git a/intel_opregion.h b/intel_opregion.h index b19cb17..71a0225 100644 --- a/intel_opregion.h +++ b/intel_opregion.h @@ -34,7 +34,6 @@ #include "QemuFwCfgLib.h" #include "i915_display.h" -#include "i915_gop.h" #include "i915ovmf.h" #include #include @@ -48,6 +47,11 @@ #include #include #include +#include "i915_controller.h" + +#ifndef INTEL_OPREGION +#define INTEL_OPREGION + #define OPREGION_HEADER_OFFSET 0 #define OPREGION_ACPI_OFFSET 0x100 #define ACPI_CLID 0x01ac /* current lid state indicator */ @@ -62,163 +66,28 @@ #define MBOX_SWSCI (1 << 1) #define MBOX_ASLE (1 << 2) #define MBOX_ASLE_EXT (1 << 4) -#define __packed __attribute__((packed)) -struct opregion_header -{ - UINT8 signature[16]; - UINT32 size; - struct - { - UINT8 rsvd; - UINT8 revision; - UINT8 minor; - UINT8 major; - } __packed over; - UINT8 bios_ver[32]; - UINT8 vbios_ver[16]; - UINT8 driver_ver[16]; - UINT32 mboxes; - UINT32 driver_model; - UINT32 pcon; - UINT8 dver[32]; - UINT8 rsvd[124]; -} __packed; - -/* OpRegion mailbox #1: public ACPI methods */ -struct opregion_acpi -{ - UINT32 drdy; /* driver readiness */ - UINT32 csts; /* notification status */ - UINT32 cevt; /* current event */ - UINT8 rsvd1[20]; - UINT32 didl[8]; /* supported display devices ID list */ - UINT32 cpdl[8]; /* currently presented display list */ - UINT32 cadl[8]; /* currently active display list */ - UINT32 nadl[8]; /* next active devices list */ - UINT32 aslp; /* ASL sleep time-out */ - UINT32 tidx; /* toggle table index */ - UINT32 chpd; /* current hotplug enable indicator */ - UINT32 clid; /* current lid state*/ - UINT32 cdck; /* current docking state */ - UINT32 sxsw; /* Sx state resume */ - UINT32 evts; /* ASL supported events */ - UINT32 cnot; /* current OS notification */ - UINT32 nrdy; /* driver status */ - UINT32 did2[7]; /* extended supported display devices ID list */ - UINT32 cpd2[7]; /* extended attached display devices list */ - UINT8 rsvd2[4]; -} __packed; - -/* OpRegion mailbox #2: SWSCI */ -struct opregion_swsci -{ - UINT32 scic; /* SWSCI command|status|data */ - UINT32 parm; /* command parameters */ - UINT32 dslp; /* driver sleep time-out */ - UINT8 rsvd[244]; -} __packed; - -/* OpRegion mailbox #3: ASLE */ -struct opregion_asle -{ - UINT32 ardy; /* driver readiness */ - UINT32 aslc; /* ASLE interrupt command */ - UINT32 tche; /* technology enabled indicator */ - UINT32 alsi; /* current ALS illuminance reading */ - UINT32 bclp; /* backlight brightness to set */ - UINT32 pfit; /* panel fitting state */ - UINT32 cblv; /* current brightness level */ - UINT16 bclm[20]; /* backlight level duty cycle mapping table */ - UINT32 cpfm; /* current panel fitting mode */ - UINT32 epfm; /* enabled panel fitting modes */ - UINT8 plut[74]; /* panel LUT and identifier */ - UINT32 pfmb; /* PWM freq and min brightness */ - UINT32 cddv; /* color correction default values */ - UINT32 pcft; /* power conservation features */ - UINT32 srot; /* supported rotation angles */ - UINT32 iuer; /* IUER events */ - UINT64 fdss; - UINT32 fdsp; - UINT32 stat; - UINT64 rvda; /* Physical (2.0) or relative from opregion (2.1+) - * address of raw VBT data. */ - UINT32 rvds; /* Size of raw vbt data */ - UINT8 rsvd[58]; -} __packed; - -/* OpRegion mailbox #5: ASLE ext */ -struct opregion_asle_ext -{ - UINT32 phed; /* Panel Header */ - UINT8 bddc[256]; /* Panel EDID */ - UINT8 rsvd[764]; -} __packed; -/** - * struct vbt_header - VBT Header structure - * @signature: VBT signature, always starts with "$VBT" - * @version: Version of this structure - * @header_size: Size of this structure - * @vbt_size: Size of VBT (VBT Header, BDB Header and data blocks) - * @vbt_checksum: Checksum - * @reserved0: Reserved - * @bdb_offset: Offset of &struct bdb_header from beginning of VBT - * @aim_offset: Offsets of add-in data blocks from beginning of VBT - */ -struct vbt_header -{ - UINT8 signature[20]; - UINT16 version; - UINT16 header_size; - UINT16 vbt_size; - UINT8 vbt_checksum; - UINT8 reserved0; - UINT32 bdb_offset; - UINT32 aim_offset[4]; -} __packed; - -/** - * struct bdb_header - BDB Header structure - * @signature: BDB signature "BIOS_DATA_BLOCK" - * @version: Version of the data block definitions - * @header_size: Size of this structure - * @bdb_size: Size of BDB (BDB Header and data blocks) - */ -struct bdb_header -{ - UINT8 signature[16]; - UINT16 version; - UINT16 header_size; - UINT16 bdb_size; -} __packed; -struct intel_opregion -{ - struct opregion_header *header; - struct opregion_acpi *acpi; - struct opregion_swsci *swsci; - struct opregion_asle *asle; - struct vbt_header *vbt; - struct bdb_header *bdb; - struct opregion_asle_ext *asle_ext; -}; -struct bdb_block -{ - UINT8 id; - UINT32 size; - const void *data; -}; struct context { const struct vbt_header *vbt; const struct bdb_header *bdb; int size; - + struct child_device_config * children; + UINT8 numChildren; UINT32 devid; int panel_type; BOOLEAN dump_all_panel_types; BOOLEAN hexdump; }; +struct bdb_block +{ + UINT8 id; + UINT32 size; + const void *data; +}; + + struct dumper { UINT8 id; @@ -266,7 +135,11 @@ enum bdb_block_id BDB_COMPRESSION_PARAMETERS = 56, BDB_SKIP = 254, /* VBIOS private block, ignore */ }; +#define port_name(p) ((p) + 'A') + +#define for_each_port(__port) \ + for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++) /* Get to bdb section of vbt. THen Scan through to read off the ids of the blocks until we find general definitions or legacy child devices. THen read them @@ -587,27 +460,32 @@ struct bdb_general_features #define DEVICE_PORT_DVOC 0x02 /* dvo_port BDB 155+ */ -#define DVO_PORT_HDMIA 0 -#define DVO_PORT_HDMIB 1 -#define DVO_PORT_HDMIC 2 -#define DVO_PORT_HDMID 3 -#define DVO_PORT_LVDS 4 -#define DVO_PORT_TV 5 -#define DVO_PORT_CRT 6 -#define DVO_PORT_DPB 7 -#define DVO_PORT_DPC 8 -#define DVO_PORT_DPD 9 -#define DVO_PORT_DPA 10 -#define DVO_PORT_DPE 11 /* 193 */ -#define DVO_PORT_HDMIE 12 /* 193 */ -#define DVO_PORT_DPF 13 /* N/A */ -#define DVO_PORT_HDMIF 14 /* N/A */ -#define DVO_PORT_DPG 15 -#define DVO_PORT_HDMIG 16 -#define DVO_PORT_MIPIA 21 /* 171 */ -#define DVO_PORT_MIPIB 22 /* 171 */ -#define DVO_PORT_MIPIC 23 /* 171 */ -#define DVO_PORT_MIPID 24 /* 171 */ +/* dvo_port BDB 155+ */ +#define DVO_PORT_HDMIA 0 +#define DVO_PORT_HDMIB 1 +#define DVO_PORT_HDMIC 2 +#define DVO_PORT_HDMID 3 +#define DVO_PORT_LVDS 4 +#define DVO_PORT_TV 5 +#define DVO_PORT_CRT 6 +#define DVO_PORT_DPB 7 +#define DVO_PORT_DPC 8 +#define DVO_PORT_DPD 9 +#define DVO_PORT_DPA 10 +#define DVO_PORT_DPE 11 /* 193 */ +#define DVO_PORT_HDMIE 12 /* 193 */ +#define DVO_PORT_DPF 13 /* N/A */ +#define DVO_PORT_HDMIF 14 /* N/A */ +#define DVO_PORT_DPG 15 /* 217 */ +#define DVO_PORT_HDMIG 16 /* 217 */ +#define DVO_PORT_DPH 17 /* 217 */ +#define DVO_PORT_HDMIH 18 /* 217 */ +#define DVO_PORT_DPI 19 /* 217 */ +#define DVO_PORT_HDMII 20 /* 217 */ +#define DVO_PORT_MIPIA 21 /* 171 */ +#define DVO_PORT_MIPIB 22 /* 171 */ +#define DVO_PORT_MIPIC 23 /* 171 */ +#define DVO_PORT_MIPID 24 /* 171 */ #define HDMI_MAX_DATA_RATE_PLATFORM 0 /* 204 */ #define HDMI_MAX_DATA_RATE_297 1 /* 204 */ @@ -845,6 +723,18 @@ struct bdb_sdvo_panel_dtds /* * Block 27 - eDP VBT Block */ +enum aux_ch { + AUX_CH_A, + AUX_CH_B, + AUX_CH_C, + AUX_CH_D, + AUX_CH_E, /* ICL+ */ + AUX_CH_F, + AUX_CH_G, + AUX_CH_H, + AUX_CH_I, +}; +#define aux_ch_name(a) ((a) + 'A') #define EDP_18BPP 0 #define EDP_24BPP 1 @@ -1235,4 +1125,8 @@ struct bdb_compression_parameters struct dsc_compression_parameters_entry data[16]; } __packed; -EFI_STATUS decodeVBT( struct vbt_header *vbt, int vbt_off, UINT8 *VBIOS); +EFI_STATUS decodeVBT(struct intel_opregion * opRegion, int vbt_off); +void parse_ddi_ports(i915_CONTROLLER *dev_priv, UINT8 bdb_version); +enum aux_ch intel_bios_port_aux_ch(i915_CONTROLLER *dev_priv, + enum port port); +#endif diff --git a/intel_vbt.c b/intel_vbt.c new file mode 100644 index 0000000..c6342ac --- /dev/null +++ b/intel_vbt.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include +#include +#include + +#include "QemuFwCfgLib.h" +#include "i915_display.h" +#include "i915_gop.h" +#include "i915ovmf.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intel_opregion.h" diff --git a/intel_vbt.h b/intel_vbt.h new file mode 100644 index 0000000..e69de29 From 644faca6ab30af088548983377ff7030d928b810 Mon Sep 17 00:00:00 2001 From: Patrick Magauran Date: Mon, 30 Nov 2020 13:20:10 -0500 Subject: [PATCH 4/5] Update Readme. --- README.md | 89 +++++++++++++++++++++---------------------------------- 1 file changed, 33 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 03220bb..4eacee2 100755 --- a/README.md +++ b/README.md @@ -1,67 +1,43 @@ # VBIOS for Intel GPU Passthrough +This project attempts to create a UEFI driver for the intel integrated GPUS so that they can be used in VFIO Passthrough. Prior to this driver, there was no easy or reliable solution to both virtualized and direct passthrough(GVT-G/D). This driver adds an opRegion for the iGPU to utilize during the Boot Process, allowing for access to the UEFI menus and any other interfaces that are created before an operating system level driver is initialized. As a bonus, this allows for MacOS to boot in this virtual environment. + +## Notice + +*This Software deals directly with the graphics hardware and interfaces. I assume no responsibility should it cause any damage to your GPUs, Cables, Displays, Other hardware, or persons. It has been tested on my personal machine, but **you are using this software at your own risk.*** + Disclaimer: When used in direct passthrough, this VBIOS could produce bad pixel clock that can potentially damage your monitor! Make sure your monitor has protections against that. I'm not responsible for any monitor damage. +## Current Feature Support + +* Boot a virtual intel GPU(GVT-G) +* Passthrough the entire Intel GPU (GVT-D) + * Display Port interfaces + * eDP interfaces, including Laptop Screens + * HDMI interfaces +* Theoretically compatible with any 14nm chip(Skylake, Kaby lake, Coffee Lake, Amber Lake, Whiskey Lake, Comet Lake). +* Auto detect Outputs and types(**NEW**) + +## Possible Features to come + +* Allow for generation Specific Quirks +* Allow for other it to work with other intel CPU Generations. + +## Known Issues + +* May have issues with thunderbolt eGPUs. If you encounter problems, try with it unplugged +* GVT-G may struggle with external displays(even if through an eGPU or other GPU) + ## What is this This is an independent Video BIOS for Intel integrated GPUs. It provides a boot display and sets up an OpRegion so that Windows guests can produce monitor output. -The OpRegion code comes from IgdAssignmentDxe and should work everywhere. The boot display works for GVT-g and can safely replace ramfb. For direct passthrough, the boot display only works with the exact combination of an HDMI monitor and an Intel Skylake processor. - -## How to build - -1. Make a workspace folder, for example: `i915-development` -2. Clone the EDK II, EDKII-Platforms, and this repo into the folder you just created -3. In the EDK II folder, run `git submodule update --init` to download the submodules -4. In the workspace folder, make a new folder called `Conf` -5. Run `cp i915ovmfPkg/target.txt Conf/target.txt` -6. Run: - -``` -ln -s ./i915ovmfPkg ./edk2/ -# Create an empty FAT disk image -dd if=/dev/zero of=disk bs=128M count=1 -sudo mkfs.vfat disk -mkdir i915_simple -cp disk i915_simple/ -``` - -7. Edit i915ovmfpkg/test and i915ovmfpkg/test-gvt-d to update the WORKSPACE variable to your workspace you created earlier. -8. Then run `./t` to build and test. Due to GVT-g and EFI shenanigans, the testing process needs root. - -**NOTE** Compilation requires the following dependencies(names are not correct): - -- lib-uuid-devel -- iasl -- nasm -- git -- clang -- lld-devel -- llvm-devel - -If you just want to use it for your VM, grab the rom file in Releases. -**NOTE** Currently, using this rom causes the intel thunderbolt controller to reset. Using a thunderbolt e-gpu may cause the system to crash. - -## VFIO Setup -Refer to the [Arch Linux wiki Guide for passthrough](https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF) and [for GVT-G](https://wiki.archlinux.org/index.php/Intel_GVT-g) -1. Install QEMU & the ovmf packages as appropriate for your distributions -2. Copy the ovmf.fd file from the appropriate locati -3. Add the following kernel parameters: `intel_iommu=on iommu=pt` -4. Reboot and run the included `iommu.sh` script to list your iommu groups and PCI ids. Script courtesy of Arch Linux Guide -5. In the ouput, search for the intel GPU. Note both the PCI location(eg 00:02.0) and the id(eg 8086:1234) -6. Follow the appropriate instructions below for what you are doing (GVT-d/g) - -### GVT-G -1. Enable the kernel modules: `kvmgt`,`vfio-iommu-type1`,`vfio-mdev` -2. Add the following kernel parameter: `i915.enable_gvt=1` -3. Reboot and determine your avaiable GVT-g modes by running the folloiwng command: `ls /sys/devices/pci${GVT_DOM}/$GVT_PCI/mdev_supported_types` where GVT_DOM is the PCI Domain(Typically 0000) and GVT_PCI is the PCI location noted earlier. If you have trouble, use the command lspci -D -nn and locate the intel gpu to get the correct domain/location. -4. Update the Type variable in test to one of the listed modes for your gpu. - -### GVT-d -1. Add the following kernel parameter: `vfio-pci.ids=PCIID` where PCIID is the ID obtained earlier(eg 8086:1234) -2. Enable the following kernel modules: `vfio_pci vfio vfio_iommu_type1 vfio_virqfd` -3. Reboot -4. Update the test-gvt-d with the correct PCI location +The OpRegion code comes from IgdAssignmentDxe and should work everywhere. The boot display works for GVT-g and can safely replace ramfb. For direct passthrough, the boot display Works on intel 14nm based CPUS and HDMI/DP/eDP displays(Inlcuding laptop Screens!). + +## Usage + +Please see the Wiki for more information regarding compiling, usage, or further information. + ## License I have no idea what this should be licensed in, but the code came from: @@ -70,3 +46,4 @@ I have no idea what this should be licensed in, but the code came from: - IgdAssignmentDxe: non-upstreamed Intel patch to OVMF - EDK II: https://github.com/tianocore/edk2 - The Linux kernel +- Intel-gpu-tools: https://cgit.freedesktop.org/xorg/app/intel-gpu-tools/tree/tools From fe9faedc076f5b37f49e91cdcdda90d1f18dabd5 Mon Sep 17 00:00:00 2001 From: Patrick Magauran Date: Mon, 30 Nov 2020 13:45:29 -0500 Subject: [PATCH 5/5] Add Release files --- Release/iommu.sh | 8 ++++++++ Release/test-gvt-d.sh | 22 ++++++++++++++++++++++ Release/test-gvt-g.sh | 26 ++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100755 Release/iommu.sh create mode 100755 Release/test-gvt-d.sh create mode 100755 Release/test-gvt-g.sh diff --git a/Release/iommu.sh b/Release/iommu.sh new file mode 100755 index 0000000..e3559fb --- /dev/null +++ b/Release/iommu.sh @@ -0,0 +1,8 @@ +#!/bin/bash +shopt -s nullglob +for g in /sys/kernel/iommu_groups/*; do + echo "IOMMU Group ${g##*/}:" + for d in $g/devices/*; do + echo -e "\t$(lspci -nns ${d##*/})" + done; +done; \ No newline at end of file diff --git a/Release/test-gvt-d.sh b/Release/test-gvt-d.sh new file mode 100755 index 0000000..d3fd656 --- /dev/null +++ b/Release/test-gvt-d.sh @@ -0,0 +1,22 @@ +#!/bin/bash +export WORKSPACE=/home/patrick/i915dev/Release +export PCILOC=0000:00:02.0 +export PCIID=8086:9bca + +cd $WORKSPACE + +cd ./i915_simple + +# Create an UEFI disk that immediately shuts down the VM when booted +mkdir -p tmpfat +mount disk tmpfat +mkdir -p tmpfat/EFI/BOOT +umount tmpfat +rmdir tmpfat +systemctl stop display-manager.service + echo $PCIID > /sys/bus/pci/drivers/vfio-pci/new_id + echo $PCILOC> /sys/bus/pci/devices/$PCILOC/driver/unbind + echo $PCILOC > /sys/bus/pci/drivers/vfio-pci/bind +#qemu-system-x86_64 -k en-us -name uefitest,debug-threads=on -nographic -vga none -serial stdio -m 2048 -M pc -cpu host -global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -machine kernel_irqchip=on -nodefaults -rtc base=localtime,driftfix=slew -no-hpet -global kvm-pit.lost_tick_policy=discard -enable-kvm -bios $WORKSPACE/OVMF_CODE.fd -device vfio-pci,host=$PCILOC,romfile=`pwd`/i915ovmf.rom -device qemu-xhci,p2=8,p3=8 -device usb-kbd -device usb-tablet -drive format=raw,file=disk -usb +timeout --foreground -k 1 8 qemu-system-x86_64 -k en-us -name uefitest,debug-threads=on -nographic -vga none -chardev stdio,id=char0,logfile=serial.log,signal=off \ + -serial chardev:char0 -m 2048 -M pc -cpu host -global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -machine kernel_irqchip=on -nodefaults -rtc base=localtime,driftfix=slew -no-hpet -global kvm-pit.lost_tick_policy=discard -enable-kvm -bios $WORKSPACE/OVMF_CODE.fd -device vfio-pci,host=$PCILOC,romfile=`pwd`/i915ovmf.rom -device qemu-xhci,p2=8,p3=8 -device usb-kbd -device usb-tablet -drive format=raw,file=disk -usb diff --git a/Release/test-gvt-g.sh b/Release/test-gvt-g.sh new file mode 100755 index 0000000..368744f --- /dev/null +++ b/Release/test-gvt-g.sh @@ -0,0 +1,26 @@ +#!/bin/bash +export WORKSPACE=/home/patrick/development +export PCILOC=00:02.0 +export PCIID=8086:9bca +export GVTMODE=i915-GVTg_V5_4 + + +cd ./i915_simple + +if [ -e /sys/bus/pci/devices/0000:$PCILOC/2aee154e-7d0d-11e8-88b8-6f45320c7162 ] +then + true +else + modprobe kvmgt || exit + #sudo dd if=/sys/class/drm/card0-HDMI-A-1/edid of=/sys/class/drm/card0/gvt_edid bs=128 count=1 + echo 2aee154e-7d0d-11e8-88b8-6f45320c7162 > /sys/bus/pci/devices/0000:$PCILOC/mdev_supported_types/$GVTMODE/create || exit +fi + +# Create an UEFI disk that immediately shuts down the VM when booted +mkdir -p tmpfat +mount disk tmpfat +mkdir -p tmpfat/EFI/BOOT +umount tmpfat +rmdir tmpfat + +qemu-system-x86_64 -k en-us -name uefitest,debug-threads=on -serial stdio -m 2048 -M pc -cpu host -global PIIX4_PM.disable_s3=1 -global PIIX4_PM.disable_s4=1 -machine kernel_irqchip=on -nodefaults -rtc base=localtime,driftfix=slew -no-hpet -global kvm-pit.lost_tick_policy=discard -enable-kvm -bios $WORKSPACE/OVMF_CODE.fd -display gtk,gl=on,grab-on-hover=on -full-screen -vga none -device vfio-pci,sysfsdev=/sys/bus/pci/devices/0000:$PCILOC/2aee154e-7d0d-11e8-88b8-6f45320c7162,addr=02.0,display=on,x-igd-opregion=on,romfile=`pwd`/i915ovmf.rom -device qemu-xhci,p2=8,p3=8 -device usb-kbd -device usb-tablet -drive format=raw,file=disk