1 /*	$OpenBSD: tvtwo.c,v 1.15 2008/03/15 21:10:34 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 2003, 2006, 2008, Miodrag Vallat.
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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 /*
31  * Driver for the Parallax XVideo and PowerVideo graphics boards.
32  *
33  * Some details about these board used to be available at:
34  *   http://www.jlw.com/~woolsey/parallax/support/developers/xvideotech.html
35  */
36 
37 /*
38  * The Parallax XVideo series frame buffers are 8/24-bit accelerated
39  * frame buffers, with hardware MPEG capabilities using a CCube chipset.
40  */
41 
42 /*
43  * Currently, this driver can only handle the 8-bit and 24-bit planes of the
44  * frame buffer, in an unaccelerated mode.
45  *
46  * TODO:
47  * - nvram handling
48  * - use the accelerator
49  * - interface to the c^3
50  */
51 
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/buf.h>
55 #include <sys/device.h>
56 #include <sys/ioctl.h>
57 #include <sys/mman.h>
58 #include <sys/conf.h>
59 
60 #include <uvm/uvm_extern.h>
61 
62 #include <machine/autoconf.h>
63 #include <machine/pmap.h>
64 #include <machine/cpu.h>
65 #include <machine/conf.h>
66 
67 #include <dev/wscons/wsconsio.h>
68 #include <dev/wscons/wsdisplayvar.h>
69 #include <dev/rasops/rasops.h>
70 #include <machine/fbvar.h>
71 
72 #include <sparc/dev/sbusvar.h>
73 
74 /*
75  * The memory layout of the board is as follows:
76  *
77  *	PROM0		000000 - 00ffff
78  *	overlay plane	010000 - 037fff
79  *	registers	040000 - 0404d0
80  *	CCube		050000 - 05ffff
81  *	8-bit plane	080000 - 17ffff
82  *	24-bit plane	200000 - 6fffff
83  *	PROM1		7f0000 - 7fffff
84  */
85 
86 #define	PX_PROM0_OFFSET		0x000000
87 #define	PX_OVERLAY_OFFSET	0x010000
88 #define	PX_REG_OFFSET		0x040000
89 #define	PX_CCUBE_OFFSET		0x050000
90 #define	PX_PLANE8_OFFSET	0x080000
91 #define	PX_PLANE24_OFFSET	0x200000
92 #define	PX_PROM1_OFFSET		0x7f0000
93 
94 #define	PX_MAP_SIZE		0x800000
95 
96 /*
97  * Partial registers layout
98  */
99 
100 #define	PX_REG_DISPKLUGE	0x00b8	/* write only */
101 #define	DISPKLUGE_DEFAULT	0xc41f
102 #define	DISPKLUGE_BLANK		(1 << 12)
103 #define	DISPKLUGE_SYNC		(1 << 13)
104 
105 #define	PX_REG_BT463_RED	0x0480
106 #define	PX_REG_BT463_GREEN	0x0490
107 #define	PX_REG_BT463_BLUE	0x04a0
108 #define	PX_REG_BT463_ALL	0x04b0
109 
110 #define	PX_REG_SIZE		0x04d0
111 
112 
113 /* per-display variables */
114 struct tvtwo_softc {
115 	struct	sunfb	sc_sunfb;	/* common base device */
116 	struct	rom_reg sc_phys;
117 
118 	volatile u_int8_t *sc_m8;
119 	volatile u_int8_t *sc_m24;
120 	volatile u_int8_t *sc_regs;
121 };
122 
123 int	tvtwo_ioctl(void *, u_long, caddr_t, int, struct proc *);
124 paddr_t	tvtwo_mmap(void *, off_t, int);
125 void	tvtwo_burner(void *, u_int, u_int);
126 
127 struct wsdisplay_accessops tvtwo_accessops = {
128 	tvtwo_ioctl,
129 	tvtwo_mmap,
130 	NULL,	/* alloc_screen */
131 	NULL,	/* free_screen */
132 	NULL,	/* show_screen */
133 	NULL,	/* load_font */
134 	NULL,	/* scrollback */
135 	NULL,	/* getchar */
136 	tvtwo_burner,
137 	NULL	/* pollc */
138 };
139 
140 void	tvtwo_directcmap(struct tvtwo_softc *);
141 static __inline__
142 void	tvtwo_ramdac_wraddr(struct tvtwo_softc *, u_int32_t);
143 void	tvtwo_reset(struct tvtwo_softc *, u_int);
144 void	tvtwo_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
145 
146 int	tvtwomatch(struct device *, void *, void *);
147 void	tvtwoattach(struct device *, struct device *, void *);
148 
149 struct cfattach tvtwo_ca = {
150 	sizeof(struct tvtwo_softc), tvtwomatch, tvtwoattach
151 };
152 
153 struct cfdriver tvtwo_cd = {
154 	NULL, "tvtwo", DV_DULL
155 };
156 
157 /*
158  * Default frame buffer resolution, depending upon the "freqcode"
159  */
160 #define	NFREQCODE	5
161 const int defwidth[NFREQCODE] = { 1152, 1152, 1152, 1024, 640 };
162 const int defheight[NFREQCODE] = { 900, 900, 900, 768, 480 };
163 
164 /*
165  * Match an XVideo or PowerVideo card.
166  */
167 int
tvtwomatch(struct device * parent,void * vcf,void * aux)168 tvtwomatch(struct device *parent, void *vcf, void *aux)
169 {
170 	struct confargs *ca = aux;
171 	struct romaux *ra = &ca->ca_ra;
172 
173 	if (strcmp(ra->ra_name, "PGI,tvtwo") == 0 ||
174 	    strcmp(ra->ra_name, "PGI,tvthree") == 0)
175 		return (1);
176 
177 	return (0);
178 }
179 
180 void
tvtwoattach(struct device * parent,struct device * self,void * args)181 tvtwoattach(struct device *parent, struct device *self, void *args)
182 {
183 	struct tvtwo_softc *sc = (struct tvtwo_softc *)self;
184 	struct confargs *ca = args;
185 	int node, width, height, freqcode;
186 	int isconsole;
187 	char *freqstring, *revision;
188 
189 	node = ca->ca_ra.ra_node;
190 
191 	printf(": %s", getpropstring(node, "model"));
192 	revision = getpropstring(node, "revision");
193 	if (*revision != '\0')
194 		printf(", revision %s", revision);
195 
196 	/*
197 	 * Older XVideo provide two sets of SBus registers:
198 	 *	R0		040000 - 040800
199 	 *	R1		080000 - 17d200
200 	 * While the more recent revisions provide only one register:
201 	 *	R0		000000 - 7fffff
202 	 *
203 	 * We'll simply ``rewrite'' R0 on older boards and handle them as
204 	 * recent boards.
205 	 */
206 	if (ca->ca_ra.ra_nreg > 1) {
207 		ca->ca_ra.ra_paddr =
208 		    (void *)((vaddr_t)ca->ca_ra.ra_paddr - PX_REG_OFFSET);
209 		ca->ca_ra.ra_len = PX_MAP_SIZE;
210 	}
211 
212 	isconsole = node == fbnode;
213 
214 	/* Map registers. */
215 	sc->sc_regs = mapiodev(ca->ca_ra.ra_reg, PX_REG_OFFSET, PX_REG_SIZE);
216 
217 	/*
218 	 * Compute framebuffer size.
219 	 * Older boards do not have the ``freqcode'' property and are
220 	 * restricted to 1152x900.
221 	 */
222 	freqstring = getpropstring(node, "freqcode");
223 	if (*freqstring != '\0') {
224 		freqcode = (int)*freqstring;
225 		if (freqcode == 'g') {
226 			width = height = 1024;
227 		} else {
228 			if (freqcode < '1' || freqcode > NFREQCODE + '0')
229 				freqcode = 0;
230 			else
231 				freqcode -= '1';
232 			width = defwidth[freqcode];
233 			height = defheight[freqcode];
234 
235 			/* in case our table is wrong or incomplete... */
236 			width = getpropint(node, "hres", width);
237 			height = getpropint(node, "vres", height);
238 		}
239 	} else {
240 		width = 1152;
241 		height = 900;
242 	}
243 
244 	/*
245 	 * Since the depth property is missing, we could do
246 	 * fb_setsize(&sc->sc_sunfb, 8, width, height, node, ca->ca_bustype);
247 	 * but for safety in case it would exist and be set to 32, do it
248 	 * manually...
249 	 */
250 	sc->sc_sunfb.sf_depth = 8;
251 	sc->sc_sunfb.sf_width = width;
252 	sc->sc_sunfb.sf_height = height;
253 	sc->sc_sunfb.sf_linebytes = width >= 1024 ? width : 1024;
254 	sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_linebytes * height;
255 
256 	printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
257 
258 	/* Map the frame buffer memory area we're interested in. */
259 	sc->sc_phys = ca->ca_ra.ra_reg[0];
260 	sc->sc_m8 = mapiodev(ca->ca_ra.ra_reg,
261 	    PX_PLANE8_OFFSET, round_page(sc->sc_sunfb.sf_fbsize));
262 	sc->sc_m24 = mapiodev(ca->ca_ra.ra_reg,
263 	    PX_PLANE24_OFFSET, round_page(4 * sc->sc_sunfb.sf_fbsize));
264 
265 	/* Enable video. */
266 	tvtwo_burner(sc, 1, 0);
267 
268 	sc->sc_sunfb.sf_ro.ri_hw = sc;
269 	sc->sc_sunfb.sf_ro.ri_bits = (u_char *)sc->sc_m8;
270 
271 	/*
272 	 * If the framebuffer width is under 1024, we will switch from
273 	 * the PROM font to the more adequate 8x16 font here.
274 	 */
275 	fbwscons_init(&sc->sc_sunfb,
276 	    isconsole && (width >= 1024) ? RI_CLEARMARGINS : RI_CLEAR);
277 	fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
278 
279 	if (isconsole) {
280 		fbwscons_console_init(&sc->sc_sunfb,
281 		    width >= 1024 ? -1 : 0);
282 	}
283 
284 	fbwscons_attach(&sc->sc_sunfb, &tvtwo_accessops, isconsole);
285 }
286 
287 int
tvtwo_ioctl(void * dev,u_long cmd,caddr_t data,int flags,struct proc * p)288 tvtwo_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p)
289 {
290 	struct tvtwo_softc *sc = dev;
291 	struct wsdisplay_fbinfo *wdf;
292 
293 	/*
294 	 * Note that, although the emulation (text) mode is running in a
295 	 * 8-bit plane, we advertize the frame buffer as 32-bit.
296 	 */
297 	switch (cmd) {
298 	case WSDISPLAYIO_GTYPE:
299 		*(u_int *)data = WSDISPLAY_TYPE_SUN24;
300 		break;
301 	case WSDISPLAYIO_GINFO:
302 		wdf = (struct wsdisplay_fbinfo *)data;
303 		wdf->height = sc->sc_sunfb.sf_height;
304 		wdf->width = sc->sc_sunfb.sf_width;
305 		wdf->depth = 32;
306 		wdf->cmsize = 0;
307 		break;
308 	case WSDISPLAYIO_GETSUPPORTEDDEPTH:
309 		*(u_int *)data = WSDISPLAYIO_DEPTH_24_32;
310 		break;
311 	case WSDISPLAYIO_LINEBYTES:
312 		*(u_int *)data = sc->sc_sunfb.sf_linebytes * 4;
313 		break;
314 
315 	case WSDISPLAYIO_GETCMAP:
316 	case WSDISPLAYIO_PUTCMAP:
317 		break;
318 
319 	case WSDISPLAYIO_SMODE:
320 		if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
321 			/* Back from X11 to text mode */
322 			tvtwo_reset(sc, 8);
323 		} else {
324 			/* Starting X11, initialize 32-bit mode */
325 			tvtwo_reset(sc, 32);
326 		}
327 		break;
328 
329 	case WSDISPLAYIO_SVIDEO:
330 	case WSDISPLAYIO_GVIDEO:
331 		break;
332 
333 	case WSDISPLAYIO_GCURPOS:
334 	case WSDISPLAYIO_SCURPOS:
335 	case WSDISPLAYIO_GCURMAX:
336 	case WSDISPLAYIO_GCURSOR:
337 	case WSDISPLAYIO_SCURSOR:
338 	default:
339 		return (-1);
340 	}
341 
342 	return (0);
343 }
344 
345 paddr_t
tvtwo_mmap(void * v,off_t offset,int prot)346 tvtwo_mmap(void *v, off_t offset, int prot)
347 {
348 	struct tvtwo_softc *sc = v;
349 
350 	if (offset & PGOFSET)
351 		return (-1);
352 
353 	/* Allow mapping as a dumb framebuffer from offset 0 */
354 	if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize * 4) {
355 		return (REG2PHYS(&sc->sc_phys,
356 		    PX_PLANE24_OFFSET + offset) | PMAP_NC);
357 	}
358 
359 	return (-1);
360 }
361 
362 void
tvtwo_burner(void * v,u_int on,u_int flags)363 tvtwo_burner(void *v, u_int on, u_int flags)
364 {
365 	struct tvtwo_softc *sc = v;
366 	u_int32_t dispkluge;
367 
368 	if (on)
369 		dispkluge = DISPKLUGE_DEFAULT & ~DISPKLUGE_BLANK;
370 	else {
371 		dispkluge = DISPKLUGE_DEFAULT | DISPKLUGE_BLANK;
372 		if (flags & WSDISPLAY_BURN_VBLANK)
373 			dispkluge |= DISPKLUGE_SYNC;
374 	}
375 
376 	*(volatile u_int32_t *)(sc->sc_regs + PX_REG_DISPKLUGE) = dispkluge;
377 }
378 
379 void
tvtwo_reset(struct tvtwo_softc * sc,u_int depth)380 tvtwo_reset(struct tvtwo_softc *sc, u_int depth)
381 {
382 	if (depth == 32) {
383 		/* Initialize a direct color map. */
384 		tvtwo_directcmap(sc);
385 	} else {
386 		fbwscons_setcolormap(&sc->sc_sunfb, tvtwo_setcolor);
387 	}
388 }
389 
390 /*
391  * Simple Bt463 programming routines.
392  */
393 
394 static __inline__ void
tvtwo_ramdac_wraddr(struct tvtwo_softc * sc,u_int32_t addr)395 tvtwo_ramdac_wraddr(struct tvtwo_softc *sc, u_int32_t addr)
396 {
397 	volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
398 
399 	dac[0] = (addr & 0xff);		/* lo addr */
400 	dac[1] = ((addr >> 8) & 0xff);	/* hi addr */
401 }
402 
403 void
tvtwo_directcmap(struct tvtwo_softc * sc)404 tvtwo_directcmap(struct tvtwo_softc *sc)
405 {
406 	volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
407 	u_int32_t c;
408 
409 	tvtwo_ramdac_wraddr(sc, 0);
410 	for (c = 0; c < 256; c++) {
411 		dac[3] = c;	/* R */
412 		dac[3] = c;	/* G */
413 		dac[3] = c;	/* B */
414 	}
415 }
416 
417 void
tvtwo_setcolor(void * v,u_int index,u_int8_t r,u_int8_t g,u_int8_t b)418 tvtwo_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
419 {
420 	struct tvtwo_softc *sc = v;
421 	volatile u_int32_t *dac = (u_int32_t *)(sc->sc_regs + PX_REG_BT463_RED);
422 
423 	tvtwo_ramdac_wraddr(sc, index);
424 	dac[3] = r;
425 	dac[3] = g;
426 	dac[3] = b;
427 }
428