xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/driver.c (revision cb29eafe2586fdb2d7685afa69fdab5d88a8b576)
1 /*
2 	Copyright (c) 2002, Thomas Kurschel
3 
4 	Part of Radeon kernel driver
5 	DevFS interface
6 */
7 
8 #include "radeon_driver.h"
9 
10 #include <OS.h>
11 #include <malloc.h>
12 #include <graphic_driver.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include "AGP.h"
16 #include "mmio.h"
17 #include "version.h"
18 #include <driver_settings.h>
19 #include <stdlib.h> // for strtoXX
20 
21 // tell the kernel what revision of the driver API we support
22 int32	api_version = 2;
23 
24 
25 static status_t open_hook(const char *name, uint32 flags, void **cookie);
26 static status_t close_hook(void *dev);
27 static status_t free_hook(void *dev);
28 static status_t read_hook(void *dev, off_t pos, void *buf, size_t *len);
29 static status_t write_hook(void *dev, off_t pos, const void *buf, size_t *len);
30 static status_t control_hook(void *dev, uint32 msg, void *buf, size_t len);
31 
32 
33 static device_hooks graphics_device_hooks = {
34 	open_hook,
35 	close_hook,
36 	free_hook,
37 	control_hook,
38 	read_hook,
39 	write_hook,
40 	NULL,
41 	NULL,
42 	NULL,
43 	NULL
44 };
45 
46 radeon_settings def_settings = { // see comments in radeon.settings
47 	2,			 		// loginfo
48 	2,			 		// logflow
49 	2,			 		// logerror
50 	false,				// switchhead
51 	false,				// force_lcd
52 	true,				// dynamic_clocks
53 	true,				// force_pci
54 	false,				// unhide_fw
55 	false,				// acc_dma
56 	false,				// acc_mmio
57 	true,				// acc_wb
58 };
59 
60 radeon_settings current_settings;
61 
62 static void
63 GetDriverSettings(void)
64 {
65 	void *settings_handle = NULL;
66 
67 	SHOW_FLOW0( 1, "" );
68 
69 	// init settings to defaults;
70 	current_settings = def_settings;
71 
72 	// get driver/accelerant settings, apsed
73 	settings_handle  = load_driver_settings ("radeon.settings");
74 	if (settings_handle != NULL) {
75 		const char *item;
76 		char       *end;
77 		uint32      value;
78 
79 		item = get_driver_parameter (settings_handle, "loginfo", "2", "2");
80 		value = strtoul (item, &end, 0);
81 		if (*end == '\0' && value <= 4) {
82 			current_settings.loginfo = value;
83 			SHOW_INFO( 1, "Log Info Level now %" B_PRIu32 "/4", value );
84 		}
85 
86 		item = get_driver_parameter (settings_handle, "logflow", "2", "2");
87 		value = strtoul (item, &end, 0);
88 		if (*end == '\0' && value <= 4) {
89 			current_settings.logflow = value;
90 			SHOW_INFO( 1, "Log Flow Level now %" B_PRIu32 "/4", value );
91 		}
92 
93 		item = get_driver_parameter (settings_handle, "logerror", "2", "2");
94 		value = strtoul (item, &end, 0);
95 		if (*end == '\0' && value <= 4) {
96 			current_settings.logerror = value;
97 			SHOW_INFO( 1, "Log Error Level now %" B_PRIu32 "/4", value );
98 		}
99 
100 		current_settings.switchhead = get_driver_boolean_parameter (settings_handle, "switchhead", false, false);
101 		current_settings.force_lcd = get_driver_boolean_parameter (settings_handle, "force_lcd", false, false);
102 		current_settings.dynamic_clocks = get_driver_boolean_parameter (settings_handle, "dynamic_clocks", true, true);
103 		current_settings.force_pci = get_driver_boolean_parameter (settings_handle, "force_pci", true, true);
104 		current_settings.unhide_fastwrites = get_driver_boolean_parameter (settings_handle, "unhide_fw", false, false);
105 		current_settings.force_acc_dma = get_driver_boolean_parameter (settings_handle, "force_acc_dma", false, false);
106 		current_settings.force_acc_mmio = get_driver_boolean_parameter (settings_handle, "force_acc_mmio", false, false);
107 		current_settings.acc_writeback = get_driver_boolean_parameter (settings_handle, "acc_writeback", false, false);
108 
109 		if ( current_settings.switchhead != def_settings.switchhead )
110 			SHOW_INFO0( 1, "Switch Head = True" );
111 		if ( current_settings.force_lcd != def_settings.force_lcd )
112 			SHOW_INFO0( 1, "Force LCD ON" );
113 		if ( current_settings.dynamic_clocks != def_settings.dynamic_clocks )
114 			SHOW_INFO0( 1, "Mobility Power Saving Disabled (Dynamic Clocks)" );
115 		if ( current_settings.force_pci != def_settings.force_pci )
116 			SHOW_INFO0( 1, "Force PCI = True" );
117 		if ( current_settings.unhide_fastwrites != def_settings.unhide_fastwrites )
118 			SHOW_INFO0( 1, "use Fastwrites ON" );
119 		if ( current_settings.force_acc_dma != def_settings.force_acc_dma )
120 			SHOW_INFO0( 1, "DMA ACC Enabled" );
121 		if ( current_settings.force_acc_mmio != def_settings.force_acc_mmio )
122 			SHOW_INFO0( 1, "DMA ACC Disabled" );
123 		if ( current_settings.acc_writeback != def_settings.acc_writeback )
124 			SHOW_INFO0( 1, "DMA WriteBack Disabled" );
125 
126 		unload_driver_settings (settings_handle);
127 	}
128 }
129 
130 
131 //	#pragma mark - driver API
132 
133 
134 status_t
135 init_hardware(void)
136 {
137 	SHOW_INFO0(0, RADEON_DRIVER_VERSION);
138 	if (Radeon_CardDetect() == B_OK)
139 		return B_OK;
140 
141 	return B_ERROR;
142 }
143 
144 
145 status_t
146 init_driver(void)
147 {
148 	SHOW_FLOW0(3, "");
149 
150 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
151 		return B_ERROR;
152 
153 	/* get a handle for the agp bus if it exists */
154 	get_module(B_AGP_GART_MODULE_NAME, (module_info **)&sAGP);
155 
156 	/* driver private data */
157 	devices = (radeon_devices *)calloc(1, sizeof(radeon_devices));
158 	if (devices == NULL) {
159 		put_module(B_PCI_MODULE_NAME);
160 		if (sAGP != NULL)
161 			put_module(B_AGP_GART_MODULE_NAME);
162 		return B_ERROR;
163 	}
164 
165 	(void)INIT_BEN(devices->kernel, "Radeon Kernel");
166 
167 	GetDriverSettings();
168 	Radeon_ProbeDevices();
169 	return B_OK;
170 }
171 
172 
173 void
174 uninit_driver(void)
175 {
176 	SHOW_FLOW0(3, "");
177 	DELETE_BEN(devices->kernel);
178 
179 	free(devices);
180 	devices = NULL;
181 
182 	put_module(B_PCI_MODULE_NAME);
183 	if (sAGP)
184 		put_module(B_AGP_GART_MODULE_NAME);
185 }
186 
187 
188 const char **
189 publish_devices(void)
190 {
191 	return (const char **)devices->device_names;
192 }
193 
194 
195 device_hooks *
196 find_device(const char *name)
197 {
198 	uint32 index;
199 
200 	// probably, we could always return standard hooks
201 	for (index = 0; devices->device_names[index]; ++index) {
202 		if (strcmp(name, devices->device_names[index]) == 0)
203 			return &graphics_device_hooks;
204 	}
205 
206 	return NULL;
207 }
208 
209 
210 //	#pragma mark - device API
211 
212 
213 static status_t
214 open_hook(const char *name, uint32 flags, void **cookie)
215 {
216 	int32 index = 0;
217 	device_info *di;
218 	status_t result = B_OK;
219 
220 	SHOW_FLOW( 3, "name=%s, flags=%" B_PRIu32 ", cookie=0x%08" B_PRIx32,
221 		name, flags, (uint32)cookie );
222 
223 	// find device info
224 	while (devices->device_names[index]
225 		&& strcmp(name, devices->device_names[index]) != 0) {
226 		index++;
227 	}
228 
229 	di = &(devices->di[index / 2]);
230 
231 	ACQUIRE_BEN(devices->kernel);
232 
233 	if (!di->is_open)
234 		result = Radeon_FirstOpen(di);
235 
236 	if (result == B_OK) {
237 		di->is_open++;
238 		*cookie = di;
239 	}
240 
241 	RELEASE_BEN(devices->kernel);
242 
243 	SHOW_FLOW(3, "returning 0x%08" B_PRIx32, result);
244 	return result;
245 }
246 
247 
248 static status_t
249 read_hook(void *dev, off_t pos, void *buf, size_t *len)
250 {
251 	*len = 0;
252 	return B_NOT_ALLOWED;
253 }
254 
255 
256 // public function: write to device (denied)
257 static status_t
258 write_hook(void *dev, off_t pos, const void *buf, size_t *len)
259 {
260 	*len = 0;
261 	return B_NOT_ALLOWED;
262 }
263 
264 
265 static status_t
266 close_hook(void *dev)
267 {
268 	return B_NO_ERROR;
269 }
270 
271 
272 static status_t
273 free_hook(void *dev)
274 {
275 	device_info *di = (device_info *)dev;
276 
277 	SHOW_FLOW0( 0, "" );
278 
279 	ACQUIRE_BEN( devices->kernel );
280 
281 	mem_freetag( di->memmgr[mt_local], dev );
282 
283 	if( di->memmgr[mt_PCI] )
284 		mem_freetag( di->memmgr[mt_PCI], dev );
285 
286 	if( di->memmgr[mt_AGP] )
287 		mem_freetag( di->memmgr[mt_AGP], dev );
288 
289 	if( di->is_open == 1 )
290 		Radeon_LastClose( di );
291 
292 	di->is_open--;
293 	RELEASE_BEN( devices->kernel );
294 
295 	return B_OK;
296 }
297 
298 
299 static status_t
300 control_hook(void *dev, uint32 msg, void *buf, size_t len)
301 {
302 	device_info *di = (device_info *)dev;
303 	status_t result = B_DEV_INVALID_IOCTL;
304 
305 	switch (msg) {
306 		// needed by app_server to load accelerant
307 		case B_GET_ACCELERANT_SIGNATURE: {
308 			char *sig = (char *)buf;
309 			strcpy(sig, "radeon.accelerant");
310 			result = B_OK;
311 		} break;
312 
313 		// needed to share data between kernel and accelerant
314 		case RADEON_GET_PRIVATE_DATA: {
315 			radeon_get_private_data *gpd = (radeon_get_private_data *)buf;
316 
317 			if (gpd->magic == RADEON_PRIVATE_DATA_MAGIC) {
318 				gpd->shared_info_area = di->shared_area;
319 				gpd->virtual_card_area = di->virtual_card_area;
320 				result = B_OK;
321 			}
322 		} break;
323 
324 		// needed for cloning
325 		case RADEON_DEVICE_NAME: {
326 			radeon_device_name *dn = (radeon_device_name *)buf;
327 
328 			if( dn->magic == RADEON_PRIVATE_DATA_MAGIC ) {
329 				strncpy( dn->name, di->name, MAX_RADEON_DEVICE_NAME_LENGTH );
330 				result = B_OK;
331 			}
332 		} break;
333 
334 		// graphics mem manager
335 		case RADEON_ALLOC_MEM: {
336 			radeon_alloc_mem *am = (radeon_alloc_mem *)buf;
337 			memory_type_e memory_type;
338 
339 			if( am->magic != RADEON_PRIVATE_DATA_MAGIC )
340 				break;
341 
342 			if( am->memory_type > mt_last )
343 				break;
344 
345 			memory_type = am->memory_type == mt_nonlocal ? di->si->nonlocal_type : am->memory_type;
346 
347 			result = mem_alloc( di->memmgr[memory_type], am->size, am->global ? 0 : dev, &am->handle, &am->offset );
348 		} break;
349 
350 		case RADEON_FREE_MEM: {
351 			radeon_free_mem *fm = (radeon_free_mem *)buf;
352 			memory_type_e memory_type;
353 
354 			if( fm->magic != RADEON_PRIVATE_DATA_MAGIC )
355 				break;
356 
357 			if( fm->memory_type > mt_last )
358 				break;
359 
360 			memory_type = fm->memory_type == mt_nonlocal ? di->si->nonlocal_type : fm->memory_type;
361 
362 			result = mem_free( di->memmgr[memory_type], fm->handle, fm->global ? 0 : dev );
363 		} break;
364 
365 		case RADEON_WAITFORIDLE: {
366 			radeon_wait_for_idle *wfi = (radeon_wait_for_idle *)buf;
367 
368 			if( wfi->magic != RADEON_PRIVATE_DATA_MAGIC )
369 				break;
370 
371 			Radeon_WaitForIdle( di, true, wfi->keep_lock );
372 			result = B_OK;
373 		} break;
374 
375 		case RADEON_WAITFORFIFO: {
376 			radeon_wait_for_fifo *wff = (radeon_wait_for_fifo *)buf;
377 
378 			if( wff->magic != RADEON_PRIVATE_DATA_MAGIC )
379 				break;
380 
381 			Radeon_WaitForFifo( di, wff->entries );
382 			result = B_OK;
383 		} break;
384 
385 		case RADEON_RESETENGINE: {
386 			radeon_no_arg *na = (radeon_no_arg *)buf;
387 
388 			if( na->magic != RADEON_PRIVATE_DATA_MAGIC )
389 				break;
390 
391 			ACQUIRE_BEN( di->si->cp.lock );
392 			Radeon_ResetEngine( di );
393 			RELEASE_BEN( di->si->cp.lock );
394 
395 			result = B_OK;
396 		} break;
397 
398 		case RADEON_VIPREAD: {
399 			radeon_vip_read *vr = (radeon_vip_read *)buf;
400 
401 			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
402 				break;
403 
404 			result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data,
405 				vr->lock ) ? B_OK : B_ERROR;
406 		} break;
407 
408 		case RADEON_VIPWRITE: {
409 			radeon_vip_write *vw = (radeon_vip_write *)buf;
410 
411 			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
412 				break;
413 
414 			result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data,
415 				vw->lock ) ? B_OK : B_ERROR;
416 		} break;
417 
418 		case RADEON_VIPFIFOREAD: {
419 			radeon_vip_fifo_read *vr = (radeon_vip_fifo_read *)buf;
420 
421 			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
422 				break;
423 
424 			result = Radeon_VIPFifoRead( di, vr->channel, vr->address, vr->count, vr->data,
425 				vr->lock ) ? B_OK : B_ERROR;
426 		} break;
427 
428 		case RADEON_VIPFIFOWRITE: {
429 			radeon_vip_fifo_write *vw = (radeon_vip_fifo_write *)buf;
430 
431 			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
432 				break;
433 
434 			result = Radeon_VIPFifoWrite( di, vw->channel, vw->address, vw->count, vw->data,
435 				vw->lock ) ? B_OK : B_ERROR;
436 		} break;
437 
438 		case RADEON_FINDVIPDEVICE: {
439 			radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf;
440 
441 			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
442 				break;
443 
444 			fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id );
445 			result = B_OK;
446 		} break;
447 
448 
449 		case RADEON_VIPRESET: {
450 			radeon_vip_reset *fvd = (radeon_vip_reset *)buf;
451 
452 			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
453 				break;
454 
455 			Radeon_VIPReset( di, fvd->lock );
456 			result = B_OK;
457 		} break;
458 
459 		case RADEON_WAIT_FOR_CAP_IRQ: {
460 			radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf;
461 
462 			if( wvc->magic != RADEON_PRIVATE_DATA_MAGIC )
463 				break;
464 
465 			// restrict wait time to 1 sec to get not stuck here in kernel
466 			result = acquire_sem_etc( di->cap_sem, 1, B_RELATIVE_TIMEOUT,
467 				min( wvc->timeout, 1000000 ));
468 
469 			if( result == B_OK ) {
470 				cpu_status prev_irq_state = disable_interrupts();
471 				acquire_spinlock( &di->cap_spinlock );
472 
473 				wvc->timestamp = di->cap_timestamp;
474 				wvc->int_status = di->cap_int_status;
475 				wvc->counter = di->cap_counter;
476 
477 				release_spinlock( &di->cap_spinlock );
478 				restore_interrupts( prev_irq_state );
479 			}
480 		} break;
481 
482 		case RADEON_DMACOPY: {
483 			radeon_dma_copy *dc = (radeon_dma_copy *)buf;
484 
485 			if( dc->magic != RADEON_PRIVATE_DATA_MAGIC )
486 				break;
487 
488 			result = Radeon_DMACopy( di, dc->src, dc->target, dc->size, dc->lock_mem, dc->contiguous );
489 		} break;
490 
491 #ifdef ENABLE_LOGGING
492 #ifdef LOG_INCLUDE_STARTUP
493 		// interface to log data
494 		case RADEON_GET_LOG_SIZE:
495 			*(uint32 *)buf = log_getsize( di->si->log );
496 			result = B_OK;
497 			break;
498 
499 		case RADEON_GET_LOG_DATA:
500 			log_getcopy( di->si->log, buf, ((uint32 *)buf)[0] );
501 			result = B_OK;
502 			break;
503 #endif
504 #endif
505 	}
506 
507 	if( result == B_DEV_INVALID_IOCTL )
508 		SHOW_ERROR( 3, "Invalid ioctl call: code=0x%" B_PRIx32, msg );
509 
510 	return result;
511 }
512