Home | History | Annotate | Line # | Download | only in gio
newport.c revision 1.7
      1 /*	$NetBSD: newport.c,v 1.7 2006/04/12 19:38:23 jmmv 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.7 2006/04/12 19:38:23 jmmv 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 	/* newport doesn't respond with correct product id, empirically
    575 	 * both empty slots and newports seem to yield this result */
    576 	if (ga->ga_product != 0x04)
    577 		return 0;
    578 
    579 	/* Don't do the destructive probe if we're already attached */
    580 	if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr)
    581 		return 1;
    582 
    583 	/* Ugly, this probe is destructive, blame SGI... */
    584 	/* XXX Should be bus_space_peek/bus_space_poke XXX */
    585 	bus_space_write_4(ga->ga_iot, ga->ga_ioh,
    586 	    NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI, 0x12345678);
    587 	if (bus_space_read_4(ga->ga_iot, ga->ga_ioh,
    588 	      NEWPORT_REX3_OFFSET + REX3_REG_XSTART)
    589 	    != ((0x12345678 & 0xffff) << 11))
    590 		return 0;
    591 
    592 	return 1;
    593 }
    594 
    595 static void
    596 newport_attach_common(struct newport_devconfig *dc, struct gio_attach_args *ga)
    597 {
    598 	dc->dc_addr = ga->ga_addr;
    599 
    600 	dc->dc_st = ga->ga_iot;
    601 	dc->dc_sh = ga->ga_ioh;
    602 
    603 	wsfont_init();
    604 
    605 	dc->dc_font = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
    606 	    WSDISPLAY_FONTORDER_L2R);
    607 	if (dc->dc_font < 0)
    608 		panic("newport_attach_common: no suitable fonts");
    609 
    610 	if (wsfont_lock(dc->dc_font, &dc->dc_fontdata))
    611 		panic("newport_attach_common: unable to lock font data");
    612 
    613 	newport_setup_hw(dc);
    614 
    615 	newport_get_resolution(dc);
    616 
    617 	newport_fill_rectangle(dc, 0, 0, dc->dc_xres, dc->dc_yres, 0);
    618 }
    619 
    620 static void
    621 newport_attach(struct device *parent, struct device *self, void *aux)
    622 {
    623 	struct gio_attach_args *ga = aux;
    624 	struct newport_softc *sc = (void *)self;
    625 	struct wsemuldisplaydev_attach_args wa;
    626 
    627 	if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr) {
    628 		wa.console = 1;
    629 		sc->sc_dc = &newport_console_dc;
    630 	} else {
    631 		wa.console = 0;
    632 		sc->sc_dc = malloc(sizeof(struct newport_devconfig),
    633 		    M_DEVBUF, M_WAITOK | M_ZERO);
    634 		if (sc->sc_dc == NULL)
    635 			panic("newport_attach: out of memory");
    636 
    637 		newport_attach_common(sc->sc_dc, ga);
    638 	}
    639 
    640 	aprint_naive(": Display adapter\n");
    641 
    642 	aprint_normal(": SGI NG1 (board revision %d, cmap revision %d, xmap revision %d, vc2 revision %d), depth %d\n",
    643 	    sc->sc_dc->dc_boardrev, sc->sc_dc->dc_cmaprev,
    644 	    sc->sc_dc->dc_xmaprev, sc->sc_dc->dc_vc2rev, sc->sc_dc->dc_depth);
    645 
    646 	wa.scrdata = &newport_screenlist;
    647 	wa.accessops = &newport_accessops;
    648 	wa.accesscookie = sc->sc_dc;
    649 
    650 	config_found(&sc->sc_dev, &wa, wsemuldisplaydevprint);
    651 }
    652 
    653 int
    654 newport_cnattach(struct gio_attach_args *ga)
    655 {
    656 	long defattr = NEWPORT_ATTR_ENCODE(WSCOL_WHITE, WSCOL_BLACK);
    657 	const struct wsscreen_descr *screen;
    658 
    659 	if (!newport_match(NULL, NULL, ga)) {
    660 		return ENXIO;
    661 	}
    662 
    663 	newport_attach_common(&newport_console_dc, ga);
    664 
    665 	if (newport_console_dc.dc_xres >= 1280 &&
    666 	    newport_console_dc.dc_yres >= 1024)
    667 		screen = &newport_screen_1280x1024;
    668 	else
    669 		screen = &newport_screen_1024x768;
    670 
    671 	wsdisplay_cnattach(screen, &newport_console_dc, 0, 0, defattr);
    672 
    673 	newport_is_console = 1;
    674 
    675 	return 0;
    676 }
    677 
    678 /**** wsdisplay textops ****/
    679 static void
    680 newport_cursor(void *c, int on, int row, int col)
    681 {
    682 	struct newport_devconfig *dc = (void *)c;
    683 	uint16_t control;
    684 	int x_offset;
    685 
    686 	control = vc2_read_ireg(dc, VC2_IREG_CONTROL);
    687 
    688 	if (!on) {
    689 		vc2_write_ireg(dc, VC2_IREG_CONTROL,
    690 		    control & ~VC2_CONTROL_CURSOR_ENABLE);
    691 	} else {
    692 		/* Work around bug in some board revisions */
    693 		if (dc->dc_boardrev < 6)
    694 			x_offset = 21;
    695 		else if (dc->dc_vc2rev == 0)
    696 			x_offset = 29;
    697 		else
    698 			x_offset = 31;
    699 
    700 		vc2_write_ireg(dc, VC2_IREG_CURSOR_X,
    701 		    col * dc->dc_fontdata->fontwidth + x_offset);
    702 		vc2_write_ireg(dc, VC2_IREG_CURSOR_Y,
    703 		    row * dc->dc_fontdata->fontheight + 31);
    704 
    705 		vc2_write_ireg(dc, VC2_IREG_CONTROL,
    706 		    control | VC2_CONTROL_CURSOR_ENABLE);
    707 	}
    708 }
    709 
    710 static int
    711 newport_mapchar(void *c, int ch, unsigned int *cp)
    712 {
    713 	struct newport_devconfig *dc = (void *)c;
    714 
    715 	if (dc->dc_fontdata->encoding != WSDISPLAY_FONTENC_ISO) {
    716 		ch = wsfont_map_unichar(dc->dc_fontdata, ch);
    717 
    718 		if (ch < 0)
    719 			goto fail;
    720 	}
    721 
    722 	if (ch < dc->dc_fontdata->firstchar ||
    723 	    ch >= dc->dc_fontdata->firstchar + dc->dc_fontdata->numchars)
    724 		goto fail;
    725 
    726 	*cp = ch;
    727 	return 5;
    728 
    729 fail:
    730 	*cp = ' ';
    731 	return 0;
    732 }
    733 
    734 static void
    735 newport_putchar(void *c, int row, int col, u_int ch, long attr)
    736 {
    737 	struct newport_devconfig *dc = (void *)c;
    738 	struct wsdisplay_font *font = dc->dc_fontdata;
    739 	uint8_t *bitmap = (u_int8_t *)font->data + (ch - font->firstchar) *
    740 	    font->fontheight * font->stride;
    741 	uint32_t pattern;
    742 	int i;
    743 	int x = col * font->fontwidth;
    744 	int y = row * font->fontheight;
    745 
    746 	rex3_wait_gfifo(dc);
    747 
    748 	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
    749 	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_STOPONX |
    750 	    REX3_DRAWMODE0_ENZPATTERN | REX3_DRAWMODE0_ZPOPAQUE);
    751 
    752 	rex3_write(dc, REX3_REG_XYSTARTI, (x << REX3_XYSTARTI_XSHIFT) | y);
    753 	rex3_write(dc, REX3_REG_XYENDI,
    754 	    (x + font->fontwidth - 1) << REX3_XYENDI_XSHIFT);
    755 
    756 	rex3_write(dc, REX3_REG_COLORI, NEWPORT_ATTR_FG(attr));
    757 	rex3_write(dc, REX3_REG_COLORBACK, NEWPORT_ATTR_BG(attr));
    758 
    759 	rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
    760 
    761 	for (i=0; i<font->fontheight; i++) {
    762 		/* XXX Works only with font->fontwidth == 8 XXX */
    763 		pattern = *bitmap << 24;
    764 
    765 		rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
    766 
    767 		bitmap += font->stride;
    768 	}
    769 }
    770 
    771 static void
    772 newport_copycols(void *c, int row, int srccol, int dstcol, int ncols)
    773 {
    774 	struct newport_devconfig *dc = (void *)c;
    775 	struct wsdisplay_font *font = dc->dc_fontdata;
    776 
    777 	newport_copy_rectangle(dc,
    778 	    srccol * font->fontwidth,			/* x1 */
    779 	    row * font->fontheight,			/* y1 */
    780 	    (srccol + ncols + 1) * font->fontwidth - 1,	/* x2 */
    781 	    (row + 1) * font->fontheight - 1,		/* y2 */
    782 	    dstcol * font->fontheight,			/* dx */
    783 	    row * font->fontheight);			/* dy */
    784 }
    785 
    786 static void
    787 newport_erasecols(void *c, int row, int startcol, int ncols,
    788     long attr)
    789 {
    790 	struct newport_devconfig *dc = (void *)c;
    791 	struct wsdisplay_font *font = dc->dc_fontdata;
    792 
    793 	newport_fill_rectangle(dc,
    794 	    startcol * font->fontwidth,				/* x1 */
    795 	    row * font->fontheight,				/* y1 */
    796 	    (startcol + ncols + 1) * font->fontwidth - 1,	/* x2 */
    797 	    (row + 1) * font->fontheight - 1,			/* y2 */
    798 	    NEWPORT_ATTR_BG(attr));
    799 }
    800 
    801 static void
    802 newport_copyrows(void *c, int srcrow, int dstrow, int nrows)
    803 {
    804 	struct newport_devconfig *dc = (void *)c;
    805 	struct wsdisplay_font *font = dc->dc_fontdata;
    806 
    807 	newport_copy_rectangle(dc,
    808 	    0,							/* x1 */
    809 	    srcrow * font->fontheight,				/* y1 */
    810 	    dc->dc_xres,					/* x2 */
    811 	    (srcrow + nrows + 1) * font->fontheight - 1,	/* y2 */
    812 	    0,							/* dx */
    813 	    dstrow * font->fontheight);				/* dy */
    814 }
    815 
    816 static void
    817 newport_eraserows(void *c, int startrow, int nrows, long attr)
    818 {
    819 	struct newport_devconfig *dc = (void *)c;
    820 	struct wsdisplay_font *font = dc->dc_fontdata;
    821 
    822 	newport_fill_rectangle(dc,
    823 	    0,							/* x1 */
    824 	    startrow * font->fontheight,			/* y1 */
    825 	    dc->dc_xres,					/* x2 */
    826 	    (startrow + nrows + 1) * font->fontheight - 1,	/* y2 */
    827 	    NEWPORT_ATTR_BG(attr));
    828 }
    829 
    830 static int
    831 newport_allocattr(void *c, int fg, int bg, int flags, long *attr)
    832 {
    833 	if (flags & WSATTR_BLINK)
    834 		return EINVAL;
    835 
    836 	if ((flags & WSATTR_WSCOLORS) == 0) {
    837 		fg = WSCOL_WHITE;
    838 		bg = WSCOL_BLACK;
    839 	}
    840 
    841 	if (flags & WSATTR_HILIT)
    842 		fg += 8;
    843 
    844 	if (flags & WSATTR_REVERSE) {
    845 		int tmp = fg;
    846 		fg = bg;
    847 		bg = tmp;
    848 	}
    849 
    850 	*attr = NEWPORT_ATTR_ENCODE(fg, bg);
    851 
    852 	return 0;
    853 }
    854 
    855 /**** wsdisplay accessops ****/
    856 
    857 static int
    858 newport_ioctl(void *c, void *vs, u_long cmd, caddr_t data, int flag,
    859 	struct lwp *l)
    860 {
    861 	struct newport_softc *sc = c;
    862 
    863 #define FBINFO (*(struct wsdisplay_fbinfo*)data)
    864 
    865 	switch (cmd) {
    866 	case WSDISPLAYIO_GINFO:
    867 		FBINFO.width  = sc->sc_dc->dc_xres;
    868 		FBINFO.height = sc->sc_dc->dc_yres;
    869 		FBINFO.depth  = sc->sc_dc->dc_depth;
    870 		FBINFO.cmsize = 1 << FBINFO.depth;
    871 		return 0;
    872 	case WSDISPLAYIO_GTYPE:
    873 		*(u_int *)data = WSDISPLAY_TYPE_NEWPORT;
    874 		return 0;
    875 	}
    876 	return EPASSTHROUGH;
    877 }
    878 
    879 static paddr_t
    880 newport_mmap(void *c, void *vs, off_t offset, int prot)
    881 {
    882 	struct newport_devconfig *dc = c;
    883 
    884 	if ( offset >= 0xfffff)
    885 		return -1;
    886 
    887 	return mips_btop(dc->dc_addr + offset);
    888 }
    889 
    890 static int
    891 newport_alloc_screen(void *c, const struct wsscreen_descr *type, void **cookiep,
    892     int *cursxp, int *cursyp, long *attrp)
    893 {
    894 	/* This won't get called for console screen and we don't support
    895 	 * virtual screens */
    896 
    897 	return ENOMEM;
    898 }
    899 
    900 static void
    901 newport_free_screen(void *c, void *cookie)
    902 {
    903 	panic("newport_free_screen");
    904 }
    905 static int
    906 newport_show_screen(void *c, void *cookie, int waitok,
    907     void (*cb)(void *, int, int), void *cbarg)
    908 {
    909 	return 0;
    910 }
    911