diff vidix/pm3_vid.c @ 22850:9a1e26fef45b

Move driver files directly into the vidix directory.
author diego
date Sun, 01 Apr 2007 00:02:43 +0000
parents
children 77def5093daf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vidix/pm3_vid.c	Sun Apr 01 00:02:43 2007 +0000
@@ -0,0 +1,375 @@
+/**
+    Driver for 3DLabs GLINT R3 and Permedia3 chips.
+
+    Copyright (C) 2002  Måns Rullgård
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+**/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include "vidix.h"
+#include "fourcc.h"
+#include "../libdha/libdha.h"
+#include "../libdha/pci_ids.h"
+#include "../libdha/pci_names.h"
+#include "../config.h"
+
+#include "pm3_regs.h"
+
+#if 0
+#define TRACE_ENTER() fprintf(stderr, "%s: enter\n", __FUNCTION__)
+#define TRACE_EXIT() fprintf(stderr, "%s: exit\n", __FUNCTION__)
+#else
+#define TRACE_ENTER()
+#define TRACE_EXIT()
+#endif
+
+pciinfo_t pci_info;
+
+void *pm3_reg_base;
+void *pm3_mem;
+
+static vidix_capability_t pm3_cap =
+{
+    "3DLabs GLINT R3/Permedia3 driver",
+    "Måns Rullgård <mru@users.sf.net>",
+    TYPE_OUTPUT,
+    { 0, 0, 0, 0 },
+    2048,
+    2048,
+    4,
+    4,
+    -1,
+    FLAG_UPSCALER|FLAG_DOWNSCALER,
+    VENDOR_3DLABS,
+    -1,
+    { 0, 0, 0, 0 }
+};
+
+
+unsigned int vixGetVersion(void)
+{
+    return(VIDIX_VERSION);
+}
+
+static unsigned short pm3_card_ids[] = 
+{
+    DEVICE_3DLABS_GLINT_R3
+};
+
+static int find_chip(unsigned chip_id)
+{
+  unsigned i;
+  for(i = 0;i < sizeof(pm3_card_ids)/sizeof(unsigned short);i++)
+  {
+    if(chip_id == pm3_card_ids[i]) return i;
+  }
+  return -1;
+}
+
+int vixProbe(int verbose, int force)
+{
+    pciinfo_t lst[MAX_PCI_DEVICES];
+    unsigned i,num_pci;
+    int err;
+
+    err = pci_scan(lst,&num_pci);
+    if(err)
+    {
+	printf("[pm3] Error occurred during pci scan: %s\n",strerror(err));
+	return err;
+    }
+    else
+    {
+	err = ENXIO;
+	for(i=0; i < num_pci; i++)
+	{
+	    if(lst[i].vendor == VENDOR_3DLABS)
+	    {
+		int idx;
+		const char *dname;
+		idx = find_chip(lst[i].device);
+		if(idx == -1)
+		    continue;
+		dname = pci_device_name(VENDOR_3DLABS, lst[i].device);
+		dname = dname ? dname : "Unknown chip";
+		printf("[pm3] Found chip: %s\n", dname);
+		if ((lst[i].command & PCI_COMMAND_IO) == 0)
+		{
+			printf("[pm3] Device is disabled, ignoring\n");
+			continue;
+		}
+		pm3_cap.device_id = lst[i].device;
+		err = 0;
+		memcpy(&pci_info, &lst[i], sizeof(pciinfo_t));
+		break;
+	    }
+	}
+    }
+    if(err && verbose) printf("[pm3] Can't find chip\n");
+    return err;
+}
+
+#define PRINT_REG(reg)							\
+{									\
+    long _foo = READ_REG(reg);						\
+    printf("[pm3] " #reg " (%x) = %#lx (%li)\n", reg, _foo, _foo);	\
+}
+
+int vixInit(void)
+{
+    pm3_reg_base = map_phys_mem(pci_info.base0, 0x20000);
+    pm3_mem = map_phys_mem(pci_info.base2, 0x2000000);
+    return 0;
+}
+
+void vixDestroy(void)
+{
+    unmap_phys_mem(pm3_reg_base, 0x20000);
+    unmap_phys_mem(pm3_mem, 0x2000000);
+}
+
+int vixGetCapability(vidix_capability_t *to)
+{
+    memcpy(to, &pm3_cap, sizeof(vidix_capability_t));
+    return 0;
+}
+
+static int is_supported_fourcc(uint32_t fourcc)
+{
+    switch(fourcc){
+    case IMGFMT_YUY2:
+    case IMGFMT_UYVY:
+	return 1;
+    default:
+	return 0;
+    }
+}
+
+int vixQueryFourcc(vidix_fourcc_t *to)
+{
+    if(is_supported_fourcc(to->fourcc))
+    {
+	to->depth = VID_DEPTH_1BPP | VID_DEPTH_2BPP |
+		    VID_DEPTH_4BPP | VID_DEPTH_8BPP |
+		    VID_DEPTH_12BPP| VID_DEPTH_15BPP|
+		    VID_DEPTH_16BPP| VID_DEPTH_24BPP|
+		    VID_DEPTH_32BPP;
+	to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY;
+	return 0;
+    }
+    else  to->depth = to->flags = 0;
+    return ENOSYS;
+}
+
+#define FORMAT_RGB8888	PM3VideoOverlayMode_COLORFORMAT_RGB8888 
+#define FORMAT_RGB4444	PM3VideoOverlayMode_COLORFORMAT_RGB4444
+#define FORMAT_RGB5551	PM3VideoOverlayMode_COLORFORMAT_RGB5551
+#define FORMAT_RGB565	PM3VideoOverlayMode_COLORFORMAT_RGB565
+#define FORMAT_RGB332	PM3VideoOverlayMode_COLORFORMAT_RGB332
+#define FORMAT_BGR8888	PM3VideoOverlayMode_COLORFORMAT_BGR8888
+#define FORMAT_BGR4444	PM3VideoOverlayMode_COLORFORMAT_BGR4444
+#define FORMAT_BGR5551	PM3VideoOverlayMode_COLORFORMAT_BGR5551
+#define FORMAT_BGR565	PM3VideoOverlayMode_COLORFORMAT_BGR565
+#define FORMAT_BGR332	PM3VideoOverlayMode_COLORFORMAT_BGR332
+#define FORMAT_CI8	PM3VideoOverlayMode_COLORFORMAT_CI8
+#define FORMAT_VUY444	PM3VideoOverlayMode_COLORFORMAT_VUY444
+#define FORMAT_YUV444	PM3VideoOverlayMode_COLORFORMAT_YUV444
+#define FORMAT_VUY422	PM3VideoOverlayMode_COLORFORMAT_VUY422
+#define FORMAT_YUV422	PM3VideoOverlayMode_COLORFORMAT_YUV422
+
+/* Notice, have to check that we don't overflow the deltas here ... */
+static void
+compute_scale_factor(
+    short* src_w, short* dst_w,
+    unsigned int* shrink_delta, unsigned int* zoom_delta)
+{
+    /* NOTE: If we don't return reasonable values here then the video
+     * unit can potential shut off and won't display an image until re-enabled.
+     * Seems as though the zoom_delta is o.k, and I've not had the problem.
+     * The 'shrink_delta' is prone to this the most - FIXME ! */
+
+    if (*src_w >= *dst_w) {
+	*src_w &= ~0x3;
+	*dst_w &= ~0x3;
+	*shrink_delta = (((*src_w << 16) / *dst_w) + 0x0f) & 0x0ffffff0;
+	*zoom_delta = 1<<16;
+	if ( ((*shrink_delta * *dst_w) >> 16) & 0x03 )
+	    *shrink_delta += 0x10;
+    } else {
+	*src_w &= ~0x3;
+	*dst_w &= ~0x3;
+	*zoom_delta = (((*src_w << 16) / *dst_w) + 0x0f) & 0x0001fff0;
+	*shrink_delta = 1<<16;
+	if ( ((*zoom_delta * *dst_w) >> 16) & 0x03 )
+	    *zoom_delta += 0x10;
+    }
+}
+
+static int frames[VID_PLAY_MAXFRAMES];
+
+static long overlay_mode, overlay_control;
+
+int vixConfigPlayback(vidix_playback_t *info)
+{
+    int shrink, zoom;
+    short src_w, drw_w;
+    short src_h, drw_h;
+    long base0;
+    int pitch;
+    int format;
+    unsigned int i;
+
+    TRACE_ENTER();
+
+    if(!is_supported_fourcc(info->fourcc))
+	return -1;
+
+    switch(info->fourcc){
+    case IMGFMT_YUY2:
+	format = FORMAT_YUV422;
+	break;
+    case IMGFMT_UYVY:
+	format = FORMAT_VUY422;
+	break;
+    default:
+	return -1;
+    }
+
+    src_w = info->src.w;
+    src_h = info->src.h;
+
+    drw_w = info->dest.w;
+    drw_h = info->dest.h;
+
+    pitch = src_w;
+
+    /* Assume we have 16 MB to play with */
+    info->num_frames = 0x1000000 / (pitch * src_h * 2);
+    if(info->num_frames > VID_PLAY_MAXFRAMES)
+	info->num_frames = VID_PLAY_MAXFRAMES;
+
+    /* Start at 16 MB. Let's hope it's not in use. */
+    base0 = 0x1000000;
+    info->dga_addr = pm3_mem + base0;
+
+    info->dest.pitch.y = 2;
+    info->dest.pitch.u = 0;
+    info->dest.pitch.v = 0;
+    info->offset.y = 0;
+    info->offset.v = 0;
+    info->offset.u = 0;
+    info->frame_size = pitch * src_h * 2;
+    for(i = 0; i < info->num_frames; i++){
+	info->offsets[i] = info->frame_size * i;
+	frames[i] = (base0 + info->offsets[i]) >> 1;
+    }
+
+    compute_scale_factor(&src_w, &drw_w, &shrink, &zoom);
+
+    WRITE_REG(PM3VideoOverlayBase0, base0 >> 1);
+    WRITE_REG(PM3VideoOverlayStride, PM3VideoOverlayStride_STRIDE(pitch));
+    WRITE_REG(PM3VideoOverlayWidth, PM3VideoOverlayWidth_WIDTH(src_w));
+    WRITE_REG(PM3VideoOverlayHeight, PM3VideoOverlayHeight_HEIGHT(src_h));
+    WRITE_REG(PM3VideoOverlayOrigin, 0);
+
+    /* Scale the source to the destinationsize */
+    if (src_h == drw_h) {
+	WRITE_REG(PM3VideoOverlayYDelta, PM3VideoOverlayYDelta_NONE);
+    } else {
+	WRITE_REG(PM3VideoOverlayYDelta,
+		  PM3VideoOverlayYDelta_DELTA(src_h, drw_h));
+    }
+    if (src_w == drw_w) {
+    	WRITE_REG(PM3VideoOverlayShrinkXDelta, 1<<16);
+    	WRITE_REG(PM3VideoOverlayZoomXDelta, 1<<16);
+    } else {
+    	WRITE_REG(PM3VideoOverlayShrinkXDelta, shrink);
+    	WRITE_REG(PM3VideoOverlayZoomXDelta, zoom);
+    }
+    WRITE_REG(PM3VideoOverlayIndex, 0);
+
+    /* Now set the ramdac video overlay region and mode */
+    RAMDAC_SET_REG(PM3RD_VideoOverlayXStartLow, (info->dest.x & 0xff));
+    RAMDAC_SET_REG(PM3RD_VideoOverlayXStartHigh, (info->dest.x & 0xf00)>>8);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayXEndLow, (info->dest.x+drw_w) & 0xff);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayXEndHigh,
+		   ((info->dest.x+drw_w) & 0xf00)>>8);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayYStartLow, (info->dest.y & 0xff)); 
+    RAMDAC_SET_REG(PM3RD_VideoOverlayYStartHigh, (info->dest.y & 0xf00)>>8);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayYEndLow, (info->dest.y+drw_h) & 0xff); 
+    RAMDAC_SET_REG(PM3RD_VideoOverlayYEndHigh,
+		   ((info->dest.y+drw_h) & 0xf00)>>8);
+
+    RAMDAC_SET_REG(PM3RD_VideoOverlayKeyR, 0xff);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayKeyG, 0x00);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayKeyB, 0xff);
+
+    overlay_mode =
+	1 << 5 |
+	format |
+	PM3VideoOverlayMode_FILTER_FULL |
+	PM3VideoOverlayMode_BUFFERSYNC_MANUAL |
+	PM3VideoOverlayMode_FLIP_VIDEO;
+
+    overlay_control = 
+	PM3RD_VideoOverlayControl_KEY_COLOR |
+	PM3RD_VideoOverlayControl_MODE_MAINKEY |
+	PM3RD_VideoOverlayControl_DIRECTCOLOR_ENABLED;
+
+    TRACE_EXIT();
+    return 0;
+}
+
+int vixPlaybackOn(void)
+{
+    TRACE_ENTER();
+
+    WRITE_REG(PM3VideoOverlayMode,
+	      overlay_mode | PM3VideoOverlayMode_ENABLE);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayControl,
+		   overlay_control | PM3RD_VideoOverlayControl_ENABLE);
+    WRITE_REG(PM3VideoOverlayUpdate,
+	      PM3VideoOverlayUpdate_ENABLE);
+
+    TRACE_EXIT();
+    return 0;
+}
+
+int vixPlaybackOff(void)
+{
+    RAMDAC_SET_REG(PM3RD_VideoOverlayControl,
+		   PM3RD_VideoOverlayControl_DISABLE);
+    WRITE_REG(PM3VideoOverlayMode,
+	      PM3VideoOverlayMode_DISABLE);
+
+    RAMDAC_SET_REG(PM3RD_VideoOverlayKeyR, 0x01);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayKeyG, 0x01);
+    RAMDAC_SET_REG(PM3RD_VideoOverlayKeyB, 0xfe);
+
+    return 0;
+}
+
+int vixPlaybackFrameSelect(unsigned int frame)
+{
+    WRITE_REG(PM3VideoOverlayBase0, frames[frame]);
+    return 0;
+}