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