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