1 /*
2  * VIDIX driver for 3DLabs Glint R3 and Permedia 3 chipsets.
3  * Copyright (C) 2002 Måns Rullgård
4  *
5  * This file is part of MPlayer.
6  *
7  * MPlayer is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * MPlayer is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <inttypes.h>
27 #include <unistd.h>
28 
29 #include "config.h"
30 #include "vidix.h"
31 #include "fourcc.h"
32 #include "dha.h"
33 #include "pci_ids.h"
34 #include "pci_names.h"
35 #include "mp_msg.h"
36 
37 #include "pm3_regs.h"
38 
39 #if 0
40 #define TRACE_ENTER() mp_msg(MSGT_VO, MSGL_DBG2, "[pm3] %s: enter\n", __FUNCTION__)
41 #define TRACE_EXIT() mp_msg(MSGT_VO, MSGL_DBG2, "[pm3] %s: exit\n", __FUNCTION__)
42 #else
43 #define TRACE_ENTER()
44 #define TRACE_EXIT()
45 #endif
46 
47 static pciinfo_t pci_info;
48 
49 void *pm3_reg_base;
50 static void *pm3_mem;
51 
52 static const vidix_capability_t pm3_cap =
53 {
54     "3DLabs GLINT R3/Permedia3 driver",
55     "Måns Rullgård <mru@users.sf.net>",
56     TYPE_OUTPUT,
57     { 0, 0, 0, 0 },
58     2048,
59     2048,
60     4,
61     4,
62     -1,
63     FLAG_UPSCALER|FLAG_DOWNSCALER,
64     VENDOR_3DLABS,
65     -1,
66     { 0, 0, 0, 0 }
67 };
68 
69 static unsigned short pm3_card_ids[] =
70 {
71     DEVICE_3DLABS_GLINT_R3
72 };
73 
find_chip(unsigned chip_id)74 static int find_chip(unsigned chip_id)
75 {
76   unsigned i;
77   for(i = 0;i < sizeof(pm3_card_ids)/sizeof(unsigned short);i++)
78   {
79     if(chip_id == pm3_card_ids[i]) return i;
80   }
81   return -1;
82 }
83 
pm3_probe(int verbose,int force)84 static int pm3_probe(int verbose, int force)
85 {
86     pciinfo_t lst[MAX_PCI_DEVICES];
87     unsigned i,num_pci;
88     int err;
89 
90     err = pci_scan(lst,&num_pci);
91     if(err)
92     {
93 	mp_msg(MSGT_VO, MSGL_STATUS, "[pm3] Error occurred during pci scan: %s\n",strerror(err));
94 	return err;
95     }
96     else
97     {
98 	err = ENXIO;
99 	for(i=0; i < num_pci; i++)
100 	{
101 	    if(lst[i].vendor == VENDOR_3DLABS)
102 	    {
103 		int idx;
104 		const char *dname;
105 		idx = find_chip(lst[i].device);
106 		if(idx == -1)
107 		    continue;
108 		dname = pci_device_name(VENDOR_3DLABS, lst[i].device);
109 		dname = dname ? dname : "Unknown chip";
110 		mp_msg(MSGT_VO, MSGL_STATUS, "[pm3] Found chip: %s\n", dname);
111 #if 0
112 		if ((lst[i].command & PCI_COMMAND_IO) == 0)
113 		{
114 			mp_msg(MSGT_VO, MSGL_STATUS, "[pm3] Device is disabled, ignoring\n");
115 			continue;
116 		}
117 #endif
118 		err = 0;
119 		memcpy(&pci_info, &lst[i], sizeof(pciinfo_t));
120 		break;
121 	    }
122 	}
123     }
124     if(err && verbose) mp_msg(MSGT_VO, MSGL_STATUS, "[pm3] Can't find chip\n");
125     return err;
126 }
127 
128 #define PRINT_REG(reg)							\
129 {									\
130     long _foo = READ_REG(reg);						\
131     mp_msg(MSGT_VO, MSGL_STATUS, "[pm3] " #reg " (%x) = %#lx (%li)\n", reg, _foo, _foo);	\
132 }
133 
pm3_init(void)134 static int pm3_init(void)
135 {
136     pm3_reg_base = map_phys_mem(pci_info.base0, 0x20000);
137     pm3_mem = map_phys_mem(pci_info.base2, 0x2000000);
138     return 0;
139 }
140 
pm3_destroy(void)141 static void pm3_destroy(void)
142 {
143     unmap_phys_mem(pm3_reg_base, 0x20000);
144     unmap_phys_mem(pm3_mem, 0x2000000);
145 }
146 
pm3_get_caps(vidix_capability_t * to)147 static int pm3_get_caps(vidix_capability_t *to)
148 {
149     memcpy(to, &pm3_cap, sizeof(vidix_capability_t));
150     to->device_id = pci_info.device;
151     return 0;
152 }
153 
is_supported_fourcc(uint32_t fourcc)154 static int is_supported_fourcc(uint32_t fourcc)
155 {
156     switch(fourcc){
157     case IMGFMT_YUY2:
158     case IMGFMT_UYVY:
159 	return 1;
160     default:
161 	return 0;
162     }
163 }
164 
pm3_query_fourcc(vidix_fourcc_t * to)165 static int pm3_query_fourcc(vidix_fourcc_t *to)
166 {
167     if(is_supported_fourcc(to->fourcc))
168     {
169 	to->depth = VID_DEPTH_ALL;
170 	to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY;
171 	return 0;
172     }
173     return ENOSYS;
174 }
175 
176 #define FORMAT_RGB8888	PM3VideoOverlayMode_COLORFORMAT_RGB8888
177 #define FORMAT_RGB4444	PM3VideoOverlayMode_COLORFORMAT_RGB4444
178 #define FORMAT_RGB5551	PM3VideoOverlayMode_COLORFORMAT_RGB5551
179 #define FORMAT_RGB565	PM3VideoOverlayMode_COLORFORMAT_RGB565
180 #define FORMAT_RGB332	PM3VideoOverlayMode_COLORFORMAT_RGB332
181 #define FORMAT_BGR8888	PM3VideoOverlayMode_COLORFORMAT_BGR8888
182 #define FORMAT_BGR4444	PM3VideoOverlayMode_COLORFORMAT_BGR4444
183 #define FORMAT_BGR5551	PM3VideoOverlayMode_COLORFORMAT_BGR5551
184 #define FORMAT_BGR565	PM3VideoOverlayMode_COLORFORMAT_BGR565
185 #define FORMAT_BGR332	PM3VideoOverlayMode_COLORFORMAT_BGR332
186 #define FORMAT_CI8	PM3VideoOverlayMode_COLORFORMAT_CI8
187 #define FORMAT_VUY444	PM3VideoOverlayMode_COLORFORMAT_VUY444
188 #define FORMAT_YUV444	PM3VideoOverlayMode_COLORFORMAT_YUV444
189 #define FORMAT_VUY422	PM3VideoOverlayMode_COLORFORMAT_VUY422
190 #define FORMAT_YUV422	PM3VideoOverlayMode_COLORFORMAT_YUV422
191 
192 /* Notice, have to check that we don't overflow the deltas here ... */
193 static void
compute_scale_factor(short * src_w,short * dst_w,uint32_t * shrink_delta,uint32_t * zoom_delta)194 compute_scale_factor(
195     short* src_w, short* dst_w,
196     uint32_t* shrink_delta, uint32_t* zoom_delta)
197 {
198     /* NOTE: If we don't return reasonable values here then the video
199      * unit can potential shut off and won't display an image until re-enabled.
200      * Seems as though the zoom_delta is o.k, and I've not had the problem.
201      * The 'shrink_delta' is prone to this the most - FIXME ! */
202 
203     if (*src_w >= *dst_w) {
204 	*src_w &= ~0x3;
205 	*dst_w &= ~0x3;
206 	*shrink_delta = (((*src_w << 16) / *dst_w) + 0x0f) & 0x0ffffff0;
207 	*zoom_delta = 1<<16;
208 	if ( ((*shrink_delta * *dst_w) >> 16) & 0x03 )
209 	    *shrink_delta += 0x10;
210     } else {
211 	*src_w &= ~0x3;
212 	*dst_w &= ~0x3;
213 	*zoom_delta = (((*src_w << 16) / *dst_w) + 0x0f) & 0x0001fff0;
214 	*shrink_delta = 1<<16;
215 	if ( ((*zoom_delta * *dst_w) >> 16) & 0x03 )
216 	    *zoom_delta += 0x10;
217     }
218 }
219 
220 static int frames[VID_PLAY_MAXFRAMES];
221 
222 static long overlay_mode, overlay_control;
223 
pm3_config_playback(vidix_playback_t * info)224 static int pm3_config_playback(vidix_playback_t *info)
225 {
226     uint32_t shrink, zoom;
227     short src_w, drw_w;
228     short src_h, drw_h;
229     long base0;
230     int pitch;
231     int format;
232     unsigned int i;
233 
234     TRACE_ENTER();
235 
236     if(!is_supported_fourcc(info->fourcc))
237 	return -1;
238 
239     switch(info->fourcc){
240     case IMGFMT_YUY2:
241 	format = FORMAT_YUV422;
242 	break;
243     case IMGFMT_UYVY:
244 	format = FORMAT_VUY422;
245 	break;
246     default:
247 	return -1;
248     }
249 
250     src_w = info->src.w;
251     src_h = info->src.h;
252 
253     drw_w = info->dest.w;
254     drw_h = info->dest.h;
255 
256     pitch = src_w;
257 
258     /* Assume we have 16 MB to play with */
259     info->num_frames = 0x1000000 / (pitch * src_h * 2);
260     if(info->num_frames > VID_PLAY_MAXFRAMES)
261 	info->num_frames = VID_PLAY_MAXFRAMES;
262 
263     /* Start at 16 MB. Let's hope it's not in use. */
264     base0 = 0x1000000;
265     info->dga_addr = pm3_mem + base0;
266 
267     info->dest.pitch.y = 2;
268     info->dest.pitch.u = 0;
269     info->dest.pitch.v = 0;
270     info->offset.y = 0;
271     info->offset.v = 0;
272     info->offset.u = 0;
273     info->frame_size = pitch * src_h * 2;
274     for(i = 0; i < info->num_frames; i++){
275 	info->offsets[i] = info->frame_size * i;
276 	frames[i] = (base0 + info->offsets[i]) >> 1;
277     }
278 
279     compute_scale_factor(&src_w, &drw_w, &shrink, &zoom);
280 
281     WRITE_REG(PM3VideoOverlayBase0, base0 >> 1);
282     WRITE_REG(PM3VideoOverlayStride, PM3VideoOverlayStride_STRIDE(pitch));
283     WRITE_REG(PM3VideoOverlayWidth, PM3VideoOverlayWidth_WIDTH(src_w));
284     WRITE_REG(PM3VideoOverlayHeight, PM3VideoOverlayHeight_HEIGHT(src_h));
285     WRITE_REG(PM3VideoOverlayOrigin, 0);
286 
287     /* Scale the source to the destinationsize */
288     if (src_h == drw_h) {
289 	WRITE_REG(PM3VideoOverlayYDelta, PM3VideoOverlayYDelta_NONE);
290     } else {
291 	WRITE_REG(PM3VideoOverlayYDelta,
292 		  PM3VideoOverlayYDelta_DELTA(src_h, drw_h));
293     }
294     if (src_w == drw_w) {
295     	WRITE_REG(PM3VideoOverlayShrinkXDelta, 1<<16);
296     	WRITE_REG(PM3VideoOverlayZoomXDelta, 1<<16);
297     } else {
298     	WRITE_REG(PM3VideoOverlayShrinkXDelta, shrink);
299     	WRITE_REG(PM3VideoOverlayZoomXDelta, zoom);
300     }
301     WRITE_REG(PM3VideoOverlayIndex, 0);
302 
303     /* Now set the ramdac video overlay region and mode */
304     RAMDAC_SET_REG(PM3RD_VideoOverlayXStartLow, (info->dest.x & 0xff));
305     RAMDAC_SET_REG(PM3RD_VideoOverlayXStartHigh, (info->dest.x & 0xf00)>>8);
306     RAMDAC_SET_REG(PM3RD_VideoOverlayXEndLow, (info->dest.x+drw_w) & 0xff);
307     RAMDAC_SET_REG(PM3RD_VideoOverlayXEndHigh,
308 		   ((info->dest.x+drw_w) & 0xf00)>>8);
309     RAMDAC_SET_REG(PM3RD_VideoOverlayYStartLow, (info->dest.y & 0xff));
310     RAMDAC_SET_REG(PM3RD_VideoOverlayYStartHigh, (info->dest.y & 0xf00)>>8);
311     RAMDAC_SET_REG(PM3RD_VideoOverlayYEndLow, (info->dest.y+drw_h) & 0xff);
312     RAMDAC_SET_REG(PM3RD_VideoOverlayYEndHigh,
313 		   ((info->dest.y+drw_h) & 0xf00)>>8);
314 
315     RAMDAC_SET_REG(PM3RD_VideoOverlayKeyR, 0xff);
316     RAMDAC_SET_REG(PM3RD_VideoOverlayKeyG, 0x00);
317     RAMDAC_SET_REG(PM3RD_VideoOverlayKeyB, 0xff);
318 
319     overlay_mode =
320 	1 << 5 |
321 	format |
322 	PM3VideoOverlayMode_FILTER_FULL |
323 	PM3VideoOverlayMode_BUFFERSYNC_MANUAL |
324 	PM3VideoOverlayMode_FLIP_VIDEO;
325 
326     overlay_control =
327 	PM3RD_VideoOverlayControl_KEY_COLOR |
328 	PM3RD_VideoOverlayControl_MODE_MAINKEY |
329 	PM3RD_VideoOverlayControl_DIRECTCOLOR_ENABLED;
330 
331     TRACE_EXIT();
332     return 0;
333 }
334 
pm3_playback_on(void)335 static int pm3_playback_on(void)
336 {
337     TRACE_ENTER();
338 
339     WRITE_REG(PM3VideoOverlayMode,
340 	      overlay_mode | PM3VideoOverlayMode_ENABLE);
341     RAMDAC_SET_REG(PM3RD_VideoOverlayControl,
342 		   overlay_control | PM3RD_VideoOverlayControl_ENABLE);
343     WRITE_REG(PM3VideoOverlayUpdate,
344 	      PM3VideoOverlayUpdate_ENABLE);
345 
346     TRACE_EXIT();
347     return 0;
348 }
349 
pm3_playback_off(void)350 static int pm3_playback_off(void)
351 {
352     RAMDAC_SET_REG(PM3RD_VideoOverlayControl,
353 		   PM3RD_VideoOverlayControl_DISABLE);
354     WRITE_REG(PM3VideoOverlayMode,
355 	      PM3VideoOverlayMode_DISABLE);
356 
357     RAMDAC_SET_REG(PM3RD_VideoOverlayKeyR, 0x01);
358     RAMDAC_SET_REG(PM3RD_VideoOverlayKeyG, 0x01);
359     RAMDAC_SET_REG(PM3RD_VideoOverlayKeyB, 0xfe);
360 
361     return 0;
362 }
363 
pm3_frame_select(unsigned int frame)364 static int pm3_frame_select(unsigned int frame)
365 {
366     WRITE_REG(PM3VideoOverlayBase0, frames[frame]);
367     return 0;
368 }
369 
370 const VDXDriver pm3_drv = {
371   "pm3",
372   NULL,
373   .probe = pm3_probe,
374   .get_caps = pm3_get_caps,
375   .query_fourcc = pm3_query_fourcc,
376   .init = pm3_init,
377   .destroy = pm3_destroy,
378   .config_playback = pm3_config_playback,
379   .playback_on = pm3_playback_on,
380   .playback_off = pm3_playback_off,
381   .frame_sel = pm3_frame_select,
382 };
383