11a89eaf2SAleksandr Rybalko /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
41a89eaf2SAleksandr Rybalko * Copyright (c) 2014 The FreeBSD Foundation
51a89eaf2SAleksandr Rybalko *
61a89eaf2SAleksandr Rybalko * This software was developed by Aleksandr Rybalko under sponsorship from the
71a89eaf2SAleksandr Rybalko * FreeBSD Foundation.
81a89eaf2SAleksandr Rybalko *
91a89eaf2SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without
101a89eaf2SAleksandr Rybalko * modification, are permitted provided that the following conditions
111a89eaf2SAleksandr Rybalko * are met:
121a89eaf2SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright
131a89eaf2SAleksandr Rybalko * notice, this list of conditions and the following disclaimer.
141a89eaf2SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright
151a89eaf2SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the
161a89eaf2SAleksandr Rybalko * documentation and/or other materials provided with the distribution.
171a89eaf2SAleksandr Rybalko *
181a89eaf2SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
191a89eaf2SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
201a89eaf2SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
211a89eaf2SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
221a89eaf2SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
231a89eaf2SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
241a89eaf2SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
251a89eaf2SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
261a89eaf2SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
271a89eaf2SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
281a89eaf2SAleksandr Rybalko * SUCH DAMAGE.
291a89eaf2SAleksandr Rybalko */
301a89eaf2SAleksandr Rybalko
311a89eaf2SAleksandr Rybalko #include <sys/param.h>
321a89eaf2SAleksandr Rybalko #include <sys/systm.h>
331a89eaf2SAleksandr Rybalko #include <sys/kernel.h>
341a89eaf2SAleksandr Rybalko #include <sys/fbio.h>
351a89eaf2SAleksandr Rybalko #include <sys/linker.h>
361a89eaf2SAleksandr Rybalko
371a89eaf2SAleksandr Rybalko #include "opt_platform.h"
381a89eaf2SAleksandr Rybalko
391a89eaf2SAleksandr Rybalko #include <machine/metadata.h>
401a89eaf2SAleksandr Rybalko #include <machine/vmparam.h>
411a89eaf2SAleksandr Rybalko #include <vm/vm.h>
421a89eaf2SAleksandr Rybalko #include <vm/pmap.h>
431a89eaf2SAleksandr Rybalko
441a89eaf2SAleksandr Rybalko #include <dev/vt/vt.h>
451a89eaf2SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h>
461a89eaf2SAleksandr Rybalko #include <dev/vt/colors/vt_termcolors.h>
471a89eaf2SAleksandr Rybalko
484dde1640SAleksandr Rybalko static vd_init_t vt_efifb_init;
498ebda6e4SGreg V static vd_fini_t vt_efifb_fini;
504dde1640SAleksandr Rybalko static vd_probe_t vt_efifb_probe;
511a89eaf2SAleksandr Rybalko
524dde1640SAleksandr Rybalko static struct vt_driver vt_efifb_driver = {
534dde1640SAleksandr Rybalko .vd_name = "efifb",
544dde1640SAleksandr Rybalko .vd_probe = vt_efifb_probe,
554dde1640SAleksandr Rybalko .vd_init = vt_efifb_init,
568ebda6e4SGreg V .vd_fini = vt_efifb_fini,
571a89eaf2SAleksandr Rybalko .vd_blank = vt_fb_blank,
58c285e4a5SJean-Sébastien Pédron .vd_bitblt_text = vt_fb_bitblt_text,
59ee97b233SColin Percival .vd_invalidate_text = vt_fb_invalidate_text,
60631bb572SJean-Sébastien Pédron .vd_bitblt_bmp = vt_fb_bitblt_bitmap,
61b93028d8SEmmanuel Vadot .vd_bitblt_argb = vt_fb_bitblt_argb,
621365d077SJean-Sébastien Pédron .vd_drawrect = vt_fb_drawrect,
631365d077SJean-Sébastien Pédron .vd_setpixel = vt_fb_setpixel,
64351e92ccSNathan Whitehorn .vd_fb_ioctl = vt_fb_ioctl,
65351e92ccSNathan Whitehorn .vd_fb_mmap = vt_fb_mmap,
667115eaf8SEd Maste .vd_suspend = vt_suspend,
677115eaf8SEd Maste .vd_resume = vt_resume,
681a89eaf2SAleksandr Rybalko /* Better than VGA, but still generic driver. */
691a89eaf2SAleksandr Rybalko .vd_priority = VD_PRIORITY_GENERIC + 1,
701a89eaf2SAleksandr Rybalko };
711a89eaf2SAleksandr Rybalko
724dde1640SAleksandr Rybalko static struct fb_info local_info;
734dde1640SAleksandr Rybalko VT_DRIVER_DECLARE(vt_efifb, vt_efifb_driver);
741a89eaf2SAleksandr Rybalko
751a89eaf2SAleksandr Rybalko static int
vt_efifb_probe(struct vt_device * vd)764dde1640SAleksandr Rybalko vt_efifb_probe(struct vt_device *vd)
771a89eaf2SAleksandr Rybalko {
784dde1640SAleksandr Rybalko int disabled;
794dde1640SAleksandr Rybalko struct efi_fb *efifb;
804dde1640SAleksandr Rybalko
814dde1640SAleksandr Rybalko disabled = 0;
824dde1640SAleksandr Rybalko TUNABLE_INT_FETCH("hw.syscons.disable", &disabled);
834dde1640SAleksandr Rybalko if (disabled != 0)
844dde1640SAleksandr Rybalko return (CN_DEAD);
854dde1640SAleksandr Rybalko
86b72ae900SAhmad Khalifa efifb = (struct efi_fb *)preload_search_info(preload_kmdp,
874dde1640SAleksandr Rybalko MODINFO_METADATA | MODINFOMD_EFI_FB);
884dde1640SAleksandr Rybalko if (efifb == NULL)
894dde1640SAleksandr Rybalko return (CN_DEAD);
904dde1640SAleksandr Rybalko
914dde1640SAleksandr Rybalko return (CN_INTERNAL);
924dde1640SAleksandr Rybalko }
934dde1640SAleksandr Rybalko
944dde1640SAleksandr Rybalko static int
vt_efifb_init(struct vt_device * vd)954dde1640SAleksandr Rybalko vt_efifb_init(struct vt_device *vd)
964dde1640SAleksandr Rybalko {
971a89eaf2SAleksandr Rybalko struct fb_info *info;
981a89eaf2SAleksandr Rybalko struct efi_fb *efifb;
99*e2a08ac9SMitchell Horne vm_memattr_t memattr;
1000244378fSToomas Soome int roff, goff, boff;
101*e2a08ac9SMitchell Horne
102*e2a08ac9SMitchell Horne #ifdef VM_MEMATTR_WRITE_COMBINING
1038dff0b67SKyle Evans char attr[16];
1048dff0b67SKyle Evans
1058dff0b67SKyle Evans /*
1068dff0b67SKyle Evans * XXX TODO: I think there's more nuance here than we're acknowledging,
1078dff0b67SKyle Evans * and we should look into it. It may be that the framebuffer lives in
1088dff0b67SKyle Evans * a segment of memory that doesn't support one or both of these. We
1098dff0b67SKyle Evans * should likely be consulting the memory map for any applicable
1108dff0b67SKyle Evans * cacheability attributes before making a final decision.
1118dff0b67SKyle Evans */
1128dff0b67SKyle Evans memattr = VM_MEMATTR_WRITE_COMBINING;
1138dff0b67SKyle Evans if (TUNABLE_STR_FETCH("hw.efifb.cache_attr", attr, sizeof(attr))) {
1148dff0b67SKyle Evans /*
1158dff0b67SKyle Evans * We'll allow WC but it's currently the default, UC is the only
1168dff0b67SKyle Evans * other tested one at this time.
1178dff0b67SKyle Evans */
1188dff0b67SKyle Evans if (strcasecmp(attr, "wc") != 0 &&
1198dff0b67SKyle Evans strcasecmp(attr, "uc") != 0) {
1208dff0b67SKyle Evans printf("efifb: unsupported cache attr specified: %s\n",
1218dff0b67SKyle Evans attr);
1228dff0b67SKyle Evans printf("efifb: expected \"wc\" or \"uc\"\n");
1238dff0b67SKyle Evans } else if (strcasecmp(attr, "uc") == 0) {
1248dff0b67SKyle Evans memattr = VM_MEMATTR_UNCACHEABLE;
1258dff0b67SKyle Evans }
1268dff0b67SKyle Evans }
127*e2a08ac9SMitchell Horne #else
128*e2a08ac9SMitchell Horne memattr = VM_MEMATTR_UNCACHEABLE;
129*e2a08ac9SMitchell Horne #endif
1301a89eaf2SAleksandr Rybalko
1311a89eaf2SAleksandr Rybalko info = vd->vd_softc;
1324dde1640SAleksandr Rybalko if (info == NULL)
1334dde1640SAleksandr Rybalko info = vd->vd_softc = (void *)&local_info;
1341a89eaf2SAleksandr Rybalko
135b72ae900SAhmad Khalifa efifb = (struct efi_fb *)preload_search_info(preload_kmdp,
1361a89eaf2SAleksandr Rybalko MODINFO_METADATA | MODINFOMD_EFI_FB);
13758df20d2SEd Maste if (efifb == NULL)
1381a89eaf2SAleksandr Rybalko return (CN_DEAD);
1391a89eaf2SAleksandr Rybalko
140ca23e9d2SEmmanuel Vadot info->fb_type = FBTYPE_EFIFB;
1411a89eaf2SAleksandr Rybalko info->fb_height = efifb->fb_height;
1421a89eaf2SAleksandr Rybalko info->fb_width = efifb->fb_width;
1431a89eaf2SAleksandr Rybalko
144296a5114SMarcel Moolenaar info->fb_depth = fls(efifb->fb_mask_red | efifb->fb_mask_green |
145296a5114SMarcel Moolenaar efifb->fb_mask_blue | efifb->fb_mask_reserved);
146296a5114SMarcel Moolenaar /* Round to a multiple of the bits in a byte. */
147d9c9c81cSPedro F. Giffuni info->fb_bpp = roundup2(info->fb_depth, NBBY);
1481a89eaf2SAleksandr Rybalko
149296a5114SMarcel Moolenaar /* Stride in bytes, not pixels */
150296a5114SMarcel Moolenaar info->fb_stride = efifb->fb_stride * (info->fb_bpp / NBBY);
1511a89eaf2SAleksandr Rybalko
1520244378fSToomas Soome roff = ffs(efifb->fb_mask_red) - 1;
1530244378fSToomas Soome goff = ffs(efifb->fb_mask_green) - 1;
1540244378fSToomas Soome boff = ffs(efifb->fb_mask_blue) - 1;
155b9f3b63aSLeandro Lupori vt_config_cons_colors(info, COLOR_FORMAT_RGB,
1560244378fSToomas Soome efifb->fb_mask_red >> roff, roff,
1570244378fSToomas Soome efifb->fb_mask_green >> goff, goff,
1580244378fSToomas Soome efifb->fb_mask_blue >> boff, boff);
1590244378fSToomas Soome info->fb_cmsize = NCOLORS;
1601a89eaf2SAleksandr Rybalko
1611a89eaf2SAleksandr Rybalko info->fb_size = info->fb_height * info->fb_stride;
1621a89eaf2SAleksandr Rybalko info->fb_pbase = efifb->fb_addr;
1637ef5e8bcSMarcel Moolenaar info->fb_vbase = (intptr_t)pmap_mapdev_attr(info->fb_pbase,
1648dff0b67SKyle Evans info->fb_size, memattr);
1651a89eaf2SAleksandr Rybalko
1661a89eaf2SAleksandr Rybalko vt_fb_init(vd);
1671a89eaf2SAleksandr Rybalko
1681a89eaf2SAleksandr Rybalko return (CN_INTERNAL);
1691a89eaf2SAleksandr Rybalko }
1708ebda6e4SGreg V
1718ebda6e4SGreg V static void
vt_efifb_fini(struct vt_device * vd,void * softc)1728ebda6e4SGreg V vt_efifb_fini(struct vt_device *vd, void *softc)
1738ebda6e4SGreg V {
1748ebda6e4SGreg V struct fb_info *info = softc;
1758ebda6e4SGreg V
1768ebda6e4SGreg V vt_fb_fini(vd, softc);
1777ae99f80SJohn Baldwin pmap_unmapdev((void *)info->fb_vbase, info->fb_size);
1788ebda6e4SGreg V }
179