1*9404ac38Smacallan /* $NetBSD: mgx.c,v 1.24 2023/07/19 10:22:15 macallan Exp $ */
2c6ec2ef8Smacallan
3c6ec2ef8Smacallan /*-
4c6ec2ef8Smacallan * Copyright (c) 2014 Michael Lorenz
5c6ec2ef8Smacallan * All rights reserved.
6c6ec2ef8Smacallan *
7c6ec2ef8Smacallan * Redistribution and use in source and binary forms, with or without
8c6ec2ef8Smacallan * modification, are permitted provided that the following conditions
9c6ec2ef8Smacallan * are met:
10c6ec2ef8Smacallan * 1. Redistributions of source code must retain the above copyright
11c6ec2ef8Smacallan * notice, this list of conditions and the following disclaimer.
12c6ec2ef8Smacallan * 2. Redistributions in binary form must reproduce the above copyright
13c6ec2ef8Smacallan * notice, this list of conditions and the following disclaimer in the
14c6ec2ef8Smacallan * documentation and/or other materials provided with the distribution.
15c6ec2ef8Smacallan *
16c6ec2ef8Smacallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17c6ec2ef8Smacallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18c6ec2ef8Smacallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19c6ec2ef8Smacallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20c6ec2ef8Smacallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21c6ec2ef8Smacallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22c6ec2ef8Smacallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23c6ec2ef8Smacallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24c6ec2ef8Smacallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25c6ec2ef8Smacallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26c6ec2ef8Smacallan * POSSIBILITY OF SUCH DAMAGE.
27c6ec2ef8Smacallan */
28c6ec2ef8Smacallan
29c6ec2ef8Smacallan /* a console driver for the SSB 4096V-MGX graphics card */
30c6ec2ef8Smacallan
31c6ec2ef8Smacallan #include <sys/cdefs.h>
32*9404ac38Smacallan __KERNEL_RCSID(0, "$NetBSD: mgx.c,v 1.24 2023/07/19 10:22:15 macallan Exp $");
33c6ec2ef8Smacallan
34c6ec2ef8Smacallan #include <sys/param.h>
35c6ec2ef8Smacallan #include <sys/systm.h>
36c6ec2ef8Smacallan #include <sys/buf.h>
37c6ec2ef8Smacallan #include <sys/device.h>
38c6ec2ef8Smacallan #include <sys/ioctl.h>
39c6ec2ef8Smacallan #include <sys/conf.h>
40c6ec2ef8Smacallan #include <sys/kmem.h>
41c1adbebeSmacallan #include <sys/kauth.h>
421ce86285Smacallan #include <sys/atomic.h>
43c6ec2ef8Smacallan
44c6ec2ef8Smacallan #include <sys/bus.h>
45c6ec2ef8Smacallan #include <machine/autoconf.h>
46c6ec2ef8Smacallan
47c6ec2ef8Smacallan #include <dev/sbus/sbusvar.h>
48c6ec2ef8Smacallan #include <dev/sun/fbio.h>
49c6ec2ef8Smacallan #include <dev/sun/fbvar.h>
50c6ec2ef8Smacallan
51c6ec2ef8Smacallan #include <dev/wscons/wsdisplayvar.h>
52c6ec2ef8Smacallan #include <dev/wscons/wsconsio.h>
53c6ec2ef8Smacallan #include <dev/wsfont/wsfont.h>
54c6ec2ef8Smacallan #include <dev/rasops/rasops.h>
55c6ec2ef8Smacallan
56c6ec2ef8Smacallan #include <dev/wscons/wsdisplay_vconsvar.h>
576aedd804Smacallan #include <dev/wscons/wsdisplay_glyphcachevar.h>
58c6ec2ef8Smacallan
59c6ec2ef8Smacallan #include <dev/ic/vgareg.h>
60c6ec2ef8Smacallan #include <dev/sbus/mgxreg.h>
61c6ec2ef8Smacallan
62da86cee2Smacallan #include "ioconf.h"
63da86cee2Smacallan
64c6ec2ef8Smacallan #include "opt_wsemul.h"
65541d4825Smacallan #include "opt_mgx.h"
66c6ec2ef8Smacallan
67c6ec2ef8Smacallan struct mgx_softc {
68c6ec2ef8Smacallan device_t sc_dev;
69da86cee2Smacallan struct fbdevice sc_fb; /* frame buffer device */
70c6ec2ef8Smacallan bus_space_tag_t sc_tag;
71c6ec2ef8Smacallan bus_space_handle_t sc_blith;
72c6ec2ef8Smacallan bus_space_handle_t sc_vgah;
73c1adbebeSmacallan bus_addr_t sc_paddr, sc_rpaddr;
74c6ec2ef8Smacallan void *sc_fbaddr;
7555009e9dSmacallan uint8_t *sc_cursor;
76c6ec2ef8Smacallan int sc_width;
77c6ec2ef8Smacallan int sc_height;
78c6ec2ef8Smacallan int sc_stride;
79541d4825Smacallan int sc_depth;
80c6ec2ef8Smacallan int sc_fbsize;
81c6ec2ef8Smacallan int sc_mode;
82541d4825Smacallan char sc_name[8];
83fd3eba58Smacallan uint32_t sc_dec, sc_r_dec, sc_r_fg;
84c6ec2ef8Smacallan u_char sc_cmap_red[256];
85c6ec2ef8Smacallan u_char sc_cmap_green[256];
86c6ec2ef8Smacallan u_char sc_cmap_blue[256];
8755009e9dSmacallan int sc_cursor_x, sc_cursor_y;
8855009e9dSmacallan int sc_hotspot_x, sc_hotspot_y;
891ce86285Smacallan int sc_video, sc_buf;
906aedd804Smacallan void (*sc_putchar)(void *, int, int, u_int, long);
91c6ec2ef8Smacallan struct vcons_screen sc_console_screen;
92c6ec2ef8Smacallan struct wsscreen_descr sc_defaultscreen_descr;
93c6ec2ef8Smacallan const struct wsscreen_descr *sc_screens[1];
94c6ec2ef8Smacallan struct wsscreen_list sc_screenlist;
95c6ec2ef8Smacallan struct vcons_data vd;
966aedd804Smacallan glyphcache sc_gc;
97ed20f135Smacallan uint8_t sc_in[256];
98c6ec2ef8Smacallan };
99c6ec2ef8Smacallan
100c6ec2ef8Smacallan static int mgx_match(device_t, cfdata_t, void *);
101c6ec2ef8Smacallan static void mgx_attach(device_t, device_t, void *);
102c6ec2ef8Smacallan static int mgx_ioctl(void *, void *, u_long, void *, int,
103c6ec2ef8Smacallan struct lwp*);
104c6ec2ef8Smacallan static paddr_t mgx_mmap(void *, void *, off_t, int);
105c6ec2ef8Smacallan static void mgx_init_screen(void *, struct vcons_screen *, int,
106c6ec2ef8Smacallan long *);
107c6ec2ef8Smacallan static void mgx_write_dac(struct mgx_softc *, int, int, int, int);
108c6ec2ef8Smacallan static void mgx_setup(struct mgx_softc *, int);
109c6ec2ef8Smacallan static void mgx_init_palette(struct mgx_softc *);
1105bc3657eSmacallan static int mgx_putcmap(struct mgx_softc *, struct wsdisplay_cmap *);
1115bc3657eSmacallan static int mgx_getcmap(struct mgx_softc *, struct wsdisplay_cmap *);
1126aedd804Smacallan static int mgx_wait_engine(struct mgx_softc *);
11365721537Sjoerg __unused static int mgx_wait_host(struct mgx_softc *);
114ed20f135Smacallan /*static*/ int mgx_wait_fifo(struct mgx_softc *, unsigned int);
1156aedd804Smacallan
1166aedd804Smacallan static void mgx_bitblt(void *, int, int, int, int, int, int, int);
1176aedd804Smacallan static void mgx_rectfill(void *, int, int, int, int, long);
1186aedd804Smacallan
1191ce86285Smacallan static void mgx_putchar_aa(void *, int, int, u_int, long);
1201ce86285Smacallan static void mgx_putchar_mono(void *, int, int, u_int, long);
1216aedd804Smacallan static void mgx_cursor(void *, int, int, int);
1226aedd804Smacallan static void mgx_copycols(void *, int, int, int, int);
1236aedd804Smacallan static void mgx_erasecols(void *, int, int, int, long);
1246aedd804Smacallan static void mgx_copyrows(void *, int, int, int);
1256aedd804Smacallan static void mgx_eraserows(void *, int, int, long);
126ed20f135Smacallan static void mgx_adapt(struct vcons_screen *, void *);
127c6ec2ef8Smacallan
12855009e9dSmacallan static int mgx_do_cursor(struct mgx_softc *, struct wsdisplay_cursor *);
12955009e9dSmacallan static void mgx_set_cursor(struct mgx_softc *);
13055009e9dSmacallan static void mgx_set_video(struct mgx_softc *, int);
13155009e9dSmacallan
132c6ec2ef8Smacallan CFATTACH_DECL_NEW(mgx, sizeof(struct mgx_softc),
133c6ec2ef8Smacallan mgx_match, mgx_attach, NULL, NULL);
134c6ec2ef8Smacallan
135c6ec2ef8Smacallan struct wsdisplay_accessops mgx_accessops = {
136c6ec2ef8Smacallan mgx_ioctl,
137c6ec2ef8Smacallan mgx_mmap,
138c6ec2ef8Smacallan NULL, /* vcons_alloc_screen */
139c6ec2ef8Smacallan NULL, /* vcons_free_screen */
140c6ec2ef8Smacallan NULL, /* vcons_show_screen */
141c6ec2ef8Smacallan NULL, /* load_font */
142c6ec2ef8Smacallan NULL, /* polls */
143c6ec2ef8Smacallan NULL, /* scroll */
144c6ec2ef8Smacallan };
145c6ec2ef8Smacallan
146da86cee2Smacallan static void mgx_unblank(device_t);
147da86cee2Smacallan
148da86cee2Smacallan dev_type_open(mgxopen);
149da86cee2Smacallan dev_type_close(mgxclose);
150da86cee2Smacallan dev_type_ioctl(mgxioctl);
151da86cee2Smacallan dev_type_mmap(mgxmmap);
152da86cee2Smacallan
153da86cee2Smacallan const struct cdevsw mgx_cdevsw = {
154da86cee2Smacallan .d_open = mgxopen,
155da86cee2Smacallan .d_close = mgxclose,
156da86cee2Smacallan .d_read = noread,
157da86cee2Smacallan .d_write = nowrite,
158da86cee2Smacallan .d_ioctl = mgxioctl,
159da86cee2Smacallan .d_stop = nostop,
160da86cee2Smacallan .d_tty = notty,
161da86cee2Smacallan .d_poll = nopoll,
162da86cee2Smacallan .d_mmap = mgxmmap,
163da86cee2Smacallan .d_kqfilter = nokqfilter,
164da86cee2Smacallan .d_discard = nodiscard,
165da86cee2Smacallan .d_flag = D_OTHER
166da86cee2Smacallan };
167da86cee2Smacallan
168da86cee2Smacallan /* frame buffer generic driver */
169da86cee2Smacallan static struct fbdriver mgx_fbdriver = {
170da86cee2Smacallan mgx_unblank, mgxopen, mgxclose, mgxioctl, nopoll, mgxmmap,
171da86cee2Smacallan nokqfilter
172da86cee2Smacallan };
173da86cee2Smacallan
174da86cee2Smacallan
175541d4825Smacallan static inline void
mgx_write_vga(struct mgx_softc * sc,uint32_t reg,uint8_t val)176541d4825Smacallan mgx_write_vga(struct mgx_softc *sc, uint32_t reg, uint8_t val)
177541d4825Smacallan {
178541d4825Smacallan bus_space_write_1(sc->sc_tag, sc->sc_vgah, reg ^ 3, val);
179541d4825Smacallan }
180541d4825Smacallan
181541d4825Smacallan static inline uint8_t
mgx_read_vga(struct mgx_softc * sc,uint32_t reg)182541d4825Smacallan mgx_read_vga(struct mgx_softc *sc, uint32_t reg)
183541d4825Smacallan {
184541d4825Smacallan return bus_space_read_1(sc->sc_tag, sc->sc_vgah, reg ^ 3);
185541d4825Smacallan }
186541d4825Smacallan
187541d4825Smacallan static inline void
mgx_write_1(struct mgx_softc * sc,uint32_t reg,uint8_t val)188541d4825Smacallan mgx_write_1(struct mgx_softc *sc, uint32_t reg, uint8_t val)
189541d4825Smacallan {
190541d4825Smacallan bus_space_write_1(sc->sc_tag, sc->sc_blith, reg ^ 3, val);
191541d4825Smacallan }
192541d4825Smacallan
193541d4825Smacallan static inline uint8_t
mgx_read_1(struct mgx_softc * sc,uint32_t reg)194541d4825Smacallan mgx_read_1(struct mgx_softc *sc, uint32_t reg)
195541d4825Smacallan {
196541d4825Smacallan return bus_space_read_1(sc->sc_tag, sc->sc_blith, reg ^ 3);
197541d4825Smacallan }
198541d4825Smacallan
199c1adbebeSmacallan #if 0
200c1adbebeSmacallan static inline uint32_t
201c1adbebeSmacallan mgx_read_4(struct mgx_softc *sc, uint32_t reg)
202c1adbebeSmacallan {
203c1adbebeSmacallan return bus_space_read_4(sc->sc_tag, sc->sc_blith, reg);
204c1adbebeSmacallan }
205c1adbebeSmacallan #endif
206c1adbebeSmacallan
207541d4825Smacallan static inline void
mgx_write_2(struct mgx_softc * sc,uint32_t reg,uint16_t val)20855009e9dSmacallan mgx_write_2(struct mgx_softc *sc, uint32_t reg, uint16_t val)
20955009e9dSmacallan {
21055009e9dSmacallan bus_space_write_2(sc->sc_tag, sc->sc_blith, reg ^ 2, val);
21155009e9dSmacallan }
21255009e9dSmacallan
21355009e9dSmacallan static inline void
mgx_write_4(struct mgx_softc * sc,uint32_t reg,uint32_t val)214541d4825Smacallan mgx_write_4(struct mgx_softc *sc, uint32_t reg, uint32_t val)
215541d4825Smacallan {
216541d4825Smacallan bus_space_write_4(sc->sc_tag, sc->sc_blith, reg, val);
217541d4825Smacallan }
218541d4825Smacallan
219fd3eba58Smacallan static inline void
mgx_set_dec(struct mgx_softc * sc,uint32_t dec)220fd3eba58Smacallan mgx_set_dec(struct mgx_softc *sc, uint32_t dec)
221fd3eba58Smacallan {
222fd3eba58Smacallan if (dec == sc->sc_r_dec) return;
223fd3eba58Smacallan sc->sc_r_dec = dec;
224fd3eba58Smacallan mgx_wait_engine(sc);
225fd3eba58Smacallan mgx_write_4(sc, ATR_DEC, dec);
226fd3eba58Smacallan }
227fd3eba58Smacallan
228fd3eba58Smacallan static inline void
mgx_set_fg(struct mgx_softc * sc,uint32_t fg)229fd3eba58Smacallan mgx_set_fg(struct mgx_softc *sc, uint32_t fg)
230fd3eba58Smacallan {
231fd3eba58Smacallan if (fg == sc->sc_r_fg) return;
232fd3eba58Smacallan sc->sc_r_fg = fg;
233fd3eba58Smacallan mgx_wait_fifo(sc, 1);
234fd3eba58Smacallan mgx_write_4(sc, ATR_FG, fg);
235fd3eba58Smacallan }
236fd3eba58Smacallan
237c6ec2ef8Smacallan static int
mgx_match(device_t parent,cfdata_t cf,void * aux)238c6ec2ef8Smacallan mgx_match(device_t parent, cfdata_t cf, void *aux)
239c6ec2ef8Smacallan {
240c6ec2ef8Smacallan struct sbus_attach_args *sa = aux;
241c6ec2ef8Smacallan
242c6ec2ef8Smacallan if (strcmp("SMSI,mgx", sa->sa_name) == 0)
243c6ec2ef8Smacallan return 100;
244c6ec2ef8Smacallan return 0;
245c6ec2ef8Smacallan }
246c6ec2ef8Smacallan
247c6ec2ef8Smacallan /*
248c6ec2ef8Smacallan * Attach a display. We need to notice if it is the console, too.
249c6ec2ef8Smacallan */
250c6ec2ef8Smacallan static void
mgx_attach(device_t parent,device_t self,void * args)251c6ec2ef8Smacallan mgx_attach(device_t parent, device_t self, void *args)
252c6ec2ef8Smacallan {
253c6ec2ef8Smacallan struct mgx_softc *sc = device_private(self);
254c6ec2ef8Smacallan struct sbus_attach_args *sa = args;
255c6ec2ef8Smacallan struct wsemuldisplaydev_attach_args aa;
256da86cee2Smacallan struct fbdevice *fb = &sc->sc_fb;
257c6ec2ef8Smacallan struct rasops_info *ri;
258c6ec2ef8Smacallan unsigned long defattr;
259c6ec2ef8Smacallan bus_space_handle_t bh;
260ed20f135Smacallan int node = sa->sa_node, bsize;
261c6ec2ef8Smacallan int isconsole;
262c6ec2ef8Smacallan
263c6ec2ef8Smacallan aprint_normal("\n");
264c6ec2ef8Smacallan sc->sc_dev = self;
265c6ec2ef8Smacallan sc->sc_tag = sa->sa_bustag;
266c6ec2ef8Smacallan
267c6ec2ef8Smacallan sc->sc_paddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot,
268c6ec2ef8Smacallan sa->sa_reg[8].oa_base);
269c1adbebeSmacallan sc->sc_rpaddr = sbus_bus_addr(sa->sa_bustag, sa->sa_slot,
270c1adbebeSmacallan sa->sa_reg[5].oa_base + MGX_REG_ATREG_OFFSET);
271c6ec2ef8Smacallan
272c6ec2ef8Smacallan /* read geometry information from the device tree */
273c6ec2ef8Smacallan sc->sc_width = prom_getpropint(sa->sa_node, "width", 1152);
274c6ec2ef8Smacallan sc->sc_height = prom_getpropint(sa->sa_node, "height", 900);
275541d4825Smacallan sc->sc_stride = prom_getpropint(sa->sa_node, "linebytes", 1152);
276541d4825Smacallan sc->sc_fbsize = prom_getpropint(sa->sa_node, "fb_size", 0x00400000);
2776aedd804Smacallan sc->sc_fbaddr = NULL;
278c6ec2ef8Smacallan if (sc->sc_fbaddr == NULL) {
279c6ec2ef8Smacallan if (sbus_bus_map(sa->sa_bustag,
280c6ec2ef8Smacallan sa->sa_slot,
281c6ec2ef8Smacallan sa->sa_reg[8].oa_base,
282c6ec2ef8Smacallan sc->sc_fbsize,
2836aedd804Smacallan BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE,
2846aedd804Smacallan &bh) != 0) {
285541d4825Smacallan aprint_error_dev(self, "couldn't map framebuffer\n");
286c6ec2ef8Smacallan return;
287c6ec2ef8Smacallan }
288c6ec2ef8Smacallan sc->sc_fbaddr = bus_space_vaddr(sa->sa_bustag, bh);
289c6ec2ef8Smacallan }
290c6ec2ef8Smacallan
291c6ec2ef8Smacallan if (sbus_bus_map(sa->sa_bustag,
292c6ec2ef8Smacallan sa->sa_slot,
293c6ec2ef8Smacallan sa->sa_reg[4].oa_base, 0x1000, 0,
294c6ec2ef8Smacallan &sc->sc_vgah) != 0) {
295c6ec2ef8Smacallan aprint_error("%s: couldn't map VGA registers\n",
296c6ec2ef8Smacallan device_xname(sc->sc_dev));
297c6ec2ef8Smacallan return;
298c6ec2ef8Smacallan }
299c6ec2ef8Smacallan
300c6ec2ef8Smacallan if (sbus_bus_map(sa->sa_bustag,
301c6ec2ef8Smacallan sa->sa_slot,
3026aedd804Smacallan sa->sa_reg[5].oa_base + MGX_REG_ATREG_OFFSET, 0x1000,
3036aedd804Smacallan 0, &sc->sc_blith) != 0) {
304c6ec2ef8Smacallan aprint_error("%s: couldn't map blitter registers\n",
305c6ec2ef8Smacallan device_xname(sc->sc_dev));
306c6ec2ef8Smacallan return;
307c6ec2ef8Smacallan }
308c6ec2ef8Smacallan
309541d4825Smacallan mgx_setup(sc, MGX_DEPTH);
310541d4825Smacallan
311541d4825Smacallan aprint_normal_dev(self, "[%s] %d MB framebuffer, %d x %d\n",
312541d4825Smacallan sc->sc_name, sc->sc_fbsize >> 20, sc->sc_width, sc->sc_height);
313541d4825Smacallan
314c6ec2ef8Smacallan
315c6ec2ef8Smacallan sc->sc_defaultscreen_descr = (struct wsscreen_descr) {
316c6ec2ef8Smacallan "default",
317c6ec2ef8Smacallan 0, 0,
318c6ec2ef8Smacallan NULL,
319c6ec2ef8Smacallan 8, 16,
3201ce86285Smacallan WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_UNDERLINE |
3211ce86285Smacallan WSSCREEN_RESIZE,
322c6ec2ef8Smacallan NULL
323c6ec2ef8Smacallan };
32455009e9dSmacallan
32555009e9dSmacallan sc->sc_cursor_x = 0;
32655009e9dSmacallan sc->sc_cursor_y = 0;
32755009e9dSmacallan sc->sc_hotspot_x = 0;
32855009e9dSmacallan sc->sc_hotspot_y = 0;
32955009e9dSmacallan sc->sc_video = WSDISPLAYIO_VIDEO_ON;
33055009e9dSmacallan
331c6ec2ef8Smacallan sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
332c6ec2ef8Smacallan sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
333c6ec2ef8Smacallan
334c6ec2ef8Smacallan isconsole = fb_is_console(node);
335c6ec2ef8Smacallan
336c6ec2ef8Smacallan sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
337c6ec2ef8Smacallan wsfont_init();
338c6ec2ef8Smacallan
339c6ec2ef8Smacallan vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, &mgx_accessops);
340c6ec2ef8Smacallan sc->vd.init_screen = mgx_init_screen;
341ed20f135Smacallan sc->vd.show_screen_cookie = sc;
342ed20f135Smacallan sc->vd.show_screen_cb = mgx_adapt;
343c6ec2ef8Smacallan
344c6ec2ef8Smacallan vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, &defattr);
345c6ec2ef8Smacallan sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
346c6ec2ef8Smacallan
347c6ec2ef8Smacallan ri = &sc->sc_console_screen.scr_ri;
348c6ec2ef8Smacallan
349c6ec2ef8Smacallan sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
350c6ec2ef8Smacallan sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
351c6ec2ef8Smacallan sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
352c6ec2ef8Smacallan sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
353c6ec2ef8Smacallan
3546aedd804Smacallan sc->sc_gc.gc_bitblt = mgx_bitblt;
3556aedd804Smacallan sc->sc_gc.gc_rectfill = mgx_rectfill;
3566aedd804Smacallan sc->sc_gc.gc_blitcookie = sc;
3576aedd804Smacallan sc->sc_gc.gc_rop = ROP_SRC;
3586aedd804Smacallan
3591ce86285Smacallan /*
3601ce86285Smacallan * leave some room between visible screen and glyph cache for upload
3611ce86285Smacallan * buffers used by putchar_mono()
3621ce86285Smacallan */
36368cb2b06Smacallan bsize = (32 * 1024 + sc->sc_stride - 1) / sc->sc_stride;
3646aedd804Smacallan glyphcache_init(&sc->sc_gc,
365ed20f135Smacallan sc->sc_height + bsize,
366ed20f135Smacallan (0x400000 / sc->sc_stride) - (sc->sc_height + bsize),
3676aedd804Smacallan sc->sc_width,
3686aedd804Smacallan ri->ri_font->fontwidth,
3696aedd804Smacallan ri->ri_font->fontheight,
3706aedd804Smacallan defattr);
3716aedd804Smacallan
372c6ec2ef8Smacallan mgx_init_palette(sc);
373c6ec2ef8Smacallan
374c6ec2ef8Smacallan if(isconsole) {
3756aedd804Smacallan wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
3766aedd804Smacallan defattr);
377c6ec2ef8Smacallan vcons_replay_msgbuf(&sc->sc_console_screen);
378c6ec2ef8Smacallan }
379c6ec2ef8Smacallan
380c6ec2ef8Smacallan aa.console = isconsole;
381c6ec2ef8Smacallan aa.scrdata = &sc->sc_screenlist;
382c6ec2ef8Smacallan aa.accessops = &mgx_accessops;
383c6ec2ef8Smacallan aa.accesscookie = &sc->vd;
384c6ec2ef8Smacallan
385c7fb772bSthorpej config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
386c6ec2ef8Smacallan
387da86cee2Smacallan /* now the Sun fb goop */
388da86cee2Smacallan fb->fb_driver = &mgx_fbdriver;
389da86cee2Smacallan fb->fb_device = sc->sc_dev;
390da86cee2Smacallan fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK;
391da86cee2Smacallan fb->fb_type.fb_type = FBTYPE_MGX;
392da86cee2Smacallan fb->fb_pixels = NULL;
393da86cee2Smacallan
394da86cee2Smacallan fb->fb_type.fb_depth = 32;
395da86cee2Smacallan fb->fb_type.fb_width = sc->sc_width;
396da86cee2Smacallan fb->fb_type.fb_height = sc->sc_height;
397da86cee2Smacallan fb->fb_linebytes = sc->sc_stride * 4;
398da86cee2Smacallan
399da86cee2Smacallan fb->fb_type.fb_cmsize = 256;
400da86cee2Smacallan fb->fb_type.fb_size = sc->sc_fbsize;
401da86cee2Smacallan fb_attach(&sc->sc_fb, isconsole);
4026aedd804Smacallan }
4036aedd804Smacallan
404c6ec2ef8Smacallan static void
mgx_write_dac(struct mgx_softc * sc,int idx,int r,int g,int b)405c6ec2ef8Smacallan mgx_write_dac(struct mgx_softc *sc, int idx, int r, int g, int b)
406c6ec2ef8Smacallan {
407c6ec2ef8Smacallan mgx_write_vga(sc, VGA_BASE + VGA_DAC_ADDRW, idx);
408c6ec2ef8Smacallan mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, r);
409c6ec2ef8Smacallan mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, g);
410c6ec2ef8Smacallan mgx_write_vga(sc, VGA_BASE + VGA_DAC_PALETTE, b);
411c6ec2ef8Smacallan }
412c6ec2ef8Smacallan
413c6ec2ef8Smacallan static void
mgx_init_palette(struct mgx_softc * sc)414c6ec2ef8Smacallan mgx_init_palette(struct mgx_softc *sc)
415c6ec2ef8Smacallan {
416c6ec2ef8Smacallan struct rasops_info *ri = &sc->sc_console_screen.scr_ri;
417c6ec2ef8Smacallan int i, j = 0;
418c6ec2ef8Smacallan uint8_t cmap[768];
419c6ec2ef8Smacallan
420541d4825Smacallan if (sc->sc_depth == 8) {
421c6ec2ef8Smacallan rasops_get_cmap(ri, cmap, sizeof(cmap));
422c6ec2ef8Smacallan for (i = 0; i < 256; i++) {
423c6ec2ef8Smacallan sc->sc_cmap_red[i] = cmap[j];
424c6ec2ef8Smacallan sc->sc_cmap_green[i] = cmap[j + 1];
425c6ec2ef8Smacallan sc->sc_cmap_blue[i] = cmap[j + 2];
426c6ec2ef8Smacallan mgx_write_dac(sc, i, cmap[j], cmap[j + 1], cmap[j + 2]);
427c6ec2ef8Smacallan j += 3;
428c6ec2ef8Smacallan }
429541d4825Smacallan } else {
430541d4825Smacallan /* linear ramp for true colour modes */
431541d4825Smacallan for (i = 0; i < 256; i++) {
432541d4825Smacallan mgx_write_dac(sc, i, i, i, i);
433541d4825Smacallan }
434541d4825Smacallan }
435c6ec2ef8Smacallan }
436c6ec2ef8Smacallan
4376aedd804Smacallan static int
mgx_putcmap(struct mgx_softc * sc,struct wsdisplay_cmap * cm)4385bc3657eSmacallan mgx_putcmap(struct mgx_softc *sc, struct wsdisplay_cmap *cm)
4395bc3657eSmacallan {
4405bc3657eSmacallan u_char *r, *g, *b;
4415bc3657eSmacallan u_int index = cm->index;
4425bc3657eSmacallan u_int count = cm->count;
4435bc3657eSmacallan int i, error;
4445bc3657eSmacallan u_char rbuf[256], gbuf[256], bbuf[256];
4455bc3657eSmacallan
4465bc3657eSmacallan if (cm->index >= 256 || cm->count > 256 ||
4475bc3657eSmacallan (cm->index + cm->count) > 256)
4485bc3657eSmacallan return EINVAL;
4495bc3657eSmacallan error = copyin(cm->red, &rbuf[index], count);
4505bc3657eSmacallan if (error)
4515bc3657eSmacallan return error;
4525bc3657eSmacallan error = copyin(cm->green, &gbuf[index], count);
4535bc3657eSmacallan if (error)
4545bc3657eSmacallan return error;
4555bc3657eSmacallan error = copyin(cm->blue, &bbuf[index], count);
4565bc3657eSmacallan if (error)
4575bc3657eSmacallan return error;
4585bc3657eSmacallan
4595bc3657eSmacallan memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
4605bc3657eSmacallan memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
4615bc3657eSmacallan memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
4625bc3657eSmacallan
4635bc3657eSmacallan r = &sc->sc_cmap_red[index];
4645bc3657eSmacallan g = &sc->sc_cmap_green[index];
4655bc3657eSmacallan b = &sc->sc_cmap_blue[index];
4665bc3657eSmacallan
4675bc3657eSmacallan for (i = 0; i < count; i++) {
4685bc3657eSmacallan mgx_write_dac(sc, index, *r, *g, *b);
4695bc3657eSmacallan index++;
4705bc3657eSmacallan r++, g++, b++;
4715bc3657eSmacallan }
4725bc3657eSmacallan return 0;
4735bc3657eSmacallan }
4745bc3657eSmacallan
4755bc3657eSmacallan static int
mgx_getcmap(struct mgx_softc * sc,struct wsdisplay_cmap * cm)4765bc3657eSmacallan mgx_getcmap(struct mgx_softc *sc, struct wsdisplay_cmap *cm)
4775bc3657eSmacallan {
4785bc3657eSmacallan u_int index = cm->index;
4795bc3657eSmacallan u_int count = cm->count;
4805bc3657eSmacallan int error;
4815bc3657eSmacallan
4825bc3657eSmacallan if (index >= 255 || count > 256 || index + count > 256)
4835bc3657eSmacallan return EINVAL;
4845bc3657eSmacallan
4855bc3657eSmacallan error = copyout(&sc->sc_cmap_red[index], cm->red, count);
4865bc3657eSmacallan if (error)
4875bc3657eSmacallan return error;
4885bc3657eSmacallan error = copyout(&sc->sc_cmap_green[index], cm->green, count);
4895bc3657eSmacallan if (error)
4905bc3657eSmacallan return error;
4915bc3657eSmacallan error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
4925bc3657eSmacallan if (error)
4935bc3657eSmacallan return error;
4945bc3657eSmacallan
4955bc3657eSmacallan return 0;
4965bc3657eSmacallan }
4975bc3657eSmacallan
4985bc3657eSmacallan static int
mgx_wait_engine(struct mgx_softc * sc)4996aedd804Smacallan mgx_wait_engine(struct mgx_softc *sc)
5006aedd804Smacallan {
5016aedd804Smacallan unsigned int i;
5026aedd804Smacallan uint8_t stat;
5036aedd804Smacallan
5046aedd804Smacallan for (i = 100000; i != 0; i--) {
5056aedd804Smacallan stat = mgx_read_1(sc, ATR_BLT_STATUS);
5066aedd804Smacallan if ((stat & (BLT_HOST_BUSY | BLT_ENGINE_BUSY)) == 0)
5076aedd804Smacallan break;
5086aedd804Smacallan }
5096aedd804Smacallan
5106aedd804Smacallan return i;
5116aedd804Smacallan }
5126aedd804Smacallan
513541d4825Smacallan static inline int
mgx_wait_host(struct mgx_softc * sc)514541d4825Smacallan mgx_wait_host(struct mgx_softc *sc)
515541d4825Smacallan {
516541d4825Smacallan unsigned int i;
517541d4825Smacallan uint8_t stat;
518541d4825Smacallan
519541d4825Smacallan for (i = 10000; i != 0; i--) {
520541d4825Smacallan stat = mgx_read_1(sc, ATR_BLT_STATUS);
521541d4825Smacallan if ((stat & BLT_HOST_BUSY) == 0)
522541d4825Smacallan break;
523541d4825Smacallan }
524541d4825Smacallan
525541d4825Smacallan return i;
526541d4825Smacallan }
527541d4825Smacallan
528ed20f135Smacallan /*static inline*/ int
mgx_wait_fifo(struct mgx_softc * sc,unsigned int nfifo)5296aedd804Smacallan mgx_wait_fifo(struct mgx_softc *sc, unsigned int nfifo)
5306aedd804Smacallan {
5316aedd804Smacallan unsigned int i;
5326aedd804Smacallan uint8_t stat;
5336aedd804Smacallan
5346aedd804Smacallan for (i = 100000; i != 0; i--) {
5356aedd804Smacallan stat = mgx_read_1(sc, ATR_FIFO_STATUS);
5366aedd804Smacallan stat = (stat & FIFO_MASK) >> FIFO_SHIFT;
5376aedd804Smacallan if (stat >= nfifo)
5386aedd804Smacallan break;
5396aedd804Smacallan mgx_write_1(sc, ATR_FIFO_STATUS, 0);
5406aedd804Smacallan }
5416aedd804Smacallan
5426aedd804Smacallan return i;
5436aedd804Smacallan }
5446aedd804Smacallan
545c6ec2ef8Smacallan static void
mgx_setup(struct mgx_softc * sc,int depth)546c6ec2ef8Smacallan mgx_setup(struct mgx_softc *sc, int depth)
547c6ec2ef8Smacallan {
548541d4825Smacallan uint32_t stride;
549541d4825Smacallan int i;
550541d4825Smacallan uint8_t reg;
551541d4825Smacallan
552fd3eba58Smacallan sc->sc_r_dec = 0xffffffff;
553fd3eba58Smacallan sc->sc_r_fg = 0x12345678;
5546aedd804Smacallan /* wait for everything to go idle */
5556aedd804Smacallan if (mgx_wait_engine(sc) == 0)
5566aedd804Smacallan return;
5576aedd804Smacallan if (mgx_wait_fifo(sc, FIFO_AT24) == 0)
5586aedd804Smacallan return;
559541d4825Smacallan
5601ce86285Smacallan sc->sc_buf = 0;
561541d4825Smacallan /* read name from sequencer */
562541d4825Smacallan for (i = 0; i < 8; i++) {
563541d4825Smacallan mgx_write_vga(sc, SEQ_INDEX, i + 0x11);
564541d4825Smacallan sc->sc_name[i] = mgx_read_vga(sc, SEQ_DATA);
565541d4825Smacallan }
566541d4825Smacallan sc->sc_name[7] = 0;
567541d4825Smacallan
568541d4825Smacallan reg = mgx_read_1(sc, ATR_PIXEL);
569541d4825Smacallan reg &= ~PIXEL_DEPTH_MASK;
5706aedd804Smacallan
5716aedd804Smacallan switch (depth) {
5726aedd804Smacallan case 8:
5736aedd804Smacallan sc->sc_dec = DEC_DEPTH_8 << DEC_DEPTH_SHIFT;
574541d4825Smacallan reg |= PIXEL_8;
5756aedd804Smacallan break;
5766aedd804Smacallan case 15:
577541d4825Smacallan sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT;
578541d4825Smacallan reg |= PIXEL_15;
579541d4825Smacallan break;
5806aedd804Smacallan case 16:
5816aedd804Smacallan sc->sc_dec = DEC_DEPTH_16 << DEC_DEPTH_SHIFT;
582541d4825Smacallan reg |= PIXEL_16;
5836aedd804Smacallan break;
5846aedd804Smacallan case 32:
5856aedd804Smacallan sc->sc_dec = DEC_DEPTH_32 << DEC_DEPTH_SHIFT;
586541d4825Smacallan reg |= PIXEL_32;
5876aedd804Smacallan break;
5886aedd804Smacallan default:
5896aedd804Smacallan return; /* not supported */
5906aedd804Smacallan }
5916aedd804Smacallan
592541d4825Smacallan /* the chip wants stride in units of 8 bytes */
593541d4825Smacallan sc->sc_stride = sc->sc_width * (depth >> 3);
594541d4825Smacallan stride = sc->sc_stride >> 3;
595541d4825Smacallan #ifdef MGX_DEBUG
596ed20f135Smacallan sc->sc_height -= 150;
597541d4825Smacallan #endif
598541d4825Smacallan
599541d4825Smacallan sc->sc_depth = depth;
600541d4825Smacallan
601541d4825Smacallan switch (sc->sc_width) {
6026aedd804Smacallan case 640:
6036aedd804Smacallan sc->sc_dec |= DEC_WIDTH_640 << DEC_WIDTH_SHIFT;
6046aedd804Smacallan break;
6056aedd804Smacallan case 800:
6066aedd804Smacallan sc->sc_dec |= DEC_WIDTH_800 << DEC_WIDTH_SHIFT;
6076aedd804Smacallan break;
6086aedd804Smacallan case 1024:
6096aedd804Smacallan sc->sc_dec |= DEC_WIDTH_1024 << DEC_WIDTH_SHIFT;
6106aedd804Smacallan break;
6116aedd804Smacallan case 1152:
6126aedd804Smacallan sc->sc_dec |= DEC_WIDTH_1152 << DEC_WIDTH_SHIFT;
6136aedd804Smacallan break;
6146aedd804Smacallan case 1280:
6156aedd804Smacallan sc->sc_dec |= DEC_WIDTH_1280 << DEC_WIDTH_SHIFT;
6166aedd804Smacallan break;
6176aedd804Smacallan case 1600:
6186aedd804Smacallan sc->sc_dec |= DEC_WIDTH_1600 << DEC_WIDTH_SHIFT;
6196aedd804Smacallan break;
6206aedd804Smacallan default:
6216aedd804Smacallan return; /* not supported */
6226aedd804Smacallan }
6231ce86285Smacallan mgx_wait_fifo(sc, 4);
6246aedd804Smacallan mgx_write_1(sc, ATR_CLIP_CONTROL, 0);
6256aedd804Smacallan mgx_write_1(sc, ATR_BYTEMASK, 0xff);
626541d4825Smacallan mgx_write_1(sc, ATR_PIXEL, reg);
6271ce86285Smacallan mgx_write_4(sc, ATR_OFFSET, 0);
6281ce86285Smacallan mgx_wait_fifo(sc, 4);
629541d4825Smacallan mgx_write_vga(sc, CRTC_INDEX, 0x13);
630541d4825Smacallan mgx_write_vga(sc, CRTC_DATA, stride & 0xff);
631541d4825Smacallan mgx_write_vga(sc, CRTC_INDEX, 0x1c);
632541d4825Smacallan mgx_write_vga(sc, CRTC_DATA, (stride & 0xf00) >> 4);
63355009e9dSmacallan
63455009e9dSmacallan /* clean up the screen if we're switching to != 8bit */
63555009e9dSmacallan if (depth != MGX_DEPTH)
63655009e9dSmacallan mgx_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 0);
63755009e9dSmacallan
6381ce86285Smacallan mgx_wait_fifo(sc, 4);
63955009e9dSmacallan /* initialize hardware cursor stuff */
64055009e9dSmacallan mgx_write_2(sc, ATR_CURSOR_ADDRESS, (sc->sc_fbsize - 1024) >> 10);
64155009e9dSmacallan mgx_write_1(sc, ATR_CURSOR_ENABLE, 0);
64255009e9dSmacallan sc->sc_cursor = (uint8_t *)sc->sc_fbaddr + sc->sc_fbsize - 1024;
64355009e9dSmacallan memset(sc->sc_cursor, 0xf0, 1024);
644ed20f135Smacallan memset(sc->sc_in, 0, sizeof(sc->sc_in));
6456aedd804Smacallan }
6466aedd804Smacallan
6476aedd804Smacallan static void
mgx_bitblt(void * cookie,int xs,int ys,int xd,int yd,int wi,int he,int rop)6486aedd804Smacallan mgx_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, int he,
6496aedd804Smacallan int rop)
6506aedd804Smacallan {
6516aedd804Smacallan struct mgx_softc *sc = cookie;
6526aedd804Smacallan uint32_t dec = sc->sc_dec;
6536aedd804Smacallan
6546aedd804Smacallan dec |= (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
6556aedd804Smacallan (DEC_START_DIMX << DEC_START_SHIFT);
6566aedd804Smacallan if (xs < xd) {
6576aedd804Smacallan xs += wi - 1;
6586aedd804Smacallan xd += wi - 1;
6596aedd804Smacallan dec |= DEC_DIR_X_REVERSE;
6606aedd804Smacallan }
6616aedd804Smacallan if (ys < yd) {
6626aedd804Smacallan ys += he - 1;
6636aedd804Smacallan yd += he - 1;
6646aedd804Smacallan dec |= DEC_DIR_Y_REVERSE;
6656aedd804Smacallan }
666fd3eba58Smacallan mgx_set_dec(sc, dec);
667fd3eba58Smacallan mgx_wait_fifo(sc, 4);
6686aedd804Smacallan mgx_write_1(sc, ATR_ROP, rop);
6696aedd804Smacallan mgx_write_4(sc, ATR_SRC_XY, (ys << 16) | xs);
6706aedd804Smacallan mgx_write_4(sc, ATR_DST_XY, (yd << 16) | xd);
6716aedd804Smacallan mgx_write_4(sc, ATR_WH, (he << 16) | wi);
6726aedd804Smacallan }
6736aedd804Smacallan
6746aedd804Smacallan static void
mgx_rectfill(void * cookie,int x,int y,int wi,int he,long fg)6756aedd804Smacallan mgx_rectfill(void *cookie, int x, int y, int wi, int he, long fg)
6766aedd804Smacallan {
6776aedd804Smacallan struct mgx_softc *sc = cookie;
6786aedd804Smacallan struct vcons_screen *scr = sc->vd.active;
6796aedd804Smacallan uint32_t dec = sc->sc_dec;
6806aedd804Smacallan uint32_t col;
6816aedd804Smacallan
6826aedd804Smacallan if (scr == NULL)
6836aedd804Smacallan return;
6846aedd804Smacallan col = scr->scr_ri.ri_devcmap[fg];
6856aedd804Smacallan
6866aedd804Smacallan dec = sc->sc_dec;
6876aedd804Smacallan dec |= (DEC_COMMAND_RECT << DEC_COMMAND_SHIFT) |
6886aedd804Smacallan (DEC_START_DIMX << DEC_START_SHIFT);
689fd3eba58Smacallan mgx_set_dec(sc, dec);
690fd3eba58Smacallan mgx_set_fg(sc, col);
691fd3eba58Smacallan mgx_wait_fifo(sc, 3);
6926aedd804Smacallan mgx_write_1(sc, ATR_ROP, ROP_SRC);
6936aedd804Smacallan mgx_write_4(sc, ATR_DST_XY, (y << 16) | x);
6946aedd804Smacallan mgx_write_4(sc, ATR_WH, (he << 16) | wi);
6956aedd804Smacallan }
6966aedd804Smacallan
6976aedd804Smacallan static void
mgx_putchar_aa(void * cookie,int row,int col,u_int c,long attr)6981ce86285Smacallan mgx_putchar_aa(void *cookie, int row, int col, u_int c, long attr)
6996aedd804Smacallan {
7006aedd804Smacallan struct rasops_info *ri = cookie;
7016aedd804Smacallan struct wsdisplay_font *font = PICK_FONT(ri, c);
7026aedd804Smacallan struct vcons_screen *scr = ri->ri_hw;
7036aedd804Smacallan struct mgx_softc *sc = scr->scr_cookie;
7046aedd804Smacallan uint32_t fg, bg;
7056aedd804Smacallan int x, y, wi, he, rv;
7066aedd804Smacallan
7076aedd804Smacallan wi = font->fontwidth;
7086aedd804Smacallan he = font->fontheight;
7096aedd804Smacallan
7106aedd804Smacallan bg = (attr >> 16) & 0xf;
7116aedd804Smacallan fg = (attr >> 24) & 0xf;
7126aedd804Smacallan
7136aedd804Smacallan x = ri->ri_xorigin + col * wi;
7146aedd804Smacallan y = ri->ri_yorigin + row * he;
7156aedd804Smacallan
7166aedd804Smacallan if (c == 0x20) {
7176aedd804Smacallan mgx_rectfill(sc, x, y, wi, he, bg);
7186aedd804Smacallan if (attr & 1)
7196aedd804Smacallan mgx_rectfill(sc, x, y + he - 2, wi, 1, fg);
7206aedd804Smacallan return;
7216aedd804Smacallan }
7221ce86285Smacallan
7236aedd804Smacallan rv = glyphcache_try(&sc->sc_gc, c, x, y, attr);
7243ea14281Smacallan if (rv != GC_OK) {
7253ea14281Smacallan volatile uint32_t junk;
7263ea14281Smacallan
7276aedd804Smacallan mgx_wait_engine(sc);
7286aedd804Smacallan sc->sc_putchar(cookie, row, col, c, attr & ~1);
729541d4825Smacallan if (rv == GC_ADD) {
730c1adbebeSmacallan /*
731c1adbebeSmacallan * try to make sure the glyph made it all the way to
732c1adbebeSmacallan * video memory before trying to blit it into the cache
733c1adbebeSmacallan */
7343ea14281Smacallan junk = *(uint32_t *)sc->sc_fbaddr;
7355bc3657eSmacallan __USE(junk);
7366aedd804Smacallan glyphcache_add(&sc->sc_gc, c, x, y);
7373ea14281Smacallan }
738541d4825Smacallan }
7396aedd804Smacallan if (attr & 1)
7406aedd804Smacallan mgx_rectfill(sc, x, y + he - 2, wi, 1, fg);
7416aedd804Smacallan }
7426aedd804Smacallan
7436aedd804Smacallan static void
mgx_putchar_mono(void * cookie,int row,int col,u_int c,long attr)7441ce86285Smacallan mgx_putchar_mono(void *cookie, int row, int col, u_int c, long attr)
7451ce86285Smacallan {
7461ce86285Smacallan struct rasops_info *ri = cookie;
7471ce86285Smacallan struct wsdisplay_font *font = PICK_FONT(ri, c);
7481ce86285Smacallan struct vcons_screen *scr = ri->ri_hw;
7491ce86285Smacallan struct mgx_softc *sc = scr->scr_cookie;
750ed20f135Smacallan uint8_t *s, *d;
751ed20f135Smacallan uint32_t fg, bg, scratch = ((sc->sc_stride * sc->sc_height) + 7) & ~7;
752ed20f135Smacallan int x, y, wi, he, len, i;
7531ce86285Smacallan
7541ce86285Smacallan wi = font->fontwidth;
7551ce86285Smacallan he = font->fontheight;
7561ce86285Smacallan
7571ce86285Smacallan bg = (attr >> 16) & 0xf;
7581ce86285Smacallan fg = (attr >> 24) & 0xf;
7591ce86285Smacallan
7601ce86285Smacallan x = ri->ri_xorigin + col * wi;
7611ce86285Smacallan y = ri->ri_yorigin + row * he;
7621ce86285Smacallan
763ed20f135Smacallan if (!CHAR_IN_FONT(c, font)) {
764ed20f135Smacallan c = 0x20;
765ed20f135Smacallan #ifdef MGX_DEBUG
766ed20f135Smacallan bg = WSCOL_LIGHT_BLUE;
767ed20f135Smacallan #endif
768ed20f135Smacallan }
7691ce86285Smacallan if (c == 0x20) {
7701ce86285Smacallan mgx_rectfill(sc, x, y, wi, he, bg);
7711ce86285Smacallan if (attr & 1)
7721ce86285Smacallan mgx_rectfill(sc, x, y + he - 2, wi, 1, fg);
7731ce86285Smacallan return;
7741ce86285Smacallan }
7751ce86285Smacallan
776fd3eba58Smacallan mgx_set_fg(sc, ri->ri_devcmap[fg]);
777fd3eba58Smacallan mgx_wait_fifo(sc, 2);
7781ce86285Smacallan mgx_write_4(sc, ATR_BG, ri->ri_devcmap[bg]);
7791ce86285Smacallan mgx_write_1(sc, ATR_ROP, ROP_SRC);
780ed20f135Smacallan
781ed20f135Smacallan /*
782ed20f135Smacallan * do hardware colour expansion
783ed20f135Smacallan * there has to be an upload port somewhere, since there are host blit
784ed20f135Smacallan * commands, but it's not used or mentioned in the xf86-video-apm driver
785ed20f135Smacallan * so for now we use the vram-to-vram blits to draw characters.
786ed20f135Smacallan * stash most of the font in vram for speed, also:
787ed20f135Smacallan * - the sbus-pci bridge doesn't seem to support 64bit accesses,
788ed20f135Smacallan * they will cause occasional data corruption and all sorts of weird
789ed20f135Smacallan * side effects, so copy font bitmaps byte-wise
790ed20f135Smacallan * - at least it doesn't seem to need any kind of buffer flushing
791ed20f135Smacallan * - still use rotation buffers for characters that don't fall into the
792ed20f135Smacallan * 8 bit range
793ed20f135Smacallan */
794ed20f135Smacallan
795ed20f135Smacallan len = (ri->ri_fontscale + 7) & ~7;
796ed20f135Smacallan s = WSFONT_GLYPH(c, font);
797ed20f135Smacallan if ((c > 32) && (c < 256)) {
798ed20f135Smacallan scratch += len * c;
799ed20f135Smacallan if (sc->sc_in[c] == 0) {
800ed20f135Smacallan d = (uint8_t *)sc->sc_fbaddr + scratch;
801ed20f135Smacallan for (i = 0; i < ri->ri_fontscale; i++)
802ed20f135Smacallan d[i] = s[i];
803ed20f135Smacallan sc->sc_in[c] = 1;
804ed20f135Smacallan }
805ed20f135Smacallan } else {
806ed20f135Smacallan sc->sc_buf = (sc->sc_buf + 1) & 7; /* rotate through 8 buffers */
807ed20f135Smacallan scratch += sc->sc_buf * len;
808ed20f135Smacallan d = (uint8_t *)sc->sc_fbaddr + scratch;
809ed20f135Smacallan for (i = 0; i < ri->ri_fontscale; i++)
810ed20f135Smacallan d[i] = s[i];
811ed20f135Smacallan }
812fd3eba58Smacallan mgx_set_dec(sc, sc->sc_dec | (DEC_COMMAND_BLT << DEC_COMMAND_SHIFT) |
8131ce86285Smacallan (DEC_START_DIMX << DEC_START_SHIFT) |
8141ce86285Smacallan DEC_SRC_LINEAR | DEC_SRC_CONTIGUOUS | DEC_MONOCHROME);
815fd3eba58Smacallan mgx_wait_fifo(sc, 3);
8161ce86285Smacallan mgx_write_4(sc, ATR_SRC_XY, ((scratch & 0xfff000) << 4) | (scratch & 0xfff));
8171ce86285Smacallan mgx_write_4(sc, ATR_DST_XY, (y << 16) | x);
8181ce86285Smacallan mgx_write_4(sc, ATR_WH, (he << 16) | wi);
8191ce86285Smacallan
8201ce86285Smacallan if (attr & 1)
8211ce86285Smacallan mgx_rectfill(sc, x, y + he - 2, wi, 1, fg);
8221ce86285Smacallan }
8231ce86285Smacallan
8241ce86285Smacallan static void
mgx_cursor(void * cookie,int on,int row,int col)8256aedd804Smacallan mgx_cursor(void *cookie, int on, int row, int col)
8266aedd804Smacallan {
8276aedd804Smacallan struct rasops_info *ri = cookie;
8286aedd804Smacallan struct vcons_screen *scr = ri->ri_hw;
8296aedd804Smacallan struct mgx_softc *sc = scr->scr_cookie;
8306aedd804Smacallan int x, y, wi,he;
8316aedd804Smacallan
8326aedd804Smacallan wi = ri->ri_font->fontwidth;
8336aedd804Smacallan he = ri->ri_font->fontheight;
8346aedd804Smacallan
8356aedd804Smacallan if (ri->ri_flg & RI_CURSOR) {
8366aedd804Smacallan x = ri->ri_ccol * wi + ri->ri_xorigin;
8376aedd804Smacallan y = ri->ri_crow * he + ri->ri_yorigin;
8386aedd804Smacallan mgx_bitblt(sc, x, y, x, y, wi, he, ROP_INV);
8396aedd804Smacallan ri->ri_flg &= ~RI_CURSOR;
8406aedd804Smacallan }
8416aedd804Smacallan
8426aedd804Smacallan ri->ri_crow = row;
8436aedd804Smacallan ri->ri_ccol = col;
8446aedd804Smacallan
8456aedd804Smacallan if (on)
8466aedd804Smacallan {
8476aedd804Smacallan x = ri->ri_ccol * wi + ri->ri_xorigin;
8486aedd804Smacallan y = ri->ri_crow * he + ri->ri_yorigin;
8496aedd804Smacallan mgx_bitblt(sc, x, y, x, y, wi, he, ROP_INV);
8506aedd804Smacallan ri->ri_flg |= RI_CURSOR;
8516aedd804Smacallan }
8526aedd804Smacallan }
8536aedd804Smacallan
8546aedd804Smacallan static void
mgx_copycols(void * cookie,int row,int srccol,int dstcol,int ncols)8556aedd804Smacallan mgx_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
8566aedd804Smacallan {
8576aedd804Smacallan struct rasops_info *ri = cookie;
8586aedd804Smacallan struct vcons_screen *scr = ri->ri_hw;
8596aedd804Smacallan struct mgx_softc *sc = scr->scr_cookie;
8606aedd804Smacallan int32_t xs, xd, y, width, height;
8616aedd804Smacallan
8626aedd804Smacallan xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
8636aedd804Smacallan xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
8646aedd804Smacallan y = ri->ri_yorigin + ri->ri_font->fontheight * row;
8656aedd804Smacallan width = ri->ri_font->fontwidth * ncols;
8666aedd804Smacallan height = ri->ri_font->fontheight;
8676aedd804Smacallan mgx_bitblt(sc, xs, y, xd, y, width, height, ROP_SRC);
8686aedd804Smacallan }
8696aedd804Smacallan
8706aedd804Smacallan static void
mgx_erasecols(void * cookie,int row,int startcol,int ncols,long fillattr)8716aedd804Smacallan mgx_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
8726aedd804Smacallan {
8736aedd804Smacallan struct rasops_info *ri = cookie;
8746aedd804Smacallan struct vcons_screen *scr = ri->ri_hw;
8756aedd804Smacallan struct mgx_softc *sc = scr->scr_cookie;
8766aedd804Smacallan int32_t x, y, width, height, bg;
8776aedd804Smacallan
8786aedd804Smacallan x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol;
8796aedd804Smacallan y = ri->ri_yorigin + ri->ri_font->fontheight * row;
8806aedd804Smacallan width = ri->ri_font->fontwidth * ncols;
8816aedd804Smacallan height = ri->ri_font->fontheight;
8826aedd804Smacallan bg = (fillattr >> 16) & 0xff;
8836aedd804Smacallan mgx_rectfill(sc, x, y, width, height, bg);
8846aedd804Smacallan }
8856aedd804Smacallan
8866aedd804Smacallan static void
mgx_copyrows(void * cookie,int srcrow,int dstrow,int nrows)8876aedd804Smacallan mgx_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
8886aedd804Smacallan {
8896aedd804Smacallan struct rasops_info *ri = cookie;
8906aedd804Smacallan struct vcons_screen *scr = ri->ri_hw;
8916aedd804Smacallan struct mgx_softc *sc = scr->scr_cookie;
8926aedd804Smacallan int32_t x, ys, yd, width, height;
8936aedd804Smacallan
8946aedd804Smacallan x = ri->ri_xorigin;
8956aedd804Smacallan ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
8966aedd804Smacallan yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
8976aedd804Smacallan width = ri->ri_emuwidth;
8986aedd804Smacallan height = ri->ri_font->fontheight * nrows;
8996aedd804Smacallan mgx_bitblt(sc, x, ys, x, yd, width, height, ROP_SRC);
9006aedd804Smacallan }
9016aedd804Smacallan
9026aedd804Smacallan static void
mgx_eraserows(void * cookie,int row,int nrows,long fillattr)9036aedd804Smacallan mgx_eraserows(void *cookie, int row, int nrows, long fillattr)
9046aedd804Smacallan {
9056aedd804Smacallan struct rasops_info *ri = cookie;
9066aedd804Smacallan struct vcons_screen *scr = ri->ri_hw;
9076aedd804Smacallan struct mgx_softc *sc = scr->scr_cookie;
9086aedd804Smacallan int32_t x, y, width, height, bg;
9096aedd804Smacallan
9106aedd804Smacallan if ((row == 0) && (nrows == ri->ri_rows)) {
9116aedd804Smacallan x = y = 0;
9126aedd804Smacallan width = ri->ri_width;
9136aedd804Smacallan height = ri->ri_height;
9146aedd804Smacallan } else {
9156aedd804Smacallan x = ri->ri_xorigin;
9166aedd804Smacallan y = ri->ri_yorigin + ri->ri_font->fontheight * row;
9176aedd804Smacallan width = ri->ri_emuwidth;
9186aedd804Smacallan height = ri->ri_font->fontheight * nrows;
9196aedd804Smacallan }
9206aedd804Smacallan bg = (fillattr >> 16) & 0xff;
9216aedd804Smacallan mgx_rectfill(sc, x, y, width, height, bg);
922c6ec2ef8Smacallan }
923c6ec2ef8Smacallan
924c6ec2ef8Smacallan static void
mgx_adapt(struct vcons_screen * scr,void * cookie)925ed20f135Smacallan mgx_adapt(struct vcons_screen *scr, void *cookie)
926ed20f135Smacallan {
927ed20f135Smacallan struct mgx_softc *sc = cookie;
928ed20f135Smacallan memset(sc->sc_in, 0, sizeof(sc->sc_in));
929ed20f135Smacallan glyphcache_adapt(scr, &sc->sc_gc);
930ed20f135Smacallan }
931ed20f135Smacallan
932ed20f135Smacallan static void
mgx_init_screen(void * cookie,struct vcons_screen * scr,int existing,long * defattr)933c6ec2ef8Smacallan mgx_init_screen(void *cookie, struct vcons_screen *scr,
934c6ec2ef8Smacallan int existing, long *defattr)
935c6ec2ef8Smacallan {
936c6ec2ef8Smacallan struct mgx_softc *sc = cookie;
937c6ec2ef8Smacallan struct rasops_info *ri = &scr->scr_ri;
938c6ec2ef8Smacallan
939541d4825Smacallan ri->ri_depth = sc->sc_depth;
940c6ec2ef8Smacallan ri->ri_width = sc->sc_width;
941c6ec2ef8Smacallan ri->ri_height = sc->sc_height;
942c6ec2ef8Smacallan ri->ri_stride = sc->sc_stride;
9433ea14281Smacallan ri->ri_flg = RI_CENTER | RI_ENABLE_ALPHA;
944c6ec2ef8Smacallan
945c6ec2ef8Smacallan if (ri->ri_depth == 8)
9463ea14281Smacallan ri->ri_flg |= RI_8BIT_IS_RGB;
947c6ec2ef8Smacallan
948541d4825Smacallan #ifdef MGX_NOACCEL
949541d4825Smacallan scr->scr_flags |= VCONS_DONT_READ;
950541d4825Smacallan #endif
9511ce86285Smacallan scr->scr_flags |= VCONS_LOADFONT;
952541d4825Smacallan
953541d4825Smacallan ri->ri_rnum = 8;
954541d4825Smacallan ri->ri_rpos = 0;
955541d4825Smacallan ri->ri_gnum = 8;
956541d4825Smacallan ri->ri_gpos = 8;
957541d4825Smacallan ri->ri_bnum = 8;
958541d4825Smacallan ri->ri_bpos = 16;
959541d4825Smacallan
960c6ec2ef8Smacallan ri->ri_bits = sc->sc_fbaddr;
961c6ec2ef8Smacallan
962c6ec2ef8Smacallan rasops_init(ri, 0, 0);
963c6ec2ef8Smacallan
964805ab46bSmacallan ri->ri_caps = WSSCREEN_REVERSE | WSSCREEN_WSCOLORS |
965805ab46bSmacallan WSSCREEN_UNDERLINE | WSSCREEN_RESIZE;
966c6ec2ef8Smacallan
967c6ec2ef8Smacallan rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
968c6ec2ef8Smacallan ri->ri_width / ri->ri_font->fontwidth);
9696aedd804Smacallan
9706aedd804Smacallan ri->ri_hw = scr;
971541d4825Smacallan
972541d4825Smacallan #ifdef MGX_NOACCEL
973541d4825Smacallan if (0)
974541d4825Smacallan #endif
975541d4825Smacallan {
9761ce86285Smacallan if (FONT_IS_ALPHA(ri->ri_font)) {
9771ce86285Smacallan sc->sc_putchar = ri->ri_ops.putchar;
9781ce86285Smacallan ri->ri_ops.putchar = mgx_putchar_aa;
9791ce86285Smacallan } else {
9801ce86285Smacallan ri->ri_ops.putchar = mgx_putchar_mono;
9811ce86285Smacallan }
9826aedd804Smacallan ri->ri_ops.cursor = mgx_cursor;
9836aedd804Smacallan ri->ri_ops.copyrows = mgx_copyrows;
9846aedd804Smacallan ri->ri_ops.eraserows = mgx_eraserows;
9856aedd804Smacallan ri->ri_ops.copycols = mgx_copycols;
9866aedd804Smacallan ri->ri_ops.erasecols = mgx_erasecols;
987c6ec2ef8Smacallan }
988541d4825Smacallan }
989c6ec2ef8Smacallan
990c6ec2ef8Smacallan static int
mgx_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)991c6ec2ef8Smacallan mgx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
992c6ec2ef8Smacallan struct lwp *l)
993c6ec2ef8Smacallan {
994c6ec2ef8Smacallan struct vcons_data *vd = v;
995c6ec2ef8Smacallan struct mgx_softc *sc = vd->cookie;
996c6ec2ef8Smacallan struct wsdisplay_fbinfo *wdf;
997c6ec2ef8Smacallan struct vcons_screen *ms = vd->active;
998c6ec2ef8Smacallan
999c6ec2ef8Smacallan switch (cmd) {
1000c6ec2ef8Smacallan case WSDISPLAYIO_GTYPE:
1001c6ec2ef8Smacallan *(u_int *)data = WSDISPLAY_TYPE_MGX;
1002c6ec2ef8Smacallan return 0;
1003c6ec2ef8Smacallan
1004c6ec2ef8Smacallan case WSDISPLAYIO_GINFO:
1005c6ec2ef8Smacallan wdf = (void *)data;
1006c6ec2ef8Smacallan wdf->height = sc->sc_height;
1007c6ec2ef8Smacallan wdf->width = sc->sc_width;
1008c6ec2ef8Smacallan wdf->depth = 8;
1009c6ec2ef8Smacallan wdf->cmsize = 256;
1010c6ec2ef8Smacallan return 0;
1011c6ec2ef8Smacallan
1012da86cee2Smacallan case FBIOGTYPE:
1013da86cee2Smacallan *(struct fbtype *)data = sc->sc_fb.fb_type;
1014b9e65661Smacallan return 0;
1015da86cee2Smacallan
1016da86cee2Smacallan case FBIOGATTR:
1017da86cee2Smacallan #define fba ((struct fbgattr *)data)
1018da86cee2Smacallan fba->real_type = sc->sc_fb.fb_type.fb_type;
1019da86cee2Smacallan fba->owner = 0; /* XXX ??? */
1020da86cee2Smacallan fba->fbtype = sc->sc_fb.fb_type;
1021da86cee2Smacallan fba->sattr.flags = 0;
1022da86cee2Smacallan fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type;
1023da86cee2Smacallan fba->sattr.dev_specific[0] = -1;
1024da86cee2Smacallan fba->emu_types[0] = sc->sc_fb.fb_type.fb_type;
1025da86cee2Smacallan fba->emu_types[1] = -1;
1026da86cee2Smacallan #undef fba
1027b9e65661Smacallan return 0;
1028c6ec2ef8Smacallan case FBIOGVIDEO:
1029c6ec2ef8Smacallan case WSDISPLAYIO_GVIDEO:
103055009e9dSmacallan *(int *)data = sc->sc_video;
1031c6ec2ef8Smacallan return 0;
1032c6ec2ef8Smacallan
1033c6ec2ef8Smacallan case WSDISPLAYIO_SVIDEO:
1034c6ec2ef8Smacallan case FBIOSVIDEO:
103555009e9dSmacallan mgx_set_video(sc, *(int *)data);
1036c6ec2ef8Smacallan return 0;
1037c6ec2ef8Smacallan
1038c6ec2ef8Smacallan case WSDISPLAYIO_LINEBYTES:
1039c6ec2ef8Smacallan {
1040c6ec2ef8Smacallan int *ret = (int *)data;
1041c6ec2ef8Smacallan *ret = sc->sc_stride;
1042c6ec2ef8Smacallan }
1043c6ec2ef8Smacallan return 0;
1044c6ec2ef8Smacallan
1045c6ec2ef8Smacallan case WSDISPLAYIO_SMODE:
1046c6ec2ef8Smacallan {
1047c6ec2ef8Smacallan int new_mode = *(int*)data;
1048c6ec2ef8Smacallan if (new_mode != sc->sc_mode)
1049c6ec2ef8Smacallan {
1050c6ec2ef8Smacallan sc->sc_mode = new_mode;
1051c6ec2ef8Smacallan if (new_mode == WSDISPLAYIO_MODE_EMUL)
1052c6ec2ef8Smacallan {
1053541d4825Smacallan mgx_setup(sc, MGX_DEPTH);
10545bc3657eSmacallan glyphcache_wipe(&sc->sc_gc);
10555bc3657eSmacallan mgx_init_palette(sc);
1056c6ec2ef8Smacallan vcons_redraw_screen(ms);
1057c6ec2ef8Smacallan } else {
1058*9404ac38Smacallan mgx_setup(sc, MGX_X_DEPTH);
1059541d4825Smacallan mgx_init_palette(sc);
1060c6ec2ef8Smacallan }
1061c6ec2ef8Smacallan }
1062c6ec2ef8Smacallan }
10635bc3657eSmacallan return 0;
1064c6ec2ef8Smacallan
10655bc3657eSmacallan case WSDISPLAYIO_GETCMAP:
10665bc3657eSmacallan return mgx_getcmap(sc, (struct wsdisplay_cmap *)data);
10675bc3657eSmacallan
10685bc3657eSmacallan case WSDISPLAYIO_PUTCMAP:
10695bc3657eSmacallan return mgx_putcmap(sc, (struct wsdisplay_cmap *)data);
10705bc3657eSmacallan
1071*9404ac38Smacallan case FBIOGETCMAP:
1072*9404ac38Smacallan #define p ((struct fbcmap *)data)
1073*9404ac38Smacallan {
1074*9404ac38Smacallan struct wsdisplay_cmap c = {
1075*9404ac38Smacallan .index = p->index,
1076*9404ac38Smacallan .count = p->count,
1077*9404ac38Smacallan .red = p->red,
1078*9404ac38Smacallan .green = p->green,
1079*9404ac38Smacallan .blue = p->blue
1080*9404ac38Smacallan };
1081*9404ac38Smacallan return mgx_getcmap(sc, &c);
1082*9404ac38Smacallan }
1083*9404ac38Smacallan break;
1084*9404ac38Smacallan case FBIOPUTCMAP:
1085*9404ac38Smacallan {
1086*9404ac38Smacallan struct wsdisplay_cmap c = {
1087*9404ac38Smacallan .index = p->index,
1088*9404ac38Smacallan .count = p->count,
1089*9404ac38Smacallan .red = p->red,
1090*9404ac38Smacallan .green = p->green,
1091*9404ac38Smacallan .blue = p->blue
1092*9404ac38Smacallan };
1093*9404ac38Smacallan return mgx_putcmap(sc, &c);
1094*9404ac38Smacallan }
1095*9404ac38Smacallan break;
1096*9404ac38Smacallan #undef p
109755009e9dSmacallan case WSDISPLAYIO_GCURPOS:
109855009e9dSmacallan {
109955009e9dSmacallan struct wsdisplay_curpos *cp = (void *)data;
110055009e9dSmacallan
110155009e9dSmacallan cp->x = sc->sc_cursor_x;
110255009e9dSmacallan cp->y = sc->sc_cursor_y;
110355009e9dSmacallan }
110455009e9dSmacallan return 0;
110555009e9dSmacallan
110655009e9dSmacallan case WSDISPLAYIO_SCURPOS:
110755009e9dSmacallan {
110855009e9dSmacallan struct wsdisplay_curpos *cp = (void *)data;
110955009e9dSmacallan
111055009e9dSmacallan sc->sc_cursor_x = cp->x;
111155009e9dSmacallan sc->sc_cursor_y = cp->y;
111255009e9dSmacallan mgx_set_cursor(sc);
111355009e9dSmacallan }
111455009e9dSmacallan return 0;
111555009e9dSmacallan
111655009e9dSmacallan case WSDISPLAYIO_GCURMAX:
111755009e9dSmacallan {
111855009e9dSmacallan struct wsdisplay_curpos *cp = (void *)data;
111955009e9dSmacallan
112055009e9dSmacallan cp->x = 64;
112155009e9dSmacallan cp->y = 64;
112255009e9dSmacallan }
112355009e9dSmacallan return 0;
112455009e9dSmacallan
112555009e9dSmacallan case WSDISPLAYIO_SCURSOR:
112655009e9dSmacallan {
112755009e9dSmacallan struct wsdisplay_cursor *cursor = (void *)data;
112855009e9dSmacallan
112955009e9dSmacallan return mgx_do_cursor(sc, cursor);
113055009e9dSmacallan }
1131b9e65661Smacallan
11325bc3657eSmacallan case WSDISPLAYIO_GET_FBINFO:
11335bc3657eSmacallan {
11345bc3657eSmacallan struct wsdisplayio_fbinfo *fbi = data;
11355bc3657eSmacallan
113655009e9dSmacallan fbi->fbi_fbsize = sc->sc_fbsize - 1024;
1137541d4825Smacallan fbi->fbi_width = sc->sc_width;
1138541d4825Smacallan fbi->fbi_height = sc->sc_height;
1139541d4825Smacallan fbi->fbi_bitsperpixel = sc->sc_depth;
1140541d4825Smacallan fbi->fbi_stride = sc->sc_stride;
1141541d4825Smacallan fbi->fbi_pixeltype = WSFB_RGB;
1142541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.red_offset = 8;
1143541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.red_size = 8;
1144541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.green_offset = 16;
1145541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.green_size = 8;
1146541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.blue_offset = 24;
1147541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.blue_size = 8;
1148541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.alpha_offset = 0;
1149541d4825Smacallan fbi->fbi_subtype.fbi_rgbmasks.alpha_size = 8;
1150541d4825Smacallan return 0;
11515bc3657eSmacallan }
11525bc3657eSmacallan }
1153c6ec2ef8Smacallan return EPASSTHROUGH;
1154c6ec2ef8Smacallan }
1155c6ec2ef8Smacallan
1156c6ec2ef8Smacallan static paddr_t
mgx_mmap(void * v,void * vs,off_t offset,int prot)1157c6ec2ef8Smacallan mgx_mmap(void *v, void *vs, off_t offset, int prot)
1158c6ec2ef8Smacallan {
1159c6ec2ef8Smacallan struct vcons_data *vd = v;
1160c6ec2ef8Smacallan struct mgx_softc *sc = vd->cookie;
11610cd8abe1Smacallan uint32_t flags = BUS_SPACE_MAP_LINEAR;
11620cd8abe1Smacallan
11630cd8abe1Smacallan #ifdef BUS_SPACE_MAP_LITTLE
11640cd8abe1Smacallan if (offset & MGX_FLIPOFFSET) {
11650cd8abe1Smacallan offset &= ~MGX_FLIPOFFSET;
11660cd8abe1Smacallan flags |= BUS_SPACE_MAP_LITTLE;
11670cd8abe1Smacallan }
11680cd8abe1Smacallan #endif
1169c6ec2ef8Smacallan
1170c6ec2ef8Smacallan /* regular fb mapping at 0 */
1171541d4825Smacallan if ((offset >= 0) && (offset < sc->sc_fbsize)) {
1172c6ec2ef8Smacallan return bus_space_mmap(sc->sc_tag, sc->sc_paddr,
11730cd8abe1Smacallan offset, prot, flags);
1174c6ec2ef8Smacallan }
1175c6ec2ef8Smacallan
1176c1adbebeSmacallan /*
1177c4eb9daeSmacallan * Blitter registers at 0x00800000, only in mapped mode.
1178c1adbebeSmacallan * Restrict to root, even though I'm fairly sure the DMA engine lives
1179c1adbebeSmacallan * elsewhere ( and isn't documented anyway )
1180c1adbebeSmacallan */
1181c1adbebeSmacallan if (kauth_authorize_machdep(kauth_cred_get(),
1182c1adbebeSmacallan KAUTH_MACHDEP_UNMANAGEDMEM,
1183c1adbebeSmacallan NULL, NULL, NULL, NULL) != 0) {
1184c1adbebeSmacallan aprint_normal("%s: mmap() rejected.\n",
1185c1adbebeSmacallan device_xname(sc->sc_dev));
1186c1adbebeSmacallan return -1;
1187c1adbebeSmacallan }
1188c1adbebeSmacallan if ((sc->sc_mode == WSDISPLAYIO_MODE_MAPPED) &&
1189c4eb9daeSmacallan (offset >= MGX_BLTOFFSET) && (offset < MGX_BLTOFFSET + 0x1000)) {
1190c1adbebeSmacallan return bus_space_mmap(sc->sc_tag, sc->sc_rpaddr,
1191c4eb9daeSmacallan offset - MGX_BLTOFFSET, prot, BUS_SPACE_MAP_LINEAR);
1192c1adbebeSmacallan }
1193c6ec2ef8Smacallan return -1;
1194c6ec2ef8Smacallan }
119555009e9dSmacallan
119655009e9dSmacallan static int
mgx_do_cursor(struct mgx_softc * sc,struct wsdisplay_cursor * cur)119755009e9dSmacallan mgx_do_cursor(struct mgx_softc *sc, struct wsdisplay_cursor *cur)
119855009e9dSmacallan {
119955009e9dSmacallan int i;
120055009e9dSmacallan if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
120155009e9dSmacallan
120255009e9dSmacallan if (cur->enable) {
120355009e9dSmacallan mgx_set_cursor(sc);
120455009e9dSmacallan mgx_write_1(sc, ATR_CURSOR_ENABLE, 1);
120555009e9dSmacallan } else {
120655009e9dSmacallan mgx_write_1(sc, ATR_CURSOR_ENABLE, 0);
120755009e9dSmacallan }
120855009e9dSmacallan }
120955009e9dSmacallan if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
121055009e9dSmacallan
121155009e9dSmacallan sc->sc_hotspot_x = cur->hot.x;
121255009e9dSmacallan sc->sc_hotspot_y = cur->hot.y;
121355009e9dSmacallan mgx_set_cursor(sc);
121455009e9dSmacallan }
121555009e9dSmacallan if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
121655009e9dSmacallan
121755009e9dSmacallan sc->sc_cursor_x = cur->pos.x;
121855009e9dSmacallan sc->sc_cursor_y = cur->pos.y;
121955009e9dSmacallan mgx_set_cursor(sc);
122055009e9dSmacallan }
122155009e9dSmacallan if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
1222d1579b2dSriastradh int cnt = uimin(2, cur->cmap.count);
122355009e9dSmacallan uint8_t c;
122455009e9dSmacallan uint8_t r[2], g[2], b[2];
122555009e9dSmacallan
122655009e9dSmacallan copyin(cur->cmap.red, r, cnt);
122755009e9dSmacallan copyin(cur->cmap.green, g, cnt);
122855009e9dSmacallan copyin(cur->cmap.blue, b, cnt);
122955009e9dSmacallan
123055009e9dSmacallan for (i = 0; i < cnt; i++) {
123155009e9dSmacallan c = r[i] & 0xe0;
123255009e9dSmacallan c |= (g[i] & 0xe0) >> 3;
123355009e9dSmacallan c |= (b[i] & 0xc0) >> 6;
123455009e9dSmacallan mgx_write_1(sc, ATR_CURSOR_FG + i, c);
123555009e9dSmacallan }
123655009e9dSmacallan }
123755009e9dSmacallan if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
123855009e9dSmacallan int j;
123955009e9dSmacallan uint8_t *fb = sc->sc_cursor;
124055009e9dSmacallan uint8_t temp;
124155009e9dSmacallan uint8_t im, ma, px;
124255009e9dSmacallan
124355009e9dSmacallan for (i = 0; i < 512; i++) {
124455009e9dSmacallan temp = 0;
124555009e9dSmacallan copyin(&cur->image[i], &im, 1);
124655009e9dSmacallan copyin(&cur->mask[i], &ma, 1);
124755009e9dSmacallan for (j = 0; j < 4; j++) {
124855009e9dSmacallan temp >>= 2;
124955009e9dSmacallan px = (ma & 1) ? 0 : 0x80;
125055009e9dSmacallan if (px == 0)
125155009e9dSmacallan px |= (im & 1) ? 0 : 0x40;
125255009e9dSmacallan temp |= px;
125355009e9dSmacallan im >>= 1;
125455009e9dSmacallan ma >>= 1;
125555009e9dSmacallan }
125655009e9dSmacallan *fb = temp;
125755009e9dSmacallan fb++;
125855009e9dSmacallan temp = 0;
125955009e9dSmacallan for (j = 0; j < 4; j++) {
126055009e9dSmacallan temp >>= 2;
126155009e9dSmacallan px = (ma & 1) ? 0 : 0x80;
126255009e9dSmacallan if (px == 0)
126355009e9dSmacallan px |= (im & 1) ? 0 : 0x40;
126455009e9dSmacallan temp |= px;
126555009e9dSmacallan im >>= 1;
126655009e9dSmacallan ma >>= 1;
126755009e9dSmacallan }
126855009e9dSmacallan *fb = temp;
126955009e9dSmacallan fb++;
127055009e9dSmacallan }
127155009e9dSmacallan }
127255009e9dSmacallan return 0;
127355009e9dSmacallan }
127455009e9dSmacallan
127555009e9dSmacallan static void
mgx_set_cursor(struct mgx_softc * sc)127655009e9dSmacallan mgx_set_cursor(struct mgx_softc *sc)
127755009e9dSmacallan {
127855009e9dSmacallan uint32_t reg;
127955009e9dSmacallan uint16_t hot;
128055009e9dSmacallan
128155009e9dSmacallan reg = (sc->sc_cursor_y << 16) | (sc->sc_cursor_x & 0xffff);
128255009e9dSmacallan mgx_write_4(sc, ATR_CURSOR_POSITION, reg);
128355009e9dSmacallan hot = (sc->sc_hotspot_y << 8) | (sc->sc_hotspot_x & 0xff);
128455009e9dSmacallan mgx_write_2(sc, ATR_CURSOR_HOTSPOT, hot);
128555009e9dSmacallan }
128655009e9dSmacallan
128755009e9dSmacallan static void
mgx_set_video(struct mgx_softc * sc,int v)128855009e9dSmacallan mgx_set_video(struct mgx_softc *sc, int v)
128955009e9dSmacallan {
129055009e9dSmacallan uint8_t reg;
129155009e9dSmacallan
129255009e9dSmacallan if (sc->sc_video == v)
129355009e9dSmacallan return;
129455009e9dSmacallan
129555009e9dSmacallan sc->sc_video = v;
129655009e9dSmacallan reg = mgx_read_1(sc, ATR_DPMS);
129755009e9dSmacallan
129855009e9dSmacallan if (v == WSDISPLAYIO_VIDEO_ON) {
129955009e9dSmacallan reg &= ~DPMS_SYNC_DISABLE_ALL;
130055009e9dSmacallan } else {
130155009e9dSmacallan reg |= DPMS_SYNC_DISABLE_ALL;
130255009e9dSmacallan }
130355009e9dSmacallan mgx_write_1(sc, ATR_DPMS, reg);
130455009e9dSmacallan }
1305da86cee2Smacallan
1306da86cee2Smacallan /* Sun fb dev goop */
1307da86cee2Smacallan static void
mgx_unblank(device_t dev)1308da86cee2Smacallan mgx_unblank(device_t dev)
1309da86cee2Smacallan {
1310da86cee2Smacallan struct mgx_softc *sc = device_private(dev);
1311da86cee2Smacallan
1312da86cee2Smacallan mgx_set_video(sc, WSDISPLAYIO_VIDEO_ON);
1313da86cee2Smacallan }
1314da86cee2Smacallan
1315da86cee2Smacallan paddr_t
mgxmmap(dev_t dev,off_t offset,int prot)1316da86cee2Smacallan mgxmmap(dev_t dev, off_t offset, int prot)
1317da86cee2Smacallan {
1318da86cee2Smacallan struct mgx_softc *sc = device_lookup_private(&mgx_cd, minor(dev));
13190cd8abe1Smacallan uint32_t flags = BUS_SPACE_MAP_LINEAR;
13200cd8abe1Smacallan
13210cd8abe1Smacallan #ifdef BUS_SPACE_MAP_LITTLE
13220cd8abe1Smacallan if (offset & MGX_FLIPOFFSET) {
13230cd8abe1Smacallan offset &= ~MGX_FLIPOFFSET;
13240cd8abe1Smacallan flags |= BUS_SPACE_MAP_LITTLE;
13250cd8abe1Smacallan }
13260cd8abe1Smacallan #endif
1327da86cee2Smacallan
1328da86cee2Smacallan /* regular fb mapping at 0 */
1329da86cee2Smacallan if ((offset >= 0) && (offset < sc->sc_fbsize)) {
1330da86cee2Smacallan return bus_space_mmap(sc->sc_tag, sc->sc_paddr,
13310cd8abe1Smacallan offset, prot, flags);
1332da86cee2Smacallan }
1333da86cee2Smacallan
1334da86cee2Smacallan /*
1335c4eb9daeSmacallan * Blitter registers at 0x00800000, only in mapped mode.
1336da86cee2Smacallan * Restrict to root, even though I'm fairly sure the DMA engine lives
1337da86cee2Smacallan * elsewhere ( and isn't documented anyway )
1338da86cee2Smacallan */
1339da86cee2Smacallan if (kauth_authorize_machdep(kauth_cred_get(),
1340da86cee2Smacallan KAUTH_MACHDEP_UNMANAGEDMEM,
1341da86cee2Smacallan NULL, NULL, NULL, NULL) != 0) {
1342da86cee2Smacallan aprint_normal("%s: mmap() rejected.\n",
1343da86cee2Smacallan device_xname(sc->sc_dev));
1344da86cee2Smacallan return -1;
1345da86cee2Smacallan }
1346da86cee2Smacallan if ((sc->sc_mode == WSDISPLAYIO_MODE_MAPPED) &&
1347c4eb9daeSmacallan (offset >= MGX_BLTOFFSET) && (offset < MGX_BLTOFFSET + 0x1000)) {
1348da86cee2Smacallan return bus_space_mmap(sc->sc_tag, sc->sc_rpaddr,
1349c4eb9daeSmacallan offset - MGX_BLTOFFSET, prot, BUS_SPACE_MAP_LINEAR);
1350da86cee2Smacallan }
1351da86cee2Smacallan return -1;
1352da86cee2Smacallan }
1353da86cee2Smacallan
1354da86cee2Smacallan int
mgxopen(dev_t dev,int flags,int mode,struct lwp * l)1355da86cee2Smacallan mgxopen(dev_t dev, int flags, int mode, struct lwp *l)
1356da86cee2Smacallan {
1357da86cee2Smacallan device_t dv = device_lookup(&mgx_cd, minor(dev));
1358da86cee2Smacallan struct mgx_softc *sc = device_private(dv);
1359da86cee2Smacallan
1360da86cee2Smacallan if (dv == NULL)
1361da86cee2Smacallan return ENXIO;
1362da86cee2Smacallan if (sc->sc_mode == WSDISPLAYIO_MODE_MAPPED)
1363da86cee2Smacallan return 0;
1364da86cee2Smacallan sc->sc_mode = WSDISPLAYIO_MODE_MAPPED;
1365*9404ac38Smacallan mgx_setup(sc, MGX_X_DEPTH);
1366da86cee2Smacallan mgx_init_palette(sc);
1367da86cee2Smacallan return 0;
1368da86cee2Smacallan }
1369da86cee2Smacallan
1370da86cee2Smacallan int
mgxclose(dev_t dev,int flags,int mode,struct lwp * l)1371da86cee2Smacallan mgxclose(dev_t dev, int flags, int mode, struct lwp *l)
1372da86cee2Smacallan {
1373da86cee2Smacallan device_t dv = device_lookup(&mgx_cd, minor(dev));
1374da86cee2Smacallan struct mgx_softc *sc = device_private(dv);
1375da86cee2Smacallan struct vcons_screen *ms = sc->vd.active;
1376da86cee2Smacallan
1377da86cee2Smacallan if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)
1378da86cee2Smacallan return 0;
1379da86cee2Smacallan
1380da86cee2Smacallan sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
1381da86cee2Smacallan
1382da86cee2Smacallan mgx_setup(sc, MGX_DEPTH);
1383da86cee2Smacallan glyphcache_wipe(&sc->sc_gc);
1384da86cee2Smacallan mgx_init_palette(sc);
1385da86cee2Smacallan if (ms != NULL) {
1386da86cee2Smacallan vcons_redraw_screen(ms);
1387da86cee2Smacallan }
1388da86cee2Smacallan return 0;
1389da86cee2Smacallan }
1390da86cee2Smacallan
1391da86cee2Smacallan int
mgxioctl(dev_t dev,u_long cmd,void * data,int flags,struct lwp * l)1392da86cee2Smacallan mgxioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
1393da86cee2Smacallan {
1394da86cee2Smacallan struct mgx_softc *sc = device_lookup_private(&mgx_cd, minor(dev));
1395da86cee2Smacallan
1396da86cee2Smacallan return mgx_ioctl(&sc->vd, NULL, cmd, data, flags, l);
1397da86cee2Smacallan }
1398