1*4b1a56afSjsg /* $OpenBSD: simplefb.c,v 1.15 2022/01/09 05:42:37 jsg Exp $ */ 26fd46d03Skettenis /* 36fd46d03Skettenis * Copyright (c) 2016 Mark Kettenis 46fd46d03Skettenis * 56fd46d03Skettenis * Permission to use, copy, modify, and distribute this software for any 66fd46d03Skettenis * purpose with or without fee is hereby granted, provided that the above 76fd46d03Skettenis * copyright notice and this permission notice appear in all copies. 86fd46d03Skettenis * 96fd46d03Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 106fd46d03Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 116fd46d03Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 126fd46d03Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 136fd46d03Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 146fd46d03Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 156fd46d03Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 166fd46d03Skettenis */ 176fd46d03Skettenis 186fd46d03Skettenis #include <sys/param.h> 196fd46d03Skettenis #include <sys/systm.h> 206fd46d03Skettenis #include <sys/device.h> 216fd46d03Skettenis 228186ecd8Skettenis #include <uvm/uvm_extern.h> 238186ecd8Skettenis 246fd46d03Skettenis #include <machine/bus.h> 256fd46d03Skettenis #include <machine/fdt.h> 266fd46d03Skettenis 276fd46d03Skettenis #include <dev/ofw/openfirm.h> 286fd46d03Skettenis #include <dev/ofw/fdt.h> 296fd46d03Skettenis 306fd46d03Skettenis #include <dev/wscons/wsconsio.h> 316fd46d03Skettenis #include <dev/wscons/wsdisplayvar.h> 326fd46d03Skettenis #include <dev/rasops/rasops.h> 336fd46d03Skettenis 3462b18b30Skettenis #define SIMPLEFB_WIDTH 160 3562b18b30Skettenis #define SIMPLEFB_HEIGHT 50 3662b18b30Skettenis 376fd46d03Skettenis struct simplefb_format { 386fd46d03Skettenis const char *format; 396fd46d03Skettenis int depth; 406fd46d03Skettenis int rpos, rnum; 416fd46d03Skettenis int gpos, gnum; 426fd46d03Skettenis int bpos, bnum; 436fd46d03Skettenis }; 446fd46d03Skettenis 456fd46d03Skettenis /* 46*4b1a56afSjsg * Supported pixel formats. Layout omitted when it matches the 476fd46d03Skettenis * rasops defaults. 486fd46d03Skettenis */ 496fd46d03Skettenis struct simplefb_format simplefb_formats[] = { 506fd46d03Skettenis { "r5g6b5", 16 }, 516fd46d03Skettenis { "x1r5g5b5", 15 }, 526fd46d03Skettenis { "a1r5g5b5", 15 }, 536fd46d03Skettenis { "r8g8b8", 24 }, 5462b18b30Skettenis { "x8r8g8b8", 32, 16, 8, 8, 8, 0, 8 }, 5562b18b30Skettenis { "a8r8g8b8", 32, 16, 8, 8, 8, 0, 8 }, 5662b18b30Skettenis { "x8b8g8r8", 32 }, 570af672a9Skettenis { "a8b8g8r8", 32 }, 580af672a9Skettenis { "x2r10g10b10", 32, 20, 10, 10, 10, 0, 10 }, 590af672a9Skettenis { "a2r10g10b10", 32, 20, 10, 10, 10, 0, 10 }, 606fd46d03Skettenis }; 616fd46d03Skettenis 626fd46d03Skettenis struct simplefb_softc { 636fd46d03Skettenis struct device sc_dev; 646fd46d03Skettenis bus_space_tag_t sc_iot; 656fd46d03Skettenis bus_space_handle_t sc_ioh; 666fd46d03Skettenis 676fd46d03Skettenis struct rasops_info sc_ri; 686fd46d03Skettenis struct wsscreen_descr sc_wsd; 696fd46d03Skettenis struct wsscreen_list sc_wsl; 706fd46d03Skettenis struct wsscreen_descr *sc_scrlist[1]; 716fd46d03Skettenis 726fd46d03Skettenis struct simplefb_format *sc_format; 736fd46d03Skettenis paddr_t sc_paddr; 746fd46d03Skettenis psize_t sc_psize; 756fd46d03Skettenis }; 766fd46d03Skettenis 7762b18b30Skettenis struct rasops_info simplefb_ri; 7862b18b30Skettenis struct wsscreen_descr simplefb_wsd = { "std" }; 7962b18b30Skettenis struct wsdisplay_charcell simplefb_bs[SIMPLEFB_WIDTH * SIMPLEFB_HEIGHT]; 8062b18b30Skettenis 816fd46d03Skettenis int simplefb_match(struct device *, void *, void *); 826fd46d03Skettenis void simplefb_attach(struct device *, struct device *, void *); 836fd46d03Skettenis 849fdf0c62Smpi const struct cfattach simplefb_ca = { 856fd46d03Skettenis sizeof(struct simplefb_softc), simplefb_match, simplefb_attach 866fd46d03Skettenis }; 876fd46d03Skettenis 886fd46d03Skettenis struct cfdriver simplefb_cd = { 896fd46d03Skettenis NULL, "simplefb", DV_DULL 906fd46d03Skettenis }; 916fd46d03Skettenis 9262b18b30Skettenis const char *simplefb_init(int, struct rasops_info *); 9362b18b30Skettenis 946fd46d03Skettenis int simplefb_wsioctl(void *, u_long, caddr_t, int, struct proc *); 956fd46d03Skettenis paddr_t simplefb_wsmmap(void *, off_t, int); 966fd46d03Skettenis int simplefb_alloc_screen(void *, const struct wsscreen_descr *, 97e0c3e559Sjsg void **, int *, int *, uint32_t *); 986fd46d03Skettenis 996fd46d03Skettenis struct wsdisplay_accessops simplefb_accessops = { 1006fd46d03Skettenis .ioctl = simplefb_wsioctl, 1016fd46d03Skettenis .mmap = simplefb_wsmmap, 1026fd46d03Skettenis .alloc_screen = simplefb_alloc_screen, 1036fd46d03Skettenis .free_screen = rasops_free_screen, 1046fd46d03Skettenis .show_screen = rasops_show_screen, 1056fd46d03Skettenis .getchar = rasops_getchar, 1066fd46d03Skettenis .load_font = rasops_load_font, 1076fd46d03Skettenis .list_font = rasops_list_font, 108ec4b3547Sfcambus .scrollback = rasops_scrollback 1096fd46d03Skettenis }; 1106fd46d03Skettenis 1116fd46d03Skettenis int 1126fd46d03Skettenis simplefb_match(struct device *parent, void *match, void *aux) 1136fd46d03Skettenis { 1146fd46d03Skettenis struct fdt_attach_args *faa = aux; 1156fd46d03Skettenis 11667e2424dSpatrick /* Don't attach if it has no address space. */ 11767e2424dSpatrick if (faa->fa_nreg < 1 || faa->fa_reg[0].size == 0) 11867e2424dSpatrick return 0; 11967e2424dSpatrick 1202723123cSkettenis /* Don't attach if another driver already claimed our framebuffer. */ 12167e2424dSpatrick if (rasops_check_framebuffer(faa->fa_reg[0].addr)) 1222723123cSkettenis return 0; 1232723123cSkettenis 1246fd46d03Skettenis return OF_is_compatible(faa->fa_node, "simple-framebuffer"); 1256fd46d03Skettenis } 1266fd46d03Skettenis 1276fd46d03Skettenis void 1286fd46d03Skettenis simplefb_attach(struct device *parent, struct device *self, void *aux) 1296fd46d03Skettenis { 1306fd46d03Skettenis struct simplefb_softc *sc = (struct simplefb_softc *)self; 1316fd46d03Skettenis struct fdt_attach_args *faa = aux; 1326fd46d03Skettenis struct rasops_info *ri = &sc->sc_ri; 1336fd46d03Skettenis struct wsemuldisplaydev_attach_args waa; 13462b18b30Skettenis const char *format; 13562b18b30Skettenis int console = 0; 136e0c3e559Sjsg uint32_t defattr; 1376fd46d03Skettenis 13862b18b30Skettenis format = simplefb_init(faa->fa_node, ri); 13962b18b30Skettenis if (format) { 1406fd46d03Skettenis printf(": unsupported format \"%s\"\n", format); 1416fd46d03Skettenis return; 1426fd46d03Skettenis } 1436fd46d03Skettenis 14462b18b30Skettenis if (faa->fa_node == stdout_node) 14562b18b30Skettenis console = 1; 14662b18b30Skettenis 1476fd46d03Skettenis sc->sc_iot = faa->fa_iot; 1486fd46d03Skettenis sc->sc_paddr = faa->fa_reg[0].addr; 1496fd46d03Skettenis sc->sc_psize = faa->fa_reg[0].size; 1506fd46d03Skettenis if (bus_space_map(sc->sc_iot, sc->sc_paddr, sc->sc_psize, 15162b18b30Skettenis BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh)) { 15262b18b30Skettenis printf(": can't map framebuffer\n"); 15362b18b30Skettenis return; 15462b18b30Skettenis } 1556fd46d03Skettenis 1566fd46d03Skettenis ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh); 1576fd46d03Skettenis ri->ri_hw = sc; 1586fd46d03Skettenis 15962b18b30Skettenis if (console) { 16062b18b30Skettenis /* Preserve contents. */ 16162b18b30Skettenis ri->ri_bs = simplefb_bs; 16262b18b30Skettenis ri->ri_flg &= ~RI_CLEAR; 16362b18b30Skettenis } 16462b18b30Skettenis 165f3d31b3eSfcambus printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 1666fd46d03Skettenis 16762b18b30Skettenis ri->ri_flg |= RI_VCONS; 16862b18b30Skettenis rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH); 1696fd46d03Skettenis 1706fd46d03Skettenis strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name)); 1716fd46d03Skettenis sc->sc_wsd.capabilities = ri->ri_caps; 1726fd46d03Skettenis sc->sc_wsd.nrows = ri->ri_rows; 1736fd46d03Skettenis sc->sc_wsd.ncols = ri->ri_cols; 1746fd46d03Skettenis sc->sc_wsd.textops = &ri->ri_ops; 1756fd46d03Skettenis sc->sc_wsd.fontwidth = ri->ri_font->fontwidth; 1766fd46d03Skettenis sc->sc_wsd.fontheight = ri->ri_font->fontheight; 1776fd46d03Skettenis 1786fd46d03Skettenis sc->sc_scrlist[0] = &sc->sc_wsd; 1796fd46d03Skettenis sc->sc_wsl.nscreens = 1; 1806fd46d03Skettenis sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 1816fd46d03Skettenis 18262b18b30Skettenis if (console) { 183fc223b23Sjsg ri->ri_ops.pack_attr(ri->ri_active, 0, 0, 0, &defattr); 18462b18b30Skettenis wsdisplay_cnattach(&sc->sc_wsd, ri->ri_active, 18562b18b30Skettenis simplefb_ri.ri_ccol, simplefb_ri.ri_crow, defattr); 18662b18b30Skettenis } 18762b18b30Skettenis 1886fd46d03Skettenis memset(&waa, 0, sizeof(waa)); 1896fd46d03Skettenis waa.scrdata = &sc->sc_wsl; 1906fd46d03Skettenis waa.accessops = &simplefb_accessops; 1916fd46d03Skettenis waa.accesscookie = ri; 19262b18b30Skettenis waa.console = console; 1936fd46d03Skettenis 1946fd46d03Skettenis config_found_sm(self, &waa, wsemuldisplaydevprint, 1956fd46d03Skettenis wsemuldisplaydevsubmatch); 1966fd46d03Skettenis } 1976fd46d03Skettenis 19862b18b30Skettenis const char * 19962b18b30Skettenis simplefb_init(int node, struct rasops_info *ri) 20062b18b30Skettenis { 20162b18b30Skettenis struct simplefb_format *fmt = NULL; 20262b18b30Skettenis static char format[16]; 20362b18b30Skettenis int i; 20462b18b30Skettenis 20562b18b30Skettenis format[0] = 0; 20662b18b30Skettenis OF_getprop(node, "format", format, sizeof(format)); 20762b18b30Skettenis format[sizeof(format) - 1] = 0; 20862b18b30Skettenis 20962b18b30Skettenis for (i = 0; i < nitems(simplefb_formats); i++) { 21062b18b30Skettenis if (strcmp(format, simplefb_formats[i].format) == 0) { 21162b18b30Skettenis fmt = &simplefb_formats[i]; 21262b18b30Skettenis break; 21362b18b30Skettenis } 21462b18b30Skettenis } 21562b18b30Skettenis if (fmt == NULL) 21662b18b30Skettenis return format; 21762b18b30Skettenis 21862b18b30Skettenis ri->ri_width = OF_getpropint(node, "width", 0); 21962b18b30Skettenis ri->ri_height = OF_getpropint(node, "height", 0); 22062b18b30Skettenis ri->ri_stride = OF_getpropint(node, "stride", 0); 22162b18b30Skettenis ri->ri_depth = fmt->depth; 22262b18b30Skettenis ri->ri_rpos = fmt->rpos; 22362b18b30Skettenis ri->ri_rnum = fmt->rnum; 22462b18b30Skettenis ri->ri_gpos = fmt->gpos; 22562b18b30Skettenis ri->ri_gnum = fmt->gnum; 22662b18b30Skettenis ri->ri_bpos = fmt->bpos; 22762b18b30Skettenis ri->ri_bnum = fmt->bnum; 22862b18b30Skettenis ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR | RI_WRONLY; 22962b18b30Skettenis 23062b18b30Skettenis return NULL; 23162b18b30Skettenis } 23262b18b30Skettenis 2336fd46d03Skettenis int 2346fd46d03Skettenis simplefb_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 2356fd46d03Skettenis { 2366fd46d03Skettenis struct rasops_info *ri = v; 2378cd7757eSkettenis struct wsdisplay_param *dp = (struct wsdisplay_param *)data; 2386fd46d03Skettenis struct wsdisplay_fbinfo *wdf; 2396fd46d03Skettenis 2406fd46d03Skettenis switch (cmd) { 2418cd7757eSkettenis case WSDISPLAYIO_GETPARAM: 2428cd7757eSkettenis if (ws_get_param) 2438cd7757eSkettenis return ws_get_param(dp); 2448cd7757eSkettenis return -1; 2458cd7757eSkettenis case WSDISPLAYIO_SETPARAM: 2468cd7757eSkettenis if (ws_set_param) 2478cd7757eSkettenis return ws_set_param(dp); 2488cd7757eSkettenis return -1; 2496fd46d03Skettenis case WSDISPLAYIO_GTYPE: 2507321c2f6Sjsg *(u_int *)data = WSDISPLAY_TYPE_EFIFB; 2516fd46d03Skettenis return 0; 2526fd46d03Skettenis case WSDISPLAYIO_GINFO: 2536fd46d03Skettenis wdf = (struct wsdisplay_fbinfo *)data; 2546fd46d03Skettenis wdf->width = ri->ri_width; 2556fd46d03Skettenis wdf->height = ri->ri_height; 2566fd46d03Skettenis wdf->depth = ri->ri_depth; 2576fd46d03Skettenis wdf->cmsize = 0; /* color map is unavailable */ 2586fd46d03Skettenis break; 2596fd46d03Skettenis case WSDISPLAYIO_LINEBYTES: 2606fd46d03Skettenis *(u_int *)data = ri->ri_stride; 2616fd46d03Skettenis break; 2626fd46d03Skettenis case WSDISPLAYIO_SMODE: 2636fd46d03Skettenis break; 2646fd46d03Skettenis case WSDISPLAYIO_GETSUPPORTEDDEPTH: 2656fd46d03Skettenis switch (ri->ri_depth) { 2666fd46d03Skettenis case 32: 2675e550f18Skettenis if (ri->ri_rnum == 10) 2685e550f18Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_30; 2695e550f18Skettenis else 2706fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 2716fd46d03Skettenis break; 2726fd46d03Skettenis case 24: 2736fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_24_24; 2746fd46d03Skettenis break; 2756fd46d03Skettenis case 16: 2766fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_16; 2776fd46d03Skettenis break; 2786fd46d03Skettenis case 15: 2796fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_15; 2806fd46d03Skettenis break; 2816fd46d03Skettenis default: 2826fd46d03Skettenis return -1; 2836fd46d03Skettenis } 2846fd46d03Skettenis break; 2856fd46d03Skettenis default: 2866fd46d03Skettenis return -1; 2876fd46d03Skettenis } 2886fd46d03Skettenis 2896fd46d03Skettenis return 0; 2906fd46d03Skettenis } 2916fd46d03Skettenis 2926fd46d03Skettenis paddr_t 2936fd46d03Skettenis simplefb_wsmmap(void *v, off_t off, int prot) 2946fd46d03Skettenis { 2956fd46d03Skettenis struct rasops_info *ri = v; 2966fd46d03Skettenis struct simplefb_softc *sc = ri->ri_hw; 2976fd46d03Skettenis 2986fd46d03Skettenis if (off < 0 || off >= sc->sc_psize) 2996fd46d03Skettenis return -1; 3006fd46d03Skettenis 3018186ecd8Skettenis return ((sc->sc_paddr + off) | PMAP_NOCACHE); 3026fd46d03Skettenis } 3036fd46d03Skettenis 3046fd46d03Skettenis int 3056fd46d03Skettenis simplefb_alloc_screen(void *v, const struct wsscreen_descr *type, 306e0c3e559Sjsg void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 3076fd46d03Skettenis { 3086fd46d03Skettenis return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp); 3096fd46d03Skettenis } 31062b18b30Skettenis 31162b18b30Skettenis #include "ukbd.h" 31262b18b30Skettenis 31362b18b30Skettenis #if NUKBD > 0 31462b18b30Skettenis #include <dev/usb/ukbdvar.h> 31562b18b30Skettenis #endif 31662b18b30Skettenis 31762b18b30Skettenis void 31862b18b30Skettenis simplefb_init_cons(bus_space_tag_t iot) 31962b18b30Skettenis { 32062b18b30Skettenis struct rasops_info *ri = &simplefb_ri; 32162b18b30Skettenis bus_space_handle_t ioh; 32262b18b30Skettenis struct fdt_reg reg; 32362b18b30Skettenis void *node; 324e0c3e559Sjsg uint32_t defattr = 0; 32562b18b30Skettenis 32662b18b30Skettenis node = fdt_find_cons("simple-framebuffer"); 32762b18b30Skettenis if (node == NULL) 32862b18b30Skettenis return; 32962b18b30Skettenis 33062b18b30Skettenis if (fdt_get_reg(node, 0, ®)) 33162b18b30Skettenis return; 33262b18b30Skettenis 33362b18b30Skettenis if (bus_space_map(iot, reg.addr, reg.size, 33462b18b30Skettenis BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh)) 33562b18b30Skettenis return; 33662b18b30Skettenis 33762b18b30Skettenis ri->ri_bits = bus_space_vaddr(iot, ioh); 33862b18b30Skettenis 33962b18b30Skettenis if (simplefb_init(stdout_node, ri)) 34062b18b30Skettenis return; 34162b18b30Skettenis 34262b18b30Skettenis ri->ri_bs = simplefb_bs; 34362b18b30Skettenis rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH); 34462b18b30Skettenis 34562b18b30Skettenis simplefb_wsd.capabilities = ri->ri_caps; 34662b18b30Skettenis simplefb_wsd.ncols = ri->ri_cols; 34762b18b30Skettenis simplefb_wsd.nrows = ri->ri_rows; 34862b18b30Skettenis simplefb_wsd.textops = &ri->ri_ops; 34962b18b30Skettenis simplefb_wsd.fontwidth = ri->ri_font->fontwidth; 35062b18b30Skettenis simplefb_wsd.fontheight = ri->ri_font->fontheight; 35162b18b30Skettenis 352fc223b23Sjsg ri->ri_ops.pack_attr(ri, 0, 0, 0, &defattr); 35362b18b30Skettenis wsdisplay_cnattach(&simplefb_wsd, ri, 0, 0, defattr); 35462b18b30Skettenis 35562b18b30Skettenis #if NUKBD > 0 35662b18b30Skettenis /* Allow USB keyboards to become the console input device. */ 35762b18b30Skettenis ukbd_cnattach(); 35862b18b30Skettenis #endif 35962b18b30Skettenis } 360