// SPDX-License-Identifier: GPL-2.0 /* * 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> *
*/
staticint 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 >>= 16 - info->var.red.length;
green >>= 16 - info->var.green.length;
blue >>= 16 - info->var.blue.length;
((u32 *)(info->pseudo_palette))[regno] =
(red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
} return 0;
}
/* * If fbcon deffered console takeover is configured, the intent is for the * framebuffer to show the boot graphics (e.g. vendor logo) until there is some * (error) message to display. But the boot graphics may have been destroyed by * e.g. option ROM output, detect this and restore the boot graphics.
*/ #ifdefined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ defined CONFIG_ACPI_BGRT staticvoid efifb_copy_bmp(u8 *src, u32 *dst, int width, conststruct screen_info *si)
{
u8 r, g, b;
while (width--) {
b = *src++;
g = *src++;
r = *src++;
*dst++ = (r << si->red_pos) |
(g << si->green_pos) |
(b << si->blue_pos);
}
}
#ifdef CONFIG_X86 /* * On x86 some firmwares use a low non native resolution for the display when * they have shown some text messages. While keeping the bgrt filled with info * for the native resolution. If the bgrt image intended for the native * resolution still fits, it will be displayed very close to the right edge of * the display looking quite bad. This function checks for this.
*/ staticbool efifb_bgrt_sanity_check(conststruct screen_info *si, u32 bmp_width)
{ /* * All x86 firmwares horizontally center the image (the yoffset * calculations differ between boards, but xoffset is predictable).
*/
u32 expected_xoffset = (si->lfb_width - bmp_width) / 2;
/* * fb_ops.fb_destroy is called by the last put_fb_info() call at the end * of unregister_framebuffer() or fb_release(). Do any cleanup here.
*/ staticvoid efifb_destroy(struct fb_info *info)
{ struct efifb_par *par = info->par;
if (info->screen_base) { if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC))
iounmap(info->screen_base); else
memunmap(info->screen_base);
}
if (request_mem_succeeded)
release_mem_region(par->base, par->size);
fb_dealloc_cmap(&info->cmap);
/* * If we fail probing the device, the kernel might try a different * driver. We get a copy of the attached screen_info, so that we can * modify its values without affecting later drivers.
*/
si = dev_get_platdata(&dev->dev); if (!si) return -ENODEV;
si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL); if (!si) return -ENOMEM;
dev_set_drvdata(&dev->dev, si);
if (si->orig_video_isVGA != VIDEO_TYPE_EFI) return -ENODEV;
if (fb_get_options("efifb", &option)) return -ENODEV;
efifb_setup(si, 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 (!si->lfb_linelength) return -ENODEV;
if (!si->lfb_depth)
si->lfb_depth = 32; if (!si->pages)
si->pages = 1; if (!fb_base_is_valid(si)) {
printk(KERN_DEBUG "efifb: invalid framebuffer address\n"); return -ENODEV;
}
printk(KERN_INFO "efifb: probing for efifb\n");
/* just assume they're all unset if any are */ if (!si->blue_size) {
si->blue_size = 8;
si->blue_pos = 0;
si->green_size = 8;
si->green_pos = 8;
si->red_size = 8;
si->red_pos = 16;
si->rsvd_size = 8;
si->rsvd_pos = 24;
}
/* 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 = si->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; if (size_remap > size_total)
size_remap = size_total; if (size_remap % PAGE_SIZE)
size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
efifb_fix.smem_len = size_remap;
if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
request_mem_succeeded = true;
} else { /* We cannot make this fatal. Sometimes this comes from magic
spaces our resource handlers simply don't know about */
pr_warn("efifb: cannot reserve video memory at 0x%lx\n",
efifb_fix.smem_start);
}
info = framebuffer_alloc(sizeof(*par), &dev->dev); if (!info) {
err = -ENOMEM; goto err_release_mem;
}
par = info->par;
info->pseudo_palette = par->pseudo_palette;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.