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