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