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