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