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