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