Commit 7c83172b98e569d9aabf947d8b3b089dadb2ff46

Authored by Huang, Ying
Committed by Linus Torvalds
1 parent f78ba15705

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>

Showing 4 changed files with 246 additions and 0 deletions Side-by-side Diff

drivers/video/Kconfig
... ... @@ -641,6 +641,17 @@
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
drivers/video/Makefile
... ... @@ -118,6 +118,7 @@
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
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");
include/linux/screen_info.h
... ... @@ -63,6 +63,8 @@
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