xref: /haiku/src/add-ons/accelerants/radeon_hd/accelerant.cpp (revision a6e73cb9e8addfe832c064bfcb68067f1c2fa3eb)
1 /*
2  * Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Alexander von Gluck, kallisti5@unixzen.com
8  */
9 
10 
11 #include "accelerant_protos.h"
12 #include "accelerant.h"
13 
14 #include "utility.h"
15 #include "pll.h"
16 #include "mc.h"
17 
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <syslog.h>
23 
24 #include <AGP.h>
25 
26 
27 #define TRACE_ACCELERANT
28 #ifdef TRACE_ACCELERANT
29 extern "C" void _sPrintf(const char *format, ...);
30 #	define TRACE(x...) _sPrintf("radeon_hd: " x)
31 #else
32 #	define TRACE(x...) ;
33 #endif
34 
35 
36 struct accelerant_info *gInfo;
37 struct register_info *gRegister;
38 crt_info *gCRT[MAX_CRT];
39 
40 
41 class AreaCloner {
42 public:
43 								AreaCloner();
44 								~AreaCloner();
45 
46 			area_id				Clone(const char *name, void **_address,
47 									uint32 spec, uint32 protection,
48 									area_id sourceArea);
49 			status_t			InitCheck()
50 									{return fArea < 0 ? (status_t)fArea : B_OK;}
51 			void				Keep();
52 
53 private:
54 			area_id				fArea;
55 };
56 
57 
58 AreaCloner::AreaCloner()
59 	:
60 	fArea(-1)
61 {
62 }
63 
64 
65 AreaCloner::~AreaCloner()
66 {
67 	if (fArea >= 0)
68 		delete_area(fArea);
69 }
70 
71 
72 area_id
73 AreaCloner::Clone(const char *name, void **_address, uint32 spec,
74 	uint32 protection, area_id sourceArea)
75 {
76 	fArea = clone_area(name, _address, spec, protection, sourceArea);
77 	return fArea;
78 }
79 
80 
81 void
82 AreaCloner::Keep()
83 {
84 	fArea = -1;
85 }
86 
87 
88 //	#pragma mark -
89 
90 
91 /*! This is the common accelerant_info initializer. It is called by
92 	both, the first accelerant and all clones.
93 */
94 static status_t
95 init_common(int device, bool isClone)
96 {
97 	// initialize global accelerant info structure
98 
99 	gInfo = (accelerant_info *)malloc(sizeof(accelerant_info));
100 	gRegister = (register_info *)malloc(sizeof(register_info));
101 
102 	if (gInfo == NULL || gRegister == NULL)
103 		return B_NO_MEMORY;
104 
105 	for (uint32 id = 0; id < MAX_CRT; id++) {
106 		gCRT[id] = (crt_info *)malloc(sizeof(crt_info));
107 		if (gCRT[id] == NULL)
108 			return B_NO_MEMORY;
109 	}
110 
111 	memset(gInfo, 0, sizeof(accelerant_info));
112 	memset(gRegister, 0, sizeof(register_info));
113 
114 	for (uint32 id = 0; id < MAX_CRT; id++)
115 		memset(gCRT[id], 0, sizeof(crt_info));
116 
117 	gInfo->is_clone = isClone;
118 	gInfo->device = device;
119 
120 	// get basic info from driver
121 
122 	radeon_get_private_data data;
123 	data.magic = RADEON_PRIVATE_DATA_MAGIC;
124 
125 	if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data,
126 			sizeof(radeon_get_private_data)) != 0) {
127 		free(gInfo);
128 		return B_ERROR;
129 	}
130 
131 	AreaCloner sharedCloner;
132 	gInfo->shared_info_area = sharedCloner.Clone("radeon hd shared info",
133 		(void **)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
134 		data.shared_info_area);
135 	status_t status = sharedCloner.InitCheck();
136 	if (status < B_OK) {
137 		free(gInfo);
138 		TRACE("%s, failed shared area%i, %i\n",
139 			__func__, data.shared_info_area, gInfo->shared_info_area);
140 		return status;
141 	}
142 
143 	AreaCloner regsCloner;
144 	gInfo->regs_area = regsCloner.Clone("radeon hd regs",
145 		(void **)&gInfo->regs, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
146 		gInfo->shared_info->registers_area);
147 	status = regsCloner.InitCheck();
148 	if (status < B_OK) {
149 		free(gInfo);
150 		return status;
151 	}
152 
153 	sharedCloner.Keep();
154 	regsCloner.Keep();
155 
156 	// Define Radeon PLL default ranges
157 	gInfo->shared_info->pll_info.reference_frequency
158 		= RHD_PLL_REFERENCE_DEFAULT;
159 	gInfo->shared_info->pll_info.min_frequency = RHD_PLL_MIN_DEFAULT;
160 	gInfo->shared_info->pll_info.max_frequency = RHD_PLL_MAX_DEFAULT;
161 
162 	return B_OK;
163 }
164 
165 
166 /*! Clean up data common to both primary and cloned accelerant */
167 static void
168 uninit_common(void)
169 {
170 	delete_area(gInfo->regs_area);
171 	delete_area(gInfo->shared_info_area);
172 
173 	gInfo->regs_area = gInfo->shared_info_area = -1;
174 
175 	// close the file handle ONLY if we're the clone
176 	if (gInfo->is_clone)
177 		close(gInfo->device);
178 
179 	free(gInfo);
180 	free(gRegister);
181 
182 	for (uint32 id = 0; id < MAX_CRT; id++)
183 		free(gCRT[id]);
184 }
185 
186 
187 /*! Populate gRegister with device dependant register locations */
188 status_t
189 init_registers(uint8 crtid)
190 {
191 	radeon_shared_info &info = *gInfo->shared_info;
192 
193 	if (info.device_chipset >= RADEON_R800) {
194 		uint32 offset = 0;
195 
196 		// AMD Eyefinity on Evergreen GPUs
197 		if (crtid == 1) {
198 			offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
199 			gRegister->vgaControl = D2VGA_CONTROL;
200 		} else if (crtid == 2) {
201 			offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
202 			gRegister->vgaControl = EVERGREEN_D3VGA_CONTROL;
203 		} else if (crtid == 3) {
204 			offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
205 			gRegister->vgaControl = EVERGREEN_D4VGA_CONTROL;
206 		} else if (crtid == 4) {
207 			offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
208 			gRegister->vgaControl = EVERGREEN_D5VGA_CONTROL;
209 		} else if (crtid == 5) {
210 			offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
211 			gRegister->vgaControl = EVERGREEN_D6VGA_CONTROL;
212 		} else {
213 			offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
214 			gRegister->vgaControl = D1VGA_CONTROL;
215 		}
216 
217 		// Evergreen+ is crtoffset + register
218 		gRegister->grphEnable = offset + EVERGREEN_GRPH_ENABLE;
219 		gRegister->grphControl = offset + EVERGREEN_GRPH_CONTROL;
220 		gRegister->grphSwapControl = offset + EVERGREEN_GRPH_SWAP_CONTROL;
221 		gRegister->grphPrimarySurfaceAddr
222 			= offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS;
223 		gRegister->grphSecondarySurfaceAddr
224 			= offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS;
225 
226 		gRegister->grphPrimarySurfaceAddrHigh
227 			= offset + EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH;
228 		gRegister->grphSecondarySurfaceAddrHigh
229 			= offset + EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH;
230 
231 		gRegister->grphPitch = offset + EVERGREEN_GRPH_PITCH;
232 		gRegister->grphSurfaceOffsetX
233 			= offset + EVERGREEN_GRPH_SURFACE_OFFSET_X;
234 		gRegister->grphSurfaceOffsetY
235 			= offset + EVERGREEN_GRPH_SURFACE_OFFSET_Y;
236 		gRegister->grphXStart = offset + EVERGREEN_GRPH_X_START;
237 		gRegister->grphYStart = offset + EVERGREEN_GRPH_Y_START;
238 		gRegister->grphXEnd = offset + EVERGREEN_GRPH_X_END;
239 		gRegister->grphYEnd = offset + EVERGREEN_GRPH_Y_END;
240 		gRegister->crtControl = offset + EVERGREEN_CRTC_CONTROL;
241 		gRegister->modeDesktopHeight = offset + EVERGREEN_DESKTOP_HEIGHT;
242 		gRegister->modeDataFormat = offset + EVERGREEN_DATA_FORMAT;
243 		gRegister->viewportStart = offset + EVERGREEN_VIEWPORT_START;
244 		gRegister->viewportSize = offset + EVERGREEN_VIEWPORT_SIZE;
245 
246 	} else if (info.device_chipset >= RADEON_R600
247 		&& info.device_chipset < RADEON_R800) {
248 
249 		// r600 - r700 are D1 or D2 based on primary / secondary crt
250 		gRegister->vgaControl
251 			= crtid == 1 ? D2VGA_CONTROL : D1VGA_CONTROL;
252 		gRegister->grphEnable
253 			= crtid == 1 ? D2GRPH_ENABLE : D1GRPH_ENABLE;
254 		gRegister->grphControl
255 			= crtid == 1 ? D2GRPH_CONTROL : D1GRPH_CONTROL;
256 		gRegister->grphSwapControl
257 			= crtid == 1 ? D2GRPH_SWAP_CNTL : D1GRPH_SWAP_CNTL;
258 		gRegister->grphPrimarySurfaceAddr
259 			= crtid == 1 ? D2GRPH_PRIMARY_SURFACE_ADDRESS
260 				: D1GRPH_PRIMARY_SURFACE_ADDRESS;
261 		gRegister->grphSecondarySurfaceAddr
262 			= crtid == 1 ? D2GRPH_SECONDARY_SURFACE_ADDRESS
263 				: D1GRPH_SECONDARY_SURFACE_ADDRESS;
264 
265 		// Surface Address high only used on r770+
266 		gRegister->grphPrimarySurfaceAddrHigh
267 			= crtid == 1 ? R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH
268 				: R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH;
269 		gRegister->grphSecondarySurfaceAddrHigh
270 			= crtid == 1 ? R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH
271 				: R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH;
272 
273 		gRegister->grphPitch
274 			= crtid == 1 ? D2GRPH_PITCH : D1GRPH_PITCH;
275 		gRegister->grphSurfaceOffsetX
276 			= crtid == 1 ? D2GRPH_SURFACE_OFFSET_X : D1GRPH_SURFACE_OFFSET_X;
277 		gRegister->grphSurfaceOffsetY
278 			= crtid == 1 ? D2GRPH_SURFACE_OFFSET_Y : D1GRPH_SURFACE_OFFSET_Y;
279 		gRegister->grphXStart
280 			= crtid == 1 ? D2GRPH_X_START : D1GRPH_X_START;
281 		gRegister->grphYStart
282 			= crtid == 1 ? D2GRPH_Y_START : D1GRPH_Y_START;
283 		gRegister->grphXEnd
284 			= crtid == 1 ? D2GRPH_X_END : D1GRPH_X_END;
285 		gRegister->grphYEnd
286 			= crtid == 1 ? D2GRPH_Y_END : D1GRPH_Y_END;
287 		gRegister->crtControl
288 			= crtid == 1 ? D2CRTC_CONTROL : D1CRTC_CONTROL;
289 		gRegister->modeDesktopHeight
290 			= crtid == 1 ? D2MODE_DESKTOP_HEIGHT : D1MODE_DESKTOP_HEIGHT;
291 		gRegister->modeDataFormat
292 			= crtid == 1 ? D2MODE_DATA_FORMAT : D1MODE_DATA_FORMAT;
293 		gRegister->viewportStart
294 			= crtid == 1 ? D2MODE_VIEWPORT_START : D1MODE_VIEWPORT_START;
295 		gRegister->viewportSize
296 			= crtid == 1 ? D2MODE_VIEWPORT_SIZE : D1MODE_VIEWPORT_SIZE;
297 	} else {
298 		// this really shouldn't happen unless a driver PCIID chipset is wrong
299 		TRACE("%s, unknown Radeon chipset: r%X\n", __func__,
300 			info.device_chipset);
301 		return B_ERROR;
302 	}
303 
304 	// Populate common registers
305 	// TODO : Wait.. this doesn't work with Eyefinity > crt 1.
306 	gRegister->crtid = crtid;
307 
308 	gRegister->modeCenter
309 		= crtid == 1 ? D2MODE_CENTER : D1MODE_CENTER;
310 	gRegister->grphUpdate
311 		= crtid == 1 ? D2GRPH_UPDATE : D1GRPH_UPDATE;
312 	gRegister->crtHPolarity
313 		= crtid == 1 ? D2CRTC_H_SYNC_A_CNTL : D1CRTC_H_SYNC_A_CNTL;
314 	gRegister->crtVPolarity
315 		= crtid == 1 ? D2CRTC_V_SYNC_A_CNTL : D1CRTC_V_SYNC_A_CNTL;
316 	gRegister->crtHTotal
317 		= crtid == 1 ? D2CRTC_H_TOTAL : D1CRTC_H_TOTAL;
318 	gRegister->crtVTotal
319 		= crtid == 1 ? D2CRTC_V_TOTAL : D1CRTC_V_TOTAL;
320 	gRegister->crtHSync
321 		= crtid == 1 ? D2CRTC_H_SYNC_A : D1CRTC_H_SYNC_A;
322 	gRegister->crtVSync
323 		= crtid == 1 ? D2CRTC_V_SYNC_A : D1CRTC_V_SYNC_A;
324 	gRegister->crtHBlank
325 		= crtid == 1 ? D2CRTC_H_BLANK_START_END : D1CRTC_H_BLANK_START_END;
326 	gRegister->crtVBlank
327 		= crtid == 1 ? D2CRTC_V_BLANK_START_END : D1CRTC_V_BLANK_START_END;
328 	gRegister->crtInterlace
329 		= crtid == 1 ? D2CRTC_INTERLACE_CONTROL : D1CRTC_INTERLACE_CONTROL;
330 	gRegister->crtCountControl
331 		= crtid == 1 ? D2CRTC_COUNT_CONTROL : D1CRTC_COUNT_CONTROL;
332 	gRegister->sclUpdate
333 		= crtid == 1 ? D2SCL_UPDATE : D1SCL_UPDATE;
334 	gRegister->sclEnable
335 		= crtid == 1 ? D2SCL_ENABLE : D1SCL_ENABLE;
336 	gRegister->sclTapControl
337 		= crtid == 1 ? D2SCL_TAP_CONTROL : D1SCL_TAP_CONTROL;
338 
339 	TRACE("%s, registers for ATI chipset r%X crt #%d loaded\n", __func__,
340 		info.device_chipset, crtid);
341 
342 	return B_OK;
343 }
344 
345 
346 //	#pragma mark - public accelerant functions
347 
348 
349 /*! Init primary accelerant */
350 status_t
351 radeon_init_accelerant(int device)
352 {
353 	TRACE("%s enter\n", __func__);
354 
355 	status_t status = init_common(device, false);
356 	if (status != B_OK)
357 		return status;
358 
359 	radeon_shared_info &info = *gInfo->shared_info;
360 
361 	init_lock(&info.accelerant_lock, "radeon hd accelerant");
362 	init_lock(&info.engine_lock, "radeon hd engine");
363 
364 	status = init_registers(0);
365 		// Initilize registers for crt0 to begin
366 
367 	if (status != B_OK)
368 		return status;
369 
370 	status = create_mode_list();
371 	if (status != B_OK) {
372 		uninit_common();
373 		return status;
374 	}
375 
376 	TRACE("%s done\n", __func__);
377 	return B_OK;
378 }
379 
380 
381 /*! This function is called for both, the primary accelerant and all of
382 	its clones.
383 */
384 void
385 radeon_uninit_accelerant(void)
386 {
387 	TRACE("%s enter\n", __func__);
388 
389 	gInfo->mode_list = NULL;
390 
391 	radeon_shared_info &info = *gInfo->shared_info;
392 
393 	uninit_lock(&info.accelerant_lock);
394 	uninit_lock(&info.engine_lock);
395 
396 	uninit_common();
397 	TRACE("%s done\n", __func__);
398 }
399 
400