1d5035d91SAndrew Turner /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3d5035d91SAndrew Turner * 4d5035d91SAndrew Turner * Copyright (c) 2014 The FreeBSD Foundation 5d5035d91SAndrew Turner * Copyright (c) 2021 Andrew Turner 6d5035d91SAndrew Turner * 7d5035d91SAndrew Turner * Portions of this software was developed by Aleksandr Rybalko under 8d5035d91SAndrew Turner * sponsorship from the FreeBSD Foundation. 9d5035d91SAndrew Turner * 10d5035d91SAndrew Turner * Redistribution and use in source and binary forms, with or without 11d5035d91SAndrew Turner * modification, are permitted provided that the following conditions 12d5035d91SAndrew Turner * are met: 13d5035d91SAndrew Turner * 1. Redistributions of source code must retain the above copyright 14d5035d91SAndrew Turner * notice, this list of conditions and the following disclaimer. 15d5035d91SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 16d5035d91SAndrew Turner * notice, this list of conditions and the following disclaimer in the 17d5035d91SAndrew Turner * documentation and/or other materials provided with the distribution. 18d5035d91SAndrew Turner * 19d5035d91SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20d5035d91SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21d5035d91SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22d5035d91SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23d5035d91SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24d5035d91SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25d5035d91SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26d5035d91SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27d5035d91SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28d5035d91SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29d5035d91SAndrew Turner * SUCH DAMAGE. 30d5035d91SAndrew Turner */ 31d5035d91SAndrew Turner 32d5035d91SAndrew Turner #include <sys/param.h> 33d5035d91SAndrew Turner #include <sys/systm.h> 34d5035d91SAndrew Turner #include <sys/kernel.h> 35d5035d91SAndrew Turner #include <sys/fbio.h> 36d5035d91SAndrew Turner 37d5035d91SAndrew Turner #include <vm/vm.h> 38d5035d91SAndrew Turner #include <vm/pmap.h> 39d5035d91SAndrew Turner 40d5035d91SAndrew Turner #include <dev/vt/vt.h> 41d5035d91SAndrew Turner #include <dev/vt/hw/fb/vt_fb.h> 42d5035d91SAndrew Turner #include <dev/vt/colors/vt_termcolors.h> 43d5035d91SAndrew Turner 44d5035d91SAndrew Turner #include <dev/ofw/openfirm.h> 45d5035d91SAndrew Turner #include <dev/ofw/ofw_bus.h> 46d5035d91SAndrew Turner #include <dev/ofw/ofw_subr.h> 47d5035d91SAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 48d5035d91SAndrew Turner 49d5035d91SAndrew Turner static vd_init_t vt_simplefb_init; 50d5035d91SAndrew Turner static vd_fini_t vt_simplefb_fini; 51d5035d91SAndrew Turner static vd_probe_t vt_simplefb_probe; 52*b93028d8SEmmanuel Vadot static vd_bitblt_argb_t vt_simplefb_bitblt_argb; 53d5035d91SAndrew Turner 54d5035d91SAndrew Turner static struct vt_driver vt_simplefb_driver = { 55d5035d91SAndrew Turner .vd_name = "simplefb", 56d5035d91SAndrew Turner .vd_probe = vt_simplefb_probe, 57d5035d91SAndrew Turner .vd_init = vt_simplefb_init, 58d5035d91SAndrew Turner .vd_fini = vt_simplefb_fini, 59d5035d91SAndrew Turner .vd_blank = vt_fb_blank, 60d5035d91SAndrew Turner .vd_bitblt_text = vt_fb_bitblt_text, 61d5035d91SAndrew Turner .vd_invalidate_text = vt_fb_invalidate_text, 62d5035d91SAndrew Turner .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 63*b93028d8SEmmanuel Vadot .vd_bitblt_argb = vt_simplefb_bitblt_argb, 64d5035d91SAndrew Turner .vd_drawrect = vt_fb_drawrect, 65d5035d91SAndrew Turner .vd_setpixel = vt_fb_setpixel, 66d5035d91SAndrew Turner .vd_fb_ioctl = vt_fb_ioctl, 67d5035d91SAndrew Turner .vd_fb_mmap = vt_fb_mmap, 68d5035d91SAndrew Turner .vd_suspend = vt_suspend, 69d5035d91SAndrew Turner .vd_resume = vt_resume, 70d5035d91SAndrew Turner /* Better than efifb, but still generic driver. */ 71d5035d91SAndrew Turner .vd_priority = VD_PRIORITY_GENERIC + 2, 72d5035d91SAndrew Turner }; 73d5035d91SAndrew Turner 74d5035d91SAndrew Turner struct { 75d5035d91SAndrew Turner const char *name; 76d5035d91SAndrew Turner int rbits, rshift; 77d5035d91SAndrew Turner int gbits, gshift; 78d5035d91SAndrew Turner int bbits, bshift; 79d5035d91SAndrew Turner int depth; 80d5035d91SAndrew Turner enum vt_color_format format; 81d5035d91SAndrew Turner } simplefb_formats[] = { 82d5035d91SAndrew Turner { 83d5035d91SAndrew Turner .name = "r5g6b5", 84d5035d91SAndrew Turner .rbits = 5, .rshift = 11, 85d5035d91SAndrew Turner .gbits = 6, .gshift = 5, 86d5035d91SAndrew Turner .bbits = 5, .bshift = 0, 87d5035d91SAndrew Turner .depth = 16, .format = COLOR_FORMAT_RGB, 88d5035d91SAndrew Turner }, 89d5035d91SAndrew Turner { 90d5035d91SAndrew Turner .name = "r8g8b8", 91d5035d91SAndrew Turner .rbits = 8, .rshift = 16, 92d5035d91SAndrew Turner .gbits = 8, .gshift = 8, 93d5035d91SAndrew Turner .bbits = 8, .bshift = 0, 94d5035d91SAndrew Turner .depth = 24, .format = COLOR_FORMAT_RGB, 95d5035d91SAndrew Turner }, 96d5035d91SAndrew Turner { 97d5035d91SAndrew Turner .name = "a8r8g8b8", 98d5035d91SAndrew Turner .rbits = 8, .rshift = 16, 99d5035d91SAndrew Turner .gbits = 8, .gshift = 8, 100d5035d91SAndrew Turner .bbits = 8, .bshift = 0, 101d5035d91SAndrew Turner .depth = 32, .format = COLOR_FORMAT_RGB, 102d5035d91SAndrew Turner }, 103d5035d91SAndrew Turner { 104d5035d91SAndrew Turner .name = "x8r8g8b8", 105d5035d91SAndrew Turner .rbits = 8, .rshift = 16, 106d5035d91SAndrew Turner .gbits = 8, .gshift = 8, 107d5035d91SAndrew Turner .bbits = 8, .bshift = 0, 108d5035d91SAndrew Turner .depth = 32, .format = COLOR_FORMAT_RGB, 109d5035d91SAndrew Turner }, 110d5035d91SAndrew Turner { 111d5035d91SAndrew Turner .name = "x2r10g10b10", 112d5035d91SAndrew Turner .rbits = 10, .rshift = 20, 113d5035d91SAndrew Turner .gbits = 10, .gshift = 10, 114d5035d91SAndrew Turner .bbits = 10, .bshift = 0, 115d5035d91SAndrew Turner .depth = 32, .format = COLOR_FORMAT_RGB, 116d5035d91SAndrew Turner }, 117d5035d91SAndrew Turner }; 118d5035d91SAndrew Turner 119d5035d91SAndrew Turner static struct fb_info local_info; 120d5035d91SAndrew Turner VT_DRIVER_DECLARE(vt_simplefb, vt_simplefb_driver); 121d5035d91SAndrew Turner 122d5035d91SAndrew Turner static bool 123d5035d91SAndrew Turner vt_simplefb_node(phandle_t *nodep) 124d5035d91SAndrew Turner { 125d5035d91SAndrew Turner phandle_t chosen, node; 126d5035d91SAndrew Turner 127d5035d91SAndrew Turner chosen = OF_finddevice("/chosen"); 128d5035d91SAndrew Turner if (chosen == -1) 129d5035d91SAndrew Turner return (false); 130d5035d91SAndrew Turner 131d5035d91SAndrew Turner for (node = OF_child(chosen); node != 0; node = OF_peer(node)) { 132d5035d91SAndrew Turner if (ofw_bus_node_is_compatible(node, "simple-framebuffer")) 133d5035d91SAndrew Turner break; 134d5035d91SAndrew Turner } 135d5035d91SAndrew Turner if (node == 0) 136d5035d91SAndrew Turner return (false); 137d5035d91SAndrew Turner 138d5035d91SAndrew Turner if (nodep != NULL) 139d5035d91SAndrew Turner *nodep = node; 140d5035d91SAndrew Turner 141d5035d91SAndrew Turner return (true); 142d5035d91SAndrew Turner } 143d5035d91SAndrew Turner 144d5035d91SAndrew Turner static int 145d5035d91SAndrew Turner vt_simplefb_probe(struct vt_device *vd) 146d5035d91SAndrew Turner { 147d5035d91SAndrew Turner int disabled; 148d5035d91SAndrew Turner 149d5035d91SAndrew Turner disabled = 0; 150d5035d91SAndrew Turner TUNABLE_INT_FETCH("hw.syscons.disable", &disabled); 151d5035d91SAndrew Turner if (disabled != 0) 152d5035d91SAndrew Turner return (CN_DEAD); 153d5035d91SAndrew Turner 154d5035d91SAndrew Turner if (!vt_simplefb_node(NULL)) 155d5035d91SAndrew Turner return (CN_DEAD); 156d5035d91SAndrew Turner 157d5035d91SAndrew Turner return (CN_INTERNAL); 158d5035d91SAndrew Turner } 159d5035d91SAndrew Turner 160d5035d91SAndrew Turner static int 161d5035d91SAndrew Turner vt_simplefb_init(struct vt_device *vd) 162d5035d91SAndrew Turner { 163d5035d91SAndrew Turner char format[16]; 164d5035d91SAndrew Turner pcell_t height, width, stride; 165d5035d91SAndrew Turner struct fb_info *sc; 166d5035d91SAndrew Turner phandle_t node; 167d5035d91SAndrew Turner bus_size_t size; 168d5035d91SAndrew Turner int error; 169d5035d91SAndrew Turner 170d5035d91SAndrew Turner /* Initialize softc */ 171d5035d91SAndrew Turner vd->vd_softc = sc = &local_info; 172d5035d91SAndrew Turner 173d5035d91SAndrew Turner if (!vt_simplefb_node(&node)) 174d5035d91SAndrew Turner return (CN_DEAD); 175d5035d91SAndrew Turner 176d5035d91SAndrew Turner if (OF_getencprop(node, "height", &height, sizeof(height)) == -1 || 177d5035d91SAndrew Turner OF_getencprop(node, "width", &width, sizeof(width)) == -1 || 178d5035d91SAndrew Turner OF_getencprop(node, "stride", &stride, sizeof(stride)) == -1 || 179d5035d91SAndrew Turner OF_getprop(node, "format", format, sizeof(format)) == -1) { 180d5035d91SAndrew Turner return (CN_DEAD); 181d5035d91SAndrew Turner } 182d5035d91SAndrew Turner 183d5035d91SAndrew Turner sc->fb_height = height; 184d5035d91SAndrew Turner sc->fb_width = width; 185d5035d91SAndrew Turner sc->fb_stride = stride; 186d5035d91SAndrew Turner sc->fb_cmsize = NCOLORS; 187d5035d91SAndrew Turner 188d5035d91SAndrew Turner error = 1; 189d5035d91SAndrew Turner for (int i = 0; i < nitems(simplefb_formats); i++) { 190d5035d91SAndrew Turner if (strcmp(format, simplefb_formats[i].name) == 0) { 191d5035d91SAndrew Turner vt_config_cons_colors(sc, 192d5035d91SAndrew Turner simplefb_formats[i].format, 193d5035d91SAndrew Turner (1 << simplefb_formats[i].rbits) - 1, 194d5035d91SAndrew Turner simplefb_formats[i].rshift, 195d5035d91SAndrew Turner (1 << simplefb_formats[i].gbits) - 1, 196d5035d91SAndrew Turner simplefb_formats[i].gshift, 197d5035d91SAndrew Turner (1 << simplefb_formats[i].bbits) - 1, 198d5035d91SAndrew Turner simplefb_formats[i].bshift); 199d5035d91SAndrew Turner sc->fb_depth = sc->fb_bpp = simplefb_formats[i].depth; 200d5035d91SAndrew Turner error = 0; 201d5035d91SAndrew Turner break; 202d5035d91SAndrew Turner } 203d5035d91SAndrew Turner } 204d5035d91SAndrew Turner if (error != 0) 205d5035d91SAndrew Turner return (CN_DEAD); 206d5035d91SAndrew Turner 207d5035d91SAndrew Turner ofw_reg_to_paddr(node, 0, &sc->fb_pbase, &size, NULL); 208d5035d91SAndrew Turner sc->fb_vbase = (intptr_t)pmap_mapdev_attr(sc->fb_pbase, 209d5035d91SAndrew Turner size, VM_MEMATTR_WRITE_COMBINING); 210d5035d91SAndrew Turner sc->fb_size = size; 211d5035d91SAndrew Turner 212d5035d91SAndrew Turner vt_fb_init(vd); 213d5035d91SAndrew Turner 214d5035d91SAndrew Turner return (CN_INTERNAL); 215d5035d91SAndrew Turner } 216d5035d91SAndrew Turner 217d5035d91SAndrew Turner static void 218d5035d91SAndrew Turner vt_simplefb_fini(struct vt_device *vd, void *softc) 219d5035d91SAndrew Turner { 220d5035d91SAndrew Turner struct fb_info *sc; 221d5035d91SAndrew Turner 222d5035d91SAndrew Turner sc = softc; 223d5035d91SAndrew Turner vt_fb_fini(vd, softc); 224d5035d91SAndrew Turner pmap_unmapdev((void *)sc->fb_vbase, sc->fb_size); 225d5035d91SAndrew Turner } 226*b93028d8SEmmanuel Vadot 227*b93028d8SEmmanuel Vadot static int 228*b93028d8SEmmanuel Vadot vt_simplefb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, 229*b93028d8SEmmanuel Vadot const uint8_t *argb, 230*b93028d8SEmmanuel Vadot unsigned int width, unsigned int height, 231*b93028d8SEmmanuel Vadot unsigned int x, unsigned int y) 232*b93028d8SEmmanuel Vadot { 233*b93028d8SEmmanuel Vadot 234*b93028d8SEmmanuel Vadot return (EOPNOTSUPP); 235*b93028d8SEmmanuel Vadot } 236