Merge tag 'efi-2020-04-rc4-5' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/u-boot.git] / lib / efi_loader / efi_gop.c
index 1afe8418e127342771b9989ef115d5c69bff5d73..1511e3bdb4220ce8a61be4ee4aa56b456ccad0f9 100644 (file)
@@ -8,24 +8,30 @@
 #include <common.h>
 #include <dm.h>
 #include <efi_loader.h>
-#include <inttypes.h>
 #include <lcd.h>
 #include <malloc.h>
 #include <video.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static const efi_guid_t efi_gop_guid = EFI_GOP_GUID;
+static const efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
 
+/**
+ * struct efi_gop_obj - graphical output protocol object
+ *
+ * @header:    EFI object header
+ * @ops:       graphical output protocol interface
+ * @info:      graphical output mode information
+ * @mode:      graphical output mode
+ * @bpix:      bits per pixel
+ * @fb:                frame buffer
+ */
 struct efi_gop_obj {
-       /* Generic EFI object parent class data */
-       struct efi_object parent;
-       /* EFI Interface callback struct for gop */
+       struct efi_object header;
        struct efi_gop ops;
-       /* The only mode we support */
        struct efi_gop_mode_info info;
        struct efi_gop_mode mode;
-       /* Fields we only have acces to during init */
+       /* Fields we only have access to during init */
        u32 bpix;
        void *fb;
 };
@@ -35,24 +41,25 @@ static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number,
                                          struct efi_gop_mode_info **info)
 {
        struct efi_gop_obj *gopobj;
+       efi_status_t ret = EFI_SUCCESS;
 
        EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info);
 
+       if (!this || !size_of_info || !info || mode_number) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+
        gopobj = container_of(this, struct efi_gop_obj, ops);
+       ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, sizeof(gopobj->info),
+                               (void **)info);
+       if (ret != EFI_SUCCESS)
+               goto out;
        *size_of_info = sizeof(gopobj->info);
-       *info = &gopobj->info;
+       memcpy(*info, &gopobj->info, sizeof(gopobj->info));
 
-       return EFI_EXIT(EFI_SUCCESS);
-}
-
-static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
-{
-       EFI_ENTRY("%p, %x", this, mode_number);
-
-       if (mode_number != 0)
-               return EFI_EXIT(EFI_INVALID_PARAMETER);
-
-       return EFI_EXIT(EFI_SUCCESS);
+out:
+       return EFI_EXIT(ret);
 }
 
 static __always_inline struct efi_gop_pixel efi_vid16_to_blt_col(u16 vid)
@@ -237,12 +244,12 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this)
 }
 
 /*
- * Gcc can't optimize our BLT function well, but we need to make sure that
+ * GCC can't optimize our BLT function well, but we need to make sure that
  * our 2-dimensional loop gets executed very quickly, otherwise the system
  * will feel slow.
  *
  * By manually putting all obvious branch targets into functions which call
- * our generic blt function with constants, the compiler can successfully
+ * our generic BLT function with constants, the compiler can successfully
  * optimize for speed.
  */
 static efi_status_t gop_blt_video_fill(struct efi_gop *this,
@@ -303,6 +310,44 @@ static efi_status_t gop_blt_vid_to_buf(struct efi_gop *this,
                           dx, dy, width, height, delta, vid_bpp);
 }
 
+/**
+ * gop_set_mode() - set graphical output mode
+ *
+ * This function implements the SetMode() service.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @this:              the graphical output protocol
+ * @mode_number:       the mode to be set
+ * Return:             status code
+ */
+static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
+{
+       struct efi_gop_obj *gopobj;
+       struct efi_gop_pixel buffer = {0, 0, 0, 0};
+       efi_uintn_t vid_bpp;
+       efi_status_t ret = EFI_SUCCESS;
+
+       EFI_ENTRY("%p, %x", this, mode_number);
+
+       if (!this) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+       if (mode_number) {
+               ret = EFI_UNSUPPORTED;
+               goto out;
+       }
+       gopobj = container_of(this, struct efi_gop_obj, ops);
+       vid_bpp = gop_get_bpp(this);
+       ret = gop_blt_video_fill(this, &buffer, EFI_BLT_VIDEO_FILL, 0, 0, 0, 0,
+                                gopobj->info.width, gopobj->info.height, 0,
+                                vid_bpp);
+out:
+       return EFI_EXIT(ret);
+}
+
 /*
  * Copy rectangle.
  *
@@ -361,7 +406,7 @@ efi_status_t EFIAPI gop_blt(struct efi_gop *this, struct efi_gop_pixel *buffer,
                                         dy, width, height, delta, vid_bpp);
                break;
        default:
-               ret = EFI_UNSUPPORTED;
+               ret = EFI_INVALID_PARAMETER;
        }
 
        if (ret != EFI_SUCCESS)
@@ -440,13 +485,13 @@ efi_status_t efi_gop_register(void)
        }
 
        /* Hook up to the device list */
-       efi_add_handle(&gopobj->parent);
+       efi_add_handle(&gopobj->header);
 
        /* Fill in object data */
-       ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid,
+       ret = efi_add_protocol(&gopobj->header, &efi_gop_guid,
                               &gopobj->ops);
        if (ret != EFI_SUCCESS) {
-               printf("ERROR: Failure adding gop protocol\n");
+               printf("ERROR: Failure adding GOP protocol\n");
                return ret;
        }
        gopobj->ops.query_mode = gop_query_mode;
@@ -458,23 +503,26 @@ efi_status_t efi_gop_register(void)
        gopobj->mode.info = &gopobj->info;
        gopobj->mode.info_size = sizeof(gopobj->info);
 
+       gopobj->mode.fb_base = fb_base;
+       gopobj->mode.fb_size = fb_size;
+
+       gopobj->info.version = 0;
+       gopobj->info.width = col;
+       gopobj->info.height = row;
 #ifdef CONFIG_DM_VIDEO
        if (bpix == VIDEO_BPP32)
 #else
        if (bpix == LCD_COLOR32)
 #endif
        {
-               /* With 32bit color space we can directly expose the fb */
-               gopobj->mode.fb_base = fb_base;
-               gopobj->mode.fb_size = fb_size;
+               gopobj->info.pixel_format = EFI_GOT_BGRA8;
+       } else {
+               gopobj->info.pixel_format = EFI_GOT_BITMASK;
+               gopobj->info.pixel_bitmask[0] = 0xf800; /* red */
+               gopobj->info.pixel_bitmask[1] = 0x07e0; /* green */
+               gopobj->info.pixel_bitmask[2] = 0x001f; /* blue */
        }
-
-       gopobj->info.version = 0;
-       gopobj->info.width = col;
-       gopobj->info.height = row;
-       gopobj->info.pixel_format = EFI_GOT_RGBA8;
        gopobj->info.pixels_per_scanline = col;
-
        gopobj->bpix = bpix;
        gopobj->fb = fb;