xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp (revision b90c801037e2a351806e0dc7ad45e801fd7bfdec)
1 /*
2  * Copyright (c) 2002, Thomas Kurschel
3  * Copyright 2004-2011 Haiku, Inc. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  *
6  * Authors:
7  *		Thomas Kurschel
8  *		Clemens Zeidler, <haiku@clemens-zeidler.de>
9  *		Alexander von Gluck IV, kallisti5@unixzen.com
10  */
11 
12 
13 #include "driver.h"
14 #include "device.h"
15 #include "lock.h"
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <AGP.h>
22 #include <KernelExport.h>
23 #include <OS.h>
24 #include <PCI.h>
25 #include <SupportDefs.h>
26 
27 
28 #define TRACE_DRIVER
29 #ifdef TRACE_DRIVER
30 #	define TRACE(x...) dprintf("radeon_hd: " x)
31 #else
32 #	define TRACE(x...) ;
33 #endif
34 
35 #define MAX_CARDS 1
36 
37 
38 // list of supported devices
39 const struct supported_device {
40 	uint32		device_id;
41 	uint16		chipset;
42 	const char*	name;
43 } kSupportedDevices[] = {
44 	// R600 series	(HD24xx - HD42xx)
45 	// Codename: Pele
46 	{0x94c7, RADEON_R600 | 0x10, "Radeon HD 2350"},	/*RV610*/
47 	{0x94c1, RADEON_R600 | 0x10, "Radeon HD 2400"},	/*RV610, IGP*/
48 	{0x94c3, RADEON_R600 | 0x10, "Radeon HD 2400"},	/*RV610*/
49 	{0x94cc, RADEON_R600 | 0x10, "Radeon HD 2400"},	/*RV610*/
50 	{0x9588, RADEON_R600 | 0x30, "Radeon HD 2600"},	/*RV630*/
51 	{0x958a, RADEON_R600 | 0x30, "Radeon HD 2600 X2"}, /*RV630*/
52 	//	Radeon 2700		- RV630
53 	{0x9400, RADEON_R600 | 0x0, "Radeon HD 2900"},	/*RV600*/
54 	{0x9405, RADEON_R600 | 0x0, "Radeon HD 2900"},	/*RV600*/
55 	{0x9611, RADEON_R600 | 0x20, "Radeon HD 3100"},	/*RV620, IGP*/
56 	{0x9613, RADEON_R600 | 0x20, "Radeon HD 3100"},	/*RV620, IGP*/
57 	{0x9610, RADEON_R600 | 0x10, "Radeon HD 3200"},	/*RV610, IGP*/
58 	{0x9612, RADEON_R600 | 0x10, "Radeon HD 3200"},	/*RV610, IGP*/
59 	{0x9615, RADEON_R600 | 0x10, "Radeon HD 3200"},	/*RV610, IGP*/
60 	{0x9614, RADEON_R600 | 0x10, "Radeon HD 3300"},	/*RV610, IGP*/
61 	//  Radeon 3430		- RV620
62 	{0x95c5, RADEON_R600 | 0x20, "Radeon HD 3450"},	/*RV620*/
63 	{0x95c6, RADEON_R600 | 0x20, "Radeon HD 3450"},	/*RV620*/
64 	{0x95c7, RADEON_R600 | 0x20, "Radeon HD 3450"},	/*RV620*/
65 	{0x95c9, RADEON_R600 | 0x20, "Radeon HD 3450"},	/*RV620*/
66 	{0x95c4, RADEON_R600 | 0x20, "Radeon HD 3470"},	/*RV620*/
67 	{0x95c0, RADEON_R600 | 0x20, "Radeon HD 3550"},	/*RV620*/
68 	{0x9581, RADEON_R600 | 0x30, "Radeon HD 3600"}, /*RV630*/
69 	{0x9583, RADEON_R600 | 0x30, "Radeon HD 3600"}, /*RV630*/
70 	{0x9598, RADEON_R600 | 0x30, "Radeon HD 3600"}, /*RV630*/
71 	{0x9591, RADEON_R600 | 0x35, "Radeon HD 3600"}, /*RV635*/
72 	{0x9589, RADEON_R600 | 0x30, "Radeon HD 3610"},	/*RV630*/
73 	//  Radeon 3650		- RV635
74 	//  Radeon 3670		- RV635
75 	{0x9507, RADEON_R600 | 0x70, "Radeon HD 3830"},	/*RV670*/
76 	{0x9505, RADEON_R600 | 0x70, "Radeon HD 3850"},	/*RV670, IGP*/
77 	{0x9513, RADEON_R600 | 0x80, "Radeon HD 3850 X2"}, /*RV670*/
78 	{0x9501, RADEON_R600 | 0x70, "Radeon HD 3870"},	/*RV670*/
79 	{0x950F, RADEON_R600 | 0x80, "Radeon HD 3870 X2"}, /*R680*/
80 	{0x9710, RADEON_R600 | 0x20, "Radeon HD 4200"},	/*RV620, IGP*/
81 	//	Radeon 4225		- RV620
82 	{0x9712, RADEON_R600 | 0x20, "Radeon HD 4270"},	/*RV620, IGP*/
83 
84 	// R700 series	(HD4330 - HD4890, HD51xx, HD5xxV)
85 	// Codename: Wekiva
86 	//	Radeon 4330		- RV710
87 	{0x954f, RADEON_R700 | 0x10, "Radeon HD 4300"},	/*RV710*/
88 	{0x9552, RADEON_R700 | 0x10, "Radeon HD 4300"},	/*RV710*/
89 	{0x9555, RADEON_R700 | 0x10, "Radeon HD 4350"},	/*RV710*/
90 	{0x9540, RADEON_R700 | 0x10, "Radeon HD 4550"},	/*RV710*/
91 	{0x9498, RADEON_R700 | 0x30, "Radeon HD 4650"},	/*RV740*/
92 	{0x94b4, RADEON_R700 | 0x40, "Radeon HD 4700"},	/*RV740*/
93 	{0x9490, RADEON_R700 | 0x30, "Radeon HD 4710"}, /*RV740*/
94 	{0x94b3, RADEON_R700 | 0x40, "Radeon HD 4770"},	/*RV740*/
95 	{0x94b5, RADEON_R700 | 0x40, "Radeon HD 4770"},	/*RV740*/
96 	{0x944a, RADEON_R700 | 0x70, "Radeon HD 4800"}, /*RV740*/
97 	{0x944e, RADEON_R700 | 0x70, "Radeon HD 4810"},	/*RV740*/
98 	{0x944c, RADEON_R700 | 0x70, "Radeon HD 4830"},	/*RV740*/
99 	{0x9442, RADEON_R700 | 0x70, "Radeon HD 4850"},	/*RV770*/
100 	{0x9443, RADEON_R700 | 0x70, "Radeon HD 4850 X2"}, /*RV770*/
101 	{0x94a1, RADEON_R700 | 0x90, "Radeon HD 4860"},	/*RV780, IGP*/
102 	{0x9440, RADEON_R700 | 0x70, "Radeon HD 4870"},	/*RV770*/
103 	{0x9441, RADEON_R700 | 0x70, "Radeon HD 4870 X2"}, /*RV770*/
104 
105 	// R800 series (HD54xx - HD59xx)
106 	// Codename: Evergreen
107 	{0x68e1, RADEON_R800 | 0x0, "Radeon HD 5430"},	/*RV8XX*/
108 	{0x68f9, RADEON_R800 | 0x0, "Radeon HD 5450"},	/*RV8XX*/
109 	{0x68e0, RADEON_R800 | 0x0, "Radeon HD 5470"},	/*RV8XX*/
110 	{0x68da, RADEON_R800 | 0x0, "Radeon HD 5500"},	/*RV8XX*/
111 	{0x68d9, RADEON_R800 | 0x0, "Radeon HD 5570"},	/*RV8XX*/
112 	{0x68b9, RADEON_R800 | 0x0, "Radeon HD 5600"},	/*RV8XX*/
113 	{0x68c1, RADEON_R800 | 0x0, "Radeon HD 5650"},	/*RV8XX*/
114 	{0x68d8, RADEON_R800 | 0x0, "Radeon HD 5670"},	/*RV8XX*/
115 	{0x68be, RADEON_R800 | 0x0, "Radeon HD 5700"},	/*RV8XX*/
116 	{0x68b8, RADEON_R800 | 0x0, "Radeon HD 5770"},	/*RV8XX*/
117 	{0x689e, RADEON_R800 | 0x0, "Radeon HD 5800"},	/*RV8XX*/
118 	{0x6899, RADEON_R800 | 0x0, "Radeon HD 5850"},	/*RV8XX*/
119 	{0x6898, RADEON_R800 | 0x0, "Radeon HD 5870"},	/*RV8XX*/
120 	{0x689c, RADEON_R800 | 0x0, "Radeon HD 5900"}	/*RV8XX*/
121 };
122 
123 
124 int32 api_version = B_CUR_DRIVER_API_VERSION;
125 
126 
127 char* gDeviceNames[MAX_CARDS + 1];
128 radeon_info* gDeviceInfo[MAX_CARDS];
129 pci_module_info* gPCI;
130 mutex gLock;
131 
132 
133 static status_t
134 get_next_radeon_hd(int32 *_cookie, pci_info &info, uint32 &type)
135 {
136 	int32 index = *_cookie;
137 
138 	// find devices
139 
140 	for (; gPCI->get_nth_pci_info(index, &info) == B_OK; index++) {
141 		// check vendor
142 		if (info.vendor_id != VENDOR_ID_ATI
143 			|| info.class_base != PCI_display
144 			|| info.class_sub != PCI_vga)
145 			continue;
146 
147 		// check device
148 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
149 				/ sizeof(kSupportedDevices[0]); i++) {
150 			if (info.device_id == kSupportedDevices[i].device_id) {
151 				type = i;
152 				*_cookie = index + 1;
153 				return B_OK;
154 			}
155 		}
156 	}
157 
158 	return B_ENTRY_NOT_FOUND;
159 }
160 
161 
162 extern "C" const char **
163 publish_devices(void)
164 {
165 	TRACE("%s\n", __func__);
166 	return (const char **)gDeviceNames;
167 }
168 
169 
170 extern "C" status_t
171 init_hardware(void)
172 {
173 	TRACE("%s\n", __func__);
174 
175 	status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCI);
176 	if (status != B_OK) {
177 		dprintf(DEVICE_NAME ": ERROR: pci module unavailable\n");
178 		return status;
179 	}
180 
181 	int32 cookie = 0;
182 	uint32 type;
183 	pci_info info;
184 	status = get_next_radeon_hd(&cookie, info, type);
185 
186 	put_module(B_PCI_MODULE_NAME);
187 	return status;
188 }
189 
190 
191 extern "C" status_t
192 init_driver(void)
193 {
194 	TRACE("%s\n", __func__);
195 
196 	status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
197 	if (status != B_OK) {
198 		dprintf(DEVICE_NAME ": ERROR: pci module unavailable\n");
199 		return status;
200 	}
201 
202 	mutex_init(&gLock, "radeon hd ksync");
203 
204 	// find devices
205 
206 	int32 found = 0;
207 
208 	for (int32 cookie = 0; found < MAX_CARDS;) {
209 		pci_info* info = (pci_info*)malloc(sizeof(pci_info));
210 		if (info == NULL)
211 			break;
212 
213 		uint32 type;
214 		status = get_next_radeon_hd(&cookie, *info, type);
215 		if (status < B_OK) {
216 			free(info);
217 			break;
218 		}
219 
220 		// create device names & allocate device info structure
221 
222 		char name[64];
223 		sprintf(name, "graphics/radeon_hd_%02x%02x%02x",
224 			info->bus, info->device,
225 			info->function);
226 
227 		gDeviceNames[found] = strdup(name);
228 		if (gDeviceNames[found] == NULL)
229 			break;
230 
231 		gDeviceInfo[found] = (radeon_info*)malloc(sizeof(radeon_info));
232 		if (gDeviceInfo[found] == NULL) {
233 			free(gDeviceNames[found]);
234 			break;
235 		}
236 
237 		// initialize the structure for later use
238 
239 		memset(gDeviceInfo[found], 0, sizeof(radeon_info));
240 		gDeviceInfo[found]->init_status = B_NO_INIT;
241 		gDeviceInfo[found]->id = found;
242 		gDeviceInfo[found]->pci = info;
243 		gDeviceInfo[found]->registers = (uint8 *)info->u.h0.base_registers[0];
244 		gDeviceInfo[found]->device_identifier = kSupportedDevices[type].name;
245 		gDeviceInfo[found]->device_chipset = kSupportedDevices[type].chipset;
246 
247 		dprintf(DEVICE_NAME ": GPU(%ld) %s, revision = 0x%x\n", found,
248 			kSupportedDevices[type].name, info->revision);
249 
250 		found++;
251 	}
252 
253 	gDeviceNames[found] = NULL;
254 
255 	if (found == 0) {
256 		mutex_destroy(&gLock);
257 		put_module(B_AGP_GART_MODULE_NAME);
258 		put_module(B_PCI_MODULE_NAME);
259 		return ENODEV;
260 	}
261 
262 	return B_OK;
263 }
264 
265 
266 extern "C" void
267 uninit_driver(void)
268 {
269 	TRACE("%s\n", __func__);
270 
271 	mutex_destroy(&gLock);
272 
273 	// free device related structures
274 	char* name;
275 	for (int32 index = 0; (name = gDeviceNames[index]) != NULL; index++) {
276 		free(gDeviceInfo[index]);
277 		free(name);
278 	}
279 
280 	put_module(B_PCI_MODULE_NAME);
281 }
282 
283 
284 extern "C" device_hooks*
285 find_device(const char* name)
286 {
287 	int index;
288 
289 	TRACE("%s\n", __func__);
290 
291 	for (index = 0; gDeviceNames[index] != NULL; index++) {
292 		if (!strcmp(name, gDeviceNames[index]))
293 			return &gDeviceHooks;
294 	}
295 
296 	return NULL;
297 }
298 
299