efifb.c revision 276064
1285169Scy/*- 2132451Sroberto * Copyright (c) 2014 The FreeBSD Foundation 3285169Scy * All rights reserved. 4285169Scy * 5132451Sroberto * This software was developed by Aleksandr Rybalko under sponsorship from the 6132451Sroberto * FreeBSD Foundation. 7132451Sroberto * 8132451Sroberto * Redistribution and use in source and binary forms, with or without 9132451Sroberto * modification, are permitted provided that the following conditions 10132451Sroberto * are met: 11132451Sroberto * 1. Redistributions of source code must retain the above copyright 12132451Sroberto * notice, this list of conditions and the following disclaimer. 13132451Sroberto * 2. Redistributions in binary form must reproduce the above copyright 14285169Scy * notice, this list of conditions and the following disclaimer in the 15200576Sroberto * documentation and/or other materials provided with the distribution. 16200576Sroberto * 17285169Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18285169Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19200576Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20200576Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21285169Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22200576Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23280849Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24280849Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25132451Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26280849Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27280849Scy * SUCH DAMAGE. 28280849Scy * 29280849Scy * $FreeBSD: head/sys/dev/vt/hw/efifb/efifb.c 276064 2014-12-22 16:46:07Z royger $ 30132451Sroberto */ 31280849Scy 32280849Scy#include <sys/cdefs.h> 33280849Scy__FBSDID("$FreeBSD: head/sys/dev/vt/hw/efifb/efifb.c 276064 2014-12-22 16:46:07Z royger $"); 34280849Scy 35280849Scy#include <sys/param.h> 36132451Sroberto#include <sys/systm.h> 37280849Scy#include <sys/kernel.h> 38280849Scy#include <sys/fbio.h> 39280849Scy#include <sys/linker.h> 40280849Scy#include <sys/bus.h> 41280849Scy#include <sys/module.h> 42280849Scy#include <sys/rman.h> 43280849Scy 44280849Scy#include "opt_platform.h" 45280849Scy 46280849Scy#include <machine/metadata.h> 47280849Scy#include <machine/vm.h> 48280849Scy#include <machine/vmparam.h> 49280849Scy#include <vm/vm.h> 50132451Sroberto#include <vm/pmap.h> 51280849Scy#include <machine/pmap.h> 52182007Sroberto 53280849Scy#include <dev/vt/vt.h> 54280849Scy#include <dev/vt/hw/fb/vt_fb.h> 55280849Scy#include <dev/vt/colors/vt_termcolors.h> 56280849Scy 57280849Scystatic vd_init_t vt_efifb_init; 58280849Scystatic vd_probe_t vt_efifb_probe; 59280849Scystatic void vt_efifb_remap(void *efifb_data); 60280849Scy 61280849Scystatic struct vt_driver vt_efifb_driver = { 62182007Sroberto .vd_name = "efifb", 63280849Scy .vd_probe = vt_efifb_probe, 64182007Sroberto .vd_init = vt_efifb_init, 65280849Scy .vd_blank = vt_fb_blank, 66280849Scy .vd_bitblt_text = vt_fb_bitblt_text, 67280849Scy .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 68280849Scy .vd_drawrect = vt_fb_drawrect, 69280849Scy .vd_setpixel = vt_fb_setpixel, 70280849Scy .vd_fb_ioctl = vt_fb_ioctl, 71280849Scy .vd_fb_mmap = vt_fb_mmap, 72280849Scy /* Better than VGA, but still generic driver. */ 73280849Scy .vd_priority = VD_PRIORITY_GENERIC + 1, 74280849Scy}; 75182007Sroberto 76182007Srobertostatic struct fb_info local_info; 77280849ScyVT_DRIVER_DECLARE(vt_efifb, vt_efifb_driver); 78280849Scy 79280849ScySYSINIT(efifb_remap, SI_SUB_KMEM, SI_ORDER_ANY, vt_efifb_remap, &local_info); 80280849Scy 81280849Scystatic int 82280849Scyvt_efifb_probe(struct vt_device *vd) 83280849Scy{ 84182007Sroberto int disabled; 85132451Sroberto struct efi_fb *efifb; 86132451Sroberto caddr_t kmdp; 87280849Scy 88280849Scy disabled = 0; 89280849Scy TUNABLE_INT_FETCH("hw.syscons.disable", &disabled); 90280849Scy if (disabled != 0) 91182007Sroberto return (CN_DEAD); 92280849Scy 93280849Scy kmdp = preload_search_by_type("elf kernel"); 94280849Scy if (kmdp == NULL) 95182007Sroberto kmdp = preload_search_by_type("elf64 kernel"); 96280849Scy efifb = (struct efi_fb *)preload_search_info(kmdp, 97280849Scy MODINFO_METADATA | MODINFOMD_EFI_FB); 98280849Scy if (efifb == NULL) 99182007Sroberto return (CN_DEAD); 100280849Scy 101280849Scy return (CN_INTERNAL); 102280849Scy} 103182007Sroberto 104280849Scystatic int 105280849Scyvt_efifb_init(struct vt_device *vd) 106280849Scy{ 107280849Scy int depth, d; 108182007Sroberto struct fb_info *info; 109280849Scy struct efi_fb *efifb; 110280849Scy caddr_t kmdp; 111280849Scy 112280849Scy info = vd->vd_softc; 113280849Scy if (info == NULL) 114280849Scy info = vd->vd_softc = (void *)&local_info; 115280849Scy 116280849Scy kmdp = preload_search_by_type("elf kernel"); 117280849Scy if (kmdp == NULL) 118280849Scy kmdp = preload_search_by_type("elf64 kernel"); 119280849Scy efifb = (struct efi_fb *)preload_search_info(kmdp, 120280849Scy MODINFO_METADATA | MODINFOMD_EFI_FB); 121280849Scy if (efifb == NULL) 122280849Scy return (CN_DEAD); 123280849Scy 124182007Sroberto info->fb_height = efifb->fb_height; 125280849Scy info->fb_width = efifb->fb_width; 126182007Sroberto 127280849Scy depth = fls(efifb->fb_mask_red); 128280849Scy d = fls(efifb->fb_mask_green); 129280849Scy depth = d > depth ? d : depth; 130182007Sroberto d = fls(efifb->fb_mask_blue); 131280849Scy depth = d > depth ? d : depth; 132280849Scy d = fls(efifb->fb_mask_reserved); 133280849Scy depth = d > depth ? d : depth; 134280849Scy info->fb_depth = depth; 135280849Scy 136280849Scy info->fb_stride = efifb->fb_stride * (depth / 8); 137280849Scy 138182007Sroberto vt_generate_cons_palette(info->fb_cmap, COLOR_FORMAT_RGB, 139280849Scy efifb->fb_mask_red, ffs(efifb->fb_mask_red) - 1, 140132451Sroberto efifb->fb_mask_green, ffs(efifb->fb_mask_green) - 1, 141132451Sroberto efifb->fb_mask_blue, ffs(efifb->fb_mask_blue) - 1); 142285169Scy 143182007Sroberto info->fb_size = info->fb_height * info->fb_stride; 144182007Sroberto info->fb_pbase = efifb->fb_addr; 145182007Sroberto /* 146182007Sroberto * Use the direct map as a crutch until pmap is available. Once pmap 147182007Sroberto * is online, the framebuffer will be remapped by vt_efifb_remap() 148182007Sroberto * using pmap_mapdev_attr(). 149182007Sroberto */ 150182007Sroberto info->fb_vbase = PHYS_TO_DMAP(efifb->fb_addr); 151182007Sroberto 152200576Sroberto /* Get pixel storage size. */ 153200576Sroberto info->fb_bpp = info->fb_stride / info->fb_width * 8; 154285169Scy 155200576Sroberto /* 156200576Sroberto * Early FB driver work with static window buffer, so reduce to minimal 157285169Scy * size, buffer or screen. 158200576Sroberto */ 159200576Sroberto info->fb_width = MIN(info->fb_width, VT_FB_DEFAULT_WIDTH); 160182007Sroberto info->fb_height = MIN(info->fb_height, VT_FB_DEFAULT_HEIGHT); 161200576Sroberto 162200576Sroberto vt_fb_init(vd); 163200576Sroberto 164200576Sroberto return (CN_INTERNAL); 165200576Sroberto} 166200576Sroberto 167200576Srobertostatic void 168182007Srobertovt_efifb_remap(void *xinfo) 169182007Sroberto{ 170200576Sroberto struct fb_info *info = xinfo; 171200576Sroberto 172182007Sroberto if (info->fb_pbase == 0) 173285169Scy return; 174200576Sroberto 175200576Sroberto /* 176200576Sroberto * Remap as write-combining. This massively improves performance and 177182007Sroberto * happens very early in kernel initialization, when everything is 178285169Scy * still single-threaded and interrupts are off, so replacing the 179285169Scy * mapping address is safe. 180285169Scy */ 181285169Scy info->fb_vbase = (intptr_t)pmap_mapdev_attr(info->fb_pbase, 182285169Scy info->fb_size, VM_MEMATTR_WRITE_COMBINING); 183285169Scy} 184285169Scy 185285169Scy/* Dummy NewBus functions to reserve the resources used by the efifb driver */ 186285169Scystatic void 187285169Scyvtefifb_identify(driver_t *driver, device_t parent) 188285169Scy{ 189285169Scy 190285169Scy if (local_info.fb_pbase == 0 || local_info.fb_size == 0) 191285169Scy return; 192285169Scy 193285169Scy if (BUS_ADD_CHILD(parent, 0, driver->name, 0) == NULL) 194285169Scy panic("Unable to attach vt_efifb console"); 195285169Scy} 196285169Scy 197285169Scystatic int 198285169Scyvtefifb_probe(device_t dev) 199285169Scy{ 200285169Scy 201285169Scy device_set_desc(dev, "vt_efifb driver"); 202285169Scy return (BUS_PROBE_NOWILDCARD); 203285169Scy} 204285169Scy 205285169Scystatic int 206285169Scyvtefifb_attach(device_t dev) 207285169Scy{ 208285169Scy struct resource *pseudo_phys_res; 209285169Scy int res_id; 210285169Scy 211285169Scy res_id = 0; 212285169Scy pseudo_phys_res = bus_alloc_resource(dev, SYS_RES_MEMORY, 213285169Scy &res_id, local_info.fb_pbase, 214285169Scy local_info.fb_pbase + local_info.fb_size, 215285169Scy local_info.fb_size, RF_ACTIVE); 216285169Scy if (pseudo_phys_res == NULL) 217285169Scy panic("Unable to reserve vt_efifb memory"); 218285169Scy return (0); 219285169Scy} 220285169Scy 221285169Scy/*-------------------- Private Device Attachment Data -----------------------*/ 222285169Scystatic device_method_t vtefifb_methods[] = { 223285169Scy /* Device interface */ 224285169Scy DEVMETHOD(device_identify, vtefifb_identify), 225285169Scy DEVMETHOD(device_probe, vtefifb_probe), 226285169Scy DEVMETHOD(device_attach, vtefifb_attach), 227285169Scy 228285169Scy DEVMETHOD_END 229285169Scy}; 230285169Scy 231285169ScyDEFINE_CLASS_0(vtefifb, vtefifb_driver, vtefifb_methods, 0); 232285169Scydevclass_t vtefifb_devclass; 233285169Scy 234285169ScyDRIVER_MODULE(vtefifb, nexus, vtefifb_driver, vtefifb_devclass, NULL, NULL); 235285169Scy