xref: /haiku/src/add-ons/kernel/drivers/graphics/intel_extreme/device.cpp (revision 1454f3c27aec3e7879a58e7cedc9d66d90c773a7)
1 /*
2  * Copyright 2006-2018, 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 "driver.h"
11 #include "device.h"
12 #include "intel_extreme.h"
13 #include "utility.h"
14 
15 #include <OS.h>
16 #include <KernelExport.h>
17 #include <Drivers.h>
18 #include <PCI.h>
19 #include <SupportDefs.h>
20 #include <graphic_driver.h>
21 #include <image.h>
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 
27 #define DEBUG_COMMANDS
28 
29 #define TRACE_DEVICE
30 #ifdef TRACE_DEVICE
31 #	define TRACE(x...) dprintf("intel_extreme: " x)
32 #else
33 #	define TRACE(x) ;
34 #endif
35 
36 #define ERROR(x...) dprintf("intel_extreme: " x)
37 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
38 
39 
40 /* device hooks prototypes */
41 
42 static status_t device_open(const char* name, uint32 flags, void** _cookie);
43 static status_t device_close(void* data);
44 static status_t device_free(void* data);
45 static status_t device_ioctl(void* data, uint32 opcode, void* buffer,
46 	size_t length);
47 static status_t device_read(void* data, off_t offset, void* buffer,
48 	size_t* length);
49 static status_t device_write(void* data, off_t offset, const void* buffer,
50 	size_t* length);
51 
52 
53 device_hooks gDeviceHooks = {
54 	device_open,
55 	device_close,
56 	device_free,
57 	device_ioctl,
58 	device_read,
59 	device_write,
60 	NULL,
61 	NULL,
62 	NULL,
63 	NULL
64 };
65 
66 
67 #ifdef DEBUG_COMMANDS
68 static int
69 getset_register(int argc, char** argv)
70 {
71 	if (argc < 2 || argc > 3) {
72 		kprintf("usage: %s <register> [set-to-value]\n", argv[0]);
73 		return 0;
74 	}
75 
76 	uint32 reg = parse_expression(argv[1]);
77 	uint32 value = 0;
78 	bool set = argc == 3;
79 	if (set)
80 		value = parse_expression(argv[2]);
81 
82 	kprintf("intel_extreme register %#" B_PRIx32 "\n", reg);
83 
84 	intel_info &info = *gDeviceInfo[0];
85 	uint32 oldValue = read32(info, reg);
86 
87 	kprintf("  %svalue: %#" B_PRIx32 " (%" B_PRIu32 ")\n", set ? "old " : "",
88 		oldValue, oldValue);
89 
90 	if (set) {
91 		write32(info, reg, value);
92 
93 		value = read32(info, reg);
94 		kprintf("  new value: %#" B_PRIx32 " (%" B_PRIu32 ")\n", value, value);
95 	}
96 
97 	return 0;
98 }
99 
100 
101 static int
102 dump_pipe_info(int argc, char** argv)
103 {
104 	int pipeOffset = 0;
105 
106 	if (argc > 2) {
107 		kprintf("usage: %s [pipe index]\n", argv[0]);
108 		return 0;
109 	}
110 
111 	if (argc > 1) {
112 		uint32 pipe = parse_expression(argv[1]);
113 		if (pipe != 0)
114 			pipeOffset = INTEL_DISPLAY_OFFSET; // Use pipe B if requested
115 	}
116 
117 	intel_info &info = *gDeviceInfo[0];
118 	uint32 value;
119 
120 	kprintf("intel_extreme pipe configuration:\n");
121 
122 	value = read32(info, INTEL_DISPLAY_A_HTOTAL + pipeOffset);
123 	kprintf("  HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
124 		(value & 0xFFFF) + 1, (value >> 16) + 1);
125 	value = read32(info, INTEL_DISPLAY_A_HBLANK + pipeOffset);
126 	kprintf("  HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
127 		(value & 0xFFFF) + 1, (value >> 16) + 1);
128 	value = read32(info, INTEL_DISPLAY_A_HSYNC + pipeOffset);
129 	kprintf("  HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
130 		(value & 0xFFFF) + 1, (value >> 16) + 1);
131 	value = read32(info, INTEL_DISPLAY_A_VTOTAL + pipeOffset);
132 	kprintf("  VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
133 		(value & 0xFFFF) + 1, (value >> 16) + 1);
134 	value = read32(info, INTEL_DISPLAY_A_VBLANK + pipeOffset);
135 	kprintf("  VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
136 		(value & 0xFFFF) + 1, (value >> 16) + 1);
137 	value = read32(info, INTEL_DISPLAY_A_VSYNC + pipeOffset);
138 	kprintf("  VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
139 		(value & 0xFFFF) + 1, (value >> 16) + 1);
140 	value = read32(info, INTEL_DISPLAY_A_PIPE_SIZE + pipeOffset);
141 	kprintf("  SIZE %" B_PRIu32 "x%" B_PRIu32 "\n",
142 		(value & 0xFFFF) + 1, (value >> 16) + 1);
143 
144 	if (info.pch_info != INTEL_PCH_NONE) {
145 		kprintf("intel_extreme transcoder configuration:\n");
146 
147 		value = read32(info, INTEL_TRANSCODER_A_HTOTAL + pipeOffset);
148 		kprintf("  HTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
149 			(value & 0xFFFF) + 1, (value >> 16) + 1);
150 		value = read32(info, INTEL_TRANSCODER_A_HBLANK + pipeOffset);
151 		kprintf("  HBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
152 			(value & 0xFFFF) + 1, (value >> 16) + 1);
153 		value = read32(info, INTEL_TRANSCODER_A_HSYNC + pipeOffset);
154 		kprintf("  HSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
155 			(value & 0xFFFF) + 1, (value >> 16) + 1);
156 		value = read32(info, INTEL_TRANSCODER_A_VTOTAL + pipeOffset);
157 		kprintf("  VTOTAL start %" B_PRIu32 " end %" B_PRIu32 "\n",
158 			(value & 0xFFFF) + 1, (value >> 16) + 1);
159 		value = read32(info, INTEL_TRANSCODER_A_VBLANK + pipeOffset);
160 		kprintf("  VBLANK start %" B_PRIu32 " end %" B_PRIu32 "\n",
161 			(value & 0xFFFF) + 1, (value >> 16) + 1);
162 		value = read32(info, INTEL_TRANSCODER_A_VSYNC + pipeOffset);
163 		kprintf("  VSYNC start %" B_PRIu32 " end %" B_PRIu32 "\n",
164 			(value & 0xFFFF) + 1, (value >> 16) + 1);
165 		value = read32(info, INTEL_TRANSCODER_A_IMAGE_SIZE + pipeOffset);
166 		kprintf("  SIZE %" B_PRIu32 "x%" B_PRIu32 "\n",
167 			(value & 0xFFFF) + 1, (value >> 16) + 1);
168 	}
169 
170 	kprintf("intel_extreme display plane configuration:\n");
171 
172 	value = read32(info, INTEL_DISPLAY_A_CONTROL + pipeOffset);
173 	kprintf("  CONTROL: %" B_PRIx32 "\n", value);
174 	value = read32(info, INTEL_DISPLAY_A_BASE + pipeOffset);
175 	kprintf("  BASE: %" B_PRIx32 "\n", value);
176 	value = read32(info, INTEL_DISPLAY_A_BYTES_PER_ROW + pipeOffset);
177 	kprintf("  BYTES_PER_ROW: %" B_PRIx32 "\n", value);
178 	value = read32(info, INTEL_DISPLAY_A_SURFACE + pipeOffset);
179 	kprintf("  SURFACE: %" B_PRIx32 "\n", value);
180 
181 	return 0;
182 }
183 
184 #endif	// DEBUG_COMMANDS
185 
186 
187 //	#pragma mark - Device Hooks
188 
189 
190 static status_t
191 device_open(const char* name, uint32 /*flags*/, void** _cookie)
192 {
193 	CALLED();
194 	int32 id;
195 
196 	// find accessed device
197 	{
198 		char* thisName;
199 
200 		// search for device name
201 		for (id = 0; (thisName = gDeviceNames[id]) != NULL; id++) {
202 			if (!strcmp(name, thisName))
203 				break;
204 		}
205 		if (!thisName)
206 			return B_BAD_VALUE;
207 	}
208 
209 	intel_info* info = gDeviceInfo[id];
210 
211 	mutex_lock(&gLock);
212 
213 	if (info->open_count == 0) {
214 		// This device hasn't been initialized yet, so we
215 		// allocate needed resources and initialize the structure
216 		info->init_status = intel_extreme_init(*info);
217 		if (info->init_status == B_OK) {
218 #ifdef DEBUG_COMMANDS
219 			add_debugger_command("ie_reg", getset_register,
220 				"dumps or sets the specified intel_extreme register");
221 			add_debugger_command("ie_pipe", dump_pipe_info,
222 				"show pipe configuration information");
223 #endif
224 		}
225 	}
226 
227 	if (info->init_status == B_OK) {
228 		info->open_count++;
229 		*_cookie = info;
230 	} else
231 		ERROR("%s: initialization failed!\n", __func__);
232 
233 	mutex_unlock(&gLock);
234 
235 	return info->init_status;
236 }
237 
238 
239 static status_t
240 device_close(void* /*data*/)
241 {
242 	CALLED();
243 	return B_OK;
244 }
245 
246 
247 static status_t
248 device_free(void* data)
249 {
250 	struct intel_info* info = (intel_info*)data;
251 
252 	mutex_lock(&gLock);
253 
254 	if (info->open_count-- == 1) {
255 		// release info structure
256 		info->init_status = B_NO_INIT;
257 		intel_extreme_uninit(*info);
258 
259 #ifdef DEBUG_COMMANDS
260 		remove_debugger_command("ie_reg", getset_register);
261 		remove_debugger_command("ie_pipe", dump_pipe_info);
262 #endif
263 	}
264 
265 	mutex_unlock(&gLock);
266 	return B_OK;
267 }
268 
269 
270 static status_t
271 device_ioctl(void* data, uint32 op, void* buffer, size_t bufferLength)
272 {
273 	struct intel_info* info = (intel_info*)data;
274 
275 	switch (op) {
276 		case B_GET_ACCELERANT_SIGNATURE:
277 			TRACE("accelerant: %s\n", INTEL_ACCELERANT_NAME);
278 			if (user_strlcpy((char*)buffer, INTEL_ACCELERANT_NAME,
279 					bufferLength) < B_OK)
280 				return B_BAD_ADDRESS;
281 			return B_OK;
282 
283 		// needed to share data between kernel and accelerant
284 		case INTEL_GET_PRIVATE_DATA:
285 		{
286 			intel_get_private_data data;
287 			if (user_memcpy(&data, buffer, sizeof(intel_get_private_data)) < B_OK)
288 				return B_BAD_ADDRESS;
289 
290 			if (data.magic == INTEL_PRIVATE_DATA_MAGIC) {
291 				data.shared_info_area = info->shared_area;
292 				return user_memcpy(buffer, &data,
293 					sizeof(intel_get_private_data));
294 			}
295 			break;
296 		}
297 
298 		// needed for cloning
299 		case INTEL_GET_DEVICE_NAME:
300 			if (user_strlcpy((char* )buffer, gDeviceNames[info->id],
301 					bufferLength) < B_OK)
302 				return B_BAD_ADDRESS;
303 			return B_OK;
304 
305 		// graphics mem manager
306 		case INTEL_ALLOCATE_GRAPHICS_MEMORY:
307 		{
308 			intel_allocate_graphics_memory allocMemory;
309 			if (user_memcpy(&allocMemory, buffer,
310 					sizeof(intel_allocate_graphics_memory)) < B_OK)
311 				return B_BAD_ADDRESS;
312 
313 			if (allocMemory.magic != INTEL_PRIVATE_DATA_MAGIC)
314 				return B_BAD_VALUE;
315 
316 			status_t status = intel_allocate_memory(*info, allocMemory.size,
317 				allocMemory.alignment, allocMemory.flags,
318 				&allocMemory.buffer_base);
319 			if (status == B_OK) {
320 				// copy result
321 				if (user_memcpy(buffer, &allocMemory,
322 						sizeof(intel_allocate_graphics_memory)) < B_OK)
323 					return B_BAD_ADDRESS;
324 			}
325 			return status;
326 		}
327 
328 		case INTEL_FREE_GRAPHICS_MEMORY:
329 		{
330 			intel_free_graphics_memory freeMemory;
331 			if (user_memcpy(&freeMemory, buffer,
332 					sizeof(intel_free_graphics_memory)) < B_OK)
333 				return B_BAD_ADDRESS;
334 
335 			if (freeMemory.magic == INTEL_PRIVATE_DATA_MAGIC)
336 				return intel_free_memory(*info, freeMemory.buffer_base);
337 			break;
338 		}
339 
340 		case INTEL_GET_BRIGHTNESS_LEGACY:
341 		case INTEL_SET_BRIGHTNESS_LEGACY:
342 		{
343 			intel_brightness_legacy brightnessLegacy;
344 			if (user_memcpy(&brightnessLegacy, buffer,
345 					sizeof(brightnessLegacy)) < B_OK)
346 				return B_BAD_ADDRESS;
347 
348 			if (brightnessLegacy.magic != INTEL_PRIVATE_DATA_MAGIC)
349 				break;
350 			if (op == INTEL_GET_BRIGHTNESS_LEGACY) {
351 				brightnessLegacy.lpc = get_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1);
352 				// copy result
353 				if (user_memcpy(buffer, &brightnessLegacy, sizeof(brightnessLegacy)) < B_OK)
354 					return B_BAD_ADDRESS;
355 			} else {
356 				set_pci_config(info->pci, LEGACY_BACKLIGHT_BRIGHTNESS, 1, brightnessLegacy.lpc);
357 			}
358 			return B_OK;
359 		}
360 
361 		default:
362 			ERROR("ioctl() unknown message %" B_PRIu32 " (length = %"
363 				B_PRIuSIZE ")\n", op, bufferLength);
364 			break;
365 	}
366 
367 	return B_DEV_INVALID_IOCTL;
368 }
369 
370 
371 static status_t
372 device_read(void* /*data*/, off_t /*pos*/, void* /*buffer*/, size_t* _length)
373 {
374 	*_length = 0;
375 	return B_NOT_ALLOWED;
376 }
377 
378 
379 static status_t
380 device_write(void* /*data*/, off_t /*pos*/, const void* /*buffer*/,
381 	size_t* _length)
382 {
383 	*_length = 0;
384 	return B_NOT_ALLOWED;
385 }
386 
387