xref: /netbsd-src/sys/dev/ic/igsfb.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: igsfb.c,v 1.26 2005/12/11 12:21:27 christos 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.26 2005/12/11 12:21:27 christos 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 lwp *);
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 				 uint32_t, uint32_t, uint16_t, uint16_t);
116 static void	igsfb_accel_copy(struct igsfb_devconfig *,
117 				 uint32_t, uint32_t, uint16_t, uint16_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 uint16_t	igsfb_spread_bits_8(uint8_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 	       (uint32_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 	uint8_t *p;
226 	int need_bswap;
227 	bus_addr_t fbaddr, craddr;
228 	off_t croffset;
229 	uint8_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(uint32_t),
247 			  sizeof(uint32_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 	*((uint32_t *)p) = 0x12345678;
258 #else
259 	*((uint32_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(uint32_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 and 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 uint8_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 	rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
461 	    ri->ri_width / ri->ri_font->fontwidth);
462 
463 
464 	/* use the sprite for the text mode cursor */
465 	igsfb_make_text_cursor(dc);
466 
467 	/* the cursor is "busy" while we are in the text mode */
468 	dc->dc_hwflags |= IGSFB_HW_TEXT_CURSOR;
469 
470 	/* propagate sprite data to the device */
471 	igsfb_update_cursor(dc, WSDISPLAY_CURSOR_DOSHAPE);
472 
473 	/* accelerated text cursor */
474 	ri->ri_ops.cursor = igsfb_accel_cursor;
475 
476 	if (dc->dc_id >= 0x2000) { /* XXX */
477 	    /* accelerated erase/copy */
478 	    ri->ri_ops.copycols = igsfb_accel_copycols;
479 	    ri->ri_ops.erasecols = igsfb_accel_erasecols;
480 	    ri->ri_ops.copyrows = igsfb_accel_copyrows;
481 	    ri->ri_ops.eraserows = igsfb_accel_eraserows;
482 
483 	    /* putchar hook to sync with the cop */
484 	    dc->dc_ri_putchar = ri->ri_ops.putchar;
485 	    ri->ri_ops.putchar = igsfb_accel_putchar;
486 	}
487 
488 	igsfb_stdscreen.nrows = ri->ri_rows;
489 	igsfb_stdscreen.ncols = ri->ri_cols;
490 	igsfb_stdscreen.textops = &ri->ri_ops;
491 	igsfb_stdscreen.capabilities = ri->ri_caps;
492 }
493 
494 
495 /*
496  * Init cursor data in dc_cursor for the accelerated text cursor.
497  */
498 static int
499 igsfb_make_text_cursor(dc)
500 	struct igsfb_devconfig *dc;
501 {
502 	struct wsdisplay_font *f = dc->dc_ri.ri_font;
503 	uint16_t cc_scan[8];	/* one sprite scanline */
504 	uint16_t s;
505 	int w, i;
506 
507 	KASSERT(f->fontwidth <= IGS_CURSOR_MAX_SIZE);
508 	KASSERT(f->fontheight <= IGS_CURSOR_MAX_SIZE);
509 
510 	w = f->fontwidth;
511 	for (i = 0; i < f->stride; ++i) {
512 		if (w >= 8) {
513 			s = 0xffff; /* all inverted */
514 			w -= 8;
515 		} else {
516 			/* first w pixels inverted, the rest is transparent */
517 			s = ~(0x5555 << (w * 2));
518 			if (IGSFB_HW_SOFT_BSWAP(dc))
519 				s = bswap16(s);
520 			w = 0;
521 		}
522 		cc_scan[i] = s;
523 	}
524 
525 	dc->dc_cursor.cc_size.x = f->fontwidth;
526 	dc->dc_cursor.cc_size.y = f->fontheight;
527 
528 	dc->dc_cursor.cc_hot.x = 0;
529 	dc->dc_cursor.cc_hot.y = 0;
530 
531 	/* init sprite array to be all transparent */
532 	memset(dc->dc_cursor.cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE);
533 
534 	for (i = 0; i < f->fontheight; ++i)
535 		memcpy(&dc->dc_cursor.cc_sprite[i * 8],
536 		       cc_scan, f->stride * sizeof(uint16_t));
537 
538 	return (0);
539 }
540 
541 
542 /*
543  * Spread a byte (abcd.efgh) into two (0a0b.0c0d 0e0f.0g0h).
544  * Helper function for igsfb_init_bit_table().
545  */
546 static uint16_t
547 igsfb_spread_bits_8(b)
548 	uint8_t b;
549 {
550 	uint16_t s = b;
551 
552 	s = ((s & 0x00f0) << 4) | (s & 0x000f);
553 	s = ((s & 0x0c0c) << 2) | (s & 0x0303);
554 	s = ((s & 0x2222) << 1) | (s & 0x1111);
555 	return (s);
556 }
557 
558 
559 /*
560  * Cursor sprite data are in 2bpp.  Incoming image/mask are in 1bpp.
561  * Prebuild the table to expand 1bpp->2bpp, with bswapping if necessary.
562  */
563 static void
564 igsfb_init_bit_table(dc)
565 	struct igsfb_devconfig *dc;
566 {
567 	uint16_t *expand = dc->dc_bexpand;
568 	int need_bswap = IGSFB_HW_SOFT_BSWAP(dc);
569 	uint16_t s;
570 	u_int i;
571 
572 	for (i = 0; i < 256; ++i) {
573 		s = igsfb_spread_bits_8(i);
574 		expand[i] = need_bswap ? bswap16(s) : s;
575 	}
576 }
577 
578 
579 /*
580  * wsdisplay_accessops: mmap()
581  *   XXX: allow mmapping i/o mapped i/o regs if INSECURE???
582  */
583 static paddr_t
584 igsfb_mmap(v, offset, prot)
585 	void *v;
586 	off_t offset;
587 	int prot;
588 {
589 	struct igsfb_devconfig *dc = v;
590 
591 	if (offset >= dc->dc_memsz || offset < 0)
592 		return (-1);
593 
594 	return (bus_space_mmap(dc->dc_memt, dc->dc_memaddr, offset, prot,
595 			       dc->dc_memflags | BUS_SPACE_MAP_LINEAR));
596 }
597 
598 
599 /*
600  * wsdisplay_accessops: ioctl()
601  */
602 static int
603 igsfb_ioctl(v, cmd, data, flag, l)
604 	void *v;
605 	u_long cmd;
606 	caddr_t data;
607 	int flag;
608 	struct lwp *l;
609 {
610 	struct igsfb_devconfig *dc = v;
611 	struct rasops_info *ri;
612 	int cursor_busy;
613 	int turnoff;
614 
615 	/* don't permit cursor ioctls if we use sprite for text cursor */
616 	cursor_busy = !dc->dc_mapped
617 		&& (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR);
618 
619 	switch (cmd) {
620 
621 	case WSDISPLAYIO_GTYPE:
622 		*(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
623 		return (0);
624 
625 	case WSDISPLAYIO_GINFO:
626 		ri = &dc->dc_ri;
627 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
628 		wsd_fbip->height = ri->ri_height;
629 		wsd_fbip->width = ri->ri_width;
630 		wsd_fbip->depth = ri->ri_depth;
631 		wsd_fbip->cmsize = IGS_CMAP_SIZE;
632 #undef wsd_fbip
633 		return (0);
634 
635 	case WSDISPLAYIO_LINEBYTES:
636 		ri = &dc->dc_ri;
637 		*(int *)data = ri->ri_stride;
638 		return (0);
639 
640 	case WSDISPLAYIO_SMODE:
641 #define d (*(int *)data)
642 		if (d != WSDISPLAYIO_MODE_EMUL) {
643 			dc->dc_mapped = 1;
644 			/* turn off hardware cursor */
645 			if (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR) {
646 				dc->dc_curenb = 0;
647 				igsfb_update_cursor(dc,
648 					WSDISPLAY_CURSOR_DOCUR);
649 			}
650 		} else {
651 			dc->dc_mapped = 0;
652 			/* reinit sprite for text cursor */
653 			if (dc->dc_hwflags & IGSFB_HW_TEXT_CURSOR) {
654 				igsfb_make_text_cursor(dc);
655 				dc->dc_curenb = 0;
656 				igsfb_update_cursor(dc,
657 					  WSDISPLAY_CURSOR_DOSHAPE
658 					| WSDISPLAY_CURSOR_DOCUR);
659 			}
660 		}
661 		return (0);
662 
663 	case WSDISPLAYIO_GVIDEO:
664 		*(u_int *)data = dc->dc_blanked ?
665 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
666 		return (0);
667 
668 	case WSDISPLAYIO_SVIDEO:
669 		turnoff = (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF);
670 		if (dc->dc_blanked != turnoff) {
671 			dc->dc_blanked = turnoff;
672 			igsfb_blank_screen(dc, dc->dc_blanked);
673 		}
674 		return (0);
675 
676 	case WSDISPLAYIO_GETCMAP:
677 		return (igsfb_get_cmap(dc, (struct wsdisplay_cmap *)data));
678 
679 	case WSDISPLAYIO_PUTCMAP:
680 		return (igsfb_set_cmap(dc, (struct wsdisplay_cmap *)data));
681 
682 	case WSDISPLAYIO_GCURMAX:
683 		((struct wsdisplay_curpos *)data)->x = IGS_CURSOR_MAX_SIZE;
684 		((struct wsdisplay_curpos *)data)->y = IGS_CURSOR_MAX_SIZE;
685 		return (0);
686 
687 	case WSDISPLAYIO_GCURPOS:
688 		if (cursor_busy)
689 			return (EBUSY);
690 		*(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos;
691 		return (0);
692 
693 	case WSDISPLAYIO_SCURPOS:
694 		if (cursor_busy)
695 			return (EBUSY);
696 		igsfb_set_curpos(dc, (struct wsdisplay_curpos *)data);
697 		return (0);
698 
699 	case WSDISPLAYIO_GCURSOR:
700 		if (cursor_busy)
701 			return (EBUSY);
702 		return (igsfb_get_cursor(dc, (struct wsdisplay_cursor *)data));
703 
704 	case WSDISPLAYIO_SCURSOR:
705 		if (cursor_busy)
706 			return (EBUSY);
707 		return (igsfb_set_cursor(dc, (struct wsdisplay_cursor *)data));
708 	}
709 
710 	return (EPASSTHROUGH);
711 }
712 
713 
714 /*
715  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SVIDEO)
716  */
717 static void
718 igsfb_blank_screen(dc, blank)
719 	struct igsfb_devconfig *dc;
720 	int blank;
721 {
722 
723 	igs_ext_write(dc->dc_iot, dc->dc_ioh,
724 		      IGS_EXT_SYNC_CTL,
725 		      blank ? IGS_EXT_SYNC_H0 | IGS_EXT_SYNC_V0
726 			    : 0);
727 }
728 
729 
730 /*
731  * wsdisplay_accessops: ioctl(WSDISPLAYIO_GETCMAP)
732  *   Served from the software cmap copy.
733  */
734 static int
735 igsfb_get_cmap(dc, p)
736 	struct igsfb_devconfig *dc;
737 	struct wsdisplay_cmap *p;
738 {
739 	u_int index, count;
740 	int err;
741 
742 	index = p->index;
743 	count = p->count;
744 
745 	if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index)
746 		return (EINVAL);
747 
748 	err = copyout(&dc->dc_cmap.r[index], p->red, count);
749 	if (err)
750 		return (err);
751 	err = copyout(&dc->dc_cmap.g[index], p->green, count);
752 	if (err)
753 		return (err);
754 	err = copyout(&dc->dc_cmap.b[index], p->blue, count);
755 	if (err)
756 		return (err);
757 
758 	return (0);
759 }
760 
761 
762 /*
763  * wsdisplay_accessops: ioctl(WSDISPLAYIO_PUTCMAP)
764  *   Set the software cmap copy and propagate changed range to the device.
765  */
766 static int
767 igsfb_set_cmap(dc, p)
768 	struct igsfb_devconfig *dc;
769 	const struct wsdisplay_cmap *p;
770 {
771 	u_int index, count;
772 	uint8_t r[IGS_CMAP_SIZE];
773 	uint8_t g[IGS_CMAP_SIZE];
774 	uint8_t b[IGS_CMAP_SIZE];
775 	int error;
776 
777 	index = p->index;
778 	count = p->count;
779 	if (index >= IGS_CMAP_SIZE || count > IGS_CMAP_SIZE - index)
780 		return (EINVAL);
781 	error = copyin(p->red, &r[index], count);
782 	if (error)
783 		return error;
784 	error = copyin(p->green, &g[index], count);
785 	if (error)
786 		return error;
787 	error = copyin(p->blue, &b[index], count);
788 	if (error)
789 		return error;
790 
791 	memcpy(&dc->dc_cmap.r[index], &r[index], count);
792 	memcpy(&dc->dc_cmap.g[index], &g[index], count);
793 	memcpy(&dc->dc_cmap.b[index], &b[index], count);
794 
795 	/* propagate changes to the device */
796 	igsfb_update_cmap(dc, index, count);
797 	return (0);
798 }
799 
800 
801 /*
802  * Propagate specified part of the software cmap copy to the device.
803  */
804 static void
805 igsfb_update_cmap(dc, index, count)
806 	struct igsfb_devconfig *dc;
807 	u_int index, count;
808 {
809 	bus_space_tag_t t;
810 	bus_space_handle_t h;
811 	u_int last, i;
812 
813 	if (index >= IGS_CMAP_SIZE)
814 		return;
815 
816 	last = index + count;
817 	if (last > IGS_CMAP_SIZE)
818 		last = IGS_CMAP_SIZE;
819 
820 	t = dc->dc_iot;
821 	h = dc->dc_ioh;
822 
823 	/* start palette writing, index is autoincremented by hardware */
824 	bus_space_write_1(t, h, IGS_DAC_PEL_WRITE_IDX, index);
825 
826 	for (i = index; i < last; ++i) {
827 		bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.r[i]);
828 		bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.g[i]);
829 		bus_space_write_1(t, h, IGS_DAC_PEL_DATA, dc->dc_cmap.b[i]);
830 	}
831 }
832 
833 
834 /*
835  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURPOS)
836  */
837 static void
838 igsfb_set_curpos(dc, curpos)
839 	struct igsfb_devconfig *dc;
840 	const struct wsdisplay_curpos *curpos;
841 {
842 	struct rasops_info *ri = &dc->dc_ri;
843 	u_int x = curpos->x, y = curpos->y;
844 
845 	if (x >= ri->ri_width)
846 		x = ri->ri_width - 1;
847 	if (y >= ri->ri_height)
848 		y = ri->ri_height - 1;
849 
850 	dc->dc_cursor.cc_pos.x = x;
851 	dc->dc_cursor.cc_pos.y = y;
852 
853 	/* propagate changes to the device */
854 	igsfb_update_curpos(dc);
855 }
856 
857 
858 static void
859 igsfb_update_curpos(dc)
860 	struct igsfb_devconfig *dc;
861 {
862 	bus_space_tag_t t;
863 	bus_space_handle_t h;
864 	int x, xoff, y, yoff;
865 
866 	xoff = 0;
867 	x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x;
868 	if (x < 0) {
869 		xoff = -x;
870 		x = 0;
871 	}
872 
873 	yoff = 0;
874 	y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y;
875 	if (y < 0) {
876 		yoff = -y;
877 		y = 0;
878 	}
879 
880 	t = dc->dc_iot;
881 	h = dc->dc_ioh;
882 
883 	igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_LO, x & 0xff);
884 	igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_HI, (x >> 8) & 0x07);
885 	igs_ext_write(t, h, IGS_EXT_SPRITE_HPRESET, xoff & 0x3f);
886 
887 	igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_LO, y & 0xff);
888 	igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_HI, (y >> 8) & 0x07);
889 	igs_ext_write(t, h, IGS_EXT_SPRITE_VPRESET, yoff & 0x3f);
890 }
891 
892 
893 /*
894  * wsdisplay_accessops: ioctl(WSDISPLAYIO_GCURSOR)
895  */
896 static int
897 igsfb_get_cursor(dc, p)
898 	struct igsfb_devconfig *dc;
899 	struct wsdisplay_cursor *p;
900 {
901 
902 	/* XXX: TODO */
903 	return (0);
904 }
905 
906 
907 /*
908  * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURSOR)
909  */
910 static int
911 igsfb_set_cursor(dc, p)
912 	struct igsfb_devconfig *dc;
913 	const struct wsdisplay_cursor *p;
914 {
915 	struct igs_hwcursor *cc;
916 	struct wsdisplay_curpos pos, hot;
917 	u_int v, index, count, icount, iwidth;
918 	uint8_t r[2], g[2], b[2], image[512], mask[512];
919 	int error;
920 
921 	cc = &dc->dc_cursor;
922 	v = p->which;
923 	index = count = icount = iwidth = 0;	/* XXX: gcc */
924 
925 	/* copy in the new cursor colormap */
926 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
927 		index = p->cmap.index;
928 		count = p->cmap.count;
929 		if (index >= 2 || (index + count) > 2)
930 			return (EINVAL);
931 		error = copyin(p->cmap.red, &r[index], count);
932 		if (error)
933 			return error;
934 		error = copyin(p->cmap.green, &g[index], count);
935 		if (error)
936 			return error;
937 		error = copyin(p->cmap.blue, &b[index], count);
938 		if (error)
939 			return error;
940 	}
941 
942 	/* verify that the new cursor data are valid */
943 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
944 		if (p->size.x > IGS_CURSOR_MAX_SIZE
945 		    || p->size.y > IGS_CURSOR_MAX_SIZE)
946 			return (EINVAL);
947 
948 		iwidth = (p->size.x + 7) >> 3; /* bytes per scan line */
949 		icount = iwidth * p->size.y;
950 		error = copyin(p->image, image, icount);
951 		if (error)
952 			return error;
953 		error = copyin(p->mask, mask, icount);
954 		if (error)
955 			return error;
956 	}
957 
958 	/* enforce that the position is within screen bounds */
959 	if (v & WSDISPLAY_CURSOR_DOPOS) {
960 		struct rasops_info *ri = &dc->dc_ri;
961 
962 		pos = p->pos;	/* local copy we can write to */
963 		if (pos.x >= ri->ri_width)
964 			pos.x = ri->ri_width - 1;
965 		if (pos.y >= ri->ri_height)
966 			pos.y = ri->ri_height - 1;
967 	}
968 
969 	/* enforce that the hot spot is within sprite bounds */
970 	if (v & WSDISPLAY_CURSOR_DOHOT)
971 		hot = p->hot;	/* local copy we can write to */
972 
973 	if (v & (WSDISPLAY_CURSOR_DOHOT | WSDISPLAY_CURSOR_DOSHAPE)) {
974 		const struct wsdisplay_curpos *nsize;
975 		struct wsdisplay_curpos *nhot;
976 
977 		nsize = (v & WSDISPLAY_CURSOR_DOSHAPE) ?
978 			    &p->size : &cc->cc_size;
979 		nhot = (v & WSDISPLAY_CURSOR_DOHOT) ? &hot : &cc->cc_hot;
980 
981 		if (nhot->x >= nsize->x)
982 			nhot->x = nsize->x - 1;
983 		if (nhot->y >= nsize->y)
984 			nhot->y = nsize->y - 1;
985 	}
986 
987 	/* copy data to the driver's cursor info */
988 	if (v & WSDISPLAY_CURSOR_DOCUR)
989 		dc->dc_curenb = p->enable;
990 	if (v & WSDISPLAY_CURSOR_DOPOS)
991 		cc->cc_pos = pos; /* local copy, possibly corrected */
992 	if (v & WSDISPLAY_CURSOR_DOHOT)
993 		cc->cc_hot = hot; /* local copy, possibly corrected */
994 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
995 		memcpy(&cc->cc_color[index], &r[index], count);
996 		memcpy(&cc->cc_color[index + 2], &g[index], count);
997 		memcpy(&cc->cc_color[index + 4], &b[index], count);
998 	}
999 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
1000 		u_int trailing_bits;
1001 
1002 		memcpy(cc->cc_image, image, icount);
1003 		memcpy(cc->cc_mask, mask, icount);
1004 		cc->cc_size = p->size;
1005 
1006 		/* clear trailing bits in the "partial" mask bytes */
1007 		trailing_bits = p->size.x & 0x07;
1008 		if (trailing_bits != 0) {
1009 			const u_int cutmask = ~((~0) << trailing_bits);
1010 			u_char *mp;
1011 			u_int i;
1012 
1013 			mp = cc->cc_mask + iwidth - 1;
1014 			for (i = 0; i < p->size.y; ++i) {
1015 				*mp &= cutmask;
1016 				mp += iwidth;
1017 			}
1018 		}
1019 		igsfb_convert_cursor_data(dc, iwidth, p->size.y);
1020 	}
1021 
1022 	/* propagate changes to the device */
1023 	igsfb_update_cursor(dc, v);
1024 
1025 	return (0);
1026 }
1027 
1028 
1029 /*
1030  * Convert incoming 1bpp cursor image/mask into native 2bpp format.
1031  */
1032 static void
1033 igsfb_convert_cursor_data(dc, width, height)
1034 	struct igsfb_devconfig *dc;
1035 	u_int width, height;
1036 {
1037 	struct igs_hwcursor *cc = &dc->dc_cursor;
1038 	uint16_t *expand = dc->dc_bexpand;
1039 	uint8_t *ip, *mp;
1040 	uint16_t is, ms, *dp;
1041 	u_int line, i;
1042 
1043 	/* init sprite to be all transparent */
1044 	memset(cc->cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE);
1045 
1046 	/* first scanline */
1047 	ip = cc->cc_image;
1048 	mp = cc->cc_mask;
1049 	dp = cc->cc_sprite;
1050 
1051 	for (line = 0; line < height; ++line) {
1052 		for (i = 0; i < width; ++i) {
1053 			is = expand[ip[i]]; /* image: 0 -> 00, 1 -> 01 */
1054 			ms = expand[mp[i]]; /*  mask: 0 -> 00, 1 -> 11 */
1055 			ms |= (ms << 1);
1056 			dp[i] = (0xaaaa & ~ms) | (is & ms);
1057 		}
1058 
1059 		/* next scanline */
1060 		ip += width;
1061 		mp += width;
1062 		dp += 8; /* 64 pixels, 2bpp, 8 pixels per short = 8 shorts */
1063 	}
1064 }
1065 
1066 
1067 /*
1068  * Propagate cursor changes to the device.
1069  * "which" is composed of WSDISPLAY_CURSOR_DO* bits.
1070  */
1071 static void
1072 igsfb_update_cursor(dc, which)
1073 	struct igsfb_devconfig *dc;
1074 	u_int which;
1075 {
1076 	bus_space_tag_t iot = dc->dc_iot;
1077 	bus_space_handle_t ioh = dc->dc_ioh;
1078 	uint8_t curctl;
1079 
1080 	curctl = 0;		/* XXX: gcc */
1081 
1082 	/*
1083 	 * We will need to tweak sprite control register for cursor
1084 	 * visibility and cursor color map manipulation.
1085 	 */
1086 	if (which & (WSDISPLAY_CURSOR_DOCUR | WSDISPLAY_CURSOR_DOCMAP)) {
1087 		curctl = igs_ext_read(iot, ioh, IGS_EXT_SPRITE_CTL);
1088 	}
1089 
1090 	if (which & WSDISPLAY_CURSOR_DOSHAPE) {
1091 		uint8_t *dst = bus_space_vaddr(dc->dc_memt, dc->dc_crh);
1092 
1093 		/*
1094 		 * memcpy between spaces of different endianness would
1095 		 * be ... special.  We cannot be sure if memcpy gonna
1096 		 * push data in 4-byte chunks, we can't pre-bswap it,
1097 		 * so do it byte-by-byte to preserve byte ordering.
1098 		 */
1099 		if (IGSFB_HW_SOFT_BSWAP(dc)) {
1100 			uint8_t *src = (uint8_t *)dc->dc_cursor.cc_sprite;
1101 			int i;
1102 
1103 			for (i = 0; i < IGS_CURSOR_DATA_SIZE; ++i)
1104 				*dst++ = *src++;
1105 		} else {
1106 			memcpy(dst, dc->dc_cursor.cc_sprite,
1107 			       IGS_CURSOR_DATA_SIZE);
1108 		}
1109 	}
1110 
1111 	if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
1112 		/* code shared with WSDISPLAYIO_SCURPOS */
1113 		igsfb_update_curpos(dc);
1114 	}
1115 
1116 	if (which & WSDISPLAY_CURSOR_DOCMAP) {
1117 		uint8_t *p;
1118 
1119 		/* tell DAC we want access to the cursor palette */
1120 		igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
1121 			      curctl | IGS_EXT_SPRITE_DAC_PEL);
1122 
1123 		p = dc->dc_cursor.cc_color;
1124 
1125 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 0);
1126 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[0]);
1127 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[2]);
1128 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[4]);
1129 
1130 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 1);
1131 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[1]);
1132 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[3]);
1133 		bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[5]);
1134 
1135 		/* restore access to the normal palette */
1136 		igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, curctl);
1137 	}
1138 
1139 	if (which & WSDISPLAY_CURSOR_DOCUR) {
1140 		if ((curctl & IGS_EXT_SPRITE_VISIBLE) == 0
1141 		    && dc->dc_curenb)
1142 			igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
1143 				      curctl | IGS_EXT_SPRITE_VISIBLE);
1144 		else if ((curctl & IGS_EXT_SPRITE_VISIBLE) != 0
1145 			 && !dc->dc_curenb)
1146 			igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL,
1147 				      curctl & ~IGS_EXT_SPRITE_VISIBLE);
1148 	}
1149 }
1150 
1151 
1152 /*
1153  * wsdisplay_accessops: alloc_screen()
1154  */
1155 static int
1156 igsfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
1157 	void *v;
1158 	const struct wsscreen_descr *type;
1159 	void **cookiep;
1160 	int *curxp, *curyp;
1161 	long *attrp;
1162 {
1163 	struct igsfb_devconfig *dc = v;
1164 	struct rasops_info *ri = &dc->dc_ri;
1165 
1166 	if (dc->dc_nscreens > 0) /* only do single screen for now */
1167 		return (ENOMEM);
1168 
1169 	dc->dc_nscreens = 1;
1170 
1171 	*cookiep = ri;		/* emulcookie for igsgfb_stdscreen.textops */
1172 	*curxp = *curyp = 0;	/* cursor position */
1173 	(*ri->ri_ops.allocattr)(ri,
1174 				WSCOL_BLACK, /* fg */
1175 				WSCOL_BLACK, /* bg */
1176 				0,           /* wsattr */
1177 				attrp);
1178 	return (0);
1179 }
1180 
1181 
1182 /*
1183  * wsdisplay_accessops: free_screen()
1184  */
1185 static void
1186 igsfb_free_screen(v, cookie)
1187 	void *v;
1188 	void *cookie;
1189 {
1190 
1191 	/* XXX */
1192 	return;
1193 }
1194 
1195 
1196 /*
1197  * wsdisplay_accessops: show_screen()
1198  */
1199 static int
1200 igsfb_show_screen(v, cookie, waitok, cb, cbarg)
1201 	void *v;
1202 	void *cookie;
1203 	int waitok;
1204 	void (*cb)(void *, int, int);
1205 	void *cbarg;
1206 {
1207 
1208 	/* XXX */
1209 	return (0);
1210 }
1211 
1212 
1213 
1214 /*
1215  * Accelerated text mode cursor that uses hardware sprite.
1216  */
1217 static void
1218 igsfb_accel_cursor(cookie, on, row, col)
1219 	void *cookie;
1220 	int on, row, col;
1221 {
1222 	struct rasops_info *ri = (struct rasops_info *)cookie;
1223 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1224 	struct igs_hwcursor *cc = &dc->dc_cursor;
1225 	u_int which;
1226 
1227 	ri->ri_crow = row;
1228 	ri->ri_ccol = col;
1229 
1230 	which = 0;
1231 	if (on) {
1232 		ri->ri_flg |= RI_CURSOR;
1233 
1234 		/* only bother to move the cursor if it's visible */
1235 		cc->cc_pos.x = ri->ri_xorigin
1236 			+ ri->ri_ccol * ri->ri_font->fontwidth;
1237 		cc->cc_pos.y = ri->ri_yorigin
1238 			+ ri->ri_crow * ri->ri_font->fontheight;
1239 		which |= WSDISPLAY_CURSOR_DOPOS;
1240 	} else
1241 		ri->ri_flg &= ~RI_CURSOR;
1242 
1243 	if (dc->dc_curenb != on) {
1244 		dc->dc_curenb = on;
1245 		which |= WSDISPLAY_CURSOR_DOCUR;
1246 	}
1247 
1248 	/* propagate changes to the device */
1249 	igsfb_update_cursor(dc, which);
1250 }
1251 
1252 
1253 
1254 /*
1255  * Accelerated raster ops that use graphic coprocessor.
1256  */
1257 
1258 static int
1259 igsfb_accel_wait(dc)
1260 	struct igsfb_devconfig *dc;
1261 {
1262 	bus_space_tag_t t = dc->dc_iot;
1263 	bus_space_handle_t h = dc->dc_coph;
1264 	int timo = 100000;
1265 	uint8_t reg;
1266 
1267 	while (timo--) {
1268 		reg = bus_space_read_1(t, h, IGS_COP_CTL_REG);
1269 		if ((reg & IGS_COP_CTL_BUSY) == 0)
1270 			return (0);
1271 	}
1272 
1273 	return (1);
1274 }
1275 
1276 
1277 static void
1278 igsfb_accel_copy(dc, src, dst, width, height)
1279 	struct igsfb_devconfig *dc;
1280 	uint32_t src, dst;
1281 	uint16_t width, height;
1282 {
1283 	bus_space_tag_t t = dc->dc_iot;
1284 	bus_space_handle_t h = dc->dc_coph;
1285 	uint32_t toend;
1286 	uint8_t drawcmd;
1287 
1288 	drawcmd = IGS_COP_DRAW_ALL;
1289 	if (dst > src) {
1290 		toend = dc->dc_ri.ri_width * (height - 1) + (width - 1);
1291 		src += toend;
1292 		dst += toend;
1293 		drawcmd |= IGS_COP_OCTANT_X_NEG | IGS_COP_OCTANT_Y_NEG;
1294 	}
1295 
1296 	igsfb_accel_wait(dc);
1297 	bus_space_write_1(t, h, IGS_COP_CTL_REG, 0);
1298 
1299 	bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S);
1300 
1301 	bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1);
1302 	bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1);
1303 
1304 	bus_space_write_4(t, h, IGS_COP_SRC_START_REG, src);
1305 	bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst);
1306 
1307 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, drawcmd);
1308 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG);
1309 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0);
1310 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG,
1311 			  IGS_COP_OP_PXBLT | IGS_COP_OP_FG_FROM_SRC);
1312 }
1313 
1314 static void
1315 igsfb_accel_fill(dc, color, dst, width, height)
1316 	struct igsfb_devconfig *dc;
1317 	uint32_t color;
1318 	uint32_t dst;
1319 	uint16_t width, height;
1320 {
1321 	bus_space_tag_t t = dc->dc_iot;
1322 	bus_space_handle_t h = dc->dc_coph;
1323 
1324 	igsfb_accel_wait(dc);
1325 	bus_space_write_1(t, h, IGS_COP_CTL_REG, 0);
1326 
1327 	bus_space_write_1(t, h, IGS_COP_FG_MIX_REG, IGS_COP_MIX_S);
1328 
1329 	bus_space_write_2(t, h, IGS_COP_WIDTH_REG, width - 1);
1330 	bus_space_write_2(t, h, IGS_COP_HEIGHT_REG, height - 1);
1331 
1332 	bus_space_write_4(t, h, IGS_COP_DST_START_REG, dst);
1333 	bus_space_write_4(t, h, IGS_COP_FG_REG, color);
1334 
1335 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_0_REG, IGS_COP_DRAW_ALL);
1336 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_1_REG, IGS_COP_PPM_FIXED_FG);
1337 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_2_REG, 0);
1338 	bus_space_write_1(t, h, IGS_COP_PIXEL_OP_3_REG, IGS_COP_OP_PXBLT);
1339 }
1340 
1341 
1342 static void
1343 igsfb_accel_copyrows(cookie, src, dst, num)
1344 	void *cookie;
1345 	int src, dst, num;
1346 {
1347 	struct rasops_info *ri = (struct rasops_info *)cookie;
1348 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1349 	uint32_t srp, dsp;
1350 	uint16_t width, height;
1351 
1352 	width = ri->ri_emuwidth;
1353 	height = num * ri->ri_font->fontheight;
1354 
1355 	srp = ri->ri_xorigin
1356 		+ ri->ri_width * (ri->ri_yorigin
1357 				  + src * ri->ri_font->fontheight);
1358 	dsp = ri->ri_xorigin
1359 		+ ri->ri_width * (ri->ri_yorigin
1360 				  + dst * ri->ri_font->fontheight);
1361 
1362 	igsfb_accel_copy(dc, srp, dsp, width, height);
1363 }
1364 
1365 
1366 void
1367 igsfb_accel_copycols(cookie, row, src, dst, num)
1368 	void *cookie;
1369 	int row, src, dst, num;
1370 {
1371 	struct rasops_info *ri = (struct rasops_info *)cookie;
1372 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1373 	uint32_t rowp, srp, dsp;
1374 	uint16_t width, height;
1375 
1376 	width = num * ri->ri_font->fontwidth;
1377 	height = ri->ri_font->fontheight;
1378 
1379 	rowp = ri->ri_xorigin
1380 		+ ri->ri_width * (ri->ri_yorigin
1381 				  + row * ri->ri_font->fontheight);
1382 
1383 	srp = rowp + src * ri->ri_font->fontwidth;
1384 	dsp = rowp + dst * ri->ri_font->fontwidth;
1385 
1386 	igsfb_accel_copy(dc, srp, dsp, width, height);
1387 }
1388 
1389 
1390 static void
1391 igsfb_accel_eraserows(cookie, row, num, attr)
1392 	void *cookie;
1393 	int row, num;
1394 	long attr;
1395 {
1396 	struct rasops_info *ri = (struct rasops_info *)cookie;
1397 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1398 	uint32_t color;
1399 	uint32_t dsp;
1400 	uint16_t width, height;
1401 
1402 	width = ri->ri_emuwidth;
1403 	height = num * ri->ri_font->fontheight;
1404 
1405 	dsp = ri->ri_xorigin
1406 		+ ri->ri_width * (ri->ri_yorigin
1407 				  + row * ri->ri_font->fontheight);
1408 
1409 	/* XXX: we "know" the encoding that rasops' allocattr uses */
1410 	color = (attr >> 16) & 0xff;
1411 
1412 	igsfb_accel_fill(dc, color, dsp, width, height);
1413 }
1414 
1415 
1416 void
1417 igsfb_accel_erasecols(cookie, row, col, num, attr)
1418 	void *cookie;
1419 	int row, col, num;
1420 	long attr;
1421 {
1422 	struct rasops_info *ri = (struct rasops_info *)cookie;
1423 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1424 	uint32_t color;
1425 	uint32_t rowp, dsp;
1426 	uint16_t width, height;
1427 
1428 	width = num * ri->ri_font->fontwidth;
1429 	height = ri->ri_font->fontheight;
1430 
1431 	rowp = ri->ri_xorigin
1432 		+ ri->ri_width * (ri->ri_yorigin
1433 				  + row * ri->ri_font->fontheight);
1434 
1435 	dsp = rowp + col * ri->ri_font->fontwidth;
1436 
1437 	/* XXX: we "know" the encoding that rasops' allocattr uses */
1438 	color = (attr >> 16) & 0xff;
1439 
1440 	igsfb_accel_fill(dc, color, dsp, width, height);
1441 }
1442 
1443 
1444 /*
1445  * Not really implemented here, but we need to hook into the one
1446  * supplied by rasops so that we can synchronize with the COP.
1447  */
1448 static void
1449 igsfb_accel_putchar(cookie, row, col, uc, attr)
1450 	void *cookie;
1451 	int row, col;
1452 	u_int uc;
1453 	long attr;
1454 {
1455 	struct rasops_info *ri = (struct rasops_info *)cookie;
1456 	struct igsfb_devconfig *dc = (struct igsfb_devconfig *)ri->ri_hw;
1457 
1458 	igsfb_accel_wait(dc);
1459 	(*dc->dc_ri_putchar)(cookie, row, col, uc, attr);
1460 }
1461