Home | History | Annotate | Line # | Download | only in gio
      1 /*	$NetBSD: newport.c,v 1.26 2026/08/18 21:27:29 adrian Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2003 Ilpo Ruotsalainen
      5  *               2009 Michael Lorenz
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  *
     30  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: newport.c,v 1.26 2026/08/18 21:27:29 adrian Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/systm.h>
     38 #include <sys/device.h>
     39 #include <sys/kmem.h>
     40 
     41 #include <machine/sysconf.h>
     42 #include <machine/machtype.h>
     43 
     44 #include <dev/arcbios/arcbios.h>
     45 #include <dev/arcbios/arcbiosvar.h>
     46 
     47 #include <dev/wscons/wsconsio.h>
     48 #include <dev/wscons/wsdisplayvar.h>
     49 #include <dev/wsfont/wsfont.h>
     50 #include <dev/rasops/rasops.h>
     51 #include <dev/wscons/wsdisplay_vconsvar.h>
     52 
     53 #include <sgimips/gio/giovar.h>
     54 #include <sgimips/gio/newportvar.h>
     55 #include <sgimips/gio/newportreg.h>
     56 
     57 struct newport_dcb_cs_params {
     58 	int cs_width;
     59 	int cs_hold;
     60 	int cs_setup;
     61 };
     62 
     63 struct newport_monitor_entry {
     64 	const char *monitor;
     65 	int x;
     66 	int y;
     67 	int hz;
     68 	bool unknown;
     69 	int cfreq;
     70 };
     71 
     72 /* otherwise (likely PAL/NTSC modes) */
     73 static struct newport_dcb_cs_params newport_dcb_cs_wslow = { 0, 12, 12 };
     74 /* cfreq > 59MHz */
     75 static struct newport_dcb_cs_params newport_dcb_cs_slow = { 0, 5, 5 };
     76 /* cfreq > 119MHz */
     77 static struct newport_dcb_cs_params newport_dcb_cs_fast = { 0, 1, 2 };
     78 
     79 /*
     80  * This (ideally) matches what the boot firmware is configuring as monitor
     81  * parameters in the RAMDAC, VC2, etc chips.
     82  */
     83 static struct newport_monitor_entry newport_monitor_list[] = {
     84 	/* Firmware monitor IDs */
     85 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
     86 	{ "1280x1024 76Hz", 1280, 1024, 76, false, 140 },
     87 	{ "1280x1024 76Hz", 1280, 1024, 76, false, 140 },
     88 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
     89 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
     90 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
     91 	{ "1024x768 70Hz", 1024, 768, 70, false, 75 },
     92 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
     93 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
     94 	{ "1280x1024 72Hz", 1280, 1024, 72, false, 130 },
     95 	{ "1280x1024 60Hz", 1280, 1024, 60, false, 108 },
     96 	{ "1280x1024 76Hz", 1280, 1024, 76, false, 140 },
     97 	{ "1280x1024 60Hz", 1280, 1024, 60, false, 108 },
     98 	{ "1280x1024 60Hz", 1280, 1024, 60, false, 108 },
     99 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
    100 	{ "1024x768 60Hz (unknown)", 1024, 768, 60, true, 64 },
    101 };
    102 
    103 struct newport_softc {
    104 	device_t sc_dev;
    105 
    106 	struct newport_devconfig *sc_dc;
    107 
    108 };
    109 
    110 struct newport_devconfig {
    111 	bus_space_tag_t		dc_st;
    112 	bus_space_handle_t	dc_sh;
    113 	bus_addr_t		dc_addr;
    114 
    115 	struct newport_softc	*dc_sc;
    116 
    117 	int			dc_boardrev;
    118 	int			dc_vc2rev;
    119 	int			dc_cmaprev;
    120 	int			dc_xmaprev;
    121 	int			dc_rexrev;
    122 	int			dc_xres;
    123 	int			dc_yres;
    124 	int			dc_depth;
    125 	int			dc_monitor_cmap_id;
    126 	int			dc_monitor_prom_id;
    127 
    128 	int			dc_font;
    129 	struct wsscreen_descr	*dc_screen;
    130 	int			dc_mode;
    131 	struct vcons_data	dc_vd;
    132 };
    133 
    134 static int  newport_match(device_t, struct cfdata *, void *);
    135 static void newport_attach(device_t, device_t, void *);
    136 
    137 CFATTACH_DECL_NEW(newport, sizeof(struct newport_softc),
    138     newport_match, newport_attach, NULL, NULL);
    139 
    140 /* textops */
    141 static void newport_cursor(void *, int, int, int);
    142 static void newport_cursor_dummy(void *, int, int, int);
    143 static void newport_putchar(void *, int, int, u_int, long);
    144 static void newport_copycols(void *, int, int, int, int);
    145 static void newport_erasecols(void *, int, int, int, long);
    146 static void newport_copyrows(void *, int, int, int);
    147 static void newport_eraserows(void *, int, int, long);
    148 
    149 static void newport_init_screen(void *, struct vcons_screen *, int, long *);
    150 
    151 /* accessops */
    152 static int     newport_ioctl(void *, void *, u_long, void *, int,
    153     struct lwp *);
    154 static paddr_t newport_mmap(void *, void *, off_t, int);
    155 
    156 static struct wsdisplay_accessops newport_accessops = {
    157 	.ioctl		= newport_ioctl,
    158 	.mmap		= newport_mmap,
    159 };
    160 
    161 static struct wsscreen_descr newport_screen = {
    162 	.name		= "default",
    163 	.ncols		= 160,
    164 	.nrows		= 64,
    165 	.fontwidth	= 8,
    166 	.fontheight	= 16,
    167 	.capabilities	= WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_REVERSE
    168 };
    169 
    170 static const struct wsscreen_descr *_newport_screenlist[] = {
    171 	&newport_screen
    172 };
    173 
    174 static const struct wsscreen_list newport_screenlist = {
    175 	sizeof(_newport_screenlist) / sizeof(struct wsscreen_descr *),
    176 	_newport_screenlist
    177 };
    178 
    179 static struct vcons_screen newport_console_screen;
    180 static struct newport_devconfig newport_console_dc;
    181 static int newport_is_console = 0;
    182 
    183 uint8_t our_cmap[768];
    184 
    185 /*
    186  * Return the monitor ID which hopefully matches the firmware selection.
    187  *
    188  * The firmware first checks to see if it's an unknown monitor
    189  * type.  If it is, then the prom ID can override it.
    190  * If it is a detected and known monitor then that is returned.
    191  *
    192  * Note that unknown monitor IDs for the SGI Indy is
    193  * 1024x768 60Hz, but for Indigo2 is 1280x1024 60Hz.
    194  *
    195  * Note that for boardrev < 4, the firmware seems to limit
    196  * the refresh rate to 72Hz, so don't allow 1280x1024 76Hz.
    197  */
    198 static uint8_t
    199 newport_get_monitor_id(struct newport_devconfig *dc)
    200 {
    201 	uint8_t id;
    202 
    203 	id = dc->dc_monitor_cmap_id;
    204 	KASSERT((id < 16));
    205 	if (id > 15)
    206 		id = 0;
    207 
    208 	/*
    209 	 * Unknown monitors on Indigo2 are 1280x1024 60Hz,
    210 	 * on Indy is 1024x768 60Hz unless configured in PROM.
    211 	 */
    212 	if (newport_monitor_list[id].unknown == true) {
    213 		if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) {
    214 			/* Default to 1280x1024 60Hz */
    215 			id = 10;
    216 		} else if (dc->dc_monitor_prom_id != -1)
    217 			id = dc->dc_monitor_prom_id;
    218 	}
    219 
    220 	/*
    221 	 * Check board revision, bump down to 72Hz if needed.
    222 	 */
    223 	if ((dc->dc_boardrev < 4) && (newport_monitor_list[id].x == 1280)
    224 	    && (newport_monitor_list[id].hz > 72))
    225 		/* 1280x1024, 72Hz */
    226 		id = 9;
    227 
    228 	/* Cap for sanity reasons */
    229 	KASSERT((id < 16));
    230 	if (id > 15)
    231 		id = 0;
    232 
    233 	return (id);
    234 }
    235 
    236 /*
    237  * Return the string representation of the monitor ID.
    238  *
    239  * This is the monitor ID that has already been populated
    240  * via the probe routines.
    241  */
    242 static const char *
    243 newport_get_monitor_str(struct newport_devconfig *dc)
    244 {
    245 	return (newport_monitor_list[newport_get_monitor_id(dc)].monitor);
    246 }
    247 
    248 /**** Low-level hardware register groveling functions ****/
    249 static void
    250 rex3_write(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
    251 {
    252 	bus_space_write_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET + rexreg,
    253 	    val);
    254 }
    255 
    256 static void
    257 rex3_write_go(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
    258 {
    259 	rex3_write(dc, rexreg + REX3_REG_GO, val);
    260 }
    261 
    262 static uint32_t
    263 rex3_read(struct newport_devconfig *dc, bus_size_t rexreg)
    264 {
    265 	return bus_space_read_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET +
    266 	    rexreg);
    267 }
    268 
    269 /*
    270  * Wait for the graphics FIFO and for it to be empty.
    271  *
    272  * This FIFO is used for submitted graphics register writes.
    273  */
    274 static void
    275 rex3_wait_gfifo(struct newport_devconfig *dc)
    276 {
    277 	while (rex3_read(dc, REX3_REG_STATUS) &
    278 	    (REX3_STATUS_GFXBUSY | REX3_STATUS_PIPELEVEL_MASK))
    279 		;
    280 }
    281 
    282 /*
    283  * Wait for the backend FIFO and for it to be empty.
    284  *
    285  * This FIFO is used for speaking to the data backend, notably
    286  * the DCB.
    287  */
    288 static void
    289 rex3_wait_bfifo(struct newport_devconfig *dc)
    290 {
    291 	while (rex3_read(dc, REX3_REG_STATUS) &
    292 	    (REX3_STATUS_BACKBUSY | REX3_STATUS_BPIPELEVEL_MASK))
    293 		;
    294 }
    295 
    296 static void
    297 vc2_write_ireg(struct newport_devconfig *dc, uint8_t ireg, uint16_t val)
    298 {
    299 	rex3_write(dc, REX3_REG_DCBMODE,
    300 	    REX3_DCBMODE_DW_3 |
    301 	    REX3_DCBMODE_ENCRSINC |
    302 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
    303 	    (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
    304 	    REX3_DCBMODE_ENASYNCACK |
    305 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
    306 
    307 	rex3_write(dc, REX3_REG_DCBDATA0, (ireg << 24) | (val << 8));
    308 }
    309 
    310 static uint16_t
    311 vc2_read_ireg(struct newport_devconfig *dc, uint8_t ireg)
    312 {
    313 	rex3_write(dc, REX3_REG_DCBMODE,
    314 	    REX3_DCBMODE_DW_1 |
    315 	    REX3_DCBMODE_ENCRSINC |
    316 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
    317 	    (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
    318 	    REX3_DCBMODE_ENASYNCACK |
    319 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
    320 
    321 	rex3_write(dc, REX3_REG_DCBDATA0, ireg << 24);
    322 
    323 	rex3_write(dc, REX3_REG_DCBMODE,
    324 	    REX3_DCBMODE_DW_2 |
    325 	    REX3_DCBMODE_ENCRSINC |
    326 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
    327 	    (VC2_DCBCRS_IREG << REX3_DCBMODE_DCBCRS_SHIFT) |
    328 	    REX3_DCBMODE_ENASYNCACK |
    329 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
    330 
    331 	return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
    332 }
    333 
    334 static uint16_t
    335 vc2_read_ram(struct newport_devconfig *dc, uint16_t addr)
    336 {
    337 	vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);
    338 
    339 	rex3_write(dc, REX3_REG_DCBMODE,
    340 	    REX3_DCBMODE_DW_2 |
    341 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
    342 	    (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
    343 	    REX3_DCBMODE_ENASYNCACK |
    344 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
    345 
    346 	return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
    347 }
    348 
    349 #if 0
    350 static void
    351 vc2_write_ram(struct newport_devconfig *dc, uint16_t addr, uint16_t val)
    352 {
    353 	vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);
    354 
    355 	rex3_write(dc, REX3_REG_DCBMODE,
    356 	    REX3_DCBMODE_DW_2 |
    357 	    (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
    358 	    (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
    359 	    REX3_DCBMODE_ENASYNCACK |
    360 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
    361 
    362 	rex3_write(dc, REX3_REG_DCBDATA0, val << 16);
    363 }
    364 #endif
    365 
    366 /*
    367  * Read from the given XMAP chip.
    368  *
    369  * Note this must not be used to read from NEWPORT_DCBADDR_XMAP_BOTH.
    370  */
    371 static u_int32_t
    372 xmap9_read(struct newport_devconfig *dc, int chip, int crs)
    373 {
    374 
    375 	KASSERT(chip != NEWPORT_DCBADDR_XMAP_BOTH);
    376 	if (chip == NEWPORT_DCBADDR_XMAP_BOTH)
    377 		chip = NEWPORT_DCBADDR_XMAP_0;
    378 
    379 	rex3_write(dc, REX3_REG_DCBMODE,
    380 		REX3_DCBMODE_DW_1 |
    381 		(chip << REX3_DCBMODE_DCBADDR_SHIFT) |
    382 		(crs << REX3_DCBMODE_DCBCRS_SHIFT) |
    383 		(3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
    384 		(1 << REX3_DCBMODE_CSHOLD_SHIFT) |
    385 		(2 << REX3_DCBMODE_CSSETUP_SHIFT));
    386 	return (uint8_t) (rex3_read(dc, REX3_REG_DCBDATA0) >> 24);
    387 }
    388 
    389 /*
    390  * write to the given XMAP chip, or to both.
    391  */
    392 static void
    393 xmap9_write(struct newport_devconfig *dc, int chip, int crs, uint8_t val)
    394 {
    395 	rex3_write(dc, REX3_REG_DCBMODE,
    396 	    REX3_DCBMODE_DW_1 |
    397 	    (chip << REX3_DCBMODE_DCBADDR_SHIFT) |
    398 	    (crs << REX3_DCBMODE_DCBCRS_SHIFT) |
    399 	    (0 << REX3_DCBMODE_CSWIDTH_SHIFT) |
    400 	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
    401 	    (2 << REX3_DCBMODE_CSSETUP_SHIFT));
    402 
    403 	rex3_write(dc, REX3_REG_DCBDATA0, val << 24);
    404 }
    405 
    406 /*
    407  * Wait for the given XMAP9 mode FIFO to be ready.
    408  *
    409  * Since we're not trying to optimise for bursting mode writes,
    410  * just wait for /a/ FIFO entry to be avaliable.
    411  *
    412  * The XMAP9 documentation covers the gray mode encoding
    413  * of this register in case there's a future need for
    414  * bursting mode updates without individual FIFO checks.
    415  */
    416 static inline void
    417 xmap9_wait_chip(struct newport_devconfig *dc, int chip)
    418 {
    419 	while (xmap9_read(dc, chip, XMAP9_DCBCRS_FIFOAVAIL) == 0)
    420 		;
    421 }
    422 
    423 /*
    424  * Wait for the backend FIFO and then both XMAP FIFOs to become available.
    425  */
    426 static inline void
    427 xmap9_wait(struct newport_devconfig *dc)
    428 {
    429 	rex3_wait_bfifo(dc);
    430 
    431 	xmap9_wait_chip(dc, NEWPORT_DCBADDR_XMAP_0);
    432 	xmap9_wait_chip(dc, NEWPORT_DCBADDR_XMAP_1);
    433 }
    434 
    435 #if 0
    436 static uint32_t
    437 xmap9_read_mode(struct newport_devconfig *dc, int chip, uint8_t idx)
    438 {
    439 	uint32_t mode = 0, val;
    440 	int i;
    441 
    442 	xmap9_wait_chip(dc, chip);
    443 
    444 	for (i = 0; i < 4; i++) {
    445 		xmap9_write(dc, chip, XMAP9_DCBCRS_MODE_SELECT,
    446 		    (idx << 2) | i);
    447 		val = xmap9_read(dc, chip, XMAP9_DCBCRS_MODE_SETUP);
    448 		mode |= (val << (i * 8));
    449 	}
    450 	return (mode);
    451 }
    452 #endif
    453 
    454 /*
    455  * Map the pixel clock frequency to which parameters to use for XMAP9
    456  * mode writes.
    457  */
    458 static const struct newport_dcb_cs_params *
    459 newport_hw_get_mode_cs_params(int cfreq)
    460 {
    461 	if (cfreq > 119)
    462 		return &newport_dcb_cs_fast;
    463 	if (cfreq > 59)
    464 		return &newport_dcb_cs_slow;
    465 	return &newport_dcb_cs_wslow;
    466 }
    467 
    468 /*
    469  * Write out the 32 bit mode entry to both XMAP9 chips.
    470  *
    471  * This is actually a fun clock domain crossing problem - the
    472  * XMAP9 isn't signaling an ACK back to the REX3 chip, so
    473  * the CS setup, width and hold times need to be calculated
    474  * based on 33MHz GIO clock (REX3) <-> the currently configured
    475  * pixel clock (XMAP9).
    476  *
    477  * The pixel clock is set by the firmware based on the attached
    478  * monitor; it programs the BT445 RAMDAC to generate a pixelclock
    479  * that's then divided in half and sent in both phases to the
    480  * various chips doing odd/even pixel handling (which includes the
    481  * XMAP9.)
    482  *
    483  * Unfortunately we don't have the pixel clock available to us - only
    484  * the monitor resolution from the VC2 table - so eventually the
    485  * driver will need to grow a way to read the monitor sense lines and
    486  * mirror what the firmware is doing.
    487  *
    488  * Also note on SGI Indy the PROM recognises "setenv monitor" to
    489  * force a 1280x1024x60Hz monitor (setenv monitor H) and
    490  * a 1280x1024*76Hz monitor (setenv monitor S).  To correctly handle
    491  * that we will ALSO need to parse the PROM environment and make
    492  * it available here.
    493  */
    494 static void
    495 xmap9_write_mode(struct newport_devconfig *dc, uint8_t index, uint32_t mode)
    496 {
    497 	const struct newport_dcb_cs_params *cs;
    498 	uint8_t id;
    499 
    500 	/* Fetch the monitor ID and then the CS parameters to use */
    501 	id = newport_get_monitor_id(dc);
    502 	cs = newport_hw_get_mode_cs_params(newport_monitor_list[id].cfreq);
    503 
    504 	/* wait for FIFO if needed */
    505 	xmap9_wait(dc);
    506 
    507 	rex3_write(dc, REX3_REG_DCBMODE,
    508 	    REX3_DCBMODE_DW_4 |
    509 	    (NEWPORT_DCBADDR_XMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
    510 	    (XMAP9_DCBCRS_MODE_SETUP << REX3_DCBMODE_DCBCRS_SHIFT) |
    511 	    (cs->cs_width << REX3_DCBMODE_CSWIDTH_SHIFT) |
    512 	    (cs->cs_hold << REX3_DCBMODE_CSHOLD_SHIFT) |
    513 	    (cs->cs_setup << REX3_DCBMODE_CSSETUP_SHIFT)
    514 	);
    515 	rex3_write(dc, REX3_REG_DCBDATA0, (index << 24) | (mode & 0xffffff));
    516 }
    517 
    518 /**** Helper functions ****/
    519 static void
    520 newport_fill_rectangle(struct newport_devconfig *dc, int x1, int y1, int wi,
    521     int he, uint32_t color)
    522 {
    523 	int x2 = x1 + wi - 1;
    524 	int y2 = y1 + he - 1;
    525 
    526 	rex3_wait_gfifo(dc);
    527 
    528 	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
    529 	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
    530 	    REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
    531 	rex3_write(dc, REX3_REG_CLIPMODE, 0x1e00);
    532 	rex3_write(dc, REX3_REG_DRAWMODE1,
    533 	    REX3_DRAWMODE1_PLANES_RGB |
    534 	    REX3_DRAWMODE1_DD_DD8 |
    535 	    REX3_DRAWMODE1_RWPACKED |
    536 	    REX3_DRAWMODE1_HD_HD8 |
    537 	    REX3_DRAWMODE1_COMPARE_LT |
    538 	    REX3_DRAWMODE1_COMPARE_EQ |
    539 	    REX3_DRAWMODE1_COMPARE_GT |
    540 	    REX3_DRAWMODE1_RGBMODE |
    541 	    REX3_DRAWMODE1_FASTCLEAR |
    542 	    REX3_DRAWMODE1_LO_SRC);
    543 	rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
    544 	rex3_write(dc, REX3_REG_COLORVRAM, color);
    545 	rex3_write(dc, REX3_REG_XYSTARTI, (x1 << REX3_XYSTARTI_XSHIFT) | y1);
    546 
    547 	rex3_write_go(dc, REX3_REG_XYENDI, (x2 << REX3_XYENDI_XSHIFT) | y2);
    548 }
    549 
    550 static void
    551 newport_bitblt(struct newport_devconfig *dc, int xs, int ys, int xd,
    552     int yd, int wi, int he, int rop)
    553 {
    554 	int xe, ye;
    555 	uint32_t tmp;
    556 
    557 	rex3_wait_gfifo(dc);
    558 	if (yd > ys) {
    559 		/* need to copy bottom up */
    560 		ye = ys;
    561 		yd += he - 1;
    562 		ys += he - 1;
    563 	} else
    564 		ye = ys + he - 1;
    565 
    566 	if (xd > xs) {
    567 		/* need to copy right to left */
    568 		xe = xs;
    569 		xd += wi - 1;
    570 		xs += wi - 1;
    571 	} else
    572 		xe = xs + wi - 1;
    573 
    574 	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_SCR2SCR |
    575 	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
    576 	    REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
    577 	rex3_write(dc, REX3_REG_DRAWMODE1,
    578 	    REX3_DRAWMODE1_PLANES_CI |
    579 	    REX3_DRAWMODE1_DD_DD8 |
    580 	    REX3_DRAWMODE1_RWPACKED |
    581 	    REX3_DRAWMODE1_HD_HD8 |
    582 	    REX3_DRAWMODE1_COMPARE_LT |
    583 	    REX3_DRAWMODE1_COMPARE_EQ |
    584 	    REX3_DRAWMODE1_COMPARE_GT |
    585 	    ((rop << 28) & REX3_DRAWMODE1_LOGICOP_MASK));
    586 	rex3_write(dc, REX3_REG_XYSTARTI, (xs << REX3_XYSTARTI_XSHIFT) | ys);
    587 	rex3_write(dc, REX3_REG_XYENDI, (xe << REX3_XYENDI_XSHIFT) | ye);
    588 
    589 	tmp = (yd - ys) & 0xffff;
    590 	tmp |= (xd - xs) << REX3_XYMOVE_XSHIFT;
    591 
    592 	rex3_write_go(dc, REX3_REG_XYMOVE, tmp);
    593 }
    594 
    595 static void
    596 newport_cmap_setrgb(struct newport_devconfig *dc, int index, uint8_t r,
    597     uint8_t g, uint8_t b)
    598 {
    599 	rex3_wait_bfifo(dc);
    600 
    601 	rex3_write(dc, REX3_REG_DCBMODE,
    602 	    REX3_DCBMODE_DW_2 |
    603 	    REX3_DCBMODE_ENCRSINC |
    604 	    (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
    605 	    (CMAP_DCBCRS_ADDRESS_LOW << REX3_DCBMODE_DCBCRS_SHIFT) |
    606 	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
    607 	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
    608 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT) |
    609 	    REX3_DCBMODE_SWAPENDIAN);
    610 
    611 	rex3_write(dc, REX3_REG_DCBDATA0, index << 16);
    612 
    613 	rex3_write(dc, REX3_REG_DCBMODE,
    614 	    REX3_DCBMODE_DW_3 |
    615 	    (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
    616 	    (CMAP_DCBCRS_PALETTE << REX3_DCBMODE_DCBCRS_SHIFT) |
    617 	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
    618 	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
    619 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
    620 
    621 	rex3_write(dc, REX3_REG_DCBDATA0, (r << 24) + (g << 16) + (b << 8));
    622 }
    623 
    624 static void
    625 newport_get_resolution(struct newport_devconfig *dc)
    626 {
    627 	uint16_t vep,lines;
    628 	uint16_t linep,cols;
    629 	uint16_t data;
    630 
    631 	vep = vc2_read_ireg(dc, VC2_IREG_VIDEO_ENTRY);
    632 
    633 	dc->dc_xres = 0;
    634 	dc->dc_yres = 0;
    635 
    636 	for (;;) {
    637 		/* Iterate over runs in video timing table */
    638 
    639 		cols = 0;
    640 
    641 		linep = vc2_read_ram(dc, vep++);
    642 		lines = vc2_read_ram(dc, vep++);
    643 
    644 		if (lines == 0)
    645 			break;
    646 
    647 		do {
    648 			/* Iterate over state runs in line sequence table */
    649 
    650 			data = vc2_read_ram(dc, linep++);
    651 
    652 			if ((data & 0x0001) == 0)
    653 				cols += (data >> 7) & 0xfe;
    654 
    655 			if ((data & 0x0080) == 0)
    656 				data = vc2_read_ram(dc, linep++);
    657 		} while ((data & 0x8000) == 0);
    658 
    659 		if (cols != 0) {
    660 			if (cols > dc->dc_xres)
    661 				dc->dc_xres = cols;
    662 
    663 			dc->dc_yres += lines;
    664 		}
    665 	}
    666 }
    667 
    668 /*
    669  * Read from an 8 bit CMAP register.
    670  *
    671  * This must only be used on individual CMAPs (0 or 1), not both.
    672  */
    673 static uint8_t
    674 cmap_reg_read(struct newport_devconfig *dc, uint8_t id, uint8_t reg)
    675 {
    676 	KASSERT(id != NEWPORT_DCBADDR_CMAP_BOTH);
    677 	if (id == NEWPORT_DCBADDR_CMAP_BOTH)
    678 		id = NEWPORT_DCBADDR_CMAP_0;
    679 
    680 	/* Get various revisions */
    681 	rex3_write(dc, REX3_REG_DCBMODE,
    682 	    REX3_DCBMODE_DW_1 |
    683 	    (id << REX3_DCBMODE_DCBADDR_SHIFT) |
    684 	    (reg << REX3_DCBMODE_DCBCRS_SHIFT) |
    685 	    (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
    686 	    (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
    687 	    (1 << REX3_DCBMODE_CSSETUP_SHIFT));
    688 	return (uint8_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 24);
    689 }
    690 
    691 static void
    692 newport_probe_monitor(struct newport_devconfig *dc)
    693 {
    694 	const char *m;
    695 	uint8_t scratch;
    696 
    697 	/*
    698 	 * CMAP1 - the 4 monitor sense bits are on bits 7:4.
    699 	 *
    700 	 * Note that for MACH_SGI_IP22_GUINNESS (Indy), the monitor PROM
    701 	 * variable can override a 'default' monitor setting of 1024x768
    702 	 * with two others - H = 1280x1024x60Hz and S = 1280x1024x76Hz.
    703 	 * So when (eventually) doing a monitor ID lookup we'll also
    704 	 * need to handle that.
    705 	 */
    706 	scratch = cmap_reg_read(dc, NEWPORT_DCBADDR_CMAP_1,
    707 	    CMAP_DCBCRS_REVISION);
    708 	aprint_debug("%s: CMAP_1 REVISION 0x%02x\n", __func__, scratch);
    709 	dc->dc_monitor_cmap_id = (scratch >> 4) & 0x0f;
    710 	dc->dc_monitor_prom_id = -1;
    711 
    712 	/* Only check the PROM monitor on SGI Indy */
    713 	if (mach_subtype != MACH_SGI_IP22_GUINNESS)
    714 		return;
    715 
    716 	m = arcbios_GetEnvironmentVariable("monitor");
    717 	if (m == NULL)
    718 		return;
    719 	else if (m[0] == '0')
    720 		return;
    721 
    722 	/*
    723 	 * H = 1280x1024, 60Hz
    724 	 * S = 1280x1024, 76Hz
    725 	 */
    726 	if (m[0] == 'h' || m[0] == 'H')
    727 		dc->dc_monitor_prom_id = 10;
    728 	else if (m[0] == 'S')
    729 		dc->dc_monitor_prom_id = 1;
    730 }
    731 
    732 /*
    733  * Probe the hardware as handed to us by the boot firmware
    734  * before it's potentially fiddled with by the console and
    735  * X11 servers.
    736  */
    737 static void
    738 newport_probe_hw(struct newport_devconfig *dc)
    739 {
    740 	uint32_t scratch;
    741 
    742 	/* Get various revisions */
    743 
    744 	/*
    745 	 * CMAP0 - CMAP revision bits 3:0, board revision bits 6:4,
    746 	 * If boardrev > 1 then the b7 == 1 signals an 8 bit framebuffer.
    747 	 */
    748 	rex3_wait_bfifo(dc);
    749 	scratch = cmap_reg_read(dc, NEWPORT_DCBADDR_CMAP_0,
    750 	    CMAP_DCBCRS_REVISION);
    751 	aprint_debug("%s: CMAP_0 REVISION 0x%02x\n", __func__, scratch);
    752 
    753 	dc->dc_boardrev = (scratch >> 4) & 0x07;
    754 	dc->dc_cmaprev = scratch & 0x07;
    755 
    756 	rex3_wait_bfifo(dc);
    757 	dc->dc_xmaprev = xmap9_read(dc, NEWPORT_DCBADDR_XMAP_0,
    758 	    XMAP9_DCBCRS_REVISION) & 0x07;
    759 	dc->dc_depth = ( (dc->dc_boardrev > 1) && (scratch & 0x80)) ? 8 : 24;
    760 
    761 	aprint_debug("%s: XMAP_0 REVISION: 0x%08x\n", __func__,
    762 	    xmap9_read(dc, NEWPORT_DCBADDR_XMAP_0, XMAP9_DCBCRS_REVISION));
    763 
    764 	scratch = vc2_read_ireg(dc, VC2_IREG_CONFIG);
    765 	dc->dc_vc2rev = (scratch & VC2_IREG_CONFIG_REVISION) >> 5;
    766 	aprint_debug("%s: VC2_IREG_CONFIG config: 0x%04x\n", __func__, scratch);
    767 }
    768 
    769 /*
    770  * Adjust the XMAP configuration based on the earlier probed board type.
    771  *
    772  * This isn't the actual operating mode; this is instead the underlying
    773  * hardware type.
    774  */
    775 static void
    776 newport_hw_adjust_xmap_cfg(struct newport_devconfig *dc, uint8_t *dcbcfg)
    777 {
    778 
    779 	/* Configure 8 or 24 bit hardware */
    780 	if (dc->dc_depth == 8)
    781 		*dcbcfg |= XMAP9_CONFIG_8BIT_SYSTEM;
    782 	else
    783 		*dcbcfg &= ~XMAP9_CONFIG_8BIT_SYSTEM;
    784 
    785 	/* XXX TODO: we aren't using PUP, so disable it? */
    786 
    787 	/*
    788 	 * Note: we're leaving the event/odd, fast/slow pclk,
    789 	 * video option board config and colourmap alone.
    790 	 */
    791 }
    792 
    793 static void
    794 newport_setup_hw_ci_cmap(struct newport_devconfig *dc)
    795 {
    796 	int i;
    797 	uint8_t ctmp;
    798 
    799 	for (i = 0; i < 256; i++) {
    800 		ctmp = i & 0xe0;
    801 		/*
    802 		 * replicate bits so 0xe0 maps to a red value of 0xff
    803 		 * in order to make white look actually white
    804 		 */
    805 		ctmp |= (ctmp >> 3) | (ctmp >> 6);
    806 		our_cmap[i * 3] = ctmp;
    807 
    808 		ctmp = (i & 0x1c) << 3;
    809 		ctmp |= (ctmp >> 3) | (ctmp >> 6);
    810 		our_cmap[i * 3 + 1] = ctmp;
    811 
    812 		ctmp = (i & 0x03) << 6;
    813 		ctmp |= ctmp >> 2;
    814 		ctmp |= ctmp >> 4;
    815 		our_cmap[i * 3 + 2] = ctmp;
    816 
    817 		newport_cmap_setrgb(dc, i, our_cmap[i * 3],
    818 		    our_cmap[i * 3 + 1], our_cmap[i * 3 + 2]);
    819 	}
    820 }
    821 
    822 static void
    823 newport_setup_hw_rgb2_cmap(struct newport_devconfig *dc)
    824 {
    825 	int i;
    826 
    827 	for (i = 0; i < 256; i++)
    828 		newport_cmap_setrgb(dc, 0x1f00 + i, i, i, i);
    829 }
    830 
    831 /*
    832  * Setup the XMAP9 mode registers with the given mode.
    833  *
    834  * This tells the two XMAP9s (one even column, one odd column)
    835  * how to interpret the pixel data being streamed in from framebuffer
    836  * memory and what config bits to expose to the CMAP hardware and
    837  * the DAC as it's converted into final RGB signals for display.
    838  *
    839  * Each entry in the mode table is a DID (display ID) in the VC2
    840  * chip, and the VC2 chip will shift out a DID value to pair with
    841  * the framebuffer memory contents being fed into the XMAP9s.
    842  * Since we're not currently filling the VC2 DID table with values,
    843  * just program them all in here with the same configuration.
    844  */
    845 static void
    846 newport_setup_hw_xmap9_modes(struct newport_devconfig *dc,
    847     uint32_t mode_mask)
    848 {
    849 	int i;
    850 
    851 	for (i = 0; i < 32; i++) {
    852 		xmap9_write_mode(dc, i, mode_mask);
    853 	}
    854 	rex3_wait_bfifo(dc);
    855 	xmap9_write(dc, NEWPORT_DCBADDR_XMAP_BOTH,
    856 	    XMAP9_DCBCRS_MODE_SELECT, 0);
    857 }
    858 
    859 static void
    860 newport_setup_hw(struct newport_devconfig *dc, int depth)
    861 {
    862 	uint16_t __unused(curp), tmp;
    863 	uint8_t dcbcfg;
    864 
    865 	/* Setup cursor glyph */
    866 	curp = vc2_read_ireg(dc, VC2_IREG_CURSOR_ENTRY);
    867 
    868 	/* Setup VC2 to a known state */
    869 	tmp = vc2_read_ireg(dc, VC2_IREG_CONTROL) & VC2_CONTROL_INTERLACE;
    870 	vc2_write_ireg(dc, VC2_IREG_CONTROL, tmp |
    871 	    VC2_CONTROL_DISPLAY_ENABLE |
    872 	    VC2_CONTROL_VTIMING_ENABLE |
    873 	    VC2_CONTROL_DID_ENABLE |
    874 	    VC2_CONTROL_CURSORFUNC_ENABLE /*|
    875 	    VC2_CONTROL_CURSOR_ENABLE*/);
    876 
    877 	/* disable all clipping */
    878 	rex3_write(dc, REX3_REG_CLIPMODE, 0x1e00);
    879 
    880 	/* Setup XMAP9s */
    881 	rex3_wait_bfifo(dc);
    882 	xmap9_write(dc, NEWPORT_DCBADDR_XMAP_BOTH, XMAP9_DCBCRS_CURSOR_CMAP,
    883 	    0);
    884 
    885 	/*
    886 	 * Always configure the 8 bit or 24 bit configuration regardless
    887 	 * of the desired bit depth.  The XMAP9 documentation mentions this
    888 	 * does have some behaviour changes regardless of the pixel formats
    889 	 * being used.
    890 	 */
    891 	rex3_wait_bfifo(dc);
    892 	dcbcfg = xmap9_read(dc, NEWPORT_DCBADDR_XMAP_0, XMAP9_DCBCRS_CONFIG);
    893 	newport_hw_adjust_xmap_cfg(dc, &dcbcfg);
    894 	rex3_wait_bfifo(dc);
    895 	xmap9_write(dc, NEWPORT_DCBADDR_XMAP_0, XMAP9_DCBCRS_CONFIG, dcbcfg);
    896 	aprint_debug("%s: XMAP_0 config: 0x%02x\n", __func__, dcbcfg);
    897 
    898 	dcbcfg = xmap9_read(dc, NEWPORT_DCBADDR_XMAP_1, XMAP9_DCBCRS_CONFIG);
    899 	newport_hw_adjust_xmap_cfg(dc, &dcbcfg);
    900 	rex3_wait_bfifo(dc);
    901 	xmap9_write(dc, NEWPORT_DCBADDR_XMAP_1, XMAP9_DCBCRS_CONFIG, dcbcfg);
    902 	aprint_debug("%s: XMAP_1 config: 0x%02x\n", __func__, dcbcfg);
    903 
    904 	if (depth == 8) {
    905 		/*
    906 		 * Configure an 8 bit RGB colour map that uses the netbsd
    907 		 * packed RGB 332 format.  The rendering routines use these
    908 		 * values from the raster map attribute list.
    909 		 */
    910 		newport_setup_hw_xmap9_modes(dc, XMAP9_MODE_GAMMA_BYPASS |
    911 		    XMAP9_MODE_PIXSIZE_8BPP | XMAP9_MODE_PIXMODE_CI);
    912 	} else {
    913 		/*
    914 		 * Configure the hardware to use the a 24 bit RGB table at
    915 		 * RGB2 in CMAP.
    916 		 */
    917 		newport_setup_hw_xmap9_modes(dc, XMAP9_MODE_GAMMA_BYPASS |
    918 		    XMAP9_MODE_PIXSIZE_24BPP | XMAP9_MODE_PIXMODE_RGB2);
    919 	}
    920 
    921 	/* Setup REX3 */
    922 	rex3_write(dc, REX3_REG_XYWIN, (4096 << 16) | 4096);
    923 	rex3_write(dc, REX3_REG_TOPSCAN, 0x3ff); /* XXX Why? XXX */
    924 
    925 	/*
    926 	 * Setup CMAP CI table 0 for an RGB 332 packing.
    927 	 *
    928 	 * This will be used by 8 bit RGB pixel modes so we can use
    929 	 * RGB 332 and not have to teach the NetBSD console code or
    930 	 * this driver to map RGB 332 -> the Newport interlaced RGB8 format.
    931 	 */
    932 	newport_setup_hw_ci_cmap(dc);
    933 
    934 	/*
    935 	 * Write a ramp into RGB2 CMAP.
    936 	 *
    937 	 * This won't be used in 8 bit console mode as that is using
    938 	 * CI pixels, not RGB8 pixels.  For 8 bit framebuffer mode it'll
    939 	 * either use the RGB332 table programmed into CMAP CI table 0
    940 	 * or X11 will allocate private colourmaps as needed.
    941 	 */
    942 	newport_setup_hw_rgb2_cmap(dc);
    943 }
    944 
    945 /**** Attach routines ****/
    946 static int
    947 newport_match(device_t parent, struct cfdata *self, void *aux)
    948 {
    949 	struct gio_attach_args *ga = aux;
    950 
    951 	/* newport doesn't decode all addresses */
    952 	if (ga->ga_addr != 0x1f000000 && ga->ga_addr != 0x1f400000 &&
    953 	    ga->ga_addr != 0x1f800000 && ga->ga_addr != 0x1fc00000)
    954 		return 0;
    955 
    956 	/* Don't do the destructive probe if we're already attached */
    957 	if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr)
    958 		return 1;
    959 
    960 	if (platform.badaddr(
    961 	    (void *)MIPS_PHYS_TO_KSEG1(ga->ga_addr + NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI),
    962 	    sizeof(uint32_t)))
    963 		return 0;
    964 	if (platform.badaddr(
    965 	    (void *)MIPS_PHYS_TO_KSEG1(ga->ga_addr + NEWPORT_REX3_OFFSET + REX3_REG_XSTART),
    966 	    sizeof(uint32_t)))
    967 		return 0;
    968 
    969 	/* Ugly, this probe is destructive, blame SGI... */
    970 	/* XXX Should be bus_space_peek/bus_space_poke XXX */
    971 	bus_space_write_4(ga->ga_iot, ga->ga_ioh,
    972 	    NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI, 0x12345678);
    973 	if (bus_space_read_4(ga->ga_iot, ga->ga_ioh,
    974 	      NEWPORT_REX3_OFFSET + REX3_REG_XSTART)
    975 	    != ((0x12345678 & 0xffff) << 11))
    976 		return 0;
    977 
    978 	return 1;
    979 }
    980 
    981 static void
    982 newport_attach_common(struct newport_devconfig *dc, struct gio_attach_args *ga)
    983 {
    984 	dc->dc_addr = ga->ga_addr;
    985 
    986 	dc->dc_st = ga->ga_iot;
    987 	dc->dc_sh = ga->ga_ioh;
    988 
    989 	newport_probe_hw(dc);
    990 	newport_probe_monitor(dc);
    991 	newport_setup_hw(dc, 8);
    992 
    993 	newport_get_resolution(dc);
    994 
    995 	newport_fill_rectangle(dc, 0, 0, dc->dc_xres, dc->dc_yres, 0);
    996 
    997 	dc->dc_screen = &newport_screen;
    998 	dc->dc_mode = WSDISPLAYIO_MODE_EMUL;
    999 }
   1000 
   1001 static void
   1002 newport_attach(device_t parent, device_t self, void *aux)
   1003 {
   1004 	struct gio_attach_args *ga = aux;
   1005 	struct newport_softc *sc = device_private(self);
   1006 	struct wsemuldisplaydev_attach_args wa;
   1007 	unsigned long defattr;
   1008 
   1009 	sc->sc_dev = self;
   1010 	if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr) {
   1011 		wa.console = 1;
   1012 		sc->sc_dc = &newport_console_dc;
   1013 	} else {
   1014 		wa.console = 0;
   1015 		sc->sc_dc = kmem_zalloc(sizeof(struct newport_devconfig),
   1016 		    KM_SLEEP);
   1017 
   1018 		newport_attach_common(sc->sc_dc, ga);
   1019 	}
   1020 
   1021 	aprint_naive(": Display adapter\n");
   1022 
   1023 	aprint_normal(": SGI NG1 (board revision %d, cmap revision %d, "
   1024 	    "xmap revision %d, vc2 revision %d), depth %d, monitor ID %d "
   1025 	    "(%s)\n",
   1026 	    sc->sc_dc->dc_boardrev, sc->sc_dc->dc_cmaprev,
   1027 	    sc->sc_dc->dc_xmaprev, sc->sc_dc->dc_vc2rev, sc->sc_dc->dc_depth,
   1028 	    newport_get_monitor_id(sc->sc_dc),
   1029 	    newport_get_monitor_str(sc->sc_dc));
   1030 	aprint_normal("%s: 13W3 Monitor ID %d, PROM ID %d, determined "
   1031 	    "monitor ID %d (%s)\n",
   1032 	    device_xname(self),
   1033 	    sc->sc_dc->dc_monitor_cmap_id,
   1034 	    sc->sc_dc->dc_monitor_prom_id,
   1035 	    newport_get_monitor_id(sc->sc_dc),
   1036 	    newport_get_monitor_str(sc->sc_dc));
   1037 
   1038 	vcons_init(&sc->sc_dc->dc_vd, sc->sc_dc, sc->sc_dc->dc_screen,
   1039 	    &newport_accessops);
   1040 	sc->sc_dc->dc_vd.init_screen = newport_init_screen;
   1041 	if (newport_is_console) {
   1042 		newport_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
   1043 		vcons_init_screen(&sc->sc_dc->dc_vd, &newport_console_screen,
   1044 		    1, &defattr);
   1045 		sc->sc_dc->dc_screen->textops =
   1046 		    &newport_console_screen.scr_ri.ri_ops;
   1047 		vcons_replay_msgbuf(&newport_console_screen);
   1048 	}
   1049 	wa.scrdata = &newport_screenlist;
   1050 	wa.accessops = &newport_accessops;
   1051 	wa.accesscookie = &sc->sc_dc->dc_vd;
   1052 
   1053 	config_found(sc->sc_dev, &wa, wsemuldisplaydevprint, CFARGS_NONE);
   1054 }
   1055 
   1056 int
   1057 newport_cnattach(struct gio_attach_args *ga)
   1058 {
   1059 	struct rasops_info *ri = &newport_console_screen.scr_ri;
   1060 	long defattr = 0x000f0000;
   1061 
   1062 	if (!newport_match(NULL, NULL, ga)) {
   1063 		return ENXIO;
   1064 	}
   1065 
   1066 	newport_attach_common(&newport_console_dc, ga);
   1067 
   1068 	ri->ri_hw = &newport_console_screen;
   1069 	ri->ri_depth = newport_console_dc.dc_depth;
   1070 	ri->ri_width = newport_console_dc.dc_xres;
   1071 	ri->ri_height = newport_console_dc.dc_yres;
   1072 	/*
   1073 	 * rasops_init() requires ri_stride to be a multiple of 4.
   1074 	 * This isn't guaranteed from the VC2 timing tables.
   1075 	 * Newport however has a hard-coded stride and we are
   1076 	 * interacting with it via blits so this doesn't really matter.
   1077 	 */
   1078 	ri->ri_stride = roundup(newport_console_dc.dc_xres, 4);
   1079 	ri->ri_flg = RI_CENTER | RI_NO_AUTO | RI_FULLCLEAR | RI_8BIT_IS_RGB;
   1080 	rasops_init(ri, 0, 0);
   1081 	ri->ri_caps = WSSCREEN_WSCOLORS;
   1082 	rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
   1083 	    ri->ri_width / ri->ri_font->fontwidth);
   1084 	ri->ri_ops.copyrows  = newport_copyrows;
   1085 	ri->ri_ops.eraserows = newport_eraserows;
   1086 	ri->ri_ops.copycols  = newport_copycols;
   1087 	ri->ri_ops.erasecols = newport_erasecols;
   1088 	ri->ri_ops.cursor    = newport_cursor_dummy;
   1089 	ri->ri_ops.putchar   = newport_putchar;
   1090 	newport_screen.textops = &ri->ri_ops;
   1091 	newport_screen.ncols = ri->ri_cols;
   1092 	newport_screen.nrows = ri->ri_rows;
   1093 	newport_console_screen.scr_cookie = &newport_console_dc;
   1094 
   1095 	wsdisplay_cnattach(&newport_screen, ri, 0, 0, defattr);
   1096 	newport_is_console = 1;
   1097 
   1098 	return 0;
   1099 }
   1100 
   1101 static void
   1102 newport_init_screen(void *cookie, struct vcons_screen *scr,
   1103     int existing, long *defattr)
   1104 {
   1105 	struct newport_devconfig *dc = cookie;
   1106 	struct rasops_info *ri = &scr->scr_ri;
   1107 
   1108 	ri->ri_depth = 8;
   1109 	ri->ri_width = dc->dc_xres;
   1110 	ri->ri_height = dc->dc_yres;
   1111 	/* see previous comment around rasops_init() in the console init */
   1112 	ri->ri_stride = roundup(dc->dc_xres, 4);
   1113 	ri->ri_flg = RI_CENTER | RI_FULLCLEAR | RI_8BIT_IS_RGB;
   1114 
   1115 	rasops_init(ri, 0, 0);
   1116 	ri->ri_caps = WSSCREEN_WSCOLORS;
   1117 
   1118 	rasops_reconfig(ri, dc->dc_yres / ri->ri_font->fontheight,
   1119 		    dc->dc_xres / ri->ri_font->fontwidth);
   1120 
   1121 	ri->ri_hw = scr;
   1122 	ri->ri_ops.copyrows  = newport_copyrows;
   1123 	ri->ri_ops.eraserows = newport_eraserows;
   1124 	ri->ri_ops.copycols  = newport_copycols;
   1125 	ri->ri_ops.erasecols = newport_erasecols;
   1126 	ri->ri_ops.cursor    = newport_cursor;
   1127 	ri->ri_ops.putchar   = newport_putchar;
   1128 }
   1129 
   1130 /**** wsdisplay textops ****/
   1131 static void
   1132 newport_cursor_dummy(void *c, int on, int row, int col)
   1133 {
   1134 }
   1135 
   1136 static void
   1137 newport_cursor(void *c, int on, int row, int col)
   1138 {
   1139 	struct rasops_info *ri = c;
   1140 	struct vcons_screen *scr = ri->ri_hw;
   1141 	struct newport_devconfig *dc = scr->scr_cookie;
   1142 	int x, y, wi,he;
   1143 
   1144 	wi = ri->ri_font->fontwidth;
   1145 	he = ri->ri_font->fontheight;
   1146 
   1147 	if (ri->ri_flg & RI_CURSOR) {
   1148 		x = ri->ri_ccol * wi + ri->ri_xorigin;
   1149 		y = ri->ri_crow * he + ri->ri_yorigin;
   1150 		newport_bitblt(dc, x, y, x, y, wi, he, 12);
   1151 		ri->ri_flg &= ~RI_CURSOR;
   1152 	}
   1153 
   1154 	ri->ri_crow = row;
   1155 	ri->ri_ccol = col;
   1156 
   1157 	if (on)
   1158 	{
   1159 		x = ri->ri_ccol * wi + ri->ri_xorigin;
   1160 		y = ri->ri_crow * he + ri->ri_yorigin;
   1161 		newport_bitblt(dc, x, y, x, y, wi, he, 12);
   1162 		ri->ri_flg |= RI_CURSOR;
   1163 	}
   1164 }
   1165 
   1166 static void
   1167 newport_putchar(void *c, int row, int col, u_int ch, long attr)
   1168 {
   1169 	struct rasops_info *ri = c;
   1170 	struct vcons_screen *scr = ri->ri_hw;
   1171 	struct newport_devconfig *dc = scr->scr_cookie;
   1172 	struct wsdisplay_font *font = PICK_FONT(ri, ch);
   1173 	uint8_t *bitmap = (u_int8_t *)font->data + (ch - font->firstchar) *
   1174 	    font->fontheight * font->stride;
   1175 	uint32_t pattern;
   1176 	int i;
   1177 	int x = col * font->fontwidth + ri->ri_xorigin;
   1178 	int y = row * font->fontheight + ri->ri_yorigin;
   1179 
   1180 	rex3_wait_gfifo(dc);
   1181 
   1182 	rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
   1183 	    REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_STOPONX |
   1184 	    REX3_DRAWMODE0_ENZPATTERN | REX3_DRAWMODE0_ZPOPAQUE);
   1185 
   1186 	rex3_write(dc, REX3_REG_DRAWMODE1,
   1187 	    REX3_DRAWMODE1_PLANES_CI |
   1188 	    REX3_DRAWMODE1_DD_DD8 |
   1189 	    REX3_DRAWMODE1_RWPACKED |
   1190 	    REX3_DRAWMODE1_HD_HD8 |
   1191 	    REX3_DRAWMODE1_COMPARE_LT |
   1192 	    REX3_DRAWMODE1_COMPARE_EQ |
   1193 	    REX3_DRAWMODE1_COMPARE_GT |
   1194 	    /*REX3_DRAWMODE1_RGBMODE |*/
   1195 	    REX3_DRAWMODE1_LO_SRC);
   1196 
   1197 	rex3_write(dc, REX3_REG_XYSTARTI, (x << REX3_XYSTARTI_XSHIFT) | y);
   1198 	rex3_write(dc, REX3_REG_XYENDI,
   1199 	    (x + font->fontwidth - 1) << REX3_XYENDI_XSHIFT);
   1200 
   1201 	rex3_write(dc, REX3_REG_COLORI, ri->ri_devcmap[(attr >> 24) & 0xf] & 0xff);
   1202 	rex3_write(dc, REX3_REG_COLORBACK, ri->ri_devcmap[(attr >> 16) & 0xf] & 0xff);
   1203 
   1204 	rex3_write(dc, REX3_REG_WRMASK, 0xff);
   1205 
   1206 	if (font->stride == 1) {
   1207 		for (i = 0; i < font->fontheight; i++) {
   1208 			pattern = *bitmap << 24;
   1209 
   1210 			rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
   1211 
   1212 			bitmap++;
   1213 		}
   1214 	} else {
   1215 		uint16_t *bitmap16 = (uint16_t *)bitmap;
   1216 		for (i = 0; i < font->fontheight; i++) {
   1217 			pattern = *bitmap16 << 16;
   1218 
   1219 			rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
   1220 
   1221 			bitmap16++;
   1222 		}
   1223 
   1224 	}
   1225 	rex3_wait_gfifo(dc);
   1226 }
   1227 
   1228 static void
   1229 newport_copycols(void *c, int row, int srccol, int dstcol, int ncols)
   1230 {
   1231 	struct rasops_info *ri = c;
   1232 	struct vcons_screen *scr = ri->ri_hw;
   1233 	struct newport_devconfig *dc = scr->scr_cookie;
   1234 	int32_t xs, xd, y, width, height;
   1235 
   1236 	xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol;
   1237 	xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol;
   1238 	y = ri->ri_yorigin + ri->ri_font->fontheight * row;
   1239 	width = ri->ri_font->fontwidth * ncols;
   1240 	height = ri->ri_font->fontheight;
   1241 	newport_bitblt(dc, xs, y, xd, y, width, height, 3);
   1242 }
   1243 
   1244 static void
   1245 newport_erasecols(void *c, int row, int startcol, int ncols,
   1246     long attr)
   1247 {
   1248 	struct rasops_info *ri = c;
   1249 	struct vcons_screen *scr = ri->ri_hw;
   1250 	struct newport_devconfig *dc = scr->scr_cookie;
   1251 	struct wsdisplay_font *font = ri->ri_font;
   1252 
   1253 	newport_fill_rectangle(dc,
   1254 	    startcol * font->fontwidth + ri->ri_xorigin,	/* x1 */
   1255 	    row * font->fontheight + ri->ri_yorigin,		/* y1 */
   1256 	    ncols * font->fontwidth,				/* wi */
   1257 	    font->fontheight,					/* he */
   1258 	    ri->ri_devcmap[(attr >> 16) & 0xf]);
   1259 }
   1260 
   1261 static void
   1262 newport_copyrows(void *c, int srcrow, int dstrow, int nrows)
   1263 {
   1264 	struct rasops_info *ri = c;
   1265 	struct vcons_screen *scr = ri->ri_hw;
   1266 	struct newport_devconfig *dc = scr->scr_cookie;
   1267 	int32_t x, ys, yd, width, height;
   1268 
   1269 	x = ri->ri_xorigin;
   1270 	ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow;
   1271 	yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow;
   1272 	width = ri->ri_emuwidth;
   1273 	height = ri->ri_font->fontheight * nrows;
   1274 
   1275 	newport_bitblt(dc, x, ys, x, yd, width, height, 3);
   1276 }
   1277 
   1278 static void
   1279 newport_eraserows(void *c, int startrow, int nrows, long attr)
   1280 {
   1281 	struct rasops_info *ri = c;
   1282 	struct vcons_screen *scr = ri->ri_hw;
   1283 	struct newport_devconfig *dc = scr->scr_cookie;
   1284 	struct wsdisplay_font *font = ri->ri_font;
   1285 
   1286 	if (startrow == 0 && nrows == ri->ri_rows) {
   1287 		newport_fill_rectangle(dc,
   1288 		    0,							/* x1 */
   1289 		    0,							/* y1 */
   1290 		    dc->dc_xres,					/* wi */
   1291 		    dc->dc_yres,					/* he */
   1292 		    ri->ri_devcmap[(attr >> 16) & 0xf]);
   1293 	} else {
   1294 		newport_fill_rectangle(dc,
   1295 		    0,							/* x1 */
   1296 		    startrow * font->fontheight + ri->ri_yorigin,	/* y1 */
   1297 		    dc->dc_xres,					/* wi */
   1298 		    nrows * font->fontheight,				/* he */
   1299 		    ri->ri_devcmap[(attr >> 16) & 0xf]);
   1300 	}
   1301 }
   1302 
   1303 /**** wsdisplay accessops ****/
   1304 
   1305 static int
   1306 newport_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
   1307 	struct lwp *l)
   1308 {
   1309 	struct vcons_data *vd;
   1310 	struct newport_devconfig *dc;
   1311 	struct vcons_screen *__unused(ms);
   1312 	int nmode;
   1313 
   1314 	vd = (struct vcons_data *)v;
   1315 	dc = (struct newport_devconfig *)vd->cookie;
   1316 	ms = (struct vcons_screen *)vd->active;
   1317 
   1318 #define FBINFO (*(struct wsdisplay_fbinfo*)data)
   1319 
   1320 	switch (cmd) {
   1321 	case WSDISPLAYIO_GINFO:
   1322 		FBINFO.width  = dc->dc_xres;
   1323 		FBINFO.height = dc->dc_yres;
   1324 		FBINFO.depth  = dc->dc_depth;
   1325 		FBINFO.cmsize = 256;
   1326 		return 0;
   1327 	case WSDISPLAYIO_GTYPE:
   1328 		*(u_int *)data = WSDISPLAY_TYPE_NEWPORT;
   1329 		return 0;
   1330 	case WSDISPLAYIO_SMODE:
   1331 		nmode = *(int *)data;
   1332 		if (nmode != dc->dc_mode) {
   1333 			dc->dc_mode = nmode;
   1334 			if (nmode == WSDISPLAYIO_MODE_EMUL) {
   1335 				rex3_wait_gfifo(dc);
   1336 				newport_setup_hw(dc, 8);
   1337 				vcons_redraw_screen(vd->active);
   1338 			} else {
   1339 				rex3_wait_gfifo(dc);
   1340 				newport_setup_hw(dc, dc->dc_depth);
   1341 			}
   1342 		}
   1343 		return 0;
   1344 	}
   1345 	return EPASSTHROUGH;
   1346 }
   1347 
   1348 static paddr_t
   1349 newport_mmap(void *v, void *vs, off_t offset, int prot)
   1350 {
   1351 	struct vcons_data *vd;
   1352 	struct newport_devconfig *dc;
   1353 
   1354 	vd = (struct vcons_data *)v;
   1355 	dc = (struct newport_devconfig *)vd->cookie;
   1356 
   1357 	if ( offset >= 0xfffff)
   1358 		return -1;
   1359 
   1360 	return bus_space_mmap(dc->dc_st, dc->dc_addr, offset, prot, 0);
   1361 }
   1362