Overlay support (now vo_xtdfx is possible :) and yet another way to

access the mem. Still the same problem than with the page fault handler :(
But it doesn't need a patched agpgart.


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9567 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
albeu 2003-03-12 11:09:23 +00:00
parent 555b3f61fe
commit 6b271acc7e
3 changed files with 251 additions and 20 deletions

View File

@ -248,6 +248,12 @@ typedef struct voodoo_yuv_fb_t voodoo_yuv_fb;
#define COMMAND_3D (0x00200000 + 0x120)
#define SWAPBUFCMD (0x00200000 + 0x128)
#define SWAPPENDING (0x00200000 + 0x24C)
#define LEFTOVBUF (0x00200000 + 0x250)
#define RIGHTOVBUF (0x00200000 + 0x254)
#define FBISWAPBUFHIST (0x00200000 + 0x258)
/* register bitfields (not all, only as needed) */
#define BIT(x) (1UL << (x))

View File

@ -31,6 +31,7 @@
#define TDFX_VID_MAJOR 178
MODULE_AUTHOR("Albeu");
MODULE_DESCRIPTION("A driver for Banshee targeted for video app");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
@ -55,9 +56,16 @@ static agp_kern_info agp_info;
static agp_memory *agp_mem = NULL;
static __initdata int tdfx_map_io = 1;
static __initdata unsigned long map_start = 0; //0x7300000;
static __initdata unsigned long map_max = (10*1024*1024);
static unsigned long map_base = 0;
MODULE_PARM(tdfx_map_io,"i");
MODULE_PARM_DESC(tdfx_map_io, "Set to 0 to use the page fault handler (you need to patch agpgart_be.c to allow the mapping in user space)\n");
MODULE_PARM(map_start,"l");
MODULE_PARM_DESC(map_start,"Use a block of physical mem instead of the agp arerture.");
MODULE_PARM(map_max,"l");
MODULE_PARM_DESC(map_max, "Maximum amout of physical memory (in bytes) that can be used\n");
static inline u32 tdfx_inl(unsigned int reg) {
return readl(tdfx_mmio_base + reg);
@ -224,14 +232,14 @@ static void agp_close(void) {
drm_agp->release();
inter_module_put("drm_agp");
}
static int agp_move(tdfx_vid_agp_move_t* m) {
u32 src = 0;
u32 src_h,src_l;
if(!agp_mem)
if(!(agp_mem||map_start))
return (-EAGAIN);
if(m->move2 > 3) {
@ -240,8 +248,10 @@ static int agp_move(tdfx_vid_agp_move_t* m) {
return (-EAGAIN);
}
src = agp_info.aper_base + m->src;
if(map_start)
src = map_start + m->src;
else
src = agp_info.aper_base + m->src;
src_l = (u32)src;
src_h = (m->width | (m->src_stride << 14)) & 0x0FFFFFFF;
@ -317,7 +327,7 @@ static void tdfx_vid_get_config(tdfx_vid_config_t* cfg) {
cfg->screen_format = 0;
break;
}
cfg->screen_stride = tdfx_inl(VIDDESKSTRIDE);
cfg->screen_stride = tdfx_inl(VIDDESKSTRIDE) & 0x7FFF;
cfg->screen_start = tdfx_inl(VIDDESKSTART);
}
@ -373,9 +383,9 @@ inline static u32 tdfx_vid_make_format(int src,u16 stride,u32 fmt) {
}
static int tdfx_vid_blit(tdfx_vid_blit_t* blit) {
u32 src_fmt,dst_fmt;
u32 src_fmt,dst_fmt,cmd = 2;
u32 cmin,cmax,srcbase,srcxy,srcfmt,srcsize;
u32 dstbase,dstxy,dstfmt,dstsize;
u32 dstbase,dstxy,dstfmt,dstsize = 0;
u32 cmd_extra = 0,src_ck[2],dst_ck[2],rop123=0;
//printk(KERN_INFO "tdfx_vid: Make src fmt 0x%x\n",blit->src_format);
@ -390,6 +400,12 @@ static int tdfx_vid_blit(tdfx_vid_blit_t* blit) {
// Be nice if user just want a simple blit
if((!blit->colorkey) && (!blit->rop[0]))
blit->rop[0] = TDFX_VID_ROP_COPY;
// No stretch : fix me the cmd should be 1 but it
// doesn't work. Maybe some other regs need to be set
// as non-stretch blit have more options
if(((!blit->dst_w) && (!blit->dst_h)) ||
((blit->dst_w == blit->src_w) && (blit->dst_h == blit->src_h)))
cmd = 2;
// Save the regs otherwise fb get crazy
// we can perhaps avoid some ...
@ -403,7 +419,8 @@ static int tdfx_vid_blit(tdfx_vid_blit_t* blit) {
dstbase = tdfx_inl(DSTBASE);
dstxy = tdfx_inl(DSTXY);
dstfmt = tdfx_inl(DSTFORMAT);
dstsize = tdfx_inl(DSTSIZE);
if(cmd == 2)
dstsize = tdfx_inl(DSTSIZE);
if(blit->colorkey & TDFX_VID_SRC_COLORKEY) {
src_ck[0] = tdfx_inl(SRCCOLORKEYMIN);
src_ck[1] = tdfx_inl(SRCCOLORKEYMAX);
@ -437,10 +454,11 @@ static int tdfx_vid_blit(tdfx_vid_blit_t* blit) {
tdfx_outl(DSTBASE,blit->dst & 0x00FFFFFF);
tdfx_outl(DSTXY,XYREG(blit->dst_x,blit->dst_y));
tdfx_outl(DSTFORMAT,dst_fmt);
tdfx_outl(DSTSIZE,XYREG(blit->dst_w,blit->dst_h));
if(cmd == 2)
tdfx_outl(DSTSIZE,XYREG(blit->dst_w,blit->dst_h));
// Send the command
tdfx_outl(COMMAND_2D,0x102 | (blit->rop[0] << 24));
tdfx_outl(COMMAND_2D,cmd | 0x100 | (blit->rop[0] << 24));
banshee_wait_idle();
// Now restore the regs to make fb happy
@ -453,7 +471,8 @@ static int tdfx_vid_blit(tdfx_vid_blit_t* blit) {
tdfx_outl(DSTBASE, dstbase);
tdfx_outl(DSTXY, dstxy);
tdfx_outl(DSTFORMAT, dstfmt);
tdfx_outl(DSTSIZE, dstsize);
if(cmd == 2)
tdfx_outl(DSTSIZE, dstsize);
if(blit->colorkey & TDFX_VID_SRC_COLORKEY) {
tdfx_outl(SRCCOLORKEYMIN,src_ck[0]);
tdfx_outl(SRCCOLORKEYMAX,src_ck[1]);
@ -499,6 +518,170 @@ static int tdfx_vid_get_yuv(unsigned long arg) {
return 0;
}
static int tdfx_vid_set_overlay(unsigned long arg) {
tdfx_vid_overlay_t ov;
uint32_t screen_w,screen_h;
uint32_t vidcfg,stride,vidbuf;
int disp_w,disp_h;
if(copy_from_user(&ov,(tdfx_vid_overlay_t*)arg,sizeof(tdfx_vid_overlay_t))) {
printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n");
return(-EFAULT);
}
if(ov.dst_x < 0 || ov.dst_y < 0) {
printk(KERN_DEBUG "tdfx_vid: Negative x/y not yet supported\n");
return(-EFAULT);
}
vidcfg = tdfx_inl(VIDPROCCFG);
// clear the overlay fmt
vidcfg &= ~(7 << 21);
switch(ov.format) {
case TDFX_VID_FORMAT_BGR15:
vidcfg |= (1 << 21);
break;
case TDFX_VID_FORMAT_BGR16:
vidcfg |= (7 << 21);
break;
case TDFX_VID_FORMAT_YUY2:
vidcfg |= (5 << 21);
break;
case TDFX_VID_FORMAT_UYVY:
vidcfg |= (6 << 21);
break;
default:
printk(KERN_DEBUG "tdfx_vid: Invalid overlay fmt 0x%x\n",ov.format);
return (-EFAULT);
}
// YUV422 need 4 bytes aligned stride and address
if((ov.format == TDFX_VID_FORMAT_YUY2 ||
ov.format == TDFX_VID_FORMAT_UYVY)) {
if((ov.src_stride & ~0x3) != ov.src_stride) {
printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned stride %d\n",ov.src_stride);
return(-EFAULT);
}
if((ov.src[0] & ~0x3) != ov.src[0] || (ov.src[1] & ~0x3) != ov.src[1]){
printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned address 0x%x 0x%x\n",ov.src[0],ov.src[1]);
return(-EFAULT);
}
}
// Now we have a good input format
// but first get the screen size to check a bit
// if the size/position is valid
screen_w = tdfx_inl(VIDSCREENSIZE);
screen_h = (screen_w >> 12) & 0xFFF;
screen_w &= 0xFFF;
disp_w = ov.dst_x + ov.dst_width > screen_w ?
screen_w - ov.dst_x : ov.dst_width;
disp_h = ov.dst_y + ov.dst_height > screen_h ?
screen_h - ov.dst_y : ov.dst_height;
if(ov.dst_x >= screen_w || ov.dst_y >= screen_h ||
disp_h <= 0 || disp_h > screen_h || disp_w <= 0 || disp_w > screen_w) {
printk(KERN_DEBUG "tdfx_vid: Invalid overlay dimension and/or position\n");
return (-EFAULT);
}
// Setup the vidproc
// H scaling
if(ov.src_width != ov.dst_width)
vidcfg |= (1<<14);
else
vidcfg &= ~(1<<14);
// V scaling
if(ov.src_height != ov.dst_height)
vidcfg |= (1<<15);
else
vidcfg &= ~(1<<15);
// Filtering can only be used in 1x mode
if(!(vidcfg | (1<<26)))
vidcfg |= (3<<16);
else
vidcfg &= ~(3<<16);
// disable overlay stereo mode
vidcfg &= ~(1<<2);
// Colorkey on/off
if(ov.use_colorkey) {
// Colorkey inversion
if(ov.invert_colorkey)
vidcfg |= (1<<6);
else
vidcfg &= ~(1<<6);
vidcfg |= (1<<5);
} else
vidcfg &= ~(1<<5);
// Overlay isn't VidIn
vidcfg &= ~(1<<9);
// vidcfg |= (1<<8);
tdfx_outl(VIDPROCCFG,vidcfg);
// Start coord
tdfx_outl(VIDOVRSTARTCRD,(ov.dst_x & 0xFFF)|((ov.dst_y & 0xFFF)<<12));
// End coord
tdfx_outl(VIDOVRENDCRD, ((ov.dst_x + disp_w) & 0xFFF)|
(((ov.dst_y + disp_h) & 0xFFF)<<12));
// H Scaling
tdfx_outl(VIDOVRDUDX,( ((u32)ov.src_width) << 20) / ov.dst_width);
// Src offset and width (in bytes)
tdfx_outl(VIDOVRDUDXOFF,((ov.src_width<<1) & 0xFFF) << 19);
// V Scaling
tdfx_outl(VIDOVRDVDY, ( ((u32)ov.src_height) << 20) / ov.dst_height);
//else
// tdfx_outl(VIDOVRDVDY,0);
// V Offset
tdfx_outl(VIDOVRDVDYOFF,0);
// Overlay stride
stride = tdfx_inl(VIDDESKSTRIDE) & 0xFFFF;
tdfx_outl(VIDDESKSTRIDE,stride | (((u32)ov.src_stride) << 16));
// Buffers address
tdfx_outl(LEFTOVBUF, ov.src[0]);
tdfx_outl(RIGHTOVBUF, ov.src[1]);
// Send a swap buffer cmd if we are not on one of the 2 buffers
vidbuf = tdfx_inl(VIDCUROVRSTART);
if(vidbuf != ov.src[0] && vidbuf != ov.src[1]) {
tdfx_outl(SWAPPENDING,0);
tdfx_outl(SWAPBUFCMD, 1);
}
printk(KERN_DEBUG "tdfx_vid: Buf0=0x%x Buf1=0x%x Current=0x%x\n",
ov.src[0],ov.src[1],tdfx_inl(VIDCUROVRSTART));
// Colorkey
if(ov.use_colorkey) {
tdfx_outl(VIDCHRMIN,ov.colorkey[0]);
tdfx_outl(VIDCHRMAX,ov.colorkey[1]);
}
return 0;
}
static int tdfx_vid_overlay_on(void) {
uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
//return 0;
if(vidcfg & (1<<8)) { // Overlay is alredy on
printk(KERN_DEBUG "tdfx_vid: Overlay is alredy on\n");
return (-EFAULT);
}
vidcfg |= (1<<8);
tdfx_outl(VIDPROCCFG,vidcfg);
return 0;
}
static int tdfx_vid_overlay_off(void) {
uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
if(vidcfg & (1<<8)) {
vidcfg &= ~(1<<8);
tdfx_outl(VIDPROCCFG,vidcfg);
return 0;
}
printk(KERN_DEBUG "tdfx_vid: Overlay is alredy off\n");
return (-EFAULT);
}
static int tdfx_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
tdfx_vid_agp_move_t move;
@ -544,6 +727,12 @@ static int tdfx_vid_ioctl(struct inode *inode, struct file *file, unsigned int c
return tdfx_vid_set_yuv(arg);
case TDFX_VID_GET_YUV:
return tdfx_vid_get_yuv(arg);
case TDFX_VID_SET_OVERLAY:
return tdfx_vid_set_overlay(arg);
case TDFX_VID_OVERLAY_ON:
return tdfx_vid_overlay_on();
case TDFX_VID_OVERLAY_OFF:
return tdfx_vid_overlay_off();
default:
printk(KERN_ERR "tdfx_vid: Invalid ioctl %d\n",cmd);
return (-EINVAL);
@ -642,11 +831,31 @@ static int tdfx_vid_mmap(struct file *file, struct vm_area_struct *vma)
printk(KERN_DEBUG "tdfx_vid: mapping agp memory into userspace\n");
#endif
size = (vma->vm_end-vma->vm_start + PAGE_SIZE - 1) / PAGE_SIZE;
if(map_start) { // Ok we map directly in the physcal ram
if(size*PAGE_SIZE > map_max) {
printk(KERN_ERR "tdfx_vid: Not enouth mem\n");
return(-EAGAIN);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
if(remap_page_range(vma, vma->vm_start,map_start,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
#else
if(remap_page_range(vma->vm_start, (unsigned long)map_start,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
#endif
{
printk(KERN_ERR "tdfx_vid: error mapping video memory\n");
return(-EAGAIN);
}
printk(KERN_INFO "Physical mem 0x%lx mapped in userspace\n",map_start);
return 0;
}
if(agp_mem)
return(-EAGAIN);
size = (vma->vm_end-vma->vm_start + PAGE_SIZE - 1) / PAGE_SIZE;
agp_mem = drm_agp->allocate_memory(size,AGP_NORMAL_MEMORY);
if(!agp_mem) {
printk(KERN_ERR "Failed to allocate AGP memory\n");
@ -681,8 +890,8 @@ static int tdfx_vid_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags |= VM_LOCKED | VM_IO;
vma->vm_ops = &tdfx_vid_vm_ops;
vma->vm_ops->open(vma);
printk(KERN_INFO "Page fault handler ready !!!!!\n");
}
printk(KERN_INFO "Page fault handler ready !!!!!\n");
return 0;
}

View File

@ -80,11 +80,27 @@ typedef struct tdfx_vid_yuv_s {
uint16_t stride;
} tdfx_vid_yuv_t;
typedef struct tdfx_vid_overlay_s {
uint32_t src[2]; // left and right buffer (2 buffer may be NULL)
uint16_t src_width,src_height;
uint16_t src_stride;
uint32_t format;
uint16_t dst_width,dst_height;
int16_t dst_x,dst_y;
uint8_t use_colorkey;
uint32_t colorkey[2]; // min/max
uint8_t invert_colorkey;
} tdfx_vid_overlay_t;
#define TDFX_VID_GET_CONFIG _IOR('J', 1, tdfx_vid_config_t)
#define TDFX_VID_AGP_MOVE _IOR('J', 2, tdfx_vid_agp_move_t)
#define TDFX_VID_BLIT _IOR('J', 3, tdfx_vid_blit_t)
#define TDFX_VID_SET_YUV _IOR('J', 4, tdfx_vid_blit_t)
#define TDFX_VID_AGP_MOVE _IOW('J', 2, tdfx_vid_agp_move_t)
#define TDFX_VID_BLIT _IOW('J', 3, tdfx_vid_blit_t)
#define TDFX_VID_SET_YUV _IOW('J', 4, tdfx_vid_blit_t)
#define TDFX_VID_GET_YUV _IOR('J', 5, tdfx_vid_blit_t)
#define TDFX_VID_BUMP0 _IOR('J', 6, u16)
#define TDFX_VID_BUMP0 _IOW('J', 6, u16)
#define TDFX_VID_SET_OVERLAY _IOW('J', 7, tdfx_vid_overlay_t)
#define TDFX_VID_OVERLAY_ON _IO ('J', 8)
#define TDFX_VID_OVERLAY_OFF _IO ('J', 9)