2014-03-05 14:37:45 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2014 The FreeBSD Foundation
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This software was developed by Aleksandr Rybalko under sponsorship from the
|
|
|
|
* FreeBSD Foundation.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/fbio.h>
|
|
|
|
#include <sys/linker.h>
|
|
|
|
|
|
|
|
#include "opt_platform.h"
|
|
|
|
|
|
|
|
#include <machine/metadata.h>
|
|
|
|
#include <machine/vm.h>
|
|
|
|
#include <machine/vmparam.h>
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#include <vm/pmap.h>
|
|
|
|
#include <machine/pmap.h>
|
|
|
|
|
|
|
|
#include <dev/vt/vt.h>
|
|
|
|
#include <dev/vt/hw/fb/vt_fb.h>
|
|
|
|
#include <dev/vt/colors/vt_termcolors.h>
|
|
|
|
|
2014-05-05 21:48:19 +00:00
|
|
|
static vd_init_t vt_efifb_init;
|
|
|
|
static vd_probe_t vt_efifb_probe;
|
2014-03-05 14:37:45 +00:00
|
|
|
|
2014-05-05 21:48:19 +00:00
|
|
|
static struct vt_driver vt_efifb_driver = {
|
|
|
|
.vd_name = "efifb",
|
|
|
|
.vd_probe = vt_efifb_probe,
|
|
|
|
.vd_init = vt_efifb_init,
|
2014-03-05 14:37:45 +00:00
|
|
|
.vd_blank = vt_fb_blank,
|
2014-08-23 15:00:47 +00:00
|
|
|
.vd_bitblt_text = vt_fb_bitblt_text,
|
2014-08-23 20:35:33 +00:00
|
|
|
.vd_bitblt_bmp = vt_fb_bitblt_bitmap,
|
2014-09-16 18:02:24 +00:00
|
|
|
.vd_drawrect = vt_fb_drawrect,
|
|
|
|
.vd_setpixel = vt_fb_setpixel,
|
2014-07-16 18:52:21 +00:00
|
|
|
.vd_fb_ioctl = vt_fb_ioctl,
|
|
|
|
.vd_fb_mmap = vt_fb_mmap,
|
2014-03-05 14:37:45 +00:00
|
|
|
/* Better than VGA, but still generic driver. */
|
|
|
|
.vd_priority = VD_PRIORITY_GENERIC + 1,
|
|
|
|
};
|
|
|
|
|
2014-05-05 21:48:19 +00:00
|
|
|
static struct fb_info local_info;
|
|
|
|
VT_DRIVER_DECLARE(vt_efifb, vt_efifb_driver);
|
2014-03-05 14:37:45 +00:00
|
|
|
|
|
|
|
static int
|
2014-05-05 21:48:19 +00:00
|
|
|
vt_efifb_probe(struct vt_device *vd)
|
2014-03-05 14:37:45 +00:00
|
|
|
{
|
2014-05-05 21:48:19 +00:00
|
|
|
int disabled;
|
2014-03-05 14:37:45 +00:00
|
|
|
struct efi_fb *efifb;
|
|
|
|
caddr_t kmdp;
|
|
|
|
|
2014-05-05 21:48:19 +00:00
|
|
|
disabled = 0;
|
|
|
|
TUNABLE_INT_FETCH("hw.syscons.disable", &disabled);
|
|
|
|
if (disabled != 0)
|
|
|
|
return (CN_DEAD);
|
2014-03-05 14:37:45 +00:00
|
|
|
|
2014-05-05 21:48:19 +00:00
|
|
|
kmdp = preload_search_by_type("elf kernel");
|
|
|
|
if (kmdp == NULL)
|
|
|
|
kmdp = preload_search_by_type("elf64 kernel");
|
|
|
|
efifb = (struct efi_fb *)preload_search_info(kmdp,
|
|
|
|
MODINFO_METADATA | MODINFOMD_EFI_FB);
|
|
|
|
if (efifb == NULL)
|
2014-03-05 14:37:45 +00:00
|
|
|
return (CN_DEAD);
|
|
|
|
|
2014-05-05 21:48:19 +00:00
|
|
|
return (CN_INTERNAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
vt_efifb_init(struct vt_device *vd)
|
|
|
|
{
|
2014-07-16 18:52:21 +00:00
|
|
|
int depth, d;
|
2014-05-05 21:48:19 +00:00
|
|
|
struct fb_info *info;
|
|
|
|
struct efi_fb *efifb;
|
|
|
|
caddr_t kmdp;
|
|
|
|
|
|
|
|
info = vd->vd_softc;
|
|
|
|
if (info == NULL)
|
|
|
|
info = vd->vd_softc = (void *)&local_info;
|
|
|
|
|
2014-03-05 14:37:45 +00:00
|
|
|
kmdp = preload_search_by_type("elf kernel");
|
|
|
|
if (kmdp == NULL)
|
|
|
|
kmdp = preload_search_by_type("elf64 kernel");
|
2014-03-27 19:43:38 +00:00
|
|
|
efifb = (struct efi_fb *)preload_search_info(kmdp,
|
|
|
|
MODINFO_METADATA | MODINFOMD_EFI_FB);
|
2014-03-14 19:37:37 +00:00
|
|
|
if (efifb == NULL)
|
2014-03-05 14:37:45 +00:00
|
|
|
return (CN_DEAD);
|
|
|
|
|
|
|
|
info->fb_height = efifb->fb_height;
|
|
|
|
info->fb_width = efifb->fb_width;
|
|
|
|
|
|
|
|
depth = fls(efifb->fb_mask_red);
|
|
|
|
d = fls(efifb->fb_mask_green);
|
|
|
|
depth = d > depth ? d : depth;
|
|
|
|
d = fls(efifb->fb_mask_blue);
|
|
|
|
depth = d > depth ? d : depth;
|
|
|
|
d = fls(efifb->fb_mask_reserved);
|
|
|
|
depth = d > depth ? d : depth;
|
|
|
|
info->fb_depth = depth;
|
|
|
|
|
|
|
|
info->fb_stride = efifb->fb_stride * (depth / 8);
|
|
|
|
|
2014-08-10 17:04:10 +00:00
|
|
|
vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB,
|
2014-03-05 14:37:45 +00:00
|
|
|
efifb->fb_mask_red, ffs(efifb->fb_mask_red) - 1,
|
|
|
|
efifb->fb_mask_green, ffs(efifb->fb_mask_green) - 1,
|
|
|
|
efifb->fb_mask_blue, ffs(efifb->fb_mask_blue) - 1);
|
|
|
|
|
|
|
|
info->fb_size = info->fb_height * info->fb_stride;
|
|
|
|
info->fb_pbase = efifb->fb_addr;
|
Better support memory mapped console devices, such as VGA and EFI
frame buffers and memory mapped UARTs.
1. Delay calling cninit() until after pmap_bootstrap(). This makes
sure we have PMAP initialized enough to add translations. Keep
kdb_init() after cninit() so that we have console when we need
to break into the debugger on boot.
2. Unfortunately, the ATPIC code had be moved as well so as to
avoid a spurious trap #30. The reason for which is not known
at this time.
3. In pmap_mapdev_attr(), when we need to map a device prior to the
VM system being initialized, use virtual_avail as the KVA to map
the device at. In particular, avoid using the direct map on amd64
because we can't demote by virtue of not being able to allocate
yet. Keep track of the translation.
Re-use the translation after the VM has been initialized to not
waste KVA and to satisfy the assumption in uart(4) that the handle
returned for the low-level console is the same as later returned
when the device is probed and attached.
4. In pmap_unmapdev() remove the mapping from the table when called
pre-init. Otherwise keep the mapping. During bus probe and attach
device resources are mapped and unmapped multiple times, which
would have us destroy the mapping used by the low-level console.
5. In pmap_init(), set pmap_initialized to signal that we're not
pre-init anymore. On amd64, bring the direct map in sync with the
translations created at that time.
6. Implement bus_space_map() and bus_space_unmap() for real: when
the tag corresponds to memory space, call the corresponding
pmap_mapdev() and pmap_unmapdev() functions to construct and
actual handle.
7. In efifb.c and vt_vga.c, remove the crutches and hacks and simply
call pmap_mapdev_attr() or bus_space_map() as desired.
Notes:
1. uart(4) already used bus_space_map() during low-level console
setup but since serial ports have traditionally been I/O port
based, the lack of a proper implementation for said function
was not a problem. It has always supported memory mapped UARTs
for low-level consoles by setting hw.uart.console accordingly.
2. The use of the direct map on amd64 without setting caching
attributes has been a bigger problem than previously thought.
This change has the fortunate (and unexpected) side-effect of
fixing various EFI frame buffer problems (though not all).
PR: 191564, 194952
Special thanks to:
1. XipLink, Inc -- generously donated an Intel Bay Trail E3800
based eval board (ADLE3800PC).
2. The FreeBSD Foundation, in particular emaste@ -- for UEFI
support in general and testing.
3. Everyone who tested the proposed for PR 191564.
4. jhb@ and kib@ for being a soundboard and applying a clue bat
if so needed.
2015-08-12 15:26:32 +00:00
|
|
|
info->fb_vbase = (intptr_t)pmap_mapdev_attr(info->fb_pbase,
|
|
|
|
info->fb_size, VM_MEMATTR_WRITE_COMBINING);
|
2014-03-05 14:37:45 +00:00
|
|
|
|
|
|
|
/* Get pixel storage size. */
|
|
|
|
info->fb_bpp = info->fb_stride / info->fb_width * 8;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Early FB driver work with static window buffer, so reduce to minimal
|
|
|
|
* size, buffer or screen.
|
|
|
|
*/
|
|
|
|
info->fb_width = MIN(info->fb_width, VT_FB_DEFAULT_WIDTH);
|
|
|
|
info->fb_height = MIN(info->fb_height, VT_FB_DEFAULT_HEIGHT);
|
|
|
|
|
|
|
|
vt_fb_init(vd);
|
|
|
|
|
|
|
|
return (CN_INTERNAL);
|
|
|
|
}
|