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