xref: /freebsd/sys/dev/vt/hw/efifb/efifb.c (revision e2a08ac9ce424f543a2f03c67fb882fdabbdd32a)
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