xref: /haiku/src/add-ons/accelerants/intel_extreme/accelerant.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
1 /*
2  * Copyright 2006-2010, 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  */
8 
9 
10 #include "accelerant_protos.h"
11 #include "accelerant.h"
12 
13 #include "utility.h"
14 
15 #include <Debug.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <syslog.h>
21 
22 #include <AGP.h>
23 
24 
25 #undef TRACE
26 #define TRACE_ACCELERANT
27 #ifdef TRACE_ACCELERANT
28 #	define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
29 #else
30 #	define TRACE(x...)
31 #endif
32 
33 #define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
34 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
35 
36 
37 struct accelerant_info* gInfo;
38 
39 
40 class AreaCloner {
41 public:
42 							AreaCloner();
43 							~AreaCloner();
44 
45 			area_id			Clone(const char* name, void** _address,
46 								uint32 spec, uint32 protection,
47 								area_id sourceArea);
48 			status_t		InitCheck()
49 								{ return fArea < 0 ? (status_t)fArea : B_OK; }
50 			void			Keep();
51 
52 private:
53 			area_id			fArea;
54 };
55 
56 
57 AreaCloner::AreaCloner()
58 	:
59 	fArea(-1)
60 {
61 }
62 
63 
64 AreaCloner::~AreaCloner()
65 {
66 	if (fArea >= 0)
67 		delete_area(fArea);
68 }
69 
70 
71 area_id
72 AreaCloner::Clone(const char* name, void** _address, uint32 spec,
73 	uint32 protection, area_id sourceArea)
74 {
75 	fArea = clone_area(name, _address, spec, protection, sourceArea);
76 	return fArea;
77 }
78 
79 
80 void
81 AreaCloner::Keep()
82 {
83 	fArea = -1;
84 }
85 
86 
87 //	#pragma mark -
88 
89 
90 /*! This is the common accelerant_info initializer. It is called by
91 	both, the first accelerant and all clones.
92 */
93 static status_t
94 init_common(int device, bool isClone)
95 {
96 	// initialize global accelerant info structure
97 
98 	gInfo = (accelerant_info*)malloc(sizeof(accelerant_info));
99 	if (gInfo == NULL)
100 		return B_NO_MEMORY;
101 
102 	memset(gInfo, 0, sizeof(accelerant_info));
103 
104 	gInfo->is_clone = isClone;
105 	gInfo->device = device;
106 
107 	// get basic info from driver
108 
109 	intel_get_private_data data;
110 	data.magic = INTEL_PRIVATE_DATA_MAGIC;
111 
112 	if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data,
113 			sizeof(intel_get_private_data)) != 0) {
114 		free(gInfo);
115 		return B_ERROR;
116 	}
117 
118 	AreaCloner sharedCloner;
119 	gInfo->shared_info_area = sharedCloner.Clone("intel extreme shared info",
120 		(void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
121 		data.shared_info_area);
122 	status_t status = sharedCloner.InitCheck();
123 	if (status < B_OK) {
124 		free(gInfo);
125 		return status;
126 	}
127 
128 	AreaCloner regsCloner;
129 	gInfo->regs_area = regsCloner.Clone("intel extreme regs",
130 		(void**)&gInfo->registers, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
131 		gInfo->shared_info->registers_area);
132 	status = regsCloner.InitCheck();
133 	if (status < B_OK) {
134 		free(gInfo);
135 		return status;
136 	}
137 
138 	sharedCloner.Keep();
139 	regsCloner.Keep();
140 
141 	// The overlay registers, hardware status, and cursor memory share
142 	// a single area with the shared_info
143 
144 	if (gInfo->shared_info->overlay_offset != 0) {
145 		gInfo->overlay_registers = (struct overlay_registers*)
146 			(gInfo->shared_info->graphics_memory
147 			+ gInfo->shared_info->overlay_offset);
148 	}
149 
150 	if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) {
151 		// allocate some extra memory for the 3D context
152 		if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE,
153 				B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) {
154 			gInfo->context_offset = gInfo->context_base
155 				- (addr_t)gInfo->shared_info->graphics_memory;
156 		}
157 	}
158 
159 	return B_OK;
160 }
161 
162 
163 /*! Clean up data common to both primary and cloned accelerant */
164 static void
165 uninit_common(void)
166 {
167 	intel_free_memory(gInfo->context_base);
168 
169 	delete_area(gInfo->regs_area);
170 	delete_area(gInfo->shared_info_area);
171 
172 	gInfo->regs_area = gInfo->shared_info_area = -1;
173 
174 	// close the file handle ONLY if we're the clone
175 	if (gInfo->is_clone)
176 		close(gInfo->device);
177 
178 	free(gInfo);
179 }
180 
181 
182 //	#pragma mark - public accelerant functions
183 
184 
185 /*! Init primary accelerant */
186 status_t
187 intel_init_accelerant(int device)
188 {
189 	CALLED();
190 
191 	status_t status = init_common(device, false);
192 	if (status != B_OK)
193 		return status;
194 
195 	intel_shared_info &info = *gInfo->shared_info;
196 
197 	init_lock(&info.accelerant_lock, "intel extreme accelerant");
198 	init_lock(&info.engine_lock, "intel extreme engine");
199 
200 	setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer");
201 
202 	// determine head depending on what's already enabled from the BIOS
203 	// TODO: it would be nicer to retrieve this data via DDC - else the
204 	//	display is gone for good if the BIOS decides to only show the
205 	//	picture on the connected analog monitor!
206 	gInfo->head_mode = 0;
207 	if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
208 		gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
209 	if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
210 		gInfo->head_mode |= HEAD_MODE_A_ANALOG;
211 
212 	uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT);
213 
214 	// If we have an enabled display pipe we save the passed information and
215 	// assume it is the valid panel size..
216 	// Later we query for proper EDID info if it exists, or figure something
217 	// else out. (Default modes, etc.)
218 	bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
219 	if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0)
220 		|| (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) {
221 		save_lvds_mode();
222 		gInfo->head_mode |= HEAD_MODE_LVDS_PANEL;
223 	}
224 
225 	TRACE("head detected: %#x\n", gInfo->head_mode);
226 	TRACE("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n",
227 		read32(INTEL_DISPLAY_A_ANALOG_PORT),
228 		read32(INTEL_DISPLAY_A_DIGITAL_PORT),
229 		read32(INTEL_DISPLAY_B_DIGITAL_PORT),
230 		read32(INTEL_DISPLAY_LVDS_PORT));
231 
232 	status = create_mode_list();
233 	if (status != B_OK) {
234 		uninit_common();
235 		return status;
236 	}
237 
238 	return B_OK;
239 }
240 
241 
242 ssize_t
243 intel_accelerant_clone_info_size(void)
244 {
245 	CALLED();
246 	// clone info is device name, so return its maximum size
247 	return B_PATH_NAME_LENGTH;
248 }
249 
250 
251 void
252 intel_get_accelerant_clone_info(void* info)
253 {
254 	CALLED();
255 	ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH);
256 }
257 
258 
259 status_t
260 intel_clone_accelerant(void* info)
261 {
262 	CALLED();
263 
264 	// create full device name
265 	char path[B_PATH_NAME_LENGTH];
266 	strcpy(path, "/dev/");
267 #ifdef __HAIKU__
268 	strlcat(path, (const char*)info, sizeof(path));
269 #else
270 	strcat(path, (const char*)info);
271 #endif
272 
273 	int fd = open(path, B_READ_WRITE);
274 	if (fd < 0)
275 		return errno;
276 
277 	status_t status = init_common(fd, true);
278 	if (status != B_OK)
279 		goto err1;
280 
281 	// get read-only clone of supported display modes
282 	status = gInfo->mode_list_area = clone_area(
283 		"intel extreme cloned modes", (void**)&gInfo->mode_list,
284 		B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area);
285 	if (status < B_OK)
286 		goto err2;
287 
288 	return B_OK;
289 
290 err2:
291 	uninit_common();
292 err1:
293 	close(fd);
294 	return status;
295 }
296 
297 
298 /*! This function is called for both, the primary accelerant and all of
299 	its clones.
300 */
301 void
302 intel_uninit_accelerant(void)
303 {
304 	CALLED();
305 
306 	// delete accelerant instance data
307 	delete_area(gInfo->mode_list_area);
308 	gInfo->mode_list = NULL;
309 
310 	intel_shared_info &info = *gInfo->shared_info;
311 
312 	uninit_lock(&info.accelerant_lock);
313 	uninit_lock(&info.engine_lock);
314 
315 	uninit_ring_buffer(info.primary_ring_buffer);
316 
317 	uninit_common();
318 }
319 
320 
321 status_t
322 intel_get_accelerant_device_info(accelerant_device_info* info)
323 {
324 	CALLED();
325 
326 	info->version = B_ACCELERANT_VERSION;
327 	strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx)
328 		? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2");
329 	strcpy(info->chipset, gInfo->shared_info->device_identifier);
330 	strcpy(info->serial_no, "None");
331 
332 	info->memory = gInfo->shared_info->graphics_memory_size;
333 	info->dac_speed = gInfo->shared_info->pll_info.max_frequency;
334 
335 	return B_OK;
336 }
337 
338 
339 sem_id
340 intel_accelerant_retrace_semaphore()
341 {
342 	CALLED();
343 	return gInfo->shared_info->vblank_sem;
344 }
345 
346