1 /* $OpenBSD: simplefb.c,v 1.2 2017/08/27 12:42:22 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2016 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <machine/bus.h> 23 #include <machine/fdt.h> 24 25 #include <dev/ofw/openfirm.h> 26 #include <dev/ofw/fdt.h> 27 28 #include <dev/wscons/wsconsio.h> 29 #include <dev/wscons/wsdisplayvar.h> 30 #include <dev/rasops/rasops.h> 31 32 #define SIMPLEFB_WIDTH 160 33 #define SIMPLEFB_HEIGHT 50 34 35 struct simplefb_format { 36 const char *format; 37 int depth; 38 int rpos, rnum; 39 int gpos, gnum; 40 int bpos, bnum; 41 }; 42 43 /* 44 * Supported pixel formats. Layout ommitted when it matches the 45 * rasops defaults. 46 */ 47 struct simplefb_format simplefb_formats[] = { 48 { "r5g6b5", 16 }, 49 { "x1r5g5b5", 15 }, 50 { "a1r5g5b5", 15 }, 51 { "r8g8b8", 24 }, 52 { "x8r8g8b8", 32, 16, 8, 8, 8, 0, 8 }, 53 { "a8r8g8b8", 32, 16, 8, 8, 8, 0, 8 }, 54 { "x8b8g8r8", 32 }, 55 { "a8b8g8r8", 32 } 56 }; 57 58 struct simplefb_softc { 59 struct device sc_dev; 60 bus_space_tag_t sc_iot; 61 bus_space_handle_t sc_ioh; 62 63 struct rasops_info sc_ri; 64 struct wsscreen_descr sc_wsd; 65 struct wsscreen_list sc_wsl; 66 struct wsscreen_descr *sc_scrlist[1]; 67 68 struct simplefb_format *sc_format; 69 paddr_t sc_paddr; 70 psize_t sc_psize; 71 }; 72 73 struct rasops_info simplefb_ri; 74 struct wsscreen_descr simplefb_wsd = { "std" }; 75 struct wsdisplay_charcell simplefb_bs[SIMPLEFB_WIDTH * SIMPLEFB_HEIGHT]; 76 77 int simplefb_match(struct device *, void *, void *); 78 void simplefb_attach(struct device *, struct device *, void *); 79 80 struct cfattach simplefb_ca = { 81 sizeof(struct simplefb_softc), simplefb_match, simplefb_attach 82 }; 83 84 struct cfdriver simplefb_cd = { 85 NULL, "simplefb", DV_DULL 86 }; 87 88 const char *simplefb_init(int, struct rasops_info *); 89 90 int simplefb_wsioctl(void *, u_long, caddr_t, int, struct proc *); 91 paddr_t simplefb_wsmmap(void *, off_t, int); 92 int simplefb_alloc_screen(void *, const struct wsscreen_descr *, 93 void **, int *, int *, long *); 94 95 struct wsdisplay_accessops simplefb_accessops = { 96 .ioctl = simplefb_wsioctl, 97 .mmap = simplefb_wsmmap, 98 .alloc_screen = simplefb_alloc_screen, 99 .free_screen = rasops_free_screen, 100 .show_screen = rasops_show_screen, 101 .getchar = rasops_getchar, 102 .load_font = rasops_load_font, 103 .list_font = rasops_list_font, 104 }; 105 106 int 107 simplefb_match(struct device *parent, void *match, void *aux) 108 { 109 struct fdt_attach_args *faa = aux; 110 111 return OF_is_compatible(faa->fa_node, "simple-framebuffer"); 112 } 113 114 void 115 simplefb_attach(struct device *parent, struct device *self, void *aux) 116 { 117 struct simplefb_softc *sc = (struct simplefb_softc *)self; 118 struct fdt_attach_args *faa = aux; 119 struct rasops_info *ri = &sc->sc_ri; 120 struct wsemuldisplaydev_attach_args waa; 121 const char *format; 122 int console = 0; 123 long defattr; 124 125 if (faa->fa_nreg < 1) 126 return; 127 128 format = simplefb_init(faa->fa_node, ri); 129 if (format) { 130 printf(": unsupported format \"%s\"\n", format); 131 return; 132 } 133 134 if (faa->fa_node == stdout_node) 135 console = 1; 136 137 sc->sc_iot = faa->fa_iot; 138 sc->sc_paddr = faa->fa_reg[0].addr; 139 sc->sc_psize = faa->fa_reg[0].size; 140 if (bus_space_map(sc->sc_iot, sc->sc_paddr, sc->sc_psize, 141 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh)) { 142 printf(": can't map framebuffer\n"); 143 return; 144 } 145 146 ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh); 147 ri->ri_hw = sc; 148 149 if (console) { 150 /* Preserve contents. */ 151 ri->ri_bs = simplefb_bs; 152 ri->ri_flg &= ~RI_CLEAR; 153 } 154 155 printf(": %dx%d\n", ri->ri_width, ri->ri_height); 156 157 ri->ri_flg |= RI_VCONS; 158 rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH); 159 160 strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name)); 161 sc->sc_wsd.capabilities = ri->ri_caps; 162 sc->sc_wsd.nrows = ri->ri_rows; 163 sc->sc_wsd.ncols = ri->ri_cols; 164 sc->sc_wsd.textops = &ri->ri_ops; 165 sc->sc_wsd.fontwidth = ri->ri_font->fontwidth; 166 sc->sc_wsd.fontheight = ri->ri_font->fontheight; 167 168 sc->sc_scrlist[0] = &sc->sc_wsd; 169 sc->sc_wsl.nscreens = 1; 170 sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 171 172 if (console) { 173 ri->ri_ops.alloc_attr(ri->ri_active, 0, 0, 0, &defattr); 174 wsdisplay_cnattach(&sc->sc_wsd, ri->ri_active, 175 simplefb_ri.ri_ccol, simplefb_ri.ri_crow, defattr); 176 } 177 178 memset(&waa, 0, sizeof(waa)); 179 waa.scrdata = &sc->sc_wsl; 180 waa.accessops = &simplefb_accessops; 181 waa.accesscookie = ri; 182 waa.console = console; 183 184 config_found_sm(self, &waa, wsemuldisplaydevprint, 185 wsemuldisplaydevsubmatch); 186 } 187 188 const char * 189 simplefb_init(int node, struct rasops_info *ri) 190 { 191 struct simplefb_format *fmt = NULL; 192 static char format[16]; 193 int i; 194 195 format[0] = 0; 196 OF_getprop(node, "format", format, sizeof(format)); 197 format[sizeof(format) - 1] = 0; 198 199 for (i = 0; i < nitems(simplefb_formats); i++) { 200 if (strcmp(format, simplefb_formats[i].format) == 0) { 201 fmt = &simplefb_formats[i]; 202 break; 203 } 204 } 205 if (fmt == NULL) 206 return format; 207 208 ri->ri_width = OF_getpropint(node, "width", 0); 209 ri->ri_height = OF_getpropint(node, "height", 0); 210 ri->ri_stride = OF_getpropint(node, "stride", 0); 211 ri->ri_depth = fmt->depth; 212 ri->ri_rpos = fmt->rpos; 213 ri->ri_rnum = fmt->rnum; 214 ri->ri_gpos = fmt->gpos; 215 ri->ri_gnum = fmt->gnum; 216 ri->ri_bpos = fmt->bpos; 217 ri->ri_bnum = fmt->bnum; 218 ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR | RI_WRONLY; 219 220 return NULL; 221 } 222 223 int 224 simplefb_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 225 { 226 struct rasops_info *ri = v; 227 struct wsdisplay_fbinfo *wdf; 228 229 switch (cmd) { 230 case WSDISPLAYIO_GTYPE: 231 *(int *)data = WSDISPLAY_TYPE_EFIFB; 232 return 0; 233 case WSDISPLAYIO_GINFO: 234 wdf = (struct wsdisplay_fbinfo *)data; 235 wdf->width = ri->ri_width; 236 wdf->height = ri->ri_height; 237 wdf->depth = ri->ri_depth; 238 wdf->cmsize = 0; /* color map is unavailable */ 239 break; 240 case WSDISPLAYIO_LINEBYTES: 241 *(u_int *)data = ri->ri_stride; 242 break; 243 case WSDISPLAYIO_SMODE: 244 break; 245 case WSDISPLAYIO_GETSUPPORTEDDEPTH: 246 switch (ri->ri_depth) { 247 case 32: 248 *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 249 break; 250 case 24: 251 *(u_int *)data = WSDISPLAYIO_DEPTH_24_24; 252 break; 253 case 16: 254 *(u_int *)data = WSDISPLAYIO_DEPTH_16; 255 break; 256 case 15: 257 *(u_int *)data = WSDISPLAYIO_DEPTH_15; 258 break; 259 default: 260 return -1; 261 } 262 break; 263 default: 264 return -1; 265 } 266 267 return 0; 268 } 269 270 paddr_t 271 simplefb_wsmmap(void *v, off_t off, int prot) 272 { 273 struct rasops_info *ri = v; 274 struct simplefb_softc *sc = ri->ri_hw; 275 276 if (off < 0 || off >= sc->sc_psize) 277 return -1; 278 279 return sc->sc_paddr + off; 280 } 281 282 int 283 simplefb_alloc_screen(void *v, const struct wsscreen_descr *type, 284 void **cookiep, int *curxp, int *curyp, long *attrp) 285 { 286 return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp); 287 } 288 289 #include "ukbd.h" 290 291 #if NUKBD > 0 292 #include <dev/usb/ukbdvar.h> 293 #endif 294 295 void 296 simplefb_init_cons(bus_space_tag_t iot) 297 { 298 struct rasops_info *ri = &simplefb_ri; 299 bus_space_handle_t ioh; 300 struct fdt_reg reg; 301 void *node; 302 long defattr = 0; 303 304 node = fdt_find_cons("simple-framebuffer"); 305 if (node == NULL) 306 return; 307 308 if (fdt_get_reg(node, 0, ®)) 309 return; 310 311 if (bus_space_map(iot, reg.addr, reg.size, 312 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh)) 313 return; 314 315 ri->ri_bits = bus_space_vaddr(iot, ioh); 316 317 if (simplefb_init(stdout_node, ri)) 318 return; 319 320 ri->ri_bs = simplefb_bs; 321 rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH); 322 323 simplefb_wsd.capabilities = ri->ri_caps; 324 simplefb_wsd.ncols = ri->ri_cols; 325 simplefb_wsd.nrows = ri->ri_rows; 326 simplefb_wsd.textops = &ri->ri_ops; 327 simplefb_wsd.fontwidth = ri->ri_font->fontwidth; 328 simplefb_wsd.fontheight = ri->ri_font->fontheight; 329 330 ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr); 331 wsdisplay_cnattach(&simplefb_wsd, ri, 0, 0, defattr); 332 333 #if NUKBD > 0 334 /* Allow USB keyboards to become the console input device. */ 335 ukbd_cnattach(); 336 #endif 337 } 338