mach64_drv.h revision 152909
12116Sjkh/* mach64_drv.h -- Private header for mach64 driver -*- linux-c -*-
22116Sjkh * Created: Fri Nov 24 22:07:58 2000 by gareth@valinux.com
32116Sjkh */
42116Sjkh/*-
52116Sjkh * Copyright 2000 Gareth Hughes
62116Sjkh * Copyright 2002 Frank C. Earl
72116Sjkh * Copyright 2002-2003 Leif Delgass
82116Sjkh * All Rights Reserved.
92116Sjkh *
102116Sjkh * Permission is hereby granted, free of charge, to any person obtaining a
112116Sjkh * copy of this software and associated documentation files (the "Software"),
122116Sjkh * to deal in the Software without restriction, including without limitation
132116Sjkh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
142116Sjkh * and/or sell copies of the Software, and to permit persons to whom the
152116Sjkh * Software is furnished to do so, subject to the following conditions:
162116Sjkh *
172116Sjkh * The above copyright notice and this permission notice (including the next
182116Sjkh * paragraph) shall be included in all copies or substantial portions of the
192116Sjkh * Software.
202116Sjkh *
212116Sjkh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
222116Sjkh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
232116Sjkh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
242116Sjkh * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
252116Sjkh * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
262116Sjkh * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
272116Sjkh *
282116Sjkh * Authors:
292116Sjkh *    Gareth Hughes <gareth@valinux.com>
302116Sjkh *    Frank C. Earl <fearl@airmail.net>
312116Sjkh *    Leif Delgass <ldelgass@retinalburn.net>
322116Sjkh *    Jos���Fonseca <j_r_fonseca@yahoo.co.uk>
332116Sjkh */
342116Sjkh
352116Sjkh#include <sys/cdefs.h>
3623577Sbde__FBSDID("$FreeBSD: head/sys/dev/drm/mach64_drv.h 152909 2005-11-28 23:13:57Z anholt $");
37213337Sdim
382116Sjkh#ifndef __MACH64_DRV_H__
39141280Sdas#define __MACH64_DRV_H__
402116Sjkh
412116Sjkh/* General customization:
422116Sjkh */
43192760Sattilio
44217108Skib#define DRIVER_AUTHOR		"Gareth Hughes, Leif Delgass, Jos�� Fonseca"
45217108Skib
46#define DRIVER_NAME		"mach64"
47#define DRIVER_DESC		"DRM module for the ATI Rage Pro"
48#define DRIVER_DATE		"20020904"
49
50#define DRIVER_MAJOR		1
51#define DRIVER_MINOR		0
52#define DRIVER_PATCHLEVEL	0
53
54/* FIXME: remove these when not needed */
55/* Development driver options */
56#define MACH64_EXTRA_CHECKING     0	/* Extra sanity checks for DMA/freelist management */
57#define MACH64_VERBOSE		  0	/* Verbose debugging output */
58
59typedef struct drm_mach64_freelist {
60	struct list_head list;	/* List pointers for free_list, placeholders, or pending list */
61	drm_buf_t *buf;		/* Pointer to the buffer */
62	int discard;		/* This flag is set when we're done (re)using a buffer */
63	u32 ring_ofs;		/* dword offset in ring of last descriptor for this buffer */
64} drm_mach64_freelist_t;
65
66typedef struct drm_mach64_descriptor_ring {
67	drm_dma_handle_t *dmah;	/* Handle to pci dma memory */
68	void *start;		/* write pointer (cpu address) to start of descriptor ring */
69	u32 start_addr;		/* bus address of beginning of descriptor ring */
70	int size;		/* size of ring in bytes */
71
72	u32 head_addr;		/* bus address of descriptor ring head */
73	u32 head;		/* dword offset of descriptor ring head */
74	u32 tail;		/* dword offset of descriptor ring tail */
75	u32 tail_mask;		/* mask used to wrap ring */
76	int space;		/* number of free bytes in ring */
77} drm_mach64_descriptor_ring_t;
78
79typedef struct drm_mach64_private {
80	drm_mach64_sarea_t *sarea_priv;
81
82	int is_pci;
83	drm_mach64_dma_mode_t driver_mode;	/* Async DMA, sync DMA, or MMIO */
84
85	int usec_timeout;	/* Timeout for the wait functions */
86
87	drm_mach64_descriptor_ring_t ring;	/* DMA descriptor table (ring buffer) */
88	int ring_running;	/* Is bus mastering is enabled */
89
90	struct list_head free_list;	/* Free-list head */
91	struct list_head placeholders;	/* Placeholder list for buffers held by clients */
92	struct list_head pending;	/* Buffers pending completion */
93
94	u32 frame_ofs[MACH64_MAX_QUEUED_FRAMES];	/* dword ring offsets of most recent frame swaps */
95
96	unsigned int fb_bpp;
97	unsigned int front_offset, front_pitch;
98	unsigned int back_offset, back_pitch;
99
100	unsigned int depth_bpp;
101	unsigned int depth_offset, depth_pitch;
102
103	u32 front_offset_pitch;
104	u32 back_offset_pitch;
105	u32 depth_offset_pitch;
106
107	drm_local_map_t *sarea;
108	drm_local_map_t *fb;
109	drm_local_map_t *mmio;
110	drm_local_map_t *ring_map;
111	drm_local_map_t *dev_buffers;	/* this is a pointer to a structure in dev */
112	drm_local_map_t *agp_textures;
113} drm_mach64_private_t;
114
115extern drm_ioctl_desc_t mach64_ioctls[];
116extern int mach64_max_ioctl;
117
118				/* mach64_dma.c */
119extern int mach64_dma_init(DRM_IOCTL_ARGS);
120extern int mach64_dma_idle(DRM_IOCTL_ARGS);
121extern int mach64_dma_flush(DRM_IOCTL_ARGS);
122extern int mach64_engine_reset(DRM_IOCTL_ARGS);
123extern int mach64_dma_buffers(DRM_IOCTL_ARGS);
124extern void mach64_driver_lastclose(drm_device_t * dev);
125
126extern int mach64_init_freelist(drm_device_t * dev);
127extern void mach64_destroy_freelist(drm_device_t * dev);
128extern drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv);
129
130extern int mach64_do_wait_for_fifo(drm_mach64_private_t * dev_priv,
131				   int entries);
132extern int mach64_do_wait_for_idle(drm_mach64_private_t * dev_priv);
133extern int mach64_wait_ring(drm_mach64_private_t * dev_priv, int n);
134extern int mach64_do_dispatch_pseudo_dma(drm_mach64_private_t * dev_priv);
135extern int mach64_do_release_used_buffers(drm_mach64_private_t * dev_priv);
136extern void mach64_dump_engine_info(drm_mach64_private_t * dev_priv);
137extern void mach64_dump_ring_info(drm_mach64_private_t * dev_priv);
138extern int mach64_do_engine_reset(drm_mach64_private_t * dev_priv);
139
140extern int mach64_do_dma_idle(drm_mach64_private_t * dev_priv);
141extern int mach64_do_dma_flush(drm_mach64_private_t * dev_priv);
142extern int mach64_do_cleanup_dma(drm_device_t * dev);
143
144				/* mach64_state.c */
145extern int mach64_dma_clear(DRM_IOCTL_ARGS);
146extern int mach64_dma_swap(DRM_IOCTL_ARGS);
147extern int mach64_dma_vertex(DRM_IOCTL_ARGS);
148extern int mach64_dma_blit(DRM_IOCTL_ARGS);
149extern int mach64_get_param(DRM_IOCTL_ARGS);
150extern int mach64_driver_vblank_wait(drm_device_t * dev,
151				     unsigned int *sequence);
152
153extern irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS);
154extern void mach64_driver_irq_preinstall(drm_device_t * dev);
155extern void mach64_driver_irq_postinstall(drm_device_t * dev);
156extern void mach64_driver_irq_uninstall(drm_device_t * dev);
157
158/* ================================================================
159 * Registers
160 */
161
162#define MACH64_AGP_BASE				0x0148
163#define MACH64_AGP_CNTL				0x014c
164#define MACH64_ALPHA_TST_CNTL			0x0550
165
166#define MACH64_DSP_CONFIG 			0x0420
167#define MACH64_DSP_ON_OFF 			0x0424
168#define MACH64_EXT_MEM_CNTL 			0x04ac
169#define MACH64_GEN_TEST_CNTL 			0x04d0
170#define MACH64_HW_DEBUG 			0x047c
171#define MACH64_MEM_ADDR_CONFIG 			0x0434
172#define MACH64_MEM_BUF_CNTL 			0x042c
173#define MACH64_MEM_CNTL 			0x04b0
174
175#define MACH64_BM_ADDR				0x0648
176#define MACH64_BM_COMMAND			0x0188
177#define MACH64_BM_DATA				0x0648
178#define MACH64_BM_FRAME_BUF_OFFSET		0x0180
179#define MACH64_BM_GUI_TABLE			0x01b8
180#define MACH64_BM_GUI_TABLE_CMD			0x064c
181#	define MACH64_CIRCULAR_BUF_SIZE_16KB		(0 << 0)
182#	define MACH64_CIRCULAR_BUF_SIZE_32KB		(1 << 0)
183#	define MACH64_CIRCULAR_BUF_SIZE_64KB		(2 << 0)
184#	define MACH64_CIRCULAR_BUF_SIZE_128KB		(3 << 0)
185#	define MACH64_LAST_DESCRIPTOR			(1 << 31)
186#define MACH64_BM_HOSTDATA			0x0644
187#define MACH64_BM_STATUS			0x018c
188#define MACH64_BM_SYSTEM_MEM_ADDR		0x0184
189#define MACH64_BM_SYSTEM_TABLE			0x01bc
190#define MACH64_BUS_CNTL				0x04a0
191#	define MACH64_BUS_MSTR_RESET			(1 << 1)
192#	define MACH64_BUS_APER_REG_DIS			(1 << 4)
193#	define MACH64_BUS_FLUSH_BUF			(1 << 2)
194#	define MACH64_BUS_MASTER_DIS			(1 << 6)
195#	define MACH64_BUS_EXT_REG_EN			(1 << 27)
196
197#define MACH64_CLR_CMP_CLR			0x0700
198#define MACH64_CLR_CMP_CNTL			0x0708
199#define MACH64_CLR_CMP_MASK			0x0704
200#define MACH64_CONFIG_CHIP_ID 			0x04e0
201#define MACH64_CONFIG_CNTL 			0x04dc
202#define MACH64_CONFIG_STAT0 			0x04e4
203#define MACH64_CONFIG_STAT1 			0x0494
204#define MACH64_CONFIG_STAT2 			0x0498
205#define MACH64_CONTEXT_LOAD_CNTL		0x072c
206#define MACH64_CONTEXT_MASK			0x0720
207#define MACH64_COMPOSITE_SHADOW_ID		0x0798
208#define MACH64_CRC_SIG 				0x04e8
209#define MACH64_CUSTOM_MACRO_CNTL 		0x04d4
210
211#define MACH64_DP_BKGD_CLR			0x06c0
212#define MACH64_DP_FOG_CLR			0x06c4
213#define MACH64_DP_FGRD_BKGD_CLR			0x06e0
214#define MACH64_DP_FRGD_CLR			0x06c4
215#define MACH64_DP_FGRD_CLR_MIX			0x06dc
216
217#define MACH64_DP_MIX				0x06d4
218#	define BKGD_MIX_NOT_D				(0 << 0)
219#	define BKGD_MIX_ZERO				(1 << 0)
220#	define BKGD_MIX_ONE				(2 << 0)
221#	define MACH64_BKGD_MIX_D			(3 << 0)
222#	define BKGD_MIX_NOT_S				(4 << 0)
223#	define BKGD_MIX_D_XOR_S				(5 << 0)
224#	define BKGD_MIX_NOT_D_XOR_S			(6 << 0)
225#	define MACH64_BKGD_MIX_S			(7 << 0)
226#	define BKGD_MIX_NOT_D_OR_NOT_S			(8 << 0)
227#	define BKGD_MIX_D_OR_NOT_S			(9 << 0)
228#	define BKGD_MIX_NOT_D_OR_S			(10 << 0)
229#	define BKGD_MIX_D_OR_S				(11 << 0)
230#	define BKGD_MIX_D_AND_S				(12 << 0)
231#	define BKGD_MIX_NOT_D_AND_S			(13 << 0)
232#	define BKGD_MIX_D_AND_NOT_S			(14 << 0)
233#	define BKGD_MIX_NOT_D_AND_NOT_S			(15 << 0)
234#	define BKGD_MIX_D_PLUS_S_DIV2			(23 << 0)
235#	define FRGD_MIX_NOT_D				(0 << 16)
236#	define FRGD_MIX_ZERO				(1 << 16)
237#	define FRGD_MIX_ONE				(2 << 16)
238#	define FRGD_MIX_D				(3 << 16)
239#	define FRGD_MIX_NOT_S				(4 << 16)
240#	define FRGD_MIX_D_XOR_S				(5 << 16)
241#	define FRGD_MIX_NOT_D_XOR_S			(6 << 16)
242#	define MACH64_FRGD_MIX_S			(7 << 16)
243#	define FRGD_MIX_NOT_D_OR_NOT_S			(8 << 16)
244#	define FRGD_MIX_D_OR_NOT_S			(9 << 16)
245#	define FRGD_MIX_NOT_D_OR_S			(10 << 16)
246#	define FRGD_MIX_D_OR_S				(11 << 16)
247#	define FRGD_MIX_D_AND_S				(12 << 16)
248#	define FRGD_MIX_NOT_D_AND_S			(13 << 16)
249#	define FRGD_MIX_D_AND_NOT_S			(14 << 16)
250#	define FRGD_MIX_NOT_D_AND_NOT_S			(15 << 16)
251#	define FRGD_MIX_D_PLUS_S_DIV2			(23 << 16)
252
253#define MACH64_DP_PIX_WIDTH			0x06d0
254#	define MACH64_HOST_TRIPLE_ENABLE		(1 << 13)
255#	define MACH64_BYTE_ORDER_MSB_TO_LSB		(0 << 24)
256#	define MACH64_BYTE_ORDER_LSB_TO_MSB		(1 << 24)
257
258#define MACH64_DP_SRC				0x06d8
259#	define MACH64_BKGD_SRC_BKGD_CLR			(0 << 0)
260#	define MACH64_BKGD_SRC_FRGD_CLR			(1 << 0)
261#	define MACH64_BKGD_SRC_HOST			(2 << 0)
262#	define MACH64_BKGD_SRC_BLIT			(3 << 0)
263#	define MACH64_BKGD_SRC_PATTERN			(4 << 0)
264#	define MACH64_BKGD_SRC_3D			(5 << 0)
265#	define MACH64_FRGD_SRC_BKGD_CLR			(0 << 8)
266#	define MACH64_FRGD_SRC_FRGD_CLR			(1 << 8)
267#	define MACH64_FRGD_SRC_HOST			(2 << 8)
268#	define MACH64_FRGD_SRC_BLIT			(3 << 8)
269#	define MACH64_FRGD_SRC_PATTERN			(4 << 8)
270#	define MACH64_FRGD_SRC_3D			(5 << 8)
271#	define MACH64_MONO_SRC_ONE			(0 << 16)
272#	define MACH64_MONO_SRC_PATTERN			(1 << 16)
273#	define MACH64_MONO_SRC_HOST			(2 << 16)
274#	define MACH64_MONO_SRC_BLIT			(3 << 16)
275
276#define MACH64_DP_WRITE_MASK			0x06c8
277
278#define MACH64_DST_CNTL				0x0530
279#	define MACH64_DST_X_RIGHT_TO_LEFT		(0 << 0)
280#	define MACH64_DST_X_LEFT_TO_RIGHT		(1 << 0)
281#	define MACH64_DST_Y_BOTTOM_TO_TOP		(0 << 1)
282#	define MACH64_DST_Y_TOP_TO_BOTTOM		(1 << 1)
283#	define MACH64_DST_X_MAJOR			(0 << 2)
284#	define MACH64_DST_Y_MAJOR			(1 << 2)
285#	define MACH64_DST_X_TILE			(1 << 3)
286#	define MACH64_DST_Y_TILE			(1 << 4)
287#	define MACH64_DST_LAST_PEL			(1 << 5)
288#	define MACH64_DST_POLYGON_ENABLE		(1 << 6)
289#	define MACH64_DST_24_ROTATION_ENABLE		(1 << 7)
290
291#define MACH64_DST_HEIGHT_WIDTH			0x0518
292#define MACH64_DST_OFF_PITCH			0x0500
293#define MACH64_DST_WIDTH_HEIGHT			0x06ec
294#define MACH64_DST_X_Y				0x06e8
295#define MACH64_DST_Y_X				0x050c
296
297#define MACH64_FIFO_STAT			0x0710
298#	define MACH64_FIFO_SLOT_MASK			0x0000ffff
299#	define MACH64_FIFO_ERR				(1 << 31)
300
301#define MACH64_GEN_TEST_CNTL			0x04d0
302#	define MACH64_GUI_ENGINE_ENABLE			(1 << 8)
303#define MACH64_GUI_CMDFIFO_DEBUG		0x0170
304#define MACH64_GUI_CMDFIFO_DATA			0x0174
305#define MACH64_GUI_CNTL				0x0178
306#       define MACH64_CMDFIFO_SIZE_MASK                 0x00000003ul
307#       define MACH64_CMDFIFO_SIZE_192                  0x00000000ul
308#       define MACH64_CMDFIFO_SIZE_128                  0x00000001ul
309#       define MACH64_CMDFIFO_SIZE_64                   0x00000002ul
310#define MACH64_GUI_STAT				0x0738
311#	define MACH64_GUI_ACTIVE			(1 << 0)
312#define MACH64_GUI_TRAJ_CNTL			0x0730
313
314#define MACH64_HOST_CNTL			0x0640
315#define MACH64_HOST_DATA0			0x0600
316
317#define MACH64_ONE_OVER_AREA			0x029c
318#define MACH64_ONE_OVER_AREA_UC			0x0300
319
320#define MACH64_PAT_REG0				0x0680
321#define MACH64_PAT_REG1				0x0684
322
323#define MACH64_SC_LEFT                          0x06a0
324#define MACH64_SC_RIGHT                         0x06a4
325#define MACH64_SC_LEFT_RIGHT                    0x06a8
326#define MACH64_SC_TOP                           0x06ac
327#define MACH64_SC_BOTTOM                        0x06b0
328#define MACH64_SC_TOP_BOTTOM                    0x06b4
329
330#define MACH64_SCALE_3D_CNTL			0x05fc
331#define MACH64_SCRATCH_REG0			0x0480
332#define MACH64_SCRATCH_REG1			0x0484
333#define MACH64_SECONDARY_TEX_OFF		0x0778
334#define MACH64_SETUP_CNTL			0x0304
335#define MACH64_SRC_CNTL				0x05b4
336#	define MACH64_SRC_BM_ENABLE			(1 << 8)
337#	define MACH64_SRC_BM_SYNC			(1 << 9)
338#	define MACH64_SRC_BM_OP_FRAME_TO_SYSTEM		(0 << 10)
339#	define MACH64_SRC_BM_OP_SYSTEM_TO_FRAME		(1 << 10)
340#	define MACH64_SRC_BM_OP_REG_TO_SYSTEM		(2 << 10)
341#	define MACH64_SRC_BM_OP_SYSTEM_TO_REG		(3 << 10)
342#define MACH64_SRC_HEIGHT1			0x0594
343#define MACH64_SRC_HEIGHT2			0x05ac
344#define MACH64_SRC_HEIGHT1_WIDTH1		0x0598
345#define MACH64_SRC_HEIGHT2_WIDTH2		0x05b0
346#define MACH64_SRC_OFF_PITCH			0x0580
347#define MACH64_SRC_WIDTH1			0x0590
348#define MACH64_SRC_Y_X				0x058c
349
350#define MACH64_TEX_0_OFF			0x05c0
351#define MACH64_TEX_CNTL				0x0774
352#define MACH64_TEX_SIZE_PITCH			0x0770
353#define MACH64_TIMER_CONFIG 			0x0428
354
355#define MACH64_VERTEX_1_ARGB			0x0254
356#define MACH64_VERTEX_1_S			0x0240
357#define MACH64_VERTEX_1_SECONDARY_S		0x0328
358#define MACH64_VERTEX_1_SECONDARY_T		0x032c
359#define MACH64_VERTEX_1_SECONDARY_W		0x0330
360#define MACH64_VERTEX_1_SPEC_ARGB		0x024c
361#define MACH64_VERTEX_1_T			0x0244
362#define MACH64_VERTEX_1_W			0x0248
363#define MACH64_VERTEX_1_X_Y			0x0258
364#define MACH64_VERTEX_1_Z			0x0250
365#define MACH64_VERTEX_2_ARGB			0x0274
366#define MACH64_VERTEX_2_S			0x0260
367#define MACH64_VERTEX_2_SECONDARY_S		0x0334
368#define MACH64_VERTEX_2_SECONDARY_T		0x0338
369#define MACH64_VERTEX_2_SECONDARY_W		0x033c
370#define MACH64_VERTEX_2_SPEC_ARGB		0x026c
371#define MACH64_VERTEX_2_T			0x0264
372#define MACH64_VERTEX_2_W			0x0268
373#define MACH64_VERTEX_2_X_Y			0x0278
374#define MACH64_VERTEX_2_Z			0x0270
375#define MACH64_VERTEX_3_ARGB			0x0294
376#define MACH64_VERTEX_3_S			0x0280
377#define MACH64_VERTEX_3_SECONDARY_S		0x02a0
378#define MACH64_VERTEX_3_SECONDARY_T		0x02a4
379#define MACH64_VERTEX_3_SECONDARY_W		0x02a8
380#define MACH64_VERTEX_3_SPEC_ARGB		0x028c
381#define MACH64_VERTEX_3_T			0x0284
382#define MACH64_VERTEX_3_W			0x0288
383#define MACH64_VERTEX_3_X_Y			0x0298
384#define MACH64_VERTEX_3_Z			0x0290
385
386#define MACH64_Z_CNTL				0x054c
387#define MACH64_Z_OFF_PITCH			0x0548
388
389#define MACH64_CRTC_VLINE_CRNT_VLINE		0x0410
390#	define MACH64_CRTC_VLINE_MASK		        0x000007ff
391#	define MACH64_CRTC_CRNT_VLINE_MASK		0x07ff0000
392#define MACH64_CRTC_OFF_PITCH			0x0414
393#define MACH64_CRTC_INT_CNTL			0x0418
394#	define MACH64_CRTC_VBLANK			(1 << 0)
395#	define MACH64_CRTC_VBLANK_INT_EN		(1 << 1)
396#	define MACH64_CRTC_VBLANK_INT			(1 << 2)
397#	define MACH64_CRTC_VLINE_INT_EN			(1 << 3)
398#	define MACH64_CRTC_VLINE_INT			(1 << 4)
399#	define MACH64_CRTC_VLINE_SYNC			(1 << 5)	/* 0=even, 1=odd */
400#	define MACH64_CRTC_FRAME			(1 << 6)	/* 0=even, 1=odd */
401#	define MACH64_CRTC_SNAPSHOT_INT_EN		(1 << 7)
402#	define MACH64_CRTC_SNAPSHOT_INT			(1 << 8)
403#	define MACH64_CRTC_I2C_INT_EN			(1 << 9)
404#	define MACH64_CRTC_I2C_INT			(1 << 10)
405#	define MACH64_CRTC2_VBLANK			(1 << 11)	/* LT Pro */
406#	define MACH64_CRTC2_VBLANK_INT_EN		(1 << 12)	/* LT Pro */
407#	define MACH64_CRTC2_VBLANK_INT			(1 << 13)	/* LT Pro */
408#	define MACH64_CRTC2_VLINE_INT_EN		(1 << 14)	/* LT Pro */
409#	define MACH64_CRTC2_VLINE_INT			(1 << 15)	/* LT Pro */
410#	define MACH64_CRTC_CAPBUF0_INT_EN		(1 << 16)
411#	define MACH64_CRTC_CAPBUF0_INT			(1 << 17)
412#	define MACH64_CRTC_CAPBUF1_INT_EN		(1 << 18)
413#	define MACH64_CRTC_CAPBUF1_INT			(1 << 19)
414#	define MACH64_CRTC_OVERLAY_EOF_INT_EN		(1 << 20)
415#	define MACH64_CRTC_OVERLAY_EOF_INT		(1 << 21)
416#	define MACH64_CRTC_ONESHOT_CAP_INT_EN		(1 << 22)
417#	define MACH64_CRTC_ONESHOT_CAP_INT		(1 << 23)
418#	define MACH64_CRTC_BUSMASTER_EOL_INT_EN		(1 << 24)
419#	define MACH64_CRTC_BUSMASTER_EOL_INT		(1 << 25)
420#	define MACH64_CRTC_GP_INT_EN			(1 << 26)
421#	define MACH64_CRTC_GP_INT			(1 << 27)
422#	define MACH64_CRTC2_VLINE_SYNC			(1 << 28) /* LT Pro */	/* 0=even, 1=odd */
423#	define MACH64_CRTC_SNAPSHOT2_INT_EN		(1 << 29)	/* LT Pro */
424#	define MACH64_CRTC_SNAPSHOT2_INT		(1 << 30)	/* LT Pro */
425#	define MACH64_CRTC_VBLANK2_INT			(1 << 31)
426#	define MACH64_CRTC_INT_ENS				\
427		(						\
428			MACH64_CRTC_VBLANK_INT_EN |		\
429			MACH64_CRTC_VLINE_INT_EN |		\
430			MACH64_CRTC_SNAPSHOT_INT_EN |		\
431			MACH64_CRTC_I2C_INT_EN |		\
432			MACH64_CRTC2_VBLANK_INT_EN |		\
433			MACH64_CRTC2_VLINE_INT_EN |		\
434			MACH64_CRTC_CAPBUF0_INT_EN |		\
435			MACH64_CRTC_CAPBUF1_INT_EN |		\
436			MACH64_CRTC_OVERLAY_EOF_INT_EN |	\
437			MACH64_CRTC_ONESHOT_CAP_INT_EN |	\
438			MACH64_CRTC_BUSMASTER_EOL_INT_EN |	\
439			MACH64_CRTC_GP_INT_EN |			\
440			MACH64_CRTC_SNAPSHOT2_INT_EN |		\
441			0					\
442		)
443#	define MACH64_CRTC_INT_ACKS			\
444		(					\
445			MACH64_CRTC_VBLANK_INT |	\
446			MACH64_CRTC_VLINE_INT |		\
447			MACH64_CRTC_SNAPSHOT_INT |	\
448			MACH64_CRTC_I2C_INT |		\
449			MACH64_CRTC2_VBLANK_INT |	\
450			MACH64_CRTC2_VLINE_INT |	\
451			MACH64_CRTC_CAPBUF0_INT |	\
452			MACH64_CRTC_CAPBUF1_INT |	\
453			MACH64_CRTC_OVERLAY_EOF_INT |	\
454			MACH64_CRTC_ONESHOT_CAP_INT |	\
455			MACH64_CRTC_BUSMASTER_EOL_INT |	\
456			MACH64_CRTC_GP_INT |		\
457			MACH64_CRTC_SNAPSHOT2_INT |	\
458			MACH64_CRTC_VBLANK2_INT |	\
459			0				\
460		)
461
462#define MACH64_DATATYPE_CI8				2
463#define MACH64_DATATYPE_ARGB1555			3
464#define MACH64_DATATYPE_RGB565				4
465#define MACH64_DATATYPE_ARGB8888			6
466#define MACH64_DATATYPE_RGB332				7
467#define MACH64_DATATYPE_Y8				8
468#define MACH64_DATATYPE_RGB8				9
469#define MACH64_DATATYPE_VYUY422				11
470#define MACH64_DATATYPE_YVYU422				12
471#define MACH64_DATATYPE_AYUV444				14
472#define MACH64_DATATYPE_ARGB4444			15
473
474#define MACH64_READ(reg)	DRM_READ32(dev_priv->mmio, (reg) )
475#define MACH64_WRITE(reg,val)	DRM_WRITE32(dev_priv->mmio, (reg), (val) )
476
477#define DWMREG0		0x0400
478#define DWMREG0_END	0x07ff
479#define DWMREG1		0x0000
480#define DWMREG1_END	0x03ff
481
482#define ISREG0(r)	(((r) >= DWMREG0) && ((r) <= DWMREG0_END))
483#define DMAREG0(r)	(((r) - DWMREG0) >> 2)
484#define DMAREG1(r)	((((r) - DWMREG1) >> 2 ) | 0x0100)
485#define DMAREG(r)	(ISREG0(r) ? DMAREG0(r) : DMAREG1(r))
486
487#define MMREG0		0x0000
488#define MMREG0_END	0x00ff
489
490#define ISMMREG0(r)	(((r) >= MMREG0) && ((r) <= MMREG0_END))
491#define MMSELECT0(r)	(((r) << 2) + DWMREG0)
492#define MMSELECT1(r)	(((((r) & 0xff) << 2) + DWMREG1))
493#define MMSELECT(r)	(ISMMREG0(r) ? MMSELECT0(r) : MMSELECT1(r))
494
495/* ================================================================
496 * DMA constants
497 */
498
499/* DMA descriptor field indices:
500 * The descriptor fields are loaded into the read-only
501 * BM_* system bus master registers during a bus-master operation
502 */
503#define MACH64_DMA_FRAME_BUF_OFFSET	0	/* BM_FRAME_BUF_OFFSET */
504#define MACH64_DMA_SYS_MEM_ADDR		1	/* BM_SYSTEM_MEM_ADDR */
505#define MACH64_DMA_COMMAND		2	/* BM_COMMAND */
506#define MACH64_DMA_RESERVED		3	/* BM_STATUS */
507
508/* BM_COMMAND descriptor field flags */
509#define MACH64_DMA_HOLD_OFFSET		(1<<30)	/* Don't increment DMA_FRAME_BUF_OFFSET */
510#define MACH64_DMA_EOL			(1<<31)	/* End of descriptor list flag */
511
512#define MACH64_DMA_CHUNKSIZE	        0x1000	/* 4kB per DMA descriptor */
513#define MACH64_APERTURE_OFFSET	        0x7ff800	/* frame-buffer offset for gui-masters */
514
515/* ================================================================
516 * Misc helper macros
517 */
518
519static __inline__ void mach64_set_dma_eol(volatile u32 * addr)
520{
521#if defined(__i386__)
522	int nr = 31;
523
524	/* Taken from include/asm-i386/bitops.h linux header */
525	__asm__ __volatile__("lock;" "btsl %1,%0":"=m"(*addr)
526			     :"Ir"(nr));
527#elif defined(__powerpc__)
528	u32 old;
529	u32 mask = cpu_to_le32(MACH64_DMA_EOL);
530
531	/* Taken from the include/asm-ppc/bitops.h linux header */
532	__asm__ __volatile__("\n\
5331:	lwarx	%0,0,%3 \n\
534	or	%0,%0,%2 \n\
535	stwcx.	%0,0,%3 \n\
536	bne-	1b":"=&r"(old), "=m"(*addr)
537			     :"r"(mask), "r"(addr), "m"(*addr)
538			     :"cc");
539#elif defined(__alpha__)
540	u32 temp;
541	u32 mask = MACH64_DMA_EOL;
542
543	/* Taken from the include/asm-alpha/bitops.h linux header */
544	__asm__ __volatile__("1:	ldl_l %0,%3\n"
545			     "	bis %0,%2,%0\n"
546			     "	stl_c %0,%1\n"
547			     "	beq %0,2f\n"
548			     ".subsection 2\n"
549			     "2:	br 1b\n"
550			     ".previous":"=&r"(temp), "=m"(*addr)
551			     :"Ir"(mask), "m"(*addr));
552#else
553	u32 mask = cpu_to_le32(MACH64_DMA_EOL);
554
555	*addr |= mask;
556#endif
557}
558
559static __inline__ void mach64_clear_dma_eol(volatile u32 * addr)
560{
561#if defined(__i386__)
562	int nr = 31;
563
564	/* Taken from include/asm-i386/bitops.h linux header */
565	__asm__ __volatile__("lock;" "btrl %1,%0":"=m"(*addr)
566			     :"Ir"(nr));
567#elif defined(__powerpc__)
568	u32 old;
569	u32 mask = cpu_to_le32(MACH64_DMA_EOL);
570
571	/* Taken from the include/asm-ppc/bitops.h linux header */
572	__asm__ __volatile__("\n\
5731:	lwarx	%0,0,%3 \n\
574	andc	%0,%0,%2 \n\
575	stwcx.	%0,0,%3 \n\
576	bne-	1b":"=&r"(old), "=m"(*addr)
577			     :"r"(mask), "r"(addr), "m"(*addr)
578			     :"cc");
579#elif defined(__alpha__)
580	u32 temp;
581	u32 mask = ~MACH64_DMA_EOL;
582
583	/* Taken from the include/asm-alpha/bitops.h linux header */
584	__asm__ __volatile__("1:	ldl_l %0,%3\n"
585			     "	and %0,%2,%0\n"
586			     "	stl_c %0,%1\n"
587			     "	beq %0,2f\n"
588			     ".subsection 2\n"
589			     "2:	br 1b\n"
590			     ".previous":"=&r"(temp), "=m"(*addr)
591			     :"Ir"(mask), "m"(*addr));
592#else
593	u32 mask = cpu_to_le32(~MACH64_DMA_EOL);
594
595	*addr &= mask;
596#endif
597}
598
599static __inline__ void mach64_ring_start(drm_mach64_private_t * dev_priv)
600{
601	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
602
603	DRM_DEBUG("%s: head_addr: 0x%08x head: %d tail: %d space: %d\n",
604		  __FUNCTION__,
605		  ring->head_addr, ring->head, ring->tail, ring->space);
606
607	if (mach64_do_wait_for_idle(dev_priv) < 0) {
608		mach64_do_engine_reset(dev_priv);
609	}
610
611	if (dev_priv->driver_mode != MACH64_MODE_MMIO) {
612		/* enable bus mastering and block 1 registers */
613		MACH64_WRITE(MACH64_BUS_CNTL,
614			     (MACH64_READ(MACH64_BUS_CNTL) &
615			      ~MACH64_BUS_MASTER_DIS)
616			     | MACH64_BUS_EXT_REG_EN);
617		mach64_do_wait_for_idle(dev_priv);
618	}
619
620	/* reset descriptor table ring head */
621	MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
622		     ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
623
624	dev_priv->ring_running = 1;
625}
626
627static __inline__ void mach64_ring_resume(drm_mach64_private_t * dev_priv,
628					  drm_mach64_descriptor_ring_t * ring)
629{
630	DRM_DEBUG("%s: head_addr: 0x%08x head: %d tail: %d space: %d\n",
631		  __FUNCTION__,
632		  ring->head_addr, ring->head, ring->tail, ring->space);
633
634	/* reset descriptor table ring head */
635	MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
636		     ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
637
638	if (dev_priv->driver_mode == MACH64_MODE_MMIO) {
639		mach64_do_dispatch_pseudo_dma(dev_priv);
640	} else {
641		/* enable GUI bus mastering, and sync the bus master to the GUI */
642		MACH64_WRITE(MACH64_SRC_CNTL,
643			     MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC |
644			     MACH64_SRC_BM_OP_SYSTEM_TO_REG);
645
646		/* kick off the transfer */
647		MACH64_WRITE(MACH64_DST_HEIGHT_WIDTH, 0);
648		if (dev_priv->driver_mode == MACH64_MODE_DMA_SYNC) {
649			if ((mach64_do_wait_for_idle(dev_priv)) < 0) {
650				DRM_ERROR("%s: idle failed, resetting engine\n",
651					  __FUNCTION__);
652				mach64_dump_engine_info(dev_priv);
653				mach64_do_engine_reset(dev_priv);
654				return;
655			}
656			mach64_do_release_used_buffers(dev_priv);
657		}
658	}
659}
660
661static __inline__ void mach64_ring_tick(drm_mach64_private_t * dev_priv,
662					drm_mach64_descriptor_ring_t * ring)
663{
664	DRM_DEBUG("%s: head_addr: 0x%08x head: %d tail: %d space: %d\n",
665		  __FUNCTION__,
666		  ring->head_addr, ring->head, ring->tail, ring->space);
667
668	if (!dev_priv->ring_running) {
669		mach64_ring_start(dev_priv);
670
671		if (ring->head != ring->tail) {
672			mach64_ring_resume(dev_priv, ring);
673		}
674	} else {
675		/* GUI_ACTIVE must be read before BM_GUI_TABLE to
676		 * correctly determine the ring head
677		 */
678		int gui_active =
679		    MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE;
680
681		ring->head_addr = MACH64_READ(MACH64_BM_GUI_TABLE) & 0xfffffff0;
682
683		if (gui_active) {
684			/* If not idle, BM_GUI_TABLE points one descriptor
685			 * past the current head
686			 */
687			if (ring->head_addr == ring->start_addr) {
688				ring->head_addr += ring->size;
689			}
690			ring->head_addr -= 4 * sizeof(u32);
691		}
692
693		if (ring->head_addr < ring->start_addr ||
694		    ring->head_addr >= ring->start_addr + ring->size) {
695			DRM_ERROR("bad ring head address: 0x%08x\n",
696				  ring->head_addr);
697			mach64_dump_ring_info(dev_priv);
698			mach64_do_engine_reset(dev_priv);
699			return;
700		}
701
702		ring->head = (ring->head_addr - ring->start_addr) / sizeof(u32);
703
704		if (!gui_active && ring->head != ring->tail) {
705			mach64_ring_resume(dev_priv, ring);
706		}
707	}
708}
709
710static __inline__ void mach64_ring_stop(drm_mach64_private_t * dev_priv)
711{
712	DRM_DEBUG("%s: head_addr: 0x%08x head: %d tail: %d space: %d\n",
713		  __FUNCTION__,
714		  dev_priv->ring.head_addr, dev_priv->ring.head,
715		  dev_priv->ring.tail, dev_priv->ring.space);
716
717	/* restore previous SRC_CNTL to disable busmastering */
718	mach64_do_wait_for_fifo(dev_priv, 1);
719	MACH64_WRITE(MACH64_SRC_CNTL, 0);
720
721	/* disable busmastering but keep the block 1 registers enabled */
722	mach64_do_wait_for_idle(dev_priv);
723	MACH64_WRITE(MACH64_BUS_CNTL, MACH64_READ(MACH64_BUS_CNTL)
724		     | MACH64_BUS_MASTER_DIS | MACH64_BUS_EXT_REG_EN);
725
726	dev_priv->ring_running = 0;
727}
728
729static __inline__ void
730mach64_update_ring_snapshot(drm_mach64_private_t * dev_priv)
731{
732	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
733
734	DRM_DEBUG("%s\n", __FUNCTION__);
735
736	mach64_ring_tick(dev_priv, ring);
737
738	ring->space = (ring->head - ring->tail) * sizeof(u32);
739	if (ring->space <= 0) {
740		ring->space += ring->size;
741	}
742}
743
744/* ================================================================
745 * DMA descriptor ring macros
746 */
747
748#define RING_LOCALS									\
749	int _ring_tail, _ring_write; unsigned int _ring_mask; volatile u32 *_ring
750
751#define RING_WRITE_OFS  _ring_write
752
753#define BEGIN_RING( n ) 								\
754do {											\
755	if ( MACH64_VERBOSE ) {								\
756		DRM_INFO( "BEGIN_RING( %d ) in %s\n",					\
757			   (n), __FUNCTION__ );						\
758	}										\
759	if ( dev_priv->ring.space <= (n) * sizeof(u32) ) {				\
760		int ret;								\
761		if ((ret=mach64_wait_ring( dev_priv, (n) * sizeof(u32))) < 0 ) {	\
762			DRM_ERROR( "wait_ring failed, resetting engine\n");		\
763			mach64_dump_engine_info( dev_priv );				\
764			mach64_do_engine_reset( dev_priv );				\
765			return ret;							\
766		}									\
767	}										\
768	dev_priv->ring.space -= (n) * sizeof(u32);					\
769	_ring = (u32 *) dev_priv->ring.start;						\
770	_ring_tail = _ring_write = dev_priv->ring.tail;					\
771	_ring_mask = dev_priv->ring.tail_mask;						\
772} while (0)
773
774#define OUT_RING( x )						\
775do {								\
776	if ( MACH64_VERBOSE ) {					\
777		DRM_INFO( "   OUT_RING( 0x%08x ) at 0x%x\n",	\
778			   (unsigned int)(x), _ring_write );	\
779	}							\
780	_ring[_ring_write++] = cpu_to_le32( x );		\
781	_ring_write &= _ring_mask;				\
782} while (0)
783
784#define ADVANCE_RING() 							\
785do {									\
786	if ( MACH64_VERBOSE ) {						\
787		DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n",	\
788			  _ring_write, _ring_tail );			\
789	}								\
790	DRM_MEMORYBARRIER();						\
791	mach64_clear_dma_eol( &_ring[(_ring_tail - 2) & _ring_mask] );	\
792	DRM_MEMORYBARRIER();						\
793	dev_priv->ring.tail = _ring_write;				\
794	mach64_ring_tick( dev_priv, &(dev_priv)->ring );		\
795} while (0)
796
797/* ================================================================
798 * DMA macros
799 */
800
801#define DMALOCALS				\
802	drm_mach64_freelist_t *_entry = NULL;	\
803	drm_buf_t *_buf = NULL; 		\
804	u32 *_buf_wptr; int _outcount
805
806#define GETBUFPTR( __buf )						\
807((dev_priv->is_pci) ? 							\
808	((u32 *)(__buf)->address) : 					\
809	((u32 *)((char *)dev_priv->dev_buffers->handle + (__buf)->offset)))
810
811#define GETBUFADDR( __buf ) ((u32)(__buf)->bus_address)
812
813#define GETRINGOFFSET() (_entry->ring_ofs)
814
815static __inline__ int mach64_find_pending_buf_entry(drm_mach64_private_t *
816						    dev_priv,
817						    drm_mach64_freelist_t **
818						    entry, drm_buf_t * buf)
819{
820	struct list_head *ptr;
821#if MACH64_EXTRA_CHECKING
822	if (list_empty(&dev_priv->pending)) {
823		DRM_ERROR("Empty pending list in %s\n", __FUNCTION__);
824		return DRM_ERR(EINVAL);
825	}
826#endif
827	ptr = dev_priv->pending.prev;
828	*entry = list_entry(ptr, drm_mach64_freelist_t, list);
829	while ((*entry)->buf != buf) {
830		if (ptr == &dev_priv->pending) {
831			return DRM_ERR(EFAULT);
832		}
833		ptr = ptr->prev;
834		*entry = list_entry(ptr, drm_mach64_freelist_t, list);
835	}
836	return 0;
837}
838
839#define DMASETPTR( _p ) 			\
840do {						\
841	_buf = (_p);				\
842	_outcount = 0;				\
843	_buf_wptr = GETBUFPTR( _buf );		\
844} while(0)
845
846/* FIXME: use a private set of smaller buffers for state emits, clears, and swaps? */
847#define DMAGETPTR( filp, dev_priv, n )					\
848do {									\
849	if ( MACH64_VERBOSE ) {						\
850		DRM_INFO( "DMAGETPTR( %d ) in %s\n",			\
851			  n, __FUNCTION__ );				\
852	}								\
853	_buf = mach64_freelist_get( dev_priv );				\
854	if (_buf == NULL) {						\
855		DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n",	\
856			   __FUNCTION__ );				\
857		return DRM_ERR(EAGAIN);					\
858	}								\
859	if (_buf->pending) {						\
860	        DRM_ERROR("%s: pending buf in DMAGETPTR\n",		\
861			   __FUNCTION__ );				\
862		return DRM_ERR(EFAULT);					\
863	}								\
864	_buf->filp = filp;						\
865	_outcount = 0;							\
866									\
867        _buf_wptr = GETBUFPTR( _buf );					\
868} while (0)
869
870#define DMAOUTREG( reg, val )					\
871do {								\
872	if ( MACH64_VERBOSE ) {					\
873		DRM_INFO( "   DMAOUTREG( 0x%x = 0x%08x )\n",	\
874			  reg, val );				\
875	}							\
876	_buf_wptr[_outcount++] = cpu_to_le32(DMAREG(reg));	\
877	_buf_wptr[_outcount++] = cpu_to_le32((val));		\
878	_buf->used += 8;					\
879} while (0)
880
881#define DMAADVANCE( dev_priv, _discard )						     \
882do {											     \
883	struct list_head *ptr;								     \
884	RING_LOCALS;									     \
885											     \
886	if ( MACH64_VERBOSE ) {								     \
887		DRM_INFO( "DMAADVANCE() in %s\n", __FUNCTION__ );			     \
888	}										     \
889											     \
890	if (_buf->used <= 0) {								     \
891		DRM_ERROR( "DMAADVANCE() in %s: sending empty buf %d\n",		     \
892				   __FUNCTION__, _buf->idx );				     \
893		return DRM_ERR(EFAULT);							     \
894	}										     \
895	if (_buf->pending) {								     \
896                /* This is a resued buffer, so we need to find it in the pending list */     \
897		int ret;								     \
898		if ( (ret=mach64_find_pending_buf_entry(dev_priv, &_entry, _buf)) ) {	     \
899			DRM_ERROR( "DMAADVANCE() in %s: couldn't find pending buf %d\n",     \
900				   __FUNCTION__, _buf->idx );				     \
901			return ret;							     \
902		}									     \
903		if (_entry->discard) {							     \
904			DRM_ERROR( "DMAADVANCE() in %s: sending discarded pending buf %d\n", \
905				   __FUNCTION__, _buf->idx );				     \
906			return DRM_ERR(EFAULT);						     \
907		}									     \
908     	} else {									     \
909		if (list_empty(&dev_priv->placeholders)) {				     \
910			DRM_ERROR( "DMAADVANCE() in %s: empty placeholder list\n",	     \
911			   	__FUNCTION__ );						     \
912			return DRM_ERR(EFAULT);						     \
913		}									     \
914		ptr = dev_priv->placeholders.next;					     \
915		list_del(ptr);								     \
916		_entry = list_entry(ptr, drm_mach64_freelist_t, list);			     \
917		_buf->pending = 1;							     \
918		_entry->buf = _buf;							     \
919		list_add_tail(ptr, &dev_priv->pending);					     \
920	}										     \
921	_entry->discard = (_discard);							     \
922	ADD_BUF_TO_RING( dev_priv );							     \
923} while (0)
924
925#define DMADISCARDBUF()									\
926do {											\
927	if (_entry == NULL) {								\
928		int ret;								\
929		if ( (ret=mach64_find_pending_buf_entry(dev_priv, &_entry, _buf)) ) {	\
930			DRM_ERROR( "%s: couldn't find pending buf %d\n",		\
931				   __FUNCTION__, _buf->idx );				\
932			return ret;							\
933		}									\
934	}										\
935	_entry->discard = 1;								\
936} while(0)
937
938#define ADD_BUF_TO_RING( dev_priv )							\
939do {											\
940	int bytes, pages, remainder;							\
941	u32 address, page;								\
942	int i;										\
943											\
944	bytes = _buf->used;								\
945	address = GETBUFADDR( _buf );							\
946											\
947	pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE;		\
948											\
949	BEGIN_RING( pages * 4 );							\
950											\
951	for ( i = 0 ; i < pages-1 ; i++ ) {						\
952		page = address + i * MACH64_DMA_CHUNKSIZE;				\
953		OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR );			\
954		OUT_RING( page );							\
955		OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET );		\
956		OUT_RING( 0 );								\
957	}										\
958											\
959	/* generate the final descriptor for any remaining commands in this buffer */	\
960	page = address + i * MACH64_DMA_CHUNKSIZE;					\
961	remainder = bytes - i * MACH64_DMA_CHUNKSIZE;					\
962											\
963	/* Save dword offset of last descriptor for this buffer.			\
964	 * This is needed to check for completion of the buffer in freelist_get		\
965	 */										\
966	_entry->ring_ofs = RING_WRITE_OFS;						\
967											\
968	OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR );				\
969	OUT_RING( page );								\
970	OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL );		\
971	OUT_RING( 0 );									\
972											\
973	ADVANCE_RING();									\
974} while(0)
975
976#define DMAADVANCEHOSTDATA( dev_priv )							\
977do {											\
978	struct list_head *ptr;								\
979	RING_LOCALS;									\
980											\
981	if ( MACH64_VERBOSE ) {								\
982		DRM_INFO( "DMAADVANCEHOSTDATA() in %s\n", __FUNCTION__ );		\
983	}										\
984											\
985	if (_buf->used <= 0) {								\
986		DRM_ERROR( "DMAADVANCEHOSTDATA() in %s: sending empty buf %d\n",	\
987				   __FUNCTION__, _buf->idx );				\
988		return DRM_ERR(EFAULT);							\
989	}										\
990	if (list_empty(&dev_priv->placeholders)) {					\
991		DRM_ERROR( "%s: empty placeholder list in DMAADVANCEHOSTDATA()\n",	\
992			   __FUNCTION__ );						\
993		return DRM_ERR(EFAULT);							\
994	}										\
995											\
996        ptr = dev_priv->placeholders.next;						\
997	list_del(ptr);									\
998	_entry = list_entry(ptr, drm_mach64_freelist_t, list);				\
999	_entry->buf = _buf;								\
1000	_entry->buf->pending = 1;							\
1001	list_add_tail(ptr, &dev_priv->pending);						\
1002	_entry->discard = 1;								\
1003	ADD_HOSTDATA_BUF_TO_RING( dev_priv );						\
1004} while (0)
1005
1006#define ADD_HOSTDATA_BUF_TO_RING( dev_priv )						 \
1007do {											 \
1008	int bytes, pages, remainder;							 \
1009	u32 address, page;								 \
1010	int i;										 \
1011											 \
1012	bytes = _buf->used - MACH64_HOSTDATA_BLIT_OFFSET;				 \
1013	pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE;		 \
1014	address = GETBUFADDR( _buf );							 \
1015											 \
1016	BEGIN_RING( 4 + pages * 4 );							 \
1017											 \
1018	OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR );				 \
1019	OUT_RING( address );								 \
1020	OUT_RING( MACH64_HOSTDATA_BLIT_OFFSET | MACH64_DMA_HOLD_OFFSET );		 \
1021	OUT_RING( 0 );									 \
1022											 \
1023	address += MACH64_HOSTDATA_BLIT_OFFSET;						 \
1024											 \
1025	for ( i = 0 ; i < pages-1 ; i++ ) {						 \
1026		page = address + i * MACH64_DMA_CHUNKSIZE;				 \
1027		OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA );		 \
1028		OUT_RING( page );							 \
1029		OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET );		 \
1030		OUT_RING( 0 );								 \
1031	}										 \
1032											 \
1033	/* generate the final descriptor for any remaining commands in this buffer */	 \
1034	page = address + i * MACH64_DMA_CHUNKSIZE;					 \
1035	remainder = bytes - i * MACH64_DMA_CHUNKSIZE;					 \
1036											 \
1037	/* Save dword offset of last descriptor for this buffer.			 \
1038	 * This is needed to check for completion of the buffer in freelist_get		 \
1039	 */										 \
1040	_entry->ring_ofs = RING_WRITE_OFS;						 \
1041											 \
1042	OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA );			 \
1043	OUT_RING( page );								 \
1044	OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL );		 \
1045	OUT_RING( 0 );									 \
1046											 \
1047	ADVANCE_RING();									 \
1048} while(0)
1049
1050#endif				/* __MACH64_DRV_H__ */
1051