Home | History | Annotate | Line # | Download | only in gio
newport.c revision 1.9
      1 /*	$NetBSD: newport.c,v 1.9 2006/12/29 05:26:30 rumble 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.9 2006/12/29 05:26:30 rumble 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, caddr_t, 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, caddr_t 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