xref: /haiku/src/add-ons/accelerants/radeon_hd/accelerant.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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.h"
12 
13 #include <AGP.h>
14 #include <Debug.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <syslog.h>
20 #include <unistd.h>
21 
22 #include <AutoDeleterOS.h>
23 
24 #include "accelerant_protos.h"
25 
26 #include "bios.h"
27 #include "connector.h"
28 #include "display.h"
29 #include "displayport.h"
30 #include "gpu.h"
31 #include "pll.h"
32 #include "utility.h"
33 
34 
35 #undef TRACE
36 
37 #define TRACE_ACCELERANT
38 #ifdef TRACE_ACCELERANT
39 #	define TRACE(x...) _sPrintf("radeon_hd: " x)
40 #else
41 #	define TRACE(x...) ;
42 #endif
43 
44 
45 struct accelerant_info* gInfo;
46 display_info* gDisplay[MAX_DISPLAY];
47 connector_info* gConnector[ATOM_MAX_SUPPORTED_DEVICE];
48 gpio_info* gGPIOInfo[MAX_GPIO_PINS];
49 
50 
51 //	#pragma mark -
52 
53 
54 /*! This is the common accelerant_info initializer. It is called by
55 	both, the first accelerant and all clones.
56 */
57 static status_t
58 init_common(int device, bool isClone)
59 {
60 	// initialize global accelerant info structure
61 
62 	gInfo = (accelerant_info*)malloc(sizeof(accelerant_info));
63 	MemoryDeleter infoDeleter(gInfo);
64 
65 	if (gInfo == NULL)
66 		return B_NO_MEMORY;
67 
68 	memset(gInfo, 0, sizeof(accelerant_info));
69 
70 	// malloc memory for active display information
71 	for (uint32 id = 0; id < MAX_DISPLAY; id++) {
72 		gDisplay[id] = (display_info*)malloc(sizeof(display_info));
73 		if (gDisplay[id] == NULL)
74 			return B_NO_MEMORY;
75 		memset(gDisplay[id], 0, sizeof(display_info));
76 
77 		gDisplay[id]->regs = (register_info*)malloc(sizeof(register_info));
78 		if (gDisplay[id]->regs == NULL)
79 			return B_NO_MEMORY;
80 		memset(gDisplay[id]->regs, 0, sizeof(register_info));
81 	}
82 
83 	// malloc for possible physical card connectors
84 	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
85 		gConnector[id] = (connector_info*)malloc(sizeof(connector_info));
86 
87 		if (gConnector[id] == NULL)
88 			return B_NO_MEMORY;
89 		memset(gConnector[id], 0, sizeof(connector_info));
90 
91 		// Init a few things
92 		gConnector[id]->router.ddcValid = false;
93 		gConnector[id]->router.cdValid = false;
94 		gConnector[id]->encoder.pll.id = ATOM_PPLL_INVALID;
95 	}
96 
97 	// malloc for card gpio pin information
98 	for (uint32 id = 0; id < MAX_GPIO_PINS; id++) {
99 		gGPIOInfo[id] = (gpio_info*)malloc(sizeof(gpio_info));
100 
101 		if (gGPIOInfo[id] == NULL)
102 			return B_NO_MEMORY;
103 		memset(gGPIOInfo[id], 0, sizeof(gpio_info));
104 	}
105 
106 	gInfo->is_clone = isClone;
107 	gInfo->device = device;
108 
109 	gInfo->dpms_mode = B_DPMS_ON;
110 		// initial state
111 
112 	// get basic info from driver
113 
114 	radeon_get_private_data data;
115 	data.magic = RADEON_PRIVATE_DATA_MAGIC;
116 
117 	if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data,
118 			sizeof(radeon_get_private_data)) != 0) {
119 		return B_ERROR;
120 	}
121 
122 	AreaDeleter sharedDeleter(clone_area("radeon hd shared info",
123 		(void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
124 		data.shared_info_area));
125 	status_t status = gInfo->shared_info_area = sharedDeleter.Get();
126 	if (status < B_OK) {
127 		TRACE("%s, failed to create shared area\n", __func__);
128 		return status;
129 	}
130 
131 	AreaDeleter regsDeleter(clone_area("radeon hd regs",
132 		(void**)&gInfo->regs, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
133 		gInfo->shared_info->registers_area));
134 	status = gInfo->regs_area = regsDeleter.Get();
135 	if (status < B_OK) {
136 		TRACE("%s, failed to create mmio area\n", __func__);
137 		return status;
138 	}
139 
140 	gInfo->rom_area = clone_area("radeon hd AtomBIOS",
141 		(void**)&gInfo->rom, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
142 		gInfo->shared_info->rom_area);
143 
144 	if (gInfo->rom_area < 0) {
145 		TRACE("%s: Clone of AtomBIOS failed!\n", __func__);
146 		gInfo->shared_info->has_rom = false;
147 	}
148 
149 	if (gInfo->rom[0] != 0x55 || gInfo->rom[1] != 0xAA)
150 		TRACE("%s: didn't find a VGA bios in cloned region!\n", __func__);
151 
152 	infoDeleter.Detach();
153 	sharedDeleter.Detach();
154 	regsDeleter.Detach();
155 
156 	return B_OK;
157 }
158 
159 
160 /*! Clean up data common to both primary and cloned accelerant */
161 static void
162 uninit_common(void)
163 {
164 	if (gInfo != NULL) {
165 		delete_area(gInfo->regs_area);
166 		delete_area(gInfo->shared_info_area);
167 		delete_area(gInfo->rom_area);
168 
169 		gInfo->regs_area = gInfo->shared_info_area = -1;
170 
171 		// close the file handle ONLY if we're the clone
172 		if (gInfo->is_clone)
173 			close(gInfo->device);
174 
175 		free(gInfo);
176 	}
177 
178 	for (uint32 id = 0; id < MAX_DISPLAY; id++) {
179 		if (gDisplay[id] != NULL) {
180 			free(gDisplay[id]->regs);
181 			free(gDisplay[id]);
182 		}
183 	}
184 
185 	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++)
186 		free(gConnector[id]);
187 
188 	for (uint32 id = 0; id < MAX_GPIO_PINS; id++)
189 		free(gGPIOInfo[id]);
190 }
191 
192 
193 //	#pragma mark - public accelerant functions
194 
195 
196 /*! Init primary accelerant */
197 status_t
198 radeon_init_accelerant(int device)
199 {
200 	TRACE("%s enter\n", __func__);
201 
202 	status_t status = init_common(device, false);
203 	if (status != B_OK)
204 		return status;
205 
206 	radeon_shared_info &info = *gInfo->shared_info;
207 
208 	init_lock(&info.accelerant_lock, "radeon hd accelerant");
209 	init_lock(&info.engine_lock, "radeon hd engine");
210 
211 	radeon_init_bios(gInfo->rom);
212 
213 	// probe firmware information
214 	radeon_gpu_probe();
215 
216 	// apply GPU quirks
217 	radeon_gpu_quirks();
218 
219 	// find GPIO pins from AtomBIOS
220 	gpio_populate();
221 
222 	// find physical card connectors from AtomBIOS
223 	status = connector_probe();
224 
225 	if (status != B_OK) {
226 		TRACE("%s: falling back to legacy connector probe.\n", __func__);
227 		status = connector_probe_legacy();
228 	}
229 
230 	if (status != B_OK) {
231 		TRACE("%s: couldn't detect supported connectors!\n", __func__);
232 		return status;
233 	}
234 
235 	// print found connectors
236 	debug_connectors();
237 
238 	// setup encoders on each connector if needed
239 	encoder_init();
240 
241 	// program external pll clock
242 	pll_external_init();
243 
244 	// setup link on any DisplayPort connectors
245 	dp_setup_connectors();
246 
247 	// detect attached displays
248 	status = detect_displays();
249 	//if (status != B_OK)
250 	//	return status;
251 
252 	// print found displays
253 	debug_displays();
254 
255 	// create initial list of video modes
256 	status = create_mode_list();
257 	//if (status != B_OK) {
258 	//	radeon_uninit_accelerant();
259 	//	return status;
260 	//}
261 
262 	radeon_gpu_mc_setup();
263 
264 	// Set up data crunching + irq rings
265 	radeon_gpu_ring_setup();
266 
267 	radeon_gpu_ring_boot(RADEON_QUEUE_TYPE_GFX_INDEX);
268 
269 	TRACE("%s done\n", __func__);
270 	return B_OK;
271 }
272 
273 
274 /*! This function is called for both, the primary accelerant and all of
275 	its clones.
276 */
277 void
278 radeon_uninit_accelerant(void)
279 {
280 	TRACE("%s enter\n", __func__);
281 
282 	gInfo->mode_list = NULL;
283 
284 	radeon_shared_info &info = *gInfo->shared_info;
285 
286 	uninit_lock(&info.accelerant_lock);
287 	uninit_lock(&info.engine_lock);
288 
289 	uninit_common();
290 	TRACE("%s done\n", __func__);
291 }
292 
293 
294 status_t
295 radeon_get_accelerant_device_info(accelerant_device_info* di)
296 {
297 	radeon_shared_info &info = *gInfo->shared_info;
298 
299 	di->version = B_ACCELERANT_VERSION;
300 	strcpy(di->name, info.deviceName);
301 
302 	char chipset[32];
303 	sprintf(chipset, "%s", gInfo->shared_info->chipsetName);
304 	strcpy(di->chipset, chipset);
305 
306 	// add flags onto chipset name
307 	if ((info.chipsetFlags & CHIP_IGP) != 0)
308 		strcat(di->chipset, " IGP");
309 	if ((info.chipsetFlags & CHIP_MOBILE) != 0)
310 		strcat(di->chipset, " Mobile");
311 	if ((info.chipsetFlags & CHIP_APU) != 0)
312 		strcat(di->chipset, " APU");
313 
314 	strcpy(di->serial_no, "None" );
315 
316 	di->memory = gInfo->shared_info->graphics_memory_size;
317 	return B_OK;
318 }
319