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