xref: /netbsd-src/sys/arch/sgimips/gio/newport.c (revision 7fa608457b817eca6e0977b37f758ae064f3c99c)
1 /*	$NetBSD: newport.c,v 1.10 2007/03/04 06:00:39 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 Ilpo Ruotsalainen
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: newport.c,v 1.10 2007/03/04 06:00:39 christos Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 
40 #include <machine/sysconf.h>
41 
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsdisplayvar.h>
44 #include <dev/wsfont/wsfont.h>
45 
46 #include <sgimips/gio/giovar.h>
47 #include <sgimips/gio/newportvar.h>
48 #include <sgimips/gio/newportreg.h>
49 
50 struct newport_softc {
51 	struct device sc_dev;
52 
53 	struct newport_devconfig *sc_dc;
54 };
55 
56 struct newport_devconfig {
57 	uint32_t		dc_addr;
58 
59 	bus_space_tag_t		dc_st;
60 	bus_space_handle_t	dc_sh;
61 
62 	int			dc_boardrev;
63 	int			dc_vc2rev;
64 	int			dc_cmaprev;
65 	int			dc_xmaprev;
66 	int			dc_rexrev;
67 	int			dc_xres;
68 	int			dc_yres;
69 	int			dc_depth;
70 
71 	int			dc_font;
72 	struct wsdisplay_font	*dc_fontdata;
73 };
74 
75 static int  newport_match(struct device *, struct cfdata *, void *);
76 static void newport_attach(struct device *, struct device *, void *);
77 
78 CFATTACH_DECL(newport, sizeof(struct newport_softc),
79     newport_match, newport_attach, NULL, NULL);
80 
81 /* textops */
82 static void newport_cursor(void *, int, int, int);
83 static int  newport_mapchar(void *, int, unsigned int *);
84 static void newport_putchar(void *, int, int, u_int, long);
85 static void newport_copycols(void *, int, int, int, int);
86 static void newport_erasecols(void *, int, int, int, long);
87 static void newport_copyrows(void *, int, int, int);
88 static void newport_eraserows(void *, int, int, long);
89 static int  newport_allocattr(void *, int, int, int, long *);
90 
91 /* accessops */
92 static int     newport_ioctl(void *, void *, u_long, void *, int,
93     struct lwp *);
94 static paddr_t newport_mmap(void *, void *, off_t, int);
95 static int     newport_alloc_screen(void *, const struct wsscreen_descr *,
96     void **, int *, int *, long *);
97 static void    newport_free_screen(void *, void *);
98 static int     newport_show_screen(void *, void *, int,
99     void (*)(void *, int, int), void *);
100 
101 static const struct wsdisplay_emulops newport_textops = {
102 	.cursor		= newport_cursor,
103 	.mapchar	= newport_mapchar,
104 	.putchar	= newport_putchar,
105 	.copycols	= newport_copycols,
106 	.erasecols	= newport_erasecols,
107 	.copyrows	= newport_copyrows,
108 	.eraserows	= newport_eraserows,
109 	.allocattr	= newport_allocattr
110 };
111 
112 static const struct wsdisplay_accessops newport_accessops = {
113 	.ioctl		= newport_ioctl,
114 	.mmap		= newport_mmap,
115 	.alloc_screen	= newport_alloc_screen,
116 	.free_screen	= newport_free_screen,
117 	.show_screen	= newport_show_screen,
118 };
119 
120 static const struct wsscreen_descr newport_screen_1024x768 = {
121 	.name		= "1024x768",
122 	.ncols		= 128,
123 	.nrows		= 48,
124 	.textops	= &newport_textops,
125 	.fontwidth	= 8,
126 	.fontheight	= 16,
127 	.capabilities	= WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_REVERSE
128 };
129 
130 static const struct wsscreen_descr newport_screen_1280x1024 = {
131 	.name		= "1280x1024",
132 	.ncols		= 160,
133 	.nrows		= 64,
134 	.textops	= &newport_textops,
135 	.fontwidth	= 8,
136 	.fontheight	= 16,
137 	.capabilities	= WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_REVERSE
138 };
139 
140 static const struct wsscreen_descr *_newport_screenlist[] = {
141 	&newport_screen_1024x768,
142 	&newport_screen_1280x1024
143 };
144 
145 static const struct wsscreen_list newport_screenlist = {
146 	sizeof(_newport_screenlist) / sizeof(struct wsscreen_descr *),
147 	_newport_screenlist
148 };
149 
150 static struct newport_devconfig newport_console_dc;
151 static int newport_is_console = 0;
152 
153 #define NEWPORT_ATTR_ENCODE(fg,bg)	(((fg) << 8) | (bg))
154 #define NEWPORT_ATTR_BG(a)		((a) & 0xff)
155 #define NEWPORT_ATTR_FG(a)		(((a) >> 8) & 0xff)
156 
157 static const uint16_t newport_cursor_data[128] = {
158 	/* Bit 0 */
159 	0xff00, 0x0000,
160 	0xff00, 0x0000,
161 	0xff00, 0x0000,
162 	0xff00, 0x0000,
163 	0xff00, 0x0000,
164 	0xff00, 0x0000,
165 	0xff00, 0x0000,
166 	0xff00, 0x0000,
167 	0xff00, 0x0000,
168 	0xff00, 0x0000,
169 	0xff00, 0x0000,
170 	0xff00, 0x0000,
171 	0xff00, 0x0000,
172 	0xff00, 0x0000,
173 	0xff00, 0x0000,
174 	0xff00, 0x0000,
175 	0x0000, 0x0000,
176 	0x0000, 0x0000,
177 	0x0000, 0x0000,
178 	0x0000, 0x0000,
179 	0x0000, 0x0000,
180 	0x0000, 0x0000,
181 	0x0000, 0x0000,
182 	0x0000, 0x0000,
183 	0x0000, 0x0000,
184 	0x0000, 0x0000,
185 	0x0000, 0x0000,
186 	0x0000, 0x0000,
187 	0x0000, 0x0000,
188 	0x0000, 0x0000,
189 	0x0000, 0x0000,
190 	0x0000, 0x0000,
191 
192 	/* Bit 1 */
193 	0x0000, 0x0000,
194 	0x0000, 0x0000,
195 	0x0000, 0x0000,
196 	0x0000, 0x0000,
197 	0x0000, 0x0000,
198 	0x0000, 0x0000,
199 	0x0000, 0x0000,
200 	0x0000, 0x0000,
201 	0x0000, 0x0000,
202 	0x0000, 0x0000,
203 	0x0000, 0x0000,
204 	0x0000, 0x0000,
205 	0x0000, 0x0000,
206 	0x0000, 0x0000,
207 	0x0000, 0x0000,
208 	0x0000, 0x0000,
209 	0x0000, 0x0000,
210 	0x0000, 0x0000,
211 	0x0000, 0x0000,
212 	0x0000, 0x0000,
213 	0x0000, 0x0000,
214 	0x0000, 0x0000,
215 	0x0000, 0x0000,
216 	0x0000, 0x0000,
217 	0x0000, 0x0000,
218 	0x0000, 0x0000,
219 	0x0000, 0x0000,
220 	0x0000, 0x0000,
221 	0x0000, 0x0000,
222 	0x0000, 0x0000,
223 	0x0000, 0x0000,
224 	0x0000, 0x0000,
225 };
226 
227 static const uint8_t newport_defcmap[16*3] = {
228 	/* Normal colors */
229 	0x00, 0x00, 0x00, /* black */
230 	0x7f, 0x00, 0x00, /* red */
231 	0x00, 0x7f, 0x00, /* green */
232 	0x7f, 0x7f, 0x00, /* brown */
233 	0x00, 0x00, 0x7f, /* blue */
234 	0x7f, 0x00, 0x7f, /* magenta */
235 	0x00, 0x7f, 0x7f, /* cyan */
236 	0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
237 
238 	/* Hilite colors */
239 	0x7f, 0x7f, 0x7f, /* black */
240 	0xff, 0x00, 0x00, /* red */
241 	0x00, 0xff, 0x00, /* green */
242 	0xff, 0xff, 0x00, /* brown */
243 	0x00, 0x00, 0xff, /* blue */
244 	0xff, 0x00, 0xff, /* magenta */
245 	0x00, 0xff, 0xff, /* cyan */
246 	0xff, 0xff, 0xff, /* white */
247 };
248 
249 /**** Low-level hardware register groveling functions ****/
250 static void
251 rex3_write(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
252 {
253 	bus_space_write_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET + rexreg,
254 	    val);
255 }
256 
257 static void
258 rex3_write_go(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
259 {
260 	rex3_write(dc, rexreg + REX3_REG_GO, val);
261 }
262 
263 static uint32_t
264 rex3_read(struct newport_devconfig *dc, bus_size_t rexreg)
265 {
266 	return bus_space_read_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET +
267 	    rexreg);
268 }
269 
270 static void
271 rex3_wait_gfifo(struct newport_devconfig *dc)
272 {
273 	while (rex3_read(dc, REX3_REG_STATUS) & REX3_STATUS_GFXBUSY)
274 		;
275 }
276 
277 static void
278 vc2_write_ireg(struct newport_devconfig *dc, uint8_t ireg, uint16_t val)
279 {
280 	rex3_write(dc, REX3_REG_DCBMODE,
281 	    REX3_DCBMODE_DW_3 |
282 	    REX3_DCBMODE_ENCRSINC |
283 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
284 	    (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
285 	    REX3_DCBMODE_ENASYNCACK |
286 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
287 
288 	rex3_write(dc, REX3_REG_DCBDATA0, (ireg << 24) | (val << 8));
289 }
290 
291 static uint16_t
292 vc2_read_ireg(struct newport_devconfig *dc, uint8_t ireg)
293 {
294 	rex3_write(dc, REX3_REG_DCBMODE,
295 	    REX3_DCBMODE_DW_1 |
296 	    REX3_DCBMODE_ENCRSINC |
297 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
298 	    (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
299 	    REX3_DCBMODE_ENASYNCACK |
300 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
301 
302 	rex3_write(dc, REX3_REG_DCBDATA0, ireg << 24);
303 
304 	rex3_write(dc, REX3_REG_DCBMODE,
305 	    REX3_DCBMODE_DW_2 |
306 	    REX3_DCBMODE_ENCRSINC |
307 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
308 	    (VC2_DCBCRS_IREG << REX3_DCBMODE_DCBCRS_SHIFT) |
309 	    REX3_DCBMODE_ENASYNCACK |
310 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
311 
312 	return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
313 }
314 
315 static uint16_t
316 vc2_read_ram(struct newport_devconfig *dc, uint16_t addr)
317 {
318 	vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);
319 
320 	rex3_write(dc, REX3_REG_DCBMODE,
321 	    REX3_DCBMODE_DW_2 |
322 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
323 	    (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
324 	    REX3_DCBMODE_ENASYNCACK |
325 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
326 
327 	return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
328 }
329 
330 static void
331 vc2_write_ram(struct newport_devconfig *dc, uint16_t addr, uint16_t val)
332 {
333 	vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);
334 
335 	rex3_write(dc, REX3_REG_DCBMODE,
336 	    REX3_DCBMODE_DW_2 |
337 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
338 	    (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
339 	    REX3_DCBMODE_ENASYNCACK |
340 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
341 
342 	rex3_write(dc, REX3_REG_DCBDATA0, val << 16);
343 }
344 
345 static u_int32_t
346 xmap9_read(struct newport_devconfig *dc, int crs)
347 {
348 	rex3_write(dc, REX3_REG_DCBMODE,
349 		REX3_DCBMODE_DW_1 |
350 		(NEWPORT_DCBADDR_XMAP_0 << REX3_DCBMODE_DCBADDR_SHIFT) |
351 		(crs << REX3_DCBMODE_DCBCRS_SHIFT) |
352 		(3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
353 		(2 << REX3_DCBMODE_CSHOLD_SHIFT) |
354 		(1 << REX3_DCBMODE_CSSETUP_SHIFT));
355 	return rex3_read(dc, REX3_REG_DCBDATA0);
356 }
357 
358 static void
359 xmap9_write(struct newport_devconfig *dc, int crs, uint8_t val)
360 {
361 	rex3_write(dc, REX3_REG_DCBMODE,
362 	    REX3_DCBMODE_DW_1 |
363 	    (NEWPORT_DCBADDR_XMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
364 	    (crs << REX3_DCBMODE_DCBCRS_SHIFT) |
365 	    (3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
366 	    (2 << REX3_DCBMODE_CSHOLD_SHIFT) |
367 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
368 
369 	rex3_write(dc, REX3_REG_DCBDATA0, val << 24);
370 }
371 
372 static void
373 xmap9_write_mode(struct newport_devconfig *dc, uint8_t index, uint32_t mode)
374 {
375 	rex3_write(dc, REX3_REG_DCBMODE,
376 	    REX3_DCBMODE_DW_4 |
377 	    (NEWPORT_DCBADDR_XMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
378 	    (XMAP9_DCBCRS_MODE_SETUP << REX3_DCBMODE_DCBCRS_SHIFT) |
379 	    (3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
380 	    (2 << REX3_DCBMODE_CSHOLD_SHIFT) |
381 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
382 
383 	rex3_write(dc, REX3_REG_DCBDATA0, (index << 24) | mode);
384 }
385 
386 /**** Helper functions ****/
387 static void
388 newport_fill_rectangle(struct newport_devconfig *dc, int x1, int y1, int x2,
389     int y2, uint8_t color)
390 {
391 	rex3_wait_gfifo(dc);
392 
393 	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
394 	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
395 	    REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
396 	rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
397 	rex3_write(dc, REX3_REG_COLORI, color);
398 	rex3_write(dc, REX3_REG_XYSTARTI, (x1 << REX3_XYSTARTI_XSHIFT) | y1);
399 
400 	rex3_write_go(dc, REX3_REG_XYENDI, (x2 << REX3_XYENDI_XSHIFT) | y2);
401 }
402 
403 static void
404 newport_copy_rectangle(struct newport_devconfig *dc, int x1, int y1, int x2,
405     int y2, int dx, int dy)
406 {
407 	uint32_t tmp;
408 
409 	rex3_wait_gfifo(dc);
410 
411 	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_SCR2SCR |
412 	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
413 	    REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
414 	rex3_write(dc, REX3_REG_XYSTARTI, (x1 << REX3_XYSTARTI_XSHIFT) | y1);
415 	rex3_write(dc, REX3_REG_XYENDI, (x2 << REX3_XYENDI_XSHIFT) | y2);
416 
417 	tmp = (dy - y1) & 0xffff;
418 	tmp |= (dx - x1) << REX3_XYMOVE_XSHIFT;
419 
420 	rex3_write_go(dc, REX3_REG_XYMOVE, tmp);
421 }
422 
423 static void
424 newport_cmap_setrgb(struct newport_devconfig *dc, int index, uint8_t r,
425     uint8_t g, uint8_t b)
426 {
427 	rex3_write(dc, REX3_REG_DCBMODE,
428 	    REX3_DCBMODE_DW_2 |
429 	    REX3_DCBMODE_ENCRSINC |
430 	    (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
431 	    (CMAP_DCBCRS_ADDRESS_LOW << REX3_DCBMODE_DCBCRS_SHIFT) |
432 	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
433 	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
434 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT) |
435 	    REX3_DCBMODE_SWAPENDIAN);
436 
437 	rex3_write(dc, REX3_REG_DCBDATA0, index << 16);
438 
439 	rex3_write(dc, REX3_REG_DCBMODE,
440 	    REX3_DCBMODE_DW_3 |
441 	    (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
442 	    (CMAP_DCBCRS_PALETTE << REX3_DCBMODE_DCBCRS_SHIFT) |
443 	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
444 	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
445 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
446 
447 	rex3_write(dc, REX3_REG_DCBDATA0, (r << 24) + (g << 16) + (b << 8));
448 }
449 
450 static void
451 newport_get_resolution(struct newport_devconfig *dc)
452 {
453 	uint16_t vep,lines;
454 	uint16_t linep,cols;
455 	uint16_t data;
456 
457 	vep = vc2_read_ireg(dc, VC2_IREG_VIDEO_ENTRY);
458 
459 	dc->dc_xres = 0;
460 	dc->dc_yres = 0;
461 
462 	for (;;) {
463 		/* Iterate over runs in video timing table */
464 
465 		cols = 0;
466 
467 		linep = vc2_read_ram(dc, vep++);
468 		lines = vc2_read_ram(dc, vep++);
469 
470 		if (lines == 0)
471 			break;
472 
473 		do {
474 			/* Iterate over state runs in line sequence table */
475 
476 			data = vc2_read_ram(dc, linep++);
477 
478 			if ((data & 0x0001) == 0)
479 				cols += (data >> 7) & 0xfe;
480 
481 			if ((data & 0x0080) == 0)
482 				data = vc2_read_ram(dc, linep++);
483 		} while ((data & 0x8000) == 0);
484 
485 		if (cols != 0) {
486 			if (cols > dc->dc_xres)
487 				dc->dc_xres = cols;
488 
489 			dc->dc_yres += lines;
490 		}
491 	}
492 }
493 
494 static void
495 newport_setup_hw(struct newport_devconfig *dc)
496 {
497 	uint16_t curp,tmp;
498 	int i;
499 	uint32_t scratch;
500 
501 	/* Get various revisions */
502 	rex3_write(dc, REX3_REG_DCBMODE,
503 	    REX3_DCBMODE_DW_1 |
504 	    (NEWPORT_DCBADDR_CMAP_0 << REX3_DCBMODE_DCBADDR_SHIFT) |
505 	    (CMAP_DCBCRS_REVISION << REX3_DCBMODE_DCBCRS_SHIFT) |
506 	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
507 	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
508 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
509 
510 	scratch = vc2_read_ireg(dc, VC2_IREG_CONFIG);
511 	dc->dc_vc2rev = (scratch & VC2_IREG_CONFIG_REVISION) >> 5;
512 
513 	scratch = rex3_read(dc, REX3_REG_DCBDATA0);
514 
515 	dc->dc_boardrev = (scratch >> 28) & 0x07;
516 	dc->dc_cmaprev = scratch & 0x07;
517 	dc->dc_xmaprev = xmap9_read(dc, XMAP9_DCBCRS_REVISION) & 0x07;
518 	dc->dc_depth = ( (dc->dc_boardrev > 1) && (scratch & 0x80)) ? 8 : 24;
519 
520 	/* Setup cursor glyph */
521 	curp = vc2_read_ireg(dc, VC2_IREG_CURSOR_ENTRY);
522 
523 	for (i=0; i<128; i++)
524 		vc2_write_ram(dc, curp + i, newport_cursor_data[i]);
525 
526 	/* Setup VC2 to a known state */
527 	tmp = vc2_read_ireg(dc, VC2_IREG_CONTROL) & VC2_CONTROL_INTERLACE;
528 	vc2_write_ireg(dc, VC2_IREG_CONTROL, tmp |
529 	    VC2_CONTROL_DISPLAY_ENABLE |
530 	    VC2_CONTROL_VTIMING_ENABLE |
531 	    VC2_CONTROL_DID_ENABLE |
532 	    VC2_CONTROL_CURSORFUNC_ENABLE |
533 	    VC2_CONTROL_CURSOR_ENABLE);
534 
535 	/* Setup XMAP9s */
536 	xmap9_write(dc, XMAP9_DCBCRS_CONFIG,
537 	    XMAP9_CONFIG_8BIT_SYSTEM | XMAP9_CONFIG_RGBMAP_CI);
538 
539 	xmap9_write(dc, XMAP9_DCBCRS_CURSOR_CMAP, 0);
540 
541 	xmap9_write_mode(dc, 0,
542 	    XMAP9_MODE_GAMMA_BYPASS |
543 	    XMAP9_MODE_PIXSIZE_8BPP);
544 	xmap9_write(dc, XMAP9_DCBCRS_MODE_SELECT, 0);
545 
546 	/* Setup REX3 */
547 	rex3_write(dc, REX3_REG_DRAWMODE1,
548 	    REX3_DRAWMODE1_PLANES_CI |
549 	    REX3_DRAWMODE1_DD_DD8 |
550 	    REX3_DRAWMODE1_RWPACKED |
551 	    REX3_DRAWMODE1_HD_HD8 |
552 	    REX3_DRAWMODE1_COMPARE_LT |
553 	    REX3_DRAWMODE1_COMPARE_EQ |
554 	    REX3_DRAWMODE1_COMPARE_GT |
555 	    REX3_DRAWMODE1_LO_SRC);
556 	rex3_write(dc, REX3_REG_XYWIN, (4096 << 16) | 4096);
557 	rex3_write(dc, REX3_REG_TOPSCAN, 0x3ff); /* XXX Why? XXX */
558 
559 	/* Setup CMAP */
560 	for (i=0; i<16; i++)
561 		newport_cmap_setrgb(dc, i, newport_defcmap[i*3],
562 		    newport_defcmap[i*3 + 1], newport_defcmap[i*3 + 2]);
563 }
564 
565 /**** Attach routines ****/
566 static int
567 newport_match(struct device *parent, struct cfdata *self, void *aux)
568 {
569 	struct gio_attach_args *ga = aux;
570 
571 	/* newport doesn't decode all addresses */
572 	if (ga->ga_addr != 0x1f000000 && ga->ga_addr != 0x1f400000 &&
573 	    ga->ga_addr != 0x1f800000 && ga->ga_addr != 0x1fc00000)
574 		return 0;
575 
576 	/* Don't do the destructive probe if we're already attached */
577 	if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr)
578 		return 1;
579 
580 	if (platform.badaddr(
581 	    (void *)(ga->ga_ioh + NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI),
582 	    sizeof(uint32_t)))
583 		return 0;
584 	if (platform.badaddr(
585 	    (void *)(ga->ga_ioh + NEWPORT_REX3_OFFSET + REX3_REG_XSTART),
586 	    sizeof(uint32_t)))
587 		return 0;
588 
589 	/* Ugly, this probe is destructive, blame SGI... */
590 	/* XXX Should be bus_space_peek/bus_space_poke XXX */
591 	bus_space_write_4(ga->ga_iot, ga->ga_ioh,
592 	    NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI, 0x12345678);
593 	if (bus_space_read_4(ga->ga_iot, ga->ga_ioh,
594 	      NEWPORT_REX3_OFFSET + REX3_REG_XSTART)
595 	    != ((0x12345678 & 0xffff) << 11))
596 		return 0;
597 
598 	return 1;
599 }
600 
601 static void
602 newport_attach_common(struct newport_devconfig *dc, struct gio_attach_args *ga)
603 {
604 	dc->dc_addr = ga->ga_addr;
605 
606 	dc->dc_st = ga->ga_iot;
607 	dc->dc_sh = ga->ga_ioh;
608 
609 	wsfont_init();
610 
611 	dc->dc_font = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
612 	    WSDISPLAY_FONTORDER_L2R);
613 	if (dc->dc_font < 0)
614 		panic("newport_attach_common: no suitable fonts");
615 
616 	if (wsfont_lock(dc->dc_font, &dc->dc_fontdata))
617 		panic("newport_attach_common: unable to lock font data");
618 
619 	newport_setup_hw(dc);
620 
621 	newport_get_resolution(dc);
622 
623 	newport_fill_rectangle(dc, 0, 0, dc->dc_xres, dc->dc_yres, 0);
624 }
625 
626 static void
627 newport_attach(struct device *parent, struct device *self, void *aux)
628 {
629 	struct gio_attach_args *ga = aux;
630 	struct newport_softc *sc = (void *)self;
631 	struct wsemuldisplaydev_attach_args wa;
632 
633 	if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr) {
634 		wa.console = 1;
635 		sc->sc_dc = &newport_console_dc;
636 	} else {
637 		wa.console = 0;
638 		sc->sc_dc = malloc(sizeof(struct newport_devconfig),
639 		    M_DEVBUF, M_WAITOK | M_ZERO);
640 		if (sc->sc_dc == NULL)
641 			panic("newport_attach: out of memory");
642 
643 		newport_attach_common(sc->sc_dc, ga);
644 	}
645 
646 	aprint_naive(": Display adapter\n");
647 
648 	aprint_normal(": SGI NG1 (board revision %d, cmap revision %d, xmap revision %d, vc2 revision %d), depth %d\n",
649 	    sc->sc_dc->dc_boardrev, sc->sc_dc->dc_cmaprev,
650 	    sc->sc_dc->dc_xmaprev, sc->sc_dc->dc_vc2rev, sc->sc_dc->dc_depth);
651 
652 	wa.scrdata = &newport_screenlist;
653 	wa.accessops = &newport_accessops;
654 	wa.accesscookie = sc->sc_dc;
655 
656 	config_found(&sc->sc_dev, &wa, wsemuldisplaydevprint);
657 }
658 
659 int
660 newport_cnattach(struct gio_attach_args *ga)
661 {
662 	long defattr = NEWPORT_ATTR_ENCODE(WSCOL_WHITE, WSCOL_BLACK);
663 	const struct wsscreen_descr *screen;
664 
665 	if (!newport_match(NULL, NULL, ga)) {
666 		return ENXIO;
667 	}
668 
669 	newport_attach_common(&newport_console_dc, ga);
670 
671 	if (newport_console_dc.dc_xres >= 1280 &&
672 	    newport_console_dc.dc_yres >= 1024)
673 		screen = &newport_screen_1280x1024;
674 	else
675 		screen = &newport_screen_1024x768;
676 
677 	wsdisplay_cnattach(screen, &newport_console_dc, 0, 0, defattr);
678 
679 	newport_is_console = 1;
680 
681 	return 0;
682 }
683 
684 /**** wsdisplay textops ****/
685 static void
686 newport_cursor(void *c, int on, int row, int col)
687 {
688 	struct newport_devconfig *dc = (void *)c;
689 	uint16_t control;
690 	int x_offset;
691 
692 	control = vc2_read_ireg(dc, VC2_IREG_CONTROL);
693 
694 	if (!on) {
695 		vc2_write_ireg(dc, VC2_IREG_CONTROL,
696 		    control & ~VC2_CONTROL_CURSOR_ENABLE);
697 	} else {
698 		/* Work around bug in some board revisions */
699 		if (dc->dc_boardrev < 6)
700 			x_offset = 21;
701 		else if (dc->dc_vc2rev == 0)
702 			x_offset = 29;
703 		else
704 			x_offset = 31;
705 
706 		vc2_write_ireg(dc, VC2_IREG_CURSOR_X,
707 		    col * dc->dc_fontdata->fontwidth + x_offset);
708 		vc2_write_ireg(dc, VC2_IREG_CURSOR_Y,
709 		    row * dc->dc_fontdata->fontheight + 31);
710 
711 		vc2_write_ireg(dc, VC2_IREG_CONTROL,
712 		    control | VC2_CONTROL_CURSOR_ENABLE);
713 	}
714 }
715 
716 static int
717 newport_mapchar(void *c, int ch, unsigned int *cp)
718 {
719 	struct newport_devconfig *dc = (void *)c;
720 
721 	if (dc->dc_fontdata->encoding != WSDISPLAY_FONTENC_ISO) {
722 		ch = wsfont_map_unichar(dc->dc_fontdata, ch);
723 
724 		if (ch < 0)
725 			goto fail;
726 	}
727 
728 	if (ch < dc->dc_fontdata->firstchar ||
729 	    ch >= dc->dc_fontdata->firstchar + dc->dc_fontdata->numchars)
730 		goto fail;
731 
732 	*cp = ch;
733 	return 5;
734 
735 fail:
736 	*cp = ' ';
737 	return 0;
738 }
739 
740 static void
741 newport_putchar(void *c, int row, int col, u_int ch, long attr)
742 {
743 	struct newport_devconfig *dc = (void *)c;
744 	struct wsdisplay_font *font = dc->dc_fontdata;
745 	uint8_t *bitmap = (u_int8_t *)font->data + (ch - font->firstchar) *
746 	    font->fontheight * font->stride;
747 	uint32_t pattern;
748 	int i;
749 	int x = col * font->fontwidth;
750 	int y = row * font->fontheight;
751 
752 	rex3_wait_gfifo(dc);
753 
754 	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
755 	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_STOPONX |
756 	    REX3_DRAWMODE0_ENZPATTERN | REX3_DRAWMODE0_ZPOPAQUE);
757 
758 	rex3_write(dc, REX3_REG_XYSTARTI, (x << REX3_XYSTARTI_XSHIFT) | y);
759 	rex3_write(dc, REX3_REG_XYENDI,
760 	    (x + font->fontwidth - 1) << REX3_XYENDI_XSHIFT);
761 
762 	rex3_write(dc, REX3_REG_COLORI, NEWPORT_ATTR_FG(attr));
763 	rex3_write(dc, REX3_REG_COLORBACK, NEWPORT_ATTR_BG(attr));
764 
765 	rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
766 
767 	for (i=0; i<font->fontheight; i++) {
768 		/* XXX Works only with font->fontwidth == 8 XXX */
769 		pattern = *bitmap << 24;
770 
771 		rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
772 
773 		bitmap += font->stride;
774 	}
775 }
776 
777 static void
778 newport_copycols(void *c, int row, int srccol, int dstcol, int ncols)
779 {
780 	struct newport_devconfig *dc = (void *)c;
781 	struct wsdisplay_font *font = dc->dc_fontdata;
782 
783 	newport_copy_rectangle(dc,
784 	    srccol * font->fontwidth,			/* x1 */
785 	    row * font->fontheight,			/* y1 */
786 	    (srccol + ncols + 1) * font->fontwidth - 1,	/* x2 */
787 	    (row + 1) * font->fontheight - 1,		/* y2 */
788 	    dstcol * font->fontheight,			/* dx */
789 	    row * font->fontheight);			/* dy */
790 }
791 
792 static void
793 newport_erasecols(void *c, int row, int startcol, int ncols,
794     long attr)
795 {
796 	struct newport_devconfig *dc = (void *)c;
797 	struct wsdisplay_font *font = dc->dc_fontdata;
798 
799 	newport_fill_rectangle(dc,
800 	    startcol * font->fontwidth,				/* x1 */
801 	    row * font->fontheight,				/* y1 */
802 	    (startcol + ncols + 1) * font->fontwidth - 1,	/* x2 */
803 	    (row + 1) * font->fontheight - 1,			/* y2 */
804 	    NEWPORT_ATTR_BG(attr));
805 }
806 
807 static void
808 newport_copyrows(void *c, int srcrow, int dstrow, int nrows)
809 {
810 	struct newport_devconfig *dc = (void *)c;
811 	struct wsdisplay_font *font = dc->dc_fontdata;
812 
813 	newport_copy_rectangle(dc,
814 	    0,							/* x1 */
815 	    srcrow * font->fontheight,				/* y1 */
816 	    dc->dc_xres,					/* x2 */
817 	    (srcrow + nrows + 1) * font->fontheight - 1,	/* y2 */
818 	    0,							/* dx */
819 	    dstrow * font->fontheight);				/* dy */
820 }
821 
822 static void
823 newport_eraserows(void *c, int startrow, int nrows, long attr)
824 {
825 	struct newport_devconfig *dc = (void *)c;
826 	struct wsdisplay_font *font = dc->dc_fontdata;
827 
828 	newport_fill_rectangle(dc,
829 	    0,							/* x1 */
830 	    startrow * font->fontheight,			/* y1 */
831 	    dc->dc_xres,					/* x2 */
832 	    (startrow + nrows + 1) * font->fontheight - 1,	/* y2 */
833 	    NEWPORT_ATTR_BG(attr));
834 }
835 
836 static int
837 newport_allocattr(void *c, int fg, int bg, int flags, long *attr)
838 {
839 	if (flags & WSATTR_BLINK)
840 		return EINVAL;
841 
842 	if ((flags & WSATTR_WSCOLORS) == 0) {
843 		fg = WSCOL_WHITE;
844 		bg = WSCOL_BLACK;
845 	}
846 
847 	if (flags & WSATTR_HILIT)
848 		fg += 8;
849 
850 	if (flags & WSATTR_REVERSE) {
851 		int tmp = fg;
852 		fg = bg;
853 		bg = tmp;
854 	}
855 
856 	*attr = NEWPORT_ATTR_ENCODE(fg, bg);
857 
858 	return 0;
859 }
860 
861 /**** wsdisplay accessops ****/
862 
863 static int
864 newport_ioctl(void *c, void *vs, u_long cmd, void *data, int flag,
865 	struct lwp *l)
866 {
867 	struct newport_softc *sc = c;
868 
869 #define FBINFO (*(struct wsdisplay_fbinfo*)data)
870 
871 	switch (cmd) {
872 	case WSDISPLAYIO_GINFO:
873 		FBINFO.width  = sc->sc_dc->dc_xres;
874 		FBINFO.height = sc->sc_dc->dc_yres;
875 		FBINFO.depth  = sc->sc_dc->dc_depth;
876 		FBINFO.cmsize = 1 << FBINFO.depth;
877 		return 0;
878 	case WSDISPLAYIO_GTYPE:
879 		*(u_int *)data = WSDISPLAY_TYPE_NEWPORT;
880 		return 0;
881 	}
882 	return EPASSTHROUGH;
883 }
884 
885 static paddr_t
886 newport_mmap(void *c, void *vs, off_t offset, int prot)
887 {
888 	struct newport_devconfig *dc = c;
889 
890 	if ( offset >= 0xfffff)
891 		return -1;
892 
893 	return mips_btop(dc->dc_addr + offset);
894 }
895 
896 static int
897 newport_alloc_screen(void *c, const struct wsscreen_descr *type, void **cookiep,
898     int *cursxp, int *cursyp, long *attrp)
899 {
900 	/* This won't get called for console screen and we don't support
901 	 * virtual screens */
902 
903 	return ENOMEM;
904 }
905 
906 static void
907 newport_free_screen(void *c, void *cookie)
908 {
909 	panic("newport_free_screen");
910 }
911 static int
912 newport_show_screen(void *c, void *cookie, int waitok,
913     void (*cb)(void *, int, int), void *cbarg)
914 {
915 	return 0;
916 }
917