xref: /openbsd-src/sys/dev/fdt/simplefb.c (revision d59bb9942320b767f2a19aaa7690c8c6e30b724c)
1 /*	$OpenBSD: simplefb.c,v 1.1 2017/01/03 19:57:01 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 struct simplefb_format {
33 	const char *format;
34 	int depth;
35 	int rpos, rnum;
36 	int gpos, gnum;
37 	int bpos, bnum;
38 };
39 
40 /*
41  * Supported pixel formats.  Layout ommitted when it matches the
42  * rasops defaults.
43  */
44 struct simplefb_format simplefb_formats[] = {
45 	{ "r5g6b5", 16 },
46 	{ "x1r5g5b5", 15 },
47 	{ "a1r5g5b5", 15 },
48 	{ "r8g8b8", 24 },
49 	{ "x8r8g8b8", 32 },
50 	{ "a8r8g8b8", 32 },
51 	{ "a8b8g8r8", 32, 0, 8, 8, 8, 16, 8 }
52 };
53 
54 struct simplefb_softc {
55 	struct device		sc_dev;
56 	bus_space_tag_t		sc_iot;
57 	bus_space_handle_t	sc_ioh;
58 
59 	struct rasops_info	sc_ri;
60 	struct wsscreen_descr	sc_wsd;
61 	struct wsscreen_list	sc_wsl;
62 	struct wsscreen_descr	*sc_scrlist[1];
63 
64 	struct simplefb_format	*sc_format;
65 	paddr_t			sc_paddr;
66 	psize_t			sc_psize;
67 };
68 
69 int	simplefb_match(struct device *, void *, void *);
70 void	simplefb_attach(struct device *, struct device *, void *);
71 
72 struct cfattach simplefb_ca = {
73 	sizeof(struct simplefb_softc), simplefb_match, simplefb_attach
74 };
75 
76 struct cfdriver simplefb_cd = {
77 	NULL, "simplefb", DV_DULL
78 };
79 
80 int	simplefb_wsioctl(void *, u_long, caddr_t, int, struct proc *);
81 paddr_t	simplefb_wsmmap(void *, off_t, int);
82 int	simplefb_alloc_screen(void *, const struct wsscreen_descr *,
83 	    void **, int *, int *, long *);
84 
85 struct wsdisplay_accessops simplefb_accessops = {
86 	.ioctl = simplefb_wsioctl,
87 	.mmap = simplefb_wsmmap,
88 	.alloc_screen = simplefb_alloc_screen,
89 	.free_screen = rasops_free_screen,
90 	.show_screen = rasops_show_screen,
91 	.getchar = rasops_getchar,
92 	.load_font = rasops_load_font,
93 	.list_font = rasops_list_font,
94 };
95 
96 int
97 simplefb_match(struct device *parent, void *match, void *aux)
98 {
99 	struct fdt_attach_args *faa = aux;
100 
101 	return OF_is_compatible(faa->fa_node, "simple-framebuffer");
102 }
103 
104 void
105 simplefb_attach(struct device *parent, struct device *self, void *aux)
106 {
107 	struct simplefb_softc *sc = (struct simplefb_softc *)self;
108 	struct fdt_attach_args *faa = aux;
109 	struct rasops_info *ri = &sc->sc_ri;
110 	struct wsemuldisplaydev_attach_args waa;
111 	char format[16];
112 	int i;
113 
114 	if (faa->fa_nreg < 1)
115 		return;
116 
117 	format[0] = 0;
118 	OF_getprop(faa->fa_node, "format", format, sizeof(format));
119 	format[sizeof(format) - 1] = 0;
120 
121 	for (i = 0; i < nitems(simplefb_formats); i++) {
122 		if (strcmp(format, simplefb_formats[i].format) == 0) {
123 			sc->sc_format = &simplefb_formats[i];
124 			break;
125 		}
126 	}
127 	if (sc->sc_format == NULL) {
128 		printf(": unsupported format \"%s\"\n", format);
129 		return;
130 	}
131 
132 	sc->sc_iot = faa->fa_iot;
133 	sc->sc_paddr = faa->fa_reg[0].addr;
134 	sc->sc_psize = faa->fa_reg[0].size;
135 	if (bus_space_map(sc->sc_iot, sc->sc_paddr, sc->sc_psize,
136 	    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_ioh))
137 		panic("%s: bus_space_map failed!", __func__);
138 
139 	ri->ri_width = OF_getpropint(faa->fa_node, "width", 0);
140 	ri->ri_height = OF_getpropint(faa->fa_node, "height", 0);
141 	ri->ri_stride = OF_getpropint(faa->fa_node, "stride", 0);
142 	ri->ri_depth = sc->sc_format->depth;
143 	ri->ri_rpos = sc->sc_format->rpos;
144 	ri->ri_rnum = sc->sc_format->rnum;
145 	ri->ri_gpos = sc->sc_format->gpos;
146 	ri->ri_gnum = sc->sc_format->gnum;
147 	ri->ri_bpos = sc->sc_format->bpos;
148 	ri->ri_bnum = sc->sc_format->bnum;
149 	ri->ri_flg = RI_CENTER | RI_CLEAR | RI_FULLCLEAR;
150 	ri->ri_flg |= RI_VCONS | RI_WRONLY;
151 	ri->ri_bits = bus_space_vaddr(sc->sc_iot, sc->sc_ioh);
152 	ri->ri_hw = sc;
153 
154 	printf(": %dx%d\n", ri->ri_width, ri->ri_height);
155 
156 	rasops_init(ri, 160, 160);
157 
158 	strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name));
159 	sc->sc_wsd.capabilities = ri->ri_caps;
160 	sc->sc_wsd.nrows = ri->ri_rows;
161 	sc->sc_wsd.ncols = ri->ri_cols;
162 	sc->sc_wsd.textops = &ri->ri_ops;
163 	sc->sc_wsd.fontwidth = ri->ri_font->fontwidth;
164 	sc->sc_wsd.fontheight = ri->ri_font->fontheight;
165 
166 	sc->sc_scrlist[0] = &sc->sc_wsd;
167 	sc->sc_wsl.nscreens = 1;
168 	sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
169 
170 	memset(&waa, 0, sizeof(waa));
171 	waa.scrdata = &sc->sc_wsl;
172 	waa.accessops = &simplefb_accessops;
173 	waa.accesscookie = ri;
174 
175 	config_found_sm(self, &waa, wsemuldisplaydevprint,
176 	    wsemuldisplaydevsubmatch);
177 }
178 
179 int
180 simplefb_wsioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
181 {
182 	struct rasops_info *ri = v;
183 	struct wsdisplay_fbinfo	*wdf;
184 
185 	switch (cmd) {
186 	case WSDISPLAYIO_GTYPE:
187 		*(int *)data = WSDISPLAY_TYPE_EFIFB;
188 		return 0;
189 	case WSDISPLAYIO_GINFO:
190 		wdf = (struct wsdisplay_fbinfo *)data;
191 		wdf->width = ri->ri_width;
192 		wdf->height = ri->ri_height;
193 		wdf->depth = ri->ri_depth;
194 		wdf->cmsize = 0;	/* color map is unavailable */
195 		break;
196 	case WSDISPLAYIO_LINEBYTES:
197 		*(u_int *)data = ri->ri_stride;
198 		break;
199 	case WSDISPLAYIO_SMODE:
200 		break;
201 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
202 		switch (ri->ri_depth) {
203 		case 32:
204 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
205 			break;
206 		case 24:
207 			*(u_int *)data = WSDISPLAYIO_DEPTH_24_24;
208 			break;
209 		case 16:
210 			*(u_int *)data = WSDISPLAYIO_DEPTH_16;
211 			break;
212 		case 15:
213 			*(u_int *)data = WSDISPLAYIO_DEPTH_15;
214 			break;
215 		default:
216 			return -1;
217 		}
218 		break;
219 	default:
220 		return -1;
221 	}
222 
223 	return 0;
224 }
225 
226 paddr_t
227 simplefb_wsmmap(void *v, off_t off, int prot)
228 {
229 	struct rasops_info *ri = v;
230 	struct simplefb_softc *sc = ri->ri_hw;
231 
232 	if (off < 0 || off >= sc->sc_psize)
233 		return -1;
234 
235 	return sc->sc_paddr + off;
236 }
237 
238 int
239 simplefb_alloc_screen(void *v, const struct wsscreen_descr *type,
240     void **cookiep, int *curxp, int *curyp, long *attrp)
241 {
242 	return rasops_alloc_screen(v, cookiep, curxp, curyp, attrp);
243 }
244