Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86_64 EFI boot support: EFI frame buffer driver

This patch adds Graphics Output Protocol support to the kernel. UEFI2.0 spec
deprecates Universal Graphics Adapter (UGA) protocol and only Graphics Output
Protocol (GOP) is produced. Therefore, the boot loader needs to query the
UEFI firmware with appropriate Output Protocol and pass the video information
to the kernel. As a result of GOP protocol, an EFI framebuffer driver is
needed for displaying console messages. The patch adds a EFI framebuffer
driver. The EFI frame buffer driver in this patch is based on the Intel Mac
framebuffer driver.

The ELILO bootloader takes care of passing the video information as
appropriate for EFI firmware.

The framebuffer driver has been tested in i386 kernel and x86_64 kernel on EFI
platform.

Signed-off-by: Chandramouli Narayanan <mouli@linux.intel.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Andi Kleen <ak@suse.de>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Huang, Ying and committed by
Linus Torvalds
7c83172b f78ba157

+246
+11
drivers/video/Kconfig
··· 641 641 You will get a boot time penguin logo at no additional cost. Please 642 642 read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. 643 643 644 + config FB_EFI 645 + bool "EFI-based Framebuffer Support" 646 + depends on (FB = y) && X86 647 + select FB_CFB_FILLRECT 648 + select FB_CFB_COPYAREA 649 + select FB_CFB_IMAGEBLIT 650 + help 651 + This is the EFI frame buffer device driver. If the firmware on 652 + your platform is UEFI2.0, select Y to add support for 653 + Graphics Output Protocol for early console messages to appear. 654 + 644 655 config FB_IMAC 645 656 bool "Intel-based Macintosh Framebuffer Support" 646 657 depends on (FB = y) && X86 && EFI
+1
drivers/video/Makefile
··· 118 118 obj-$(CONFIG_FB_UVESA) += uvesafb.o 119 119 obj-$(CONFIG_FB_VESA) += vesafb.o 120 120 obj-$(CONFIG_FB_IMAC) += imacfb.o 121 + obj-$(CONFIG_FB_EFI) += efifb.o 121 122 obj-$(CONFIG_FB_VGA16) += vga16fb.o 122 123 obj-$(CONFIG_FB_OF) += offb.o 123 124 obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o
+232
drivers/video/efifb.c
··· 1 + /* 2 + * Framebuffer driver for EFI/UEFI based system 3 + * 4 + * (c) 2006 Edgar Hucek <gimli@dark-green.com> 5 + * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de> 6 + * 7 + */ 8 + 9 + #include <linux/module.h> 10 + #include <linux/kernel.h> 11 + #include <linux/errno.h> 12 + #include <linux/fb.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/screen_info.h> 15 + 16 + #include <video/vga.h> 17 + 18 + static struct fb_var_screeninfo efifb_defined __initdata = { 19 + .activate = FB_ACTIVATE_NOW, 20 + .height = -1, 21 + .width = -1, 22 + .right_margin = 32, 23 + .upper_margin = 16, 24 + .lower_margin = 4, 25 + .vsync_len = 4, 26 + .vmode = FB_VMODE_NONINTERLACED, 27 + }; 28 + 29 + static struct fb_fix_screeninfo efifb_fix __initdata = { 30 + .id = "EFI VGA", 31 + .type = FB_TYPE_PACKED_PIXELS, 32 + .accel = FB_ACCEL_NONE, 33 + .visual = FB_VISUAL_TRUECOLOR, 34 + }; 35 + 36 + static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, 37 + unsigned blue, unsigned transp, 38 + struct fb_info *info) 39 + { 40 + /* 41 + * Set a single color register. The values supplied are 42 + * already rounded down to the hardware's capabilities 43 + * (according to the entries in the `var' structure). Return 44 + * != 0 for invalid regno. 45 + */ 46 + 47 + if (regno >= info->cmap.len) 48 + return 1; 49 + 50 + if (regno < 16) { 51 + red >>= 8; 52 + green >>= 8; 53 + blue >>= 8; 54 + ((u32 *)(info->pseudo_palette))[regno] = 55 + (red << info->var.red.offset) | 56 + (green << info->var.green.offset) | 57 + (blue << info->var.blue.offset); 58 + } 59 + return 0; 60 + } 61 + 62 + static struct fb_ops efifb_ops = { 63 + .owner = THIS_MODULE, 64 + .fb_setcolreg = efifb_setcolreg, 65 + .fb_fillrect = cfb_fillrect, 66 + .fb_copyarea = cfb_copyarea, 67 + .fb_imageblit = cfb_imageblit, 68 + }; 69 + 70 + static int __init efifb_probe(struct platform_device *dev) 71 + { 72 + struct fb_info *info; 73 + int err; 74 + unsigned int size_vmode; 75 + unsigned int size_remap; 76 + unsigned int size_total; 77 + 78 + efifb_fix.smem_start = screen_info.lfb_base; 79 + efifb_defined.bits_per_pixel = screen_info.lfb_depth; 80 + efifb_defined.xres = screen_info.lfb_width; 81 + efifb_defined.yres = screen_info.lfb_height; 82 + efifb_fix.line_length = screen_info.lfb_linelength; 83 + 84 + /* size_vmode -- that is the amount of memory needed for the 85 + * used video mode, i.e. the minimum amount of 86 + * memory we need. */ 87 + size_vmode = efifb_defined.yres * efifb_fix.line_length; 88 + 89 + /* size_total -- all video memory we have. Used for 90 + * entries, ressource allocation and bounds 91 + * checking. */ 92 + size_total = screen_info.lfb_size; 93 + if (size_total < size_vmode) 94 + size_total = size_vmode; 95 + 96 + /* size_remap -- the amount of video memory we are going to 97 + * use for efifb. With modern cards it is no 98 + * option to simply use size_total as that 99 + * wastes plenty of kernel address space. */ 100 + size_remap = size_vmode * 2; 101 + if (size_remap < size_vmode) 102 + size_remap = size_vmode; 103 + if (size_remap > size_total) 104 + size_remap = size_total; 105 + efifb_fix.smem_len = size_remap; 106 + 107 + if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb")) 108 + /* We cannot make this fatal. Sometimes this comes from magic 109 + spaces our resource handlers simply don't know about */ 110 + printk(KERN_WARNING 111 + "efifb: cannot reserve video memory at 0x%lx\n", 112 + efifb_fix.smem_start); 113 + 114 + info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); 115 + if (!info) { 116 + err = -ENOMEM; 117 + goto err_release_mem; 118 + } 119 + info->pseudo_palette = info->par; 120 + info->par = NULL; 121 + 122 + info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); 123 + if (!info->screen_base) { 124 + printk(KERN_ERR "efifb: abort, cannot ioremap video memory " 125 + "0x%x @ 0x%lx\n", 126 + efifb_fix.smem_len, efifb_fix.smem_start); 127 + err = -EIO; 128 + goto err_unmap; 129 + } 130 + 131 + printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, " 132 + "using %dk, total %dk\n", 133 + efifb_fix.smem_start, info->screen_base, 134 + size_remap/1024, size_total/1024); 135 + printk(KERN_INFO "efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", 136 + efifb_defined.xres, efifb_defined.yres, 137 + efifb_defined.bits_per_pixel, efifb_fix.line_length, 138 + screen_info.pages); 139 + 140 + efifb_defined.xres_virtual = efifb_defined.xres; 141 + efifb_defined.yres_virtual = efifb_fix.smem_len / 142 + efifb_fix.line_length; 143 + printk(KERN_INFO "efifb: scrolling: redraw\n"); 144 + efifb_defined.yres_virtual = efifb_defined.yres; 145 + 146 + /* some dummy values for timing to make fbset happy */ 147 + efifb_defined.pixclock = 10000000 / efifb_defined.xres * 148 + 1000 / efifb_defined.yres; 149 + efifb_defined.left_margin = (efifb_defined.xres / 8) & 0xf8; 150 + efifb_defined.hsync_len = (efifb_defined.xres / 8) & 0xf8; 151 + 152 + efifb_defined.red.offset = screen_info.red_pos; 153 + efifb_defined.red.length = screen_info.red_size; 154 + efifb_defined.green.offset = screen_info.green_pos; 155 + efifb_defined.green.length = screen_info.green_size; 156 + efifb_defined.blue.offset = screen_info.blue_pos; 157 + efifb_defined.blue.length = screen_info.blue_size; 158 + efifb_defined.transp.offset = screen_info.rsvd_pos; 159 + efifb_defined.transp.length = screen_info.rsvd_size; 160 + 161 + printk(KERN_INFO "efifb: %s: " 162 + "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", 163 + "Truecolor", 164 + screen_info.rsvd_size, 165 + screen_info.red_size, 166 + screen_info.green_size, 167 + screen_info.blue_size, 168 + screen_info.rsvd_pos, 169 + screen_info.red_pos, 170 + screen_info.green_pos, 171 + screen_info.blue_pos); 172 + 173 + efifb_fix.ypanstep = 0; 174 + efifb_fix.ywrapstep = 0; 175 + 176 + info->fbops = &efifb_ops; 177 + info->var = efifb_defined; 178 + info->fix = efifb_fix; 179 + info->flags = FBINFO_FLAG_DEFAULT; 180 + 181 + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { 182 + err = -ENOMEM; 183 + goto err_unmap; 184 + } 185 + if (register_framebuffer(info) < 0) { 186 + err = -EINVAL; 187 + goto err_fb_dealoc; 188 + } 189 + printk(KERN_INFO "fb%d: %s frame buffer device\n", 190 + info->node, info->fix.id); 191 + return 0; 192 + 193 + err_fb_dealoc: 194 + fb_dealloc_cmap(&info->cmap); 195 + err_unmap: 196 + iounmap(info->screen_base); 197 + framebuffer_release(info); 198 + err_release_mem: 199 + release_mem_region(efifb_fix.smem_start, size_total); 200 + return err; 201 + } 202 + 203 + static struct platform_driver efifb_driver = { 204 + .probe = efifb_probe, 205 + .driver = { 206 + .name = "efifb", 207 + }, 208 + }; 209 + 210 + static struct platform_device efifb_device = { 211 + .name = "efifb", 212 + }; 213 + 214 + static int __init efifb_init(void) 215 + { 216 + int ret; 217 + 218 + if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) 219 + return -ENODEV; 220 + 221 + ret = platform_driver_register(&efifb_driver); 222 + 223 + if (!ret) { 224 + ret = platform_device_register(&efifb_device); 225 + if (ret) 226 + platform_driver_unregister(&efifb_driver); 227 + } 228 + return ret; 229 + } 230 + module_init(efifb_init); 231 + 232 + MODULE_LICENSE("GPL");
+2
include/linux/screen_info.h
··· 63 63 64 64 #define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */ 65 65 66 + #define VIDEO_TYPE_EFI 0x70 /* EFI graphic mode */ 67 + 66 68 #ifdef __KERNEL__ 67 69 extern struct screen_info screen_info; 68 70