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