vgafb.c revision 1.2
1/*	$OpenBSD: vgafb.c,v 1.2 2001/09/13 13:38:45 drahn Exp $	*/
2/*	$NetBSD: vga.c,v 1.3 1996/12/02 22:24:54 cgd Exp $	*/
3
4/*
5 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
6 * All rights reserved.
7 *
8 * Author: Chris G. Demetriou
9 *
10 * Permission to use, copy, modify and distribute this software and
11 * its documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
15 *
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23 *  School of Computer Science
24 *  Carnegie Mellon University
25 *  Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie the
28 * rights to redistribute these changes.
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/device.h>
35#include <sys/buf.h>
36
37#include <vm/vm.h>
38#include <uvm/uvm_extern.h>
39
40#include <machine/bus.h>
41
42#include <dev/cons.h>
43#include <dev/ofw/openfirm.h>
44
45#include <dev/wscons/wsconsio.h>
46#include <dev/wscons/wsdisplayvar.h>
47#include <dev/wscons/wscons_raster.h>
48#include <dev/rcons/raster.h>
49
50#include <arch/macppc/pci/vgafbvar.h>
51
52/* parameters set by OF to detect console */
53extern int cons_displaytype;
54extern bus_space_tag_t cons_membus;
55extern bus_space_handle_t cons_display_mem_h;
56extern bus_space_handle_t cons_display_ctl_h;
57extern int cons_width;
58extern int cons_linebytes;
59extern int cons_height;
60extern int cons_depth;
61extern int cons_display_ofh;
62
63struct cfdriver vgafb_cd = {
64	NULL, "vgafb", DV_DULL,
65};
66
67void	vgafb_cursor __P((void *, int, int, int));
68void	vgafb_putchar __P((void *, int, int, u_int, long));
69void	vgafb_copycols __P((void *, int, int, int, int));
70void	vgafb_erasecols __P((void *, int, int, int));
71void	vgafb_copyrows __P((void *, int, int, int));
72void	vgafb_eraserows __P((void *, int, int));
73void	vgafb_alloc_attr __P((void *c, int fg, int bg, int flags, long *));
74
75void vgafb_setcolor __P((unsigned int index, u_int8_t r, u_int8_t g, u_int8_t b));
76extern const char fontdata_8x16[];
77
78struct vgafb_devconfig {
79	struct rcons dc_ri;
80};
81struct raster vgafb_raster;
82
83
84struct vgafb_devconfig vgafb_console_dc;
85
86struct wsscreen_descr vgafb_stdscreen = {
87	"std",
88	0, 0,   /* will be filled in -- XXX shouldn't, it's global */
89	0,
90	0, 0,
91	WSSCREEN_REVERSE
92};
93const struct wsscreen_descr *vgafb_scrlist[] = {
94	&vgafb_stdscreen,
95	/* XXX other formats, graphics screen? */
96};
97
98struct wsscreen_list vgafb_screenlist = {
99	sizeof(vgafb_scrlist) / sizeof(struct wsscreen_descr *), vgafb_scrlist
100};
101
102
103struct wsdisplay_emulops vgafb_emulops = {
104	rcons_cursor,
105	rcons_mapchar,
106	rcons_putchar,
107	rcons_copycols,
108	rcons_erasecols,
109	rcons_copyrows,
110	rcons_eraserows,
111	rcons_alloc_attr
112};
113
114struct wsdisplay_accessops vgafb_accessops = {
115	vgafb_ioctl,
116	vgafb_mmap,
117	vgafb_alloc_screen,
118	vgafb_free_screen,
119	vgafb_show_screen,
120	0 /* load_font */
121};
122
123int	vgafb_print __P((void *, const char *));
124int	vgafb_getcmap __P((struct vgafb_config *vc, struct wsdisplay_cmap *cm));
125int	vgafb_putcmap __P((struct vgafb_config *vc, struct wsdisplay_cmap *cm));
126
127#define FONT_WIDTH 8
128#define FONT_HEIGHT 16
129
130/*
131 * The following functions implement back-end configuration grabbing
132 * and attachment.
133 */
134int
135vgafb_common_probe(iot, memt, iobase, iosize, membase, memsize, mmiobase, mmiosize)
136	bus_space_tag_t iot, memt;
137	u_int32_t iobase, membase, mmiobase;
138	size_t iosize, memsize, mmiosize;
139{
140	bus_space_handle_t ioh_b, ioh_c, ioh_d, memh, mmioh;
141	int gotio_b, gotio_c, gotio_d, gotmem, gotmmio, rv;
142
143	gotio_b = gotio_c = gotio_d = gotmem = gotmmio = rv = 0;
144
145	if (iosize != 0) {
146		if (bus_space_map(iot, iobase+0x3b0, 0xc, 0, &ioh_b))
147			goto bad;
148		gotio_b = 1;
149		if (bus_space_map(iot, iobase+0x3c0, 0x10, 0, &ioh_c))
150			goto bad;
151		gotio_c = 1;
152		if (bus_space_map(iot, iobase+0x3d0, 0x10, 0, &ioh_d))
153			goto bad;
154		gotio_d = 1;
155	}
156	if (mmiosize != 0) {
157		printf("vgafb_common_probe, mmio base %x size %x\n",
158			mmiobase, mmiosize);
159		if (bus_space_map(iot, mmiobase, mmiosize, 0, &mmioh))
160			goto bad;
161		printf("vgafb_common_probe, mmio done\n");
162		gotmmio = 1;
163	}
164#if 0
165	printf("vgafb_common_probe, mem base %x size %x memt %x\n",
166		membase, memsize, memt);
167#endif
168
169#if 0
170	if (bus_space_map(memt, membase, memsize, 0, &memh))
171		goto bad;
172	gotmem = 1;
173
174	/* CR1 - Horiz. Display End */
175	bus_space_write_1(iot, ioh_d, 4, 0x1);
176	width = bus_space_read_1(iot, ioh_d, 5);
177	/* this is not bit width yet */
178
179	/* use CR17 - mode control for this?? */
180	if ((width != 0xff) && (width < 600)) {
181		/* not accessable or in graphics mode? */
182		goto bad;
183	}
184#endif
185
186#if 0
187	vgadata = bus_space_read_2(memt, memh, 0);
188	bus_space_write_2(memt, memh, 0, 0xa55a);
189	rv = (bus_space_read_2(memt, memh, 0) == 0xa55a);
190	bus_space_write_2(memt, memh, 0, vgadata);
191#else
192	rv = 1;
193#endif
194
195
196bad:
197	if (gotio_b)
198		bus_space_unmap(iot, ioh_b, 0xc);
199	if (gotio_c)
200		bus_space_unmap(iot, ioh_c, 0x10);
201	if (gotio_d)
202		bus_space_unmap(iot, ioh_d, 0x10);
203	if (gotmmio)
204		bus_space_unmap(memt, mmioh, mmiosize);
205	if (gotmem)
206		bus_space_unmap(memt, memh, memsize);
207
208	return (rv);
209}
210
211void
212vgafb_common_setup(iot, memt, vc, iobase, iosize, membase, memsize, mmiobase, mmiosize)
213	bus_space_tag_t iot, memt;
214	struct vgafb_config *vc;
215	u_int32_t iobase, membase, mmiobase;
216	size_t iosize, memsize, mmiosize;
217{
218
219        vc->vc_iot = iot;
220        vc->vc_memt = memt;
221	vc->vc_paddr = membase;
222
223	if (iosize != 0) {
224           if (bus_space_map(vc->vc_iot, iobase+0x3b0, 0xc, 0, &vc->vc_ioh_b))
225		panic("vgafb_common_setup: couldn't map io b");
226           if (bus_space_map(vc->vc_iot, iobase+0x3c0, 0x10, 0, &vc->vc_ioh_c))
227		panic("vgafb_common_setup: couldn't map io c");
228           if (bus_space_map(vc->vc_iot, iobase+0x3d0, 0x10, 0, &vc->vc_ioh_d))
229		panic("vgafb_common_setup: couldn't map io d");
230	}
231	if (mmiosize != 0) {
232           if (bus_space_map(vc->vc_memt, mmiobase, mmiosize, 0, &vc->vc_mmioh))
233		panic("vgafb_common_setup: couldn't map mmio");
234	}
235#if 0
236	printf("commons setup mapping mem base %x size %x\n", membase, memsize);
237#endif
238	/* memsize  should only be visable region for console */
239	memsize = cons_height * cons_linebytes;
240        if (bus_space_map(vc->vc_memt, membase, memsize, 0, &vc->vc_memh))
241		panic("vgafb_common_setup: couldn't map memory");
242	cons_display_mem_h = vc->vc_memh;
243	vc->vc_ofh = cons_display_ofh;
244#if 0
245	printf("display_mem_h %x\n", cons_display_mem_h );
246#endif
247
248#if 0
249	if (iosize != 0) {
250		/* CR1 - Horiz. Display End */
251		bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x1);
252		width = bus_space_read_1(iot, vc->vc_ioh_d, 5);
253		/* (stored value + 1) * depth -> pixel width */
254		width = ( width + 1 ) * 8;
255
256		/* CR1 - Horiz. Display End */
257		bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x12);
258		{
259			u_int8_t t1, t2, t3;
260			bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x12);
261			t1 = bus_space_read_1(iot, vc->vc_ioh_d, 5);
262
263			bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x7);
264			t2 = bus_space_read_1(iot, vc->vc_ioh_d, 5);
265			height = t1 + ((t2&0x40) << 3)
266				    + ((t2&0x02) << 7) + 1;
267			bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x17);
268			t3 = bus_space_read_1(iot, vc->vc_ioh_d, 5);
269			if (t3 & 0x04) {
270				height *= 2;
271			}
272			if (t1 == 0xff && t2 == 0xff && t3 == 0xff) {
273				/* iospace not working??? */
274				/* hope, better guess than 2048x2048 */
275				width = 640;
276				height = 480;
277			}
278		}
279		vc->vc_ncol = width / FONT_WIDTH;
280		vc->vc_nrow = height / FONT_HEIGHT;
281	} else {
282		/* iosize == 0
283		 * default to 640x480 and hope
284		 */
285		vc->vc_ncol = 640 / FONT_WIDTH;
286		vc->vc_nrow = 480 / FONT_HEIGHT;
287	}
288	vc->vc_ncol = cons_width / FONT_WIDTH;
289	vc->vc_nrow = cons_height / FONT_HEIGHT;
290	printf(", %dx%d", vc->vc_ncol, vc->vc_nrow);
291#endif
292
293	vc->vc_crow = vc->vc_ccol = 0; /* Has to be some onscreen value */
294	vc->vc_so = 0;
295
296	/* clear screen, frob cursor, etc.? */
297	/*
298	*/
299
300#if defined(alpha)
301	/*
302	 * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!!
303	 * XXX Therefore, though the comments say "blue bg", the code uses
304	 * XXX the value for a red background!
305	 */
306	vc->vc_at = 0x40 | 0x0f;		/* blue bg|white fg */
307	vc->vc_so_at = 0x40 | 0x0f | 0x80;	/* blue bg|white fg|blink */
308#else
309	vc->vc_at = 0x00 | 0xf;			/* black bg|white fg */
310	vc->vc_so_at = 0x00 | 0xf | 0x80;	/* black bg|white fg|blink */
311#endif
312}
313
314void
315vgafb_wsdisplay_attach(parent, vc, console)
316	struct device *parent;
317	struct vgafb_config *vc;
318	int console;
319{
320	struct wsemuldisplaydev_attach_args aa;
321
322        aa.console = console;
323	aa.scrdata = &vgafb_screenlist;
324	aa.accessops = &vgafb_accessops;
325	aa.accesscookie = vc;
326
327        config_found(parent, &aa, wsemuldisplaydevprint);
328}
329
330
331int
332vgafb_print(aux, pnp)
333	void *aux;
334	const char *pnp;
335{
336
337	if (pnp)
338		printf("wsdisplay at %s", pnp);
339	return (UNCONF);
340}
341
342int
343vgafb_ioctl(v, cmd, data, flag, p)
344	void *v;
345	u_long cmd;
346	caddr_t data;
347	int flag;
348	struct proc *p;
349{
350	struct vgafb_config *vc = v;
351	struct wsdisplay_fbinfo *wdf;
352
353	switch (cmd) {
354	case WSDISPLAYIO_GTYPE:
355		*(u_int *)data = WSDISPLAY_TYPE_PCIVGA;
356		return 0;
357	case WSDISPLAYIO_GINFO:
358		wdf = (void *)data;
359		wdf->height = cons_height;
360		wdf->width  = cons_width;
361		wdf->depth  = cons_depth;
362		wdf->cmsize = 256;
363		return 0;
364
365	case WSDISPLAYIO_LINEBYTES:
366		*(u_int *)data = cons_linebytes;
367		return 0;
368
369	case WSDISPLAYIO_GETCMAP:
370		return vgafb_getcmap(vc, (struct wsdisplay_cmap *)data);
371
372	case WSDISPLAYIO_PUTCMAP:
373		return vgafb_putcmap(vc, (struct wsdisplay_cmap *)data);
374
375	case WSDISPLAYIO_SVIDEO:
376	case WSDISPLAYIO_GVIDEO:
377	case WSDISPLAYIO_GCURPOS:
378	case WSDISPLAYIO_SCURPOS:
379	case WSDISPLAYIO_GCURMAX:
380	case WSDISPLAYIO_GCURSOR:
381	case WSDISPLAYIO_SCURSOR:
382		return -1; /* not supported yet */
383	}
384
385        /* XXX */
386        return -1;
387}
388
389paddr_t
390vgafb_mmap(v, offset, prot)
391	void *v;
392	off_t offset;
393	int prot;
394{
395	struct vgafb_config *vc = v;
396	bus_space_handle_t h;
397
398	/* memsize... */
399	if (offset >= 0x00000 && offset < 0x800000)	/* 8MB of mem??? */
400		h = vc->vc_paddr + offset;
401	/* XXX the following are probably wrong. we want physical addresses
402	   here, not virtual ones */
403	else if (offset >= 0x10000000 && offset < 0x10040000 )
404		/* 256KB of iohb */
405		h = vc->vc_ioh_b;
406	else if (offset >= 0x10040000 && offset < 0x10080000)
407		/* 256KB of iohc */
408		h = vc->vc_ioh_c;
409	else if (offset >= 0x18880000 && offset < 0x100c0000)
410		/* 256KB of iohd */
411		h = vc->vc_ioh_d;
412	else if (offset >= 0x20000000 && offset < 0x30000000)
413		/* mmiosize... */
414		h = vc->vc_mmioh + (offset - 0x20000000);
415	else {
416		/* XXX - allow mapping of the actual physical
417		 * device address, if the address is read from
418		 * pci bus config space
419		 */
420
421		/* NEEDS TO BE RESTRICTED to valid addresses for this device */
422
423		h = offset;
424	}
425
426#ifdef alpha
427	port = (u_int32_t *)(h << 5);
428	return alpha_btop(port);		/* XXX */
429#elif defined(i386)
430	port = (u_int32_t *)(h << 5);
431	return i386_btop(port);
432#elif defined(__powerpc__)
433	{
434	/* huh ??? */
435	return h;
436	/*
437	return powerpc_btop(port);
438	*/
439	}
440#endif
441}
442
443
444void
445vgafb_cnprobe(cp)
446	struct consdev *cp;
447{
448	if (cons_displaytype != 1) {
449		cp->cn_pri = CN_DEAD;
450		return;
451	}
452
453	cp->cn_pri = CN_REMOTE;
454	#if 0
455	for (j = 0; j < 2; j++) {
456		for (i = 0; i < cons_width * cons_height; i++) {
457			bus_space_write_1(cons_membus,
458				cons_display_mem_h, i, j);
459
460		}
461	}
462	#endif
463
464}
465
466extern struct raster_font fontdata8x16;
467void
468vgafb_cnattach(iot, memt, pc, bus, device, function)
469	void * pc;
470	bus_space_tag_t iot, memt;
471	int bus, device, function;
472{
473        long defattr;
474
475	struct vgafb_devconfig *dc = &vgafb_console_dc;
476        struct rcons *ri = &dc->dc_ri;
477	ri->rc_sp = &vgafb_raster;
478
479	ri->rc_sp->width = cons_width;
480	ri->rc_sp->height = cons_height;
481	ri->rc_sp->depth = cons_depth;
482	ri->rc_sp->linelongs = cons_linebytes /4; /* XXX */
483	ri->rc_sp->pixels = (void *)cons_display_mem_h;
484	ri->rc_crow = ri->rc_ccol = -1;
485	ri->rc_crowp = &ri->rc_crow;
486	ri->rc_ccolp = &ri->rc_ccol;
487
488	rcons_init(ri, 160, 160);
489
490	vgafb_stdscreen.nrows = ri->rc_maxrow;
491	vgafb_stdscreen.ncols = ri->rc_maxcol;
492	vgafb_stdscreen.textops = &vgafb_emulops;
493	rcons_alloc_attr(ri, 0, 0, 0, &defattr);
494
495	#if 0
496	{
497		int i;
498		for (i = 0; i < cons_width * cons_height; i++) {
499			bus_space_write_1(cons_membus,
500				cons_display_mem_h, i, 0x1);
501
502		}
503	}
504	#endif
505	{
506	  int i;
507	  for (i = 0; i < 256; i++) {
508	     vgafb_setcolor(i, 255,255,255);
509	  }
510	}
511	vgafb_setcolor(WSCOL_BLACK, 0, 0, 0);
512	vgafb_setcolor(255, 255, 255, 255);
513	vgafb_setcolor(WSCOL_RED, 255, 0, 0);
514	vgafb_setcolor(WSCOL_GREEN, 0, 255, 0);
515	vgafb_setcolor(WSCOL_BROWN, 154, 85, 46);
516	vgafb_setcolor(WSCOL_BLUE, 0, 0, 255);
517	vgafb_setcolor(WSCOL_MAGENTA, 255, 255, 0);
518	vgafb_setcolor(WSCOL_CYAN, 0, 255, 255);
519	vgafb_setcolor(WSCOL_WHITE, 255, 255, 255);
520	wsdisplay_cnattach(&vgafb_stdscreen, ri, 0, 0, defattr);
521}
522
523void
524vgafb_setcolor(index, r, g, b)
525	unsigned int index;
526	u_int8_t r, g, b;
527{
528	OF_call_method_1("color!", cons_display_ofh, 4, r, g, b, index);
529}
530
531int
532vgafb_getcmap(vc, cm)
533	struct vgafb_config *vc;
534	struct wsdisplay_cmap *cm;
535{
536	u_int index = cm->index;
537	u_int count = cm->count;
538	int error;
539
540	if (index >= 256 || count > 256 || index + count > 256)
541		return EINVAL;
542
543	error = copyout(&vc->vc_cmap_red[index],   cm->red,   count);
544	if (error)
545		return error;
546	error = copyout(&vc->vc_cmap_green[index], cm->green, count);
547	if (error)
548		return error;
549	error = copyout(&vc->vc_cmap_blue[index],  cm->blue,  count);
550	if (error)
551		return error;
552
553	return 0;
554}
555
556int
557vgafb_putcmap(vc, cm)
558	struct vgafb_config *vc;
559	struct wsdisplay_cmap *cm;
560{
561	int index = cm->index;
562	int count = cm->count;
563	int i;
564	u_char *r, *g, *b;
565
566	if (cm->index >= 256 || cm->count > 256 ||
567	    (cm->index + cm->count) > 256)
568		return EINVAL;
569	if (!uvm_useracc(cm->red, cm->count, B_READ) ||
570	    !uvm_useracc(cm->green, cm->count, B_READ) ||
571	    !uvm_useracc(cm->blue, cm->count, B_READ))
572		return EFAULT;
573	copyin(cm->red,   &(vc->vc_cmap_red[index]),   count);
574	copyin(cm->green, &(vc->vc_cmap_green[index]), count);
575	copyin(cm->blue,  &(vc->vc_cmap_blue[index]),  count);
576
577	r = &(vc->vc_cmap_red[index]);
578	g = &(vc->vc_cmap_green[index]);
579	b = &(vc->vc_cmap_blue[index]);
580
581	for (i = 0; i < count; i++) {
582		OF_call_method_1("color!", vc->vc_ofh, 4, *r, *g, *b, index);
583		r++, g++, b++, index++;
584	}
585	return 0;
586}
587