Blame view
drivers/video/efifb.c
9.62 KB
7c83172b9 x86_64 EFI boot s... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * Framebuffer driver for EFI/UEFI based system * * (c) 2006 Edgar Hucek <gimli@dark-green.com> * Original efi driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de> * */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/fb.h> #include <linux/platform_device.h> #include <linux/screen_info.h> |
7c08c9ae0 efifb/imacfb cons... |
15 |
#include <linux/dmi.h> |
85a00d9bb efifb: check that... |
16 |
#include <linux/pci.h> |
7c83172b9 x86_64 EFI boot s... |
17 |
#include <video/vga.h> |
2995e5062 x86: sysfb: move ... |
18 |
#include <asm/sysfb.h> |
7c83172b9 x86_64 EFI boot s... |
19 |
|
da0241f12 efifb: Fix mismat... |
20 |
static bool request_mem_succeeded = false; |
b4aa01630 efifb: Implement ... |
21 |
static struct pci_dev *default_vga; |
48c68c4f1 Drivers: video: r... |
22 |
static struct fb_var_screeninfo efifb_defined = { |
7c83172b9 x86_64 EFI boot s... |
23 24 25 26 27 28 29 30 31 |
.activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, .right_margin = 32, .upper_margin = 16, .lower_margin = 4, .vsync_len = 4, .vmode = FB_VMODE_NONINTERLACED, }; |
48c68c4f1 Drivers: video: r... |
32 |
static struct fb_fix_screeninfo efifb_fix = { |
7c83172b9 x86_64 EFI boot s... |
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
.id = "EFI VGA", .type = FB_TYPE_PACKED_PIXELS, .accel = FB_ACCEL_NONE, .visual = FB_VISUAL_TRUECOLOR, }; static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) { /* * Set a single color register. The values supplied are * already rounded down to the hardware's capabilities * (according to the entries in the `var' structure). Return * != 0 for invalid regno. */ if (regno >= info->cmap.len) return 1; if (regno < 16) { red >>= 8; green >>= 8; blue >>= 8; ((u32 *)(info->pseudo_palette))[regno] = (red << info->var.red.offset) | (green << info->var.green.offset) | (blue << info->var.blue.offset); } return 0; } |
89f3f2199 efifb: fix frameb... |
64 65 66 67 |
static void efifb_destroy(struct fb_info *info) { if (info->screen_base) iounmap(info->screen_base); |
da0241f12 efifb: Fix mismat... |
68 69 70 |
if (request_mem_succeeded) release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); |
907355a97 Release efifb's c... |
71 |
fb_dealloc_cmap(&info->cmap); |
89f3f2199 efifb: fix frameb... |
72 73 |
framebuffer_release(info); } |
7c83172b9 x86_64 EFI boot s... |
74 75 |
static struct fb_ops efifb_ops = { .owner = THIS_MODULE, |
89f3f2199 efifb: fix frameb... |
76 |
.fb_destroy = efifb_destroy, |
7c83172b9 x86_64 EFI boot s... |
77 78 79 80 81 |
.fb_setcolreg = efifb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, }; |
b4aa01630 efifb: Implement ... |
82 83 84 85 |
struct pci_dev *vga_default_device(void) { return default_vga; } |
1b23170a8 vga: fix build wh... |
86 |
EXPORT_SYMBOL_GPL(vga_default_device); |
b4aa01630 efifb: Implement ... |
87 88 89 90 |
void vga_set_default_device(struct pci_dev *pdev) { default_vga = pdev; } |
e6816a8d8 fbdev: efifb: bin... |
91 |
static int efifb_setup(char *options) |
7c08c9ae0 efifb/imacfb cons... |
92 93 94 |
{ char *this_opt; int i; |
b4aa01630 efifb: Implement ... |
95 |
struct pci_dev *dev = NULL; |
7c08c9ae0 efifb/imacfb cons... |
96 |
|
b4aa01630 efifb: Implement ... |
97 98 99 |
if (options && *options) { while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; |
7c08c9ae0 efifb/imacfb cons... |
100 |
|
b4aa01630 efifb: Implement ... |
101 |
for (i = 0; i < M_UNKNOWN; i++) { |
55aa42f2e efifb: prevent nu... |
102 103 |
if (efifb_dmi_list[i].base != 0 && !strcmp(this_opt, efifb_dmi_list[i].optname)) { |
2995e5062 x86: sysfb: move ... |
104 105 106 107 |
screen_info.lfb_base = efifb_dmi_list[i].base; screen_info.lfb_linelength = efifb_dmi_list[i].stride; screen_info.lfb_width = efifb_dmi_list[i].width; screen_info.lfb_height = efifb_dmi_list[i].height; |
b4aa01630 efifb: Implement ... |
108 |
} |
7c08c9ae0 efifb/imacfb cons... |
109 |
} |
b4aa01630 efifb: Implement ... |
110 111 112 113 114 115 116 117 |
if (!strncmp(this_opt, "base:", 5)) screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0); else if (!strncmp(this_opt, "stride:", 7)) screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4; else if (!strncmp(this_opt, "height:", 7)) screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0); else if (!strncmp(this_opt, "width:", 6)) screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); |
7c08c9ae0 efifb/imacfb cons... |
118 |
} |
7c08c9ae0 efifb/imacfb cons... |
119 |
} |
b4aa01630 efifb: Implement ... |
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
for_each_pci_dev(dev) { int i; if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) continue; for (i=0; i < DEVICE_COUNT_RESOURCE; i++) { resource_size_t start, end; if (!(pci_resource_flags(dev, i) & IORESOURCE_MEM)) continue; start = pci_resource_start(dev, i); end = pci_resource_end(dev, i); if (!start || !end) continue; if (screen_info.lfb_base >= start && (screen_info.lfb_base + screen_info.lfb_size) < end) default_vga = dev; } } |
7c08c9ae0 efifb/imacfb cons... |
144 145 |
return 0; } |
e6816a8d8 fbdev: efifb: bin... |
146 |
static int efifb_probe(struct platform_device *dev) |
7c83172b9 x86_64 EFI boot s... |
147 148 149 150 151 152 |
{ struct fb_info *info; int err; unsigned int size_vmode; unsigned int size_remap; unsigned int size_total; |
e6816a8d8 fbdev: efifb: bin... |
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
char *option = NULL; if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) return -ENODEV; if (fb_get_options("efifb", &option)) return -ENODEV; efifb_setup(option); /* We don't get linelength from UGA Draw Protocol, only from * EFI Graphics Protocol. So if it's not in DMI, and it's not * passed in from the user, we really can't use the framebuffer. */ if (!screen_info.lfb_linelength) return -ENODEV; |
7c08c9ae0 efifb/imacfb cons... |
168 |
|
7c08c9ae0 efifb/imacfb cons... |
169 170 171 172 |
if (!screen_info.lfb_depth) screen_info.lfb_depth = 32; if (!screen_info.pages) screen_info.pages = 1; |
133bb070e efifb: exit if fr... |
173 174 175 176 177 178 179 |
if (!screen_info.lfb_base) { printk(KERN_DEBUG "efifb: invalid framebuffer address "); return -ENODEV; } printk(KERN_INFO "efifb: probing for efifb "); |
7c08c9ae0 efifb/imacfb cons... |
180 181 182 183 184 185 186 187 188 189 190 191 |
/* just assume they're all unset if any are */ if (!screen_info.blue_size) { screen_info.blue_size = 8; screen_info.blue_pos = 0; screen_info.green_size = 8; screen_info.green_pos = 8; screen_info.red_size = 8; screen_info.red_pos = 16; screen_info.rsvd_size = 8; screen_info.rsvd_pos = 24; } |
7c83172b9 x86_64 EFI boot s... |
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
efifb_fix.smem_start = screen_info.lfb_base; efifb_defined.bits_per_pixel = screen_info.lfb_depth; efifb_defined.xres = screen_info.lfb_width; efifb_defined.yres = screen_info.lfb_height; efifb_fix.line_length = screen_info.lfb_linelength; /* size_vmode -- that is the amount of memory needed for the * used video mode, i.e. the minimum amount of * memory we need. */ size_vmode = efifb_defined.yres * efifb_fix.line_length; /* size_total -- all video memory we have. Used for * entries, ressource allocation and bounds * checking. */ size_total = screen_info.lfb_size; if (size_total < size_vmode) size_total = size_vmode; /* size_remap -- the amount of video memory we are going to * use for efifb. With modern cards it is no * option to simply use size_total as that * wastes plenty of kernel address space. */ size_remap = size_vmode * 2; |
7c83172b9 x86_64 EFI boot s... |
216 217 |
if (size_remap > size_total) size_remap = size_total; |
7c08c9ae0 efifb/imacfb cons... |
218 219 |
if (size_remap % PAGE_SIZE) size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE); |
7c83172b9 x86_64 EFI boot s... |
220 |
efifb_fix.smem_len = size_remap; |
7c08c9ae0 efifb/imacfb cons... |
221 |
if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) { |
da0241f12 efifb: Fix mismat... |
222 |
request_mem_succeeded = true; |
7c08c9ae0 efifb/imacfb cons... |
223 |
} else { |
7c83172b9 x86_64 EFI boot s... |
224 225 226 227 228 229 |
/* We cannot make this fatal. Sometimes this comes from magic spaces our resource handlers simply don't know about */ printk(KERN_WARNING "efifb: cannot reserve video memory at 0x%lx ", efifb_fix.smem_start); |
7c08c9ae0 efifb/imacfb cons... |
230 |
} |
7c83172b9 x86_64 EFI boot s... |
231 232 233 |
info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); if (!info) { |
7c08c9ae0 efifb/imacfb cons... |
234 235 |
printk(KERN_ERR "efifb: cannot allocate framebuffer "); |
7c83172b9 x86_64 EFI boot s... |
236 237 238 239 240 |
err = -ENOMEM; goto err_release_mem; } info->pseudo_palette = info->par; info->par = NULL; |
1471ca9aa fbdev: allow pass... |
241 242 243 244 245 246 247 |
info->apertures = alloc_apertures(1); if (!info->apertures) { err = -ENOMEM; goto err_release_fb; } info->apertures->ranges[0].base = efifb_fix.smem_start; info->apertures->ranges[0].size = size_remap; |
4410f3910 fbdev: add suppor... |
248 |
|
3c004b4f7 efifb: Enable wri... |
249 |
info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len); |
7c83172b9 x86_64 EFI boot s... |
250 251 252 253 254 255 |
if (!info->screen_base) { printk(KERN_ERR "efifb: abort, cannot ioremap video memory " "0x%x @ 0x%lx ", efifb_fix.smem_len, efifb_fix.smem_start); err = -EIO; |
7c08c9ae0 efifb/imacfb cons... |
256 |
goto err_release_fb; |
7c83172b9 x86_64 EFI boot s... |
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
} printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, " "using %dk, total %dk ", efifb_fix.smem_start, info->screen_base, size_remap/1024, size_total/1024); printk(KERN_INFO "efifb: mode is %dx%dx%d, linelength=%d, pages=%d ", efifb_defined.xres, efifb_defined.yres, efifb_defined.bits_per_pixel, efifb_fix.line_length, screen_info.pages); efifb_defined.xres_virtual = efifb_defined.xres; efifb_defined.yres_virtual = efifb_fix.smem_len / efifb_fix.line_length; printk(KERN_INFO "efifb: scrolling: redraw "); efifb_defined.yres_virtual = efifb_defined.yres; /* some dummy values for timing to make fbset happy */ efifb_defined.pixclock = 10000000 / efifb_defined.xres * 1000 / efifb_defined.yres; efifb_defined.left_margin = (efifb_defined.xres / 8) & 0xf8; efifb_defined.hsync_len = (efifb_defined.xres / 8) & 0xf8; efifb_defined.red.offset = screen_info.red_pos; efifb_defined.red.length = screen_info.red_size; efifb_defined.green.offset = screen_info.green_pos; efifb_defined.green.length = screen_info.green_size; efifb_defined.blue.offset = screen_info.blue_pos; efifb_defined.blue.length = screen_info.blue_size; efifb_defined.transp.offset = screen_info.rsvd_pos; efifb_defined.transp.length = screen_info.rsvd_size; printk(KERN_INFO "efifb: %s: " "size=%d:%d:%d:%d, shift=%d:%d:%d:%d ", "Truecolor", screen_info.rsvd_size, screen_info.red_size, screen_info.green_size, screen_info.blue_size, screen_info.rsvd_pos, screen_info.red_pos, screen_info.green_pos, screen_info.blue_pos); efifb_fix.ypanstep = 0; efifb_fix.ywrapstep = 0; info->fbops = &efifb_ops; info->var = efifb_defined; info->fix = efifb_fix; |
4410f3910 fbdev: add suppor... |
311 |
info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; |
7c83172b9 x86_64 EFI boot s... |
312 |
|
7c08c9ae0 efifb/imacfb cons... |
313 314 315 |
if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) { printk(KERN_ERR "efifb: cannot allocate colormap "); |
7c83172b9 x86_64 EFI boot s... |
316 317 |
goto err_unmap; } |
7c08c9ae0 efifb/imacfb cons... |
318 319 320 |
if ((err = register_framebuffer(info)) < 0) { printk(KERN_ERR "efifb: cannot register framebuffer "); |
7c83172b9 x86_64 EFI boot s... |
321 322 |
goto err_fb_dealoc; } |
31b6780c1 framebuffer: Use ... |
323 324 |
fb_info(info, "%s frame buffer device ", info->fix.id); |
7c83172b9 x86_64 EFI boot s... |
325 326 327 328 329 330 |
return 0; err_fb_dealoc: fb_dealloc_cmap(&info->cmap); err_unmap: iounmap(info->screen_base); |
7c08c9ae0 efifb/imacfb cons... |
331 |
err_release_fb: |
7c83172b9 x86_64 EFI boot s... |
332 333 |
framebuffer_release(info); err_release_mem: |
da0241f12 efifb: Fix mismat... |
334 |
if (request_mem_succeeded) |
7c08c9ae0 efifb/imacfb cons... |
335 |
release_mem_region(efifb_fix.smem_start, size_total); |
7c83172b9 x86_64 EFI boot s... |
336 337 338 339 |
return err; } static struct platform_driver efifb_driver = { |
e6816a8d8 fbdev: efifb: bin... |
340 341 342 |
.driver = { .name = "efi-framebuffer", .owner = THIS_MODULE, |
7c83172b9 x86_64 EFI boot s... |
343 |
}, |
e6816a8d8 fbdev: efifb: bin... |
344 |
.probe = efifb_probe, |
7c83172b9 x86_64 EFI boot s... |
345 |
}; |
e6816a8d8 fbdev: efifb: bin... |
346 |
module_platform_driver(efifb_driver); |
7c83172b9 x86_64 EFI boot s... |
347 |
MODULE_LICENSE("GPL"); |