vgafb.c revision 1.43
1/*	$OpenBSD: vgafb.c,v 1.43 2013/06/04 02:09:00 mpi 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#include <macppc/macppc/ofw_machdep.h>
44
45#include <dev/wscons/wsconsio.h>
46#include <dev/wscons/wsdisplayvar.h>
47#include <dev/rasops/rasops.h>
48#include <dev/wsfont/wsfont.h>
49
50#include <macppc/pci/vgafbvar.h>
51
52struct cfdriver vgafb_cd = {
53	NULL, "vgafb", DV_DULL,
54};
55
56void vgafb_setcolor(struct vga_config *vc, unsigned int index,
57		    u_int8_t r, u_int8_t g, u_int8_t b);
58void vgafb_restore_default_colors(struct vga_config *vc);
59
60extern struct vga_config vgafbcn;
61
62struct wsscreen_descr vgafb_stdscreen = {
63	"std",
64	0, 0,   /* will be filled in -- XXX shouldn't, it's global */
65	0,
66	0, 0,
67	WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
68	WSSCREEN_REVERSE | WSSCREEN_WSCOLORS
69};
70const struct wsscreen_descr *vgafb_scrlist[] = {
71	&vgafb_stdscreen,
72	/* XXX other formats, graphics screen? */
73};
74
75struct wsscreen_list vgafb_screenlist = {
76	sizeof(vgafb_scrlist) / sizeof(struct wsscreen_descr *), vgafb_scrlist
77};
78
79struct wsdisplay_accessops vgafb_accessops = {
80	vgafb_ioctl,
81	vgafb_mmap,
82	vgafb_alloc_screen,
83	vgafb_free_screen,
84	vgafb_show_screen,
85	NULL,		/* load_font */
86	NULL,		/* scrollback */
87	NULL,		/* getchar */
88	vgafb_burn,	/* burner */
89};
90
91int	vgafb_getcmap(struct vga_config *vc, struct wsdisplay_cmap *cm);
92int	vgafb_putcmap(struct vga_config *vc, struct wsdisplay_cmap *cm);
93
94#define FONT_WIDTH 8
95#define FONT_HEIGHT 16
96
97#ifdef APERTURE
98extern int allowaperture;
99#endif
100
101
102void
103vgafb_init(bus_space_tag_t iot, bus_space_tag_t memt, struct vga_config *vc,
104    u_int32_t  membase, size_t memsize, u_int32_t mmiobase, size_t mmiosize)
105{
106	vc->vc_iot = iot;
107	vc->vc_memt = memt;
108	vc->vc_paddr = membase;
109
110	if (mmiosize != 0)
111	       if (bus_space_map(vc->vc_memt, mmiobase, mmiosize, 0,
112		   &vc->vc_mmioh))
113			panic("vgafb_init: couldn't map mmio");
114
115	/* memsize should only be visible region for console */
116	memsize = cons_height * cons_linebytes;
117	if (bus_space_map(vc->vc_memt, membase, memsize,
118	    /* XXX */ppc_proc_is_64b ? 0 : 1, &vc->vc_memh))
119		panic("vgafb_init: can't map mem space");
120
121	if (cons_depth == 8)
122		vgafb_restore_default_colors(vc);
123}
124
125void
126vgafb_restore_default_colors(struct vga_config *vc)
127{
128	int i;
129
130	for (i = 0; i < 256; i++) {
131		const u_char *color;
132
133		color = &rasops_cmap[i * 3];
134		vgafb_setcolor(vc, i, color[0], color[1], color[2]);
135	}
136}
137
138void
139vgafb_wsdisplay_attach(struct device *parent, struct vga_config *vc,
140    int console)
141{
142	struct wsemuldisplaydev_attach_args aa;
143
144	aa.console = console;
145	aa.scrdata = &vgafb_screenlist;
146	aa.accessops = &vgafb_accessops;
147	aa.accesscookie = vc;
148	aa.defaultscreens = 0;
149
150	/* no need to keep the burner function if no hw support */
151	if (cons_backlight_available == 0)
152		vgafb_accessops.burn_screen = NULL;
153	else {
154		vc->vc_backlight_on = WSDISPLAYIO_VIDEO_OFF;
155		vgafb_burn(vc, WSDISPLAYIO_VIDEO_ON, 0);	/* paranoia */
156	}
157
158	config_found(parent, &aa, wsemuldisplaydevprint);
159}
160
161int
162vgafb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
163{
164	struct vga_config *vc = v;
165	struct wsdisplay_fbinfo *wdf;
166
167	switch (cmd) {
168	case WSDISPLAYIO_GTYPE:
169		*(u_int *)data = WSDISPLAY_TYPE_PCIVGA;
170		return 0;
171	case WSDISPLAYIO_GINFO:
172		wdf = (void *)data;
173		wdf->height = cons_height;
174		wdf->width  = cons_width;
175		wdf->depth  = cons_depth;
176		wdf->cmsize = 256;
177		return 0;
178
179	case WSDISPLAYIO_LINEBYTES:
180		*(u_int *)data = cons_linebytes;
181		return 0;
182
183	case WSDISPLAYIO_GETCMAP:
184		return vgafb_getcmap(vc, (struct wsdisplay_cmap *)data);
185
186	case WSDISPLAYIO_PUTCMAP:
187		return vgafb_putcmap(vc, (struct wsdisplay_cmap *)data);
188
189	case WSDISPLAYIO_SMODE:
190		vc->vc_mode = *(u_int *)data;
191		/* track the state of the display,
192		 * if returning to WSDISPLAYIO_MODE_EMUL
193		 * restore the last palette, workaround for
194		 * bad accellerated X servers that does not restore
195		 * the correct palette.
196		 */
197		if (cons_depth == 8)
198			vgafb_restore_default_colors(vc);
199		break;
200
201	case WSDISPLAYIO_GETPARAM:
202	{
203		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
204
205		switch (dp->param) {
206		case WSDISPLAYIO_PARAM_BRIGHTNESS:
207			if (cons_backlight_available != 0) {
208				dp->min = MIN_BRIGHTNESS;
209				dp->max = MAX_BRIGHTNESS;
210				dp->curval = cons_brightness;
211				return 0;
212			}
213			return -1;
214		case WSDISPLAYIO_PARAM_BACKLIGHT:
215			if (cons_backlight_available != 0) {
216				dp->min = 0;
217				dp->max = 1;
218				dp->curval = vc->vc_backlight_on;
219				return 0;
220			} else
221				return -1;
222		}
223	}
224		return -1;
225
226	case WSDISPLAYIO_SETPARAM:
227	{
228		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
229
230		switch (dp->param) {
231		case WSDISPLAYIO_PARAM_BRIGHTNESS:
232			if (cons_backlight_available == 1) {
233				of_setbrightness(dp->curval);
234				return 0;
235			} else
236				return -1;
237		case WSDISPLAYIO_PARAM_BACKLIGHT:
238			if (cons_backlight_available != 0) {
239				vgafb_burn(vc,
240				    dp->curval ? WSDISPLAYIO_VIDEO_ON :
241				      WSDISPLAYIO_VIDEO_OFF, 0);
242				return 0;
243			} else
244				return -1;
245		}
246	}
247		return -1;
248
249	case WSDISPLAYIO_SVIDEO:
250	case WSDISPLAYIO_GVIDEO:
251		break;
252
253	case WSDISPLAYIO_GCURPOS:
254	case WSDISPLAYIO_SCURPOS:
255	case WSDISPLAYIO_GCURMAX:
256	case WSDISPLAYIO_GCURSOR:
257	case WSDISPLAYIO_SCURSOR:
258	default:
259		return -1; /* not supported yet */
260	}
261
262	return (0);
263}
264
265paddr_t
266vgafb_mmap(void *v, off_t off, int prot)
267{
268	struct vga_config *vc = v;
269
270	if (off & PGOFSET)
271		return (-1);
272
273	switch (vc->vc_mode) {
274	case WSDISPLAYIO_MODE_MAPPED:
275#ifdef APERTURE
276		if (allowaperture == 0)
277			return (-1);
278#endif
279
280		if (vc->mmiosize == 0)
281			return (-1);
282
283		if (off >= vc->membase && off < (vc->membase + vc->memsize))
284			return (off);
285
286		 if (off >= vc->mmiobase && off < (vc->mmiobase+vc->mmiosize))
287			return (off);
288		break;
289
290	case WSDISPLAYIO_MODE_DUMBFB:
291		if (off >= 0x00000 && off < vc->memsize)
292			return (vc->vc_paddr + off);
293		break;
294
295	}
296
297	return (-1);
298}
299
300int
301vgafb_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
302{
303	struct vga_config *vc = &vgafbcn;
304	struct rasops_info *ri = &vc->ri;
305	long defattr;
306	int i;
307
308	vgafb_init(iot, memt, vc, cons_addr, cons_linebytes * cons_height,0, 0);
309
310	ri->ri_flg = RI_CENTER;
311	ri->ri_depth = cons_depth;
312	ri->ri_bits = (void *)vc->vc_memh;
313	ri->ri_width = cons_width;
314	ri->ri_height = cons_height;
315	ri->ri_stride = cons_linebytes;
316	ri->ri_hw = vc;
317
318	/* Clear the screen */
319	for (i = 0; i < cons_linebytes * cons_height; i++)
320		bus_space_write_1(memt,	vc->vc_memh, i, 0);
321
322	rasops_init(ri, 160, 160);	/* XXX */
323
324	vgafb_stdscreen.nrows = ri->ri_rows;
325	vgafb_stdscreen.ncols = ri->ri_cols;
326	vgafb_stdscreen.textops = &ri->ri_ops;
327
328	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
329
330	wsdisplay_cnattach(&vgafb_stdscreen, ri, 0, 0, defattr);
331	vc->nscreens++;
332
333	return (0);
334}
335
336struct {
337	u_int8_t r;
338	u_int8_t g;
339	u_int8_t b;
340} vgafb_color[256];
341
342void
343vgafb_setcolor(struct vga_config *vc, unsigned int index, u_int8_t r,
344    u_int8_t g, u_int8_t b)
345{
346	vc->vc_cmap_red[index] = r;
347	vc->vc_cmap_green[index] = g;
348	vc->vc_cmap_blue[index] = b;
349
350	vgafb_color[index].r = r;
351	vgafb_color[index].g = g;
352	vgafb_color[index].b = b;
353	OF_call_method_1("set-colors", cons_display_ofh, 3,
354	    &vgafb_color[index], index, 1);
355}
356
357int
358vgafb_getcmap(struct vga_config *vc, struct wsdisplay_cmap *cm)
359{
360	u_int index = cm->index;
361	u_int count = cm->count;
362	int error;
363
364	if (index >= 256 || count > 256 - index)
365		return EINVAL;
366
367	error = copyout(&vc->vc_cmap_red[index],   cm->red,   count);
368	if (error)
369		return error;
370	error = copyout(&vc->vc_cmap_green[index], cm->green, count);
371	if (error)
372		return error;
373	error = copyout(&vc->vc_cmap_blue[index],  cm->blue,  count);
374	if (error)
375		return error;
376
377	return 0;
378}
379
380int
381vgafb_putcmap(struct vga_config *vc, struct wsdisplay_cmap *cm)
382{
383	u_int index = cm->index;
384	u_int count = cm->count;
385	u_int i;
386	int error;
387	u_int8_t *r, *g, *b;
388
389	if (index >= 256 || count > 256 - index)
390		return EINVAL;
391
392	if ((error = copyin(cm->red, &vc->vc_cmap_red[index], count)) != 0)
393		return (error);
394	if ((error = copyin(cm->green, &vc->vc_cmap_green[index], count)) != 0)
395		return (error);
396	if ((error = copyin(cm->blue, &vc->vc_cmap_blue[index], count)) != 0)
397		return (error);
398
399	r = &(vc->vc_cmap_red[index]);
400	g = &(vc->vc_cmap_green[index]);
401	b = &(vc->vc_cmap_blue[index]);
402
403	for (i = 0; i < count; i++) {
404		vgafb_color[i].r = *r;
405		vgafb_color[i].g = *g;
406		vgafb_color[i].b = *b;
407		r++, g++, b++;
408	}
409	OF_call_method_1("set-colors", cons_display_ofh, 3,
410	    &vgafb_color, index, count);
411	return 0;
412}
413
414void
415vgafb_burn(void *v, u_int on, u_int flags)
416{
417	struct vga_config *vc = v;
418
419	if (cons_backlight_available == 1 &&
420	    vc->vc_backlight_on != on) {
421		if (on == WSDISPLAYIO_VIDEO_ON) {
422			OF_call_method_1("backlight-on", cons_display_ofh, 0);
423		} else {
424			OF_call_method_1("backlight-off", cons_display_ofh, 0);
425		}
426		vc->vc_backlight_on = on;
427	}
428}
429
430int
431vgafb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
432    int *curxp, int *curyp, long *attrp)
433{
434	struct vga_config *vc = v;
435	struct rasops_info *ri = &vc->ri;
436
437	if (vc->nscreens > 0)
438		return (ENOMEM);
439
440	*cookiep = ri;
441	*curxp = 0;
442	*curyp = 0;
443	ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
444	vc->nscreens++;
445
446	return (0);
447}
448
449void
450vgafb_free_screen(void *v, void *cookie)
451{
452	struct vga_config *vc = v;
453
454	if (vc == &vgafbcn)
455		panic("vgafb_free_screen: console");
456
457	vc->nscreens--;
458}
459
460int
461vgafb_show_screen(void *v, void *cookie, int waitok,
462    void (*cb)(void *, int, int), void *cbarg)
463{
464	return (0);
465}
466