1/*	$NetBSD: ct65550.c,v 1.15 2021/08/07 16:19:12 thorpej Exp $	*/
2
3/*
4 * Copyright (c) 2006 Michael Lorenz
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * A console driver for Chips & Technologies 65550 graphics controllers
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: ct65550.c,v 1.15 2021/08/07 16:19:12 thorpej Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/device.h>
39#include <sys/kauth.h>
40#include <sys/bus.h>
41#include <dev/videomode/videomode.h>
42
43#include <dev/ic/ct65550reg.h>
44#include <dev/ic/ct65550var.h>
45
46#include "opt_wsemul.h"
47#include "opt_chipsfb.h"
48
49static struct vcons_screen chipsfb_console_screen;
50
51extern const u_char rasops_cmap[768];
52
53static void 	chipsfb_init(struct chipsfb_softc *);
54
55static void	chipsfb_cursor(void *, int, int, int);
56static void	chipsfb_copycols(void *, int, int, int, int);
57static void	chipsfb_erasecols(void *, int, int, int, long);
58static void	chipsfb_copyrows(void *, int, int, int);
59static void	chipsfb_eraserows(void *, int, int, long);
60
61#if 0
62static int	chipsfb_allocattr(void *, int, int, int, long *);
63static void	chipsfb_scroll(void *, void *, int);
64static int	chipsfb_load_font(void *, void *, struct wsdisplay_font *);
65#endif
66
67static int	chipsfb_putcmap(struct chipsfb_softc *,
68			    struct wsdisplay_cmap *);
69static int 	chipsfb_getcmap(struct chipsfb_softc *,
70			    struct wsdisplay_cmap *);
71static int 	chipsfb_putpalreg(struct chipsfb_softc *, uint8_t, uint8_t,
72			    uint8_t, uint8_t);
73
74static void	chipsfb_bitblt(void *, int, int, int, int,
75			    int, int, int);
76static void	chipsfb_rectfill(struct chipsfb_softc *, int, int, int, int,
77			    int);
78static void	chipsfb_putchar(void *, int, int, u_int, long);
79static void	chipsfb_putchar_aa(void *, int, int, u_int, long);
80static void	chipsfb_setup_mono(struct chipsfb_softc *, int, int, int,
81			    int, uint32_t, uint32_t);
82static void	chipsfb_feed(struct chipsfb_softc *, int, uint8_t *);
83
84#if 0
85static void	chipsfb_showpal(struct chipsfb_softc *);
86#endif
87static void	chipsfb_restore_palette(struct chipsfb_softc *);
88
89static void	chipsfb_wait_idle(struct chipsfb_softc *);
90
91struct wsscreen_descr chipsfb_defaultscreen = {
92	"default",	/* name */
93	0, 0,		/* ncols, nrows */
94	NULL,		/* textops */
95	8, 16,		/* fontwidth, fontheight */
96	WSSCREEN_WSCOLORS | WSSCREEN_HILIT, /* capabilities */
97	NULL,		/* modecookie */
98};
99
100const struct wsscreen_descr *_chipsfb_scrlist[] = {
101	&chipsfb_defaultscreen,
102	/* XXX other formats, graphics screen? */
103};
104
105struct wsscreen_list chipsfb_screenlist = {
106	sizeof(_chipsfb_scrlist) / sizeof(struct wsscreen_descr *), _chipsfb_scrlist
107};
108
109static int	chipsfb_ioctl(void *, void *, u_long, void *, int,
110		    struct lwp *);
111static paddr_t	chipsfb_mmap(void *, void *, off_t, int);
112static void	chipsfb_clearscreen(struct chipsfb_softc *);
113static void	chipsfb_init_screen(void *, struct vcons_screen *, int,
114			    long *);
115
116
117struct wsdisplay_accessops chipsfb_accessops = {
118	chipsfb_ioctl,
119	chipsfb_mmap,
120	NULL,	/* vcons_alloc_screen */
121	NULL,	/* vcons_free_screen */
122	NULL,	/* vcons_show_screen */
123	NULL,	/* load_font */
124	NULL,	/* polls */
125	NULL,	/* scroll */
126};
127
128/*
129 * Inline functions for getting access to register aperture.
130 */
131static inline void
132chipsfb_write32(struct chipsfb_softc *sc, uint32_t reg, uint32_t val)
133{
134	bus_space_write_4(sc->sc_memt, sc->sc_mmregh, reg, val);
135}
136
137static inline uint32_t
138chipsfb_read32(struct chipsfb_softc *sc, uint32_t reg)
139{
140	return bus_space_read_4(sc->sc_memt, sc->sc_mmregh, reg);
141}
142
143static inline void
144chipsfb_write_vga(struct chipsfb_softc *sc, uint32_t reg,  uint8_t val)
145{
146	bus_space_write_1(sc->sc_iot, sc->sc_ioregh, reg, val);
147}
148
149static inline uint8_t
150chipsfb_read_vga(struct chipsfb_softc *sc, uint32_t reg)
151{
152	return bus_space_read_1(sc->sc_iot, sc->sc_ioregh, reg);
153}
154
155static inline uint8_t
156chipsfb_read_indexed(struct chipsfb_softc *sc, uint32_t reg, uint8_t index)
157{
158
159	chipsfb_write_vga(sc, reg & 0xfffe, index);
160	return chipsfb_read_vga(sc, reg | 0x0001);
161}
162
163static inline void
164chipsfb_write_indexed(struct chipsfb_softc *sc, uint32_t reg, uint8_t index,
165    uint8_t val)
166{
167
168	chipsfb_write_vga(sc, reg & 0xfffe, index);
169	chipsfb_write_vga(sc, reg | 0x0001, val);
170}
171
172static void
173chipsfb_wait_idle(struct chipsfb_softc *sc)
174{
175
176#ifdef CHIPSFB_DEBUG
177	chipsfb_write32(sc, CT_OFF_FB + (800 * 598) - 4, 0);
178#endif
179
180	/* spin until the blitter is idle */
181	while ((chipsfb_read32(sc, CT_BLT_CONTROL) & BLT_IS_BUSY) != 0) {
182	}
183
184#ifdef CHIPSFB_DEBUG
185	chipsfb_write32(sc, CT_OFF_FB + (800 * 598) - 4, 0xffffffff);
186#endif
187}
188
189void
190chipsfb_do_attach(struct chipsfb_softc *sc)
191{
192	struct wsemuldisplaydev_attach_args aa;
193	struct rasops_info *ri;
194	prop_dictionary_t dict;
195	ulong defattr;
196	bool console = false;
197	int width, height, i, j;
198	uint32_t bg, fg, ul;
199	uint8_t cmap[768];
200
201	dict = device_properties(sc->sc_dev);
202	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
203	sc->sc_dacw = -1;
204
205#ifdef CHIPSFB_DEBUG
206	printf(prop_dictionary_externalize(dict));
207#endif
208	chipsfb_init(sc);
209
210	width = height = -1;
211
212	/* detect panel size */
213	width = chipsfb_read_indexed(sc, CT_FP_INDEX, FP_HSIZE_LSB);
214	width |= (chipsfb_read_indexed(sc, CT_FP_INDEX, FP_HORZ_OVERFLOW_1)
215	    & 0x0f) << 8;
216	width = (width + 1) * 8;
217	height = chipsfb_read_indexed(sc, CT_FP_INDEX, FP_VSIZE_LSB);
218	height |= (chipsfb_read_indexed(sc, CT_FP_INDEX, FP_VERT_OVERFLOW_1)
219	    & 0x0f) << 8;
220	height++;
221	if ((width < 640) || ( width > 1280) || (height < 480) ||
222	    (height > 1024)) {
223		/* no sane values in the panel registers */
224		width = height = -1;
225	} else
226		aprint_verbose("Panel size: %d x %d\n", width, height);
227
228	if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width))
229		sc->sc_width = width;
230	if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height))
231		sc->sc_height = height;
232	if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_bits_per_pixel))
233		sc->sc_bits_per_pixel = 8;
234	if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_linebytes))
235		sc->sc_linebytes = (sc->sc_width * sc->sc_bits_per_pixel) >> 3;
236
237	prop_dictionary_get_bool(dict, "is_console", &console);
238
239#ifdef notyet
240	/* XXX this should at least be configurable via kernel config */
241	chipsfb_set_videomode(sc, &videomode_list[16]);
242#endif
243
244	vcons_init(&sc->vd, sc, &chipsfb_defaultscreen, &chipsfb_accessops);
245	sc->vd.init_screen = chipsfb_init_screen;
246
247	sc->sc_gc.gc_bitblt = chipsfb_bitblt;
248	sc->sc_gc.gc_blitcookie = sc;
249	sc->sc_gc.gc_rop = ROP_COPY;
250
251	ri = &chipsfb_console_screen.scr_ri;
252	if (console) {
253		vcons_init_screen(&sc->vd, &chipsfb_console_screen, 1,
254		    &defattr);
255		chipsfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
256
257		chipsfb_defaultscreen.textops = &ri->ri_ops;
258		chipsfb_defaultscreen.capabilities = ri->ri_caps;
259		chipsfb_defaultscreen.nrows = ri->ri_rows;
260		chipsfb_defaultscreen.ncols = ri->ri_cols;
261		glyphcache_init(&sc->sc_gc, sc->sc_height + 1,
262				(sc->sc_fbsize / sc->sc_linebytes) - sc->sc_height - 1,
263				sc->sc_width,
264				ri->ri_font->fontwidth,
265				ri->ri_font->fontheight,
266				defattr);
267		wsdisplay_cnattach(&chipsfb_defaultscreen, ri, 0, 0, defattr);
268	} else {
269		if (chipsfb_console_screen.scr_ri.ri_rows == 0) {
270			/* do some minimal setup to avoid weirdnesses later */
271			vcons_init_screen(&sc->vd, &chipsfb_console_screen, 1,
272			    &defattr);
273		} else
274			(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
275
276		glyphcache_init(&sc->sc_gc, sc->sc_height + 1,
277				(sc->sc_fbsize / sc->sc_linebytes) - sc->sc_height - 1,
278				sc->sc_width,
279				ri->ri_font->fontwidth,
280				ri->ri_font->fontheight,
281				defattr);
282	}
283
284	rasops_unpack_attr(defattr, &fg, &bg, &ul);
285	sc->sc_bg = ri->ri_devcmap[bg];
286	chipsfb_clearscreen(sc);
287
288	if (console)
289		vcons_replay_msgbuf(&chipsfb_console_screen);
290
291	aprint_normal_dev(sc->sc_dev, "%d MB aperture, %d MB VRAM at 0x%08x\n",
292	    (u_int)(sc->sc_fbsize >> 20),
293	    (int)sc->memsize >> 20, (u_int)sc->sc_fb);
294#ifdef CHIPSFB_DEBUG
295	aprint_debug("fb: %08lx\n", (ulong)ri->ri_bits);
296#endif
297
298	j = 0;
299	rasops_get_cmap(ri, cmap, sizeof(cmap));
300	for (i = 0; i < 256; i++) {
301		chipsfb_putpalreg(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
302		j += 3;
303	}
304
305	aa.console = console;
306	aa.scrdata = &chipsfb_screenlist;
307	aa.accessops = &chipsfb_accessops;
308	aa.accesscookie = &sc->vd;
309
310	config_found(sc->sc_dev, &aa, wsemuldisplaydevprint, CFARGS_NONE);
311}
312
313static int
314chipsfb_putpalreg(struct chipsfb_softc *sc, uint8_t index, uint8_t r,
315    uint8_t g, uint8_t b)
316{
317
318	sc->sc_cmap_red[index] = r;
319	sc->sc_cmap_green[index] = g;
320	sc->sc_cmap_blue[index] = b;
321
322	chipsfb_write_vga(sc, CT_DACMASK, 0xff);
323	chipsfb_write_vga(sc, CT_WRITEINDEX, index);
324	chipsfb_write_vga(sc, CT_DACDATA, r);
325	chipsfb_write_vga(sc, CT_DACDATA, g);
326	chipsfb_write_vga(sc, CT_DACDATA, b);
327
328	return 0;
329}
330
331static int
332chipsfb_putcmap(struct chipsfb_softc *sc, struct wsdisplay_cmap *cm)
333{
334	u_char *r, *g, *b;
335	u_int index = cm->index;
336	u_int count = cm->count;
337	int i, error;
338	u_char rbuf[256], gbuf[256], bbuf[256];
339
340#ifdef CHIPSFB_DEBUG
341	aprint_debug("putcmap: %d %d\n",index, count);
342#endif
343	if (cm->index >= 256 || cm->count > 256 ||
344	    (cm->index + cm->count) > 256)
345		return EINVAL;
346	error = copyin(cm->red, &rbuf[index], count);
347	if (error)
348		return error;
349	error = copyin(cm->green, &gbuf[index], count);
350	if (error)
351		return error;
352	error = copyin(cm->blue, &bbuf[index], count);
353	if (error)
354		return error;
355
356	memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
357	memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
358	memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
359
360	r = &sc->sc_cmap_red[index];
361	g = &sc->sc_cmap_green[index];
362	b = &sc->sc_cmap_blue[index];
363
364	for (i = 0; i < count; i++) {
365		chipsfb_putpalreg(sc, index, *r, *g, *b);
366		index++;
367		r++, g++, b++;
368	}
369	return 0;
370}
371
372static int
373chipsfb_getcmap(struct chipsfb_softc *sc, struct wsdisplay_cmap *cm)
374{
375	u_int index = cm->index;
376	u_int count = cm->count;
377	int error;
378
379	if (index >= 255 || count > 256 || index + count > 256)
380		return EINVAL;
381
382	error = copyout(&sc->sc_cmap_red[index],   cm->red,   count);
383	if (error)
384		return error;
385	error = copyout(&sc->sc_cmap_green[index], cm->green, count);
386	if (error)
387		return error;
388	error = copyout(&sc->sc_cmap_blue[index],  cm->blue,  count);
389	if (error)
390		return error;
391
392	return 0;
393}
394
395static void
396chipsfb_clearscreen(struct chipsfb_softc *sc)
397{
398	chipsfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, sc->sc_bg);
399}
400
401/*
402 * wsdisplay_emulops
403 */
404
405static void
406chipsfb_cursor(void *cookie, int on, int row, int col)
407{
408	struct rasops_info *ri = cookie;
409	struct vcons_screen *scr = ri->ri_hw;
410	struct chipsfb_softc *sc = scr->scr_cookie;
411	int x, y, wi, he;
412
413	wi = ri->ri_font->fontwidth;
414	he = ri->ri_font->fontheight;
415
416	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
417		x = ri->ri_ccol * wi + ri->ri_xorigin;
418		y = ri->ri_crow * he + ri->ri_yorigin;
419		if (ri->ri_flg & RI_CURSOR) {
420			chipsfb_bitblt(sc, x, y, x, y, wi, he, ROP_NOT_DST);
421			ri->ri_flg &= ~RI_CURSOR;
422		}
423		ri->ri_crow = row;
424		ri->ri_ccol = col;
425		if (on) {
426			x = ri->ri_ccol * wi + ri->ri_xorigin;
427			y = ri->ri_crow * he + ri->ri_yorigin;
428			chipsfb_bitblt(sc, x, y, x, y, wi, he, ROP_NOT_DST);
429			ri->ri_flg |= RI_CURSOR;
430		}
431	} else {
432		ri->ri_flg &= ~RI_CURSOR;
433		ri->ri_crow = row;
434		ri->ri_ccol = col;
435	}
436}
437
438#if 0
439int
440chipsfb_mapchar(void *cookie, int uni, u_int *index)
441{
442	return 0;
443}
444#endif
445
446static void
447chipsfb_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
448{
449	struct rasops_info *ri = cookie;
450	struct vcons_screen *scr = ri->ri_hw;
451	struct chipsfb_softc *sc = scr->scr_cookie;
452	int32_t xs, xd, y, width, height;
453
454	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
455		xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
456		xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
457		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
458		width = ri->ri_font->fontwidth * ncols;
459		height = ri->ri_font->fontheight;
460		chipsfb_bitblt(sc, xs, y, xd, y, width, height, ROP_COPY);
461	}
462}
463
464static void
465chipsfb_erasecols(void *cookie, int row, int startcol, int ncols,
466    long fillattr)
467{
468	struct rasops_info *ri = cookie;
469	struct vcons_screen *scr = ri->ri_hw;
470	struct chipsfb_softc *sc = scr->scr_cookie;
471	int32_t x, y, width, height, fg, bg, ul;
472
473	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
474		x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
475		y = ri->ri_yorigin + ri->ri_font->fontheight * row;
476		width = ri->ri_font->fontwidth * ncols;
477		height = ri->ri_font->fontheight;
478		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
479
480		chipsfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]);
481	}
482}
483
484static void
485chipsfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
486{
487	struct rasops_info *ri = cookie;
488	struct vcons_screen *scr = ri->ri_hw;
489	struct chipsfb_softc *sc = scr->scr_cookie;
490	int32_t x, ys, yd, width, height;
491
492	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
493		x = ri->ri_xorigin;
494		ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
495		yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
496		width = ri->ri_emuwidth;
497		height = ri->ri_font->fontheight * nrows;
498		chipsfb_bitblt(sc, x, ys, x, yd, width, height, ROP_COPY);
499	}
500}
501
502static void
503chipsfb_eraserows(void *cookie, int row, int nrows, long fillattr)
504{
505	struct rasops_info *ri = cookie;
506	struct vcons_screen *scr = ri->ri_hw;
507	struct chipsfb_softc *sc = scr->scr_cookie;
508	int32_t x, y, width, height, fg, bg, ul;
509
510	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
511		rasops_unpack_attr(fillattr, &fg, &bg, &ul);
512		if ((row == 0) && (nrows == ri->ri_rows)) {
513			/* clear the whole screen */
514			chipsfb_rectfill(sc, 0, 0, ri->ri_width,
515			    ri->ri_height, ri->ri_devcmap[bg]);
516		} else {
517			x = ri->ri_xorigin;
518			y = ri->ri_yorigin + ri->ri_font->fontheight * row;
519			width = ri->ri_emuwidth;
520			height = ri->ri_font->fontheight * nrows;
521			chipsfb_rectfill(sc, x, y, width, height,
522			    ri->ri_devcmap[bg]);
523		}
524	}
525}
526
527static void
528chipsfb_bitblt(void *cookie, int xs, int ys, int xd, int yd,
529    int width, int height, int rop)
530{
531	struct chipsfb_softc *sc = cookie;
532	uint32_t src, dst, cmd = rop, stride, size;
533
534	cmd |= BLT_PAT_IS_SOLID;
535
536	/* we assume 8 bit for now */
537	src = xs + ys * sc->sc_linebytes;
538	dst = xd + yd * sc->sc_linebytes;
539
540	if (xs < xd) {
541		/* right-to-left operation */
542		cmd |= BLT_START_RIGHT;
543		src += width - 1;
544		dst += width - 1;
545	}
546
547	if (ys < yd) {
548		/* bottom-to-top operation */
549		cmd |= BLT_START_BOTTOM;
550		src += (height - 1) * sc->sc_linebytes;
551		dst += (height - 1) * sc->sc_linebytes;
552	}
553
554	stride = (sc->sc_linebytes << 16) | sc->sc_linebytes;
555	size = (height << 16) | width;
556
557	chipsfb_wait_idle(sc);
558	chipsfb_write32(sc, CT_BLT_STRIDE, stride);
559	chipsfb_write32(sc, CT_BLT_SRCADDR, src);
560	chipsfb_write32(sc, CT_BLT_DSTADDR, dst);
561	chipsfb_write32(sc, CT_BLT_CONTROL, cmd);
562	chipsfb_write32(sc, CT_BLT_SIZE, size);
563#ifdef CHIPSFB_WAIT
564	chipsfb_wait_idle(sc);
565#endif
566}
567
568static void
569chipsfb_rectfill(struct chipsfb_softc *sc, int x, int y, int width,
570    int height, int colour)
571{
572	uint32_t dst, cmd, stride, size;
573
574	cmd = BLT_PAT_IS_SOLID | BLT_PAT_IS_MONO | ROP_PAT;
575
576	/* we assume 8 bit for now */
577	dst = x + y * sc->sc_linebytes;
578
579	stride = (sc->sc_linebytes << 16) | sc->sc_linebytes;
580	size = (height << 16) | width;
581
582	chipsfb_wait_idle(sc);
583	chipsfb_write32(sc, CT_BLT_STRIDE, stride);
584	chipsfb_write32(sc, CT_BLT_SRCADDR, dst);
585	chipsfb_write32(sc, CT_BLT_DSTADDR, dst);
586	chipsfb_write32(sc, CT_BLT_CONTROL, cmd);
587	chipsfb_write32(sc, CT_BLT_BG, colour);
588	chipsfb_write32(sc, CT_BLT_FG, colour);
589	chipsfb_write32(sc, CT_BLT_SIZE, size);
590#ifdef CHIPSFB_WAIT
591	chipsfb_wait_idle(sc);
592#endif
593}
594
595static void
596chipsfb_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
597{
598	struct rasops_info *ri = cookie;
599	struct wsdisplay_font *font = PICK_FONT(ri, c);
600	struct vcons_screen *scr = ri->ri_hw;
601	struct chipsfb_softc *sc = scr->scr_cookie;
602	uint32_t bg, latch = 0, bg8, fg8, pixel, dst, stride, size;
603	int i, l, x, y, wi, he, r, g, b, aval;
604	int r1, g1, b1, r0, g0, b0, fgo, bgo, off, pad;
605	uint8_t *data8;
606	int rv;
607
608	if (__predict_false((unsigned int)row > ri->ri_rows ||
609	    (unsigned int)col > ri->ri_cols))
610		return;
611
612	if (__predict_false((sc->sc_mode != WSDISPLAYIO_MODE_EMUL)))
613		return;
614
615	if (__predict_false((!CHAR_IN_FONT(c, font))))
616		return;
617
618	wi = font->fontwidth;
619	he = font->fontheight;
620
621	bg = ri->ri_devcmap[(attr >> 16) & 0xf];
622	x = ri->ri_xorigin + col * wi;
623	y = ri->ri_yorigin + row * he;
624
625	if (c == 0x20) {
626		chipsfb_rectfill(sc, x, y, wi, he, bg);
627		return;
628	}
629
630	rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
631	if (rv == GC_OK)
632		return;
633
634	data8 = WSFONT_GLYPH(c, font);
635
636	/* we assume 8 bit for now */
637	dst = x + y * sc->sc_linebytes;
638
639	stride = sc->sc_linebytes << 16;
640	size = (he << 16) | wi;
641
642	/* set up for host blit */
643	chipsfb_wait_idle(sc);
644	chipsfb_write32(sc, CT_BLT_STRIDE, stride);
645	chipsfb_write32(sc, CT_BLT_DSTADDR, dst);
646	chipsfb_write32(sc, CT_BLT_SRCADDR, 0);
647	chipsfb_write32(sc, CT_BLT_CONTROL,
648	    BLT_PAT_IS_SOLID | BLT_SRC_IS_CPU | ROP_COPY);
649	chipsfb_write32(sc, CT_BLT_SIZE, size);
650
651	/*
652	 * we need the RGB colours here, so get offsets into rasops_cmap
653	 */
654	fgo = ((attr >> 24) & 0xf) * 3;
655	bgo = ((attr >> 16) & 0xf) * 3;
656
657	r0 = rasops_cmap[bgo];
658	r1 = rasops_cmap[fgo];
659	g0 = rasops_cmap[bgo + 1];
660	g1 = rasops_cmap[fgo + 1];
661	b0 = rasops_cmap[bgo + 2];
662	b1 = rasops_cmap[fgo + 2];
663#define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6))
664	bg8 = R3G3B2(r0, g0, b0);
665	fg8 = R3G3B2(r1, g1, b1);
666
667	/* see if we need to pad lines to 64bit */
668	pad = (wi + 3) & 4;
669	for (l = 0; l < he; l++) {
670		off = 0;
671		latch = 0;
672		for (i = 0; i < wi; i++) {
673			aval = *data8;
674			if (aval == 0) {
675				pixel = bg8;
676			} else if (aval == 255) {
677				pixel = fg8;
678			} else {
679				r = aval * r1 + (255 - aval) * r0;
680				g = aval * g1 + (255 - aval) * g0;
681				b = aval * b1 + (255 - aval) * b0;
682				pixel = ((r & 0xe000) >> 8) |
683					((g & 0xe000) >> 11) |
684					((b & 0xc000) >> 14);
685			}
686			latch |= pixel << off;
687			off += 8;
688			/* write in 32bit chunks */
689			if ((i & 3) == 3) {
690				chipsfb_write32(sc,
691				    CT_OFF_DATA - CT_OFF_BITBLT, latch);
692				latch = 0;
693				off = 0;
694			}
695			data8++;
696		}
697		/* if we have pixels left in latch write them out */
698		if ((i & 3) != 0) {
699			chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, latch);
700		}
701		/* this chip needs scanlines 64bit aligned */
702		if (pad) chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, 0);
703	}
704
705	if (rv == GC_ADD) {
706		glyphcache_add(&sc->sc_gc, c, x, y);
707	}
708}
709
710static void
711chipsfb_putchar(void *cookie, int row, int col, u_int c, long attr)
712{
713	struct rasops_info *ri = cookie;
714	struct wsdisplay_font *font = PICK_FONT(ri, c);
715	struct vcons_screen *scr = ri->ri_hw;
716	struct chipsfb_softc *sc = scr->scr_cookie;
717
718	if (__predict_false((unsigned int)row > ri->ri_rows ||
719	    (unsigned int)col > ri->ri_cols))
720		return;
721
722	if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) {
723		uint8_t *data;
724		int fg, bg, uc;
725		int x, y, wi, he;
726
727		wi = font->fontwidth;
728		he = font->fontheight;
729
730		if (!CHAR_IN_FONT(c, font))
731			return;
732		bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xf];
733		fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xf];
734		x = ri->ri_xorigin + col * wi;
735		y = ri->ri_yorigin + row * he;
736		if (c == 0x20) {
737			chipsfb_rectfill(sc, x, y, wi, he, bg);
738		} else {
739			uc = c - font->firstchar;
740			data = (uint8_t *)font->data + uc *
741			    ri->ri_fontscale;
742			chipsfb_setup_mono(sc, x, y, wi, he, fg, bg);
743			chipsfb_feed(sc, font->stride * he, data);
744		}
745	}
746}
747
748static void
749chipsfb_setup_mono(struct chipsfb_softc *sc, int xd, int yd, int width,
750    int height, uint32_t fg, uint32_t bg)
751{
752	uint32_t dst, cmd, stride, size;
753
754	cmd = BLT_PAT_IS_SOLID | BLT_SRC_IS_CPU | BLT_SRC_IS_MONO | ROP_COPY;
755
756	/* we assume 8 bit for now */
757	dst = xd + yd * sc->sc_linebytes;
758
759	stride = (sc->sc_linebytes << 16);
760	size = (height << 16) | width;
761
762	chipsfb_wait_idle(sc);
763	chipsfb_write32(sc, CT_BLT_STRIDE, stride);
764	chipsfb_write32(sc, CT_BLT_DSTADDR, dst);
765	chipsfb_write32(sc, CT_BLT_SRCADDR, 0);
766	chipsfb_write32(sc, CT_BLT_CONTROL, cmd);
767	chipsfb_write32(sc, CT_BLT_BG, bg);
768	chipsfb_write32(sc, CT_BLT_FG, fg);
769	chipsfb_write32(sc, CT_BLT_SIZE, size);
770}
771
772static void
773chipsfb_feed(struct chipsfb_softc *sc, int count, uint8_t *data)
774{
775	int i;
776	uint32_t latch = 0, bork;
777	int shift = 0;
778
779	for (i = 0; i < count; i++) {
780		bork = data[i];
781		latch |= (bork << shift);
782		if (shift == 24) {
783			chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, latch);
784			latch = 0;
785			shift = 0;
786		} else
787			shift += 8;
788	}
789
790	if (shift != 0) {
791		chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, latch);
792	}
793
794	/* apparently the chip wants 64bit-aligned data or it won't go idle */
795	if ((count + 3) & 0x04) {
796		chipsfb_write32(sc, CT_OFF_DATA - CT_OFF_BITBLT, 0);
797	}
798#ifdef CHIPSFB_WAIT
799	chipsfb_wait_idle(sc);
800#endif
801}
802
803#if 0
804static void
805chipsfb_showpal(struct chipsfb_softc *sc)
806{
807	int i, x = 0;
808
809	for (i = 0; i < 16; i++) {
810		chipsfb_rectfill(sc, x, 0, 64, 64, i);
811		x += 64;
812	}
813}
814#endif
815
816#if 0
817static int
818chipsfb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
819{
820
821	return 0;
822}
823#endif
824
825static void
826chipsfb_restore_palette(struct chipsfb_softc *sc)
827{
828	int i;
829
830	for (i = 0; i < 256; i++) {
831		chipsfb_putpalreg(sc,
832		   i,
833		   sc->sc_cmap_red[i],
834		   sc->sc_cmap_green[i],
835		   sc->sc_cmap_blue[i]);
836	}
837}
838
839/*
840 * wsdisplay_accessops
841 */
842
843static int
844chipsfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
845	struct lwp *l)
846{
847	struct vcons_data *vd = v;
848	struct chipsfb_softc *sc = vd->cookie;
849	struct wsdisplay_fbinfo *wdf;
850	struct vcons_screen *ms = vd->active;
851
852	switch (cmd) {
853	case WSDISPLAYIO_GTYPE:
854		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
855		return 0;
856
857	case WSDISPLAYIO_GINFO:
858		wdf = (void *)data;
859		wdf->height = ms->scr_ri.ri_height;
860		wdf->width = ms->scr_ri.ri_width;
861		wdf->depth = ms->scr_ri.ri_depth;
862		wdf->cmsize = 256;
863		return 0;
864
865	case WSDISPLAYIO_GETCMAP:
866		return chipsfb_getcmap(sc,
867		    (struct wsdisplay_cmap *)data);
868
869	case WSDISPLAYIO_PUTCMAP:
870		return chipsfb_putcmap(sc,
871		    (struct wsdisplay_cmap *)data);
872
873
874	case WSDISPLAYIO_SMODE: {
875		int new_mode = *(int*)data;
876		if (new_mode != sc->sc_mode) {
877			sc->sc_mode = new_mode;
878			if(new_mode == WSDISPLAYIO_MODE_EMUL) {
879				chipsfb_init(sc);
880				chipsfb_restore_palette(sc);
881				glyphcache_wipe(&sc->sc_gc);
882				vcons_redraw_screen(ms);
883			}
884		}
885		}
886		return 0;
887
888	case WSDISPLAYIO_GET_FBINFO: {
889		struct wsdisplayio_fbinfo *fbi = data;
890		return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
891	}
892
893	default:
894		if (sc->sc_ioctl != NULL)
895			return sc->sc_ioctl(v, vs, cmd, data, flag, l);
896	}
897	return EPASSTHROUGH;
898}
899
900static paddr_t
901chipsfb_mmap(void *v, void *vs, off_t offset, int prot)
902{
903	struct vcons_data *vd = v;
904	struct chipsfb_softc *sc = vd->cookie;
905	paddr_t pa;
906
907	if (sc->sc_mmap != NULL) {
908		pa = sc->sc_mmap(v, vs, offset, prot);
909		if (pa != -1) return pa;
910	}
911
912	/* 'regular' framebuffer mmap()ing */
913	if (offset < sc->memsize) {
914		pa = bus_space_mmap(sc->sc_memt, sc->sc_fb, offset, prot,
915		    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
916		return pa;
917	}
918
919	/*
920	 * restrict all other mappings to processes with superuser privileges
921	 * or the kernel itself
922	 */
923	if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM,
924	    NULL, NULL, NULL, NULL) != 0) {
925		aprint_normal_dev(sc->sc_dev, "mmap() rejected.\n");
926		return -1;
927	}
928
929	if ((offset >= sc->sc_fb) && (offset < (sc->sc_fb + sc->sc_fbsize))) {
930		pa = bus_space_mmap(sc->sc_memt, offset, 0, prot,
931		    BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE);
932		return pa;
933	}
934
935#ifdef PCI_MAGIC_IO_RANGE
936	/* allow mapping of IO space */
937	if ((offset >= PCI_MAGIC_IO_RANGE) &&
938	    (offset < PCI_MAGIC_IO_RANGE + 0x10000)) {
939		pa = bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
940		    0, prot, BUS_SPACE_MAP_LINEAR);
941		return pa;
942	}
943#endif
944
945	return -1;
946}
947
948static void
949chipsfb_init_screen(void *cookie, struct vcons_screen *scr,
950    int existing, long *defattr)
951{
952	struct chipsfb_softc *sc = cookie;
953	struct rasops_info *ri = &scr->scr_ri;
954
955	ri->ri_depth = sc->sc_bits_per_pixel;
956	ri->ri_width = sc->sc_width;
957	ri->ri_height = sc->sc_height;
958	ri->ri_stride = sc->sc_width;
959	ri->ri_flg = RI_CENTER | RI_FULLCLEAR |
960		     RI_8BIT_IS_RGB | RI_ENABLE_ALPHA;
961
962	ri->ri_bits = bus_space_vaddr(sc->sc_memt, sc->sc_fbh);
963
964#ifdef CHIPSFB_DEBUG
965	aprint_debug("addr: %08lx\n", (ulong)ri->ri_bits);
966#endif
967	if (existing) {
968		ri->ri_flg |= RI_CLEAR;
969	}
970
971	rasops_init(ri, 0, 0);
972	ri->ri_caps = WSSCREEN_WSCOLORS;
973
974	rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
975		    sc->sc_width / ri->ri_font->fontwidth);
976
977	ri->ri_hw = scr;
978	ri->ri_ops.copyrows = chipsfb_copyrows;
979	ri->ri_ops.copycols = chipsfb_copycols;
980	ri->ri_ops.eraserows = chipsfb_eraserows;
981	ri->ri_ops.erasecols = chipsfb_erasecols;
982	ri->ri_ops.cursor = chipsfb_cursor;
983	if (FONT_IS_ALPHA(ri->ri_font)) {
984		ri->ri_ops.putchar = chipsfb_putchar_aa;
985	} else
986		ri->ri_ops.putchar = chipsfb_putchar;
987}
988
989#if 0
990int
991chipsfb_load_font(void *v, void *cookie, struct wsdisplay_font *data)
992{
993
994	return 0;
995}
996#endif
997
998static void
999chipsfb_init(struct chipsfb_softc *sc)
1000{
1001	uint8_t reg;
1002
1003	chipsfb_wait_idle(sc);
1004
1005	/* setup the blitter */
1006	chipsfb_write32(sc, CT_BLT_EXPCTL, MONO_SRC_ALIGN_BYTE);
1007
1008	/* put DAC into 8bit mode */
1009	reg = chipsfb_read_indexed(sc, CT_CONF_INDEX, XR_PIXEL_PIPELINE_CTL_0);
1010	reg |= ENABLE_8BIT_DAC;
1011	chipsfb_write_indexed(sc, CT_CONF_INDEX, XR_PIXEL_PIPELINE_CTL_0, reg);
1012}
1013
1014uint32_t
1015chipsfb_probe_vram(struct chipsfb_softc *sc)
1016{
1017	uint32_t ofs = 0x00080000;	/* 512kB */
1018
1019	/*
1020	 * advance in 0.5MB steps, see if we can read back what we wrote and
1021	 * if what we wrote to 0 is left untouched. Max. fb size is 4MB so
1022	 * we voluntarily stop there.
1023	 */
1024	bus_space_write_4(sc->sc_memt, sc->sc_fbh, 0, 0xf0f0f0f0);
1025	bus_space_write_4(sc->sc_memt, sc->sc_fbh, ofs, 0x0f0f0f0f);
1026	while ((bus_space_read_4(sc->sc_memt, sc->sc_fbh, 0) == 0xf0f0f0f0) &&
1027	    (bus_space_read_4(sc->sc_memt, sc->sc_fbh, ofs) == 0x0f0f0f0f) &&
1028	    (ofs < 0x00400000)) {
1029
1030		ofs += 0x00080000;
1031		bus_space_write_4(sc->sc_memt, sc->sc_fbh, ofs, 0x0f0f0f0f);
1032	}
1033
1034	return ofs;
1035}
1036