1*afbb90bcStobhe /* $OpenBSD: simplefb.c,v 1.21 2024/11/12 20:52:35 tobhe 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 /* 464b1a56afSjsg * Supported pixel formats. Layout omitted when it matches the 476fd46d03Skettenis * rasops defaults. 486fd46d03Skettenis */ 49c39c0495Skn const struct simplefb_format simplefb_formats[] = { 50*afbb90bcStobhe { "r5g6b5", 16, 11, 5, 5, 6, 0, 5 }, 51*afbb90bcStobhe { "x1r5g5b5", 15, 10, 5, 5, 5, 0, 5 }, 52*afbb90bcStobhe { "a1r5g5b5", 15, 10, 5, 5, 5, 0, 5 }, 53*afbb90bcStobhe { "r8g8b8", 24, 16, 8, 8, 8, 0, 8 }, 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 77f2edca47Stobhe void (*simplefb_burn_hook)(u_int) = NULL; 78f2edca47Stobhe 7962b18b30Skettenis struct rasops_info simplefb_ri; 8062b18b30Skettenis struct wsscreen_descr simplefb_wsd = { "std" }; 8162b18b30Skettenis struct wsdisplay_charcell simplefb_bs[SIMPLEFB_WIDTH * SIMPLEFB_HEIGHT]; 8262b18b30Skettenis 836fd46d03Skettenis int simplefb_match(struct device *, void *, void *); 846fd46d03Skettenis void simplefb_attach(struct device *, struct device *, void *); 856fd46d03Skettenis 869fdf0c62Smpi const struct cfattach simplefb_ca = { 876fd46d03Skettenis sizeof(struct simplefb_softc), simplefb_match, simplefb_attach 886fd46d03Skettenis }; 896fd46d03Skettenis 906fd46d03Skettenis struct cfdriver simplefb_cd = { 916fd46d03Skettenis NULL, "simplefb", DV_DULL 926fd46d03Skettenis }; 936fd46d03Skettenis 9462b18b30Skettenis const char *simplefb_init(int, struct rasops_info *); 9562b18b30Skettenis 966fd46d03Skettenis int simplefb_wsioctl(void *, u_long, caddr_t, int, struct proc *); 976fd46d03Skettenis paddr_t simplefb_wsmmap(void *, off_t, int); 986fd46d03Skettenis int simplefb_alloc_screen(void *, const struct wsscreen_descr *, 99e0c3e559Sjsg void **, int *, int *, uint32_t *); 100f2edca47Stobhe void simplefb_burn_screen(void *, u_int, u_int); 1016fd46d03Skettenis 1026fd46d03Skettenis struct wsdisplay_accessops simplefb_accessops = { 1036fd46d03Skettenis .ioctl = simplefb_wsioctl, 1046fd46d03Skettenis .mmap = simplefb_wsmmap, 1056fd46d03Skettenis .alloc_screen = simplefb_alloc_screen, 1066fd46d03Skettenis .free_screen = rasops_free_screen, 1076fd46d03Skettenis .show_screen = rasops_show_screen, 1086fd46d03Skettenis .getchar = rasops_getchar, 1096fd46d03Skettenis .load_font = rasops_load_font, 1106fd46d03Skettenis .list_font = rasops_list_font, 111f2edca47Stobhe .scrollback = rasops_scrollback, 112f2edca47Stobhe .burn_screen = simplefb_burn_screen, 1136fd46d03Skettenis }; 1146fd46d03Skettenis 1156fd46d03Skettenis int 1166fd46d03Skettenis simplefb_match(struct device *parent, void *match, void *aux) 1176fd46d03Skettenis { 1186fd46d03Skettenis struct fdt_attach_args *faa = aux; 1196fd46d03Skettenis 12067e2424dSpatrick /* Don't attach if it has no address space. */ 12167e2424dSpatrick if (faa->fa_nreg < 1 || faa->fa_reg[0].size == 0) 12267e2424dSpatrick return 0; 12367e2424dSpatrick 1242723123cSkettenis /* Don't attach if another driver already claimed our framebuffer. */ 12567e2424dSpatrick if (rasops_check_framebuffer(faa->fa_reg[0].addr)) 1262723123cSkettenis return 0; 1272723123cSkettenis 1286fd46d03Skettenis return OF_is_compatible(faa->fa_node, "simple-framebuffer"); 1296fd46d03Skettenis } 1306fd46d03Skettenis 1316fd46d03Skettenis void 1326fd46d03Skettenis simplefb_attach(struct device *parent, struct device *self, void *aux) 1336fd46d03Skettenis { 1346fd46d03Skettenis struct simplefb_softc *sc = (struct simplefb_softc *)self; 1356fd46d03Skettenis struct fdt_attach_args *faa = aux; 1366fd46d03Skettenis struct rasops_info *ri = &sc->sc_ri; 1376fd46d03Skettenis struct wsemuldisplaydev_attach_args waa; 13862b18b30Skettenis const char *format; 13962b18b30Skettenis int console = 0; 140e0c3e559Sjsg uint32_t defattr; 1416fd46d03Skettenis 14262b18b30Skettenis format = simplefb_init(faa->fa_node, ri); 14362b18b30Skettenis if (format) { 1446fd46d03Skettenis printf(": unsupported format \"%s\"\n", format); 1456fd46d03Skettenis return; 1466fd46d03Skettenis } 1476fd46d03Skettenis 14862b18b30Skettenis if (faa->fa_node == stdout_node) 14962b18b30Skettenis console = 1; 15062b18b30Skettenis 1516fd46d03Skettenis sc->sc_iot = faa->fa_iot; 1526fd46d03Skettenis sc->sc_paddr = faa->fa_reg[0].addr; 1536fd46d03Skettenis sc->sc_psize = faa->fa_reg[0].size; 1546fd46d03Skettenis if (bus_space_map(sc->sc_iot, sc->sc_paddr, sc->sc_psize, 15562b18b30Skettenis BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh)) { 15662b18b30Skettenis printf(": can't map framebuffer\n"); 15762b18b30Skettenis return; 15862b18b30Skettenis } 1596fd46d03Skettenis 1606fd46d03Skettenis ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh); 1616fd46d03Skettenis ri->ri_hw = sc; 1626fd46d03Skettenis 16362b18b30Skettenis if (console) { 16462b18b30Skettenis /* Preserve contents. */ 16562b18b30Skettenis ri->ri_bs = simplefb_bs; 16662b18b30Skettenis ri->ri_flg &= ~RI_CLEAR; 16762b18b30Skettenis } 16862b18b30Skettenis 169f3d31b3eSfcambus printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 1706fd46d03Skettenis 17162b18b30Skettenis ri->ri_flg |= RI_VCONS; 17262b18b30Skettenis rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH); 1736fd46d03Skettenis 1746fd46d03Skettenis strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name)); 1756fd46d03Skettenis sc->sc_wsd.capabilities = ri->ri_caps; 1766fd46d03Skettenis sc->sc_wsd.nrows = ri->ri_rows; 1776fd46d03Skettenis sc->sc_wsd.ncols = ri->ri_cols; 1786fd46d03Skettenis sc->sc_wsd.textops = &ri->ri_ops; 1796fd46d03Skettenis sc->sc_wsd.fontwidth = ri->ri_font->fontwidth; 1806fd46d03Skettenis sc->sc_wsd.fontheight = ri->ri_font->fontheight; 1816fd46d03Skettenis 1826fd46d03Skettenis sc->sc_scrlist[0] = &sc->sc_wsd; 1836fd46d03Skettenis sc->sc_wsl.nscreens = 1; 1846fd46d03Skettenis sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist; 1856fd46d03Skettenis 18662b18b30Skettenis if (console) { 187fc223b23Sjsg ri->ri_ops.pack_attr(ri->ri_active, 0, 0, 0, &defattr); 18862b18b30Skettenis wsdisplay_cnattach(&sc->sc_wsd, ri->ri_active, 18962b18b30Skettenis simplefb_ri.ri_ccol, simplefb_ri.ri_crow, defattr); 19062b18b30Skettenis } 19162b18b30Skettenis 1926fd46d03Skettenis memset(&waa, 0, sizeof(waa)); 1936fd46d03Skettenis waa.scrdata = &sc->sc_wsl; 1946fd46d03Skettenis waa.accessops = &simplefb_accessops; 1956fd46d03Skettenis waa.accesscookie = ri; 19662b18b30Skettenis waa.console = console; 1976fd46d03Skettenis 1986fd46d03Skettenis config_found_sm(self, &waa, wsemuldisplaydevprint, 1996fd46d03Skettenis wsemuldisplaydevsubmatch); 2006fd46d03Skettenis } 2016fd46d03Skettenis 20262b18b30Skettenis const char * 20362b18b30Skettenis simplefb_init(int node, struct rasops_info *ri) 20462b18b30Skettenis { 205c39c0495Skn const struct simplefb_format *fmt = NULL; 20662b18b30Skettenis static char format[16]; 20762b18b30Skettenis int i; 20862b18b30Skettenis 20962b18b30Skettenis format[0] = 0; 21062b18b30Skettenis OF_getprop(node, "format", format, sizeof(format)); 21162b18b30Skettenis format[sizeof(format) - 1] = 0; 21262b18b30Skettenis 21362b18b30Skettenis for (i = 0; i < nitems(simplefb_formats); i++) { 21462b18b30Skettenis if (strcmp(format, simplefb_formats[i].format) == 0) { 21562b18b30Skettenis fmt = &simplefb_formats[i]; 21662b18b30Skettenis break; 21762b18b30Skettenis } 21862b18b30Skettenis } 21962b18b30Skettenis if (fmt == NULL) 22062b18b30Skettenis return format; 22162b18b30Skettenis 22262b18b30Skettenis ri->ri_width = OF_getpropint(node, "width", 0); 22362b18b30Skettenis ri->ri_height = OF_getpropint(node, "height", 0); 22462b18b30Skettenis ri->ri_stride = OF_getpropint(node, "stride", 0); 22562b18b30Skettenis ri->ri_depth = fmt->depth; 22662b18b30Skettenis ri->ri_rpos = fmt->rpos; 22762b18b30Skettenis ri->ri_rnum = fmt->rnum; 22862b18b30Skettenis ri->ri_gpos = fmt->gpos; 22962b18b30Skettenis ri->ri_gnum = fmt->gnum; 23062b18b30Skettenis ri->ri_bpos = fmt->bpos; 23162b18b30Skettenis ri->ri_bnum = fmt->bnum; 23262b18b30Skettenis ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR | RI_WRONLY; 23362b18b30Skettenis 23462b18b30Skettenis return NULL; 23562b18b30Skettenis } 23662b18b30Skettenis 2376fd46d03Skettenis int 2386fd46d03Skettenis simplefb_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 2396fd46d03Skettenis { 2406fd46d03Skettenis struct rasops_info *ri = v; 24163294167Skettenis struct simplefb_softc *sc = ri->ri_hw; 2428cd7757eSkettenis struct wsdisplay_param *dp = (struct wsdisplay_param *)data; 2436fd46d03Skettenis struct wsdisplay_fbinfo *wdf; 2446fd46d03Skettenis 2456fd46d03Skettenis switch (cmd) { 2468cd7757eSkettenis case WSDISPLAYIO_GETPARAM: 2478cd7757eSkettenis if (ws_get_param) 2488cd7757eSkettenis return ws_get_param(dp); 2498cd7757eSkettenis return -1; 2508cd7757eSkettenis case WSDISPLAYIO_SETPARAM: 2518cd7757eSkettenis if (ws_set_param) 2528cd7757eSkettenis return ws_set_param(dp); 2538cd7757eSkettenis return -1; 2546fd46d03Skettenis case WSDISPLAYIO_GTYPE: 2557321c2f6Sjsg *(u_int *)data = WSDISPLAY_TYPE_EFIFB; 2566fd46d03Skettenis return 0; 2576fd46d03Skettenis case WSDISPLAYIO_GINFO: 2586fd46d03Skettenis wdf = (struct wsdisplay_fbinfo *)data; 2596fd46d03Skettenis wdf->width = ri->ri_width; 2606fd46d03Skettenis wdf->height = ri->ri_height; 2616fd46d03Skettenis wdf->depth = ri->ri_depth; 26263294167Skettenis wdf->stride = ri->ri_stride; 26363294167Skettenis wdf->offset = sc->sc_paddr & PAGE_MASK; 2646fd46d03Skettenis wdf->cmsize = 0; /* color map is unavailable */ 2656fd46d03Skettenis break; 2666fd46d03Skettenis case WSDISPLAYIO_LINEBYTES: 2676fd46d03Skettenis *(u_int *)data = ri->ri_stride; 2686fd46d03Skettenis break; 2696fd46d03Skettenis case WSDISPLAYIO_SMODE: 2706fd46d03Skettenis break; 2716fd46d03Skettenis case WSDISPLAYIO_GETSUPPORTEDDEPTH: 2726fd46d03Skettenis switch (ri->ri_depth) { 2736fd46d03Skettenis case 32: 2745e550f18Skettenis if (ri->ri_rnum == 10) 2755e550f18Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_30; 2765e550f18Skettenis else 2776fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; 2786fd46d03Skettenis break; 2796fd46d03Skettenis case 24: 2806fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_24_24; 2816fd46d03Skettenis break; 2826fd46d03Skettenis case 16: 2836fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_16; 2846fd46d03Skettenis break; 2856fd46d03Skettenis case 15: 2866fd46d03Skettenis *(u_int *)data = WSDISPLAYIO_DEPTH_15; 2876fd46d03Skettenis break; 2886fd46d03Skettenis default: 2896fd46d03Skettenis return -1; 2906fd46d03Skettenis } 2916fd46d03Skettenis break; 292e0f76f79Skettenis case WSDISPLAYIO_GVIDEO: 293e0f76f79Skettenis case WSDISPLAYIO_SVIDEO: 294e0f76f79Skettenis break; 2956fd46d03Skettenis default: 2966fd46d03Skettenis return -1; 2976fd46d03Skettenis } 2986fd46d03Skettenis 2996fd46d03Skettenis return 0; 3006fd46d03Skettenis } 3016fd46d03Skettenis 3026fd46d03Skettenis paddr_t 3036fd46d03Skettenis simplefb_wsmmap(void *v, off_t off, int prot) 3046fd46d03Skettenis { 3056fd46d03Skettenis struct rasops_info *ri = v; 3066fd46d03Skettenis struct simplefb_softc *sc = ri->ri_hw; 3076fd46d03Skettenis 308ec0359a7Skettenis if (off < 0 || off >= (sc->sc_psize + (sc->sc_paddr & PAGE_MASK))) 3096fd46d03Skettenis return -1; 3106fd46d03Skettenis 311ec0359a7Skettenis return (((sc->sc_paddr & ~PAGE_MASK) + off) | PMAP_NOCACHE); 3126fd46d03Skettenis } 3136fd46d03Skettenis 3146fd46d03Skettenis int 3156fd46d03Skettenis simplefb_alloc_screen(void *v, const struct wsscreen_descr *type, 316e0c3e559Sjsg void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 3176fd46d03Skettenis { 3186fd46d03Skettenis return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp); 3196fd46d03Skettenis } 32062b18b30Skettenis 321f2edca47Stobhe void 322f2edca47Stobhe simplefb_burn_screen(void *v, u_int on, u_int flags) 323f2edca47Stobhe { 324f2edca47Stobhe if (simplefb_burn_hook != NULL) 325f2edca47Stobhe simplefb_burn_hook(on); 326f2edca47Stobhe } 327f2edca47Stobhe 32862b18b30Skettenis #include "ukbd.h" 32962b18b30Skettenis 33062b18b30Skettenis #if NUKBD > 0 33162b18b30Skettenis #include <dev/usb/ukbdvar.h> 33262b18b30Skettenis #endif 33362b18b30Skettenis 33462b18b30Skettenis void 33562b18b30Skettenis simplefb_init_cons(bus_space_tag_t iot) 33662b18b30Skettenis { 33762b18b30Skettenis struct rasops_info *ri = &simplefb_ri; 33862b18b30Skettenis bus_space_handle_t ioh; 33962b18b30Skettenis struct fdt_reg reg; 34062b18b30Skettenis void *node; 341e0c3e559Sjsg uint32_t defattr = 0; 34262b18b30Skettenis 34362b18b30Skettenis node = fdt_find_cons("simple-framebuffer"); 34462b18b30Skettenis if (node == NULL) 34562b18b30Skettenis return; 34662b18b30Skettenis 34762b18b30Skettenis if (fdt_get_reg(node, 0, ®)) 34862b18b30Skettenis return; 34962b18b30Skettenis 35062b18b30Skettenis if (bus_space_map(iot, reg.addr, reg.size, 35162b18b30Skettenis BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh)) 35262b18b30Skettenis return; 35362b18b30Skettenis 35462b18b30Skettenis ri->ri_bits = bus_space_vaddr(iot, ioh); 35562b18b30Skettenis 35662b18b30Skettenis if (simplefb_init(stdout_node, ri)) 35762b18b30Skettenis return; 35862b18b30Skettenis 35962b18b30Skettenis ri->ri_bs = simplefb_bs; 36062b18b30Skettenis rasops_init(ri, SIMPLEFB_HEIGHT, SIMPLEFB_WIDTH); 36162b18b30Skettenis 36262b18b30Skettenis simplefb_wsd.capabilities = ri->ri_caps; 36362b18b30Skettenis simplefb_wsd.ncols = ri->ri_cols; 36462b18b30Skettenis simplefb_wsd.nrows = ri->ri_rows; 36562b18b30Skettenis simplefb_wsd.textops = &ri->ri_ops; 36662b18b30Skettenis simplefb_wsd.fontwidth = ri->ri_font->fontwidth; 36762b18b30Skettenis simplefb_wsd.fontheight = ri->ri_font->fontheight; 36862b18b30Skettenis 369fc223b23Sjsg ri->ri_ops.pack_attr(ri, 0, 0, 0, &defattr); 37062b18b30Skettenis wsdisplay_cnattach(&simplefb_wsd, ri, 0, 0, defattr); 37162b18b30Skettenis 37262b18b30Skettenis #if NUKBD > 0 37362b18b30Skettenis /* Allow USB keyboards to become the console input device. */ 37462b18b30Skettenis ukbd_cnattach(); 37562b18b30Skettenis #endif 37662b18b30Skettenis } 377