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