# EDID 介紹 EDID全名為Extended Display Identification Data,是由VESA協會制定的顯示器標準資訊格式。具體來說,可以把 EDID 當成一個顯示器的 metadata / 身分證,其內容會包含顯示器的相關資訊,如顯示器名稱、產品序號、支援解析度、聲音格式等等。目的為告訴輸出端顯示器支援的能力,確保電腦或是機上盒等影音輸出裝置,在連接上顯示器後,能根據資訊輸出正確的影音格式,因此可以避免無法顯示或顯示比例不正常等狀況發生。 目前此項技術已廣泛應用於影音顯示介面如 DisplayPort、HDMI。在實作上,為了要容納先前提到的EDID資訊於顯示器中,儲存在 EEPROM 中,並且在HDMI介面會利用I2C的介面來進行雙向的資料傳輸。 EDID 透過 I2C 與 source 進行傳輸 ![image](https://hackmd.io/_uploads/Bk9xGxZ0kx.png) ![image](https://hackmd.io/_uploads/SkxVEx-AJl.png) 目前 HDMI 介面使用 EDID v1.3,DP 介面則使用 EDID v1.4 ## EDID 資料結構(v1.3) EDID 由 1 ~ 4 個 block 組成,每個 block 大小為 128 Byte。第一個 block 又稱為 EDID Base Block,由 VESA EDID 標準制定。隨著越來越多的顯示/聲音格式,需要更多的容量存放訊息,所以也發展成利用 Extension Block 格式在 EDID 內放置多個 Block,最多可放置 255個 Block。 EDID Base Block 又稱為 Block,每個 Byte 採用 16 進位資料格式。 TODO: write the detail of the first block ## UEFI EDID related protocol 在 UEFI 環境下,常會需要透過 GOP 與其相關的 Protocol 進行顯示相關功能開發,而 UEFI 定義了相關的 protocol 來取得 EDID 資訊 ### EdidDiscovered ```c! typedef struct { UINT32 SizeOfEdid; UINT8 *Edid; } EFI_EDID_DISCOVERED_PROTOCOL; ``` #### SizeofEdid: Edid buffer 大小,最小值 128 byte。 若沒有 EDID 資訊,則設為 0。 #### Edid 指向唯讀位元陣列的指標,該位元陣列為顯示器(video output device) EDID 資訊。 #### 說明 該 Protocol 包含從顯示器回傳的 EDID 資訊,若該顯示器沒有任何 EDID 資訊,則 SizeofEdid = 0 且 \*Edid = NULL; 當 GOPDriverBinding -> Start() 被呼叫時,該 Protocol 會被 installed 在每個實體連接的 display device 的 child handle 上 Ex: 當一個 HDMI display device 連接到 video controller 時,HDMI ddevice 會被 installed 成一個 child handle,並同時 install EdidDiscovered. 若連接著 video output device 並非 EDID capable(非常老的類比 CRT 螢幕),或是 EDID 資訊無法取得,則該 protocol 會以 SizeofEdid = 0 且 \*Edid = NULL 的方式被安裝。 ### EdidOverride ```c! typedef struct _EFI_EDID_OVERRIDE_PROTOCOL { EFI_EDID_OVERRIDE_PROTOCOL_GET_EDID GetEdid; } EFI_EDID_OVERRIDE_PROTOCOL; ``` #### GetEdid 回傳 EDID value & attribute #### 說明 由 platform firmware 產生,該 protocol 允許系統提供另一個 EDID 資訊給 GOP。 #### EFI_EDID_OVERRIDE_PROTOCOL.GetEdid() ```c typedef EFI_STATUS (EFIAPI \*EFI_EDID_OVERRIDE_PROTOCOL_GET_EDID) ( IN EFI_EDID_OVERRIDE_PROTOCOL *This, IN EFI_HANDLE *ChildHandle, OUT UINT32 *Attributes, OUT UINTN *EdidSize, OUT UINT8 **Edid ); ``` #### 說明 Returns policy information and potentially a replacement EDID for the specified video output device. This protocol is optionally provided by the platform to override or provide EDID information and/or output device display properties to the producer of the Graphics Output protocol. If ChildHandle does not represent a video output device, or there are no override for the video output device specified by ChildHandle, then EFI_UNSUPPORTED is returned. Otherwise, the Attributes, EdidSize, and Edid parameters are returned along with a status of EFI_SUCCESS. ### EdidActive ```c! typedef struct { UINT32 SizeOfEdid; UINT8 *Edid; } EFI_EDID_ACTIVE_PROTOCOL; ``` #### 說明: 包含 **正在使用**的(Active)顯示器的 EDID 資訊, 該資訊由 EFI_EDID_OVERRIDE_PROTOCOL 或 EFI_EDID_DISCOVERED_PROTOCOL 提供。 若沒有 override,則 EDID 資訊和 EFI_EDID_DISCOVERED_PROTOCOL 相同 When the set of active video output devices attached to a frame buffer are selected, the EFI_EDID_ACTIVE_PROTOCOL must be installed onto the handles that represent the each of those active video output devices. If the EFI_EDID_OVERRIDE_PROTOCOL has override EDID information for an active video output device, then the EDID information specified by GetEdid() is used for the EFI_EDID_ACTIVE_PROTOCOL. Otherwise, the EDID information from the EFI_EDID_DISCOVERED_PROTOCOL is used for the EFI_EDID_ACTIVE_PROTOCOL. Since all EDID information is read-only, it is legal for the pointer associated with the EFI_EDID_ACTIVE_PROTOCOL to be the same as the pointer associated with the EFI_EDID_DISCOVERED_PROTOCOL when no overrides are present. ## UEFI Application 取得 EDID 資訊 下列程式為一個 UEFI application,透過 EdidDiscoveredProtocol 取得 EDID 資訊。 ```c #include <Uefi.h> #include <Library/UefiLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Protocol/EdidDiscovered.h> EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_EDID_DISCOVERED_PROTOCOL *EdidDiscovered; // Locate the EDID Discovered Protocol. Status = gBS->LocateProtocol(&gEfiEdidDiscoveredProtocolGuid, NULL, (VOID **)&EdidDiscovered); if (EFI_ERROR(Status)) { Print(L"Failed to locate EDID Discovered Protocol: %r\n", Status); return Status; } // Check if EDID data is available. if (EdidDiscovered->Edid == NULL || EdidDiscovered->SizeOfEdid == 0) { Print(L"No EDID data available.\n"); return EFI_NOT_FOUND; } // Print the EDID data in hexadecimal format. Print(L"EDID Data (%d bytes):\n", EdidDiscovered->SizeOfEdid); for (UINTN i = 0; i < EdidDiscovered->SizeOfEdid; i++) { Print(L"%02x ", EdidDiscovered->Edid[i]); if ((i + 1) % 16 == 0) { Print(L"\n"); } } Print(L"\n"); return EFI_SUCCESS; } ``` ## Reference https://www.graniteriverlabs.com/zh-tw/technical-blog/edid-overview https://silverwind1982.pixnet.net/blog/post/365351044 https://uefi.org/sites/default/files/resources/2_-_AMD_UEFI_Plugfest_EDID_Spring2012.pdf https://glenwing.github.io/docs/VESA-EEDID-A1.pdf