diff options
-rw-r--r-- | cmd/bootefi.c | 3 | ||||
-rw-r--r-- | include/efi_api.h | 47 | ||||
-rw-r--r-- | include/efi_loader.h | 2 | ||||
-rw-r--r-- | lib/efi_loader/Makefile | 1 | ||||
-rw-r--r-- | lib/efi_loader/efi_gop.c | 152 |
5 files changed, 205 insertions, 0 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 2f0b90a..3add632 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -141,6 +141,9 @@ static unsigned long do_bootefi_exec(void *efi) #ifdef CONFIG_PARTITIONS efi_disk_register(); #endif +#ifdef CONFIG_LCD + efi_gop_register(); +#endif /* Call our payload! */ #ifdef DEBUG_EFI diff --git a/include/efi_api.h b/include/efi_api.h index 03f6687..6960448 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -365,4 +365,51 @@ struct efi_console_control_protocol uint16_t *password); }; +#define EFI_GOP_GUID \ + EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, \ + 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) + +#define EFI_GOT_RGBA8 0 +#define EFI_GOT_BGRA8 1 +#define EFI_GOT_BITMASK 2 + +struct efi_gop_mode_info +{ + u32 version; + u32 width; + u32 height; + u32 pixel_format; + u32 pixel_bitmask[4]; + u32 pixels_per_scanline; +}; + +struct efi_gop_mode +{ + u32 max_mode; + u32 mode; + struct efi_gop_mode_info *info; + unsigned long info_size; + efi_physical_addr_t fb_base; + unsigned long fb_size; +}; + +#define EFI_BLT_VIDEO_FILL 0 +#define EFI_BLT_VIDEO_TO_BLT_BUFFER 1 +#define EFI_BLT_BUFFER_TO_VIDEO 2 +#define EFI_BLT_VIDEO_TO_VIDEO 3 + +struct efi_gop +{ + efi_status_t (EFIAPI *query_mode)(struct efi_gop *this, u32 mode_number, + unsigned long *size_of_info, + struct efi_gop_mode_info **info); + efi_status_t (EFIAPI *set_mode)(struct efi_gop *this, u32 mode_number); + efi_status_t (EFIAPI *blt)(struct efi_gop *this, void *buffer, + unsigned long operation, unsigned long sx, + unsigned long sy, unsigned long dx, + unsigned long dy, unsigned long width, + unsigned long height, unsigned long delta); + struct efi_gop_mode *mode; +}; + #endif diff --git a/include/efi_loader.h b/include/efi_loader.h index 74bed26..9f61fc4 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -89,6 +89,8 @@ extern struct list_head efi_obj_list; /* Called by bootefi to make all disk storage accessible as EFI objects */ int efi_disk_register(void); +/* Called by bootefi to make GOP (graphical) interface available */ +int efi_gop_register(void); /* * Stub implementation for a protocol opener that just returns the handle as * interface diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 28725a2..83e31f6 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -9,4 +9,5 @@ obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o +obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c new file mode 100644 index 0000000..bdd62bc --- /dev/null +++ b/lib/efi_loader/efi_gop.c @@ -0,0 +1,152 @@ +/* + * EFI application disk support + * + * Copyright (c) 2016 Alexander Graf + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <efi_loader.h> +#include <inttypes.h> +#include <lcd.h> +#include <malloc.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const efi_guid_t efi_gop_guid = EFI_GOP_GUID; + +struct efi_gop_obj { + /* Generic EFI object parent class data */ + struct efi_object parent; + /* EFI Interface callback struct for gop */ + struct efi_gop ops; + /* The only mode we support */ + struct efi_gop_mode_info info; + struct efi_gop_mode mode; +}; + +static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number, + unsigned long *size_of_info, + struct efi_gop_mode_info **info) +{ + struct efi_gop_obj *gopobj; + + EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info); + + gopobj = container_of(this, struct efi_gop_obj, ops); + *size_of_info = sizeof(gopobj->info); + *info = &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); +} + +static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, + unsigned long operation, unsigned long sx, + unsigned long sy, unsigned long dx, + unsigned long dy, unsigned long width, + unsigned long height, unsigned long delta) +{ + int i, j, line_len16, line_len32; + void *fb; + + EFI_ENTRY("%p, %p, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx", this, + buffer, operation, sx, sy, dx, dy, width, height, delta); + + if (operation != EFI_BLT_BUFFER_TO_VIDEO) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + fb = (void*)gd->fb_base; + line_len16 = panel_info.vl_col * sizeof(u16); + line_len32 = panel_info.vl_col * sizeof(u32); + + /* Copy the contents line by line */ + + switch (panel_info.vl_bpix) { + case LCD_COLOR32: + for (i = 0; i < height; i++) { + u32 *dest = fb + ((i + dy) * line_len32) + + (dx * sizeof(u32)); + u32 *src = buffer + ((i + sy) * line_len32) + + (sx * sizeof(u32)); + + /* Same color format, just memcpy */ + memcpy(dest, src, width * sizeof(u32)); + } + break; + case LCD_COLOR16: + for (i = 0; i < height; i++) { + u16 *dest = fb + ((i + dy) * line_len16) + + (dx * sizeof(u16)); + u32 *src = buffer + ((i + sy) * line_len32) + + (sx * sizeof(u32)); + + /* Convert from rgb888 to rgb565 */ + for (j = 0; j < width; j++) { + u32 rgb888 = src[j]; + dest[j] = ((((rgb888 >> (16 + 3)) & 0x1f) << 11) | + (((rgb888 >> (8 + 2)) & 0x3f) << 5) | + (((rgb888 >> (0 + 3)) & 0x1f) << 0)); + } + } + break; + } + + lcd_sync(); + + return EFI_EXIT(EFI_SUCCESS); +} + +/* This gets called from do_bootefi_exec(). */ +int efi_gop_register(void) +{ + struct efi_gop_obj *gopobj; + int line_len; + + switch (panel_info.vl_bpix) { + case LCD_COLOR32: + case LCD_COLOR16: + break; + default: + /* So far, we only work in 16 or 32 bit mode */ + return -1; + } + + gopobj = calloc(1, sizeof(*gopobj)); + + /* Fill in object data */ + gopobj->parent.protocols[0].guid = &efi_gop_guid; + gopobj->parent.protocols[0].open = efi_return_handle; + gopobj->parent.handle = &gopobj->ops; + gopobj->ops.query_mode = gop_query_mode; + gopobj->ops.set_mode = gop_set_mode; + gopobj->ops.blt = gop_blt; + gopobj->ops.mode = &gopobj->mode; + + gopobj->mode.max_mode = 1; + gopobj->mode.info = &gopobj->info; + gopobj->mode.info_size = sizeof(gopobj->info); + gopobj->mode.fb_base = gd->fb_base; + gopobj->mode.fb_size = lcd_get_size(&line_len); + + gopobj->info.version = 0; + gopobj->info.width = panel_info.vl_col; + gopobj->info.height = panel_info.vl_row; + gopobj->info.pixel_format = EFI_GOT_RGBA8; + gopobj->info.pixels_per_scanline = panel_info.vl_col; + + /* Hook up to the device list */ + list_add_tail(&gopobj->parent.link, &efi_obj_list); + + return 0; +} |