core: fix audio-only + framestep weird behavior
[mplayer/glamo.git] / vidix / pm3_vid.c
blob6678ddf3f728a32b94dd0e4b6a6c874b8b530bc2
1 /*
2 * VIDIX driver for 3DLabs Glint R3 and Permedia 3 chipsets.
3 * Copyright (C) 2002 Måns Rullgård
5 * This file is part of MPlayer.
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.
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.
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.
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <inttypes.h>
27 #include <unistd.h>
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"
36 #include "pm3_regs.h"
38 #if 0
39 #define TRACE_ENTER() fprintf(stderr, "%s: enter\n", __FUNCTION__)
40 #define TRACE_EXIT() fprintf(stderr, "%s: exit\n", __FUNCTION__)
41 #else
42 #define TRACE_ENTER()
43 #define TRACE_EXIT()
44 #endif
46 static pciinfo_t pci_info;
48 void *pm3_reg_base;
49 static void *pm3_mem;
51 static vidix_capability_t pm3_cap =
53 "3DLabs GLINT R3/Permedia3 driver",
54 "Måns Rullgård <mru@users.sf.net>",
55 TYPE_OUTPUT,
56 { 0, 0, 0, 0 },
57 2048,
58 2048,
61 -1,
62 FLAG_UPSCALER|FLAG_DOWNSCALER,
63 VENDOR_3DLABS,
64 -1,
65 { 0, 0, 0, 0 }
68 static unsigned short pm3_card_ids[] =
70 DEVICE_3DLABS_GLINT_R3
73 static int find_chip(unsigned chip_id)
75 unsigned i;
76 for(i = 0;i < sizeof(pm3_card_ids)/sizeof(unsigned short);i++)
78 if(chip_id == pm3_card_ids[i]) return i;
80 return -1;
83 static int pm3_probe(int verbose, int force)
85 pciinfo_t lst[MAX_PCI_DEVICES];
86 unsigned i,num_pci;
87 int err;
89 err = pci_scan(lst,&num_pci);
90 if(err)
92 printf("[pm3] Error occurred during pci scan: %s\n",strerror(err));
93 return err;
95 else
97 err = ENXIO;
98 for(i=0; i < num_pci; i++)
100 if(lst[i].vendor == VENDOR_3DLABS)
102 int idx;
103 const char *dname;
104 idx = find_chip(lst[i].device);
105 if(idx == -1)
106 continue;
107 dname = pci_device_name(VENDOR_3DLABS, lst[i].device);
108 dname = dname ? dname : "Unknown chip";
109 printf("[pm3] Found chip: %s\n", dname);
110 #if 0
111 if ((lst[i].command & PCI_COMMAND_IO) == 0)
113 printf("[pm3] Device is disabled, ignoring\n");
114 continue;
116 #endif
117 pm3_cap.device_id = lst[i].device;
118 err = 0;
119 memcpy(&pci_info, &lst[i], sizeof(pciinfo_t));
120 break;
124 if(err && verbose) printf("[pm3] Can't find chip\n");
125 return err;
128 #define PRINT_REG(reg) \
130 long _foo = READ_REG(reg); \
131 printf("[pm3] " #reg " (%x) = %#lx (%li)\n", reg, _foo, _foo); \
134 static int pm3_init(void)
136 pm3_reg_base = map_phys_mem(pci_info.base0, 0x20000);
137 pm3_mem = map_phys_mem(pci_info.base2, 0x2000000);
138 return 0;
141 static void pm3_destroy(void)
143 unmap_phys_mem(pm3_reg_base, 0x20000);
144 unmap_phys_mem(pm3_mem, 0x2000000);
147 static int pm3_get_caps(vidix_capability_t *to)
149 memcpy(to, &pm3_cap, sizeof(vidix_capability_t));
150 return 0;
153 static int is_supported_fourcc(uint32_t fourcc)
155 switch(fourcc){
156 case IMGFMT_YUY2:
157 case IMGFMT_UYVY:
158 return 1;
159 default:
160 return 0;
164 static int pm3_query_fourcc(vidix_fourcc_t *to)
166 if(is_supported_fourcc(to->fourcc))
168 to->depth = VID_DEPTH_ALL;
169 to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY;
170 return 0;
172 else to->depth = to->flags = 0;
173 return ENOSYS;
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
192 /* Notice, have to check that we don't overflow the deltas here ... */
193 static void
194 compute_scale_factor(
195 short* src_w, short* dst_w,
196 uint32_t* shrink_delta, uint32_t* zoom_delta)
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 ! */
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;
220 static int frames[VID_PLAY_MAXFRAMES];
222 static long overlay_mode, overlay_control;
224 static int pm3_config_playback(vidix_playback_t *info)
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;
234 TRACE_ENTER();
236 if(!is_supported_fourcc(info->fourcc))
237 return -1;
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;
250 src_w = info->src.w;
251 src_h = info->src.h;
253 drw_w = info->dest.w;
254 drw_h = info->dest.h;
256 pitch = src_w;
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;
263 /* Start at 16 MB. Let's hope it's not in use. */
264 base0 = 0x1000000;
265 info->dga_addr = pm3_mem + base0;
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;
279 compute_scale_factor(&src_w, &drw_w, &shrink, &zoom);
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);
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));
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);
301 WRITE_REG(PM3VideoOverlayIndex, 0);
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);
315 RAMDAC_SET_REG(PM3RD_VideoOverlayKeyR, 0xff);
316 RAMDAC_SET_REG(PM3RD_VideoOverlayKeyG, 0x00);
317 RAMDAC_SET_REG(PM3RD_VideoOverlayKeyB, 0xff);
319 overlay_mode =
320 1 << 5 |
321 format |
322 PM3VideoOverlayMode_FILTER_FULL |
323 PM3VideoOverlayMode_BUFFERSYNC_MANUAL |
324 PM3VideoOverlayMode_FLIP_VIDEO;
326 overlay_control =
327 PM3RD_VideoOverlayControl_KEY_COLOR |
328 PM3RD_VideoOverlayControl_MODE_MAINKEY |
329 PM3RD_VideoOverlayControl_DIRECTCOLOR_ENABLED;
331 TRACE_EXIT();
332 return 0;
335 static int pm3_playback_on(void)
337 TRACE_ENTER();
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);
346 TRACE_EXIT();
347 return 0;
350 static int pm3_playback_off(void)
352 RAMDAC_SET_REG(PM3RD_VideoOverlayControl,
353 PM3RD_VideoOverlayControl_DISABLE);
354 WRITE_REG(PM3VideoOverlayMode,
355 PM3VideoOverlayMode_DISABLE);
357 RAMDAC_SET_REG(PM3RD_VideoOverlayKeyR, 0x01);
358 RAMDAC_SET_REG(PM3RD_VideoOverlayKeyG, 0x01);
359 RAMDAC_SET_REG(PM3RD_VideoOverlayKeyB, 0xfe);
361 return 0;
364 static int pm3_frame_select(unsigned int frame)
366 WRITE_REG(PM3VideoOverlayBase0, frames[frame]);
367 return 0;
370 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,