diff options
| -rw-r--r-- | linux-core/i810_dma.c | 126 | ||||
| -rw-r--r-- | linux-core/i810_drm.h | 4 | ||||
| -rw-r--r-- | linux-core/i810_drv.h | 20 | ||||
| -rw-r--r-- | linux/i810.h | 12 | ||||
| -rw-r--r-- | linux/i810_dma.c | 126 | ||||
| -rw-r--r-- | linux/i810_drm.h | 4 | ||||
| -rw-r--r-- | linux/i810_drv.h | 20 | 
7 files changed, 289 insertions, 23 deletions
| diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 678610c6..8042b7fc 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -289,10 +289,12 @@ static int i810_wait_ring(drm_device_t *dev, int n)  	   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;  	   	ring->space = ring->head - (ring->tail+8);  		if (ring->space < 0) ring->space += ring->Size; - -		if (ring->head != last_head) -		   end = jiffies + (HZ*3); - +	    +		if (ring->head != last_head) { +			end = jiffies + (HZ*3); +			last_head = ring->head; +		} +	    	   	iters++;  		if(time_before(end, jiffies)) {  		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n); @@ -410,6 +412,7 @@ static int i810_dma_initialize(drm_device_t *dev,  	dev_priv->pitch = init->pitch;  	dev_priv->back_offset = init->back_offset;  	dev_priv->depth_offset = init->depth_offset; +	dev_priv->front_offset = init->front_offset;  	dev_priv->overlay_offset = init->overlay_offset;  	dev_priv->overlay_physical = init->overlay_physical; @@ -589,6 +592,8 @@ static void i810EmitState( drm_device_t *dev )     	drm_i810_private_t *dev_priv = dev->dev_private;        	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;  	unsigned int dirty = sarea_priv->dirty; +	 +	DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);  	if (dirty & I810_UPLOAD_BUFFERS) {  		i810EmitDestVerified( dev, sarea_priv->BufferState ); @@ -627,6 +632,14 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,  	int cpp = 2;  	int i;  	RING_LOCALS; +	 +	if ( dev_priv->current_page == 1 ) { +	        unsigned int tmp = flags; +	        +		flags &= ~(I810_FRONT | I810_BACK); +		if (tmp & I810_FRONT) flags |= I810_BACK; +		if (tmp & I810_BACK) flags |= I810_FRONT; +	}    	i810_kernel_lost_context(dev); @@ -692,10 +705,11 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  	drm_clip_rect_t *pbox = sarea_priv->boxes;  	int pitch = dev_priv->pitch;  	int cpp = 2; -	int ofs = dev_priv->back_offset;  	int i;  	RING_LOCALS; +	DRM_DEBUG("swapbuffers\n"); +    	i810_kernel_lost_context(dev);        	if (nbox > I810_NR_SAREA_CLIPRECTS) @@ -706,7 +720,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  		unsigned int w = pbox->x2 - pbox->x1;  		unsigned int h = pbox->y2 - pbox->y1;  		unsigned int dst = pbox->x1*cpp + pbox->y1*pitch; -		unsigned int start = ofs + dst; +		unsigned int start = dst;  		if (pbox->x1 > pbox->x2 ||  		    pbox->y1 > pbox->y2 || @@ -718,9 +732,15 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  		OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );  		OUT_RING( pitch | (0xCC << 16));  		OUT_RING( (h << 16) | (w * cpp)); -		OUT_RING( dst ); +		if (dev_priv->current_page == 0) +		  OUT_RING(dev_priv->front_offset + start); +		else +		  OUT_RING(dev_priv->back_offset + start);  		OUT_RING( pitch ); -		OUT_RING( start ); +		if (dev_priv->current_page == 0) +		  OUT_RING(dev_priv->back_offset + start); +		else +		  OUT_RING(dev_priv->front_offset + start);  		ADVANCE_LP_RING();  	}  } @@ -807,6 +827,52 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,  	}  } +static void i810_dma_dispatch_flip( drm_device_t *dev ) +{ +        drm_i810_private_t *dev_priv = dev->dev_private; +	RING_LOCALS; +	int pitch = dev_priv->pitch; + +	DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n",  +		__FUNCTION__,  +		dev_priv->current_page, +		dev_priv->sarea_priv->pf_current_page); +	 +        i810_kernel_lost_context(dev); + +	BEGIN_LP_RING( 2 ); +   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );  +	OUT_RING( 0 ); +	ADVANCE_LP_RING(); + +	BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 ); +	/* On i815 at least ASYNC is buggy */ +	/* pitch<<5 is from 11.2.8 p158, +	   its the pitch / 8 then left shifted 8, +	   so (pitch >> 3) << 8 */ +	OUT_RING( CMD_OP_FRONTBUFFER_INFO | (pitch<<5) /*| ASYNC_FLIP */ ); +	if ( dev_priv->current_page == 0 ) { +		OUT_RING( dev_priv->back_offset ); +		dev_priv->current_page = 1; +	} else { +		OUT_RING( dev_priv->front_offset ); +		dev_priv->current_page = 0; +	} +	OUT_RING(0); +	ADVANCE_LP_RING(); + +	BEGIN_LP_RING(2); +	OUT_RING( CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP ); +	OUT_RING( 0 ); +	ADVANCE_LP_RING(); + +	/* Increment the frame counter.  The client-side 3D driver must +	 * throttle the framerate by waiting for this value before +	 * performing the swapbuffer ioctl. +	 */ +	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + +}  void i810_dma_quiescent(drm_device_t *dev)  { @@ -1198,3 +1264,47 @@ int i810_ov0_flip(struct inode *inode, struct file *filp,  } +/* Not sure why this isn't set all the time: + */  +static void i810_do_init_pageflip( drm_device_t *dev ) +{ +	drm_i810_private_t *dev_priv = dev->dev_private; +	 +	DRM_DEBUG("%s\n", __FUNCTION__); +	dev_priv->page_flipping = 1; +	dev_priv->current_page = 0; +	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; +} + +int i810_do_cleanup_pageflip( drm_device_t *dev ) +{ +	drm_i810_private_t *dev_priv = dev->dev_private; + +	DRM_DEBUG("%s\n", __FUNCTION__); +	if (dev_priv->current_page != 0) +		i810_dma_dispatch_flip( dev ); + +	dev_priv->page_flipping = 0; +	return 0; +} + +int i810_flip_bufs(struct inode *inode, struct file *filp, +		   unsigned int cmd, unsigned long arg) +{ +	drm_file_t *priv = filp->private_data; +	drm_device_t *dev = priv->dev; +	drm_i810_private_t *dev_priv = dev->dev_private; + +	DRM_DEBUG("%s\n", __FUNCTION__); + +   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { +		DRM_ERROR("i810_flip_buf called without lock held\n"); +		return -EINVAL; +	} + +	if (!dev_priv->page_flipping)  +		i810_do_init_pageflip( dev ); + +	i810_dma_dispatch_flip( dev ); +   	return 0; +} diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h index f8c27d83..b35593bd 100644 --- a/linux-core/i810_drm.h +++ b/linux-core/i810_drm.h @@ -166,6 +166,9 @@ typedef struct _drm_i810_sarea {  	int vertex_prim; +	int pf_enabled;               /* is pageflipping allowed? */ +	int pf_active; +	int pf_current_page;	    /* which buffer is being displayed? */  } drm_i810_sarea_t;  /* WARNING: If you change any of these defines, make sure to change the @@ -189,6 +192,7 @@ typedef struct _drm_i810_sarea {  #define DRM_IOCTL_I810_OV0FLIP		DRM_IO ( 0x4b)  #define DRM_IOCTL_I810_MC		DRM_IOW( 0x4c, drm_i810_mc_t)  #define DRM_IOCTL_I810_RSTATUS		DRM_IO ( 0x4d ) +#define DRM_IOCTL_I810_FLIP             DRM_IO ( 0x4e )  typedef struct _drm_i810_clear {  	int clear_color; diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index aa82c647..736c20d7 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -75,7 +75,20 @@ typedef struct drm_i810_private {  	int overlay_physical;  	int w, h;  	int pitch; +  	int back_pitch; +	int depth_pitch; +	int do_boxes; +	int dma_used; + +	int current_page; +	int page_flipping; + +	wait_queue_head_t irq_queue; +   	atomic_t irq_received; +   	atomic_t irq_emitted; +   +        int front_offset;  } drm_i810_private_t;  				/* i810_dma.c */ @@ -124,6 +137,8 @@ int i810_swap_bufs(struct inode *inode, struct file *filp,  int i810_clear_bufs(struct inode *inode, struct file *filp,  		    unsigned int cmd, unsigned long arg); +int i810_flip_bufs(struct inode *inode, struct file *filp, +		   unsigned int cmd, unsigned long arg);  #define I810_BASE(reg)		((unsigned long) \  				dev_priv->mmio_map->handle) @@ -225,12 +240,15 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,  #define CMD_OP_Z_BUFFER_INFO     ((0x0<<29)|(0x16<<23))  #define CMD_OP_DESTBUFFER_INFO   ((0x0<<29)|(0x15<<23))  #define CMD_OP_FRONTBUFFER_INFO  ((0x0<<29)|(0x14<<23)) +#define CMD_OP_WAIT_FOR_EVENT    ((0x0<<29)|(0x03<<23))  #define BR00_BITBLT_CLIENT   0x40000000  #define BR00_OP_COLOR_BLT    0x10000000  #define BR00_OP_SRC_COPY_BLT 0x10C00000  #define BR13_SOLID_PATTERN   0x80000000 - +#define WAIT_FOR_PLANE_A_SCANLINES (1<<1)  +#define WAIT_FOR_PLANE_A_FLIP      (1<<2)  +#define WAIT_FOR_VBLANK (1<<3)  #endif diff --git a/linux/i810.h b/linux/i810.h index bfb760ab..ba40892f 100644 --- a/linux/i810.h +++ b/linux/i810.h @@ -45,7 +45,7 @@  #define DRIVER_NAME		"i810"  #define DRIVER_DESC		"Intel i810" -#define DRIVER_DATE		"20020211" +#define DRIVER_DATE		"20030605"  /* Interface history   * @@ -54,10 +54,11 @@   *       - XFree86 4.2   * 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility)   *       - Remove requirement for interrupt (leave stubs again) + * 1.3   - Add page flipping.   */  #define DRIVER_MAJOR		1 -#define DRIVER_MINOR		2 -#define DRIVER_PATCHLEVEL	1 +#define DRIVER_MINOR		3 +#define DRIVER_PATCHLEVEL	0  #define DRIVER_IOCTLS							    \  	[DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)]   = { i810_dma_init,    1, 1 }, \ @@ -73,8 +74,9 @@  	[DRM_IOCTL_NR(DRM_IOCTL_I810_FSTATUS)] = { i810_fstatus,    1, 0 }, \  	[DRM_IOCTL_NR(DRM_IOCTL_I810_OV0FLIP)] = { i810_ov0_flip,   1, 0 }, \  	[DRM_IOCTL_NR(DRM_IOCTL_I810_MC)]      = { i810_dma_mc,     1, 1 }, \ -	[DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 } - +	[DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus,    1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_I810_FLIP)] =    { i810_flip_bufs,  1, 0 } +   #define __HAVE_COUNTERS         4  #define __HAVE_COUNTER6         _DRM_STAT_IRQ diff --git a/linux/i810_dma.c b/linux/i810_dma.c index 678610c6..8042b7fc 100644 --- a/linux/i810_dma.c +++ b/linux/i810_dma.c @@ -289,10 +289,12 @@ static int i810_wait_ring(drm_device_t *dev, int n)  	   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;  	   	ring->space = ring->head - (ring->tail+8);  		if (ring->space < 0) ring->space += ring->Size; - -		if (ring->head != last_head) -		   end = jiffies + (HZ*3); - +	    +		if (ring->head != last_head) { +			end = jiffies + (HZ*3); +			last_head = ring->head; +		} +	    	   	iters++;  		if(time_before(end, jiffies)) {  		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n); @@ -410,6 +412,7 @@ static int i810_dma_initialize(drm_device_t *dev,  	dev_priv->pitch = init->pitch;  	dev_priv->back_offset = init->back_offset;  	dev_priv->depth_offset = init->depth_offset; +	dev_priv->front_offset = init->front_offset;  	dev_priv->overlay_offset = init->overlay_offset;  	dev_priv->overlay_physical = init->overlay_physical; @@ -589,6 +592,8 @@ static void i810EmitState( drm_device_t *dev )     	drm_i810_private_t *dev_priv = dev->dev_private;        	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;  	unsigned int dirty = sarea_priv->dirty; +	 +	DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);  	if (dirty & I810_UPLOAD_BUFFERS) {  		i810EmitDestVerified( dev, sarea_priv->BufferState ); @@ -627,6 +632,14 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,  	int cpp = 2;  	int i;  	RING_LOCALS; +	 +	if ( dev_priv->current_page == 1 ) { +	        unsigned int tmp = flags; +	        +		flags &= ~(I810_FRONT | I810_BACK); +		if (tmp & I810_FRONT) flags |= I810_BACK; +		if (tmp & I810_BACK) flags |= I810_FRONT; +	}    	i810_kernel_lost_context(dev); @@ -692,10 +705,11 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  	drm_clip_rect_t *pbox = sarea_priv->boxes;  	int pitch = dev_priv->pitch;  	int cpp = 2; -	int ofs = dev_priv->back_offset;  	int i;  	RING_LOCALS; +	DRM_DEBUG("swapbuffers\n"); +    	i810_kernel_lost_context(dev);        	if (nbox > I810_NR_SAREA_CLIPRECTS) @@ -706,7 +720,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  		unsigned int w = pbox->x2 - pbox->x1;  		unsigned int h = pbox->y2 - pbox->y1;  		unsigned int dst = pbox->x1*cpp + pbox->y1*pitch; -		unsigned int start = ofs + dst; +		unsigned int start = dst;  		if (pbox->x1 > pbox->x2 ||  		    pbox->y1 > pbox->y2 || @@ -718,9 +732,15 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  		OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );  		OUT_RING( pitch | (0xCC << 16));  		OUT_RING( (h << 16) | (w * cpp)); -		OUT_RING( dst ); +		if (dev_priv->current_page == 0) +		  OUT_RING(dev_priv->front_offset + start); +		else +		  OUT_RING(dev_priv->back_offset + start);  		OUT_RING( pitch ); -		OUT_RING( start ); +		if (dev_priv->current_page == 0) +		  OUT_RING(dev_priv->back_offset + start); +		else +		  OUT_RING(dev_priv->front_offset + start);  		ADVANCE_LP_RING();  	}  } @@ -807,6 +827,52 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,  	}  } +static void i810_dma_dispatch_flip( drm_device_t *dev ) +{ +        drm_i810_private_t *dev_priv = dev->dev_private; +	RING_LOCALS; +	int pitch = dev_priv->pitch; + +	DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n",  +		__FUNCTION__,  +		dev_priv->current_page, +		dev_priv->sarea_priv->pf_current_page); +	 +        i810_kernel_lost_context(dev); + +	BEGIN_LP_RING( 2 ); +   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );  +	OUT_RING( 0 ); +	ADVANCE_LP_RING(); + +	BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 ); +	/* On i815 at least ASYNC is buggy */ +	/* pitch<<5 is from 11.2.8 p158, +	   its the pitch / 8 then left shifted 8, +	   so (pitch >> 3) << 8 */ +	OUT_RING( CMD_OP_FRONTBUFFER_INFO | (pitch<<5) /*| ASYNC_FLIP */ ); +	if ( dev_priv->current_page == 0 ) { +		OUT_RING( dev_priv->back_offset ); +		dev_priv->current_page = 1; +	} else { +		OUT_RING( dev_priv->front_offset ); +		dev_priv->current_page = 0; +	} +	OUT_RING(0); +	ADVANCE_LP_RING(); + +	BEGIN_LP_RING(2); +	OUT_RING( CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP ); +	OUT_RING( 0 ); +	ADVANCE_LP_RING(); + +	/* Increment the frame counter.  The client-side 3D driver must +	 * throttle the framerate by waiting for this value before +	 * performing the swapbuffer ioctl. +	 */ +	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + +}  void i810_dma_quiescent(drm_device_t *dev)  { @@ -1198,3 +1264,47 @@ int i810_ov0_flip(struct inode *inode, struct file *filp,  } +/* Not sure why this isn't set all the time: + */  +static void i810_do_init_pageflip( drm_device_t *dev ) +{ +	drm_i810_private_t *dev_priv = dev->dev_private; +	 +	DRM_DEBUG("%s\n", __FUNCTION__); +	dev_priv->page_flipping = 1; +	dev_priv->current_page = 0; +	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; +} + +int i810_do_cleanup_pageflip( drm_device_t *dev ) +{ +	drm_i810_private_t *dev_priv = dev->dev_private; + +	DRM_DEBUG("%s\n", __FUNCTION__); +	if (dev_priv->current_page != 0) +		i810_dma_dispatch_flip( dev ); + +	dev_priv->page_flipping = 0; +	return 0; +} + +int i810_flip_bufs(struct inode *inode, struct file *filp, +		   unsigned int cmd, unsigned long arg) +{ +	drm_file_t *priv = filp->private_data; +	drm_device_t *dev = priv->dev; +	drm_i810_private_t *dev_priv = dev->dev_private; + +	DRM_DEBUG("%s\n", __FUNCTION__); + +   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { +		DRM_ERROR("i810_flip_buf called without lock held\n"); +		return -EINVAL; +	} + +	if (!dev_priv->page_flipping)  +		i810_do_init_pageflip( dev ); + +	i810_dma_dispatch_flip( dev ); +   	return 0; +} diff --git a/linux/i810_drm.h b/linux/i810_drm.h index f8c27d83..b35593bd 100644 --- a/linux/i810_drm.h +++ b/linux/i810_drm.h @@ -166,6 +166,9 @@ typedef struct _drm_i810_sarea {  	int vertex_prim; +	int pf_enabled;               /* is pageflipping allowed? */ +	int pf_active; +	int pf_current_page;	    /* which buffer is being displayed? */  } drm_i810_sarea_t;  /* WARNING: If you change any of these defines, make sure to change the @@ -189,6 +192,7 @@ typedef struct _drm_i810_sarea {  #define DRM_IOCTL_I810_OV0FLIP		DRM_IO ( 0x4b)  #define DRM_IOCTL_I810_MC		DRM_IOW( 0x4c, drm_i810_mc_t)  #define DRM_IOCTL_I810_RSTATUS		DRM_IO ( 0x4d ) +#define DRM_IOCTL_I810_FLIP             DRM_IO ( 0x4e )  typedef struct _drm_i810_clear {  	int clear_color; diff --git a/linux/i810_drv.h b/linux/i810_drv.h index aa82c647..736c20d7 100644 --- a/linux/i810_drv.h +++ b/linux/i810_drv.h @@ -75,7 +75,20 @@ typedef struct drm_i810_private {  	int overlay_physical;  	int w, h;  	int pitch; +  	int back_pitch; +	int depth_pitch; +	int do_boxes; +	int dma_used; + +	int current_page; +	int page_flipping; + +	wait_queue_head_t irq_queue; +   	atomic_t irq_received; +   	atomic_t irq_emitted; +   +        int front_offset;  } drm_i810_private_t;  				/* i810_dma.c */ @@ -124,6 +137,8 @@ int i810_swap_bufs(struct inode *inode, struct file *filp,  int i810_clear_bufs(struct inode *inode, struct file *filp,  		    unsigned int cmd, unsigned long arg); +int i810_flip_bufs(struct inode *inode, struct file *filp, +		   unsigned int cmd, unsigned long arg);  #define I810_BASE(reg)		((unsigned long) \  				dev_priv->mmio_map->handle) @@ -225,12 +240,15 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,  #define CMD_OP_Z_BUFFER_INFO     ((0x0<<29)|(0x16<<23))  #define CMD_OP_DESTBUFFER_INFO   ((0x0<<29)|(0x15<<23))  #define CMD_OP_FRONTBUFFER_INFO  ((0x0<<29)|(0x14<<23)) +#define CMD_OP_WAIT_FOR_EVENT    ((0x0<<29)|(0x03<<23))  #define BR00_BITBLT_CLIENT   0x40000000  #define BR00_OP_COLOR_BLT    0x10000000  #define BR00_OP_SRC_COPY_BLT 0x10C00000  #define BR13_SOLID_PATTERN   0x80000000 - +#define WAIT_FOR_PLANE_A_SCANLINES (1<<1)  +#define WAIT_FOR_PLANE_A_FLIP      (1<<2)  +#define WAIT_FOR_VBLANK (1<<3)  #endif | 
