1be8d3241SAlexander Graf /* 2be8d3241SAlexander Graf * EFI application disk support 3be8d3241SAlexander Graf * 4be8d3241SAlexander Graf * Copyright (c) 2016 Alexander Graf 5be8d3241SAlexander Graf * 6be8d3241SAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 7be8d3241SAlexander Graf */ 8be8d3241SAlexander Graf 9be8d3241SAlexander Graf #include <common.h> 10*a8122410SAlexander Graf #include <dm.h> 11be8d3241SAlexander Graf #include <efi_loader.h> 12be8d3241SAlexander Graf #include <inttypes.h> 13be8d3241SAlexander Graf #include <lcd.h> 14be8d3241SAlexander Graf #include <malloc.h> 15*a8122410SAlexander Graf #include <video.h> 16be8d3241SAlexander Graf 17be8d3241SAlexander Graf DECLARE_GLOBAL_DATA_PTR; 18be8d3241SAlexander Graf 19be8d3241SAlexander Graf static const efi_guid_t efi_gop_guid = EFI_GOP_GUID; 20be8d3241SAlexander Graf 21be8d3241SAlexander Graf struct efi_gop_obj { 22be8d3241SAlexander Graf /* Generic EFI object parent class data */ 23be8d3241SAlexander Graf struct efi_object parent; 24be8d3241SAlexander Graf /* EFI Interface callback struct for gop */ 25be8d3241SAlexander Graf struct efi_gop ops; 26be8d3241SAlexander Graf /* The only mode we support */ 27be8d3241SAlexander Graf struct efi_gop_mode_info info; 28be8d3241SAlexander Graf struct efi_gop_mode mode; 29*a8122410SAlexander Graf /* Fields we only have acces to during init */ 30*a8122410SAlexander Graf u32 bpix; 31be8d3241SAlexander Graf }; 32be8d3241SAlexander Graf 33be8d3241SAlexander Graf static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number, 34be8d3241SAlexander Graf unsigned long *size_of_info, 35be8d3241SAlexander Graf struct efi_gop_mode_info **info) 36be8d3241SAlexander Graf { 37be8d3241SAlexander Graf struct efi_gop_obj *gopobj; 38be8d3241SAlexander Graf 39be8d3241SAlexander Graf EFI_ENTRY("%p, %x, %p, %p", this, mode_number, size_of_info, info); 40be8d3241SAlexander Graf 41be8d3241SAlexander Graf gopobj = container_of(this, struct efi_gop_obj, ops); 42be8d3241SAlexander Graf *size_of_info = sizeof(gopobj->info); 43be8d3241SAlexander Graf *info = &gopobj->info; 44be8d3241SAlexander Graf 45be8d3241SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 46be8d3241SAlexander Graf } 47be8d3241SAlexander Graf 48be8d3241SAlexander Graf static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number) 49be8d3241SAlexander Graf { 50be8d3241SAlexander Graf EFI_ENTRY("%p, %x", this, mode_number); 51be8d3241SAlexander Graf 52be8d3241SAlexander Graf if (mode_number != 0) 53be8d3241SAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 54be8d3241SAlexander Graf 55be8d3241SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 56be8d3241SAlexander Graf } 57be8d3241SAlexander Graf 58be8d3241SAlexander Graf static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, 59be8d3241SAlexander Graf unsigned long operation, unsigned long sx, 60be8d3241SAlexander Graf unsigned long sy, unsigned long dx, 61be8d3241SAlexander Graf unsigned long dy, unsigned long width, 62be8d3241SAlexander Graf unsigned long height, unsigned long delta) 63be8d3241SAlexander Graf { 64*a8122410SAlexander Graf struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops); 65be8d3241SAlexander Graf int i, j, line_len16, line_len32; 66be8d3241SAlexander Graf void *fb; 67be8d3241SAlexander Graf 68be8d3241SAlexander Graf EFI_ENTRY("%p, %p, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx", this, 69be8d3241SAlexander Graf buffer, operation, sx, sy, dx, dy, width, height, delta); 70be8d3241SAlexander Graf 71be8d3241SAlexander Graf if (operation != EFI_BLT_BUFFER_TO_VIDEO) 72be8d3241SAlexander Graf return EFI_EXIT(EFI_INVALID_PARAMETER); 73be8d3241SAlexander Graf 74be8d3241SAlexander Graf fb = (void*)gd->fb_base; 75*a8122410SAlexander Graf line_len16 = gopobj->info.width * sizeof(u16); 76*a8122410SAlexander Graf line_len32 = gopobj->info.width * sizeof(u32); 77be8d3241SAlexander Graf 78be8d3241SAlexander Graf /* Copy the contents line by line */ 79be8d3241SAlexander Graf 80*a8122410SAlexander Graf switch (gopobj->bpix) { 81*a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO 82*a8122410SAlexander Graf case VIDEO_BPP32: 83*a8122410SAlexander Graf #else 84be8d3241SAlexander Graf case LCD_COLOR32: 85*a8122410SAlexander Graf #endif 86be8d3241SAlexander Graf for (i = 0; i < height; i++) { 87be8d3241SAlexander Graf u32 *dest = fb + ((i + dy) * line_len32) + 88be8d3241SAlexander Graf (dx * sizeof(u32)); 89be8d3241SAlexander Graf u32 *src = buffer + ((i + sy) * line_len32) + 90be8d3241SAlexander Graf (sx * sizeof(u32)); 91be8d3241SAlexander Graf 92be8d3241SAlexander Graf /* Same color format, just memcpy */ 93be8d3241SAlexander Graf memcpy(dest, src, width * sizeof(u32)); 94be8d3241SAlexander Graf } 95be8d3241SAlexander Graf break; 96*a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO 97*a8122410SAlexander Graf case VIDEO_BPP16: 98*a8122410SAlexander Graf #else 99be8d3241SAlexander Graf case LCD_COLOR16: 100*a8122410SAlexander Graf #endif 101be8d3241SAlexander Graf for (i = 0; i < height; i++) { 102be8d3241SAlexander Graf u16 *dest = fb + ((i + dy) * line_len16) + 103be8d3241SAlexander Graf (dx * sizeof(u16)); 104be8d3241SAlexander Graf u32 *src = buffer + ((i + sy) * line_len32) + 105be8d3241SAlexander Graf (sx * sizeof(u32)); 106be8d3241SAlexander Graf 107be8d3241SAlexander Graf /* Convert from rgb888 to rgb565 */ 108be8d3241SAlexander Graf for (j = 0; j < width; j++) { 109be8d3241SAlexander Graf u32 rgb888 = src[j]; 110be8d3241SAlexander Graf dest[j] = ((((rgb888 >> (16 + 3)) & 0x1f) << 11) | 111be8d3241SAlexander Graf (((rgb888 >> (8 + 2)) & 0x3f) << 5) | 112be8d3241SAlexander Graf (((rgb888 >> (0 + 3)) & 0x1f) << 0)); 113be8d3241SAlexander Graf } 114be8d3241SAlexander Graf } 115be8d3241SAlexander Graf break; 116be8d3241SAlexander Graf } 117be8d3241SAlexander Graf 118*a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO 119*a8122410SAlexander Graf video_sync_all(); 120*a8122410SAlexander Graf #else 121be8d3241SAlexander Graf lcd_sync(); 122*a8122410SAlexander Graf #endif 123be8d3241SAlexander Graf 124be8d3241SAlexander Graf return EFI_EXIT(EFI_SUCCESS); 125be8d3241SAlexander Graf } 126be8d3241SAlexander Graf 127be8d3241SAlexander Graf /* This gets called from do_bootefi_exec(). */ 128be8d3241SAlexander Graf int efi_gop_register(void) 129be8d3241SAlexander Graf { 130be8d3241SAlexander Graf struct efi_gop_obj *gopobj; 131*a8122410SAlexander Graf u32 bpix, col, row; 132be8d3241SAlexander Graf 133*a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO 134*a8122410SAlexander Graf struct udevice *vdev; 135*a8122410SAlexander Graf 136*a8122410SAlexander Graf /* We only support a single video output device for now */ 137*a8122410SAlexander Graf if (uclass_first_device(UCLASS_VIDEO, &vdev)) 138*a8122410SAlexander Graf return -1; 139*a8122410SAlexander Graf 140*a8122410SAlexander Graf struct video_priv *priv = dev_get_uclass_priv(vdev); 141*a8122410SAlexander Graf bpix = priv->bpix; 142*a8122410SAlexander Graf col = video_get_xsize(vdev); 143*a8122410SAlexander Graf row = video_get_ysize(vdev); 144*a8122410SAlexander Graf #else 145*a8122410SAlexander Graf 146*a8122410SAlexander Graf bpix = panel_info.vl_bpix; 147*a8122410SAlexander Graf col = panel_info.vl_col; 148*a8122410SAlexander Graf row = panel_info.vl_row; 149*a8122410SAlexander Graf #endif 150*a8122410SAlexander Graf 151*a8122410SAlexander Graf switch (bpix) { 152*a8122410SAlexander Graf #ifdef CONFIG_DM_VIDEO 153*a8122410SAlexander Graf case VIDEO_BPP16: 154*a8122410SAlexander Graf case VIDEO_BPP32: 155*a8122410SAlexander Graf #else 156be8d3241SAlexander Graf case LCD_COLOR32: 157be8d3241SAlexander Graf case LCD_COLOR16: 158*a8122410SAlexander Graf #endif 159be8d3241SAlexander Graf break; 160be8d3241SAlexander Graf default: 161be8d3241SAlexander Graf /* So far, we only work in 16 or 32 bit mode */ 162be8d3241SAlexander Graf return -1; 163be8d3241SAlexander Graf } 164be8d3241SAlexander Graf 165be8d3241SAlexander Graf gopobj = calloc(1, sizeof(*gopobj)); 166be8d3241SAlexander Graf 167be8d3241SAlexander Graf /* Fill in object data */ 168be8d3241SAlexander Graf gopobj->parent.protocols[0].guid = &efi_gop_guid; 169be8d3241SAlexander Graf gopobj->parent.protocols[0].open = efi_return_handle; 170be8d3241SAlexander Graf gopobj->parent.handle = &gopobj->ops; 171be8d3241SAlexander Graf gopobj->ops.query_mode = gop_query_mode; 172be8d3241SAlexander Graf gopobj->ops.set_mode = gop_set_mode; 173be8d3241SAlexander Graf gopobj->ops.blt = gop_blt; 174be8d3241SAlexander Graf gopobj->ops.mode = &gopobj->mode; 175be8d3241SAlexander Graf 176be8d3241SAlexander Graf gopobj->mode.max_mode = 1; 177be8d3241SAlexander Graf gopobj->mode.info = &gopobj->info; 178be8d3241SAlexander Graf gopobj->mode.info_size = sizeof(gopobj->info); 179be8d3241SAlexander Graf 180be8d3241SAlexander Graf gopobj->info.version = 0; 181*a8122410SAlexander Graf gopobj->info.width = col; 182*a8122410SAlexander Graf gopobj->info.height = row; 183be8d3241SAlexander Graf gopobj->info.pixel_format = EFI_GOT_RGBA8; 184*a8122410SAlexander Graf gopobj->info.pixels_per_scanline = col; 185*a8122410SAlexander Graf 186*a8122410SAlexander Graf gopobj->bpix = bpix; 187be8d3241SAlexander Graf 188be8d3241SAlexander Graf /* Hook up to the device list */ 189be8d3241SAlexander Graf list_add_tail(&gopobj->parent.link, &efi_obj_list); 190be8d3241SAlexander Graf 191be8d3241SAlexander Graf return 0; 192be8d3241SAlexander Graf } 193