xref: /haiku/src/add-ons/accelerants/intel_extreme/accelerant.cpp (revision 776c58b2b56d8bcf33638a2ecb6c697f95a1cbf3)
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 	gInfo->overlay_registers = (struct overlay_registers*)
145 		(gInfo->shared_info->graphics_memory
146 		+ gInfo->shared_info->overlay_offset);
147 
148 	if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) {
149 		// allocate some extra memory for the 3D context
150 		if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE,
151 				B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) {
152 			gInfo->context_offset = gInfo->context_base
153 				- (addr_t)gInfo->shared_info->graphics_memory;
154 		}
155 	}
156 
157 	return B_OK;
158 }
159 
160 
161 /*! Clean up data common to both primary and cloned accelerant */
162 static void
163 uninit_common(void)
164 {
165 	intel_free_memory(gInfo->context_base);
166 
167 	delete_area(gInfo->regs_area);
168 	delete_area(gInfo->shared_info_area);
169 
170 	gInfo->regs_area = gInfo->shared_info_area = -1;
171 
172 	// close the file handle ONLY if we're the clone
173 	if (gInfo->is_clone)
174 		close(gInfo->device);
175 
176 	free(gInfo);
177 }
178 
179 
180 //	#pragma mark - public accelerant functions
181 
182 
183 /*! Init primary accelerant */
184 status_t
185 intel_init_accelerant(int device)
186 {
187 	CALLED();
188 
189 	status_t status = init_common(device, false);
190 	if (status != B_OK)
191 		return status;
192 
193 	intel_shared_info &info = *gInfo->shared_info;
194 
195 	init_lock(&info.accelerant_lock, "intel extreme accelerant");
196 	init_lock(&info.engine_lock, "intel extreme engine");
197 
198 	setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer");
199 
200 	// determine head depending on what's already enabled from the BIOS
201 	// TODO: it would be nicer to retrieve this data via DDC - else the
202 	//	display is gone for good if the BIOS decides to only show the
203 	//	picture on the connected analog monitor!
204 	gInfo->head_mode = 0;
205 	if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
206 		gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
207 	if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
208 		gInfo->head_mode |= HEAD_MODE_A_ANALOG;
209 
210 	uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT);
211 
212 	// If we have an enabled display pipe we save the passed information and
213 	// assume it is the valid panel size..
214 	// Later we query for proper EDID info if it exists, or figure something
215 	// else out. (Default modes, etc.)
216 	bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
217 	if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0)
218 		|| (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) {
219 		save_lvds_mode();
220 		gInfo->head_mode |= HEAD_MODE_LVDS_PANEL;
221 	}
222 
223 	TRACE("head detected: %#x\n", gInfo->head_mode);
224 	TRACE("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n",
225 		read32(INTEL_DISPLAY_A_ANALOG_PORT),
226 		read32(INTEL_DISPLAY_A_DIGITAL_PORT),
227 		read32(INTEL_DISPLAY_B_DIGITAL_PORT),
228 		read32(INTEL_DISPLAY_LVDS_PORT));
229 
230 	status = create_mode_list();
231 	if (status != B_OK) {
232 		uninit_common();
233 		return status;
234 	}
235 
236 	return B_OK;
237 }
238 
239 
240 ssize_t
241 intel_accelerant_clone_info_size(void)
242 {
243 	CALLED();
244 	// clone info is device name, so return its maximum size
245 	return B_PATH_NAME_LENGTH;
246 }
247 
248 
249 void
250 intel_get_accelerant_clone_info(void* info)
251 {
252 	CALLED();
253 	ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH);
254 }
255 
256 
257 status_t
258 intel_clone_accelerant(void* info)
259 {
260 	CALLED();
261 
262 	// create full device name
263 	char path[B_PATH_NAME_LENGTH];
264 	strcpy(path, "/dev/");
265 #ifdef __HAIKU__
266 	strlcat(path, (const char*)info, sizeof(path));
267 #else
268 	strcat(path, (const char*)info);
269 #endif
270 
271 	int fd = open(path, B_READ_WRITE);
272 	if (fd < 0)
273 		return errno;
274 
275 	status_t status = init_common(fd, true);
276 	if (status != B_OK)
277 		goto err1;
278 
279 	// get read-only clone of supported display modes
280 	status = gInfo->mode_list_area = clone_area(
281 		"intel extreme cloned modes", (void**)&gInfo->mode_list,
282 		B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area);
283 	if (status < B_OK)
284 		goto err2;
285 
286 	return B_OK;
287 
288 err2:
289 	uninit_common();
290 err1:
291 	close(fd);
292 	return status;
293 }
294 
295 
296 /*! This function is called for both, the primary accelerant and all of
297 	its clones.
298 */
299 void
300 intel_uninit_accelerant(void)
301 {
302 	CALLED();
303 
304 	// delete accelerant instance data
305 	delete_area(gInfo->mode_list_area);
306 	gInfo->mode_list = NULL;
307 
308 	intel_shared_info &info = *gInfo->shared_info;
309 
310 	uninit_lock(&info.accelerant_lock);
311 	uninit_lock(&info.engine_lock);
312 
313 	uninit_ring_buffer(info.primary_ring_buffer);
314 
315 	uninit_common();
316 }
317 
318 
319 status_t
320 intel_get_accelerant_device_info(accelerant_device_info* info)
321 {
322 	CALLED();
323 
324 	info->version = B_ACCELERANT_VERSION;
325 	strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx)
326 		? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2");
327 	strcpy(info->chipset, gInfo->shared_info->device_identifier);
328 	strcpy(info->serial_no, "None");
329 
330 	info->memory = gInfo->shared_info->graphics_memory_size;
331 	info->dac_speed = gInfo->shared_info->pll_info.max_frequency;
332 
333 	return B_OK;
334 }
335 
336 
337 sem_id
338 intel_accelerant_retrace_semaphore()
339 {
340 	CALLED();
341 	return gInfo->shared_info->vblank_sem;
342 }
343 
344