xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon/driver.c (revision fce4895d1884da5ae6fb299d23c735c598e690b1)
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 %ld/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 %ld/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 %ld/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=%ld, cookie=0x%08lx", name, flags, (uint32)cookie );
221 
222 	// find device info
223 	while (devices->device_names[index]
224 		&& strcmp(name, devices->device_names[index]) != 0) {
225 		index++;
226 	}
227 
228 	di = &(devices->di[index / 2]);
229 
230 	ACQUIRE_BEN(devices->kernel);
231 
232 	if (!di->is_open)
233 		result = Radeon_FirstOpen(di);
234 
235 	if (result == B_OK) {
236 		di->is_open++;
237 		*cookie = di;
238 	}
239 
240 	RELEASE_BEN(devices->kernel);
241 
242 	SHOW_FLOW(3, "returning 0x%08lx", result);
243 	return result;
244 }
245 
246 
247 static status_t
248 read_hook(void *dev, off_t pos, void *buf, size_t *len)
249 {
250 	*len = 0;
251 	return B_NOT_ALLOWED;
252 }
253 
254 
255 // public function: write to device (denied)
256 static status_t
257 write_hook(void *dev, off_t pos, const void *buf, size_t *len)
258 {
259 	*len = 0;
260 	return B_NOT_ALLOWED;
261 }
262 
263 
264 static status_t
265 close_hook(void *dev)
266 {
267 	return B_NO_ERROR;
268 }
269 
270 
271 static status_t
272 free_hook(void *dev)
273 {
274 	device_info *di = (device_info *)dev;
275 
276 	SHOW_FLOW0( 0, "" );
277 
278 	ACQUIRE_BEN( devices->kernel );
279 
280 	mem_freetag( di->memmgr[mt_local], dev );
281 
282 	if( di->memmgr[mt_PCI] )
283 		mem_freetag( di->memmgr[mt_PCI], dev );
284 
285 	if( di->memmgr[mt_AGP] )
286 		mem_freetag( di->memmgr[mt_AGP], dev );
287 
288 	if( di->is_open == 1 )
289 		Radeon_LastClose( di );
290 
291 	di->is_open--;
292 	RELEASE_BEN( devices->kernel );
293 
294 	return B_OK;
295 }
296 
297 
298 static status_t
299 control_hook(void *dev, uint32 msg, void *buf, size_t len)
300 {
301 	device_info *di = (device_info *)dev;
302 	status_t result = B_DEV_INVALID_IOCTL;
303 
304 	switch (msg) {
305 		// needed by app_server to load accelerant
306 		case B_GET_ACCELERANT_SIGNATURE: {
307 			char *sig = (char *)buf;
308 			strcpy(sig, "radeon.accelerant");
309 			result = B_OK;
310 		} break;
311 
312 		// needed to share data between kernel and accelerant
313 		case RADEON_GET_PRIVATE_DATA: {
314 			radeon_get_private_data *gpd = (radeon_get_private_data *)buf;
315 
316 			if (gpd->magic == RADEON_PRIVATE_DATA_MAGIC) {
317 				gpd->shared_info_area = di->shared_area;
318 				gpd->virtual_card_area = di->virtual_card_area;
319 				result = B_OK;
320 			}
321 		} break;
322 
323 		// needed for cloning
324 		case RADEON_DEVICE_NAME: {
325 			radeon_device_name *dn = (radeon_device_name *)buf;
326 
327 			if( dn->magic == RADEON_PRIVATE_DATA_MAGIC ) {
328 				strncpy( dn->name, di->name, MAX_RADEON_DEVICE_NAME_LENGTH );
329 				result = B_OK;
330 			}
331 		} break;
332 
333 		// graphics mem manager
334 		case RADEON_ALLOC_MEM: {
335 			radeon_alloc_mem *am = (radeon_alloc_mem *)buf;
336 			memory_type_e memory_type;
337 
338 			if( am->magic != RADEON_PRIVATE_DATA_MAGIC )
339 				break;
340 
341 			if( am->memory_type > mt_last )
342 				break;
343 
344 			memory_type = am->memory_type == mt_nonlocal ? di->si->nonlocal_type : am->memory_type;
345 
346 			result = mem_alloc( di->memmgr[memory_type], am->size, am->global ? 0 : dev, &am->handle, &am->offset );
347 		} break;
348 
349 		case RADEON_FREE_MEM: {
350 			radeon_free_mem *fm = (radeon_free_mem *)buf;
351 			memory_type_e memory_type;
352 
353 			if( fm->magic != RADEON_PRIVATE_DATA_MAGIC )
354 				break;
355 
356 			if( fm->memory_type > mt_last )
357 				break;
358 
359 			memory_type = fm->memory_type == mt_nonlocal ? di->si->nonlocal_type : fm->memory_type;
360 
361 			result = mem_free( di->memmgr[memory_type], fm->handle, fm->global ? 0 : dev );
362 		} break;
363 
364 		case RADEON_WAITFORIDLE: {
365 			radeon_wait_for_idle *wfi = (radeon_wait_for_idle *)buf;
366 
367 			if( wfi->magic != RADEON_PRIVATE_DATA_MAGIC )
368 				break;
369 
370 			Radeon_WaitForIdle( di, true, wfi->keep_lock );
371 			result = B_OK;
372 		} break;
373 
374 		case RADEON_WAITFORFIFO: {
375 			radeon_wait_for_fifo *wff = (radeon_wait_for_fifo *)buf;
376 
377 			if( wff->magic != RADEON_PRIVATE_DATA_MAGIC )
378 				break;
379 
380 			Radeon_WaitForFifo( di, wff->entries );
381 			result = B_OK;
382 		} break;
383 
384 		case RADEON_RESETENGINE: {
385 			radeon_no_arg *na = (radeon_no_arg *)buf;
386 
387 			if( na->magic != RADEON_PRIVATE_DATA_MAGIC )
388 				break;
389 
390 			ACQUIRE_BEN( di->si->cp.lock );
391 			Radeon_ResetEngine( di );
392 			RELEASE_BEN( di->si->cp.lock );
393 
394 			result = B_OK;
395 		} break;
396 
397 		case RADEON_VIPREAD: {
398 			radeon_vip_read *vr = (radeon_vip_read *)buf;
399 
400 			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
401 				break;
402 
403 			result = Radeon_VIPRead( di, vr->channel, vr->address, &vr->data,
404 				vr->lock ) ? B_OK : B_ERROR;
405 		} break;
406 
407 		case RADEON_VIPWRITE: {
408 			radeon_vip_write *vw = (radeon_vip_write *)buf;
409 
410 			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
411 				break;
412 
413 			result = Radeon_VIPWrite( di, vw->channel, vw->address, vw->data,
414 				vw->lock ) ? B_OK : B_ERROR;
415 		} break;
416 
417 		case RADEON_VIPFIFOREAD: {
418 			radeon_vip_fifo_read *vr = (radeon_vip_fifo_read *)buf;
419 
420 			if( vr->magic != RADEON_PRIVATE_DATA_MAGIC )
421 				break;
422 
423 			result = Radeon_VIPFifoRead( di, vr->channel, vr->address, vr->count, vr->data,
424 				vr->lock ) ? B_OK : B_ERROR;
425 		} break;
426 
427 		case RADEON_VIPFIFOWRITE: {
428 			radeon_vip_fifo_write *vw = (radeon_vip_fifo_write *)buf;
429 
430 			if( vw->magic != RADEON_PRIVATE_DATA_MAGIC )
431 				break;
432 
433 			result = Radeon_VIPFifoWrite( di, vw->channel, vw->address, vw->count, vw->data,
434 				vw->lock ) ? B_OK : B_ERROR;
435 		} break;
436 
437 		case RADEON_FINDVIPDEVICE: {
438 			radeon_find_vip_device *fvd = (radeon_find_vip_device *)buf;
439 
440 			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
441 				break;
442 
443 			fvd->channel = Radeon_FindVIPDevice( di, fvd->device_id );
444 			result = B_OK;
445 		} break;
446 
447 
448 		case RADEON_VIPRESET: {
449 			radeon_vip_reset *fvd = (radeon_vip_reset *)buf;
450 
451 			if( fvd->magic != RADEON_PRIVATE_DATA_MAGIC )
452 				break;
453 
454 			Radeon_VIPReset( di, fvd->lock );
455 			result = B_OK;
456 		} break;
457 
458 		case RADEON_WAIT_FOR_CAP_IRQ: {
459 			radeon_wait_for_cap_irq *wvc = (radeon_wait_for_cap_irq *)buf;
460 
461 			if( wvc->magic != RADEON_PRIVATE_DATA_MAGIC )
462 				break;
463 
464 			// restrict wait time to 1 sec to get not stuck here in kernel
465 			result = acquire_sem_etc( di->cap_sem, 1, B_RELATIVE_TIMEOUT,
466 				min( wvc->timeout, 1000000 ));
467 
468 			if( result == B_OK ) {
469 				cpu_status prev_irq_state = disable_interrupts();
470 				acquire_spinlock( &di->cap_spinlock );
471 
472 				wvc->timestamp = di->cap_timestamp;
473 				wvc->int_status = di->cap_int_status;
474 				wvc->counter = di->cap_counter;
475 
476 				release_spinlock( &di->cap_spinlock );
477 				restore_interrupts( prev_irq_state );
478 			}
479 		} break;
480 
481 		case RADEON_DMACOPY: {
482 			radeon_dma_copy *dc = (radeon_dma_copy *)buf;
483 
484 			if( dc->magic != RADEON_PRIVATE_DATA_MAGIC )
485 				break;
486 
487 			result = Radeon_DMACopy( di, dc->src, dc->target, dc->size, dc->lock_mem, dc->contiguous );
488 		} break;
489 
490 #ifdef ENABLE_LOGGING
491 #ifdef LOG_INCLUDE_STARTUP
492 		// interface to log data
493 		case RADEON_GET_LOG_SIZE:
494 			*(uint32 *)buf = log_getsize( di->si->log );
495 			result = B_OK;
496 			break;
497 
498 		case RADEON_GET_LOG_DATA:
499 			log_getcopy( di->si->log, buf, ((uint32 *)buf)[0] );
500 			result = B_OK;
501 			break;
502 #endif
503 #endif
504 	}
505 
506 	if( result == B_DEV_INVALID_IOCTL )
507 		SHOW_ERROR( 3, "Invalid ioctl call: code=0x%lx", msg );
508 
509 	return result;
510 }
511