summaryrefslogtreecommitdiff
path: root/usr/src/boot/sys/boot/efi/loader/framebuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/boot/sys/boot/efi/loader/framebuffer.c')
-rw-r--r--usr/src/boot/sys/boot/efi/loader/framebuffer.c100
1 files changed, 56 insertions, 44 deletions
diff --git a/usr/src/boot/sys/boot/efi/loader/framebuffer.c b/usr/src/boot/sys/boot/efi/loader/framebuffer.c
index f063cc1639..534e00cf9c 100644
--- a/usr/src/boot/sys/boot/efi/loader/framebuffer.c
+++ b/usr/src/boot/sys/boot/efi/loader/framebuffer.c
@@ -50,10 +50,11 @@ EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID;
static EFI_GUID active_edid_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
-static EFI_GUID discovered_edid_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID;
/* Saved initial GOP mode. */
static uint32_t default_mode = UINT32_MAX;
+/* Cached EDID. */
+static struct vesa_edid_info *edid_info;
static uint32_t gop_default_mode(void);
static int efifb_set_mode(EFI_GRAPHICS_OUTPUT *, uint_t);
@@ -451,63 +452,54 @@ efifb_gop_get_edid(EFI_HANDLE gop)
{
const uint8_t magic[] = EDID_MAGIC;
EFI_EDID_ACTIVE_PROTOCOL *edid;
- struct vesa_edid_info *edid_info;
+ struct vesa_edid_info *edid_infop;
EFI_GUID *guid;
EFI_STATUS status;
size_t size;
- edid_info = calloc(1, sizeof (*edid_info));
- if (edid_info == NULL)
- return (NULL);
-
guid = &active_edid_guid;
- status = BS->OpenProtocol(gop, guid, (void **)&edid, IH, NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (status != EFI_SUCCESS) {
- guid = &discovered_edid_guid;
- status = BS->OpenProtocol(gop, guid, (void **)&edid, IH, NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- }
+ status = OpenProtocolByHandle(gop, guid, (void **)&edid);
if (status != EFI_SUCCESS)
- goto error;
+ return (NULL);
+
+ size = sizeof (*edid_infop);
+ if (size < edid->SizeOfEdid)
+ size = edid->SizeOfEdid;
- size = edid->SizeOfEdid;
- if (size > sizeof (*edid_info))
- size = sizeof (*edid_info);
+ edid_infop = calloc(1, size);
+ if (edid_infop == NULL) {
+ status = BS->CloseProtocol(gop, guid, IH, NULL);
+ return (NULL);
+ }
- memcpy(edid_info, edid->Edid, size);
+ memcpy(edid_infop, edid->Edid, edid->SizeOfEdid);
status = BS->CloseProtocol(gop, guid, IH, NULL);
/* Validate EDID */
- if (memcmp(edid_info, magic, sizeof (magic)) != 0)
+ if (memcmp(edid_infop, magic, sizeof (magic)) != 0)
goto error;
- if (edid_info->header.version == 1 &&
- (edid_info->display.supported_features
- & EDID_FEATURE_PREFERRED_TIMING_MODE) &&
- edid_info->detailed_timings[0].pixel_clock) {
- return (edid_info);
- }
+ if (edid_infop->header.version != 1)
+ goto error;
+ return (edid_infop);
error:
- free(edid_info);
+ free(edid_infop);
return (NULL);
}
-static int
-efifb_get_edid(UINT32 *pwidth, UINT32 *pheight)
+static bool
+efifb_get_edid(edid_res_list_t *res)
{
extern EFI_GRAPHICS_OUTPUT *gop;
- struct vesa_edid_info *edid_info;
- int rv = 1;
-
- edid_info = efifb_gop_get_edid(gop);
- if (edid_info != NULL) {
- *pwidth = GET_EDID_INFO_WIDTH(edid_info, 0);
- *pheight = GET_EDID_INFO_HEIGHT(edid_info, 0);
- rv = 0;
- }
- free(edid_info);
+ bool rv = false;
+
+ if (edid_info == NULL)
+ edid_info = efifb_gop_get_edid(gop);
+
+ if (edid_info != NULL)
+ rv = gfx_get_edid_resolution(edid_info, res);
+
return (rv);
}
@@ -548,13 +540,22 @@ static void
print_efifb(int mode, struct efi_fb *efifb, int verbose)
{
uint_t depth;
- UINT32 width, height;
+ edid_res_list_t res;
+ struct resolution *rp;
+ TAILQ_INIT(&res);
if (verbose == 1) {
printf("Framebuffer mode: %s\n",
plat_stdout_is_framebuffer() ? "on" : "off");
- if (efifb_get_edid(&width, &height) == 0)
- printf("EDID mode: %dx%d\n\n", width, height);
+ if (efifb_get_edid(&res)) {
+ printf("EDID");
+ while ((rp = TAILQ_FIRST(&res)) != NULL) {
+ printf(" %dx%d", rp->width, rp->height);
+ TAILQ_REMOVE(&res, rp, next);
+ free(rp);
+ }
+ printf("\n");
+ }
}
if (mode >= 0) {
@@ -665,12 +666,23 @@ efifb_find_mode(char *str)
static uint32_t
gop_default_mode(void)
{
+ edid_res_list_t res;
+ struct resolution *rp;
extern EFI_GRAPHICS_OUTPUT *gop;
- UINT32 mode, width = 0, height = 0;
+ UINT32 mode;
mode = gop->Mode->MaxMode;
- if (efifb_get_edid(&width, &height) == 0)
- mode = efifb_find_mode_xydm(width, height, -1, -1);
+ TAILQ_INIT(&res);
+ if (efifb_get_edid(&res)) {
+ while ((rp = TAILQ_FIRST(&res)) != NULL) {
+ if (mode == gop->Mode->MaxMode) {
+ mode = efifb_find_mode_xydm(
+ rp->width, rp->height, -1, -1);
+ }
+ TAILQ_REMOVE(&res, rp, next);
+ free(rp);
+ }
+ }
if (mode == gop->Mode->MaxMode)
mode = default_mode;