xref: /openbsd/sys/dev/fdt/simplefb.c (revision 4b1a56af)
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, &reg))
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