1/*
2	Copyright (c) 2002-04, Thomas Kurschel
3
4
5	Part of Radeon accelerant
6
7	DMA engine handling.
8
9	Currently, VID DMA is always used and data is always copied from
10	graphics memory to other memory.
11*/
12
13#include "radeon_driver.h"
14#include "mmio.h"
15#include "rbbm_regs.h"
16#include "dma_regs.h"
17#include <string.h>
18
19// this is arbitrary and hopefully sufficiently high
20#define RADEON_MAX_DMA_SIZE			16*1024*1024
21
22
23// initialize DMA engine
24status_t Radeon_InitDMA( device_info *di )
25{
26	status_t res;
27
28	// allocate descriptor table in graphics mem
29	// (docu says that is _must_ be in graphics mem)
30	di->dma_desc_max_num = RADEON_MAX_DMA_SIZE / 4096;
31
32	res = mem_alloc( di->memmgr[mt_local], di->dma_desc_max_num * sizeof( DMA_descriptor ), 0,
33		&di->dma_desc_handle, &di->dma_desc_offset );
34
35	if( res != B_OK )
36		return res;
37
38	// allow DMA IRQ
39	OUTREGP( di->regs, RADEON_GEN_INT_CNTL, RADEON_VIDDMA_MASK, ~RADEON_VIDDMA_MASK );
40	// acknowledge possibly pending IRQ
41	OUTREG( di->regs, RADEON_GEN_INT_STATUS, RADEON_VIDDMA_AK );
42
43	return B_OK;
44}
45
46
47// prepare DMA engine to copy data from graphics mem to other mem
48static status_t Radeon_PrepareDMA(
49	device_info *di, uint32 src, char *target, size_t size, bool lock_mem, bool contiguous )
50{
51	physical_entry map[16];
52	status_t res;
53	DMA_descriptor *cur_desc;
54	int num_desc;
55
56	if( lock_mem && !contiguous ) {
57		res = lock_memory( target, size, B_DMA_IO | B_READ_DEVICE );
58
59		if( res != B_OK ) {
60			SHOW_ERROR( 2, "Cannot lock memory (%s)", strerror( res ));
61			return res;
62		}
63	}
64
65	// adjust virtual address for graphics card
66	src += di->si->memory[mt_local].virtual_addr_start;
67
68	cur_desc = (DMA_descriptor *)(di->si->local_mem + di->dma_desc_offset);
69	num_desc = 0;
70
71	// memory may be fragmented, so we create S/G list
72	while( size > 0 ) {
73		int i;
74
75		if( contiguous ) {
76			// if memory is contiguous, ask for start address only to reduce work
77			get_memory_map( target, 1, map, 16 );
78			// replace received size with total size
79			map[0].size = size;
80		} else {
81			get_memory_map( target, size, map, 16 );
82		}
83
84		for( i = 0; i < 16; ++i ) {
85			phys_addr_t address = map[i].address;
86			size_t contig_size = map[i].size;
87
88			if( contig_size == 0 )
89				break;
90
91#if B_HAIKU_PHYSICAL_BITS > 32
92			if (address + contig_size > (phys_addr_t)1 << 32) {
93				SHOW_ERROR(2, "Physical address > 4 GB: %#" B_PRIxPHYSADDR
94					"size: %#" B_PRIxSIZE, address, size);
95				res = B_BAD_VALUE;
96				goto err;
97			}
98#endif
99
100			target += contig_size;
101
102			while( contig_size > 0 ) {
103				size_t cur_size;
104
105				cur_size = min( contig_size, RADEON_DMA_DESC_MAX_SIZE );
106
107				if( ++num_desc > (int)di->dma_desc_max_num ) {
108					SHOW_ERROR( 2, "Overflow of DMA descriptors, %ld bytes left", size );
109					res = B_BAD_VALUE;
110					goto err;
111				}
112
113				cur_desc->src_address = src;
114				cur_desc->dest_address = address;
115				cur_desc->command = cur_size;
116				cur_desc->res = 0;
117
118				++cur_desc;
119				address += cur_size;
120				contig_size -= cur_size;
121				src += cur_size;
122				size -= cur_size;
123			}
124		}
125	}
126
127	// mark last descriptor as being last one
128	(cur_desc - 1)->command |= RADEON_DMA_COMMAND_EOL;
129
130	return B_OK;
131
132err:
133	if( lock_mem && !contiguous )
134		unlock_memory( target, size, B_DMA_IO| B_READ_DEVICE );
135
136	return res;
137}
138
139
140// finish DMA
141// caller must ensure that DMA channel has stopped
142static void Radeon_FinishDMA(
143	device_info *di, uint32 src, char *target, size_t size, bool lock_mem, bool contiguous )
144{
145	if( lock_mem && !contiguous )
146		unlock_memory( target, size, B_DMA_IO| B_READ_DEVICE );
147}
148
149
150// copy from graphics memory to other memory via DMA
151// 	src		- offset in graphics mem
152//	target	- target address
153//	size	- number of bytes to copy
154//	lock_mem - true, if memory is not locked
155//	contiguous - true, if memory is physically contiguous (implies lock_mem=false)
156status_t Radeon_DMACopy(
157	device_info *di, uint32 src, char *target, size_t size, bool lock_mem, bool contiguous )
158{
159	status_t res;
160
161	/*SHOW_FLOW( 0, "src=%ld, target=%p, size=%ld, lock_mem=%d, contiguous=%d",
162		src, target, size, lock_mem, contiguous );*/
163
164	res =  Radeon_PrepareDMA( di, src, target, size, lock_mem, contiguous );
165	if( res != B_OK )
166		return res;
167
168	//SHOW_FLOW0( 0, "2" );
169
170	OUTREG( di->regs, RADEON_DMA_VID_TABLE_ADDR, di->si->memory[mt_local].virtual_addr_start +
171		di->dma_desc_offset );
172
173	res = acquire_sem_etc( di->dma_sem, 1, B_RELATIVE_TIMEOUT, 1000000 );
174
175	// be sure that transmission is really finished
176	while( (INREG( di->regs, RADEON_DMA_VID_STATUS ) & RADEON_DMA_STATUS_ACTIVE) != 0 ) {
177		SHOW_FLOW0( 0, "DMA transmission still active" );
178		snooze( 1000 );
179	}
180
181	Radeon_FinishDMA( di, src, target, size, lock_mem, contiguous );
182
183	//SHOW_FLOW0( 0, "3" );
184
185	return res;
186}
187