xref: /haiku/src/add-ons/accelerants/radeon_hd/connector.cpp (revision 22440f4105cafc95cc1d49f9bc65bb395c527d86)
1 /*
2  * Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *      Alexander von Gluck, kallisti5@unixzen.com
7  */
8 
9 
10 #include "connector.h"
11 
12 #include <assert.h>
13 #include <Debug.h>
14 
15 #include "accelerant_protos.h"
16 #include "accelerant.h"
17 #include "bios.h"
18 #include "encoder.h"
19 #include "gpu.h"
20 #include "utility.h"
21 
22 
23 #undef TRACE
24 
25 #define TRACE_CONNECTOR
26 #ifdef TRACE_CONNECTOR
27 #   define TRACE(x...) _sPrintf("radeon_hd: " x)
28 #else
29 #   define TRACE(x...) ;
30 #endif
31 
32 #define ERROR(x...) _sPrintf("radeon_hd: " x)
33 
34 
35 static void
36 gpio_lock_i2c(void* cookie, bool lock)
37 {
38 	gpio_info* info = (gpio_info*)cookie;
39 
40 	uint32 buffer = 0;
41 
42 	if (lock == true) {
43 		// hwCapable and > DCE3
44 		if (info->i2c.hwCapable == true && gInfo->shared_info->dceMajor >= 3) {
45 			// Switch GPIO pads to ddc mode
46 			buffer = Read32(OUT, info->i2c.sclMaskReg);
47 			buffer &= ~(1 << 16);
48 			Write32(OUT, info->i2c.sclMaskReg, buffer);
49 		}
50 
51 		// Clear pins
52 		buffer = Read32(OUT, info->i2c.sclAReg) & ~info->i2c.sclAMask;
53 		Write32(OUT, info->i2c.sclAReg, buffer);
54 		buffer = Read32(OUT, info->i2c.sdaAReg) & ~info->i2c.sdaAMask;
55 		Write32(OUT, info->i2c.sdaAReg, buffer);
56 	}
57 
58 	// Set pins to input
59 	buffer = Read32(OUT, info->i2c.sclEnReg) & ~info->i2c.sclEnMask;
60 	Write32(OUT, info->i2c.sclEnReg, buffer);
61 	buffer = Read32(OUT, info->i2c.sdaEnReg) & ~info->i2c.sdaEnMask;
62 	Write32(OUT, info->i2c.sdaEnReg, buffer);
63 
64 	// mask clock GPIO pins for software use
65 	buffer = Read32(OUT, info->i2c.sclMaskReg);
66 	if (lock == true)
67 		buffer |= info->i2c.sclMask;
68 	else
69 		buffer &= ~info->i2c.sclMask;
70 
71 	Write32(OUT, info->i2c.sclMaskReg, buffer);
72 	Read32(OUT, info->i2c.sclMaskReg);
73 
74 	// mask data GPIO pins for software use
75 	buffer = Read32(OUT, info->i2c.sdaMaskReg);
76 	if (lock == true)
77 		buffer |= info->i2c.sdaMask;
78 	else
79 		buffer &= ~info->i2c.sdaMask;
80 
81 	Write32(OUT, info->i2c.sdaMaskReg, buffer);
82 	Read32(OUT, info->i2c.sdaMaskReg);
83 }
84 
85 
86 static status_t
87 gpio_get_i2c_bit(void* cookie, int* _clock, int* _data)
88 {
89 	gpio_info* info = (gpio_info*)cookie;
90 
91 	uint32 scl = Read32(OUT, info->i2c.sclYReg) & info->i2c.sclYMask;
92 	uint32 sda = Read32(OUT, info->i2c.sdaYReg) & info->i2c.sdaYMask;
93 
94 	*_clock = scl != 0;
95 	*_data = sda != 0;
96 
97 	return B_OK;
98 }
99 
100 
101 static status_t
102 gpio_set_i2c_bit(void* cookie, int clock, int data)
103 {
104 	gpio_info* info = (gpio_info*)cookie;
105 
106 	uint32 scl = Read32(OUT, info->i2c.sclEnReg) & ~info->i2c.sclEnMask;
107 	scl |= clock ? 0 : info->i2c.sclEnMask;
108 	Write32(OUT, info->i2c.sclEnReg, scl);
109 	Read32(OUT, info->i2c.sclEnReg);
110 
111 	uint32 sda = Read32(OUT, info->i2c.sdaEnReg) & ~info->i2c.sdaEnMask;
112 	sda |= data ? 0 : info->i2c.sdaEnMask;
113 	Write32(OUT, info->i2c.sdaEnReg, sda);
114 	Read32(OUT, info->i2c.sdaEnReg);
115 
116 	return B_OK;
117 }
118 
119 
120 bool
121 connector_read_edid(uint32 connectorIndex, edid1_info* edid)
122 {
123 	// ensure things are sane
124 	uint32 i2cPinIndex = gConnector[connectorIndex]->i2cPinIndex;
125 	if (gGPIOInfo[i2cPinIndex]->valid == false
126 		|| gGPIOInfo[i2cPinIndex]->i2c.valid == false) {
127 		ERROR("%s: invalid gpio %" B_PRIu32 " for connector %" B_PRIu32 "\n",
128 			__func__, i2cPinIndex, connectorIndex);
129 		return false;
130 	}
131 
132 	i2c_bus bus;
133 
134 	ddc2_init_timing(&bus);
135 	bus.cookie = (void*)gGPIOInfo[i2cPinIndex];
136 	bus.set_signals = &gpio_set_i2c_bit;
137 	bus.get_signals = &gpio_get_i2c_bit;
138 
139 	gpio_lock_i2c(bus.cookie, true);
140 	status_t edid_result = ddc2_read_edid1(&bus, edid, NULL, NULL);
141 	gpio_lock_i2c(bus.cookie, false);
142 
143 	if (edid_result != B_OK)
144 		return false;
145 
146 	TRACE("%s: found edid monitor on connector #%" B_PRId32 "\n",
147 		__func__, connectorIndex);
148 
149 	return true;
150 }
151 
152 
153 bool
154 connector_read_mode_lvds(uint32 connectorIndex, display_mode* mode)
155 {
156 	assert(mode);
157 
158 	uint8 dceMajor;
159 	uint8 dceMinor;
160 	int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
161 	uint16 offset;
162 
163 	union atomLVDSInfo {
164 		struct _ATOM_LVDS_INFO info;
165 		struct _ATOM_LVDS_INFO_V12 info_12;
166 	};
167 
168 	// Wipe out display_mode
169 	memset(mode, 0, sizeof(display_mode));
170 
171 	if (atom_parse_data_header(gAtomContext, index, NULL,
172 		&dceMajor, &dceMinor, &offset) == B_OK) {
173 
174 		union atomLVDSInfo* lvdsInfo
175 			= (union atomLVDSInfo*)(gAtomContext->bios + offset);
176 
177 		display_timing* timing = &mode->timing;
178 
179 		// Pixel Clock
180 		timing->pixel_clock
181 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usPixClk) * 10;
182 		// Horizontal
183 		timing->h_display
184 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHActive);
185 		timing->h_total = timing->h_display + B_LENDIAN_TO_HOST_INT16(
186 			lvdsInfo->info.sLCDTiming.usHBlanking_Time);
187 		timing->h_sync_start = timing->h_display
188 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncOffset);
189 		timing->h_sync_end = timing->h_sync_start
190 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncWidth);
191 		// Vertical
192 		timing->v_display
193 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVActive);
194 		timing->v_total = timing->v_display + B_LENDIAN_TO_HOST_INT16(
195 			lvdsInfo->info.sLCDTiming.usVBlanking_Time);
196 		timing->v_sync_start = timing->v_display
197 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncOffset);
198 		timing->v_sync_end = timing->v_sync_start
199 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncWidth);
200 
201 		#if 0
202 		// Who cares.
203 		uint32 powerDelay
204 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.usOffDelayInMs);
205 		#endif
206 
207 		// Store special lvds flags the encoder setup needs
208 		gConnector[connectorIndex]->lvdsFlags = lvdsInfo->info.ucLVDS_Misc;
209 
210 		// Spread Spectrum ID (in SS table)
211 		gInfo->lvdsSpreadSpectrumID = lvdsInfo->info.ucSS_Id;
212 
213 		uint16 flags = B_LENDIAN_TO_HOST_INT16(
214 			lvdsInfo->info.sLCDTiming.susModeMiscInfo.usAccess);
215 
216 		if ((flags & ATOM_VSYNC_POLARITY) == 0)
217 			timing->flags |= B_POSITIVE_VSYNC;
218 		if ((flags & ATOM_HSYNC_POLARITY) == 0)
219 			timing->flags |= B_POSITIVE_HSYNC;
220 
221 		// Extra flags
222 		if ((flags & ATOM_INTERLACE) != 0)
223 			timing->flags |= B_TIMING_INTERLACED;
224 
225 		#if 0
226 		// We don't use these timing flags at the moment
227 		if ((flags & ATOM_COMPOSITESYNC) != 0)
228 			timing->flags |= MODE_FLAG_CSYNC;
229 		if ((flags & ATOM_DOUBLE_CLOCK_MODE) != 0)
230 			timing->flags |= MODE_FLAG_DBLSCAN;
231 		#endif
232 
233 		mode->h_display_start = 0;
234 		mode->v_display_start = 0;
235 		mode->virtual_width = timing->h_display;
236 		mode->virtual_height = timing->v_display;
237 
238 		// Assume 32-bit color
239 		mode->space = B_RGB32_LITTLE;
240 
241 		TRACE("%s: %" B_PRIu32 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16
242 			" %" B_PRIu16  " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16
243 			" %" B_PRIu16 "\n", __func__, timing->pixel_clock,
244 			timing->h_display, timing->h_sync_start, timing->h_sync_end,
245 			timing->h_total, timing->v_display, timing->v_sync_start,
246 			timing->v_sync_end, timing->v_total);
247 
248 		return true;
249 	}
250 	return false;
251 }
252 
253 
254 static status_t
255 connector_attach_gpio_i2c(uint32 connectorIndex, uint8 hwPin)
256 {
257 	gConnector[connectorIndex]->i2cPinIndex = 0;
258 	for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
259 		if (gGPIOInfo[i]->hwPin != hwPin)
260 			continue;
261 		gConnector[connectorIndex]->i2cPinIndex = i;
262 		return B_OK;
263 	}
264 
265 	// We couldnt find the GPIO pin in the known GPIO pins.
266     TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
267 		__func__, hwPin, connectorIndex);
268 	return B_ERROR;
269 }
270 
271 
272 static status_t
273 connector_attach_gpio_hpd(uint32 connectorIndex, uint8 hwPin)
274 {
275     gConnector[connectorIndex]->hpdPinIndex = 0;
276 
277     for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
278         if (gGPIOInfo[i]->hwPin != hwPin)
279             continue;
280         gConnector[connectorIndex]->hpdPinIndex = i;
281         return B_OK;
282     }
283 
284 	// We couldnt find the GPIO pin in the known GPIO pins.
285     TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
286         __func__, hwPin, connectorIndex);
287     return B_ERROR;
288 }
289 
290 
291 static status_t
292 gpio_general_populate()
293 {
294 	int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
295 	uint16 tableOffset;
296 	uint16 tableSize;
297 
298 	struct _ATOM_GPIO_PIN_LUT* gpioInfo;
299 
300 	if (atom_parse_data_header(gAtomContext, index, &tableSize, NULL, NULL,
301 		&tableOffset)) {
302 		ERROR("%s: could't read GPIO_Pin_LUT table from AtomBIOS index %d!\n",
303 			__func__, index);
304 	}
305 	gpioInfo = (struct _ATOM_GPIO_PIN_LUT*)(gAtomContext->bios + tableOffset);
306 
307 	int numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER)) /
308 		sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
309 
310 	// Find the next available GPIO pin index
311 	int32 gpioIndex = -1;
312 	for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) {
313 		if (!gGPIOInfo[pin]->valid) {
314 			gpioIndex = pin;
315 			break;
316 		}
317 	}
318 	if (gpioIndex < 0) {
319 		ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__);
320 		return B_ERROR;
321 	}
322 
323 	ATOM_GPIO_PIN_ASSIGNMENT* pin = gpioInfo->asGPIO_Pin;
324 	for (int i = 0; i < numIndices; i++) {
325 		if (gGPIOInfo[gpioIndex]->valid) {
326 			ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n",
327 				__func__);
328 			return B_ERROR;
329 		}
330 		gGPIOInfo[gpioIndex]->valid = true;
331 		gGPIOInfo[gpioIndex]->i2c.valid = false;
332 		gGPIOInfo[gpioIndex]->hwPin = pin->ucGPIO_ID;
333 		gGPIOInfo[gpioIndex]->hwReg
334 			= B_LENDIAN_TO_HOST_INT16(pin->usGpioPin_AIndex) * 4;
335 		gGPIOInfo[gpioIndex]->hwMask
336 			= (1 << pin->ucGpioPinBitShift);
337 		pin = (ATOM_GPIO_PIN_ASSIGNMENT*)((uint8*)pin
338 			+ sizeof(ATOM_GPIO_PIN_ASSIGNMENT));
339 
340 		TRACE("%s: general GPIO @ %" B_PRId32 ", valid: %s, "
341 			"hwPin: 0x%" B_PRIX32 "\n", __func__, gpioIndex,
342 			gGPIOInfo[gpioIndex]->valid ? "true" : "false",
343 			gGPIOInfo[gpioIndex]->hwPin);
344 
345 		gpioIndex++;
346 	}
347 	return B_OK;
348 }
349 
350 
351 static status_t
352 gpio_i2c_populate()
353 {
354 	radeon_shared_info &info = *gInfo->shared_info;
355 
356 	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
357 	uint16 tableOffset;
358 	uint16 tableSize;
359 
360 	if (atom_parse_data_header(gAtomContext, index, &tableSize,
361 		NULL, NULL, &tableOffset) != B_OK) {
362 		ERROR("%s: could't read GPIO_I2C_Info table from AtomBIOS index %d!\n",
363 			__func__, index);
364 		return B_ERROR;
365 	}
366 
367 	struct _ATOM_GPIO_I2C_INFO* i2cInfo
368 		= (struct _ATOM_GPIO_I2C_INFO*)(gAtomContext->bios + tableOffset);
369 
370 	uint32 numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER))
371 		/ sizeof(ATOM_GPIO_I2C_ASSIGMENT);
372 
373 	if (numIndices > ATOM_MAX_SUPPORTED_DEVICE) {
374 		ERROR("%s: ERROR: AtomBIOS contains more GPIO_Info items then I"
375 			"was prepared for! (seen: %" B_PRIu32 "; max: %" B_PRIu32 ")\n",
376 			__func__, numIndices, (uint32)ATOM_MAX_SUPPORTED_DEVICE);
377 		return B_ERROR;
378 	}
379 
380 	// Find the next available GPIO pin index
381 	int32 gpioIndex = -1;
382 	for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) {
383 		if (!gGPIOInfo[pin]->valid) {
384 			gpioIndex = pin;
385 			break;
386 		}
387 	}
388 	if (gpioIndex < 0) {
389 		ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__);
390 		return B_ERROR;
391 	}
392 
393 	for (uint32 i = 0; i < numIndices; i++) {
394 		if (gGPIOInfo[gpioIndex]->valid) {
395 			ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n",
396 				__func__);
397 			return B_ERROR;
398 		}
399 		ATOM_GPIO_I2C_ASSIGMENT* gpio = &i2cInfo->asGPIO_Info[i];
400 
401 		if (info.dceMajor >= 3) {
402 			if (i == 4 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex)
403 				== 0x1fda && gpio->sucI2cId.ucAccess == 0x94) {
404 				gpio->sucI2cId.ucAccess = 0x14;
405 				TRACE("%s: BUG: GPIO override for DCE 3 occured\n", __func__);
406 			}
407 		}
408 
409 		if (info.dceMajor >= 4) {
410 			if (i == 7 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex)
411 				== 0x1936 && gpio->sucI2cId.ucAccess == 0) {
412 				gpio->sucI2cId.ucAccess = 0x97;
413 				gpio->ucDataMaskShift = 8;
414 				gpio->ucDataEnShift = 8;
415 				gpio->ucDataY_Shift = 8;
416 				gpio->ucDataA_Shift = 8;
417 				TRACE("%s: BUG: GPIO override for DCE 4 occured\n", __func__);
418 			}
419 		}
420 
421 		// populate gpio information
422 		gGPIOInfo[gpioIndex]->hwPin = gpio->sucI2cId.ucAccess;
423 		gGPIOInfo[gpioIndex]->i2c.hwCapable
424 			= (gpio->sucI2cId.sbfAccess.bfHW_Capable) ? true : false;
425 
426 		// GPIO mask (Allows software to control the GPIO pad)
427 		// 0 = chip access; 1 = only software;
428 		gGPIOInfo[gpioIndex]->i2c.sclMaskReg
429 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) * 4;
430 		gGPIOInfo[gpioIndex]->i2c.sdaMaskReg
431 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataMaskRegisterIndex) * 4;
432 		gGPIOInfo[gpioIndex]->i2c.sclMask = 1 << gpio->ucClkMaskShift;
433 		gGPIOInfo[gpioIndex]->i2c.sdaMask = 1 << gpio->ucDataMaskShift;
434 
435 		// GPIO output / write (A) enable
436 		// 0 = GPIO input (Y); 1 = GPIO output (A);
437 		gGPIOInfo[gpioIndex]->i2c.sclEnReg
438 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkEnRegisterIndex) * 4;
439 		gGPIOInfo[gpioIndex]->i2c.sdaEnReg
440 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataEnRegisterIndex) * 4;
441 		gGPIOInfo[gpioIndex]->i2c.sclEnMask = 1 << gpio->ucClkEnShift;
442 		gGPIOInfo[gpioIndex]->i2c.sdaEnMask = 1 << gpio->ucDataEnShift;
443 
444 		// GPIO output / write (A)
445 		gGPIOInfo[gpioIndex]->i2c.sclAReg
446 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkA_RegisterIndex) * 4;
447 		gGPIOInfo[gpioIndex]->i2c.sdaAReg
448 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataA_RegisterIndex) * 4;
449 		gGPIOInfo[gpioIndex]->i2c.sclAMask = 1 << gpio->ucClkA_Shift;
450 		gGPIOInfo[gpioIndex]->i2c.sdaAMask = 1 << gpio->ucDataA_Shift;
451 
452 		// GPIO input / read (Y)
453 		gGPIOInfo[gpioIndex]->i2c.sclYReg
454 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkY_RegisterIndex) * 4;
455 		gGPIOInfo[gpioIndex]->i2c.sdaYReg
456 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataY_RegisterIndex) * 4;
457 		gGPIOInfo[gpioIndex]->i2c.sclYMask = 1 << gpio->ucClkY_Shift;
458 		gGPIOInfo[gpioIndex]->i2c.sdaYMask = 1 << gpio->ucDataY_Shift;
459 
460 		// ensure data is valid
461 		gGPIOInfo[gpioIndex]->i2c.valid
462 			= gGPIOInfo[gpioIndex]->i2c.sclMaskReg ? true : false;
463 		gGPIOInfo[gpioIndex]->valid = gGPIOInfo[gpioIndex]->i2c.valid;
464 
465 		TRACE("%s: i2c GPIO @ %" B_PRIu32 ", valid: %s, hwPin: 0x%" B_PRIX32 "\n",
466 			__func__, gpioIndex, gGPIOInfo[gpioIndex]->valid ? "true" : "false",
467 			gGPIOInfo[gpioIndex]->hwPin);
468 
469 		gpioIndex++;
470 	}
471 
472 	return B_OK;
473 }
474 
475 
476 status_t
477 gpio_populate()
478 {
479 	status_t result = gpio_general_populate();
480 	if (result != B_OK)
481 		return result;
482 
483 	result = gpio_i2c_populate();
484 	return result;
485 }
486 
487 
488 status_t
489 connector_probe_legacy()
490 {
491 	int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
492 	uint8 tableMajor;
493 	uint8 tableMinor;
494 	uint16 tableSize;
495 	uint16 tableOffset;
496 
497 	if (atom_parse_data_header(gAtomContext, index, &tableSize,
498 		&tableMajor, &tableMinor, &tableOffset) != B_OK) {
499 		ERROR("%s: unable to parse data header!\n", __func__);
500 		return B_ERROR;
501 	}
502 
503 	union atomSupportedDevices {
504 		struct _ATOM_SUPPORTED_DEVICES_INFO info;
505 		struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
506 		struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
507 	};
508 	union atomSupportedDevices* supportedDevices;
509 	supportedDevices = (union atomSupportedDevices*)
510 		(gAtomContext->bios + tableOffset);
511 
512 	uint16 deviceSupport
513 		= B_LENDIAN_TO_HOST_INT16(supportedDevices->info.usDeviceSupport);
514 
515 	uint32 maxDevice;
516 
517 	if (tableMajor > 1)
518 		maxDevice = ATOM_MAX_SUPPORTED_DEVICE;
519 	else
520 		maxDevice = ATOM_MAX_SUPPORTED_DEVICE_INFO;
521 
522 	uint32 i;
523 	uint32 connectorIndex = 0;
524 	for (i = 0; i < maxDevice; i++) {
525 
526 		gConnector[connectorIndex]->valid = false;
527 
528 		// check if this connector is used
529 		if ((deviceSupport & (1 << i)) == 0)
530 			continue;
531 
532 		if (i == ATOM_DEVICE_CV_INDEX) {
533 			TRACE("%s: skipping component video\n",
534 				__func__);
535 			continue;
536 		}
537 
538 		ATOM_CONNECTOR_INFO_I2C ci
539 			= supportedDevices->info.asConnInfo[i];
540 
541 		gConnector[connectorIndex]->type = kConnectorConvertLegacy[
542 			ci.sucConnectorInfo.sbfAccess.bfConnectorType];
543 
544 		if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_UNKNOWN) {
545 			TRACE("%s: skipping unknown connector at %" B_PRId32
546 				" of 0x%" B_PRIX8 "\n", __func__, i,
547 				ci.sucConnectorInfo.sbfAccess.bfConnectorType);
548 			continue;
549 		}
550 
551 		// TODO: give tv unique connector ids
552 
553 		// Always set CRT1 and CRT2 as VGA, some cards incorrectly set
554 		// VGA ports as DVI
555 		if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
556 			gConnector[connectorIndex]->type = VIDEO_CONNECTOR_VGA;
557 
558 		uint8 dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
559 		uint32 encoderObject = encoder_object_lookup((1 << i), dac);
560 		uint32 encoderID = (encoderObject & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
561 
562 		gConnector[connectorIndex]->valid = true;
563 		gConnector[connectorIndex]->flags = (1 << i);
564 		gConnector[connectorIndex]->encoder.valid = true;
565 		gConnector[connectorIndex]->encoder.objectID = encoderID;
566 		gConnector[connectorIndex]->encoder.type
567 			= encoder_type_lookup(encoderID, (1 << i));
568 
569 		// TODO: Eval external encoders on legacy connector probe
570 		gConnector[connectorIndex]->encoderExternal.valid = false;
571 		// encoder_is_external(encoderID);
572 
573 		connector_attach_gpio_i2c(connectorIndex, ci.sucI2cId.ucAccess);
574 
575 		pll_limit_probe(&gConnector[connectorIndex]->encoder.pll);
576 
577 		connectorIndex++;
578 	}
579 
580 	// TODO: combine shared connectors
581 
582 	if (connectorIndex == 0) {
583 		TRACE("%s: zero connectors found using legacy detection\n", __func__);
584 		return B_ERROR;
585 	}
586 
587 	return B_OK;
588 }
589 
590 
591 // r600+
592 status_t
593 connector_probe()
594 {
595 	int index = GetIndexIntoMasterTable(DATA, Object_Header);
596 	uint8 tableMajor;
597 	uint8 tableMinor;
598 	uint16 tableSize;
599 	uint16 tableOffset;
600 
601 	if (atom_parse_data_header(gAtomContext, index, &tableSize,
602 		&tableMajor, &tableMinor, &tableOffset) != B_OK) {
603 		ERROR("%s: ERROR: parsing data header failed!\n", __func__);
604 		return B_ERROR;
605 	}
606 
607 	if (tableMinor < 2) {
608 		ERROR("%s: ERROR: table minor version unknown! "
609 			"(%" B_PRIu8 ".%" B_PRIu8 ")\n", __func__, tableMajor, tableMinor);
610 		return B_ERROR;
611 	}
612 
613 	ATOM_CONNECTOR_OBJECT_TABLE* connectorObject;
614 	ATOM_ENCODER_OBJECT_TABLE* encoderObject;
615 	ATOM_OBJECT_TABLE* routerObject;
616 	ATOM_DISPLAY_OBJECT_PATH_TABLE* pathObject;
617 	ATOM_OBJECT_HEADER* objectHeader;
618 
619 	objectHeader = (ATOM_OBJECT_HEADER*)(gAtomContext->bios + tableOffset);
620 	pathObject = (ATOM_DISPLAY_OBJECT_PATH_TABLE*)
621 		(gAtomContext->bios + tableOffset
622 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usDisplayPathTableOffset));
623 	connectorObject = (ATOM_CONNECTOR_OBJECT_TABLE*)
624 		(gAtomContext->bios + tableOffset
625 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usConnectorObjectTableOffset));
626 	encoderObject = (ATOM_ENCODER_OBJECT_TABLE*)
627 		(gAtomContext->bios + tableOffset
628 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usEncoderObjectTableOffset));
629 	routerObject = (ATOM_OBJECT_TABLE*)
630 		(gAtomContext->bios + tableOffset
631 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usRouterObjectTableOffset));
632 	int deviceSupport = B_LENDIAN_TO_HOST_INT16(objectHeader->usDeviceSupport);
633 
634 	int pathSize = 0;
635 	int32 i = 0;
636 
637 	TRACE("%s: found %" B_PRIu8 " potential display paths.\n", __func__,
638 		pathObject->ucNumOfDispPath);
639 
640 	uint32 connectorIndex = 0;
641 	for (i = 0; i < pathObject->ucNumOfDispPath; i++) {
642 
643 		if (connectorIndex >= ATOM_MAX_SUPPORTED_DEVICE)
644 			continue;
645 
646 		uint8* address = (uint8*)pathObject->asDispPath;
647 		ATOM_DISPLAY_OBJECT_PATH* path;
648 		address += pathSize;
649 		path = (ATOM_DISPLAY_OBJECT_PATH*)address;
650 		pathSize += B_LENDIAN_TO_HOST_INT16(path->usSize);
651 
652 		uint32 connectorType;
653 		uint16 connectorFlags = B_LENDIAN_TO_HOST_INT16(path->usDeviceTag);
654 
655 		if ((deviceSupport & connectorFlags) != 0) {
656 
657 			uint16 connectorObjectID
658 				= (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
659 					& OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
660 			//uint8 con_obj_num
661 			//	= (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
662 			//	& ENUM_ID_MASK) >> ENUM_ID_SHIFT;
663 			//uint8 con_obj_type
664 			//	= (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
665 			//	& OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
666 
667 			if (connectorFlags == ATOM_DEVICE_CV_SUPPORT) {
668 				TRACE("%s: Path #%" B_PRId32 ": skipping component video.\n",
669 					__func__, i);
670 				continue;
671 			}
672 
673 			radeon_shared_info &info = *gInfo->shared_info;
674 
675 			uint16 igpLaneInfo;
676 			if ((info.chipsetFlags & CHIP_IGP) != 0) {
677 				ERROR("%s: TODO: IGP chip connector detection\n", __func__);
678 				// try non-IGP method for now
679 				igpLaneInfo = 0;
680 				connectorType = kConnectorConvert[connectorObjectID];
681 			} else {
682 				igpLaneInfo = 0;
683 				connectorType = kConnectorConvert[connectorObjectID];
684 			}
685 
686 			if (connectorType == VIDEO_CONNECTOR_UNKNOWN) {
687 				ERROR("%s: Path #%" B_PRId32 ": skipping unknown connector.\n",
688 					__func__, i);
689 				continue;
690 			}
691 
692 			connector_info* connector = gConnector[connectorIndex];
693 
694 			int32 j;
695 			for (j = 0; j < ((B_LENDIAN_TO_HOST_INT16(path->usSize) - 8) / 2);
696 				j++) {
697 				//uint16 grph_obj_id
698 				//	= (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j])
699 				//	& OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
700 				//uint8 grph_obj_num
701 				//	= (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) &
702 				//	ENUM_ID_MASK) >> ENUM_ID_SHIFT;
703 				uint8 graphicObjectType
704 					= (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) &
705 					OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
706 
707 				if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) {
708 					// Found an encoder
709 					int32 k;
710 					for (k = 0; k < encoderObject->ucNumberOfObjects; k++) {
711 						uint16 encoderObjectRaw
712 							= B_LENDIAN_TO_HOST_INT16(
713 							encoderObject->asObjects[k].usObjectID);
714 						if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j])
715 							== encoderObjectRaw) {
716 							ATOM_COMMON_RECORD_HEADER* record
717 								= (ATOM_COMMON_RECORD_HEADER*)
718 								((uint16*)gAtomContext->bios + tableOffset
719 								+ B_LENDIAN_TO_HOST_INT16(
720 								encoderObject->asObjects[k].usRecordOffset));
721 							ATOM_ENCODER_CAP_RECORD* capRecord;
722 							uint16 caps = 0;
723 							while (record->ucRecordSize > 0
724 								&& record->ucRecordType > 0
725 								&& record->ucRecordType
726 								<= ATOM_MAX_OBJECT_RECORD_NUMBER) {
727 								switch (record->ucRecordType) {
728 									case ATOM_ENCODER_CAP_RECORD_TYPE:
729 										capRecord = (ATOM_ENCODER_CAP_RECORD*)
730 											record;
731 										caps = B_LENDIAN_TO_HOST_INT16(
732 											capRecord->usEncoderCap);
733 										break;
734 								}
735 								record = (ATOM_COMMON_RECORD_HEADER*)
736 									((char*)record + record->ucRecordSize);
737 							}
738 
739 							uint32 encoderID
740 								= (encoderObjectRaw & OBJECT_ID_MASK)
741 									>> OBJECT_ID_SHIFT;
742 
743 							uint32 encoderType = encoder_type_lookup(encoderID,
744 								connectorFlags);
745 
746 							if (encoderType == VIDEO_ENCODER_NONE) {
747 								ERROR("%s: Path #%" B_PRId32 ":"
748 									"skipping unknown encoder.\n",
749 									__func__, i);
750 								continue;
751 							}
752 
753 							encoder_info* encoder;
754 
755 							// External encoders are behind DVO or UNIPHY
756 							if (encoder_is_external(encoderID)) {
757 								encoder = &connector->encoderExternal;
758 								encoder->isExternal = true;
759 								encoder->isDPBridge
760 									= encoder_is_dp_bridge(encoderID);
761 							} else {
762 								encoder = &connector->encoder;
763 								encoder->isExternal = false;
764 								encoder->isDPBridge = false;
765 							}
766 
767 							// Set up found connector encoder generics
768 							encoder->valid = true;
769 							encoder->capabilities = caps;
770 							encoder->objectID = encoderID;
771 							encoder->type = encoderType;
772 							encoder->linkEnumeration
773 								= (encoderObjectRaw & ENUM_ID_MASK)
774 									>> ENUM_ID_SHIFT;
775 							pll_limit_probe(&encoder->pll);
776 						}
777 					}
778 					// END if object is encoder
779 				} else if (graphicObjectType == GRAPH_OBJECT_TYPE_ROUTER) {
780 					ERROR("%s: TODO: Found router object?\n", __func__);
781 				} // END if object is router
782 			}
783 
784 			// Set up information buses such as ddc
785 			if (((connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0)
786 				&& (connectorFlags & ATOM_DEVICE_CV_SUPPORT) == 0) {
787 				for (j = 0; j < connectorObject->ucNumberOfObjects; j++) {
788 					if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
789 						== B_LENDIAN_TO_HOST_INT16(
790 						connectorObject->asObjects[j].usObjectID)) {
791 						ATOM_COMMON_RECORD_HEADER* record
792 							= (ATOM_COMMON_RECORD_HEADER*)(gAtomContext->bios
793 							+ tableOffset + B_LENDIAN_TO_HOST_INT16(
794 							connectorObject->asObjects[j].usRecordOffset));
795 						while (record->ucRecordSize > 0
796 							&& record->ucRecordType > 0
797 							&& record->ucRecordType
798 								<= ATOM_MAX_OBJECT_RECORD_NUMBER) {
799 							ATOM_I2C_RECORD* i2cRecord;
800 							ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig;
801 							ATOM_HPD_INT_RECORD* hpdRecord;
802 
803 							switch (record->ucRecordType) {
804 								case ATOM_I2C_RECORD_TYPE:
805 									i2cRecord
806 										= (ATOM_I2C_RECORD*)record;
807 									i2cConfig
808 										= (ATOM_I2C_ID_CONFIG_ACCESS*)
809 										&i2cRecord->sucI2cId;
810 									connector_attach_gpio_i2c(connectorIndex,
811 										i2cConfig->ucAccess);
812 									break;
813 								case ATOM_HPD_INT_RECORD_TYPE:
814 									hpdRecord = (ATOM_HPD_INT_RECORD*)record;
815 									connector_attach_gpio_hpd(connectorIndex,
816 										hpdRecord->ucHPDIntGPIOID);
817 									break;
818 							}
819 
820 							// move to next record
821 							record = (ATOM_COMMON_RECORD_HEADER*)
822 								((char*)record + record->ucRecordSize);
823 						}
824 					}
825 				}
826 			}
827 
828 			connector->valid = true;
829 			connector->flags = connectorFlags;
830 			connector->type = connectorType;
831 			connector->objectID = connectorObjectID;
832 
833 			connectorIndex++;
834 		} // END for each valid connector
835 	} // end for each display path
836 
837 	return B_OK;
838 }
839 
840 
841 bool
842 connector_is_dp(uint32 connectorIndex)
843 {
844 	connector_info* connector = gConnector[connectorIndex];
845 
846 	// Traditional DisplayPort connector
847 	if (connector->type == VIDEO_CONNECTOR_DP
848 		|| connector->type == VIDEO_CONNECTOR_EDP) {
849 		return true;
850 	}
851 
852 	// DisplayPort bridge on external encoder
853 	if (connector->encoderExternal.valid == true
854 		&& connector->encoderExternal.isDPBridge == true) {
855 		return true;
856 	}
857 
858 	return false;
859 }
860 
861 
862 void
863 debug_connectors()
864 {
865 	ERROR("Currently detected connectors=============\n");
866 	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
867 		if (gConnector[id]->valid == true) {
868 			uint32 connectorType = gConnector[id]->type;
869 			uint16 i2cPinIndex = gConnector[id]->i2cPinIndex;
870 			uint16 hpdPinIndex = gConnector[id]->hpdPinIndex;
871 
872 			ERROR("Connector #%" B_PRIu32 ")\n", id);
873 			ERROR(" + connector:          %s\n",
874 				get_connector_name(connectorType));
875 			ERROR(" + i2c gpio table id:  %" B_PRIu16 "\n", i2cPinIndex);
876 			ERROR("   - gpio hw pin:      0x%" B_PRIX32 "\n",
877 				gGPIOInfo[i2cPinIndex]->hwPin);
878 			ERROR("   - gpio valid:       %s\n",
879 				gGPIOInfo[i2cPinIndex]->valid ? "true" : "false");
880 			ERROR("   - i2c valid:        %s\n",
881 				gGPIOInfo[i2cPinIndex]->i2c.valid ? "true" : "false");
882 			ERROR(" + hpd gpio table id:  %" B_PRIu16 "\n", hpdPinIndex);
883 			ERROR("   - gpio hw pin:      0x%" B_PRIX32 "\n",
884 				 gGPIOInfo[hpdPinIndex]->hwPin);
885 			ERROR("   - gpio valid:       %s\n",
886 				gGPIOInfo[hpdPinIndex]->valid ? "true" : "false");
887 			encoder_info* encoder = &gConnector[id]->encoder;
888 			ERROR(" + encoder:            %s\n",
889 				get_encoder_name(encoder->type));
890 			ERROR("   - id:               %" B_PRIu16 "\n", encoder->objectID);
891 			ERROR("   - type:             %s\n",
892 				encoder_name_lookup(encoder->objectID));
893 			ERROR("   - capabilities:     0x%" B_PRIX32 "\n",
894 				encoder->capabilities);
895 			ERROR("   - enumeration:      %" B_PRIu32 "\n",
896 				encoder->linkEnumeration);
897 
898 			encoder = &gConnector[id]->encoderExternal;
899 
900 			ERROR("   - is bridge:        %s\n",
901 				encoder->valid ? "true" : "false");
902 
903 			if (!encoder->valid)
904 				ERROR("   + external encoder: none\n");
905 			else {
906 			ERROR("   + external encoder: %s\n",
907 					get_encoder_name(encoder->type));
908 				ERROR("     - valid:          true\n");
909 				ERROR("     - id:             %" B_PRIu16 "\n",
910 					encoder->objectID);
911 				ERROR("     - type:           %s\n",
912 					encoder_name_lookup(encoder->objectID));
913 				ERROR("     - enumeration:    %" B_PRIu32 "\n",
914 					encoder->linkEnumeration);
915 			}
916 
917 			uint32 connectorFlags = gConnector[id]->flags;
918 			bool flags = false;
919 			ERROR(" + flags:\n");
920 			if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
921 				ERROR("   * device CRT1 support\n");
922 				flags = true;
923 			}
924 			if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
925 				ERROR("   * device CRT2 support\n");
926 				flags = true;
927 			}
928 			if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
929 				ERROR("   * device LCD1 support\n");
930 				flags = true;
931 			}
932 			if ((connectorFlags & ATOM_DEVICE_LCD2_SUPPORT) != 0) {
933 				ERROR("   * device LCD2 support\n");
934 				flags = true;
935 			}
936 			if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
937 				ERROR("   * device TV1 support\n");
938 				flags = true;
939 			}
940 			if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
941 				ERROR("   * device CV support\n");
942 				flags = true;
943 			}
944 			if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
945 				ERROR("   * device DFP1 support\n");
946 				flags = true;
947 			}
948 			if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
949 				ERROR("   * device DFP2 support\n");
950 				flags = true;
951 			}
952 			if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
953 				ERROR("   * device DFP3 support\n");
954 				flags = true;
955 			}
956 			if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) {
957 				ERROR("   * device DFP4 support\n");
958 				flags = true;
959 			}
960 			if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) {
961 				ERROR("   * device DFP5 support\n");
962 				flags = true;
963 			}
964 			if ((connectorFlags & ATOM_DEVICE_DFP6_SUPPORT) != 0) {
965 				ERROR("   * device DFP6 support\n");
966 				flags = true;
967 			}
968 			if (flags == false)
969 				ERROR("   * no known flags\n");
970 		}
971 	}
972 	ERROR("==========================================\n");
973 }
974