xref: /netbsd-src/sys/dev/ic/igsfb.c (revision de1dfb1250df962f1ff3a011772cf58e605aed11)
1 /*	$NetBSD: igsfb.c,v 1.17 2003/11/13 03:09:29 chs Exp $ */
2 
3 /*
4  * Copyright (c) 2002, 2003 Valeriy E. Ushakov
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 
30 /*
31  * Integraphics Systems IGA 168x and CyberPro series.
32  */
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: igsfb.c,v 1.17 2003/11/13 03:09:29 chs Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/ioctl.h>
42 #include <sys/buf.h>
43 #include <uvm/uvm_extern.h>
44 
45 #include <machine/bus.h>
46 
47 #include <dev/wscons/wsdisplayvar.h>
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wsfont/wsfont.h>
50 #include <dev/rasops/rasops.h>
51 
52 #include <dev/ic/igsfbreg.h>
53 #include <dev/ic/igsfbvar.h>
54 
55 
56 struct igsfb_devconfig igsfb_console_dc;
57 
58 /*
59  * wsscreen
60  */
61 
62 /* filled from rasops_info in igsfb_common_init */
63 static struct wsscreen_descr igsfb_stdscreen = {
64 	"std",			/* name */
65 	0, 0,			/* ncols, nrows */
66 	NULL,			/* textops */
67 	0, 0,			/* fontwidth, fontheight */
68 	0			/* capabilities */
69 };
70 
71 static const struct wsscreen_descr *_igsfb_scrlist[] = {
72 	&igsfb_stdscreen,
73 };
74 
75 static const struct wsscreen_list igsfb_screenlist = {
76 	sizeof(_igsfb_scrlist) / sizeof(struct wsscreen_descr *),
77 	_igsfb_scrlist
78 };
79 
80 
81 /*
82  * wsdisplay_accessops
83  */
84 
85 static int	igsfb_ioctl(void *, u_long, caddr_t, int, struct proc *);
86 static paddr_t	igsfb_mmap(void *, off_t, int);
87 
88 static int	igsfb_alloc_screen(void *, const struct wsscreen_descr *,
89 				   void **, int *, int *, long *);
90 static void	igsfb_free_screen(void *, void *);
91 static int	igsfb_show_screen(void *, void *, int,
92 				  void (*) (void *, int, int), void *);
93 
94 static const struct wsdisplay_accessops igsfb_accessops = {
95 	igsfb_ioctl,
96 	igsfb_mmap,
97 	igsfb_alloc_screen,
98 	igsfb_free_screen,
99 	igsfb_show_screen,
100 	NULL,			/* load_font */
101 	NULL,			/* pollc */
102 	NULL,			/* getwschar */
103 	NULL			/* putwschar */
104 };
105 
106 
107 /*
108  * acceleration
109  */
110 static int	igsfb_make_text_cursor(struct igsfb_devconfig *);
111 static void	igsfb_accel_cursor(void *, int, int, int);
112 
113 static int	igsfb_accel_wait(struct igsfb_devconfig *);
114 static void	igsfb_accel_fill(struct igsfb_devconfig *,
115 				 u_int32_t, u_int32_t, u_int16_t, u_int16_t);
116 static void	igsfb_accel_copy(struct igsfb_devconfig *,
117 				 u_int32_t, u_int32_t, u_int16_t, u_int16_t);
118 
119 static void	igsfb_accel_copycols(void *, int, int, int, int);
120 static void	igsfb_accel_erasecols(void *, int, int, int, long);
121 static void	igsfb_accel_copyrows(void *, int, int, int);
122 static void	igsfb_accel_eraserows(void *, int, int, long);
123 static void	igsfb_accel_putchar(void *, int, int, u_int, long);
124 
125 
126 /*
127  * internal functions
128  */
129 static int	igsfb_init_video(struct igsfb_devconfig *);
130 static void	igsfb_init_cmap(struct igsfb_devconfig *);
131 static u_int16_t igsfb_spread_bits_8(u_int8_t);
132 static void	igsfb_init_bit_table(struct igsfb_devconfig *);
133 static void	igsfb_init_wsdisplay(struct igsfb_devconfig *);
134 
135 static void	igsfb_blank_screen(struct igsfb_devconfig *, int);
136 static int	igsfb_get_cmap(struct igsfb_devconfig *,
137 			       struct wsdisplay_cmap *);
138 static int	igsfb_set_cmap(struct igsfb_devconfig *,
139 			       const struct wsdisplay_cmap *);
140 static void	igsfb_update_cmap(struct igsfb_devconfig *, u_int, u_int);
141 static void	igsfb_set_curpos(struct igsfb_devconfig *,
142 				 const struct wsdisplay_curpos *);
143 static void	igsfb_update_curpos(struct igsfb_devconfig *);
144 static int	igsfb_get_cursor(struct igsfb_devconfig *,
145 				 struct wsdisplay_cursor *);
146 static int	igsfb_set_cursor(struct igsfb_devconfig *,
147 				 const struct wsdisplay_cursor *);
148 static void	igsfb_update_cursor(struct igsfb_devconfig *, u_int);
149 static void	igsfb_convert_cursor_data(struct igsfb_devconfig *,
150 					  u_int, u_int);
151 
152 
153 int
154 igsfb_cnattach_subr(dc)
155 	struct igsfb_devconfig *dc;
156 {
157 	struct rasops_info *ri;
158 	long defattr;
159 
160 	KASSERT(dc == &igsfb_console_dc);
161 
162 	igsfb_init_video(dc);
163 	igsfb_init_wsdisplay(dc);
164 
165 	dc->dc_nscreens = 1;
166 
167 	ri = &dc->dc_ri;
168 	(*ri->ri_ops.allocattr)(ri,
169 				WSCOL_BLACK, /* fg */
170 				WSCOL_BLACK, /* bg */
171 				0,           /* wsattrs */
172 				&defattr);
173 
174 	wsdisplay_cnattach(&igsfb_stdscreen,
175 			   ri,   /* emulcookie */
176 			   0, 0, /* cursor position */
177 			   defattr);
178 	return (0);
179 }
180 
181 
182 /*
183  * Finish off the attach.  Bus specific attach method should have
184  * enabled io and memory accesses and mapped io (and cop?) registers.
185  */
186 void
187 igsfb_attach_subr(sc, isconsole)
188 	struct igsfb_softc *sc;
189 	int isconsole;
190 {
191 	struct igsfb_devconfig *dc = sc->sc_dc;
192 	struct wsemuldisplaydev_attach_args waa;
193 
194 	KASSERT(dc != NULL);
195 
196 	if (!isconsole) {
197 		igsfb_init_video(dc);
198 		igsfb_init_wsdisplay(dc);
199 	}
200 
201 	printf("%s: %dMB, %s%dx%d, %dbpp\n",
202 	       sc->sc_dev.dv_xname,
203 	       (u_int32_t)(dc->dc_vmemsz >> 20),
204 	       (dc->dc_hwflags & IGSFB_HW_BSWAP)
205 		   ? (dc->dc_hwflags & IGSFB_HW_BE_SELECT)
206 		       ? "hardware bswap, " : "software bswap, "
207 		   : "",
208 	       dc->dc_width, dc->dc_height, dc->dc_depth);
209 
210 	/* attach wsdisplay */
211 	waa.console = isconsole;
212 	waa.scrdata = &igsfb_screenlist;
213 	waa.accessops = &igsfb_accessops;
214 	waa.accesscookie = dc;
215 
216 	config_found(&sc->sc_dev, &waa, wsemuldisplaydevprint);
217 }
218 
219 
220 static int
221 igsfb_init_video(dc)
222 	struct igsfb_devconfig *dc;
223 {
224 	bus_space_handle_t tmph;
225 	u_int8_t *p;
226 	int need_bswap;
227 	bus_addr_t fbaddr, craddr;
228 	off_t croffset;
229 	u_int8_t busctl, curctl;
230 
231 	/* Total amount of video memory. */
232 	busctl = igs_ext_read(dc->dc_iot, dc->dc_ioh, IGS_EXT_BUS_CTL);
233 	if (busctl & 0x2)
234 		dc->dc_vmemsz = 4;
235 	else if (busctl & 0x1)
236 		dc->dc_vmemsz = 2;
237 	else
238 		dc->dc_vmemsz = 1;
239 	dc->dc_vmemsz <<= 20;	/* megabytes -> bytes */
240 
241 	/*
242 	 * Check for endianness mismatch by writing a word at the end of
243 	 * the video memory (off-screen) and reading it back byte-by-byte.
244 	 */
245 	if (bus_space_map(dc->dc_memt,
246 			  dc->dc_memaddr + dc->dc_vmemsz - sizeof(u_int32_t),
247 			  sizeof(u_int32_t),
248 			  dc->dc_memflags | BUS_SPACE_MAP_LINEAR,
249 			  &tmph) != 0)
250 	{
251 		printf("unable to map video memory for endianness test\n");
252 		return (1);
253 	}
254 
255 	p = bus_space_vaddr(dc->dc_memt, tmph);
256 #if BYTE_ORDER == BIG_ENDIAN
257 	*((u_int32_t *)p) = 0x12345678;
258 #else
259 	*((u_int32_t *)p) = 0x78563412;
260 #endif
261 	if (p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78)
262 		need_bswap = 0;
263 	else
264 		need_bswap = 1;
265 
266 	bus_space_unmap(dc->dc_memt, tmph, sizeof(u_int32_t));
267 
268 	/*
269 	 * On CyberPro we can use magic bswap bit in linear address.
270 	 */
271 	fbaddr = dc->dc_memaddr;
272 	if (need_bswap) {
273 		dc->dc_hwflags |= IGSFB_HW_BSWAP;
274 		if (dc->dc_id >= 0x2000) {
275 			dc->dc_hwflags |= IGSFB_HW_BE_SELECT;
276 			fbaddr |= IGS_MEM_BE_SELECT;
277 		}
278 	}
279 
280 	/*
281 	 * XXX: TODO: make it possible to select the desired video mode.
282 	 * For now - hardcode to 1024x768/8bpp.  This is what Krups OFW uses.
283 	 */
284 	igsfb_hw_setup(dc);
285 	delay(10000);		/* XXX: uwe */
286 
287 	dc->dc_width = 1024;
288 	dc->dc_height = 768;
289 	dc->dc_depth = 8;
290 
291 	/*
292 	 * Don't map in all N megs, just the amount we need for the wsscreen.
293 	 */
294 	dc->dc_fbsz = dc->dc_width * dc->dc_height; /* XXX: 8bpp specific */
295 	if (bus_space_map(dc->dc_memt, fbaddr, dc->dc_fbsz,
296 			  dc->dc_memflags | BUS_SPACE_MAP_LINEAR,
297 			  &dc->dc_fbh) != 0)
298 	{
299 		bus_space_unmap(dc->dc_iot, dc->dc_ioh, IGS_REG_SIZE);
300 		printf("unable to map framebuffer\n");
301 		return (1);
302 	}
303 
304 	igsfb_init_cmap(dc);
305 
306 	/*
307 	 * 1KB for cursor sprite data at the very end of the video memory.
308 	 */
309 	croffset = dc->dc_vmemsz - IGS_CURSOR_DATA_SIZE;
310 	craddr = fbaddr + croffset;
311 	if (bus_space_map(dc->dc_memt, craddr, IGS_CURSOR_DATA_SIZE,
312 			  dc->dc_memflags | BUS_SPACE_MAP_LINEAR,
313 			  &dc->dc_crh) != 0)
314 	{
315 		bus_space_unmap(dc->dc_iot, dc->dc_ioh, IGS_REG_SIZE);
316 		bus_space_unmap(dc->dc_memt, dc->dc_fbh, dc->dc_fbsz);
317 		printf("unable to map cursor sprite region\n");
318 		return (1);
319 	}
320 
321 	/*
322 	 * Tell the device where cursor sprite data are located in the
323 	 * linear space (it takes data offset in 1KB units).
324 	 */
325 	croffset >>= 10;	/* bytes -> kilobytes */
326 	igs_ext_write(dc->dc_iot, dc->dc_ioh,
327 		      IGS_EXT_SPRITE_DATA_LO, croffset & 0xff);
328 	igs_ext_write(dc->dc_iot, dc->dc_ioh,
329 		      IGS_EXT_SPRITE_DATA_HI, (croffset >> 8) & 0xf);
330 
331 	/* init the bit expansion table for cursor sprite data conversion */
332 	igsfb_init_bit_table(dc);
333 
334 	/* XXX: fill dc_cursor and use igsfb_update_cursor() instead? */
335 	memset(&dc->dc_cursor, 0, sizeof(struct igs_hwcursor));
336 	memset(bus_space_vaddr(dc->dc_memt, dc->dc_crh),
337 	       /* transparent */ 0xaa, IGS_CURSOR_DATA_SIZE);
338 
339 	curctl = igs_ext_read(dc->dc_iot, dc->dc_ioh, IGS_EXT_SPRITE_CTL);
340 	curctl |= IGS_EXT_SPRITE_64x64;
341 	curctl &= ~IGS_EXT_SPRITE_VISIBLE;
342 	igs_ext_write(dc->dc_iot, dc->dc_ioh, IGS_EXT_SPRITE_CTL, curctl);
343 	dc->dc_curenb = 0;
344 
345 	/*
346 	 * Map abd init graphic coprocessor for accelerated rasops.
347 	 */
348 	if (dc->dc_id >= 0x2000) { /* XXX */
349 		if (bus_space_map(dc->dc_iot,
350 				  dc->dc_iobase + IGS_COP_BASE_B, IGS_COP_SIZE,
351 				  dc->dc_ioflags,
352 				  &dc->dc_coph) != 0)
353 		{
354 			printf("unable to map COP registers\n");
355 			return (1);
356 		}
357 
358 		/* XXX: hardcoded 8bpp */
359 		bus_space_write_2(dc->dc_iot, dc->dc_coph,
360 				  IGS_COP_SRC_MAP_WIDTH_REG,
361 				  dc->dc_width - 1);
362 		bus_space_write_2(dc->dc_iot, dc->dc_coph,
363 				  IGS_COP_DST_MAP_WIDTH_REG,
364 				  dc->dc_width - 1);
365 
366 		bus_space_write_1(dc->dc_iot, dc->dc_coph,
367 				  IGS_COP_MAP_FMT_REG,
368 				  IGS_COP_MAP_8BPP);
369 	}
370 
371 	/* make sure screen is not blanked */
372 	dc->dc_blanked = 0;
373 	igsfb_blank_screen(dc, dc->dc_blanked);
374 
375 	return (0);
376 }
377 
378 
379 static void
380 igsfb_init_cmap(dc)
381 	struct igsfb_devconfig *dc;
382 {
383 	bus_space_tag_t iot = dc->dc_iot;
384 	bus_space_handle_t ioh = dc->dc_ioh;
385 	const u_int8_t *p;
386 	int i;
387 
388 	p = rasops_cmap;	/* "ANSI" color map */
389 
390 	/* init software copy */
391 	for (i = 0; i < IGS_CMAP_SIZE; ++i, p += 3) {
392 		dc->dc_cmap.r[i] = p[0];
393 		dc->dc_cmap.g[i] = p[1];
394 		dc->dc_cmap.b[i] = p[2];
395 	}
396 
397 	/* propagate to the device */
398 	igsfb_update_cmap(dc, 0, IGS_CMAP_SIZE);
399 
400 	/* set overscan color (XXX: use defattr's background?) */
401 	igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_RED,   0);
402 	igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_GREEN, 0);
403 	igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_BLUE,  0);
404 }
405 
406 
407 static void
408 igsfb_init_wsdisplay(dc)
409 	struct igsfb_devconfig *dc;
410 {
411 	struct rasops_info *ri;
412 	int wsfcookie;
413 
414 	ri = &dc->dc_ri;
415 	ri->ri_hw = dc;
416 
417 	ri->ri_flg = RI_CENTER | RI_CLEAR;
418 	if (IGSFB_HW_SOFT_BSWAP(dc))
419 	    ri->ri_flg |= RI_BSWAP;
420 
421 	ri->ri_depth = dc->dc_depth;
422 	ri->ri_width = dc->dc_width;
423 	ri->ri_height = dc->dc_height;
424 
425 	ri->ri_stride = dc->dc_width; /* XXX: 8bpp specific */
426 	ri->ri_bits = (u_char *)dc->dc_fbh;
427 
428 	/*
429 	 * Initialize wsfont related stuff.
430 	 */
431 	wsfont_init();
432 
433 	/* prefer gallant that is identical to the one the prom uses */
434 	wsfcookie = wsfont_find("Gallant", 12, 22, 0,
435 				WSDISPLAY_FONTORDER_L2R,
436 				WSDISPLAY_FONTORDER_L2R);
437 	if (wsfcookie <= 0) {
438 #ifdef DIAGNOSTIC
439 		printf("unable to find font Gallant 12x22\n");
440 #endif
441 		wsfcookie = wsfont_find(NULL, 0, 0, 0, /* any font at all? */
442 					WSDISPLAY_FONTORDER_L2R,
443 					WSDISPLAY_FONTORDER_L2R);
444 	}
445 
446 	if (wsfcookie <= 0) {
447 		printf("unable to find any fonts\n");
448 		return;
449 	}
450 
451 	if (wsfont_lock(wsfcookie, &ri->ri_font) != 0) {
452 		printf("unable to lock font\n");
453 		return;
454 	}
455 	ri->ri_wsfcookie = wsfcookie;
456 
457 
458 	/* XXX: TODO: compute term size based on font dimensions? */
459 	rasops_init(ri, 34, 80);
460 
461 
462 	/* use the sprite for the text mode cursor */
463 	igsfb_make_text_cursor(dc);
464 
465 	/* the cursor is "busy" while we are in the text mode */
466 	dc->dc_hwflags |= IGSFB_HW_TEXT_CURSOR;
467 
468 	/* propagate sprite data to the device */
469 	igsfb_update_cursor(dc, WSDISPLAY_CURSOR_DOSHAPE);
470 
471 	/* accelerated text cursor */
472 	ri->ri_ops.cursor = igsfb_accel_cursor;
473 
474 	if (dc->dc_id >= 0x2000) { /* XXX */
475 	    /* accelerated erase/copy */
476 	    ri->ri_ops.copycols = igsfb_accel_copycols;
477 	    ri->ri_ops.erasecols = igsfb_accel_erasecols;
478 	    ri->ri_ops.copyrows = igsfb_accel_copyrows;
479 	    ri->ri_ops.eraserows = igsfb_accel_eraserows;
480 
481 	    /* putchar hook to sync with the cop */
482 	    dc->dc_ri_putchar = ri->ri_ops.putchar;
483 	    ri->ri_ops.putchar = igsfb_accel_putchar;
484 	}
485 
486 	igsfb_stdscreen.nrows = ri->ri_rows;
487 	igsfb_stdscreen.ncols = ri->ri_cols;
488 	igsfb_stdscreen.textops = &ri->ri_ops;
489 	igsfb_stdscreen.capabilities = ri->ri_caps;
490 }
491 
492 
493 /*
494  * Init cursor data in dc_cursor for the accelerated text cursor.
495  */
496 static int
497 igsfb_make_text_cursor(dc)
498 	struct igsfb_devconfig *dc;
499 {
500 	struct wsdisplay_font *f = dc->dc_ri.ri_font;
501 	u_int16_t cc_scan[8];	/* one sprite scanline */
502 	u_int16_t s;
503 	int w, i;
504 
505 	KASSERT(f->fontwidth <= IGS_CURSOR_MAX_SIZE);
506 	KASSERT(f->fontheight <= IGS_CURSOR_MAX_SIZE);
507 
508 	w = f->fontwidth;
509 	for (i = 0; i < f->stride; ++i) {
510 		if (w >= 8) {
511 			s = 0xffff; /* all inverted */
512 			w -= 8;
513 		} else {
514 			/* first w pixels inverted, the rest is transparent */
515 			s = ~(0x5555 << (w * 2));
516 			if (IGSFB_HW_SOFT_BSWAP(dc))
517 				s = bswap16(s);
518 			w = 0;
519 		}
520 		cc_scan[i] = s;
521 	}
522 
523 	dc->dc_cursor.cc_size.x = f->fontwidth;
524 	dc->dc_cursor.cc_size.y = f->fontheight;
525 
526 	dc->dc_cursor.cc_hot.x = 0;
527 	dc->dc_cursor.cc_hot.y = 0;
528 
529 	/* init sprite array to be all transparent */
530 	memset(dc->dc_cursor.cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE);
531 
532 	for (i = 0; i < f->fontheight; ++i)
533 		memcpy(&dc->dc_cursor.cc_sprite[i * 8],
534 		       cc_scan, f->stride * sizeof(u_int16_t));
535 
536 	return (0);
537 }
538 
539 
540 /*
541  * Spread a byte (abcd.efgh) into two (0a0b.0c0d 0e0f.0g0h).
542  * Helper function for igsfb_init_bit_table().
543  */
544 static u_int16_t
545 igsfb_spread_bits_8(b)
546 	u_int8_t b;
547 {
548 	u_int16_t s = b;
549 
550 	s = ((s & 0x00f0) << 4) | (s & 0x000f);
551 	s = ((s & 0x0c0c) << 2) | (s & 0x0303);
552 	s = ((s & 0x2222) << 1) | (s & 0x1111);
553 	return (s);
554 }
555 
556 
557 /*
558  * Cursor sprite data are in 2bpp.  Incoming image/mask are in 1bpp.
559  * Prebuild the table to expand 1bpp->2bpp, with bswapping if neccessary.
560  */
561 static void
562 igsfb_init_bit_table(dc)
563 	struct igsfb_devconfig *dc;
564 {
565 	u_int16_t *expand = dc->dc_bexpand;
566 	int need_bswap = IGSFB_HW_SOFT_BSWAP(dc);
567 	u_int16_t s;
568 	u_int i;
569 
570 	for (i = 0; i < 256; ++i) {
571 		s = igsfb_spread_bits_8(i);
572 		expand[i] = need_bswap ? bswap16(s) : s;
573 	}
574 }
575 
576 
577 /*
578  * wsdisplay_accessops: mmap()
579  *   XXX: allow mmapping i/o mapped i/o regs if INSECURE???
580  */
581 static paddr_t
582 igsfb_mmap(v, offset, prot)
583 	void *v;
584 	off_t offset;
585 	int prot;
586 {
587 	struct igsfb_devconfig *dc = v;
588 
589 	if (offset >= dc->dc_memsz || offset < 0)
590 		return (-1);
591 
592 	return (bus_space_mmap(dc->dc_memt, dc->dc_memaddr, offset, prot,
593 			       dc->dc_memflags | BUS_SPACE_MAP_LINEAR));
594 }
595 
596 
597 /*
598  * wsdisplay_accessops: ioctl()
599  */
600 static int
601 igsfb_ioctl(v, cmd, data, flag, p)
602 	void *v;
603 	u_long cmd;
604 	caddr_t data;
605 	int flag;
606 	struct proc *p;
607 {
608 	struct igsfb_devconfig *dc = v;
609 	struct rasops_info *ri;
610 	int cursor_busy;
611 	int turnoff;
612 
613 	/* don't permit cursor ioctls if we use sprite for text cursor */
614 	cursor_busy = !dc->dc_mapped
615 		&& (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR);
616 
617 	switch (cmd) {
618 
619 	case WSDISPLAYIO_GTYPE:
620 		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
621 		return (0);
622 
623 	case WSDISPLAYIO_GINFO:
624 		ri = &dc->dc_ri;
625 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
626 		wsd_fbip->height = ri->ri_height;
627 		wsd_fbip->width = ri->ri_width;
628 		wsd_fbip->depth = ri->ri_depth;
629 		wsd_fbip->cmsize = IGS_CMAP_SIZE;
630 #undef wsd_fbip
631 		return (0);
632 
633 	case WSDISPLAYIO_SMODE:
634 #define d (*(int *)data)
635 		if (d == WSDISPLAYIO_MODE_MAPPED)
636 			dc->dc_mapped = 1;
637 		else {
638 			dc->dc_mapped = 0;
639 			/* reinit sprite for text cursor */
640 			if (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR) {
641 				igsfb_make_text_cursor(dc);
642 				dc->dc_curenb = 0;
643 				igsfb_update_cursor(dc,
644 					  WSDISPLAY_CURSOR_DOSHAPE
645 					| WSDISPLAY_CURSOR_DOCUR);
646 			}
647 		}
648 		return (0);
649 
650 	case WSDISPLAYIO_GVIDEO:
651 		*(u_int *)data = dc->dc_blanked ?
652 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
653 		return (0);
654 
655 	case WSDISPLAYIO_SVIDEO:
656 		turnoff = (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF);
657 		if (dc->dc_blanked != turnoff) {
658 			dc->dc_blanked = turnoff;
659 			igsfb_blank_screen(dc, dc->dc_blanked);
660 		}
661 		return (0);
662 
663 	case WSDISPLAYIO_GETCMAP:
664 		return (igsfb_get_cmap(dc, (struct wsdisplay_cmap *)data));
665 
666 	case WSDISPLAYIO_PUTCMAP:
667 		return (igsfb_set_cmap(dc, (struct wsdisplay_cmap *)data));
668 
669 	case WSDISPLAYIO_GCURMAX:
670 		((struct wsdisplay_curpos *)data)->x = IGS_CURSOR_MAX_SIZE;
671 		((struct wsdisplay_curpos *)data)->y = IGS_CURSOR_MAX_SIZE;
672 		return (0);
673 
674 	case WSDISPLAYIO_GCURPOS:
675 		if (cursor_busy)
676 			return (EBUSY);
677 		*(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos;
678 		return (0);
679 
680 	case WSDISPLAYIO_SCURPOS:
681 		if (cursor_busy)
682 			return (EBUSY);
683 		igsfb_set_curpos(dc, (struct wsdisplay_curpos *)data);
684 		return (0);
685 
686 	case WSDISPLAYIO_GCURSOR:
687 		if (cursor_busy)
688 			return (EBUSY);
689 		return (igsfb_get_cursor(dc, (struct wsdisplay_cursor *)data));
690 
691 	case WSDISPLAYIO_SCURSOR:
692 		if (cursor_busy)
693 			return (EBUSY);
694 		return (igsfb_set_cursor(dc, (struct wsdisplay_cursor *)data));
695 	}
696 
697 	return (EPASSTHROUGH);
698 }
699 
700 
701 /*
702  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SVIDEO)
703  */
704 static void
705 igsfb_blank_screen(dc, blank)
706 	struct igsfb_devconfig *dc;
707 	int blank;
708 {
709 
710 	igs_ext_write(dc->dc_iot, dc->dc_ioh,
711 		      IGS_EXT_SYNC_CTL,
712 		      blank ? IGS_EXT_SYNC_H0 | IGS_EXT_SYNC_V0
713 			    : 0);
714 }
715 
716 
717 /*
718  * wsdisplay_accessops: ioctl(WSDISPLAYIO_GETCMAP)
719  *   Served from the software cmap copy.
720  */
721 static int
722 igsfb_get_cmap(dc, p)
723 	struct igsfb_devconfig *dc;
724 	struct wsdisplay_cmap *p;
725 {
726 	u_int index, count;
727 	int err;
728 
729 	index = p->index;
730 	count = p->count;
731 
732 	if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index)
733 		return (EINVAL);
734 
735 	err = copyout(&dc->dc_cmap.r[index], p->red, count);
736 	if (err)
737 		return (err);
738 	err = copyout(&dc->dc_cmap.g[index], p->green, count);
739 	if (err)
740 		return (err);
741 	err = copyout(&dc->dc_cmap.b[index], p->blue, count);
742 	if (err)
743 		return (err);
744 
745 	return (0);
746 }
747 
748 
749 /*
750  * wsdisplay_accessops: ioctl(WSDISPLAYIO_PUTCMAP)
751  *   Set the software cmap copy and propagate changed range to the device.
752  */
753 static int
754 igsfb_set_cmap(dc, p)
755 	struct igsfb_devconfig *dc;
756 	const struct wsdisplay_cmap *p;
757 {
758 	u_int index, count;
759 	uint8_t r[IGS_CMAP_SIZE];
760 	uint8_t g[IGS_CMAP_SIZE];
761 	uint8_t b[IGS_CMAP_SIZE];
762 	int error;
763 
764 	index = p->index;
765 	count = p->count;
766 	if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index)
767 		return (EINVAL);
768 	error = copyin(p->red, &r[index], count);
769 	if (error)
770 		return error;
771 	error = copyin(p->green, &g[index], count);
772 	if (error)
773 		return error;
774 	error = copyin(p->blue, &b[index], count);
775 	if (error)
776 		return error;
777 
778 	memcpy(&dc->dc_cmap.r[index], &r[index], count);
779 	memcpy(&dc->dc_cmap.g[index], &g[index], count);
780 	memcpy(&dc->dc_cmap.b[index], &b[index], count);
781 
782 	/* propagate changes to the device */
783 	igsfb_update_cmap(dc, index, count);
784 	return (0);
785 }
786 
787 
788 /*
789  * Propagate specified part of the software cmap copy to the device.
790  */
791 static void
792 igsfb_update_cmap(dc, index, count)
793 	struct igsfb_devconfig *dc;
794 	u_int index, count;
795 {
796 	bus_space_tag_t t;
797 	bus_space_handle_t h;
798 	u_int last, i;
799 
800 	if (index >= IGS_CMAP_SIZE)
801 		return;
802 
803 	last = index + count;
804 	if (last > IGS_CMAP_SIZE)
805 		last = IGS_CMAP_SIZE;
806 
807 	t = dc->dc_iot;
808 	h = dc->dc_ioh;
809 
810 	/* start palette writing, index is autoincremented by hardware */
811 	bus_space_write_1(t, h, IGS_DAC_PEL_WRITE_IDX, index);
812 
813 	for (i = index; i < last; ++i) {
814 		bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.r[i]);
815 		bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.g[i]);
816 		bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.b[i]);
817 	}
818 }
819 
820 
821 /*
822  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURPOS)
823  */
824 static void
825 igsfb_set_curpos(dc, curpos)
826 	struct igsfb_devconfig *dc;
827 	const struct wsdisplay_curpos *curpos;
828 {
829 	struct rasops_info *ri = &dc->dc_ri;
830 	u_int x = curpos->x, y = curpos->y;
831 
832 	if (x >= ri->ri_width)
833 		x = ri->ri_width - 1;
834 	if (y >= ri->ri_height)
835 		y = ri->ri_height - 1;
836 
837 	dc->dc_cursor.cc_pos.x = x;
838 	dc->dc_cursor.cc_pos.y = y;
839 
840 	/* propagate changes to the device */
841 	igsfb_update_curpos(dc);
842 }
843 
844 
845 static void
846 igsfb_update_curpos(dc)
847 	struct igsfb_devconfig *dc;
848 {
849 	bus_space_tag_t t;
850 	bus_space_handle_t h;
851 	int x, xoff, y, yoff;
852 
853 	xoff = 0;
854 	x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x;
855 	if (x < 0) {
856 		xoff = -x;
857 		x = 0;
858 	}
859 
860 	yoff = 0;
861 	y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y;
862 	if (y < 0) {
863 		yoff = -y;
864 		y = 0;
865 	}
866 
867 	t = dc->dc_iot;
868 	h = dc->dc_ioh;
869 
870 	igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_LO, x & 0xff);
871 	igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_HI, (x >> 8) & 0x07);
872 	igs_ext_write(t, h, IGS_EXT_SPRITE_HPRESET, xoff & 0x3f);
873 
874 	igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_LO, y & 0xff);
875 	igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_HI, (y >> 8) & 0x07);
876 	igs_ext_write(t, h, IGS_EXT_SPRITE_VPRESET, yoff & 0x3f);
877 }
878 
879 
880 /*
881  * wsdisplay_accessops: ioctl(WSDISPLAYIO_GCURSOR)
882  */
883 static int
884 igsfb_get_cursor(dc, p)
885 	struct igsfb_devconfig *dc;
886 	struct wsdisplay_cursor *p;
887 {
888 
889 	/* XXX: TODO */
890 	return (0);
891 }
892 
893 
894 /*
895  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURSOR)
896  */
897 static int
898 igsfb_set_cursor(dc, p)
899 	struct igsfb_devconfig *dc;
900 	const struct wsdisplay_cursor *p;
901 {
902 	struct igs_hwcursor *cc;
903 	struct wsdisplay_curpos pos, hot;
904 	u_int v, index, count, icount, iwidth;
905 	uint8_t r[2], g[2], b[2], image[512], mask[512];
906 	int error;
907 
908 	cc = &dc->dc_cursor;
909 	v = p->which;
910 	index = count = icount = iwidth = 0;	/* XXX: gcc */
911 
912 	/* copy in the new cursor colormap */
913 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
914 		index = p->cmap.index;
915 		count = p->cmap.count;
916 		if (index >= 2 || (index + count) > 2)
917 			return (EINVAL);
918 		error = copyin(p->cmap.red, &r[index], count);
919 		if (error)
920 			return error;
921 		error = copyin(p->cmap.green, &g[index], count);
922 		if (error)
923 			return error;
924 		error = copyin(p->cmap.blue, &b[index], count);
925 		if (error)
926 			return error;
927 	}
928 
929 	/* verify that the new cursor data are valid */
930 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
931 		if (p->size.x > IGS_CURSOR_MAX_SIZE
932 		    || p->size.y > IGS_CURSOR_MAX_SIZE)
933 			return (EINVAL);
934 
935 		iwidth = (p->size.x + 7) >> 3; /* bytes per scan line */
936 		icount = iwidth * p->size.y;
937 		error = copyin(p->image, image, icount);
938 		if (error)
939 			return error;
940 		error = copyin(p->mask, mask, icount);
941 		if (error)
942 			return error;
943 	}
944 
945 	/* enforce that the position is within screen bounds */
946 	if (v & WSDISPLAY_CURSOR_DOPOS) {
947 		struct rasops_info *ri = &dc->dc_ri;
948 
949 		pos = p->pos;	/* local copy we can write to */
950 		if (pos.x >= ri->ri_width)
951 			pos.x = ri->ri_width - 1;
952 		if (pos.y >= ri->ri_height)
953 			pos.y = ri->ri_height - 1;
954 	}
955 
956 	/* enforce that the hot spot is within sprite bounds */
957 	if (v & WSDISPLAY_CURSOR_DOHOT)
958 		hot = p->hot;	/* local copy we can write to */
959 
960 	if (v & (WSDISPLAY_CURSOR_DOHOT | WSDISPLAY_CURSOR_DOSHAPE)) {
961 		const struct wsdisplay_curpos *nsize;
962 		struct wsdisplay_curpos *nhot;
963 
964 		nsize = (v & WSDISPLAY_CURSOR_DOSHAPE) ?
965 			    &p->size : &cc->cc_size;
966 		nhot = (v & WSDISPLAY_CURSOR_DOHOT) ? &hot : &cc->cc_hot;
967 
968 		if (nhot->x >= nsize->x)
969 			nhot->x = nsize->x - 1;
970 		if (nhot->y >= nsize->y)
971 			nhot->y = nsize->y - 1;
972 	}
973 
974 	/* copy data to the driver's cursor info */
975 	if (v & WSDISPLAY_CURSOR_DOCUR)
976 		dc->dc_curenb = p->enable;
977 	if (v & WSDISPLAY_CURSOR_DOPOS)
978 		cc->cc_pos = pos; /* local copy, possibly corrected */
979 	if (v & WSDISPLAY_CURSOR_DOHOT)
980 		cc->cc_hot = hot; /* local copy, possibly corrected */
981 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
982 		memcpy(&cc->cc_color[index], &r[index], count);
983 		memcpy(&cc->cc_color[index + 2], &g[index], count);
984 		memcpy(&cc->cc_color[index + 4], &b[index], count);
985 	}
986 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
987 		u_int trailing_bits;
988 
989 		memcpy(cc->cc_image, image, icount);
990 		memcpy(cc->cc_mask, mask, icount);
991 		cc->cc_size = p->size;
992 
993 		/* clear trailing bits in the "partial" mask bytes */
994 		trailing_bits = p->size.x & 0x07;
995 		if (trailing_bits != 0) {
996 			const u_int cutmask = ~((~0) << trailing_bits);
997 			u_char *mp;
998 			u_int i;
999 
1000 			mp = cc->cc_mask + iwidth - 1;
1001 			for (i = 0; i < p->size.y; ++i) {
1002 				*mp &= cutmask;
1003 				mp += iwidth;
1004 			}
1005 		}
1006 		igsfb_convert_cursor_data(dc, iwidth, p->size.y);
1007 	}
1008 
1009 	/* propagate changes to the device */
1010 	igsfb_update_cursor(dc, v);
1011 
1012 	return (0);
1013 }
1014 
1015 
1016 /*
1017  * Convert incoming 1bpp cursor image/mask into native 2bpp format.
1018  */
1019 static void
1020 igsfb_convert_cursor_data(dc, width, height)
1021 	struct igsfb_devconfig *dc;
1022 	u_int width, height;
1023 {
1024 	struct igs_hwcursor *cc = &dc->dc_cursor;
1025 	u_int16_t *expand = dc->dc_bexpand;
1026 	u_int8_t *ip, *mp;
1027 	u_int16_t is, ms, *dp;
1028 	u_int line, i;
1029 
1030 	/* init sprite to be all transparent */
1031 	memset(cc->cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE);
1032 
1033 	/* first scanline */
1034 	ip = cc->cc_image;
1035 	mp = cc->cc_mask;
1036 	dp = cc->cc_sprite;
1037 
1038 	for (line = 0; line < height; ++line) {
1039 		for (i = 0; i < width; ++i) {
1040 			is = expand[ip[i]]; /* image: 0 -> 00, 1 -> 01 */
1041 			ms = expand[mp[i]]; /*  mask: 0 -> 00, 1 -> 11 */
1042 			ms |= (ms << 1);
1043 			dp[i] = (0xaaaa & ~ms) | (is & ms);
1044 		}
1045 
1046 		/* next scanline */
1047 		ip += width;
1048 		mp += width;
1049 		dp += 8; /* 64 pixels, 2bpp, 8 pixels per short = 8 shorts */
1050 	}
1051 }
1052 
1053 
1054 /*
1055  * Propagate cursor changes to the device.
1056  * "which" is composed of WSDISPLAY_CURSOR_DO* bits.
1057  */
1058 static void
1059 igsfb_update_cursor(dc, which)
1060 	struct igsfb_devconfig *dc;
1061 	u_int which;
1062 {
1063 	bus_space_tag_t iot = dc->dc_iot;
1064 	bus_space_handle_t ioh = dc->dc_ioh;
1065 	u_int8_t curctl;
1066 
1067 	curctl = 0;		/* XXX: gcc */
1068 
1069 	/*
1070 	 * We will need to tweak sprite control register for cursor
1071 	 * visibility and cursor color map manipualtion.
1072 	 */
1073 	if (which & (WSDISPLAY_CURSOR_DOCUR | WSDISPLAY_CURSOR_DOCMAP)) {
1074 		curctl = igs_ext_read(iot, ioh, IGS_EXT_SPRITE_CTL);
1075 	}
1076 
1077 	if (which & WSDISPLAY_CURSOR_DOSHAPE) {
1078 		u_int8_t *dst = bus_space_vaddr(dc->dc_memt, dc->dc_crh);
1079 
1080 		/*
1081 		 * memcpy between spaces of different endianness would
1082 		 * be ... special.  We cannot be sure if memcpy gonna
1083 		 * push data in 4-byte chunks, we can't pre-bswap it,
1084 		 * so do it byte-by-byte to preserve byte ordering.
1085 		 */
1086 		if (IGSFB_HW_SOFT_BSWAP(dc)) {
1087 			u_int8_t *src = (u_int8_t *)dc->dc_cursor.cc_sprite;
1088 			int i;
1089 
1090 			for (i = 0; i < IGS_CURSOR_DATA_SIZE; ++i)
1091 				*dst++ = *src++;
1092 		} else {
1093 			memcpy(dst, dc->dc_cursor.cc_sprite,
1094 			       IGS_CURSOR_DATA_SIZE);
1095 		}
1096 	}
1097 
1098 	if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
1099 		/* code shared with WSDISPLAYIO_SCURPOS */
1100 		igsfb_update_curpos(dc);
1101 	}
1102 
1103 	if (which & WSDISPLAY_CURSOR_DOCMAP) {
1104 		u_int8_t *p;
1105 
1106 		/* tell DAC we want access to the cursor palette */
1107 		igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
1108 			      curctl | IGS_EXT_SPRITE_DAC_PEL);
1109 
1110 		p = dc->dc_cursor.cc_color;
1111 
1112 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 0);
1113 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[0]);
1114 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[2]);
1115 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[4]);
1116 
1117 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 1);
1118 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[1]);
1119 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[3]);
1120 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[5]);
1121 
1122 		/* restore access to the normal palette */
1123 		igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, curctl);
1124 	}
1125 
1126 	if (which & WSDISPLAY_CURSOR_DOCUR) {
1127 		if ((curctl & IGS_EXT_SPRITE_VISIBLE) == 0
1128 		    && dc->dc_curenb)
1129 			igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
1130 				      curctl | IGS_EXT_SPRITE_VISIBLE);
1131 		else if ((curctl & IGS_EXT_SPRITE_VISIBLE) != 0
1132 			 && !dc->dc_curenb)
1133 			igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
1134 				      curctl & ~IGS_EXT_SPRITE_VISIBLE);
1135 	}
1136 }
1137 
1138 
1139 /*
1140  * wsdisplay_accessops: alloc_screen()
1141  */
1142 static int
1143 igsfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
1144 	void *v;
1145 	const struct wsscreen_descr *type;
1146 	void **cookiep;
1147 	int *curxp, *curyp;
1148 	long *attrp;
1149 {
1150 	struct igsfb_devconfig *dc = v;
1151 	struct rasops_info *ri = &dc->dc_ri;
1152 
1153 	if (dc->dc_nscreens > 0) /* only do single screen for now */
1154 		return (ENOMEM);
1155 
1156 	dc->dc_nscreens = 1;
1157 
1158 	*cookiep = ri;		/* emulcookie for igsgfb_stdscreen.textops */
1159 	*curxp = *curyp = 0;	/* cursor position */
1160 	(*ri->ri_ops.allocattr)(ri,
1161 				WSCOL_BLACK, /* fg */
1162 				WSCOL_BLACK, /* bg */
1163 				0,           /* wsattr */
1164 				attrp);
1165 	return (0);
1166 }
1167 
1168 
1169 /*
1170  * wsdisplay_accessops: free_screen()
1171  */
1172 static void
1173 igsfb_free_screen(v, cookie)
1174 	void *v;
1175 	void *cookie;
1176 {
1177 
1178 	/* XXX */
1179 	return;
1180 }
1181 
1182 
1183 /*
1184  * wsdisplay_accessops: show_screen()
1185  */
1186 static int
1187 igsfb_show_screen(v, cookie, waitok, cb, cbarg)
1188 	void *v;
1189 	void *cookie;
1190 	int waitok;
1191 	void (*cb)(void *, int, int);
1192 	void *cbarg;
1193 {
1194 
1195 	/* XXX */
1196 	return (0);
1197 }
1198 
1199 
1200 
1201 /*
1202  * Accelerated text mode cursor that uses hardware sprite.
1203  */
1204 static void
1205 igsfb_accel_cursor(cookie, on, row, col)
1206 	void *cookie;
1207 	int on, row, col;
1208 {
1209 	struct rasops_info *ri = (struct rasops_info *)cookie;
1210 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1211 	struct igs_hwcursor *cc = &dc->dc_cursor;
1212 	u_int which;
1213 
1214 	ri->ri_crow = row;
1215 	ri->ri_ccol = col;
1216 
1217 	which = 0;
1218 	if (on) {
1219 		ri->ri_flg |= RI_CURSOR;
1220 
1221 		/* only bother to move the cursor if it's visibile */
1222 		cc->cc_pos.x = ri->ri_xorigin
1223 			+ ri->ri_ccol * ri->ri_font->fontwidth;
1224 		cc->cc_pos.y = ri->ri_yorigin
1225 			+ ri->ri_crow * ri->ri_font->fontheight;
1226 		which |= WSDISPLAY_CURSOR_DOPOS;
1227 	} else
1228 		ri->ri_flg &= ~RI_CURSOR;
1229 
1230 	if (dc->dc_curenb != on) {
1231 		dc->dc_curenb = on;
1232 		which |= WSDISPLAY_CURSOR_DOCUR;
1233 	}
1234 
1235 	/* propagate changes to the device */
1236 	igsfb_update_cursor(dc, which);
1237 }
1238 
1239 
1240 
1241 /*
1242  * Accelerated raster ops that use graphic coprocessor.
1243  */
1244 
1245 static int
1246 igsfb_accel_wait(dc)
1247 	struct igsfb_devconfig *dc;
1248 {
1249 	bus_space_tag_t t = dc->dc_iot;
1250 	bus_space_handle_t h = dc->dc_coph;
1251 	int timo = 100000;
1252 	u_int8_t reg;
1253 
1254 	while (timo--) {
1255 		reg = bus_space_read_1(t, h, IGS_COP_CTL_REG);
1256 		if ((reg & IGS_COP_CTL_BUSY) == 0)
1257 			return (0);
1258 	}
1259 
1260 	return (1);
1261 }
1262 
1263 
1264 static void
1265 igsfb_accel_copy(dc, src, dst, width, height)
1266 	struct igsfb_devconfig *dc;
1267 	u_int32_t src, dst;
1268 	u_int16_t width, height;
1269 {
1270 	bus_space_tag_t t = dc->dc_iot;
1271 	bus_space_handle_t h = dc->dc_coph;
1272 	u_int32_t toend;
1273 	u_int8_t drawcmd;
1274 
1275 	drawcmd = IGS_COP_DRAW_ALL;
1276 	if (dst > src) {
1277 		toend = dc->dc_ri.ri_width * (height - 1) + (width - 1);
1278 		src += toend;
1279 		dst += toend;
1280 		drawcmd |= IGS_COP_OCTANT_X_NEG | IGS_COP_OCTANT_Y_NEG;
1281 	}
1282 
1283 	igsfb_accel_wait(dc);
1284 	bus_space_write_1(t, h, IGS_COP_CTL_REG, 0);
1285 
1286 	bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S);
1287 
1288 	bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1);
1289 	bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1);
1290 
1291 	bus_space_write_4(t, h, IGS_COP_SRC_START_REG, src);
1292 	bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst);
1293 
1294 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, drawcmd);
1295 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG);
1296 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0);
1297 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG,
1298 			  IGS_COP_OP_PXBLT | IGS_COP_OP_FG_FROM_SRC);
1299 }
1300 
1301 static void
1302 igsfb_accel_fill(dc, color, dst, width, height)
1303 	struct igsfb_devconfig *dc;
1304 	u_int32_t color;
1305 	u_int32_t dst;
1306 	u_int16_t width, height;
1307 {
1308 	bus_space_tag_t t = dc->dc_iot;
1309 	bus_space_handle_t h = dc->dc_coph;
1310 
1311 	igsfb_accel_wait(dc);
1312 	bus_space_write_1(t, h, IGS_COP_CTL_REG, 0);
1313 
1314 	bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S);
1315 
1316 	bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1);
1317 	bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1);
1318 
1319 	bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst);
1320 	bus_space_write_4(t, h, IGS_COP_FG_REG, color);
1321 
1322 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, IGS_COP_DRAW_ALL);
1323 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG);
1324 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0);
1325 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG, IGS_COP_OP_PXBLT);
1326 }
1327 
1328 
1329 static void
1330 igsfb_accel_copyrows(cookie, src, dst, num)
1331 	void *cookie;
1332 	int src, dst, num;
1333 {
1334 	struct rasops_info *ri = (struct rasops_info *)cookie;
1335 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1336 	u_int32_t srp, dsp;
1337 	u_int16_t width, height;
1338 
1339 	width = ri->ri_emuwidth;
1340 	height = num * ri->ri_font->fontheight;
1341 
1342 	srp = ri->ri_xorigin
1343 		+ ri->ri_width * (ri->ri_yorigin
1344 				  + src * ri->ri_font->fontheight);
1345 	dsp = ri->ri_xorigin
1346 		+ ri->ri_width * (ri->ri_yorigin
1347 				  + dst * ri->ri_font->fontheight);
1348 
1349 	igsfb_accel_copy(dc, srp, dsp, width, height);
1350 }
1351 
1352 
1353 void
1354 igsfb_accel_copycols(cookie, row, src, dst, num)
1355 	void *cookie;
1356 	int row, src, dst, num;
1357 {
1358 	struct rasops_info *ri = (struct rasops_info *)cookie;
1359 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1360 	u_int32_t rowp, srp, dsp;
1361 	u_int16_t width, height;
1362 
1363 	width = num * ri->ri_font->fontwidth;
1364 	height = ri->ri_font->fontheight;
1365 
1366 	rowp = ri->ri_xorigin
1367 		+ ri->ri_width * (ri->ri_yorigin
1368 				  + row * ri->ri_font->fontheight);
1369 
1370 	srp = rowp + src * ri->ri_font->fontwidth;
1371 	dsp = rowp + dst * ri->ri_font->fontwidth;
1372 
1373 	igsfb_accel_copy(dc, srp, dsp, width, height);
1374 }
1375 
1376 
1377 static void
1378 igsfb_accel_eraserows(cookie, row, num, attr)
1379 	void *cookie;
1380 	int row, num;
1381 	long attr;
1382 {
1383 	struct rasops_info *ri = (struct rasops_info *)cookie;
1384 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1385 	u_int32_t color;
1386 	u_int32_t dsp;
1387 	u_int16_t width, height;
1388 
1389 	width = ri->ri_emuwidth;
1390 	height = num * ri->ri_font->fontheight;
1391 
1392 	dsp = ri->ri_xorigin
1393 		+ ri->ri_width * (ri->ri_yorigin
1394 				  + row * ri->ri_font->fontheight);
1395 
1396 	/* XXX: we "know" the encoding that rasops' allocattr uses */
1397 	color = (attr >> 16) & 0xff;
1398 
1399 	igsfb_accel_fill(dc, color, dsp, width, height);
1400 }
1401 
1402 
1403 void
1404 igsfb_accel_erasecols(cookie, row, col, num, attr)
1405 	void *cookie;
1406 	int row, col, num;
1407 	long attr;
1408 {
1409 	struct rasops_info *ri = (struct rasops_info *)cookie;
1410 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1411 	u_int32_t color;
1412 	u_int32_t rowp, dsp;
1413 	u_int16_t width, height;
1414 
1415 	width = num * ri->ri_font->fontwidth;
1416 	height = ri->ri_font->fontheight;
1417 
1418 	rowp = ri->ri_xorigin
1419 		+ ri->ri_width * (ri->ri_yorigin
1420 				  + row * ri->ri_font->fontheight);
1421 
1422 	dsp = rowp + col * ri->ri_font->fontwidth;
1423 
1424 	/* XXX: we "know" the encoding that rasops' allocattr uses */
1425 	color = (attr >> 16) & 0xff;
1426 
1427 	igsfb_accel_fill(dc, color, dsp, width, height);
1428 }
1429 
1430 
1431 /*
1432  * Not really implemented here, but we need to hook into the one
1433  * supplied by rasops so that we can synchronize with the COP.
1434  */
1435 static void
1436 igsfb_accel_putchar(cookie, row, col, uc, attr)
1437 	void *cookie;
1438 	int row, col;
1439 	u_int uc;
1440 	long attr;
1441 {
1442 	struct rasops_info *ri = (struct rasops_info *)cookie;
1443 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1444 
1445 	igsfb_accel_wait(dc);
1446 	(*dc->dc_ri_putchar)(cookie, row, col, uc, attr);
1447 }
1448