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