1/*
2 * Copyright 2006-2011, 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 *		Alexander von Gluck, kallisti5@unixzen.com
8 */
9
10
11#include "accelerant.h"
12
13#include <AGP.h>
14#include <Debug.h>
15#include <errno.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
19#include <syslog.h>
20#include <unistd.h>
21
22#include "accelerant_protos.h"
23
24#include "bios.h"
25#include "connector.h"
26#include "display.h"
27#include "displayport.h"
28#include "gpu.h"
29#include "pll.h"
30#include "utility.h"
31
32
33#undef TRACE
34
35#define TRACE_ACCELERANT
36#ifdef TRACE_ACCELERANT
37#	define TRACE(x...) _sPrintf("radeon_hd: " x)
38#else
39#	define TRACE(x...) ;
40#endif
41
42
43struct accelerant_info* gInfo;
44display_info* gDisplay[MAX_DISPLAY];
45connector_info* gConnector[ATOM_MAX_SUPPORTED_DEVICE];
46gpio_info* gGPIOInfo[ATOM_MAX_SUPPORTED_DEVICE];
47
48
49class AreaCloner {
50public:
51								AreaCloner();
52								~AreaCloner();
53
54			area_id				Clone(const char* name, void** _address,
55									uint32 spec, uint32 protection,
56									area_id sourceArea);
57			status_t			InitCheck()
58									{return fArea < 0 ? (status_t)fArea : B_OK;}
59			void				Keep();
60
61private:
62			area_id				fArea;
63};
64
65
66AreaCloner::AreaCloner()
67	:
68	fArea(-1)
69{
70}
71
72
73AreaCloner::~AreaCloner()
74{
75	if (fArea >= 0)
76		delete_area(fArea);
77}
78
79
80area_id
81AreaCloner::Clone(const char* name, void** _address, uint32 spec,
82	uint32 protection, area_id sourceArea)
83{
84	fArea = clone_area(name, _address, spec, protection, sourceArea);
85	return fArea;
86}
87
88
89void
90AreaCloner::Keep()
91{
92	fArea = -1;
93}
94
95
96//	#pragma mark -
97
98
99/*! This is the common accelerant_info initializer. It is called by
100	both, the first accelerant and all clones.
101*/
102static status_t
103init_common(int device, bool isClone)
104{
105	// initialize global accelerant info structure
106
107	gInfo = (accelerant_info*)malloc(sizeof(accelerant_info));
108
109	if (gInfo == NULL)
110		return B_NO_MEMORY;
111
112	memset(gInfo, 0, sizeof(accelerant_info));
113
114	// malloc memory for active display information
115	for (uint32 id = 0; id < MAX_DISPLAY; id++) {
116		gDisplay[id] = (display_info*)malloc(sizeof(display_info));
117		if (gDisplay[id] == NULL)
118			return B_NO_MEMORY;
119		memset(gDisplay[id], 0, sizeof(display_info));
120
121		gDisplay[id]->regs = (register_info*)malloc(sizeof(register_info));
122		if (gDisplay[id]->regs == NULL)
123			return B_NO_MEMORY;
124		memset(gDisplay[id]->regs, 0, sizeof(register_info));
125	}
126
127	// malloc for possible physical card connectors
128	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
129		gConnector[id] = (connector_info*)malloc(sizeof(connector_info));
130
131		if (gConnector[id] == NULL)
132			return B_NO_MEMORY;
133		memset(gConnector[id], 0, sizeof(connector_info));
134	}
135
136	// malloc for card gpio pin information
137	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
138		gGPIOInfo[id] = (gpio_info*)malloc(sizeof(gpio_info));
139
140		if (gGPIOInfo[id] == NULL)
141			return B_NO_MEMORY;
142		memset(gGPIOInfo[id], 0, sizeof(gpio_info));
143	}
144
145	gInfo->is_clone = isClone;
146	gInfo->device = device;
147
148	gInfo->dpms_mode = B_DPMS_ON;
149		// initial state
150
151	// get basic info from driver
152
153	radeon_get_private_data data;
154	data.magic = RADEON_PRIVATE_DATA_MAGIC;
155
156	if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data,
157			sizeof(radeon_get_private_data)) != 0) {
158		free(gInfo);
159		return B_ERROR;
160	}
161
162	AreaCloner sharedCloner;
163	gInfo->shared_info_area = sharedCloner.Clone("radeon hd shared info",
164		(void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
165		data.shared_info_area);
166	status_t status = sharedCloner.InitCheck();
167	if (status < B_OK) {
168		free(gInfo);
169		TRACE("%s, failed to create shared area\n", __func__);
170		return status;
171	}
172
173	AreaCloner regsCloner;
174	gInfo->regs_area = regsCloner.Clone("radeon hd regs",
175		(void**)&gInfo->regs, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
176		gInfo->shared_info->registers_area);
177	status = regsCloner.InitCheck();
178	if (status < B_OK) {
179		free(gInfo);
180		TRACE("%s, failed to create mmio area\n", __func__);
181		return status;
182	}
183
184	gInfo->rom_area = clone_area("radeon hd AtomBIOS",
185		(void**)&gInfo->rom, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
186		gInfo->shared_info->rom_area);
187
188	if (gInfo->rom_area < 0) {
189		TRACE("%s: Clone of AtomBIOS failed!\n", __func__);
190		gInfo->shared_info->has_rom = false;
191	}
192
193	if (gInfo->rom[0] != 0x55 || gInfo->rom[1] != 0xAA)
194		TRACE("%s: didn't find a VGA bios in cloned region!\n", __func__);
195
196	sharedCloner.Keep();
197	regsCloner.Keep();
198
199	return B_OK;
200}
201
202
203/*! Clean up data common to both primary and cloned accelerant */
204static void
205uninit_common(void)
206{
207	if (gInfo != NULL) {
208		delete_area(gInfo->regs_area);
209		delete_area(gInfo->shared_info_area);
210		delete_area(gInfo->rom_area);
211
212		gInfo->regs_area = gInfo->shared_info_area = -1;
213
214		// close the file handle ONLY if we're the clone
215		if (gInfo->is_clone)
216			close(gInfo->device);
217
218		free(gInfo);
219	}
220
221	for (uint32 id = 0; id < MAX_DISPLAY; id++) {
222		if (gDisplay[id] != NULL) {
223			free(gDisplay[id]->regs);
224			free(gDisplay[id]);
225		}
226	}
227
228	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
229		free(gConnector[id]);
230		free(gGPIOInfo[id]);
231	}
232}
233
234
235//	#pragma mark - public accelerant functions
236
237
238/*! Init primary accelerant */
239status_t
240radeon_init_accelerant(int device)
241{
242	TRACE("%s enter\n", __func__);
243
244	status_t status = init_common(device, false);
245	if (status != B_OK)
246		return status;
247
248	radeon_shared_info &info = *gInfo->shared_info;
249
250	init_lock(&info.accelerant_lock, "radeon hd accelerant");
251	init_lock(&info.engine_lock, "radeon hd engine");
252
253	radeon_init_bios(gInfo->rom);
254
255	// probe firmware information
256	radeon_gpu_probe();
257
258	// find GPIO pins from AtomBIOS
259	gpio_probe();
260
261	// find physical card connectors from AtomBIOS
262	status = connector_probe();
263
264	if (status != B_OK) {
265		TRACE("%s: falling back to legacy connector probe.\n", __func__);
266		status = connector_probe_legacy();
267	}
268
269	if (status != B_OK) {
270		TRACE("%s: couldn't detect supported connectors!\n", __func__);
271		return status;
272	}
273
274	// print found connectors
275	debug_connectors();
276
277	// setup encoders on each connector if needed
278	encoder_init();
279
280	// program external pll clock
281	pll_external_init();
282
283	// setup link on any DisplayPort connectors
284	dp_setup_connectors();
285
286	// detect attached displays
287	status = detect_displays();
288	//if (status != B_OK)
289	//	return status;
290
291	// print found displays
292	debug_displays();
293
294	// create initial list of video modes
295	status = create_mode_list();
296	//if (status != B_OK) {
297	//	radeon_uninit_accelerant();
298	//	return status;
299	//}
300
301	radeon_gpu_mc_setup();
302
303	// Set up data crunching + irq rings
304	radeon_gpu_ring_setup();
305
306	radeon_gpu_ring_boot(RADEON_QUEUE_TYPE_GFX_INDEX);
307
308	TRACE("%s done\n", __func__);
309	return B_OK;
310}
311
312
313/*! This function is called for both, the primary accelerant and all of
314	its clones.
315*/
316void
317radeon_uninit_accelerant(void)
318{
319	TRACE("%s enter\n", __func__);
320
321	gInfo->mode_list = NULL;
322
323	radeon_shared_info &info = *gInfo->shared_info;
324
325	uninit_lock(&info.accelerant_lock);
326	uninit_lock(&info.engine_lock);
327
328	uninit_common();
329	TRACE("%s done\n", __func__);
330}
331
332
333status_t
334radeon_get_accelerant_device_info(accelerant_device_info* di)
335{
336	radeon_shared_info &info = *gInfo->shared_info;
337
338	di->version = B_ACCELERANT_VERSION;
339	strcpy(di->name, info.deviceName);
340
341	char chipset[32];
342	sprintf(chipset, "%s", gInfo->shared_info->chipsetName);
343	strcpy(di->chipset, chipset);
344
345	// add flags onto chipset name
346	if ((info.chipsetFlags & CHIP_IGP) != 0)
347		strcat(di->chipset, " IGP");
348	if ((info.chipsetFlags & CHIP_MOBILE) != 0)
349		strcat(di->chipset, " Mobile");
350	if ((info.chipsetFlags & CHIP_APU) != 0)
351		strcat(di->chipset, " APU");
352
353	strcpy(di->serial_no, "None" );
354
355	di->memory = gInfo->shared_info->graphics_memory_size;
356	return B_OK;
357}
358